/* * Retrieve a string for a specified string index from the USB device * * device - USB device pointer * stringIndex - String index to retrieve * output - Output buffer * len - Output buffer len * * returns true or false on error */ bool retrieveString(IOUSBDeviceInterface300** device, const unsigned char stringIndex, char* output, const int len) { IOUSBDevRequest request; CFStringRef string; const UInt8 buf[512]; // Perform a device request to read the string descriptor. request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); request.bRequest = kUSBRqGetDescriptor; request.wValue = (kUSBStringDesc << 8) | stringIndex; request.wIndex = 0; // Language (Optionally 0x409 for US English) request.wLength = sizeof(buf); request.pData = (void *)buf; bzero((void *)buf, sizeof(buf)); if ((*device)->DeviceRequest(device, &request) == kIOReturnSuccess) { int length; length = buf[0] - 2; // First byte is length (in bytes) // Convert from UTF-16 Little Endian string = CFStringCreateWithBytes(kCFAllocatorDefault, &buf[2], length, kCFStringEncodingUTF16LE, false); // To C String CFStringGetCString(string, output, len, kCFStringEncodingUTF8); CFRelease(string); } return false; }
void Xbox360Peripheral::SendInit(UInt16 value, UInt16 index) { IOUSBDevRequest controlReq; controlReq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice); controlReq.bRequest = 0xa9; controlReq.wValue = value; controlReq.wIndex = index; controlReq.wLength = 0; controlReq.pData = NULL; device->DeviceRequest(&controlReq, 100, 100, NULL); // Will fail - but device should still act on it }
void Xbox360Peripheral::SendSpecial(UInt16 value) { IOUSBDevRequest controlReq; controlReq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface); controlReq.bRequest = 0x00; controlReq.wValue = value; controlReq.wIndex = 0x0002; controlReq.wLength = 0; controlReq.pData = NULL; if (device->DeviceRequest(&controlReq, 100, 100, NULL) != kIOReturnSuccess) IOLog("Failed to send special message %.4x\n", value); }
IOReturn AnchorWrite(IOUSBDeviceInterface245 **dev, UInt16 anchorAddress, UInt16 count, UInt8 writeBuffer[]) { IOUSBDevRequest request; request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice); request.bRequest = 0xa0; request.wValue = anchorAddress; request.wIndex = 0; request.wLength = count; request.pData = writeBuffer; return (*dev)->DeviceRequest(dev, &request); }
IOReturn com_apple_AnchorUSB::AnchorWrite(UInt16 anchorAddress, UInt16 count, UInt8 writeBuffer[]) { IOUSBDevRequest request; request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice); request.bRequest = 0xa0; request.wValue = anchorAddress; request.wIndex = 0; request.wLength = count; request.pData = writeBuffer; return fDevice->DeviceRequest(&request); }
bool Xbox360Peripheral::SendSwitch(bool sendOut) { IOUSBDevRequest controlReq; controlReq.bmRequestType = USBmakebmRequestType(sendOut ? kUSBOut : kUSBIn, kUSBVendor, kUSBDevice); controlReq.bRequest = 0xa1; controlReq.wValue = 0x0000; controlReq.wIndex = 0xe416; controlReq.wLength = sizeof(chatpadInit); controlReq.pData = chatpadInit; IOReturn err = device->DeviceRequest(&controlReq, 100, 100, NULL); if (err == kIOReturnSuccess) return true; const char *errStr = stringFromReturn(err); IOLog("start - failed to %s chatpad setting (%s)\n", sendOut ? "write" : "read", errStr); return false; }
IOReturn AppleUSBCDC::reInitDevice() { IOUSBDevRequest req; IOReturn ior = kIOReturnSuccess; XTRACE(this, 0, 0, "reInitDevice"); req.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqSetConfig; req.wValue = fConfig; req.wIndex = 0; req.wLength = 0; req.pData = 0; ior = fpDevice->DeviceRequest(&req, 5000, 0); if (ior != kIOReturnSuccess) { XTRACE(this, 0, ior, "reInitDevice - DeviceRequest (SetConfig) error"); } return ior; }/* end reInitDevice */
int HoRNDIS::rndisCommand(struct rndis_msg_hdr *buf, int buflen) { int count; int rc = kIOReturnSuccess; IOUSBDevRequestDesc rq; IOBufferMemoryDescriptor *txdsc = IOBufferMemoryDescriptor::withCapacity(le32_to_cpu(buf->msg_len), kIODirectionOut); IOBufferMemoryDescriptor *rxdsc = IOBufferMemoryDescriptor::withCapacity(RNDIS_CMD_BUF_SZ, kIODirectionIn); if (buf->msg_type != RNDIS_MSG_HALT && buf->msg_type != RNDIS_MSG_RESET) { /* lock? */ buf->request_id = cpu_to_le32(xid++); if (!buf->request_id) buf->request_id = cpu_to_le32(xid++); } memcpy(txdsc->getBytesNoCopy(), buf, le32_to_cpu(buf->msg_len)); rq.bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; rq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface); rq.wValue = 0; rq.wIndex = fCommInterface->GetInterfaceNumber(); rq.pData = txdsc; rq.wLength = cpu_to_le32(buf->msg_len); if ((rc = fCommInterface->DeviceRequest(&rq)) != kIOReturnSuccess) goto bailout; /* Linux polls on the status channel, too; hopefully this shouldn't be needed if we're just talking to Android. */ /* Now we wait around a while for the device to get back to us. */ for (count = 0; count < 10; count++) { struct rndis_msg_hdr *inbuf = (struct rndis_msg_hdr *) rxdsc->getBytesNoCopy(); IOUSBDevRequestDesc rxrq; memset(inbuf, 0, RNDIS_CMD_BUF_SZ); rxrq.bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; rxrq.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface); rxrq.wValue = 0; rxrq.wIndex = fCommInterface->GetInterfaceNumber(); rxrq.pData = rxdsc; rxrq.wLength = RNDIS_CMD_BUF_SZ; if ((rc = fCommInterface->DeviceRequest(&rxrq)) != kIOReturnSuccess) goto bailout; if (rxrq.wLenDone < 8) { LOG(V_ERROR, "short read on control request?"); IOSleep(20); continue; } if (inbuf->msg_type == (buf->msg_type | RNDIS_MSG_COMPLETION)) { if (inbuf->request_id == buf->request_id) { if (inbuf->msg_type == RNDIS_MSG_RESET_C) break; if (inbuf->status == RNDIS_STATUS_SUCCESS) { /* ...and copy it out! */ LOG(V_DEBUG, "RNDIS command completed"); memcpy(buf, inbuf, le32_to_cpu(rxrq.wLenDone)); break; } LOG(V_ERROR, "RNDIS command returned status %08x", inbuf->status); rc = -1; break; } else { LOG(V_ERROR, "RNDIS return had incorrect xid?"); } } else { switch (inbuf->msg_type) { case RNDIS_MSG_INDICATE: LOG(V_ERROR, "unsupported: RNDIS_MSG_INDICATE"); break; case RNDIS_MSG_KEEPALIVE: LOG(V_ERROR, "unsupported: RNDIS_MSG_KEEPALIVE"); break; default: LOG(V_ERROR, "unexpected msg type %08x, msg_len %08x", inbuf->msg_type, inbuf->msg_len); break; } } IOSleep(20); } if (count == 10) { LOG(V_ERROR, "command timed out?"); rc = kIOReturnTimeout; } bailout: txdsc->complete(); txdsc->release(); rxdsc->complete(); rxdsc->release(); return rc; }
/** Try out the given device and see if there's a match. Returns 0 on * success, -1 on failure. */ static int try_device(io_service_t device, usb_handle *handle) { kern_return_t kr; IOCFPlugInInterface **plugin = NULL; IOUSBDeviceInterface500** dev = NULL; SInt32 score; HRESULT result; UInt8 serialIndex; UInt32 locationId; // Create an intermediate plugin. kr = IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); if ((kr != 0) || (plugin == NULL)) { goto error; } // Now create the device interface. result = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500), (LPVOID*)&dev); if ((result != 0) || (dev == NULL)) { ERR("Couldn't create a device interface (%08x)\n", (int) result); goto error; } /* * We don't need the intermediate interface after the device interface * is created. */ IODestroyPlugInInterface(plugin); // So, we have a device, finally. Grab its vitals. kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor); if (kr != 0) { ERR("GetDeviceVendor"); goto error; } kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product); if (kr != 0) { ERR("GetDeviceProduct"); goto error; } kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class); if (kr != 0) { ERR("GetDeviceClass"); goto error; } kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass); if (kr != 0) { ERR("GetDeviceSubClass"); goto error; } kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol); if (kr != 0) { ERR("GetDeviceProtocol"); goto error; } kr = (*dev)->GetLocationID(dev, &locationId); if (kr != 0) { ERR("GetLocationId"); goto error; } snprintf(handle->info.device_path, sizeof(handle->info.device_path), "usb:%" PRIu32 "X", (unsigned int)locationId); kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); if (serialIndex > 0) { IOUSBDevRequest req; UInt16 buffer[256]; req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = (kUSBStringDesc << 8) | serialIndex; //language ID (en-us) for serial number string req.wIndex = 0x0409; req.pData = buffer; req.wLength = sizeof(buffer); kr = (*dev)->DeviceRequest(dev, &req); if (kr == kIOReturnSuccess && req.wLenDone > 0) { int i, count; // skip first word, and copy the rest to the serial string, changing shorts to bytes. count = (req.wLenDone - 1) / 2; for (i = 0; i < count; i++) handle->info.serial_number[i] = buffer[i + 1]; handle->info.serial_number[i] = 0; } } else { // device has no serial number handle->info.serial_number[0] = 0; } handle->info.writable = 1; if (try_interfaces(dev, handle)) { goto error; } (*dev)->Release(dev); return 0; error: if (dev != NULL) { (*dev)->Release(dev); } return -1; }
//Gets a new device descriptor. //Is also used to see if we can talk to the device. IOKitError::Enum IOKitDevice::GetNewDescriptor(usb_device_t** device, IOUSBDeviceDescriptor& stDeviceDescriptor) { //Set up request for device descriptor IOUSBDevRequest req; req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = kUSBDeviceDesc << 8; req.wIndex = 0; req.wLength = sizeof(IOUSBDeviceDescriptor); req.pData = &(stDeviceDescriptor); //// retrieve device descriptors //// //device must be open for DeviceRequest (*device)->USBDeviceOpen(device); IOReturn ret = (*device)->DeviceRequest(device, &req); if(ret != kIOReturnSuccess) { int try_unsuspend = 1; #if (DeviceVersion >= 320) { UInt32 info; //device may be suspended. unsuspend it and try again //IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not (*device)->GetUSBDeviceInformation(device, &info); try_unsuspend = info & (1 << kUSBInformationDeviceIsSuspendedBit); } #endif if(try_unsuspend) { //resume the device (*device)->USBDeviceSuspend(device, 0); ret = (*device)->DeviceRequest(device, &req); //resuspend the device (*device)->USBDeviceSuspend(device, 1); } } /* //!!Would it just be easier to get this information from the IORegistry? //Set up request for product description IOUSBDevRequest product_desc_req; string_descriptor productDescription; product_desc_req.bmRequestType = LIBUSB_ENDPOINT_IN; product_desc_req.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR; product_desc_req.wValue = (LIBUSB_DT_STRING << 8) | stDeviceDescriptor.iSerialNumber; product_desc_req.wIndex = 0x409; product_desc_req.wLength = sizeof(productDescription); product_desc_req.pData = &productDescription; UCHAR aucBlah[255]; IOReturn product_desc_ret = (*device)->DeviceRequest(device, &product_desc_req); //!!Is this guaranteed to be null-terminated? if(product_desc_ret == kIOReturnSuccess) { //Convert from unicode to ascii int si, di; int length = sizeof(productDescription); for(di = 0, si = 0; si < productDescription.length; di++, si+=2) { if(di >= (length - 1)) break; if(productDescription.string[si] == '\0') { aucBlah[di] = '\0'; break; } if(productDescription.string[si + 1]) //high byte aucBlah[di] = '?'; else aucBlah[di] = productDescription.string[si]; } aucBlah[di] = '\0'; } else { aucBlah[0] = '\0'; } */ (*device)->USBDeviceClose(device); if(ret != kIOReturnSuccess) { //could not retrieve device descriptor return darwin_to_libusb(ret); } //// end: retrieve device descriptors //// return darwin_to_libusb(ret); }
#include <IOKit/IOLib.h> #include <IOKit/IOPlatformExpert.h> #include <IOKit/hidsystem/IOHidUsageTables.h> #include <IOKit/IOReturn.h> #define NAME "TM" // I don't know what these do, but I recorded this communication between // the iMate driver and the iMate device. And replaying them with a short pause // between them seems to get the iMate device to do what I want. #define kNumInitCmds 15 static UInt8 gCmd1[] = {0x0f, 0xfe}; static UInt8 gCmd2[] = {0x07, 0xfe}; static IOUSBDevRequest gInitSequence[kNumInitCmds] = { {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x01, 0x0004, 0x00FF, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x01, 0x0002, 0x0000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x0030, 0x0000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x007f, 0x0000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x00ff, 0x0000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x007b, 0x0000, sizeof(gCmd1), gCmd1, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x00ff, 0x0000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x007f, 0x0000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x00fb, 0x0000, sizeof(gCmd2), gCmd2, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x007f, 0x0000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x01, 0x0001, 0x8000, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x01, 0x0004, 0x00FF, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x01, 0x0004, 0x000a, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x01, 0x0003, 0x0001, 0, NULL, 0}, {USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface), 0x00, 0x007e, 0x0000, 0, NULL, 0} };
static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) { kern_return_t kr; io_service_t usbDevice; io_service_t usbInterface; IOCFPlugInInterface **plugInInterface = NULL; IOUSBInterfaceInterface220 **iface = NULL; IOUSBDeviceInterface197 **dev = NULL; HRESULT result; SInt32 score; UInt32 locationId; UInt16 vendor; UInt16 product; UInt8 serialIndex; char serial[256]; char devpathBuf[64]; char *devpath = NULL; while ((usbInterface = IOIteratorNext(iterator))) { //* Create an intermediate interface plugin kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); IOObjectRelease(usbInterface); if ((kIOReturnSuccess != kr) || (!plugInInterface)) { DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr); continue; } //* This gets us the interface object result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*) &iface); //* We only needed the plugin to get the interface, so discard it (*plugInInterface)->Release(plugInInterface); if (result || !iface) { DBG("ERR: Couldn't query the interface (%08x)\n", (int) result); continue; } //* this gets us an ioservice, with which we will find the actual //* device; after getting a plugin, and querying the interface, of //* course. //* Gotta love OS X kr = (*iface)->GetDevice(iface, &usbDevice); if (kIOReturnSuccess != kr || !usbDevice) { DBG("ERR: Couldn't grab device from interface (%08x)\n", kr); continue; } plugInInterface = NULL; score = 0; //* create an intermediate device plugin kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); //* only needed this to find the plugin (void)IOObjectRelease(usbDevice); if ((kIOReturnSuccess != kr) || (!plugInInterface)) { DBG("ERR: Unable to create a device plug-in (%08x)\n", kr); continue; } result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev); //* only needed this to query the plugin (*plugInInterface)->Release(plugInInterface); if (result || !dev) { DBG("ERR: Couldn't create a device interface (%08x)\n", (int) result); continue; } //* Now after all that, we actually have a ref to the device and //* the interface that matched our criteria kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->GetLocationID(dev, &locationId); if (kr == 0) { snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId); devpath = devpathBuf; } kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); if (serialIndex > 0) { IOUSBDevRequest req; UInt16 buffer[256]; UInt16 languages[128]; memset(languages, 0, sizeof(languages)); req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = (kUSBStringDesc << 8) | 0; req.wIndex = 0; req.pData = languages; req.wLength = sizeof(languages); kr = (*dev)->DeviceRequest(dev, &req); if (kr == kIOReturnSuccess && req.wLenDone > 0) { int langCount = (req.wLenDone - 2) / 2, lang; for (lang = 1; lang <= langCount; lang++) { memset(buffer, 0, sizeof(buffer)); memset(&req, 0, sizeof(req)); req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = (kUSBStringDesc << 8) | serialIndex; req.wIndex = languages[lang]; req.pData = buffer; req.wLength = sizeof(buffer); kr = (*dev)->DeviceRequest(dev, &req); if (kr == kIOReturnSuccess && req.wLenDone > 0) { int i, count; // skip first word, and copy the rest to the serial string, // changing shorts to bytes. count = (req.wLenDone - 1) / 2; for (i = 0; i < count; i++) serial[i] = buffer[i + 1]; serial[i] = 0; break; } } } } (*dev)->Release(dev); DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product, serial); usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface, vendor, product); if (handle == NULL) { DBG("ERR: Could not find device interface: %08x\n", kr); (*iface)->Release(iface); continue; } DBG("AndroidDeviceAdded calling register_usb_transport\n"); register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1); // Register for an interest notification of this device being removed. // Pass the reference to our private data as the refCon for the // notification. kr = IOServiceAddInterestNotification(notificationPort, usbInterface, kIOGeneralInterest, AndroidInterfaceNotify, handle, &handle->usbNotification); if (kIOReturnSuccess != kr) { DBG("ERR: Unable to create interest notification (%08x)\n", kr); } } }
// // 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 }
IOUSBFindEndpointRequest findEndpointRequest; findEndpointRequest.type = type; findEndpointRequest.direction = direction; if (IOUSBPipe* pipe = m_pInterface->FindNextPipe(NULL, &findEndpointRequest)) { shim->setPipe(pipe); return true; } return false; } IOReturn USBInterfaceShim::hciCommand(void* command, UInt16 length) { IOUSBDevRequest request = { .bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBDevice), .bRequest = 0, .wValue = 0, .wIndex = 0, .wLength = length, .pData = command }; return m_pInterface->DeviceRequest(&request); } USBPipeShim::USBPipeShim() { m_pPipe = NULL; } void USBPipeShim::setPipe(OSObject* pipe)
IOReturn AppleUSBCDC::setPropertiesWL( OSObject * properties ) { IOReturn result = kIOReturnBadArgument; OSDictionary *propertyDict; WWAN_DICTIONARY whichDictionary = WWAN_DICTIONARY_UNKNOWN; OSObject * dynamicKey = NULL; bool rc = false; propertyDict = OSDynamicCast( OSDictionary, properties ); if ( propertyDict != NULL ) { OSCollectionIterator *propertyIterator; #if TARGET_OS_EMBEDDED // Suspend support OSBoolean *suspendDevice = OSDynamicCast(OSBoolean, propertyDict->getObject("SuspendDevice")); if ( suspendDevice == kOSBooleanTrue ) { Log("AppleUSBCDC::setProperties - SuspendDevice: true\n"); if ( fpDevice->isOpen(this) ) { if ( ( result = fpDevice->SuspendDevice(true) ) != kIOReturnSuccess ) { Log("AppleUSBCDC::setProperties - failed to suspend the device, error: %08x \n", result); } } else { Log("AppleUSBCDC::setProperties - device was not open \n"); return kIOReturnError; } return result; } else if ( suspendDevice == kOSBooleanFalse ) { Log("AppleUSBCDC::setProperties - SuspendDevice: false\n"); if ( fpDevice->isOpen(this) ) { if ( ( result = fpDevice->SuspendDevice(false) ) != kIOReturnSuccess ) { Log("AppleUSBCDC::setProperties - failed to !suspend the device, error: %08x \n", result); } } else { IOLog("AppleUSBCDC::setProperties - device was not open \n"); result = kIOReturnError; } return result; } // Remote Wake-up support OSBoolean *remoteWakeup = OSDynamicCast(OSBoolean, propertyDict->getObject("RemoteWakeUp")); IOUSBDevRequest devreq; if ( remoteWakeup ) { devreq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice); if ( remoteWakeup == kOSBooleanTrue ) { devreq.bRequest = kUSBRqSetFeature; } else { devreq.bRequest = kUSBRqClearFeature; } devreq.wValue = kUSBFeatureDeviceRemoteWakeup; devreq.wIndex = 0; devreq.wLength = 0; devreq.pData = 0; result = fpDevice->DeviceRequest(&devreq); if ( result == kIOReturnSuccess ) { IOLog("AppleUSBCDC::setProperties - Set/Clear remote wake up feature successful\n"); } else { IOLog("AppleUSBCDC::setProperties - Set/Clear remote wake up feature failed, %08x\n", result); } return result; } #endif // TARGET_OS_EMBEDDED if (dynamicKey = propertyDict->getObject(kWWAN_TYPE)) whichDictionary = WWAN_SET_DYNAMIC_DICTIONARY; else if (dynamicKey = propertyDict->getObject(kWWAN_HW_VERSION)) whichDictionary = WWAN_SET_HARDWARE_DICTIONARY; else if (dynamicKey = propertyDict->getObject("AccessPointName")) whichDictionary = WWAN_SET_MODEM_DICTIONARY; else if (dynamicKey = propertyDict->getObject("LCPMTU")) whichDictionary = WWAN_SET_PPP_DICTIONARY; else if (dynamicKey = propertyDict->getObject(kWWAN_UNIQUIFIER)) whichDictionary = WWAN_SET_MODEM_DICTIONARY; // if we still can't determine which dictionary it is // Iterate to see if it is a property we know about.. if (whichDictionary == WWAN_DICTIONARY_UNKNOWN) { propertyIterator = OSCollectionIterator::withCollection( propertyDict ); if ( propertyIterator != NULL ) { OSSymbol *key; while( ( key = (OSSymbol *)propertyIterator->getNextObject() ) ) { // Log("[setPropertiesWL] key: %s \n", key->getCStringNoCopy()); // if (dynamicKey) // setProperty(key->getCStringNoCopy(),key); // setProperty(key->getCStringNoCopy(),propertyDict->getObject(key)); if (key->isEqualTo(kWWAN_SC_SETUP)) { if (fTerminate == true) return kIOReturnNoDevice;//We were terminated in the middle of handling a wwand request. rc = fpDevice->setProperty(kWWAN_SC_SETUP,propertyDict->getObject(key)); goto exit; } /* if (key->isEqualTo(kWWAN_UNIQUIFIER)) { rc = fpDevice->setProperty(kWWAN_UNIQUIFIER,propertyDict->getObject(key)); goto exit; } */ } propertyIterator->release(); } else { // Log("[setPropertiesWL] could not obtain an OSCollectionIterator... \n"); ALERT(0, 0, "setPropertiesWL - Could not obtain an OSCollectionIterator..."); result = kIOReturnError; } } else { switch (whichDictionary) { case WWAN_SET_DYNAMIC_DICTIONARY: rc = fpDevice->setProperty(kWWAN_DynamicDictonary,propertyDict); // Log("[setPropertiesWL] setting kWWAN_DynamicDictonary\n"); break; case WWAN_SET_HARDWARE_DICTIONARY: rc = fpDevice->setProperty(kWWAN_HardwareDictionary,propertyDict); // Log("[setPropertiesWL] setting kWWAN_HardwareDictionary\n"); break; case WWAN_SET_MODEM_DICTIONARY: rc = fpDevice->setProperty("DeviceModemOverrides",propertyDict); // Log("[setPropertiesWL] setting DeviceModemOverrides\n"); break; case WWAN_SET_PPP_DICTIONARY: rc = fpDevice->setProperty("DevicePPPOverrides",propertyDict); // Log("[setPropertiesWL] setting DevicePPPOverrides\n"); break; case WWAN_DICTIONARY_UNKNOWN: // Log("AppleWWANSUpport::setPropertiesWL - Unknown Dictionary"); break; default: // Log("AppleWWANSUpport::setPropertiesWL - default Unknown Dictionary"); break; } } fpDevice->messageClients ( kIOMessageServicePropertyChange ); // Log("[setPropertiesWL] set kWWAN_HardwareDictionary [%x] pNub mesaging Clients with kIOMessageServicePropertyChange \n",rc); } exit: this->messageClients ( kIOMessageServicePropertyChange ); fpDevice->messageClients ( kIOMessageServicePropertyChange ); return kIOReturnSuccess; }