libusb: implement libusb_get_parent

Newer versions of drivers such as libwacom (graphics tablets) or
libfprint (fingerprint scanners) call g_usb_device_get_parent.  This in
turn calls libusb_get_parent on platforms which implement it, and
returns NULL on platforms that don't.  This patch implements this
function on FreeBSD.

Reviewed by:	bapt, kevans
Differential Revision:	https://reviews.freebsd.org/D46992
This commit is contained in:
Aymeric Wibo 2025-06-12 11:54:13 -05:00 committed by Kyle Evans
parent 55efb3bf2b
commit 4c556a4e8d
4 changed files with 41 additions and 4 deletions

View file

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd May 16, 2025
.Dd June 12, 2025
.Dt LIBUSB 3
.Os
.Sh NAME
@ -117,7 +117,7 @@ This function does not return NULL.
.Fn libusb_set_debug "libusb_context *ctx" "int level"
Set the debug level to
.Fa level .
.Pp
.Sh DEVICE HANDLING AND ENUMERATION
.Ft ssize_t
.Fn libusb_get_device_list "libusb_context *ctx" "libusb_device ***list"
Populate
@ -220,6 +220,11 @@ Close a device handle.
Get the device contained by devh.
Returns NULL on error.
.Pp
.Ft libusb_device *
.Fn libusb_get_parent "libusb_device *dev"
Get dev's parent device.
Returns NULL if the device has no parent (i.e. is a root device).
.Pp
.Ft int
.Fn libusb_get_configuration "libusb_device_handle *devh" "int *config"
Returns the value of the current configuration.

View file

@ -503,6 +503,7 @@ int libusb_open(libusb_device * dev, libusb_device_handle ** devh);
libusb_device_handle *libusb_open_device_with_vid_pid(libusb_context * ctx, uint16_t vendor_id, uint16_t product_id);
void libusb_close(libusb_device_handle * devh);
libusb_device *libusb_get_device(libusb_device_handle * devh);
libusb_device *libusb_get_parent(libusb_device * dev);
int libusb_get_configuration(libusb_device_handle * devh, int *config);
int libusb_set_configuration(libusb_device_handle * devh, int configuration);
int libusb_claim_interface(libusb_device_handle * devh, int interface_number);

View file

@ -3,6 +3,7 @@
*
* Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
* Copyright (c) 2009-2023 Hans Petter Selasky
* Copyright (c) 2024 Aymeric Wibo
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -311,9 +312,9 @@ ssize_t
libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
{
struct libusb20_backend *usb_backend;
struct libusb20_device *pdev;
struct libusb20_device *pdev, *parent_dev;
struct libusb_device *dev;
int i;
int i, j, k;
ctx = GET_CONTEXT(ctx);
@ -365,6 +366,9 @@ libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
/* set context we belong to */
dev->ctx = ctx;
/* assume we have no parent by default */
dev->parent_dev = NULL;
/* link together the two structures */
dev->os_priv = pdev;
pdev->privLuData = dev;
@ -374,6 +378,25 @@ libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
}
(*list)[i] = NULL;
/* for each device, find its parent */
for (j = 0; j < i; j++) {
pdev = (*list)[j]->os_priv;
for (k = 0; k < i; k++) {
if (k == j)
continue;
parent_dev = (*list)[k]->os_priv;
if (parent_dev->bus_number != pdev->bus_number)
continue;
if (parent_dev->device_address == pdev->parent_address) {
(*list)[j]->parent_dev = libusb_ref_device((*list)[k]);
break;
}
}
}
libusb20_be_free(usb_backend);
return (i);
}
@ -540,6 +563,7 @@ libusb_unref_device(libusb_device *dev)
CTX_UNLOCK(dev->ctx);
if (dev->refcnt == 0) {
libusb_unref_device(dev->parent_dev);
libusb20_dev_free(dev->os_priv);
free(dev);
}
@ -816,6 +840,12 @@ libusb_set_interface_alt_setting(struct libusb20_device *pdev,
return (err ? LIBUSB_ERROR_OTHER : 0);
}
libusb_device *
libusb_get_parent(libusb_device *dev)
{
return (dev->parent_dev);
}
static struct libusb20_transfer *
libusb10_get_transfer(struct libusb20_device *pdev,
uint8_t endpoint, uint8_t xfer_index)

View file

@ -142,6 +142,7 @@ struct libusb_device {
struct libusb_super_pollfd dev_poll;
struct libusb_context *ctx;
struct libusb_device *parent_dev;
TAILQ_ENTRY(libusb_device) hotplug_entry;