struct usb_device *usb_device_open(const char *dev_name) { int fd, did_retry = 0, writeable = 1; D("usb_device_open %s\n", dev_name); retry: fd = open(dev_name, O_RDWR); if (fd < 0) { /* if we fail, see if have read-only access */ fd = open(dev_name, O_RDONLY); D("usb_device_open open returned %d errno %d\n", fd, errno); if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) { /* work around race condition between inotify and permissions management */ sleep(1); did_retry = 1; goto retry; } if (fd < 0) return NULL; writeable = 0; D("[ usb open read-only %s fd = %d]\n", dev_name, fd); } struct usb_device* result = usb_device_new(dev_name, fd); if (result) result->writeable = writeable; return result; }
MtpDevice* MtpDevice::open(const char* deviceName, int fd) { struct usb_device *device = usb_device_new(deviceName, fd); if (!device) { ALOGE("usb_device_new failed for %s", deviceName); return NULL; } struct usb_descriptor_header* desc; struct usb_descriptor_iter iter; usb_descriptor_iter_init(device, &iter); while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { if (desc->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE && interface->bInterfaceSubClass == 1 && // Still Image Capture interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470) { char* manufacturerName = usb_device_get_manufacturer_name(device); char* productName = usb_device_get_product_name(device); ALOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName); free(manufacturerName); free(productName); } else if (interface->bInterfaceClass == 0xFF && interface->bInterfaceSubClass == 0xFF && interface->bInterfaceProtocol == 0) { char* interfaceName = usb_device_get_string(device, interface->iInterface); if (!interfaceName) { continue; } else if (strcmp(interfaceName, "MTP")) { free(interfaceName); continue; } free(interfaceName); // Looks like an android style MTP device char* manufacturerName = usb_device_get_manufacturer_name(device); char* productName = usb_device_get_product_name(device); ALOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName); free(manufacturerName); free(productName); } #if 0 else { // look for special cased devices based on vendor/product ID // we are doing this mainly for testing purposes uint16_t vendor = usb_device_get_vendor_id(device); uint16_t product = usb_device_get_product_id(device); if (!isMtpDevice(vendor, product)) { // not an MTP or PTP device continue; } // request MTP OS string and descriptor // some music players need to see this before entering MTP mode. char buffer[256]; memset(buffer, 0, sizeof(buffer)); int ret = usb_device_control_transfer(device, USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE, 0, buffer, sizeof(buffer), 0); printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno); if (ret > 0) { printf("got MTP string %s\n", buffer); ret = usb_device_control_transfer(device, USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1, 0, 4, buffer, sizeof(buffer), 0); printf("OS descriptor got %d\n", ret); } else { printf("no MTP string\n"); } } #endif // if we got here, then we have a likely MTP or PTP device // interface should be followed by three endpoints struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in_desc = NULL; struct usb_endpoint_descriptor *ep_out_desc = NULL; struct usb_endpoint_descriptor *ep_intr_desc = NULL; for (int i = 0; i < 3; i++) { ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter); if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) { ALOGE("endpoints not found\n"); usb_device_close(device); return NULL; } if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ep_in_desc = ep; else ep_out_desc = ep; } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT && ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { ep_intr_desc = ep; } } if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) { ALOGE("endpoints not found\n"); usb_device_close(device); return NULL; } if (usb_device_claim_interface(device, interface->bInterfaceNumber)) { ALOGE("usb_device_claim_interface failed errno: %d\n", errno); usb_device_close(device); return NULL; } MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber, ep_in_desc, ep_out_desc, ep_intr_desc); mtpDevice->initialize(); return mtpDevice; } } usb_device_close(device); ALOGE("device not found"); return NULL; }