Finally got around looking further at the Darwin issue. It looks like
the main problem was that process_new_device() was maintaining a static
device pointer for the last device seen (last_dev), and the value wasn't
reset as it should when calling get_device_list(), resulting in a bad
pointer ref.
To ensure we can issue concurrent calls to get_device_list(), I chose to
maintained last_dev there and just pass it as a parameter to
process_new_device(). Testing seem to indicate that this avoids the
issue we experienced previously.
Also, since it's fairly clear that we're not going to be able to hold a
June 1st deadline for 1.0.12, you'll see from the roadmap that I pushed
the release to 2012.06.15.
I also moved the gerrit+Jenkins target from 1.0.12 to 1.0.13, as it
doesn't look like I'll have time to look into that if I want to address
the other Windows items for 1.0.12. FYI, one of the reasons we still
don't have the -devel branch up is because I have some concerns about
whether we should use separate repos or just a branch, the resolution of
which depends on finding out how happy gerrit really is with a
multi-branch repo carrying out the custom versioning we have to
duplicate from the non-gerrit-supported git-hooks. Obviously, I'd rather
go with the one that's easier to maintain in gerrit.
Regards,
/Pete
>From 9989b19894ac0e03a5e048e998aef340752f642f Mon Sep 17 00:00:00 2001
From: Pete Batard <p...@akeo.ie>
Date: Thu, 10 May 2012 20:01:10 +0100
Subject: [PATCH 1/2] 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
* Unsupported for *BSD platforms
---
examples/xusb.c | 4 ---
libusb/core.c | 64 +++++++++++++++++++++++++++++++++++++++++++
libusb/libusb.h | 3 ++
libusb/libusbi.h | 2 ++
libusb/os/darwin_usb.c | 70 ++++++++++++++++++++++++++++++++++++++++-------
libusb/os/linux_usbfs.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usb.c | 2 ++
7 files changed, 201 insertions(+), 15 deletions(-)
diff --git a/examples/xusb.c b/examples/xusb.c
index 65dda7b..d775781 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 e9690fc..4887b80 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 68ccfe1..8623862 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 0f6babe..f64a1ec 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 libusb_device **last_dev) {
struct darwin_device_priv *priv;
- struct libusb_device *dev;
+ 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,16 @@ 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;
+ struct libusb_device *last_dev = NULL;
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, &last_dev);
(*(device))->Release(device);
}
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index a843289..a01fff8 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 62e41e8..c4212c0 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -1002,8 +1002,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.10.msysgit.1
------------------------------------------------------------------------------
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