summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2022-09-03 16:58:19 +0100
committerRichard Hughes <richard@hughsie.com>2022-09-04 20:01:09 +0100
commit36f53da169cd5ad7f690b682729f35d057353758 (patch)
treec24b2a55472ae74642e2cf7d9a2604d962f64a27
parent6eb98600ad27e089ac7bca02972a23fcda2390db (diff)
downloadgusb-36f53da169cd5ad7f690b682729f35d057353758.tar.gz
Add support for getting BOS descriptors
-rw-r--r--gusb/gusb-bos-descriptor-private.h18
-rw-r--r--gusb/gusb-bos-descriptor.c109
-rw-r--r--gusb/gusb-bos-descriptor.h20
-rw-r--r--gusb/gusb-device.c103
-rw-r--r--gusb/gusb-device.h7
-rw-r--r--gusb/gusb.h1
-rw-r--r--gusb/libgusb.ver10
-rw-r--r--gusb/meson.build7
8 files changed, 275 insertions, 0 deletions
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 <richard@hughsie.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include <libusb.h>
+
+#include <gusb/gusb-bos-descriptor.h>
+
+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 <richard@hughsie.com>
+ *
+ * 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 <string.h>
+
+#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 <richard@hughsie.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+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:
@@ -607,6 +608,108 @@ g_usb_device_get_interfaces (GUsbDevice *device, GError **error)
}
/**
+ * 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
* @error: a #GError, or %NULL
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 <gusb/gusb-util.h>
#include <gusb/gusb-interface.h>
+#include <gusb/gusb-bos-descriptor.h>
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 <gusb/gusb-autocleanups.h>
#include <gusb/gusb-context.h>
#include <gusb/gusb-interface.h>
+#include <gusb/gusb-bos-descriptor.h>
#include <gusb/gusb-endpoint.h>
#include <gusb/gusb-source.h>
#include <gusb/gusb-device.h>
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',