You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 lines
2.6 KiB

# License: Apache 2.0. See LICENSE file in root directory.
# Copyright(c) 2021 Intel Corporation. All Rights Reserved.
"""
USB interface library for Linux
Uses the lsusb built-in utility. Be careful to cache results or else it will
run every call!
"""
from rspy import log
import re, subprocess
def itree():
"""
Yields all device interfaces from 'lsusb -t' in tuples:
(bus, device, interface, ports)
All integers, and ports is a list of port numbers.
"""
df = subprocess.run( ['lsusb', '-t'],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True, timeout=2 )
bus = None
ports = []
for i in df.stdout.split('\n'):
if not i:
continue
spaces = len(i) - len(i.lstrip())
if spaces % 4:
raise ValueError( f'invalid number of spaces ({spaces}) in "{i}"')
indent = int(spaces / 4)
if indent == 0:
match = re.search( r'Bus (\d+).', i )
if not match:
raise ValueError( f'expected "Bus #." in "{i}"' )
bus = int( match.group(1) )
ports = []
continue
match = re.search( r'Port (\d+): Dev (\d+), If (\d+),', i )
if not match:
raise ValueError( f'unexpected format in "{i}"')
continue
while indent <= len(ports):
ports.pop()
port = int( match.group(1) )
ports.append( port )
device = int( match.group(2) )
interface = int( match.group(3) )
bus_device = f'{bus}-{device}'
yield (bus, device, interface, ports)
def tree():
"""
Yields all devices from 'lsusb -t' in tuples:
(device-id, ports)
Where both are strings: '<bus>-<device>' as device-id and '<bus>-<port#>(.<port#>)*' for the
port representation.
"""
devices = set()
for b,d,i,p in itree():
device_id = f'{b}-{d}'
if device_id not in devices:
devices.add( device_id )
port = f'{b}-' + '.'.join( [str(n) for n in p] )
yield (device_id, port)
def devices_by_vendor( vid ):
"""
"""
df = subprocess.run( ['lsusb', '-d', vid + ':'],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True, timeout=2 )
for i in df.stdout.split('\n'):
if i:
match = re.search( r'^Bus (\d+) Device (\d+):', i )
if not match:
raise ValueError( i )
bus = int( match.group(1) )
device = int( match.group(2) )
yield f'{bus}-{device}'