3
from subprocess import PIPE, Popen
7
class HardwareDetection(object):
10
* Detect the available graphics cards
11
* See what drivers support them (If they are
12
ATI or NVIDIA cards). If more than one card is
13
available, try to find the highest common
14
driver version which supports them all.
15
(READ the comments in the code for further
17
* Return a dictionary such as the following:
22
0: {'compatible': True, 'recommended': True, 'name': 'xorg-driver-fglrx'}
25
0: {'compatible': True, 'recommended': False, 'name': 'nvidia-glx-177'},
26
1: {'compatible': True, 'recommended': True, 'name': 'nvidia-glx-173'},
27
2: {'compatible': True, 'recommended': False, 'name': 'nvidia-glx-96'},
28
3: {'compatible': False, 'recommended': False, 'name': 'nvidia-glx-71'}
34
aliasesPath = '/usr/share/jockey/modaliases/'
37
def __init__(self, datadir=aliasesPath):
39
If the modaliases path does not exist
40
print none, so that debconf is not triggered.
42
if not os.path.isdir(datadir):
44
raise IOError, "dir %s not found" % datadir
45
self.datadir = datadir
49
self.removeUnsupported()
53
Detect the models of the graphics cards
54
and store them in self.cards
57
p1 = Popen(['lspci', '-n'], stdout=PIPE)
58
p = p1.communicate()[0].split('\n')
59
indentifier1 = re.compile('.*0300: *(.+):(.+) \(.+\)')
60
indentifier2 = re.compile('.*0300: *(.+):(.+)')
62
m1 = indentifier1.match(line)
63
m2 = indentifier2.match(line)
65
id1 = m1.group(1).strip().lower()
66
id2 = m1.group(2).strip().lower()
70
id1 = m2.group(1).strip().lower()
71
id2 = m2.group(2).strip().lower()
77
Get the data from the modaliases for each driver
78
and store them in self.drivers
81
files = os.listdir(self.datadir)
85
a = open(self.datadir + file, 'r')
87
NvidiaIdentifier = re.compile('.*alias pci:v0000(.+)d0000(.+)sv.*nvidia.*nvidia-glx-(.+).*')
88
AtiIdentifier = re.compile('.*alias pci:v0000(.+)d0000(.+)sv\*sd\*bc03sc\*i\*.*fglrx.*')
90
m1 = NvidiaIdentifier.match(line)
91
m2 = AtiIdentifier.match(line)
93
id1 = m1.group(1).strip().lower()#e.g. 10de or 12d2 for nvidia
94
id2 = m1.group(2).strip().lower()#the id which is specific to the model
95
drivername = m1.group(3).strip().lower()#e.g. 173, 177, 96 or 71
96
if id1 in ['10de', '12d2']:#if NVIDIA
97
self.drivers.setdefault('nvidia', {}).setdefault(int(drivername), []).append(id1 + ':' + id2)
99
id1 = m2.group(1).strip().lower()#e.g. 1002 for ati
100
id2 = m2.group(2).strip().lower()#the id which is specific to the model
101
drivername = 'fglrx'#m1.group(3).strip().lower()#e.g. 173, 177, 96 or 71
102
if id1 in ['1002']:#if ATI
103
self.drivers.setdefault('fglrx', {}).setdefault(drivername, []).append(id1 + ':' + id2)
108
If the modaliases files don't contain anything useful
109
just print none and exit so as not to trigger debconf.
111
if len(self.drivers.keys()) == 0:
112
raise ValueError, "modaliases have no useful information"
116
See if the detected graphics cards are NVIDIA cards.
117
If they are NVIDIA cards, append them to self.nvidiaCards
119
self.driversForCards = {}
120
self.nvidiaCards = []
123
It is possible to override hardware detection (only for testing
124
purposes) by setting self.cards to one of the following lists:
126
self.cards = ['10de:02e2', '10de:002d', '10de:0296', '10de:087f']
127
self.cards = ['10de:02e2', '10de:087f']
128
self.cards = ['10de:02e2', '10de:087f', '10de:fake']
129
self.cards = ['10de:fake']
130
self.cards = ['1002:fake'] ATI
131
self.cards = ['1002:95c7'] ATI
133
#self.cards = ['1002:fake', '1002:95c7']
135
for card in self.cards:
136
if card[0: card.find(':')] in ['10de', '12d2']:
137
self.nvidiaCards.append(card)
138
elif card[0: card.find(':')] == '1002':
139
self.atiCards.append(card)
141
self.nvidiaOrderedList = self.drivers['nvidia'].keys()
142
self.nvidiaOrderedList.sort(reverse=True)
144
self.atiOrderedList = self.drivers['fglrx'].keys()
146
See what drivers support each card and fill self.driversForCards
147
so as to have something like the following:
149
self.driversForCards = {
150
'id_of_card1': [driver1, driver2],
151
'id_of_card2': [driver2, driver3],
154
for card in self.nvidiaCards:
156
for driver in self.nvidiaOrderedList:
157
if card in self.drivers['nvidia'][driver]:
159
self.driversForCards.setdefault(card, []).append(driver)
160
if supported == False:
161
self.driversForCards.setdefault(card, []).append(None)
163
for card in self.atiCards:
165
for driver in self.atiOrderedList:
166
if card in self.drivers['fglrx'][driver]:
168
self.driversForCards.setdefault(card, []).append(driver)
169
if supported == False:
170
self.driversForCards.setdefault(card, []).append(None)
172
def removeUnsupported(self):
174
Remove unsupported cards from self.nvidiaCards and from
177
#print self.driversForCards
178
unsupportedCards = []
179
for card in self.driversForCards:
180
if None in self.driversForCards[card]:
181
unsupportedCards.append(card)
183
for unsupported in unsupportedCards:
185
self.nvidiaCards.remove(unsupported)
187
self.atiCards.remove(unsupported)
188
del self.driversForCards[unsupported]
190
def selectDriver(self):
192
If more than one card is available, try to get the highest common driver
195
compatibleDrivers = {}
196
recommendedDrivers = {}
197
availableDrivers = {}
199
nvidiaCardsNumber = len(self.nvidiaCards)
200
atiCardsNumber = len(self.atiCards)
201
if nvidiaCardsNumber > 0:#if a NVIDIA card is available
202
if nvidiaCardsNumber > 1:#if more than 1 card
204
occurrence stores the number of occurrences (the values of the
205
dictionary) of each driver version (the keys of the dictionary)
208
occurrence = {177: 1, 173: 3}
209
This means that driver 177 supports only 1 card while 173
213
#print self.driversForCards
214
for card in self.driversForCards:
215
if '1002' not in card:
216
for drv in self.driversForCards[card]:
217
occurrence.setdefault(drv, 0)
220
occurrences = occurrence.keys()
221
occurrences.sort(reverse=True)
223
candidates is the list of the likely candidates for the
227
for driver in occurrences:
228
if occurrence[driver] == nvidiaCardsNumber:
229
candidates.append(driver)
232
if len(candidates) > 0:
234
If more than one driver version works for all the available
235
cards then the newest one is selected.
238
If a user has the following cards:
239
* GeForce 9300 (supported by driver 177 and 173)
240
* GeForce 7300 (supported by driver 177 and 173)
241
* GeForce 6200 (supported by driver 177 and 173)
243
Driver 177 is selected.
245
candidates.sort(reverse=True)
248
if 173 in candidates['nvidia'] and 177 in candidates['nvidia']:
250
Prefer the stable driver
252
choice = candidates['nvidia'][1]
254
choice = candidates['nvidia'][0]
255
# if self.verbose and not self.printonly:
256
# print 'Recommended NVIDIA driver:', choice
259
Otherwise, if there is no single driver version which works
260
for all the available cards, the newest is selected.
263
If a user has the following cards:
264
* GeForce 9300 (supported by driver 177 and 173)
265
* GeForce 1 (supported by driver 71)
266
* GeForce 2 (supported by driver 71)
268
The most modern card has the highest priority since
269
no common driver can be found. The other 2 cards
270
should use the open source driver
273
if 173 in occurrences and 177 in occurrences:
275
Prefer the stable driver
277
choice = occurrences[1]
279
choice = occurrences[0]
280
# if self.verbose and not self.printonly:
281
# print 'Recommended NVIDIA driver:', choice
282
else:#just one NVIDIA card
284
The choice is easy if only one card is available and/or supported.
286
The newest driver which supports the card is chosen.
289
for card in self.driversForCards.keys():
290
if '1002' not in card:
294
drivers = self.driversForCards[self.driversForCards.keys()[position]]
296
if 173 in drivers and 177 in drivers:
298
Prefer the stable driver
304
#choice = self.driversForCards[self.driversForCards.keys()[position]][0]
306
for card in self.driversForCards:
307
if '1002' not in card:
308
for drv in self.driversForCards[card]:
309
compatibleDrivers.setdefault('nvidia', []).append('nvidia-glx-' + str(drv))
311
choice = 'nvidia-glx-' + str(choice)
313
recommendedDrivers['nvidia'] = choice
317
if atiCardsNumber > 0:
318
choice = self.driversForCards[self.driversForCards.keys()[0]][0]
320
compatibleDrivers.setdefault('fglrx', []).append('xorg-driver-' + choice)
321
recommendedDrivers['fglrx'] = 'xorg-driver-' + choice
323
if atiCardsNumber == 0 and nvidiaCardsNumber == 0 :
325
If no card is supported
329
compatibleDrivers['nvidia'] = []
330
recommendedDrivers['nvidia'] = choice
331
compatibleDrivers['fglrx'] = []
332
recommendedDrivers['fglrx'] = choice
334
for driver in self.drivers:
335
availableDrivers.setdefault(driver, [])
337
for drv in self.drivers[driver]:
340
if driver == 'nvidia':
341
temp.sort(reverse=True)
343
availableDrivers[driver].append('nvidia-glx-' + str(drv))
344
elif driver == 'fglrx':
346
availableDrivers[driver].append('xorg-driver-' + str(drv))
348
for driver in availableDrivers:
350
self.driverDetails.setdefault(driver, {})
352
for drv in availableDrivers[driver]:
353
self.driverDetails[driver].setdefault(it, {})
354
self.driverDetails[driver][it]['name'] = drv
356
self.driverDetails[driver][it]['compatible'] = drv in compatibleDrivers[driver]
357
self.driverDetails[driver][it]['recommended'] = recommendedDrivers[driver] == drv
359
self.driverDetails[driver][it]['compatible'] = False
360
self.driverDetails[driver][it]['recommended'] = False
365
# print 'DriverDetails =', self.driverDetails
366
## print 'Compatible =', compatibleDrivers, '\nRecommended', recommendedDrivers
367
# print 'All drivers =', availableDrivers#self.drivers['nvidia'].keys(), self.drivers['fglrx'].keys()
368
return self.driverDetails
369
if __name__ == '__main__':
370
a = HardwareDetection()
371
print a.selectDriver()