Re: lsusb -t doesn't always work with 2.6.35

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 12, 2010 at 05:14:42PM +0600, Andrey Rahmatullin wrote:
> Hello.
> 
> On 2.6.35 lsusb -t from usbutils 0.87 sometimes works as with previous
> kernels, but sometimes shows only some devices:
> 
> /:  Bus 05.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
> /:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
> /:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
> /:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
> /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/8p, 480M
>     |__ Port 4: Dev 3, If 0, Class=stor., Driver=usb-storage, 480M
> 
> 
> lsusb and lsusb -v always show all devices.

Do you have any usb 3.0 devices in your system?

What is the difference when it works properly in the output vs the
incorrect one?  What type of devices are missing?

And does the following python script always work properly?

thanks,

greg k-h
#!/usr/bin/env python
# lsusb.py
# Displays your USB devices in reasonable form.
# (c) Kurt Garloff <garloff@xxxxxxx>, 2/2009, GPL v2 or v3.
# Usage: See usage()

import os, sys, re, getopt

# from __future__ import print_function

# Global options
showint = False
showhubint = False
noemptyhub = False
nohub = False
warnsort = False

prefix = "/sys/bus/usb/devices/"
usbids = "/usr/share/usb.ids"

esc = chr(27)
norm = esc + "[0;0m"
bold = esc + "[0;1m"
red =  esc + "[0;31m"
green= esc + "[0;32m"
amber= esc + "[0;33m"

cols = ("", "", "", "", "")

def readattr(path, name):
	"Read attribute from sysfs and return as string"
	f = open(prefix + path + "/" + name);
	return f.readline().rstrip("\n");

def readlink(path, name):
	"Read symlink and return basename"
	return os.path.basename(os.readlink(prefix + path + "/" + name));

class UsbClass:
	"Container for USB Class/Subclass/Protocol"
	def __init__(self, cl, sc, pr, str = ""):
		self.pclass = cl
		self.subclass = sc
		self.proto = pr
		self.desc = str
	def __repr__(self):
		return self.desc
	def __cmp__(self, oth):
		# Works only on 64bit systems:
		#return self.pclass*0x10000+self.subclass*0x100+self.proto \
		#	- oth.pclass*0x10000-oth.subclass*0x100-oth.proto
		if self.pclass != oth.pclass:
			return self.pclass - oth.pclass
		if self.subclass != oth.subclass:
			return self.subclass - oth.subclass
		return self.proto - oth.proto

class UsbVendor:
	"Container for USB Vendors"
	def __init__(self, vid, vname = ""):
		self.vid = vid
		self.vname = vname
	def __repr__(self):
		return self.vname
	def __cmp__(self, oth):
		return self.vid - oth.vid

class UsbProduct:
	"Container for USB VID:PID devices"
	def __init__(self, vid, pid, pname = ""):
		self.vid = vid
		self.pid = pid
		self.pname = pname
	def __repr__(self):
		return self.pname
	def __cmp__(self, oth):
		# Works only on 64bit systems:
		# return self.vid*0x10000 + self.pid \
		#	- oth.vid*0x10000 - oth.pid
		if self.vid != oth.vid:
			return self.vid - oth.vid
		return self.pid - oth.pid

usbvendors = []
usbproducts = []
usbclasses = []

def ishexdigit(str):
	"return True if all digits are valid hex digits"
	for dg in str:
		if not dg.isdigit() and not dg in 'abcdef':
			return False
	return True

def parse_usb_ids():
	"Parse /usr/share/usb.ids and fill usbvendors, usbproducts, usbclasses"
	id = 0
	sid = 0
	mode = 0
	strg = ""
	cstrg = ""
	for ln in file(usbids, "r").readlines():
		if ln[0] == '#':
			continue
		ln = ln.rstrip('\n')
		if len(ln) == 0:
			continue
		if ishexdigit(ln[0:4]):
			mode = 0
			id = int(ln[:4], 16)
			usbvendors.append(UsbVendor(id, ln[6:]))
			continue
		if ln[0] == '\t' and ishexdigit(ln[1:3]):
			sid = int(ln[1:5], 16)
			# USB devices
			if mode == 0:
				usbproducts.append(UsbProduct(id, sid, ln[7:]))
				continue
			elif mode == 1:
				nm = ln[5:]
				if nm != "Unused":
					strg = cstrg + ":" + nm
				else:
					strg = cstrg + ":"
				usbclasses.append(UsbClass(id, sid, -1, strg))
				continue
		if ln[0] == 'C':
			mode = 1
			id = int(ln[2:4], 16)
			cstrg = ln[6:]
			usbclasses.append(UsbClass(id, -1, -1, cstrg))
			continue
		if mode == 1 and ln[0] == '\t' and ln[1] == '\t' and ishexdigit(ln[2:4]):
			prid = int(ln[2:4], 16)
			usbclasses.append(UsbClass(id, sid, prid, strg + ":" + ln[6:]))
			continue
		mode = 2

def bin_search(first, last, item, list):
	"binary search on list, returns -1 on fail, match idx otherwise, recursive"
	#print "bin_search(%i,%i)" % (first, last)
	if first == last:
		return -1
	if first == last-1:
		if item == list[first]:
			return first
		else:
			return -1
	mid = (first+last) // 2
	if item == list[mid]:
		return mid
	elif item < list[mid]:
		return bin_search(first, mid, item, list)
	else:
		return bin_search(mid, last, item, list)


def find_usb_prod(vid, pid):
	"Return device name from USB Vendor:Product list"
	strg = ""
	dev = UsbVendor(vid, "")
	lnvend = len(usbvendors)
	ix = bin_search(0, lnvend, dev, usbvendors)
	if ix != -1:
		strg = usbvendors[ix].__repr__()
	else:
		return ""
	dev = UsbProduct(vid, pid, "")
	lnprod = len(usbproducts)
	ix = bin_search(0, lnprod, dev, usbproducts)
	if ix != -1:
		return strg + " " + usbproducts[ix].__repr__()
	return strg

def find_usb_class(cid, sid, pid):
	"Return USB protocol from usbclasses list"
	if cid == 0xff and sid == 0xff and pid == 0xff:
		return "Vendor Specific"
	lnlst = len(usbclasses)
	dev = UsbClass(cid, sid, pid, "")
	ix = bin_search(0, lnlst, dev, usbclasses)
	if ix != -1:
		return usbclasses[ix].__repr__()
	dev = UsbClass(cid, sid, -1, "")
	ix = bin_search(0, lnlst, dev, usbclasses)
	if ix != -1:
		return usbclasses[ix].__repr__()
	dev = UsbClass(cid, -1, -1, "")
	ix = bin_search(0, lnlst, dev, usbclasses)
	if ix != -1:
		return usbclasses[ix].__repr__()
	return ""


devlst = (	'usb/lp',	# usblp 
		'host', 	# usb-storage
		'video4linux/video', 	# uvcvideo et al.
		'sound/card',	# snd-usb-audio 
		'net/', 	# cdc_ether, ...
		'input/input',	# usbhid
		'bluetooth/hci',	# btusb
		'ttyUSB',	# btusb
		'tty/',		# cdc_acm
	)

def find_storage(hostno):
	"Return SCSI block dev names for host"
	res = ""
	for ent in os.listdir("/sys/class/scsi_device/"):
		(host, bus, tgt, lun) = ent.split(":")
		if host == hostno:
			try:
				for ent2 in os.listdir("/sys/class/scsi_device/%s/device/block" % ent):
					res += ent2 + " "
			except:
				pass
	return res

def find_dev(driver, usbname):
	"Return pseudo devname that's driven by driver"
	res = ""
	for nm in devlst:
		dir = prefix + usbname
		prep = ""
		#print nm
		idx = nm.find('/')
		if idx != -1:
			prep = nm[:idx+1]
			dir += "/" + nm[:idx]
			nm = nm[idx+1:]
		ln = len(nm)
		try:
			for ent in os.listdir(dir):
				if ent[:ln] == nm:
					res += prep+ent+" "
					if nm == "host":
						res += "(" + find_storage(ent[ln:])[:-1] + ")"
		except:
			pass
	return res


class UsbInterface:
	"Container for USB interface info"
	def __init__(self, parent = None, level = 1):
		self.parent = parent
		self.level = level
		self.fname = ""
		self.iclass = 0
		self.isclass = 0
		self.iproto = 0
		self.noep = 0
		self.driver = ""
		self.devname = ""
		self.protoname = ""
	def read(self, fname):
		fullpath = ""
		if self.parent:
			fullpath += self.parent.fname + "/"
		fullpath += fname
		#self.fname = fullpath
		self.fname = fname
		self.iclass = int(readattr(fullpath, "bInterfaceClass"),16)
		self.isclass = int(readattr(fullpath, "bInterfaceSubClass"),16)
		self.iproto = int(readattr(fullpath, "bInterfaceProtocol"),16)
		self.noep = int(readattr(fullpath, "bNumEndpoints"))
		try:
			self.driver = readlink(fname, "driver")
			self.devname = find_dev(self.driver, fname)
		except:
			pass
		self.protoname = find_usb_class(self.iclass, self.isclass, self.iproto)
	def __str__(self):
		return "%-16s(IF) %02x:%02x:%02x %iEPs (%s) %s%s %s%s%s\n" % \
			(" " * self.level+self.fname, self.iclass,
			 self.isclass, self.iproto, self.noep,
			 self.protoname, 
			 cols[3], self.driver,
			 cols[4], self.devname, cols[0])

class UsbDevice:
	"Container for USB device info"
	def __init__(self, parent = None, level = 0):
		self.parent = parent
		self.level = level
		self.fname = ""
		self.iclass = 0
		self.isclass = 0
		self.iproto = 0
		self.vid = 0
		self.pid = 0
		self.name = ""
		self.usbver = ""
		self.speed = ""
		self.maxpower = ""
		self.noports = 0
		self.nointerfaces = 0
		self.driver = ""
		self.devname = ""
		self.interfaces = []
		self.children = []

	def read(self, fname):
		self.fname = fname
		self.iclass = int(readattr(fname, "bDeviceClass"), 16)
		self.isclass = int(readattr(fname, "bDeviceSubClass"), 16)
		self.iproto = int(readattr(fname, "bDeviceProtocol"), 16)
		self.vid = int(readattr(fname, "idVendor"), 16)
		self.pid = int(readattr(fname, "idProduct"), 16)
		try:
			self.name = readattr(fname, "manufacturer") + " " \
				  + readattr(fname, "product")
			self.name += " " + readattr(fname, "serial")
			if self.name[:5] == "Linux":
				rx = re.compile(r"Linux [^ ]* (.hci_hcd) .HCI Host Controller ([0-9a-f:\.]*)")
				mch = rx.match(self.name)
				if mch:
					self.name = mch.group(1) + " " + mch.group(2)

		except:
			pass
		if not self.name:
			self.name = find_usb_prod(self.vid, self.pid)
		self.usbver = readattr(fname, "version")
		self.speed = readattr(fname, "speed")
		self.maxpower = readattr(fname, "bMaxPower")
		self.noports = int(readattr(fname, "maxchild"))
		self.nointerfaces = int(readattr(fname, "bNumInterfaces"))
		try:
			self.driver = readlink(fname, "driver")
			self.devname = find_dev(self.driver, fname)
		except:
			pass

	def readchildren(self):
		if self.fname[0:3] == "usb":
			fname = self.fname[3:]
		else:
			fname = self.fname
		for dirent in os.listdir(prefix + self.fname):
			if not dirent[0:1].isdigit():
				continue
			#print dirent
			if os.access(prefix + dirent + "/bInterfaceClass", os.R_OK):
				iface = UsbInterface(self, self.level+1)
				iface.read(dirent)
				self.interfaces.append(iface)
			else:
				usbdev = UsbDevice(self, self.level+1)
				usbdev.read(dirent)
				usbdev.readchildren()
				self.children.append(usbdev)

	def __str__(self):
		#str = " " * self.level + self.fname
		if self.iclass == 9:
			col = cols[2]
			if noemptyhub and len(self.children) == 0:
				return ""
			if nohub:
				str = ""
		else:
			col = cols[1]
		if not nohub or self.iclass != 9:
			str = "%-16s%s%04x:%04x%s %02x %s %3sMBit/s %s %iIFs (%s%s%s)" % \
				(" " * self.level + self.fname, 
				 cols[1], self.vid, self.pid, cols[0],
				 self.iclass, self.usbver, self.speed, self.maxpower,
				 self.nointerfaces, col, self.name, cols[0])
			#if self.driver != "usb":
			#	str += " %s" % self.driver
			if self.iclass == 9 and not showhubint:
				str += " %shub%s\n" % (cols[2], cols[0])
			else:
				str += "\n"
				if showint:	
					for iface in self.interfaces:
						str += iface.__str__()
		for child in self.children:
			str += child.__str__()
		return str

def deepcopy(lst):
	"Returns a deep copy from the list lst"
	copy = []
	for item in lst:
		copy.append(item)
	return copy

def display_diff(lst1, lst2, fmtstr, args):
	"Compare lists (same length!) and display differences"
	for idx in range(0, len(lst1)):
		if lst1[idx] != lst2[idx]:
			print "Warning: " + fmtstr % args(lst2[idx])

def fix_usbvend():
	"Sort USB vendor list and (optionally) display diffs"
	if warnsort:
		oldusbvend = deepcopy(usbvendors)
	usbvendors.sort()
	if warnsort:
		display_diff(usbvendors, oldusbvend, 
				"Unsorted Vendor ID %04x",
				lambda x: (x.vid,))

def fix_usbprod():
	"Sort USB products list"
	if warnsort:
		oldusbprod = deepcopy(usbproducts)
	usbproducts.sort()
	if warnsort:
		display_diff(usbproducts, oldusbprod, 
				"Unsorted Vendor:Product ID %04x:%04x",
				lambda x: (x.vid, x.pid))

def fix_usbclass():
	"Sort USB class list"
	if warnsort:
		oldusbcls = deepcopy(usbclasses)
	usbclasses.sort()
	if warnsort:
		display_diff(usbclasses, oldusbcls,
				"Unsorted USB class %02x:%02x:%02x",
				lambda x: (x.pclass, x.subclass, x.proto))


def usage():
	"Displays usage information"
	print "Usage: lsusb.py [options]"
	print "Options:"
	print " -h display this help"
	print " -i display interface information"
	print " -I display interface information, even for hubs"
	print " -u suppress empty hubs"
	print " -U suppress all hubs"
	print " -c use colors"
	print " -w display warning if usb.ids is not sorted correctly"
	print " -f FILE override filename for /usr/share/usb.ids"
	return 2

def read_usb():
	"Read toplevel USB entries and print"
	for dirent in os.listdir(prefix):
		#print dirent,
		if not dirent[0:3] == "usb":
			continue
		usbdev = UsbDevice(None, 0)
		usbdev.read(dirent)
		usbdev.readchildren()
		os.write(sys.stdout.fileno(), usbdev.__str__())

def main(argv):
	"main entry point"
	global showint, showhubint, noemptyhub, nohub, warnsort, cols, usbids
	try:
		(optlist, args) = getopt.gnu_getopt(argv[1:], "hiIuUwcf:", ("help",))
	except getopt.GetoptError, exc:
		print "Error:", exc
		sys.exit(usage())
	for opt in optlist:
		if opt[0] == "-h" or opt[0] == "--help":
			usage()
			sys.exit(0)
		if opt[0] == "-i":
			showint = True
			continue
		if opt[0] == "-I":
			showint = True
			showhubint = True
			continue
		if opt[0] == "-u":
			noemptyhub = True
			continue
		if opt[0] == "-U":
			noemptyhub = True
			nohub = True
			continue
		if opt[0] == "-c":
			cols = (norm, bold, red, green, amber)
			continue
		if opt[0] == "-w":
			warnsort = True
			continue
		if opt[0] == "-f":
			usbids = opt[1]
			continue
	if len(args) > 0:
		print "Error: excess args %s ..." % args[0]
		sys.exit(usage())

	parse_usb_ids()
	fix_usbvend()	
	fix_usbprod()
	fix_usbclass()
	read_usb()

# Entry point
if __name__ == "__main__":
	main(sys.argv)



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux