summaryrefslogtreecommitdiffstats
path: root/displayconfig/ScanPCI.py
diff options
context:
space:
mode:
Diffstat (limited to 'displayconfig/ScanPCI.py')
-rw-r--r--displayconfig/ScanPCI.py340
1 files changed, 340 insertions, 0 deletions
diff --git a/displayconfig/ScanPCI.py b/displayconfig/ScanPCI.py
new file mode 100644
index 0000000..ec63b55
--- /dev/null
+++ b/displayconfig/ScanPCI.py
@@ -0,0 +1,340 @@
+###########################################################################
+# ScanPCI.py - #
+# ------------------------------ #
+# copyright : (C) 2005 by Simon Edwards #
+# email : simon@simonzone.com #
+# #
+###########################################################################
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 2 of the License, or #
+# (at your option) any later version. #
+# #
+###########################################################################
+"""Provides information about the devices attached to the PCI bus.
+"""
+import struct
+import csv
+import os.path
+import sys
+
+###########################################################################
+class PCIDevice(object):
+ def __init__(self,line=None):
+ self.vendor = None # PCI vendor id
+ self.device = None
+
+ self.subvendor = None # 0xffff if not probe_type'd or no subid
+ self.subdevice = None # 0xffff if not probe_type'd or no subid
+ self.pci_class = None # 'None' if not probe_type'd
+
+ self.pci_bus = None # pci bus id 8 bits wide
+ self.pci_device = None # pci device id 5 bits wide
+ self.pci_function = None# pci function id 3 bits wide
+
+ self.module = None
+ self.text = None
+ self.already_found = False
+
+ if line is not None:
+ self.loadFromString(line)
+
+ def isGfxCard(self):
+ if self.module is not None and \
+ (self.module.startswith("Card:") or self.module.startswith("Server:XFree86(")):
+ return True
+
+ return (self.pci_class & PCIBus.PCI_BASE_CLASS_MASK)==PCIBus.PCI_BASE_CLASS_DISPLAY
+
+ def getModule(self):
+ if self.module is not None:
+ if self.module.startswith("Server:XFree86("):
+ return self.module[15:-1]
+ elif self.module.startswith("Card:"):
+ return self.module[5:]
+ return self.module
+
+ def isModuleXorgDriver(self):
+ return self.module is not None and \
+ (self.module.startswith("Server:XFree86(") or self.module.startswith("Card:"))
+
+ def __str__(self):
+ s = "PCI:%i:%i:%i, " % (self.pci_bus,self.pci_device,self.pci_function)
+ s += "Vendor:%x, Device:%x," % (self.vendor,self.device)
+ if self.subvendor is not None:
+ s += " Subvendor:%x," % self.subvendor
+ if self.subdevice is not None:
+ s += " Subdevice:%x," % self.subdevice
+ if self.pci_class is not None:
+ s += " Class:%x," % self.pci_class
+ if self.module is not None:
+ s += " Module:%s," % self.module
+ if self.text is not None:
+ s += " Text:%s" % self.text
+ return s
+
+ def loadFromString(self,line):
+ parts = line.split(",")
+ for i in range(len(parts)):
+ bit = parts[i].strip()
+ if bit.startswith("PCI:"):
+ pci_code = bit[4:].split(":")
+ self.pci_bus = int(pci_code[0])
+ self.pci_device = int(pci_code[1])
+ self.pci_function = int(pci_code[2])
+ elif bit.startswith("Vendor:"):
+ self.vendor = int(bit[7:],16)
+ elif bit.startswith("Device:"):
+ self.device = int(bit[7:],16)
+ elif bit.startswith("Subvendor:"):
+ self.subvendor = int(bit[10:],16)
+ elif bit.startswith("Subdevice:"):
+ self.subdevice = int(bit[10:],16)
+ elif bit.startswith("Class:"):
+ self.pci_class = int(bit[6:],16)
+ elif bit.startswith("Module:"):
+ self.module = bit[7:]
+ elif bit.startswith("Text:"):
+ self.text = " ".join(parts[i:]).strip()[5:]
+ break
+
+############################################################################
+class PCIBus(object):
+ PCI_CLASS_SERIAL_USB = 0x0c03
+ PCI_CLASS_SERIAL_FIREWIRE = 0x0c00
+ PCI_BASE_CLASS_MASK = 0xff00
+ PCI_BASE_CLASS_DISPLAY = 0x0300
+
+ def __init__(self, data_file_dir="."):
+ self.devices = []
+ self.data_file_dir = data_file_dir
+
+ def detect(self,device_data="/proc/bus/pci/devices"):
+ # Shamelessly translated from ldetect's pci.c.
+ fhandle = open(device_data)
+ for line in fhandle.readlines():
+ #print "L:",line
+ entry = PCIDevice()
+ self.devices.append(entry)
+ parts = line.split()
+
+ devbusfn = int(parts[0],16)
+ idbits = int(parts[1],16)
+ entry.vendor = idbits >> 16
+ entry.device = idbits & 0xffff
+ entry.pci_bus = devbusfn >> 8
+ entry.pci_device = (devbusfn & 0xff) >> 3
+ entry.pci_function = (devbusfn & 0xff) & 0x07
+
+ try:
+ infohandle = open("/proc/bus/pci/%02x/%02x.%d" % (
+ entry.pci_bus, entry.pci_device, entry.pci_function),"r")
+ # these files are 256 bytes but we only need first 48 bytes
+ buf = infohandle.read(48)
+ (class_prog, entry.pci_class, entry.subvendor, entry.subdevice) = \
+ struct.unpack("<xxxxxxxxxBHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxHH",buf)
+ #print "STRUCT: ",struct.unpack("@xxxxxxxxxBHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxHH",buf)
+ if (entry.subvendor==0 and entry.subdevice==0) or \
+ (entry.subvendor==entry.vendor and entry.subdevice==entry.device):
+ entry.subvendor = 0xffff
+ entry.subdevice = 0xffff
+ if entry.pci_class == PCIBus.PCI_CLASS_SERIAL_USB:
+ # taken from kudzu's pci.c
+ if class_prog == 0:
+ entry.module = "usb-uhci"
+ elif class_prog == 0x10:
+ entry.module = "usb-ohci"
+ elif class_prog == 0x20:
+ entry.module = "ehci-hcd"
+ if entry.pci_class == PCIBus.PCI_CLASS_SERIAL_FIREWIRE:
+ # taken from kudzu's pci.c
+ if class_prog == 0x10:
+ entry.module = "ohci1394"
+ infohandle.close()
+ except IOError:
+ pass
+ fhandle.close()
+
+ #if False or os.path.exists("/usr/share/ldetect-lst/pcitable"):
+ #self._resolveDevicesWithLdetect()
+ #else:
+ self._resolveDevicesWithHwdata()
+ #self._resolveDevicesWithDiscover()
+
+ def _resolveDevicesWithLdetect(self):
+ # Scan the PCI database.
+ #fhandle = open(os.path.join(self.data_file_dir,"pcitable"),"r")
+ fhandle = open(os.path.join("/opt/kde3/share/apps/guidance/","pcitable"),"r")
+
+ # This class is just for skipping comment lines in the database file.
+ # This whole class is just an iterator wrapper that we put around our file iterator.
+ class commentskipperiterator(object):
+ def __init__(self,fhandle):
+ self.fhandle = iter(fhandle)
+ def __iter__(self):
+ return self
+ def next(self):
+ line = self.fhandle.next()
+ while line[0]=="#":
+ line = self.fhandle.next()
+ return line
+
+ unknowndevices = self.devices[:]
+
+ # Process each row of the DB.
+ for row in csv.reader(commentskipperiterator(fhandle),delimiter='\t'):
+ if len(row)==4:
+ (vendor,device,module,text) = row
+ elif len(row)==6:
+ (vendor, device, subvendor, subdevice, module, text) = row
+ subvendor = int(subvendor[2:],16)
+ subdevice = int(subdevice[2:],16)
+ else:
+ continue
+ vendor = int(vendor[2:],16) # parse hex numbers of the form 0x1abc
+ device = int(device[2:],16)
+
+ i = 0
+ while i<len(unknowndevices):
+ pcidevice = unknowndevices[i]
+ if pcidevice.vendor==vendor and pcidevice.device==device \
+ and (len(row)==4 \
+ or (pcidevice.subvendor==subvendor and pcidevice.subdevice==subdevice)):
+ if module!="unknown":
+ pcidevice.module = module
+ pcidevice.text = text
+ if len(row)==6: # Close match, also matched on subdevice/subvendor ids.
+ del unknowndevices[i]
+ else:
+ i += 1
+ else:
+ i += 1
+
+ fhandle.close()
+
+ def _resolveDevicesWithDiscover(self):
+
+ unknown_devices = self.devices[:]
+ self._resolveDevicesWithDiscoverFile("/usr/share/discover/pci-26.lst",unknown_devices)
+ self._resolveDevicesWithDiscoverFile("/usr/share/discover/pci.lst",unknown_devices)
+
+ def _resolveDevicesWithDiscoverFile(self,filename,unknown_devices):
+ # Scan the PCI database.
+ fhandle = open(filename,"r")
+
+ # Process each row of the DB.
+ for line in fhandle:
+ row = line.replace("\t"," ").split(" ")
+ if len(row) >= 1 and row[0] != '':
+ # Skip manufacturer info lines.
+ continue
+
+ vendor = int(row[1][:4],16)
+ device = int(row[1][4:],16)
+ module = row[3]
+ text = ' '.join(row[4:]).strip()
+
+ i = 0
+ while i<len(unknown_devices):
+ pcidevice = unknown_devices[i]
+ if pcidevice.vendor==vendor and pcidevice.device==device:
+ pcidevice.module = module
+ pcidevice.text = text
+ del unknown_devices[i]
+ else:
+ i += 1
+
+ fhandle.close()
+
+ def _resolveDevicesWithHwdata(self):
+ # Scan the PCI database.
+ fhandle = open("/usr/share/hwdata/pci.ids","r")
+
+ # This class is just for skipping comment lines in the database file.
+ # This whole class is just an iterator wrapper that we put around our file iterator.
+ class commentskipperiterator(object):
+ def __init__(self,fhandle):
+ self.fhandle = iter(fhandle)
+ def __iter__(self):
+ return self
+ def next(self):
+ line = self.fhandle.next()
+ while line[0]=="#":
+ line = self.fhandle.next()
+ return line
+
+ unknowndevices = self.devices[:]
+
+ # Process each row of the DB.
+ for row in fhandle:
+ stripped_row = row.strip()
+
+ if stripped_row=='' or stripped_row[0]=='#':
+ continue # Comment or blank line, skip it.
+
+ if stripped_row[0]=='C':
+ # Reached the device class data, stop.
+ break
+
+ if row[0]!='\t':
+ # Vendor line
+ vendor_parts = stripped_row.split(' ')
+ vendor = int(vendor_parts[0],16)
+ continue
+
+ if row[1]!='\t':
+ # Device line
+ device_parts = stripped_row.split(' ')
+ device = int(device_parts[0],16)
+ subvendor = None
+ subdevice = None
+ else:
+ # Subvendor line
+ subvendor_parts = stripped_row.split(' ')
+ subvendor = int(subvendor_parts[0],16)
+ subdevice = int(subvendor_parts[1],16)
+
+ i = 0
+ while i<len(unknowndevices):
+ pcidevice = unknowndevices[i]
+ if pcidevice.vendor==vendor and pcidevice.device==device \
+ and (subvendor is None \
+ or (pcidevice.subvendor==subvendor and pcidevice.subdevice==subdevice)):
+ #pcidevice.module = module
+ if subvendor is None:
+ pcidevice.text = ' '.join(vendor_parts[1:]) + '|' + ' '.join(device_parts[1:]).strip()
+ i += 1
+ else:
+ pcidevice.text = ' '.join(vendor_parts[1:]) + '|' + ' '.join(device_parts[1:]+subvendor_parts[2:]).strip()
+ del unknowndevices[i] # Perfect match, finished with this device.
+ else:
+ i += 1
+
+ fhandle.close()
+
+ def __str__(self):
+ return "\n".join([str(x) for x in self.devices])
+
+ def loadFromFile(self,filename):
+ fhandle = open(filename,'r')
+ for line in fhandle.readlines():
+ if line.strip()!="":
+ entry = PCIDevice(line=line)
+ self.devices.append(entry)
+ fhandle.close()
+
+############################################################################
+def main():
+ bus = PCIBus("ldetect-lst/")
+ if len(sys.argv)>1:
+ if sys.argv[1]=="--help" or sys.argv[1]=="-h":
+ print "Usage:\n ScanPCI.py <pci device file name>"
+ sys.exit(0)
+ bus.detect(sys.argv[1])
+ else:
+ bus.detect()
+ print bus
+
+if __name__=='__main__':
+ main()