summaryrefslogtreecommitdiff
path: root/libusb/os/darwin_usb.c
diff options
context:
space:
mode:
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;