diff options
author | Hans de Goede <hdegoede@redhat.com> | 2011-09-06 12:40:47 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2011-09-06 14:08:28 +0200 |
commit | 4819d1362b550d88afcbdb1bd35704c34bf619ef (patch) | |
tree | 04622c55ddcbb1d103d44c44a3a8ed4db33166e5 | |
parent | 230127c0c15b6e2407cc25e82b91abc8c5a915f8 (diff) | |
download | gusb-4819d1362b550d88afcbdb1bd35704c34bf619ef.tar.gz |
gusb-device: Move setting config / claiming of interface to their own methods
Always doing a set-config on device open is not a good idea, see:
http://libusb.sourceforge.net/api-1.0/caveats.html
So remove the configuration parameter from g_usb_device_open and add a
g_usb_device_set_configuration instead which apps can use if they really
want to do a set_configuration (which most apps should not do).
Also add a g_usb_device_get_configuration method for completeness.
Likewise remove the interface parameter, an app may want to claim more
then one interface. And may even want to do some things which require
the device to be open without claiming any interfaces, like getting the
active configuration.
And add a g_usb_device_claim_interface method to replace the interface
parameter to g_usb_device_open. The new g_usb_device_claim_interface
can also automatically unbind any kernel drivers which are bound to
the interface before claiming it, this is controlled through the
flags parameter, by specifying the
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER flag.
Also add a g_usb_device_release_interface method for completeness.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | gusb/gusb-device.c | 171 | ||||
-rw-r--r-- | gusb/gusb-device.h | 28 | ||||
-rw-r--r-- | gusb/gusb-self-test.c | 36 |
3 files changed, 203 insertions, 32 deletions
diff --git a/gusb/gusb-device.c b/gusb/gusb-device.c index 0891498..0511b9d 100644 --- a/gusb/gusb-device.c +++ b/gusb/gusb-device.c @@ -212,9 +212,6 @@ static void g_usb_device_async_not_open_error(GUsbDevice *device, /** * g_usb_device_open: * @device: a #GUsbDevice - * @configuration: the configuration index to use, usually '1' - * @interface: the configuration interface to use, usually '0' - * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Opens the device for use. @@ -227,12 +224,8 @@ static void g_usb_device_async_not_open_error(GUsbDevice *device, **/ gboolean g_usb_device_open (GUsbDevice *device, - guint configuration, - guint interface, - GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; gint rc; g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); @@ -244,28 +237,12 @@ g_usb_device_open (GUsbDevice *device, "Device %04x:%04x is already open", g_usb_device_get_vid (device), g_usb_device_get_pid (device)); - goto out; + return FALSE; } /* open device */ rc = libusb_open (device->priv->device, &device->priv->handle); - ret = g_usb_device_libusb_error_to_gerror (device, rc, error); - if (!ret) - goto out; - - /* set configuration */ - rc = libusb_set_configuration (device->priv->handle, configuration); - ret = g_usb_device_libusb_error_to_gerror (device, rc, error); - if (!ret) - goto out; - - /* claim interface */ - rc = libusb_claim_interface (device->priv->handle, interface); - ret = g_usb_device_libusb_error_to_gerror (device, rc, error); - if (!ret) - goto out; -out: - return ret; + return g_usb_device_libusb_error_to_gerror (device, rc, error); } /** @@ -290,6 +267,150 @@ g_usb_device_close (GUsbDevice *device, GError **error) return TRUE; } +/** + * g_usb_device_get_configuration: + * @device: a #GUsbDevice + * @error: a #GError, or %NULL + * + * Get the bConfigurationValue for the active configuration of the device. + * + * Warning: this function is synchronous. + * + * Return value: The bConfigurationValue of the active config, or -1 on error + * + * Since: 0.1.0 + **/ +gint g_usb_device_get_configuration (GUsbDevice *device, + GError **error) +{ + gint rc; + int config; + + g_return_val_if_fail (G_USB_IS_DEVICE (device), -1); + + if (device->priv->handle == NULL) { + g_usb_device_not_open_error (device, error); + return -1; + } + + rc = libusb_get_configuration (device->priv->handle, &config); + if (rc != LIBUSB_SUCCESS) { + g_usb_device_libusb_error_to_gerror (device, rc, error); + return -1; + } + + return config; +} + +/** + * g_usb_device_set_configuration: + * @device: a #GUsbDevice + * @configuration: the configuration value to set + * @error: a #GError, or %NULL + * + * Set the active bConfigurationValue for the device. + * + * Warning: this function is synchronous. + * + * Return value: %TRUE on success + * + * Since: 0.1.0 + **/ +gboolean g_usb_device_set_configuration (GUsbDevice *device, + gint configuration, + GError **error) +{ + gint rc; + + g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); + + if (device->priv->handle == NULL) + return g_usb_device_not_open_error (device, error); + + rc = libusb_set_configuration (device->priv->handle, configuration); + return g_usb_device_libusb_error_to_gerror (device, rc, error); +} + +/** + * g_usb_device_claim_interface: + * @device: a #GUsbDevice + * @interface: bInterfaceNumber of the interface you wish to claim + * @flags: #GUsbDeviceClaimInterfaceFlags + * @error: a #GError, or %NULL + * + * Claim an interface of the device. + * + * Return value: %TRUE on success + * + * Since: 0.1.0 + **/ +gboolean g_usb_device_claim_interface (GUsbDevice *device, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error) +{ + gint rc; + + g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); + + if (device->priv->handle == NULL) + return g_usb_device_not_open_error (device, error); + + if (flags & G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER) { + rc = libusb_detach_kernel_driver (device->priv->handle, + interface); + if (rc != LIBUSB_SUCCESS && + rc != LIBUSB_ERROR_NOT_FOUND /* No driver attached */) + return g_usb_device_libusb_error_to_gerror (device, rc, + error); + } + + rc = libusb_claim_interface (device->priv->handle, interface); + return g_usb_device_libusb_error_to_gerror (device, rc, error); +} + +/** + * g_usb_device_release_interface: + * @device: a #GUsbDevice + * @interface: bInterfaceNumber of the interface you wish to release + * @flags: #GUsbDeviceClaimInterfaceFlags + * @error: a #GError, or %NULL + * + * Release an interface of the device. + * + * Return value: %TRUE on success + * + * Since: 0.1.0 + **/ +gboolean g_usb_device_release_interface (GUsbDevice *device, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error) +{ + gint rc; + + g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); + + if (device->priv->handle == NULL) + return g_usb_device_not_open_error (device, error); + + rc = libusb_release_interface (device->priv->handle, interface); + if (rc != LIBUSB_SUCCESS) + return g_usb_device_libusb_error_to_gerror (device, rc, error); + + if (flags & G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER) { + rc = libusb_attach_kernel_driver (device->priv->handle, + interface); + if (rc != LIBUSB_SUCCESS && + rc != LIBUSB_ERROR_NOT_FOUND && /* No driver attached */ + rc != LIBUSB_ERROR_BUSY /* driver rebound already */) + return g_usb_device_libusb_error_to_gerror (device, rc, + error); + } + + return TRUE; +} + typedef gssize (GUsbDeviceTransferFinishFunc) (GUsbDevice *device, GAsyncResult *res, GError **error); typedef struct { diff --git a/gusb/gusb-device.h b/gusb/gusb-device.h index acb6572..f10a9c0 100644 --- a/gusb/gusb-device.h +++ b/gusb/gusb-device.h @@ -87,6 +87,16 @@ typedef enum { G_USB_DEVICE_ERROR_LAST } GUsbDeviceError; +/** + * GUsbDeviceClaimInterfaceFlags: + * + * Flags for the g_usb_device_claim_interface and + * g_usb_device_release_interface methods flags parameters. + **/ +typedef enum { + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER = 1 << 0, +} GUsbDeviceClaimInterfaceFlags; + struct _GUsbDevice { GObject parent; @@ -109,13 +119,25 @@ guint16 g_usb_device_get_vid (GUsbDevice *device); guint16 g_usb_device_get_pid (GUsbDevice *device); gboolean g_usb_device_open (GUsbDevice *device, - guint configuration, - guint interface, - GCancellable *cancellable, GError **error); gboolean g_usb_device_close (GUsbDevice *device, GError **error); +gint g_usb_device_get_configuration (GUsbDevice *device, + GError **error); +gboolean g_usb_device_set_configuration (GUsbDevice *device, + gint configuration, + GError **error); + +gboolean g_usb_device_claim_interface (GUsbDevice *device, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error); +gboolean g_usb_device_release_interface (GUsbDevice *device, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error); + /* sync -- TODO: use GCancellable and GUsbSource */ gboolean g_usb_device_control_transfer (GUsbDevice *device, GUsbDeviceDirection direction, diff --git a/gusb/gusb-self-test.c b/gusb/gusb-self-test.c index 14c8038..81df02f 100644 --- a/gusb/gusb-self-test.c +++ b/gusb/gusb-self-test.c @@ -223,18 +223,25 @@ gusb_device_huey_func (void) g_clear_error (&error); /* open */ - ret = g_usb_device_open (device, 0x01, 0x00, cancellable, &error); + ret = g_usb_device_open (device, &error); g_assert_no_error (error); g_assert (ret); /* open opened */ - ret = g_usb_device_open (device, 0x01, 0x00, cancellable, &error); + ret = g_usb_device_open (device, &error); g_assert_error (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_ALREADY_OPEN); g_assert (!ret); g_clear_error (&error); + /* claim interface 0 */ + ret = g_usb_device_claim_interface (device, 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error (error); + g_assert (ret); + /* do a request (unlock) */ ret = g_usb_device_control_transfer (device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, @@ -272,6 +279,13 @@ gusb_device_huey_func (void) g_assert (!ret); g_clear_error (&error); + /* release interface 0 */ + ret = g_usb_device_release_interface (device, 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error (error); + g_assert (ret); + /* close */ ret = g_usb_device_close (device, &error); g_assert_no_error (error); @@ -382,18 +396,25 @@ gusb_device_munki_func (void) g_clear_error (&error); /* open */ - ret = g_usb_device_open (device, 0x01, 0x00, cancellable, &error); + ret = g_usb_device_open (device, &error); g_assert_no_error (error); g_assert (ret); /* open opened */ - ret = g_usb_device_open (device, 0x01, 0x00, cancellable, &error); + ret = g_usb_device_open (device, &error); g_assert_error (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_ALREADY_OPEN); g_assert (!ret); g_clear_error (&error); + /* claim interface 0 */ + ret = g_usb_device_claim_interface (device, 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error (error); + g_assert (ret); + /* do a request (get chip id) */ ret = g_usb_device_control_transfer (device, G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, @@ -447,6 +468,13 @@ gusb_device_munki_func (void) g_main_loop_run (helper->loop); g_main_loop_unref (helper->loop); + /* release interface 0 */ + ret = g_usb_device_release_interface (device, 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error (error); + g_assert (ret); + /* close */ ret = g_usb_device_close (device, &error); g_assert_no_error (error); |