From 36f53da169cd5ad7f690b682729f35d057353758 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 3 Sep 2022 16:58:19 +0100 Subject: Add support for getting BOS descriptors --- gusb/gusb-bos-descriptor-private.h | 18 ++++++ gusb/gusb-bos-descriptor.c | 109 +++++++++++++++++++++++++++++++++++++ gusb/gusb-bos-descriptor.h | 20 +++++++ gusb/gusb-device.c | 103 +++++++++++++++++++++++++++++++++++ gusb/gusb-device.h | 7 +++ gusb/gusb.h | 1 + gusb/libgusb.ver | 10 ++++ gusb/meson.build | 7 +++ 8 files changed, 275 insertions(+) create mode 100644 gusb/gusb-bos-descriptor-private.h create mode 100644 gusb/gusb-bos-descriptor.c create mode 100644 gusb/gusb-bos-descriptor.h diff --git a/gusb/gusb-bos-descriptor-private.h b/gusb/gusb-bos-descriptor-private.h new file mode 100644 index 0000000..4db8320 --- /dev/null +++ b/gusb/gusb-bos-descriptor-private.h @@ -0,0 +1,18 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include + +G_BEGIN_DECLS + +GUsbBosDescriptor *_g_usb_bos_descriptor_new (const struct libusb_bos_dev_capability_descriptor *bos_cap); + +G_END_DECLS diff --git a/gusb/gusb-bos-descriptor.c b/gusb/gusb-bos-descriptor.c new file mode 100644 index 0000000..b0664f8 --- /dev/null +++ b/gusb/gusb-bos-descriptor.c @@ -0,0 +1,109 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/** + * SECTION:gusb-bos-descriptor + * @short_description: GLib wrapper around a USB BOS descriptor. + * + * This object is a thin glib wrapper around a `libusb_bos_dev_capability_descriptor`. + * + * All the data is copied when the object is created and the original descriptor can be destroyed + * at any point. + */ + +#include "config.h" + +#include + +#include "gusb-bos-descriptor-private.h" + +struct _GUsbBosDescriptor +{ + GObject parent_instance; + + struct libusb_bos_dev_capability_descriptor bos_cap; + GBytes *extra; +}; + +G_DEFINE_TYPE (GUsbBosDescriptor, g_usb_bos_descriptor, G_TYPE_OBJECT) + +static void +g_usb_bos_descriptor_finalize (GObject *object) +{ + GUsbBosDescriptor *self = G_USB_BOS_DESCRIPTOR (object); + + g_bytes_unref (self->extra); + + G_OBJECT_CLASS (g_usb_bos_descriptor_parent_class)->finalize (object); +} + +static void +g_usb_bos_descriptor_class_init (GUsbBosDescriptorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = g_usb_bos_descriptor_finalize; +} + +static void +g_usb_bos_descriptor_init (GUsbBosDescriptor *self) +{ +} + +/** + * _g_usb_bos_descriptor_new: + * + * Return value: a new #GUsbBosDescriptor object. + * + * Since: 0.4.0 + **/ +GUsbBosDescriptor * +_g_usb_bos_descriptor_new (const struct libusb_bos_dev_capability_descriptor *bos_cap) +{ + GUsbBosDescriptor *self; + self = g_object_new (G_USB_TYPE_BOS_DESCRIPTOR, NULL); + + /* copy the data */ + memcpy (&self->bos_cap, bos_cap, sizeof (*bos_cap)); + self->extra = g_bytes_new (bos_cap->dev_capability_data, bos_cap->bLength - 0x03); + + return G_USB_BOS_DESCRIPTOR (self); +} + +/** + * g_usb_bos_descriptor_get_capability: + * @self: a #GUsbBosDescriptor + * + * Gets the BOS descriptor capability. + * + * Return value: capability + * + * Since: 0.4.0 + **/ +guint8 +g_usb_bos_descriptor_get_capability (GUsbBosDescriptor *self) +{ + g_return_val_if_fail (G_USB_IS_BOS_DESCRIPTOR (self), 0); + return self->bos_cap.bDevCapabilityType; +} + +/** + * g_usb_bos_descriptor_get_extra: + * @self: a #GUsbBosDescriptor + * + * Gets any extra data from the BOS descriptor. + * + * Return value: (transfer none): a #GBytes, or %NULL for failure + * + * Since: 0.4.0 + **/ +GBytes * +g_usb_bos_descriptor_get_extra (GUsbBosDescriptor *self) +{ + g_return_val_if_fail (G_USB_IS_BOS_DESCRIPTOR (self), NULL); + return self->extra; +} diff --git a/gusb/gusb-bos-descriptor.h b/gusb/gusb-bos-descriptor.h new file mode 100644 index 0000000..813779e --- /dev/null +++ b/gusb/gusb-bos-descriptor.h @@ -0,0 +1,20 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define G_USB_TYPE_BOS_DESCRIPTOR (g_usb_bos_descriptor_get_type ()) +G_DECLARE_FINAL_TYPE (GUsbBosDescriptor, g_usb_bos_descriptor, G_USB, BOS_DESCRIPTOR, GObject) + +guint8 g_usb_bos_descriptor_get_capability (GUsbBosDescriptor *self); +GBytes *g_usb_bos_descriptor_get_extra (GUsbBosDescriptor *self); + +G_END_DECLS diff --git a/gusb/gusb-device.c b/gusb/gusb-device.c index 81f90ad..beec181 100644 --- a/gusb/gusb-device.c +++ b/gusb/gusb-device.c @@ -24,6 +24,7 @@ #include "gusb-util.h" #include "gusb-device-private.h" #include "gusb-interface-private.h" +#include "gusb-bos-descriptor-private.h" /** * GUsbDevicePrivate: @@ -606,6 +607,108 @@ g_usb_device_get_interfaces (GUsbDevice *device, GError **error) return array; } +/** + * g_usb_device_get_bos_descriptor: + * @device: a #GUsbDevice + * @capability: a BOS capability type + * @error: a #GError, or %NULL + * + * Gets the first bos_descriptor that matches the descriptor capability. + * If you want to find all the BOS descriptors that match (there may be other matching BOS + * descriptors you have to use `g_usb_device_get_bos_descriptors()` and check each one manually. + * + * Return value: (transfer full): a #GUsbBosDescriptor or %NULL for not found + * + * Since: 0.4.0 + **/ +GUsbBosDescriptor * +g_usb_device_get_bos_descriptor (GUsbDevice *device, + guint8 capability, + GError **error) +{ + gint rc; + guint8 num_device_caps; + GUsbBosDescriptor *bos_descriptor = NULL; + struct libusb_bos_descriptor *bos = NULL; + + g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + rc = libusb_get_bos_descriptor (device->priv->handle, &bos); + if (!g_usb_device_libusb_error_to_gerror (device, rc, error)) + return NULL; + + /* find the right data */ +#ifdef __FreeBSD__ + num_device_caps = bos->bNumDeviceCapabilities; +#else + num_device_caps = bos->bNumDeviceCaps; +#endif + for (guint i = 0; i < num_device_caps; i++) { + struct libusb_bos_dev_capability_descriptor *bos_cap = bos->dev_capability[i]; + if (bos_cap->bDevCapabilityType == capability) { + bos_descriptor = _g_usb_bos_descriptor_new (bos_cap); + break; + } + } + + /* nothing matched */ + if (bos_descriptor == NULL) { + g_set_error (error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED, + "no BOS descriptor for capability 0x%02x", + capability); + } + + libusb_free_bos_descriptor (bos); + return bos_descriptor; +} + +/** + * g_usb_device_get_bos_descriptors: + * @device: a #GUsbDevice + * @error: a #GError, or %NULL + * + * Gets all the BOS descriptors exported by the device. + * + * Return value: (transfer container) (element-type GUsbBosDescriptor): an array of BOS descriptors + * + * Since: 0.4.0 + **/ +GPtrArray * +g_usb_device_get_bos_descriptors (GUsbDevice *device, GError **error) +{ + gint rc; + guint8 num_device_caps; + struct libusb_bos_descriptor *bos = NULL; + GPtrArray *array = NULL; + + g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + rc = libusb_get_bos_descriptor (device->priv->handle, &bos); + if (!g_usb_device_libusb_error_to_gerror (device, rc, error)) + return NULL; + + /* get all BOS descriptors */ + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +#ifdef __FreeBSD__ + num_device_caps = bos->bNumDeviceCapabilities; +#else + num_device_caps = bos->bNumDeviceCaps; +#endif + for (guint i = 0; i < num_device_caps; i++) { + GUsbBosDescriptor *bos_descriptor = NULL; + struct libusb_bos_dev_capability_descriptor *bos_cap = bos->dev_capability[i]; + bos_descriptor = _g_usb_bos_descriptor_new (bos_cap); + g_ptr_array_add (array, bos_descriptor); + } + + libusb_free_bos_descriptor (bos); + return array; +} + /** * g_usb_device_close: * @device: a #GUsbDevice diff --git a/gusb/gusb-device.h b/gusb/gusb-device.h index 34085f9..a4f6140 100644 --- a/gusb/gusb-device.h +++ b/gusb/gusb-device.h @@ -12,6 +12,7 @@ #include #include +#include G_BEGIN_DECLS @@ -184,6 +185,12 @@ GUsbInterface *g_usb_device_get_interface (GUsbDevice *device, GPtrArray *g_usb_device_get_interfaces (GUsbDevice *device, GError **error); +GPtrArray *g_usb_device_get_bos_descriptors(GUsbDevice *device, + GError **error); +GUsbBosDescriptor *g_usb_device_get_bos_descriptor(GUsbDevice *device, + guint8 capability, + GError **error); + gboolean g_usb_device_open (GUsbDevice *device, GError **error); gboolean g_usb_device_close (GUsbDevice *device, diff --git a/gusb/gusb.h b/gusb/gusb.h index 96f860c..d8ffea0 100644 --- a/gusb/gusb.h +++ b/gusb/gusb.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/gusb/libgusb.ver b/gusb/libgusb.ver index 5bf17f7..2bdd669 100644 --- a/gusb/libgusb.ver +++ b/gusb/libgusb.ver @@ -166,3 +166,13 @@ LIBGUSB_0.3.10 { g_usb_context_set_hotplug_poll_interval; local: *; } LIBGUSB_0.3.8; + +LIBGUSB_0.4.0 { + global: + g_usb_bos_descriptor_get_capability; + g_usb_bos_descriptor_get_extra; + g_usb_bos_descriptor_get_type; + g_usb_device_get_bos_descriptor; + g_usb_device_get_bos_descriptors; + local: *; +} LIBGUSB_0.3.10; diff --git a/gusb/meson.build b/gusb/meson.build index 243b0be..150e8b5 100644 --- a/gusb/meson.build +++ b/gusb/meson.build @@ -34,6 +34,8 @@ install_headers([ 'gusb-device-list.h', 'gusb-interface.h', 'gusb-interface-private.h', + 'gusb-bos-descriptor.h', + 'gusb-bos-descriptor-private.h', 'gusb-endpoint.h', 'gusb-endpoint-private.h', 'gusb-source.h', @@ -56,6 +58,7 @@ gusb = library( 'gusb-device.c', 'gusb-device-list.c', 'gusb-interface.c', + 'gusb-bos-descriptor.c', 'gusb-endpoint.c', 'gusb-source.c', 'gusb-util.c', @@ -115,6 +118,9 @@ libgusb_girtarget = gnome.generate_gir(gusb, 'gusb-interface.c', 'gusb-interface.h', 'gusb-interface-private.h', + 'gusb-bos-descriptor.c', + 'gusb-bos-descriptor.h', + 'gusb-bos-descriptor-private.h', 'gusb-endpoint.c', 'gusb-endpoint.h', 'gusb-endpoint-private.h', @@ -196,6 +202,7 @@ if get_option('tests') 'gusb-device.c', 'gusb-device-list.c', 'gusb-interface.c', + 'gusb-bos-descriptor.c', 'gusb-endpoint.c', 'gusb-self-test.c', 'gusb-source.c', -- cgit v1.2.1