// this method will override the Platform specific implementation of joinPMtree // it will cause any IOUSBDevice and IOUSBInterface clients to join the IOPower tree as // children of the IOUSHubPolicyMaker for the hub to which they are attached void IOUSBNub::joinPMtree ( IOService * driver ) { IOUSBHubPolicyMaker *hubPolicyMaker = NULL; IOUSBDevice *device = OSDynamicCast(IOUSBDevice, this); IOUSBInterface *interface = NULL; // we should be either an IOUSBDevice or an IOUSBInterface if (device) hubPolicyMaker = device->GetHubParent(); else { interface = OSDynamicCast(IOUSBInterface, this); if (interface && interface->GetDevice()) hubPolicyMaker = interface->GetDevice()->GetHubParent(); } if (hubPolicyMaker) { hubPolicyMaker->joinPMtree(driver); } else { USBLog(1, "%s[%p]::joinPMtree - no hub policy maker - calling through to super::joinPMtree", getName(), this); super::joinPMtree(driver); } }
bool com_yaqinking_MyFirstUSBDriver::start(IOService *provider) { IOUSBInterface* interface; IOUSBFindEndpointRequest request; IOUSBPipe* pipe = NULL; IOLog("%s(%p)::start \n",getName(),this); if (!super::start(provider)) { return false; } interface = OSDynamicCast(IOUSBInterface, provider); if (interface == NULL) { IOLog("%s(%p)::start -> provider not a IOUSBInterface \n",getName(),this); return false; } request.type = kUSBBulk; request.direction = kUSBOut; pipe = interface->FindNextPipe(NULL, &request,true); if (pipe) { logEndPoint(pipe); pipe->release(); } return true; }
bool AppleUSBCDC::confirmControl(UInt8 subClass, IOUSBInterface *CInterface) { IOUSBFindInterfaceRequest req; IOUSBInterface *Comm; UInt8 intSubClass; bool driverOK = false; XTRACE(this, subClass, 0, "confirmControl"); // We need to look for CDC interfaces of the specified subclass req.bInterfaceClass = kUSBCommunicationClass; // req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; req.bInterfaceSubClass = subClass; req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; req.bAlternateSetting = kIOUSBFindInterfaceDontCare; Comm = fpDevice->FindNextInterface(NULL, &req); if (!Comm) { XTRACE(this, 0, 0, "confirmDriver - Finding the first CDC interface failed"); return false; } while (Comm) { intSubClass = Comm->GetInterfaceSubClass(); if (intSubClass == subClass) // Just to make sure... { XTRACE(this, Comm->GetInterfaceNumber(), CInterface->GetInterfaceNumber(), "confirmControl - Checking interfaces"); if (Comm == CInterface) { driverOK = true; break; } } // see if there's another CDC interface req.bInterfaceClass = kUSBCommunicationClass; // req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; req.bInterfaceSubClass = subClass; req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; req.bAlternateSetting = kIOUSBFindInterfaceDontCare; Comm = fpDevice->FindNextInterface(Comm, &req); if (!Comm) { XTRACE(this, 0, 0, "confirmControl - No more CDC interfaces"); } } return driverOK; }/* end confirmControl */
bool HoRNDISUSBInterface::start(IOService *provider) { IOUSBInterface *intf; intf = OSDynamicCast(IOUSBInterface, provider); if (!intf) { LOG(V_ERROR, "cast to IOUSBInterface failed?"); return false; } fpDevice = intf->GetDevice(); return HoRNDIS::start(provider); }
bool XboxOneControllerDriver::handleStart(IOService *provider) { IOUSBInterface* interface = nullptr; IOUSBPipe* interruptPipe = nullptr; IOReturn ior = kIOReturnSuccess; IOUSBFindEndpointRequest pipeRequest = { .type = kUSBInterrupt, .direction = kUSBOut, }; // Apple says you should call super::handleStart at the *beginning* of the method. if (!super::handleStart(provider)) { goto cleanup; } // Paranoid check: is it the correct kind of object? interface = OSDynamicCast(IOUSBInterface, provider); if (interface == nullptr) { IO_LOG_DEBUG("IOUSBHIDDriver is handling start on an object that's not a IOUSBInterface??"); goto cleanup; } // Find the pipe through which we have to send the hello message. // This is redundant with work that IOUSBHIDDriver already did, but there are no accessors. interruptPipe = interface->FindNextPipe(nullptr, &pipeRequest); if (interruptPipe == nullptr) { IO_LOG_DEBUG("No interrupt pipe found on controller"); goto cleanup; } // `sendHello` needs _interruptPipe to be set, but only retain it if it succeeds. _interruptPipe = interruptPipe; ior = sendHello(); if (ior != kIOReturnSuccess) { IO_LOG_DEBUG("Couldn't send hello message: %08x", ior); _interruptPipe = nullptr; goto cleanup; } _interruptPipe->retain(); cleanup: return _interruptPipe != nullptr; }
// Start device bool WirelessGamingReceiver::start(IOService *provider) { const IOUSBConfigurationDescriptor *cd; IOUSBFindInterfaceRequest interfaceRequest; IOUSBFindEndpointRequest pipeRequest; IOUSBInterface *interface; int iConnection, iOther, i; if (!IOService::start(provider)) { // IOLog("start - superclass failed\n"); return false; } device = OSDynamicCast(IOUSBDevice, provider); if (device == NULL) { // IOLog("start - invalid provider\n"); goto fail; } // Check for configurations if (device->GetNumConfigurations() < 1) { device = NULL; // IOLog("start - device has no configurations!\n"); goto fail; } // Set configuration cd = device->GetFullConfigurationDescriptor(0); if (cd == NULL) { device = NULL; // IOLog("start - couldn't get configuration descriptor\n"); goto fail; } if (!device->open(this)) { device = NULL; // IOLog("start - failed to open device\n"); goto fail; } if (device->SetConfiguration(this, cd->bConfigurationValue, true) != kIOReturnSuccess) { // IOLog("start - unable to set configuration\n"); goto fail; } for (i = 0; i < WIRELESS_CONNECTIONS; i++) { connections[i].controller = NULL; connections[i].controllerIn = NULL; connections[i].controllerOut = NULL; connections[i].other = NULL; connections[i].otherIn = NULL; connections[i].otherOut = NULL; connections[i].inputArray = NULL; connections[i].service = NULL; connections[i].controllerStarted = false; } pipeRequest.interval = 0; pipeRequest.maxPacketSize = 0; pipeRequest.type = kUSBInterrupt; interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare; interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; interfaceRequest.bAlternateSetting = 0; interface = NULL; iConnection = 0; iOther = 0; while ((interface = device->FindNextInterface(interface, &interfaceRequest)) != NULL) { switch(interface->GetInterfaceProtocol()) { case 129: // Controller if (!interface->open(this)) { // IOLog("start: Failed to open control interface\n"); goto fail; } connections[iConnection].controller = interface; pipeRequest.direction = kUSBIn; connections[iConnection].controllerIn = interface->FindNextPipe(NULL, &pipeRequest); if (connections[iConnection].controllerIn == NULL) { // IOLog("start: Failed to open control input pipe\n"); goto fail; } else connections[iConnection].controllerIn->retain(); pipeRequest.direction = kUSBOut; connections[iConnection].controllerOut = interface->FindNextPipe(NULL, &pipeRequest); if (connections[iConnection].controllerOut == NULL) { // IOLog("start: Failed to open control output pipe\n"); goto fail; } else connections[iConnection].controllerOut->retain(); iConnection++; break; case 130: // It is a mystery if (!interface->open(this)) { // IOLog("start: Failed to open mystery interface\n"); goto fail; } connections[iOther].other = interface; pipeRequest.direction = kUSBIn; connections[iOther].otherIn = interface->FindNextPipe(NULL, &pipeRequest); if (connections[iOther].otherIn == NULL) { // IOLog("start: Failed to open mystery input pipe\n"); goto fail; } else connections[iOther].otherIn->retain(); pipeRequest.direction = kUSBOut; connections[iOther].otherOut = interface->FindNextPipe(NULL, &pipeRequest); if (connections[iOther].otherOut == NULL) { // IOLog("start: Failed to open mystery output pipe\n"); goto fail; } else connections[iOther].otherOut->retain(); iOther++; break; default: // IOLog("start: Ignoring interface (protocol %d)\n", interface->GetInterfaceProtocol()); break; } } if (iConnection != iOther) IOLog("start - interface mismatch?\n"); connectionCount = iConnection; for (i = 0; i < connectionCount; i++) { connections[i].inputArray = OSArray::withCapacity(5); if (connections[i].inputArray == NULL) { // IOLog("start: Failed to allocate packet buffer %d\n", i); goto fail; } if (!QueueRead(i)) { // IOLog("start: Failed to start read %d\n", i); goto fail; } } // IOLog("start: Transform and roll out (%d interfaces)\n", connectionCount); return true; fail: ReleaseAll(); return false; }
// // start // when this method is called, I have been selected as the driver for this device. // I can still return false to allow a different driver to load // bool local_IOath3kfrmwr::start(IOService *provider) { IOReturn err; const IOUSBConfigurationDescriptor *cd; // Do all the work here, on an IOKit matching thread. // 0.1 Get my USB Device DEBUG_LOG("%s(%p)::start!\n", getName(), this); pUsbDev = OSDynamicCast(IOUSBDevice, provider); if(!pUsbDev) { DEBUG_LOG("%s(%p)::start - Provider isn't a USB device!!!\n", getName(), this); return false; } // 0.2 Reset the device err = pUsbDev->ResetDevice(); if (err) { DEBUG_LOG("%s(%p)::start - failed to reset the device\n", getName(), this); pUsbDev->close(this); return false; } else IOLog("%s(%p)::start: device reset\n", getName(), this); // 0.3 Find the first config/interface int numconf = 0; if ((numconf = pUsbDev->GetNumConfigurations()) < 1) { DEBUG_LOG("%s(%p)::start - no composite configurations\n", getName(), this); return false; } else DEBUG_LOG("%s(%p)::start: num configurations %d\n", getName(), this, numconf); cd = pUsbDev->GetFullConfigurationDescriptor(0); // Set the configuration to the first config if (!cd) { DEBUG_LOG("%s(%p)::start - no config descriptor\n", getName(), this); return false; } // 1.0 Open the USB device if (!pUsbDev->open(this)) { DEBUG_LOG("%s(%p)::start - unable to open device for configuration\n", getName(), this); return false; } // 1.1 Set the configuration to the first config err = pUsbDev->SetConfiguration(this, cd->bConfigurationValue, true); if (err) { DEBUG_LOG("%s(%p)::start - unable to set the configuration\n", getName(), this); pUsbDev->close(this); return false; } DEBUG_LOG("%s(%p)::start - UPLOADED - %c\n", getName(), this,uploaded); //Uploading only one time if (!uploaded) { // 1.2 Get the status of the USB device (optional, for diag.) USBStatus status; err = pUsbDev->GetDeviceStatus(&status); if (err) { DEBUG_LOG("%s(%p)::start - unable to get device status\n", getName(), this); pUsbDev->close(this); return false; } else IOLog("%s(%p)::start: device status %d\n", getName(), this, (int)status); // 2.0 Find the interface for bulk endpoint transfers IOUSBFindInterfaceRequest request; request.bInterfaceClass = kIOUSBFindInterfaceDontCare; request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; request.bAlternateSetting = kIOUSBFindInterfaceDontCare; IOUSBInterface * intf = pUsbDev->FindNextInterface(NULL, &request); if (!intf) { DEBUG_LOG("%s(%p)::start - unable to find interface\n", getName(), this); pUsbDev->close(this); return false; } // 2.1 Open the interface if (!intf->open(this)) { DEBUG_LOG("%s(%p)::start - unable to open interface\n", getName(), this); pUsbDev->close(this); return false; } // 2.2 Get info on endpoints (optional, for diag.) int numep = intf->GetNumEndpoints(); DEBUG_LOG("%s(%p)::start: interface has %d endpoints\n", getName(), this, numep); UInt8 transferType = 0; UInt16 maxPacketSize = 0; UInt8 interval = 0; err = intf->GetEndpointProperties(0, 0x02, kUSBOut, &transferType, &maxPacketSize, &interval); if (err) { DEBUG_LOG("%s(%p)::start - failed to get endpoint 2 properties\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } else DEBUG_LOG("%s(%p)::start: EP2 %d %d %d\n", getName(), this, transferType, maxPacketSize, interval); err = intf->GetEndpointProperties(0, 0x01, kUSBIn, &transferType, &maxPacketSize, &interval); if (err) { DEBUG_LOG("%s(%p)::start - failed to get endpoint 1 properties\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } else {DEBUG_LOG("%s(%p)::start: EP1 %d %d %d\n", getName(), this, transferType, maxPacketSize, interval); } // 2.3 Get the pipe for bulk endpoint 2 Out IOUSBPipe * pipe = intf->GetPipeObj(0x02); if (!pipe) { DEBUG_LOG("%s(%p)::start - failed to find bulk out pipe\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } /* // TODO: Test the alternative way to do it: IOUSBFindEndpointRequest pipereq; pipereq.type = kUSBBulk; pipereq.direction = kUSBOut; pipereq.maxPacketSize = BULK_SIZE; pipereq.interval = 0; IOUSBPipe *pipe = intf->FindNextPipe(NULL, &pipereq); pipe = intf->FindNextPipe(pipe, &pipereq); if (!pipe) { DEBUG_LOG("%s(%p)::start - failed to find bulk out pipe 2\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } */ // 3.0 Send request to Control Endpoint to initiate the firmware transfer IOUSBDevRequest ctlreq; ctlreq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice); ctlreq.bRequest = USB_REQ_DFU_DNLOAD; ctlreq.wValue = 0; ctlreq.wIndex = 0; ctlreq.wLength = 20; ctlreq.pData = firmware_buf; #if 0 // Trying to troubleshoot the problem after Restart (with OSBundleRequired Root) for (int irep = 0; irep < 5; irep++) { // retry on error err = pUsbDev->DeviceRequest(&ctlreq); // (synchronous, will block) if (err) DEBUG_LOG("%s(%p)::start - failed to initiate firmware transfer (%d), retrying (%d)\n", getName(), this, err, irep+1); else break; } #else err = pUsbDev->DeviceRequest(&ctlreq); // (synchronous, will block) #endif if (err) { DEBUG_LOG("%s(%p)::start - failed to initiate firmware transfer (%d)\n", getName(), this, err); intf->close(this); pUsbDev->close(this); return false; } // 3.1 Create IOMemoryDescriptor for bulk transfers char buftmp[BULK_SIZE]; IOMemoryDescriptor * membuf = IOMemoryDescriptor::withAddress(&buftmp, BULK_SIZE, kIODirectionNone); if (!membuf) { DEBUG_LOG("%s(%p)::start - failed to map memory descriptor\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } err = membuf->prepare(); if (err) { DEBUG_LOG("%s(%p)::start - failed to prepare memory descriptor\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } // 3.2 Send the rest of firmware to the bulk pipe char * buf = firmware_buf; int size = sizeof(firmware_buf); buf += 20; size -= 20; int ii = 1; while (size) { int to_send = size < BULK_SIZE ? size : BULK_SIZE; memcpy(buftmp, buf, to_send); err = pipe->Write(membuf, 10000, 10000, to_send); if (err) { DEBUG_LOG("%s(%p)::start - failed to write firmware to bulk pipe (%d)\n", getName(), this, ii); intf->close(this); pUsbDev->close(this); return false; } buf += to_send; size -= to_send; ii++; } IOLog("%s(%p)::start: firmware was sent to bulk pipe\n", getName(), this); err = membuf->complete(); if (err) { DEBUG_LOG("%s(%p)::start - failed to complete memory descriptor\n", getName(), this); intf->close(this); pUsbDev->close(this); uploaded = false; return false; } /* // TODO: Test the alternative way to do it: IOMemoryDescriptor * membuf = IOMemoryDescriptor::withAddress(&firmware_buf[20], 246804-20, kIODirectionNone); // sizeof(firmware_buf) if (!membuf) { DEBUG_LOG("%s(%p)::start - failed to map memory descriptor\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } err = membuf->prepare(); if (err) { DEBUG_LOG("%s(%p)::start - failed to prepare memory descriptor\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } //err = pipe->Write(membuf); err = pipe->Write(membuf, 10000, 10000, 246804-20, NULL); if (err) { DEBUG_LOG("%s(%p)::start - failed to write firmware to bulk pipe\n", getName(), this); intf->close(this); pUsbDev->close(this); return false; } DEBUG_LOG("%s(%p)::start: firmware was sent to bulk pipe\n", getName(), this); */ // 4.0 Get device status (it fails, but somehow is important for operational device) err = pUsbDev->GetDeviceStatus(&status); if (err) { DEBUG_LOG("%s(%p)::start - unable to get device status\n", getName(), this); intf->close(this); pUsbDev->close(this); DEBUG_LOG("%s(%p)::start - Firmware Uploaded State Changed to - %c\n", getName(), this,uploaded); // Set the Upload State uploaded = true; return false; } else {DEBUG_LOG("%s(%p)::start: device status %d\n", getName(), this, (int)status); } // Close the interface intf->close(this); DEBUG_LOG("%s(%p)::start - Firmware Uploaded State Changed to - %c\n", getName(), this,uploaded); // Set the Upload State uploaded = true; } else { IOLog("%s(%p)::Firmware already uploaded\n", getName(), this); } // Close the USB device pUsbDev->close(this); return false; // return false to allow a different driver to load }
bool AppleUSBCDC::confirmDriver(UInt8 subClass, UInt8 dataInterface) { IOUSBFindInterfaceRequest req; IOUSBInterface *Comm; UInt8 intSubClass; UInt8 controlInterfaceNumber; bool driverOK = false; XTRACE(this, subClass, dataInterface, "confirmDriver"); // We need to look for CDC interfaces of the specified subclass req.bInterfaceClass = kUSBCommunicationClass; // req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; req.bInterfaceSubClass = subClass; req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; req.bAlternateSetting = kIOUSBFindInterfaceDontCare; Comm = fpDevice->FindNextInterface(NULL, &req); if (!Comm) { XTRACE(this, 0, 0, "confirmDriver - Finding the first CDC interface failed"); return false; } while (Comm) { controlInterfaceNumber = Comm->GetInterfaceNumber(); intSubClass = Comm->GetInterfaceSubClass(); if (intSubClass == subClass) // Just to make sure... { switch (intSubClass) { case kUSBAbstractControlModel: driverOK = checkACM(Comm, controlInterfaceNumber, dataInterface); break; case kUSBEthernetControlModel: driverOK = checkECM(Comm, controlInterfaceNumber, dataInterface); break; case kUSBWirelessHandsetControlModel: driverOK = checkWMC(Comm, controlInterfaceNumber, dataInterface); break; case kUSBDeviceManagementModel: driverOK = checkDMM(Comm, controlInterfaceNumber, dataInterface); break; case kUSBEthernetEmulationModel: // There's only one interface for EEM so the data and the control interface are the same // May need to revisit this if (controlInterfaceNumber == dataInterface) { driverOK = true; } break; case kUSBNetworkControlModel: driverOK = checkMBIM(Comm, controlInterfaceNumber, dataInterface); break; case kUSBMobileBroadbandInterfaceModel: driverOK = checkMBIM(Comm, controlInterfaceNumber, dataInterface); break; default: break; } } if (driverOK) { XTRACE(this, 0, 0, "confirmDriver - Interface confirmed"); break; } // see if there's another CDC interface req.bInterfaceClass = kUSBCommunicationClass; // req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; req.bInterfaceSubClass = subClass; req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; req.bAlternateSetting = kIOUSBFindInterfaceDontCare; Comm = fpDevice->FindNextInterface(Comm, &req); if (!Comm) { XTRACE(this, 0, 0, "confirmDriver - No more CDC interfaces"); } } return driverOK; }/* end confirmDriver */