blob: c461bf975151b9645d7a1e35d82aaab836ec7360 [file] [log] [blame]
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