| From 8d5b4aa632613f7107a5611ad6717c82ed1269fa Mon Sep 17 00:00:00 2001 |
| From: Dmitry Torokhov <dtor@chromium.org> |
| Date: Wed, 5 Jun 2019 11:25:28 -0700 |
| Subject: [PATCH 4/6] CHROMIUM: linux_usbfs: make use of port data from |
| USBFS_CONNINFO_EX |
| |
| Add a new backend operation get_port_numbers() and use information |
| returned by IOCTL_USBFS_CONNINFO_EX, when available, to return |
| connection path for the device. If backend or data is not available, let |
| core continue traversing the device tree and get the data from there. |
| |
| This especially is useful in cases where we are interfacing via file |
| descriptors passed to clients and device tree is not available. |
| |
| Signed-off-by: Dmitry Torokhov <dtor@chromium.org> |
| --- |
| libusb/core.c | 7 +++++++ |
| libusb/libusbi.h | 17 +++++++++++++++++ |
| libusb/os/linux_usbfs.c | 30 ++++++++++++++++++++++++++++++ |
| 3 files changed, 54 insertions(+) |
| |
| diff --git a/libusb/core.c b/libusb/core.c |
| index ec429b7c..05c67546 100644 |
| --- a/libusb/core.c |
| +++ b/libusb/core.c |
| @@ -948,6 +948,13 @@ int API_EXPORTED libusb_get_port_numbers(libusb_device *dev, |
| if (port_numbers_len <= 0) |
| return LIBUSB_ERROR_INVALID_PARAM; |
| |
| + if (usbi_backend.get_port_numbers) { |
| + int ret = usbi_backend.get_port_numbers(dev, port_numbers, |
| + port_numbers_len); |
| + if (ret != LIBUSB_ERROR_OTHER) |
| + return ret; |
| + } |
| + |
| // HCDs can be listed as devices with port #0 |
| while((dev) && (dev->port_number != 0)) { |
| if (--i < 0) { |
| diff --git a/libusb/libusbi.h b/libusb/libusbi.h |
| index b1fc88c9..46b87de6 100644 |
| --- a/libusb/libusbi.h |
| +++ b/libusb/libusbi.h |
| @@ -1135,6 +1135,23 @@ struct usbi_os_backend { |
| int (*get_config_descriptor_by_value)(struct libusb_device *device, |
| uint8_t bConfigurationValue, void **buffer); |
| |
| + /* Get the list of all port numbers from root for the specified device. |
| + * |
| + * Optional, if not present the core will attempt traversing device |
| + * tree to collect this data. |
| + * |
| + * Copies the list of port numbers into port_numbers (up to |
| + * port_numbers_len entries). |
| + * |
| + * Returns: |
| + * - number of entries in port_numbers array |
| + * - LIBUSB_ERROR_OVERFLOW if the array is too small |
| + * - LIBUSB_ERROR_OTHER if backend was not able to provide this |
| + * information |
| + */ |
| + int (*get_port_numbers)(struct libusb_device *device, |
| + uint8_t* port_numbers, int port_numbers_len); |
| + |
| /* Get the bConfigurationValue for the active configuration for a device. |
| * Optional. This should only be implemented if you can retrieve it from |
| * cache (don't generate I/O). |
| diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c |
| index 8348734a..9461f565 100644 |
| --- a/libusb/os/linux_usbfs.c |
| +++ b/libusb/os/linux_usbfs.c |
| @@ -125,6 +125,8 @@ struct linux_device_priv { |
| size_t descriptors_len; |
| struct config_descriptor *config_descriptors; |
| int active_config; /* cache val for !sysfs_available */ |
| + uint8_t *ports; |
| + int num_ports; |
| }; |
| |
| struct linux_device_handle_priv { |
| @@ -870,6 +872,21 @@ static int op_get_config_descriptor(struct libusb_device *dev, |
| return len; |
| } |
| |
| +static int op_get_port_numbers(struct libusb_device *dev, |
| + uint8_t* port_numbers, int port_numbers_len) |
| +{ |
| + struct linux_device_priv *priv = usbi_get_device_priv(dev); |
| + |
| + if (!priv->ports) |
| + return LIBUSB_ERROR_OTHER; |
| + |
| + if (priv->num_ports > port_numbers_len) |
| + return LIBUSB_ERROR_OVERFLOW; |
| + |
| + memcpy(port_numbers, priv->ports, priv->num_ports); |
| + return priv->num_ports; |
| +} |
| + |
| /* send a control message to retrieve active configuration */ |
| static int usbfs_get_active_config(struct libusb_device *dev, int fd) |
| { |
| @@ -1101,6 +1118,17 @@ static int initialize_from_usbfs(struct libusb_device *dev, int wrapped_fd) |
| dev->bus_number = ci.busnum; |
| dev->device_address = ci.devnum; |
| dev->speed = device_speed_from_kernel(ctx, ci.speed); |
| + |
| + /* Save port information */ |
| + if (ci.num_ports > 0 && |
| + ci.num_ports <= sizeof(ci.ports) / sizeof(ci.ports[0])) { |
| + dev->port_number = ci.ports[0]; |
| + priv->ports = malloc(ci.num_ports); |
| + if (!priv->ports) |
| + return LIBUSB_ERROR_NO_MEM; |
| + priv->num_ports = ci.num_ports; |
| + memcpy(priv->ports, ci.ports, ci.num_ports); |
| + } |
| } else { |
| dev->speed = usbfs_get_speed(ctx, fd); |
| } |
| @@ -1939,6 +1967,7 @@ static void op_destroy_device(struct libusb_device *dev) |
| { |
| struct linux_device_priv *priv = usbi_get_device_priv(dev); |
| |
| + free(priv->ports); |
| free(priv->config_descriptors); |
| free(priv->descriptors); |
| free(priv->sysfs_dir); |
| @@ -2867,6 +2896,7 @@ const struct usbi_os_backend usbi_backend = { |
| .get_active_config_descriptor = op_get_active_config_descriptor, |
| .get_config_descriptor = op_get_config_descriptor, |
| .get_config_descriptor_by_value = op_get_config_descriptor_by_value, |
| + .get_port_numbers = op_get_port_numbers, |
| |
| .wrap_sys_device = op_wrap_sys_device, |
| .open = op_open, |
| -- |
| 2.38.1.584.g0f3c55d4c2-goog |
| |