Coverage for linuxpy/usb/usbfs.py: 0%
60 statements
« prev ^ index » next coverage.py v7.6.8, created at 2025-05-27 13:54 +0200
« prev ^ index » next coverage.py v7.6.8, created at 2025-05-27 13:54 +0200
1#
2# This file is part of the linuxpy project
3#
4# Copyright (c) 2023 Tiago Coutinho
5# Distributed under the GPLv3 license. See LICENSE for more info.
7import collections
8import functools
9import struct
11from .base import USB_DEV_PATH, USB_DEV_TMPFS_PATH, BaseDevice
13USBFS_MAXDRIVERNAME = 255
16DeviceDescriptorDecoder = struct.Struct("<BBHBBBBHHHBBBB")
17DeviceDescriptor = collections.namedtuple(
18 "DeviceDescriptor",
19 (
20 "length",
21 "descriptor_type",
22 "bcdUSB",
23 "device_class",
24 "device_sub_class",
25 "protocol",
26 "max_pack_size",
27 "vendor_id",
28 "product_id",
29 "bcdDevice",
30 "manufacturer",
31 "product_index",
32 "serial_number_index",
33 "nb_configs",
34 ),
35)
38def read_descriptor(fd):
39 # just after the open() call we can read the ubfs device descriptor
40 # it will contain at least 18 bytes with basic usb device information
41 data = fd.read(256)
42 return DeviceDescriptor(*DeviceDescriptorDecoder.unpack_from(data))
45class Device(BaseDevice):
46 def __init__(self, path):
47 super().__init__(path)
48 self.descriptor = None
50 @functools.cached_property
51 def bus_number(self):
52 return int(self.filename.parent.name)
54 @functools.cached_property
55 def device_address(self):
56 return int(self.filename.name)
58 @functools.cached_property
59 def session_id(self):
60 return self.bus_number << 8 | self.device_address
62 @property
63 def vendor_id(self):
64 return self.descriptor.vendor_id
66 @property
67 def product_id(self):
68 return self.descriptor.product_id
70 @property
71 def manufacturer(self):
72 return self.descriptor.manufacturer
74 def open(self):
75 self._fobj = open(self.filename, "rb")
76 self.descriptor = read_descriptor(self._fobj)
79@functools.cache
80def usbfs_path():
81 for path in (USB_DEV_TMPFS_PATH, USB_DEV_PATH):
82 if path.is_dir():
83 # assume if we find any files that it must be the right place
84 if next(path.iterdir(), None):
85 return path
87 # On udev based systems without any usb-devices /dev/bus/usb will not
88 # exist. So if we've not found anything and we're using udev for hotplug
89 # simply assume /dev/bus/usb rather then making this fail
90 return USB_DEV_TMPFS_PATH
93def iter_paths():
94 for path in usbfs_path().iterdir():
95 try:
96 int(path.name)
97 except ValueError:
98 continue
99 for sub_path in path.iterdir():
100 try:
101 int(sub_path.name)
102 except ValueError:
103 continue
104 yield sub_path
107def iter_devices():
108 for path in iter_paths():
109 yield Device(path)
112def lsusb():
113 for dev in iter_devices():
114 dev.open()