Add port_number, port_chain for all platform#58
Add port_number, port_chain for all platform#58CCnut wants to merge 10 commits intokevinmehall:mainfrom
port_number, port_chain for all platform#58Conversation
|
I'm wondering what location paths are used for -- what's your use case? This isn't necessarily a problem to add, but I don't want to go so far as caching every device property so wondering where to draw the line. For properties not supported, you can always look them up via the instance ID. |
|
Does the existing What would be ideal is a cross-platform way to identify the port, like libusb's Besides being Windows-specific and not portable, |
|
Getting Try enumerating the complete usb device tree to locate the position of the usb device, or use I will try to implement |
port_number, port_chain for all platform
kevinmehall
left a comment
There was a problem hiding this comment.
Haven't had a chance to test this or give it a full review, but here are some initial questions.
| // Find Port_#xxxx | ||
| // Port_#0002.Hub_#000D | ||
| if let Some(location_info) = devinst.get_property::<OsString>(DEVPKEY_Device_LocationInfo) { | ||
| let s = location_info.to_string_lossy(); | ||
| if &s[0..6] == "Port_#" { | ||
| if let Ok(n) = s[6..10].parse::<u32>() { | ||
| return Some(n); | ||
| } | ||
| } | ||
| } | ||
| // Find last #USB(x) | ||
| // PCIROOT(B2)#PCI(0300)#PCI(0000)#USBROOT(0)#USB(1)#USB(2)#USBMI(3) | ||
| if let Some(location_paths) = | ||
| devinst.get_property::<Vec<OsString>>(DEVPKEY_Device_LocationPaths) | ||
| { | ||
| for location_path in location_paths { | ||
| let s = location_path.to_string_lossy(); | ||
| for b in s.split('#').rev() { | ||
| if b.contains("USB(") { | ||
| if let Ok(n) = b[5..b.len()].parse::<u32>() { | ||
| return Some(n); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| devinst.get_property::<u32>(DEVPKEY_Device_Address) |
There was a problem hiding this comment.
Is there a reason all three of these techniques are used? Would be worth a comment explaining under what circumstances we'd hit each of these.
There was a problem hiding this comment.
This function references the libusb code.
The DEVPKEY_Device_LocationInfo and DEVPKEY_Device_LocationPaths parameters may not return a matching format.
| } | ||
| } | ||
| // Find last #USB(x) | ||
| // PCIROOT(B2)#PCI(0300)#PCI(0000)#USBROOT(0)#USB(1)#USB(2)#USBMI(3) |
There was a problem hiding this comment.
Or, do these #USB(n) elements directly correspond to the port chain that we could just parse from the location path?
| } | ||
|
|
||
| pub fn probe_device(devinst: DevInst) -> Option<DeviceInfo> { | ||
| pub fn enum_root_hub(rootinst: DevInst) -> impl Iterator<Item = (DevInst, Vec<u32>)> { |
There was a problem hiding this comment.
Would there be a way to do this starting from a device and looking up its parent rather than switching to start at a root hub? Besides the increased complexity, one argument against this is that with hotplug attach events, we're given a single DevInst and would like to be able to find all of its DeviceInfo properties without walking the whole tree.
|
|
||
| fn get_port_number(device: &IoService) -> Option<u32> { | ||
| get_integer_property::<u32>(device, "PortNum").or_else(|| { | ||
| if let Ok(parent) = get_parent(device) { |
There was a problem hiding this comment.
Is the parent something other than a hub here? How is the line below getting the port for a specific child device when the property is on the parent?
| }; | ||
|
|
||
| // Ignore the same sessionID | ||
| if session_id |
There was a problem hiding this comment.
Did you observe it reporting a device as its own parent or find documentation indicating that, or is this just a precaution to prevent infinite-looping?
There was a problem hiding this comment.
The parent device may return the same sessionID, which needs to be ignored until a new sessionID is obtained or the obtaining fails.
kevinmehall
left a comment
There was a problem hiding this comment.
This is far too complicated for the functionality added. Libusb does a lot of crazy stuff that is no longer relevant; please don't copy what libusb does without understanding why it does it. Since much of this code is practically unreachable, it's also untested.
For example, this adds an alternative way to look up port numbers on macOS if portNum is missing -- it turns out that libusb had this because macOS versions 10.11.0 - 10.11.2 lacked the portNum property, but macOS 10.11.2 is 9 years old. Meanwhile, the locationId is just a bitwise encoding of the port path we're looking for, no iokit tree traversal needed.
Similarly on Windows, this adds two additional methods of finding the port number. The Windows backend already relies heavily on the port number, because it's what's passed to the hub ioctls to get descriptors. We've been using DEVPKEY_Device_Address exclusively for that with no problems so far.
I've gone ahead and implemented a simpler version as #71. Need to figure out what to do with the bus number though, and may end up using some of this Windows code after all.
| let bus_devs = cfgmgr32::list_interfaces(GUID_DEVINTERFACE_USB_HOST_CONTROLLER, None) | ||
| .iter() | ||
| .flat_map(|i| get_device_interface_property::<WCString>(i, DEVPKEY_Device_InstanceId)) | ||
| .flat_map(|d| DevInst::from_instance_id(&d)) | ||
| .flat_map(|d| d.children()) | ||
| .map(|d| d.instance_id().to_string()) | ||
| .enumerate() | ||
| .map(|v| (v.1, (v.0 + 1) as u8)) | ||
| .collect::<HashMap<String, u8>>(); |
There was a problem hiding this comment.
The existing bus number using DEVPKEY_Device_BusNumber is indeed wrong (#70) but as mentioned in that issue I'm considering just exposing the bus ID as a string rather than trying to map it to a small integer.
| } | ||
| } | ||
| // Find last #USB(x) | ||
| // PCIROOT(B2)#PCI(0300)#PCI(0000)#USBROOT(0)#USB(1)#USB(2)#USBMI(3) |
|
The usb bus number on Windows is related to Here's what I've tried so far to get the bus number. Use a prefix of |
|
Superseded by #71, but thanks for your work on this in helping figure out what was needed here. |


Add location paths for USB devices on Windows