summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2011-09-06 12:40:47 +0200
committerHans de Goede <hdegoede@redhat.com>2011-09-06 14:08:28 +0200
commit4819d1362b550d88afcbdb1bd35704c34bf619ef (patch)
tree04622c55ddcbb1d103d44c44a3a8ed4db33166e5
parent230127c0c15b6e2407cc25e82b91abc8c5a915f8 (diff)
downloadgusb-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.c171
-rw-r--r--gusb/gusb-device.h28
-rw-r--r--gusb/gusb-self-test.c36
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);