PyXR

c:\projects\bitpim\src \ usb_ids.py



0001 #!/usr/bin/env python
0002 ### BITPIM
0003 ###
0004 ### Copyright (C) 2003 Steve Palm <n9yty@n9yty.com>
0005 ###
0006 ### This program is free software; you can redistribute it and/or modify
0007 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0008 ###
0009 ### $Id: usb_ids.py 2867 2006-03-05 01:03:55Z djpham $
0010 
0011 """Parse the usb.ids file for quick access to the information contained therein"""
0012 
0013 import re
0014 
0015 vendor_re = re.compile(r"^([0-9A-Fa-f]{4,4})\s+(.*)$")
0016 device_re = re.compile(r"^\t([0-9A-Fa-f]{4,4})\s+(.*)$")
0017 iface_re = re.compile(r"^\t\t([0-9A-Fa-f]{2,2})\s+(.*)$")
0018 usbclass_re = re.compile(r"^C\s([0-9A-Fa-f]{2,2})\s+(.*)$")
0019 usbsubclass_re = re.compile(r"^\t([0-9A-Fa-f]{2,2})\s+(.*)$")
0020 usbprotocol_re = re.compile(r"^\t\t([0-9A-Fa-f]{2,2})\s+(.*)$")
0021 
0022 ###
0023 ###  USB Info superclass
0024 ###
0025 class usbInfoObject:
0026         """ Super class for all types of USB vendor/device/interface/class/sublcass/protocol
0027                 classes which will be descendants of this. I chose to make and use various children
0028                 of this class, as it's possible they may have unique information of their own some
0029                 time later, as well as allowing a more natural name/syntax based on object use.
0030         """
0031         def __init__(self, id, description):
0032                 """ Set our ID code, description, and prepare to accept children """
0033                 self.id = id
0034                 self.description = description
0035                 self.children = {};
0036         
0037         def description(self):
0038                 """ Return the description for this object """
0039                 return self.description
0040 
0041         def id(self):
0042                 """ Return our ID code """
0043                 return self.id
0044 
0045         def addChild(self, child):
0046                 """ Add a child to our list """
0047                 self.children[int(child.id, 16)] = child
0048 
0049         def getChild(self, child):
0050                 """ If we have a child matching the request, return it """
0051                 if child in self.children:
0052                         return self.children[child]
0053                 else:
0054                         return None
0055         
0056         def getChildren(self):
0057                 """ Return a list of all our children """
0058                 return self.children.values()
0059 
0060 ###
0061 ###  USB ID file superclass --- This is our master object
0062 ###
0063 class usb_ids:
0064         """ Class that represents the data in the usb.ids file
0065                 It reads/parses the file and creates the objects to match
0066         """
0067         
0068         def __init__(self, fname=None):
0069                 """ Initialize the class.  This includes reading the supplied file
0070                     and creating/populating as many related objects as needed.
0071                 """
0072                 self.vendorlist = VendorList()
0073                 self.usbclasslist = USBClassList()
0074                 self.inVendor = 0
0075                 self.inClass = 0
0076                 if fname is not None:
0077                         self.add_data(fname)
0078 
0079         def add_data(self, fname):
0080                 try:
0081                         ufile = open(fname, "rt")
0082                         try:        
0083                                 aline = ufile.readline()
0084                                 while aline != "":
0085                                         # Remove any EOL characters
0086                                         while (aline[:-1] in ["\r", "\n"]):
0087                                                 aline = aline[:-1]
0088 
0089                                         # Check for a vendor ID line
0090                                         m = vendor_re.match(aline)
0091                                         if (m):
0092                                                 self.inVendor = 1
0093                                                 self.inClass = 0
0094                                                 self.curr_vendor = VendorID(m.group(1), m.group(2))
0095                                                 self.vendorlist.addVendor(m.group(1), self.curr_vendor)
0096 
0097                                         if (self.inVendor):
0098                                                 # Check for a device ID line
0099                                                 m = device_re.match(aline)
0100                                                 if (m):
0101                                                         self.curr_device = DeviceID(m.group(1), m.group(2))
0102                                                         self.curr_vendor.addDevice(self.curr_device)
0103         
0104                                                 # Check for a interface ID line
0105                                                 m = iface_re.match(aline)
0106                                                 if (m):
0107                                                         self.curr_device.addInterface(InterfaceID(m.group(1), m.group(2)))
0108 
0109                                         # Check for a USB Class line
0110                                         m = usbclass_re.match(aline)
0111                                         if (m):
0112                                                 self.inClass = 1
0113                                                 self.inVendor = 0
0114                                                 self.curr_usbclass = USBClass(m.group(1), m.group(2))
0115                                                 self.usbclasslist.addClass(m.group(1), self.curr_usbclass)
0116                                         
0117                                         if (self.inClass):
0118                                                 # Check for a USB SubClass line
0119                                                 m = usbsubclass_re.match(aline)
0120                                                 if (m):
0121                                                         self.curr_usbsubclass = USBClassSubclass(m.group(1), m.group(2))
0122                                                         self.curr_usbclass.addSubclass(self.curr_usbsubclass)
0123         
0124                                                 # Check for a USB Protocol line
0125                                                 m = usbprotocol_re.match(aline)
0126                                                 if (m):
0127                                                         self.curr_usbsubclass.addProtocol(USBClassProtocol(m.group(1), m.group(2)))
0128 
0129                                         # Get next line (if it exists)
0130                                         aline = ufile.readline()
0131                         except IOError:
0132                                 # We'll take a pass on it, live with what (if any) data we get
0133                                 pass
0134                                 
0135                 except IOError:
0136                         print ("Cannot open the USB ID file: %s" % fname)
0137                         raise
0138 
0139                 if (ufile):
0140                         ufile.close()
0141 
0142         def lookupdevice(self, vendor, product=None, interface=None):
0143                 return self.vendorlist.getVendorInfo(vendor, product, interface)                
0144 
0145         def lookupclass(self, klass, subclass=None, protocol=None):
0146                 return self.usbclasslist.getClassInfo(klass, subclass, protocol)
0147 
0148         def getVendorList(self):
0149                 """ Return the object representing the list of vendors """
0150                 return self.vendorlist
0151 
0152         def getUSBClassList(self):
0153                 """ Return the object representing the list of USB Classes """
0154                 return self.usbclasslist
0155 
0156 ###
0157 ###  USB VendorID/DeviceID information related classes
0158 ###
0159 class VendorID(usbInfoObject):
0160         """ This class abstracts USB Vendor ID information
0161                 It holds the description, and a list of Device ID's
0162         """
0163         def addDevice(self, device):
0164                 """ Put this device on our list """
0165                 self.addChild(device)
0166 
0167         def getDevice(self, device):
0168                 """ Return the requested device by ID, if we have it """
0169                 return self.getChild(device)
0170 
0171         def getDevices(self):
0172                 """ Return a list of our devices """
0173                 return self.getChildren()
0174 
0175 class DeviceID(usbInfoObject):
0176         """ This class abstracts USB Device ID information 
0177         It holds the description and a list of the Interface ID's
0178         """        
0179         def addInterface(self, interface):
0180                 """ Put this interface on our list """
0181                 self.addChild(interface)
0182         
0183         def getInterface(self, interface):
0184                 """ Return the requested interface by ID, if we have it """
0185                 return self.getChild(interface)
0186 
0187         def getInterfaces(self):
0188                 """ Return a list of our interfaces """
0189                 return self.getChildren()
0190 
0191 class InterfaceID(usbInfoObject):
0192         """ This class abstracts USB Interface information
0193                 It holds the description
0194         """
0195         pass
0196 
0197 class VendorList:
0198         """ This class is responsible for the collection of vendor data
0199                 It allows you to ask for:
0200                  - vendor info by VendorID
0201                  - device info by VendorID/DeviceID
0202                  - interface """
0203         def __init__(self):
0204                 """ Prepare a dict to handle all of our children vendor objects """
0205                 self.vendorlist = {}
0206 
0207         def addVendor(self, vID, vDesc):
0208                 """ Put this vendor into our dictionary """
0209                 self.vendorlist[int(vID,16)] = vDesc
0210 
0211         def getVendorInfo(self, vID, dID=None, iID=None):
0212                 """ Lookup info for vendor, device, interface - last two are optional """
0213                 # First things first... Get information if available....
0214                 self.vendor = self.device = self.iface = None
0215                 self.vDesc = self.dDesc = self.iDesc = None
0216 
0217                 # --- Vendor
0218                 if vID in self.vendorlist:
0219                         self.vendor = self.vendorlist[vID]
0220                         self.vDesc = self.vendor.description
0221 
0222                 # --- Device
0223                 if self.vendor:
0224                         self.device = self.vendor.getDevice(dID)
0225                 if self.device:
0226                         self.dDesc = self.device.description
0227 
0228                 # --- Interface
0229                 if self.device:
0230                         self.iface = self.device.getInterface(iID)
0231                 if self.iface:
0232                         self.iDesc = self.iface.description
0233 
0234                 # Now, decide how we were called, and return appropriately
0235                 if ((dID is None) and (iID is None)):
0236                         return (self.vDesc,)
0237                 elif (iID is None):
0238                         return (self.vDesc, self.dDesc)
0239                 else:
0240                         return (self.vDesc, self.dDesc, self.iDesc)
0241         
0242         def getVendorList(self):
0243                 return self.vendorlist.values()
0244 
0245 
0246 ###
0247 ###  USB Class information related classes
0248 ###
0249 class USBClass(usbInfoObject):
0250         """ This class abstracts USB Class information
0251                 It holds the description, and a list of Subclasses
0252         """
0253         def addSubclass(self, subclass):
0254                 """ Put this subclass on our list """
0255                 self.addChild(subclass)
0256 
0257         def getSubclass(self, subclass):
0258                 """ Return subclass by ID, if we have it """
0259                 return self.getChild(subclass)
0260 
0261         def getSubclasses(self):
0262                 """ Return a list of our subclasses """
0263                 return self.getChildren()
0264         
0265 
0266 class USBClassSubclass(usbInfoObject):
0267         """ This class abstracts USB Device SubClass information   
0268                 It holds the description and a list of the protocols
0269         """        
0270         def addProtocol(self, protocol):
0271                 """ Put this protocol on our list """
0272                 self.addChild(protocol)
0273 
0274         def getProtocol(self, protocol):
0275                 """ Return protocol as ID, if we have it """
0276                 return self.getChild(protocol)
0277 
0278         def getProtocols(self):
0279                 """ Return a list of our protocols """
0280                 return self.getChildren()
0281 
0282 class USBClassProtocol(usbInfoObject):
0283         """ This class abstracts USB Interface information
0284                 It holds the description
0285         """
0286         pass
0287 
0288 
0289 class USBClassList:
0290         """ This class is responsible for the collection of USB Class data
0291                 It allows you to ask for:
0292                  - USB Class info by Class ID
0293                  - USB SubClass info by ClassID/SubclassID
0294                  - USB Protocol info by ClassID/SubclassID/ProtocolID
0295         """
0296         def __init__(self):
0297                 self.classlist = {}
0298 
0299         def addClass(self, cID, cDesc):
0300                 self.classlist[int(cID, 16)] = cDesc
0301 
0302         def getClassInfo(self, cID, sID=None, pID=None):
0303                 """ Lookup info for class, subclass, protocol - last two are optional """
0304                 # First things first... Get information if available....
0305                 self.usbclass = self.subclass = self.protocol = None
0306                 self.cDesc = self.sDesc = self.pDesc = None
0307 
0308                 # --- USB Class
0309                 if cID in self.classlist:
0310                         self.usbclass = self.classlist[cID]
0311                         self.cDesc = self.usbclass.description
0312 
0313                 # --- USB Subclass
0314                 if self.usbclass:
0315                         self.subclass = self.usbclass.getSubclass(sID)
0316                 if self.subclass:
0317                         self.sDesc = self.subclass.description
0318 
0319                 # --- USB Protocol
0320                 if self.subclass:
0321                         self.protocol = self.subclass.getProtocol(pID)
0322                 if self.protocol:
0323                         self.pDesc = self.protocol.description
0324 
0325                 # Now, decide how we were called, and return appropriately
0326                 if ((sID is None) and (pID is None)):
0327                         return (self.cDesc,)
0328                 elif (pID is None):
0329                         return (self.cDesc, self.sDesc)
0330                 else:
0331                         return (self.cDesc, self.sDesc, self.pDesc)
0332 
0333         def getUSBClassList(self):
0334                 return self.classlist.values()
0335 
0336 
0337 
0338 ###
0339 ###  Interactive testing code
0340 ###
0341 if (__name__ == "__main__"):
0342     import os, guihelper
0343     def print_vendor_info(USBids):
0344             # Print out vendor / device / interface info
0345             vlist = USBids.getVendorList()
0346             for v in vlist.getVendorList():
0347                     print ("VENDOR: %s %s" % (v.id, v.description))
0348                     for d in v.getDevices():
0349                             print ("\tDEVICE: %s %s" % (d.id, d.description))
0350                             for i in d.getInterfaces():
0351                                     print ("\t\tIFACE: %s %s" % (i.id, i.description))
0352     
0353     def print_class_info(USBids):
0354             # Print out class / subclass / protocol
0355             clist = USBids.getUSBClassList()
0356             for c in clist.getUSBClassList():
0357                     print ("CLASS: %s %s" % (c.id, c.description))
0358                     for s in c.getSubclasses():
0359                             print ("\tSUBCLASS: %s %s" % (s.id, s.description))
0360                             for p in s.getProtocols():
0361                                     print ("\t\tPROTOCOL: %s %s" % (p.id, p.description))        
0362 
0363     myUSBids = usb_ids(os.path.join(guihelper.resourcedirectory,
0364                                     "usb.ids"))
0365 
0366     # PRINT OUT THE WHOLE TREE AS A TEST CASE
0367     # print_vendor_info(myUSBids)
0368     # print_class_info(myUSBids)
0369 
0370     # Our list is now internally decimal, so to lookup/inquire by hex
0371     # You must convert to decimal before passing your inquiry in...
0372 
0373     # Test lookup for various bits of USB Vendor/Device/Interface information
0374     print "Inquire on Vendor 1452, Device 518, Iface 1 using various levels of detail:" 
0375     vlist = myUSBids.getVendorList()
0376     print vlist.getVendorInfo(1452)
0377     print vlist.getVendorInfo(1452, 518)
0378     print vlist.getVendorInfo(1452, 518, 1)
0379     print
0380     
0381     # Test lookup for various bits of USB Class/Subclass/Protocol information
0382     print "Inquire on Class 8, Subclass 4, Protocol 0 using various levels of detail:" 
0383     clist = myUSBids.getUSBClassList()
0384     print clist.getClassInfo(8)
0385     print clist.getClassInfo(8, 4)
0386     print clist.getClassInfo(8, 4, 0)
0387     print
0388 
0389     # For reference, this is how you'd inquire on hex values
0390     # print vlist.getVendorInfo(int("05ac", 16))
0391     # print vlist.getVendorInfo(int("05ac", 16), int("0206", 16))
0392     # print vlist.getVendorInfo(int("05ac", 16), int("0206", 16), int("01", 16))
0393     # print clist.getClassInfo(int("08", 16))
0394     # print clist.getClassInfo(int("08", 16), int("04", 16))
0395     # print clist.getClassInfo(int("08", 16), int("04", 16), int("00", 16))
0396 
0397     # The following are in hex just becuase that way I can visually match them
0398     # up with the entries in the test.ids file
0399 
0400     # Now, let's test for something that doesn't exist:
0401     print "Look up something with little detail in Internet file... 1004/6000/(00..02)"
0402     print vlist.getVendorInfo(int("1004", 16), int("6000", 16), int("00", 16))
0403     print vlist.getVendorInfo(int("1004", 16), int("6000", 16), int("01", 16))
0404     print vlist.getVendorInfo(int("1004", 16), int("6000", 16), int("02", 16))
0405     print
0406 
0407     # Put the data in from our local copy
0408     print "Add in our test data to override internet data"
0409     myUSBids.add_data(os.path.join(guihelper.resourcedirectory,
0410                                    "test.ids"))
0411     print
0412     
0413     # Now, it should be there
0414     print "Check it again..."
0415     print vlist.getVendorInfo(int("1004", 16), int("6000", 16), int("00", 16))
0416     print vlist.getVendorInfo(int("1004", 16), int("6000", 16), int("01", 16))
0417     print vlist.getVendorInfo(int("1004", 16), int("6000", 16), int("02", 16))
0418 

Generated by PyXR 0.9.4