diff options
author | Richard Hughes <richard@hughsie.com> | 2011-08-16 17:06:54 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2011-08-16 17:06:56 +0100 |
commit | fb561b2fe3ed792b3e054bbed6b723900a609e7e (patch) | |
tree | af6d39ffb872af0f96c923b466abddb803ee9dda /gusb | |
parent | 195f12cf7bd688f02ab47f5a8aa9ebd62fefa281 (diff) | |
download | gusb-fb561b2fe3ed792b3e054bbed6b723900a609e7e.tar.gz |
Add functionality to GUsbDevice to do sync bulk, control and interrupt transfers
We'll be also adding _async() versions too which use a GUsbSource, and hopefully
then we can also do something sane with GCancellable.
Diffstat (limited to 'gusb')
-rw-r--r-- | gusb/gusb-device.c | 193 | ||||
-rw-r--r-- | gusb/gusb-device.h | 67 | ||||
-rw-r--r-- | gusb/gusb-self-test.c | 99 |
3 files changed, 359 insertions, 0 deletions
diff --git a/gusb/gusb-device.c b/gusb/gusb-device.c index 95d0768..f4e3734 100644 --- a/gusb/gusb-device.c +++ b/gusb/gusb-device.c @@ -278,6 +278,199 @@ out: } /** + * g_usb_device_control_transfer: + * @device: a #GUsbDevice + * @request_type: the request type field for the setup packet + * @request: the request field for the setup packet + * @value: the value field for the setup packet + * @index: the index field for the setup packet + * @data: a suitably-sized data buffer for either input or output + * @length: the length field for the setup packet. + * @actual_length: the actual number of bytes sent, or %NULL + * @timeout: timeout timeout (in millseconds) that this function should wait + * before giving up due to no response being received. For an unlimited + * timeout, use 0. + * @cancellable: a #GCancellable, or %NULL + * @error: a #GError, or %NULL + * + * Perform a USB control transfer. + * + * Warning: this function is syncronous, and cannot be cancelled. + * + * Return value: %TRUE on success + **/ +gboolean +g_usb_device_control_transfer (GUsbDevice *device, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 index, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = TRUE; + gint rc; + guint8 request_type_raw = 0; + + /* munge back to flags */ + if (direction == G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST) + request_type_raw |= 0x80; + request_type_raw |= (request_type << 5); + request_type_raw |= recipient; + + if (device->priv->handle == NULL) { + ret = FALSE; + g_set_error_literal (error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_OPEN, + "The device has not been opened"); + goto out; + } + + /* TODO: setup an async transfer so we can cancel it */ + rc = libusb_control_transfer (device->priv->handle, + request_type_raw, + request, + value, + index, + data, + length, + timeout); + if (rc < 0) { + ret = g_usb_device_libusb_error_to_gerror (device, rc, error); + goto out; + } + if (actual_length != NULL) + *actual_length = rc; +out: + return ret; +} + +/** + * g_usb_device_bulk_transfer: + * @device: a #GUsbDevice + * @endpoint: the address of a valid endpoint to communicate with + * @data: a suitably-sized data buffer for either input or output + * @length: the length field for the setup packet. + * @actual_length: the actual number of bytes sent, or %NULL + * @timeout: timeout timeout (in millseconds) that this function should wait + * before giving up due to no response being received. For an unlimited + * timeout, use 0. + * @cancellable: a #GCancellable, or %NULL + * @error: a #GError, or %NULL + * + * Perform a USB bulk transfer. + * + * Warning: this function is syncronous, and cannot be cancelled. + * + * Return value: %TRUE on success + **/ +gboolean +g_usb_device_bulk_transfer (GUsbDevice *device, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = TRUE; + gint rc; + gint transferred; + + if (device->priv->handle == NULL) { + ret = FALSE; + g_set_error_literal (error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_OPEN, + "The device has not been opened"); + goto out; + } + + /* TODO: setup an async transfer so we can cancel it */ + rc = libusb_bulk_transfer (device->priv->handle, + endpoint, + data, + length, + &transferred, + timeout); + if (rc < 0) { + ret = g_usb_device_libusb_error_to_gerror (device, rc, error); + goto out; + } + if (actual_length != NULL) + *actual_length = transferred; +out: + return ret; +} + +/** + * g_usb_device_interrupt_transfer: + * @device: a #GUsbDevice + * @endpoint: the address of a valid endpoint to communicate with + * @data: a suitably-sized data buffer for either input or output + * @length: the length field for the setup packet. + * @actual_length: the actual number of bytes sent, or %NULL + * @timeout: timeout timeout (in millseconds) that this function should wait + * before giving up due to no response being received. For an unlimited + * timeout, use 0. + * @cancellable: a #GCancellable, or %NULL + * @error: a #GError, or %NULL + * + * Perform a USB interrupt transfer. + * + * Warning: this function is syncronous, and cannot be cancelled. + * + * Return value: %TRUE on success + **/ +gboolean +g_usb_device_interrupt_transfer (GUsbDevice *device, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = TRUE; + gint rc; + gint transferred; + + if (device->priv->handle == NULL) { + ret = FALSE; + g_set_error_literal (error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_OPEN, + "The device has not been opened"); + goto out; + } + + /* TODO: setup an async transfer so we can cancel it */ + rc = libusb_interrupt_transfer (device->priv->handle, + endpoint, + data, + length, + &transferred, + timeout); + if (rc < 0) { + ret = g_usb_device_libusb_error_to_gerror (device, rc, error); + goto out; + } + if (actual_length != NULL) + *actual_length = transferred; +out: + return ret; +} + +/** * usb_device_set_property: **/ static void diff --git a/gusb/gusb-device.h b/gusb/gusb-device.h index f296a42..d1e9216 100644 --- a/gusb/gusb-device.h +++ b/gusb/gusb-device.h @@ -37,6 +37,40 @@ typedef struct _GUsbDevice GUsbDevice; typedef struct _GUsbDeviceClass GUsbDeviceClass; /** + * GUsbDeviceDirection: + * + * The message direction. + **/ +typedef enum { + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, /* IN */ + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE /* OUT */ +} GUsbDeviceDirection; + +/** + * GUsbDeviceRequestType: + * + * The message request type. + **/ +typedef enum { + G_USB_DEVICE_REQUEST_TYPE_STANDARD, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_REQUEST_TYPE_RESERVED +} GUsbDeviceRequestType; + +/** + * GUsbDeviceRecipient: + * + * The message recipient. + **/ +typedef enum { + G_USB_DEVICE_RECIPIENT_DEVICE, + G_USB_DEVICE_RECIPIENT_INTERFACE, + G_USB_DEVICE_RECIPIENT_ENDPOINT, + G_USB_DEVICE_RECIPIENT_OTHER +} GUsbDeviceRecipient; + +/** * GUsbDeviceError: * * The error code. @@ -80,6 +114,39 @@ gboolean g_usb_device_open (GUsbDevice *device, gboolean g_usb_device_close (GUsbDevice *device, GError **error); +/* sync -- TODO: use GCancellable and GUsbSource */ +gboolean g_usb_device_control_transfer (GUsbDevice *device, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 index, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error); + +gboolean g_usb_device_bulk_transfer (GUsbDevice *device, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error); + +gboolean g_usb_device_interrupt_transfer (GUsbDevice *device, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error); + G_END_DECLS #endif /* __GUSB_DEVICE_H__ */ diff --git a/gusb/gusb-self-test.c b/gusb/gusb-self-test.c index 5729d8d..0c09d23 100644 --- a/gusb/gusb-self-test.c +++ b/gusb/gusb-self-test.c @@ -178,6 +178,104 @@ gusb_device_list_func (void) g_object_unref (ctx); } +static void +gusb_device_huey_func (void) +{ + GUsbContext *ctx; + GUsbDeviceList *list; + GError *error = NULL; + GUsbDevice *device; + gboolean ret; + GCancellable *cancellable = NULL; + const gchar request[8] = { 0x0e, 'G', 'r', 'M', 'b', 'k', 'e', 'd' }; + + ctx = g_usb_context_new (&error); + g_assert_no_error (error); + g_assert (ctx != NULL); + + g_usb_context_set_debug (ctx, G_LOG_LEVEL_ERROR); + + list = g_usb_device_list_new (ctx); + g_assert (list != NULL); + + /* coldplug, and get the huey */ + g_usb_device_list_coldplug (list); + device = g_usb_device_list_find_by_vid_pid (list, + 0x0971, + 0x2005, + &error); + g_assert_no_error (error); + g_assert (device != NULL); + + /* close not opened */ + ret = g_usb_device_close (device, &error); + g_assert_error (error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_OPEN); + g_assert (!ret); + g_clear_error (&error); + + /* open */ + ret = g_usb_device_open (device, 0x01, 0x00, cancellable, &error); + g_assert_no_error (error); + g_assert (ret); + + /* open opened */ + ret = g_usb_device_open (device, 0x01, 0x00, cancellable, &error); + g_assert_error (error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_ALREADY_OPEN); + g_assert (!ret); + g_clear_error (&error); + + /* do a request (unlock) */ + ret = g_usb_device_control_transfer (device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + 0x09, /* request */ + 0x0200, /* value */ + 0, /* index */ + (guint8*) request, + 8, + NULL, + 2000, + cancellable, + &error); + g_assert_no_error (error); + g_assert (ret); + + /* do a request we know is going to fail */ + ret = g_usb_device_control_transfer (device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + 0x09, /* request */ + 0x0200, /* value */ + 0, /* index */ + (guint8*) request, + 8, + NULL, + 2000, + cancellable, + &error); + g_assert_error (error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED); + g_assert (!ret); + g_clear_error (&error); + + /* close */ + ret = g_usb_device_close (device, &error); + g_assert_no_error (error); + g_assert (ret); + + g_object_unref (device); + + g_object_unref (list); + g_object_unref (ctx); +} + int main (int argc, char **argv) { @@ -193,6 +291,7 @@ main (int argc, char **argv) g_test_add_func ("/gusb/source", gusb_source_func); g_test_add_func ("/gusb/device", gusb_device_func); g_test_add_func ("/gusb/device-list", gusb_device_list_func); + g_test_add_func ("/gusb/device[huey]", gusb_device_huey_func); return g_test_run (); } |