Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read common descriptors from sysfs, when available #458

Open
ronny-rentner opened this issue Sep 30, 2022 · 7 comments
Open

Read common descriptors from sysfs, when available #458

ronny-rentner opened this issue Sep 30, 2022 · 7 comments

Comments

@ronny-rentner
Copy link

ronny-rentner commented Sep 30, 2022

Running Debian Linux 11 with Python 3.10 and libusb1. I am trying to connect to an LG UltraFine monitor via USB-C.

It works via lsusb (running as my user):

$ lsusb -D /dev/bus/usb/003/010
Device: ID 043e:9a39 LG Electronics USA, Inc. LG Monitor Controls
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2 
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x043e LG Electronics USA, Inc.
  idProduct          0x9a39 
  bcdDevice            4.11
  iManufacturer           1 LG Electronics Inc.
  iProduct                3 LG Monitor Controls
  iSerial                 4 107NTYTAD986
  bNumConfigurations      1

but not via pyusb:

$ python -c 'import usb.core; d = usb.core.find(idVendor=0x043e, idProduct=0x9a39); print(d)'
DEVICE ID 043e:9a39 on Bus 003 Address 010 =================
 bLength                :   0x12 (18 bytes)
 bDescriptorType        :    0x1 Device
 bcdUSB                 :  0x200 USB 2.0
 bDeviceClass           :   0xef Miscellaneous
 bDeviceSubClass        :    0x2
 bDeviceProtocol        :    0x1
 bMaxPacketSize0        :   0x40 (64 bytes)
 idVendor               : 0x043e
 idProduct              : 0x9a39
 bcdDevice              :  0x411 Device 4.11
 iManufacturer          :    0x1 Error Accessing String
 iProduct               :    0x3 Error Accessing String
 iSerialNumber          :    0x4 Error Accessing String
 bNumConfigurations     :    0x1
$ ls -lah /dev/bus/usb/003/010
crw-rw-r-- 1 root root 189, 265 Sep 28 07:48 /dev/bus/usb/003/010

The device file is world readable.

The strange thing is that pyusb and also lsusb try to open the device with write permissions. I wonder why those are necessary to list something.

I can also do

$ cat /sys/bus/usb/devices/3-6.3/manufacturer
LG Electronics Inc.

or

$ cat /sys/bus/usb/devices/3-6.3/product 
LG Monitor Controls
$ ll /sys/bus/usb/devices/3-6.3/product 
-r--r--r-- 1 root root 4096 Sep 28 07:48 /sys/bus/usb/devices/3-6.3/product

I would expect pyusb to be able to show the vendor and manufacturer similar to lsusb without having write permissions (which are not necessary).

@jonasmalacofilho
Copy link
Member

Write permissions are required because:

  • fetching a descriptor like iManufacturer requires submitting a control transfer to the device;
  • and that, in turn, require suitable permissions, as specified by the corresponding kernel driver (in this case, usbfs).1

Regarding why lsusb seems to you to show a bit more information, that is because lsusb can try to use a few different ways to show you the manufacturer and similar infos: one of those is indeed just fetching the corresponding descriptor from the device, but it can also read that info from udev, or fallback to the USB IDs table. But PyUSB shouldn't be compared to lsusb; rather, it's something that can be used as building block to build something like lsusb (and, IIRC, the usbutils source code includes a PyUSB-based implementation).

Footnotes

  1. Intuition about what should be a "read" or "write" operation can be tricky: it's necessary to consider how the USB protocol works, and how the kernel driver will decide to handle it, both for correctness and security.

@ronny-rentner
Copy link
Author

Well, as it seems, when you do cat /sys/bus/usb/devices/3-6.3/manufacturer you can also just read the information without write permissions from the kernel, without using usbfs and without using udev. Or who populates /sys/bus/usb?

@jonasmalacofilho
Copy link
Member

Please send a patch/PR that implements this special case.

Or who populates /sys/bus/usb?

The Linux kernel, specifically the USB core. But I haven't checked whether they might be missing sometimes, you need to check that and handle any cases where they are present in the device, but somehow not in sysfs.

@ronny-rentner
Copy link
Author

Well, if you're open to accepting a patch to fix this, I'd be willing to work on it. Can we reopen the ticket for this? It might take a bit as I am also busy with other stuff.

@ronny-rentner
Copy link
Author

PS: I would probably not replace any existing logic but just whenever there is "Error Accessing String" do an extra step and try to find the string through /sys/bus/usb
Sounds pretty straight forward to me.

@jonasmalacofilho jonasmalacofilho changed the title Wrong permission error, "Error Accessing String" Read common descriptors from sysfs, when available Oct 6, 2022
@jonasmalacofilho
Copy link
Member

jonasmalacofilho commented Oct 6, 2022

Can we reopen the ticket for this?

Done, but I also renamed for accuracy.

PS: I would probably not replace any existing logic but just whenever there is "Error Accessing String" do an extra step and try to find the string through /sys/bus/usb
Sounds pretty straight forward to me.

Actually, it should probably go in the Device.manufacturer and similar properties, not in Device.__str__ (which may then be reworked to use the new feature).

PyUSB is not a lsusb clone: sure, this feature will improve Device.__str__, but it's also necessary (and, arguably, more important) to make the data available for callers using PyUSB for something more than print(dev).

And the preference order should probably be: locally cached value > (on Linux:) sysfs value > GET_DESCRIPTOR transfer.

@ronny-rentner
Copy link
Author

Thanks for the direction, will do it like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants