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.
tde-guidance/displayconfig/ScanPCI.py

341 lines
13 KiB

###########################################################################
# 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()