v2, that takes into account what was discussed previously (but still
provides get_parent).
Regards,
/Pete
>From 4ff57d754aed031b8b73e161e56064338b4bd06a Mon Sep 17 00:00:00 2001
From: Pete Batard <p...@akeo.ie>
Date: Mon, 14 May 2012 11:44:00 +0100
Subject: [PATCH] All: Add parent and port topology calls
* Adds libusb_get_port_number, libusb_get_parent and libusb_get_port_path
* Linux implementation provided by Alan Stern, OS X by Nathan Hjelm
---
examples/xusb.c | 4 ---
libusb/core.c | 64 +++++++++++++++++++++++++++++++++++++++++++
libusb/libusb.h | 3 ++
libusb/libusbi.h | 2 +
libusb/os/darwin_usb.c | 69 ++++++++++++++++++++++++++++++++++++++++-------
libusb/os/linux_usbfs.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usb.c | 2 +
7 files changed, 200 insertions(+), 15 deletions(-)
diff --git a/examples/xusb.c b/examples/xusb.c
index 2c0409f..5bf63f8 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -576,9 +576,7 @@ static int test_device(uint16_t vid, uint16_t pid)
{
libusb_device_handle *handle;
libusb_device *dev;
-#ifdef HAS_GETPORTPATH
uint8_t bus, port_path[8];
-#endif
struct libusb_config_descriptor *conf_desc;
const struct libusb_endpoint_descriptor *endpoint;
int i, j, k, r;
@@ -603,7 +601,6 @@ static int test_device(uint16_t vid, uint16_t pid)
}
dev = libusb_get_device(handle);
-#ifdef HAS_GETPORTPATH
bus = libusb_get_bus_number(dev);
r = libusb_get_port_path(NULL, dev, port_path, sizeof(port_path));
if (r > 0) {
@@ -613,7 +610,6 @@ static int test_device(uint16_t vid, uint16_t pid)
}
printf("\n");
}
-#endif
r = libusb_get_device_speed(dev);
if ((r<0) || (r>4)) r=0;
printf("speed: %s\n", speed_name[r]);
diff --git a/libusb/core.c b/libusb/core.c
index 2c3de76..6defd0a 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -660,6 +660,70 @@ uint8_t API_EXPORTED libusb_get_bus_number(libusb_device
*dev)
}
/** \ingroup dev
+ * Get the number of the port that a device is connected to
+ * \param dev a device
+ * \returns the port number (0 if not available)
+ */
+uint8_t API_EXPORTED libusb_get_port_number(libusb_device *dev)
+{
+ return dev->port_number;
+}
+
+/** \ingroup dev
+ * Get the list of all port numbers from root for the specified device
+ * \param dev a device
+ * \param path the array that should contain the port numbers
+ * \param path_len the maximum length of the array. As per the USB 3.0
+ * specs, the current maximum limit for the depth is 7.
+ * \returns the number of elements filled
+ * \returns LIBUSB_ERROR_OVERFLOW if the array is too small
+ */
+int API_EXPORTED libusb_get_port_path(libusb_context *ctx, libusb_device *dev,
uint8_t* path, uint8_t path_len)
+{
+ int i = path_len;
+ ssize_t r;
+ struct libusb_device **devs;
+
+ /* The device needs to be open, else the parents may have been
destroyed */
+ r = libusb_get_device_list(ctx, &devs);
+ if (r < 0)
+ return (int)r;
+
+ while(dev) {
+ // HCDs can be listed as devices and would have port #0
+ // TODO: see how the other backends want to implement HCDs as
parents
+ if (dev->port_number == 0)
+ break;
+ i--;
+ if (i < 0) {
+ return LIBUSB_ERROR_OVERFLOW;
+ }
+ path[i] = dev->port_number;
+ dev = dev->parent_dev;
+ }
+ libusb_free_device_list(devs, 1);
+ memmove(path, &path[i], path_len-i);
+ return path_len-i;
+}
+
+/** \ingroup dev
+ * Get the the parent from the specified device
+ * \param dev a device
+ * \returns the device parent or NULL if not available
+ * You should issue a libusb_get_device_list() before calling this
+ * function and make sure that you only access the parent before issuing
+ * libusb_free_device_list(). The reason is that libusbx currently does
+ * not maintain a permanent list of device instances, and therefore can
+ * only guarantee that parents are fully instantiated within a
+ * libusb_get_device_list() - libusb_free_device_list() block.
+ */
+DEFAULT_VISIBILITY
+libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev)
+{
+ return dev->parent_dev;
+}
+
+/** \ingroup dev
* Get the address of the device on the bus it is connected to.
* \param dev a device
* \returns the device address
diff --git a/libusb/libusb.h b/libusb/libusb.h
index 3e91275..6748b43 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -976,6 +976,9 @@ int LIBUSB_CALL
libusb_get_config_descriptor_by_value(libusb_device *dev,
void LIBUSB_CALL libusb_free_config_descriptor(
struct libusb_config_descriptor *config);
uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev);
+uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev);
+libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev);
+int LIBUSB_CALL libusb_get_port_path(libusb_context *ctx, libusb_device *dev,
uint8_t* path, uint8_t path_length);
uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev);
int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev);
int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index b8abab5..e04d4c2 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -293,6 +293,8 @@ struct libusb_device {
struct libusb_context *ctx;
uint8_t bus_number;
+ uint8_t port_number;
+ struct libusb_device* parent_dev;
uint8_t device_address;
uint8_t num_configurations;
enum libusb_speed speed;
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index e6e514e..51ebdfe 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -185,11 +185,26 @@ static int usb_setup_device_iterator (io_iterator_t
*deviceIterator, long locati
return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict,
deviceIterator);
}
-static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator,
UInt32 *locationp) {
+static int get_ioregistry_value_number (io_service_t service, CFStringRef
property, CFNumberType type, void *p) {
+ CFTypeRef cfNumber = IORegistryEntryCreateCFProperty (service, property,
kCFAllocatorDefault, 0);
+ int ret = 0;
+
+ if (cfNumber) {
+ if (CFGetTypeID(cfNumber) == CFNumberGetTypeID()) {
+ ret = CFNumberGetValue(cfNumber, type, p);
+ }
+
+ CFRelease (cfNumber);
+ }
+
+ return ret;
+}
+
+static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator,
UInt32 *locationp, UInt8 *portp, UInt32 *parent_locationp) {
io_cf_plugin_ref_t *plugInInterface = NULL;
usb_device_t **device;
- io_service_t usbDevice;
- long result;
+ io_service_t usbDevice, parent;
+ kern_return_t result;
SInt32 score;
if (!IOIteratorIsValid (deviceIterator))
@@ -203,6 +218,22 @@ static usb_device_t **usb_get_next_device (io_iterator_t
deviceIterator, UInt32
/* we are done with the usb_device_t */
(void)IOObjectRelease(usbDevice);
+
+ if (portp) {
+ *portp = 0;
+ (void) get_ioregistry_value_number (usbDevice, CFSTR("PortNum"),
kCFNumberSInt8Type, portp);
+ }
+
+ if (parent_locationp) {
+ *parent_locationp = 0;
+
+ result = IORegistryEntryGetParentEntry (usbDevice, kIOUSBPlane, &parent);
+
+ if (kIOReturnSuccess == result) {
+ (void) get_ioregistry_value_number (parent, CFSTR("locationID"),
kCFNumberLongType, parent_locationp);
+ }
+ }
+
if (kIOReturnSuccess == result && plugInInterface)
break;
@@ -235,7 +266,7 @@ static kern_return_t darwin_get_device (uint32_t
dev_location, usb_device_t ***d
return kresult;
/* This port of libusb uses locations to keep track of devices. */
- while ((*darwin_device = usb_get_next_device (deviceIterator, &location)) !=
NULL) {
+ while ((*darwin_device = usb_get_next_device (deviceIterator, &location,
NULL, NULL)) != NULL) {
if (location == dev_location)
break;
@@ -691,9 +722,11 @@ static int darwin_cache_device_descriptor (struct
libusb_context *ctx, struct li
return 0;
}
-static int process_new_device (struct libusb_context *ctx, usb_device_t
**device, UInt32 locationID, struct discovered_devs **_discdevs) {
+static int process_new_device (struct libusb_context *ctx, usb_device_t
**device, UInt32 locationID,
+ UInt32 parent_location, UInt8 port, struct
discovered_devs **_discdevs) {
struct darwin_device_priv *priv;
- struct libusb_device *dev;
+ static struct libusb_device *last_dev = NULL;
+ struct libusb_device *dev, *parent = NULL;
struct discovered_devs *discdevs;
UInt16 address;
UInt8 devSpeed;
@@ -726,6 +759,19 @@ static int process_new_device (struct libusb_context *ctx,
usb_device_t **device
if (ret < 0)
break;
+ /* the device iterator provides devices in increasing order of location.
given this property
+ * we can use the last device to find the parent. */
+ for (parent = last_dev ; parent ; parent = parent->parent_dev) {
+ struct darwin_device_priv *parent_priv = (struct darwin_device_priv *)
parent->os_priv;
+
+ if (parent_priv->location == parent_location) {
+ break;
+ }
+ }
+
+ dev->parent_dev = parent;
+
+ dev->port_number = port;
dev->bus_number = locationID >> 24;
dev->device_address = address;
@@ -756,8 +802,10 @@ static int process_new_device (struct libusb_context *ctx,
usb_device_t **device
}
*_discdevs = discdevs;
+ last_dev = dev;
- usbi_info (ctx, "found device with address %d at %s", dev->device_address,
priv->sys_path);
+ usbi_info (ctx, "found device with address %d port = %d parent = %p at
%p", dev->device_address,
+ dev->port_number, priv->sys_path, (void *) parent);
} while (0);
if (need_unref)
@@ -770,14 +818,15 @@ static int darwin_get_device_list(struct libusb_context
*ctx, struct discovered_
io_iterator_t deviceIterator;
usb_device_t **device;
kern_return_t kresult;
- UInt32 location;
+ UInt32 location, parent_location;
+ UInt8 port;
kresult = usb_setup_device_iterator (&deviceIterator, 0);
if (kresult != kIOReturnSuccess)
return darwin_to_libusb (kresult);
- while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
- (void) process_new_device (ctx, device, location, _discdevs);
+ while ((device = usb_get_next_device (deviceIterator, &location, &port,
&parent_location)) != NULL) {
+ (void) process_new_device (ctx, device, location, parent_location, port,
_discdevs);
(*(device))->Release(device);
}
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index a6114ca..a9e4ca0 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1157,6 +1157,74 @@ static int sysfs_scan_device(struct libusb_context *ctx,
devname);
}
+static void sysfs_analyze_topology(struct discovered_devs *discdevs)
+{
+ struct linux_device_priv *priv;
+ int i, j;
+ struct libusb_device *dev1, *dev2;
+ const char *sysfs_dir1, *sysfs_dir2;
+ const char *p;
+ int n, boundary_char;
+
+ /* Fill in the port_number and parent_dev fields for each device */
+
+ for (i = 0; i < discdevs->len; ++i) {
+ dev1 = discdevs->devices[i];
+ priv = _device_priv(dev1);
+ if (!priv)
+ continue;
+ sysfs_dir1 = priv->sysfs_dir;
+
+ /* Root hubs have sysfs_dir names of the form "usbB",
+ * where B is the bus number. All other devices have
+ * sysfs_dir names of the form "B-P[.P ...]", where the
+ * P values are port numbers leading from the root hub
+ * to the device.
+ */
+
+ /* Root hubs don't have parents or port numbers */
+ if (sysfs_dir1[0] == 'u')
+ continue;
+
+ /* The rightmost component is the device's port number */
+ p = strrchr(sysfs_dir1, '.');
+ if (!p) {
+ p = strchr(sysfs_dir1, '-');
+ if (!p)
+ continue; /* Should never happen */
+ }
+ dev1->port_number = atoi(p + 1);
+
+ /* Search for the parent device */
+ boundary_char = *p;
+ n = p - sysfs_dir1;
+ for (j = 0; j < discdevs->len; ++j) {
+ dev2 = discdevs->devices[j];
+ priv = _device_priv(dev2);
+ if (!priv)
+ continue;
+ sysfs_dir2 = priv->sysfs_dir;
+
+ if (boundary_char == '-') {
+ /* The parent's name must begin with 'usb';
+ * skip past that part of sysfs_dir2.
+ */
+ if (sysfs_dir2[0] != 'u')
+ continue;
+ sysfs_dir2 += 3;
+ }
+
+ /* The remainder of the parent's name must be equal to
+ * the first n bytes of sysfs_dir1.
+ */
+ if (memcmp(sysfs_dir1, sysfs_dir2, n) == 0 &&
!sysfs_dir2[n]) {
+ dev1->parent_dev = dev2;
+ break;
+ }
+ }
+ }
+}
+
static int sysfs_get_device_list(struct libusb_context *ctx,
struct discovered_devs **_discdevs)
{
@@ -1189,6 +1257,7 @@ static int sysfs_get_device_list(struct libusb_context
*ctx,
if (!r)
*_discdevs = discdevs;
closedir(devices);
+ sysfs_analyze_topology(discdevs);
return r;
}
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index f29f84c..5c1ce7e 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -1001,8 +1001,10 @@ static int init_device(struct libusb_device* dev, struct
libusb_device* parent_d
}
dev->bus_number = parent_dev->bus_number;
priv->port = port_number;
+ dev->port_number = port_number;
priv->depth = parent_priv->depth + 1;
priv->parent_dev = parent_dev;
+ dev->parent_dev = parent_dev;
// If the device address is already set, we can stop here
if (dev->device_address != 0) {
--
1.7.9.msysgit.0
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel