| Index: src/libusb-glue.h |
| =================================================================== |
| --- src/libusb-glue.h (revision 162277) |
| +++ src/libusb-glue.h (working copy) |
| @@ -3,7 +3,7 @@ |
| * Low-level USB interface glue towards libusb. |
| * |
| * Copyright (C) 2005-2007 Richard A. Low <richard@wentnet.com> |
| - * Copyright (C) 2005-2011 Linus Walleij <triad@df.lth.se> |
| + * Copyright (C) 2005-2012 Linus Walleij <triad@df.lth.se> |
| * Copyright (C) 2006-2011 Marcus Meissner |
| * Copyright (C) 2007 Ted Bullock |
| * Copyright (C) 2008 Chris Bagwell <chris@cnpbagwell.com> |
| @@ -91,7 +91,9 @@ |
| #ifdef HAVE_LIBOPENUSB |
| openusb_dev_handle_t* handle; |
| #endif |
| + uint8_t config; |
| uint8_t interface; |
| + uint8_t altsetting; |
| int inep; |
| int inep_maxpacket; |
| int outep; |
| Index: src/libusb1-glue.c |
| =================================================================== |
| --- src/libusb1-glue.c (revision 162277) |
| +++ src/libusb1-glue.c (working copy) |
| @@ -87,7 +87,9 @@ |
| static LIBMTP_error_number_t init_usb(); |
| static void close_usb(PTP_USB* ptp_usb); |
| static int find_interface_and_endpoints(libusb_device *dev, |
| + uint8_t *conf, |
| uint8_t *interface, |
| + uint8_t *altsetting, |
| int* inep, |
| int* inep_maxpacket, |
| int* outep, |
| @@ -297,6 +299,7 @@ |
| && intf->bInterfaceSubClass == 0x01 |
| && intf->bInterfaceProtocol == 0x01) { |
| if (dumpfile != NULL) { |
| + fprintf(dumpfile, "Configuration %d, interface %d, altsetting %d:\n", i, j, k); |
| fprintf(dumpfile, " Found PTP device, check vendor " |
| "extension...\n"); |
| } |
| @@ -321,7 +324,7 @@ |
| fprintf(dumpfile, " Interface description contains the string \"MTP\"\n"); |
| fprintf(dumpfile, " Device recognized as MTP, no further probing.\n"); |
| } |
| - libusb_free_config_descriptor (config); |
| + libusb_free_config_descriptor(config); |
| libusb_close(devh); |
| return 1; |
| } |
| @@ -334,13 +337,14 @@ |
| if (config->interface[j].altsetting[k].bInterfaceClass != |
| LIBUSB_CLASS_MASS_STORAGE) { |
| LIBMTP_INFO("avoid probing device using attached kernel interface\n"); |
| - libusb_free_config_descriptor (config); |
| + libusb_free_config_descriptor(config); |
| return 0; |
| } |
| } |
| } |
| - } |
| - } |
| + } |
| + libusb_free_config_descriptor(config); |
| + } |
| |
| /* |
| * Only probe for OS descriptor if the device is vendor specific |
| @@ -1623,11 +1627,12 @@ |
| return PTP_RC_OK; |
| } |
| |
| -static int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, libusb_device* dev) |
| +static int init_ptp_usb(PTPParams* params, PTP_USB* ptp_usb, libusb_device* dev) |
| { |
| libusb_device_handle *device_handle; |
| unsigned char buf[255]; |
| int ret, usbresult; |
| + struct libusb_config_descriptor *config; |
| |
| params->sendreq_func=ptp_usb_sendreq; |
| params->senddata_func=ptp_usb_senddata; |
| @@ -1646,50 +1651,81 @@ |
| |
| ret = libusb_open(dev, &device_handle); |
| if (ret != LIBUSB_SUCCESS) { |
| - perror("usb_open()"); |
| + perror("libusb_open() failed!"); |
| return -1; |
| } |
| ptp_usb->handle = device_handle; |
| + |
| /* |
| * If this device is known to be wrongfully claimed by other kernel |
| * drivers (such as mass storage), then try to unload it to make it |
| * accessible from user space. |
| */ |
| if (FLAG_UNLOAD_DRIVER(ptp_usb) && |
| - libusb_kernel_driver_active (device_handle, ptp_usb->interface) |
| + libusb_kernel_driver_active(device_handle, ptp_usb->interface) |
| ) { |
| - if (LIBUSB_SUCCESS != libusb_detach_kernel_driver (device_handle, ptp_usb->interface)) { |
| - return -1; |
| + if (LIBUSB_SUCCESS != libusb_detach_kernel_driver(device_handle, ptp_usb->interface)) { |
| + perror("libusb_detach_kernel_driver() failed, continuing anyway..."); |
| } |
| } |
| -#ifdef __WIN32__ |
| - // Only needed on Windows, and cause problems on other platforms. |
| - if (libusb_set_configuration(device_handle, dev->config->bConfigurationValue)) { |
| - perror("usb_set_configuration()"); |
| + |
| + /* |
| + * Check if the config is set to something else than what we want |
| + * to use. Only set the configuration if we absolutely have to. |
| + * Also do not bail out if we fail. |
| + */ |
| + ret = libusb_get_active_config_descriptor(dev, &config); |
| + if (ret != LIBUSB_SUCCESS) { |
| + perror("libusb_get_active_config_descriptor(1) failed"); |
| return -1; |
| } |
| -#endif |
| - // It seems like on kernel 2.6.31 if we already have it open on another |
| - // pthread in our app, we'll get an error if we try to claim it again, |
| - // but that error is harmless because our process already claimed the interface |
| + if (config->bConfigurationValue != ptp_usb->config) { |
| + fprintf(stderr, "desired configuration different from current, trying to set configuration\n"); |
| + if (libusb_set_configuration(device_handle, ptp_usb->config)) { |
| + perror("libusb_set_configuration() failed, continuing anyway..."); |
| + } |
| + /* Re-fetch the config descriptor if we changed */ |
| + libusb_free_config_descriptor(config); |
| + ret = libusb_get_active_config_descriptor(dev, &config); |
| + if (ret != LIBUSB_SUCCESS) { |
| + perror("libusb_get_active_config_descriptor(2) failed"); |
| + return -1; |
| + } |
| + } |
| + |
| + /* |
| + * It seems like on kernel 2.6.31 if we already have it open on another |
| + * pthread in our app, we'll get an error if we try to claim it again, |
| + * but that error is harmless because our process already claimed the interface |
| + */ |
| usbresult = libusb_claim_interface(device_handle, ptp_usb->interface); |
| |
| if (usbresult != 0) |
| - fprintf(stderr, "ignoring usb_claim_interface = %d", usbresult); |
| + fprintf(stderr, "ignoring libusb_claim_interface() = %d", usbresult); |
| |
| - // FIXME : Discovered in the Barry project |
| - // kernels >= 2.6.28 don't set the interface the same way as |
| - // previous versions did, and the Blackberry gets confused |
| - // if it isn't explicitly set |
| - // See above, same issue with pthreads means that if this fails it is not |
| - // fatal |
| - // However, this causes problems on Macs so disable here |
| + /* |
| + * If the altsetting is set to something different than we want, switch |
| + * it. |
| + * |
| + * FIXME: this seems to cause trouble on the Mac:s so disable it. Retry |
| + * this on the Mac now that it only sets this when the altsetting differs. |
| + */ |
| #ifndef __APPLE__ |
| - usbresult = libusb_set_interface_alt_setting(device_handle, ptp_usb->interface, 0); |
| - if (usbresult) |
| - fprintf(stderr, "ignoring usb_claim_interface = %d", usbresult); |
| +#if 0 /* Disable this always, no idea on how to handle it */ |
| + if (config->interface[].altsetting[].bAlternateSetting != |
| + ptp_usb->altsetting) { |
| + fprintf(stderr, "desired altsetting different from current, trying to set altsetting\n"); |
| + usbresult = libusb_set_interface_alt_setting(device_handle, |
| + ptp_usb->interface, |
| + ptp_usb->altsetting); |
| + if (usbresult != 0) |
| + fprintf(stderr, "ignoring libusb_set_interface_alt_setting() = %d\n", usbresult); |
| + } |
| #endif |
| +#endif |
| |
| + libusb_free_config_descriptor(config); |
| + |
| if (FLAG_SWITCH_MODE_BLACKBERRY(ptp_usb)) { |
| int ret; |
| |
| @@ -1823,76 +1859,88 @@ |
| * Self-explanatory? |
| */ |
| static int find_interface_and_endpoints(libusb_device *dev, |
| + uint8_t *conf, |
| uint8_t *interface, |
| + uint8_t *altsetting, |
| int* inep, |
| int* inep_maxpacket, |
| int* outep, |
| int *outep_maxpacket, |
| int* intep) |
| { |
| - int i, ret; |
| + uint8_t i, ret; |
| struct libusb_device_descriptor desc; |
| |
| - ret = libusb_get_device_descriptor (dev, &desc); |
| - if (ret != LIBUSB_SUCCESS) return -1; |
| + ret = libusb_get_device_descriptor(dev, &desc); |
| + if (ret != LIBUSB_SUCCESS) |
| + return -1; |
| |
| // Loop over the device configurations |
| for (i = 0; i < desc.bNumConfigurations; i++) { |
| uint8_t j; |
| struct libusb_config_descriptor *config; |
| |
| - ret = libusb_get_config_descriptor (dev, i, &config); |
| + ret = libusb_get_config_descriptor(dev, i, &config); |
| + if (ret != 0) |
| + continue; |
| + |
| + *conf = config->bConfigurationValue; |
| + |
| if (ret != LIBUSB_SUCCESS) continue; |
| // Loop over each configurations interfaces |
| for (j = 0; j < config->bNumInterfaces; j++) { |
| - uint8_t k; |
| + uint8_t k, l; |
| uint8_t no_ep; |
| int found_inep = 0; |
| int found_outep = 0; |
| int found_intep = 0; |
| const struct libusb_endpoint_descriptor *ep; |
| |
| - // MTP devices shall have 3 endpoints, ignore those interfaces |
| - // that haven't. |
| - no_ep = config->interface[j].altsetting->bNumEndpoints; |
| - if (no_ep != 3) |
| - continue; |
| + // Inspect the altsettings of this interface... |
| + for (k = 0; k < config->interface[j].num_altsetting; k++) { |
| |
| - *interface = config->interface[j].altsetting->bInterfaceNumber; |
| - ep = config->interface[j].altsetting->endpoint; |
| + // MTP devices shall have 3 endpoints, ignore those interfaces |
| + // that haven't. |
| + no_ep = config->interface[j].altsetting[k].bNumEndpoints; |
| + if (no_ep != 3) |
| + continue; |
| |
| - // Loop over the three endpoints to locate two bulk and |
| - // one interrupt endpoint and FAIL if we cannot, and continue. |
| - for (k = 0; k < no_ep; k++) { |
| - if (ep[k].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK) { |
| - if ((ep[k].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == |
| - LIBUSB_ENDPOINT_DIR_MASK) { |
| - *inep = ep[k].bEndpointAddress; |
| - *inep_maxpacket = ep[k].wMaxPacketSize; |
| - found_inep = 1; |
| + *interface = config->interface[j].altsetting[k].bInterfaceNumber; |
| + *altsetting = config->interface[j].altsetting[k].bAlternateSetting; |
| + ep = config->interface[j].altsetting[k].endpoint; |
| + |
| + // Loop over the three endpoints to locate two bulk and |
| + // one interrupt endpoint and FAIL if we cannot, and continue. |
| + for (l = 0; l < no_ep; l++) { |
| + if (ep[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK) { |
| + if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == |
| + LIBUSB_ENDPOINT_DIR_MASK) { |
| + *inep = ep[l].bEndpointAddress; |
| + *inep_maxpacket = ep[l].wMaxPacketSize; |
| + found_inep = 1; |
| + } |
| + if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 0) { |
| + *outep = ep[l].bEndpointAddress; |
| + *outep_maxpacket = ep[l].wMaxPacketSize; |
| + found_outep = 1; |
| + } |
| + } else if (ep[l].bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT) { |
| + if ((ep[l].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == |
| + LIBUSB_ENDPOINT_DIR_MASK) { |
| + *intep = ep[l].bEndpointAddress; |
| + found_intep = 1; |
| + } |
| } |
| - if ((ep[k].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 0) { |
| - *outep = ep[k].bEndpointAddress; |
| - *outep_maxpacket = ep[k].wMaxPacketSize; |
| - found_outep = 1; |
| - } |
| - } else if (ep[k].bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT) { |
| - if ((ep[k].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == |
| - LIBUSB_ENDPOINT_DIR_MASK) { |
| - *intep = ep[k].bEndpointAddress; |
| - found_intep = 1; |
| - } |
| } |
| - } |
| - if (found_inep && found_outep && found_intep) { |
| - libusb_free_config_descriptor (config); |
| - // We assigned the endpoints so return here. |
| - return 0; |
| - } |
| - // Else loop to next interface/config |
| - } |
| - libusb_free_config_descriptor (config); |
| - } |
| + if (found_inep && found_outep && found_intep) { |
| + libusb_free_config_descriptor(config); |
| + // We assigned the endpoints so return here. |
| + return 0; |
| + } |
| + } // Next altsetting |
| + } // Next interface |
| + libusb_free_config_descriptor(config); |
| + } // Next config |
| return -1; |
| } |
| |
| @@ -1921,14 +1969,14 @@ |
| if (init_usb_ret != LIBMTP_ERROR_NONE) |
| return init_usb_ret; |
| |
| - nrofdevs = libusb_get_device_list (NULL, &devs); |
| + nrofdevs = libusb_get_device_list(NULL, &devs); |
| for (i = 0; i < nrofdevs ; i++) { |
| - if (libusb_get_bus_number (devs[i]) != device->bus_location) |
| + if (libusb_get_bus_number(devs[i]) != device->bus_location) |
| continue; |
| - if (libusb_get_device_address (devs[i]) != device->devnum) |
| + if (libusb_get_device_address(devs[i]) != device->devnum) |
| continue; |
| |
| - ret = libusb_get_device_descriptor (devs[i], &desc); |
| + ret = libusb_get_device_descriptor(devs[i], &desc); |
| if (ret != LIBUSB_SUCCESS) continue; |
| |
| if(desc.idVendor == device->device_entry.vendor_id && |
| @@ -1967,7 +2015,9 @@ |
| |
| /* Assign interface and endpoints to usbinfo... */ |
| err = find_interface_and_endpoints(ldevice, |
| + &ptp_usb->config, |
| &ptp_usb->interface, |
| + &ptp_usb->altsetting, |
| &ptp_usb->inep, |
| &ptp_usb->inep_maxpacket, |
| &ptp_usb->outep, |