summaryrefslogtreecommitdiff
path: root/libusb/os/darwin_usb.c
diff options
context:
space:
mode:
authorNathan Hjelm <hjelmn@me.com>2010-08-02 21:27:38 -0600
committerPete Batard <pbatard@gmail.com>2010-08-05 11:08:38 +0100
commite2e354d519c77c65d9ae3c8e4db6f0c9eedc4148 (patch)
treea634b15d0c0e29cb03c4ca0ce9eff1d5d2e4f4ee /libusb/os/darwin_usb.c
parentf901e14356f7fb961443e8a7c4782d36827fe15d (diff)
downloadlibusb-e2e354d519c77c65d9ae3c8e4db6f0c9eedc4148.tar.gz
Darwin: Cache device configuration value
Cache device configuration value to bring the Darwin backend more in line with the libusb spec. To handle buggy devices GetConfiguration is not called unless the device has more than one configuration.
Diffstat (limited to 'libusb/os/darwin_usb.c')
-rw-r--r--libusb/os/darwin_usb.c123
1 files changed, 73 insertions, 50 deletions
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index fae75b4..646c938 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -374,7 +374,7 @@ static int get_configuration_index (struct libusb_device *dev, int config_value)
for (i = 0 ; i < numConfig ; i++) {
(*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc);
- if (libusb_le16_to_cpu (desc->bConfigurationValue) == config_value)
+ if (desc->bConfigurationValue == config_value)
return i;
}
@@ -384,15 +384,12 @@ static int get_configuration_index (struct libusb_device *dev, int config_value)
static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) {
struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
- UInt8 config_value;
int config_index;
- IOReturn kresult;
- kresult = (*(priv->device))->GetConfiguration (priv->device, &config_value);
- if (kresult != kIOReturnSuccess)
- return darwin_to_libusb (kresult);
+ if (0 == priv->active_config)
+ return LIBUSB_ERROR_INVALID_PARAM;
- config_index = get_configuration_index (dev, config_value);
+ config_index = get_configuration_index (dev, priv->active_config);
if (config_index < 0)
return config_index;
@@ -438,6 +435,64 @@ static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t confi
return darwin_to_libusb (kresult);
}
+/* check whether the os has configured the device */
+static int darwin_check_configuration (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **darwin_device) {
+ struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+
+ IOUSBConfigurationDescriptorPtr configDesc;
+ IOUSBFindInterfaceRequest request;
+ kern_return_t kresult;
+ io_iterator_t interface_iterator;
+ io_service_t firstInterface;
+
+ if (priv->dev_descriptor.bNumConfigurations < 1) {
+ usbi_err (ctx, "device has no configurations");
+ return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */
+ }
+
+ /* find the first configuration */
+ kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
+ priv->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1;
+
+ /* check if the device is already configured. there is probably a better way than iterating over the
+ to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices
+ might lock up on the device request) */
+
+ /* Setup the Interface Request */
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
+ if (kresult)
+ return darwin_to_libusb (kresult);
+
+ /* iterate once */
+ firstInterface = IOIteratorNext(interface_iterator);
+
+ /* done with the interface iterator */
+ IOObjectRelease(interface_iterator);
+
+ if (firstInterface) {
+ IOObjectRelease (firstInterface);
+
+ /* device is configured */
+ if (priv->dev_descriptor.bNumConfigurations == 1)
+ /* to avoid problems with some devices get the configurations value from the configuration descriptor */
+ priv->active_config = priv->first_config;
+ else
+ /* devices with more than one configuration should work with GetConfiguration */
+ (*darwin_device)->GetConfiguration (darwin_device, &priv->active_config);
+ } else
+ /* not configured */
+ priv->active_config = 0;
+
+ usbi_info (ctx, "active config: %u, first config: %u", priv->active_config, priv->first_config);
+
+ return 0;
+}
+
static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID, struct discovered_devs **_discdevs) {
struct darwin_device_priv *priv;
struct libusb_device *dev;
@@ -529,6 +584,11 @@ static int process_new_device (struct libusb_context *ctx, usb_device_t **device
dev->bus_number = locationID >> 24;
dev->device_address = address;
+ /* check current active configuration (and cache the first configuration value-- which may be used by claim_interface) */
+ ret = darwin_check_configuration (ctx, dev, device);
+ if (ret < 0)
+ break;
+
/* save our location, we'll need this later */
priv->location = locationID;
snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass);
@@ -696,14 +756,8 @@ static void darwin_close (struct libusb_device_handle *dev_handle) {
static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) {
struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
- UInt8 configNum;
- IOReturn kresult;
-
- kresult = (*(dpriv->device))->GetConfiguration (dpriv->device, &configNum);
- if (kresult != kIOReturnSuccess)
- return darwin_to_libusb (kresult);
- *config = (int) configNum;
+ *config = (int) dpriv->active_config;
return 0;
}
@@ -728,6 +782,8 @@ static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int
if (dev_handle->claimed_interfaces & (1 << i))
darwin_claim_interface (dev_handle, i);
+ dpriv->active_config = config;
+
return 0;
}
@@ -811,7 +867,6 @@ static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int i
IOReturn kresult;
IOCFPlugInInterface **plugInInterface = NULL;
SInt32 score;
- uint8_t new_config;
/* current interface */
struct __darwin_interface *cInterface = &priv->interfaces[iface];
@@ -821,43 +876,11 @@ static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int i
return darwin_to_libusb (kresult);
/* make sure we have an interface */
- if (!usbInterface) {
- u_int8_t nConfig; /* Index of configuration to use */
- IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */
- /* Only a composite class device with no vendor-specific driver will
- be configured. Otherwise, we need to do it ourselves, or there
- will be no interfaces for the device. */
-
- usbi_info (HANDLE_CTX (dev_handle), "no interface found; selecting configuration" );
-
- kresult = (*(dpriv->device))->GetNumberOfConfigurations (dpriv->device, &nConfig);
- if (kresult != kIOReturnSuccess) {
- usbi_err (HANDLE_CTX (dev_handle), "GetNumberOfConfigurations: %s", darwin_error_str(kresult));
- return darwin_to_libusb(kresult);
- }
-
- if (nConfig < 1) {
- usbi_err (HANDLE_CTX (dev_handle), "GetNumberOfConfigurations: no configurations");
- return LIBUSB_ERROR_OTHER;
- }
-
- usbi_info (HANDLE_CTX (dev_handle), "device has %d configuration%s. using the first",
- (int)nConfig, (nConfig > 1 ? "s" : "") );
-
- /* Always use the first configuration */
- kresult = (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, 0, &configDesc);
- if (kresult != kIOReturnSuccess) {
- usbi_err (HANDLE_CTX (dev_handle), "GetConfigurationDescriptorPtr: %s",
- darwin_error_str(kresult));
-
- new_config = 1;
- } else
- new_config = configDesc->bConfigurationValue;
-
- usbi_info (HANDLE_CTX (dev_handle), "new configuration value is %d", new_config);
+ if (!usbInterface && dpriv->first_config != 0) {
+ usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config);
/* set the configuration */
- kresult = darwin_set_configuration (dev_handle, new_config);
+ kresult = darwin_set_configuration (dev_handle, dpriv->first_config);
if (kresult != LIBUSB_SUCCESS) {
usbi_err (HANDLE_CTX (dev_handle), "could not set configuration");
return kresult;