3 # Copyright (c) 2003 Intel Corporation
6 # Copyright (c) 2004-2006 The Trustees of Princeton University
11 The point of this small utility is to take a file in the format
12 of /lib/modules/`uname -r`/modules.pcimap and /usr/share/hwdata/pcitable
13 and output a condensed, more easily used format for module detection. This is
14 done by first getting a list of all the built modules, then loading the
15 pci ids for each of those modules from modules.pcimap, then finally merging
16 in the contents of pcitable (for built modules only). The result should be
17 a file with a pretty comprehensive mapping of pci ids to module names.
19 The output is used by the PlanetLab boot cd (3.0+) and the pl_hwinit script
20 to load all the applicable modules by scanning lspci output.
24 Expected format of file modules.dep includes lines of:
26 /full/module/path/mod.ko: <dependencies>
28 Expected format of file modules.pcimap includes lines of:
30 # pci_module vendor device subvendor subdevice class class_mask driver_data
31 cciss 0x00000e11 0x0000b060 0x00000e11 0x00004070 0x00000000 0x00000000 0x0
32 cciss 0x00000e11 0x0000b178 0x00000e11 0x00004070 0x00000000 0x00000000 0x0
34 Expected format of file pcitable includes lines of:
36 # ("%d\t%d\t%s\t"%s"\n", vendid, devid, moduleName, cardDescription)
37 # or ("%d\t%d\t%d\t%d\t%s\t"%s"\n", vendid, devid, subvendid, subdevid, moduleNa
38 # me, cardDescription)
39 0x0e11 0x0508 "tmspci" "Compaq|Netelligent 4/16 Token Ring"
40 0x1000 0x0407 0x8086 0x0532 "megaraid" "Storage RAID Controller SRCU42X"
42 Lines listing a module name of ignore or unknown from pcitable are skipped
46 Output format, for each line that matches the above lines:
47 cciss 0e11:b060 0e11:b178
56 def merge_files(modules_dep_path, modules_pcimap_path, pcitable_path):
58 merge the three files as described above, and return a dictionary.
59 keys are module names, value is a list of pci ids for that module,
60 in the form "0e11:b178"
64 modulesdep_file= file(modules_dep_path,"r")
66 sys.stderr.write( "Unable to open modules.dep: %s\n" %
71 pcimap_file= file(modules_pcimap_path,"r")
73 sys.stderr.write( "Unable to open modules.pcimap: %s\n" %
78 pcitable_file= file(pcitable_path,"r")
80 sys.stderr.write( "Unable to open pcitable: %s\n" %
84 # associative array to store all matches of module -> ['vendor:device',..]
89 # first step, create an associative array of all the built modules
90 for line in modulesdep_file:
91 parts= string.split(line,":")
95 full_mod_path= parts[0]
96 parts= string.split(full_mod_path,"/")
97 module= parts[len(parts)-1]
98 module_len= len(module)
99 if module[module_len-3:] == ".ko":
101 all_modules[module]= []
103 modulesdep_file.close()
105 # now, parse the pcimap and add devices
107 for line in pcimap_file:
110 # skip blank lines, or lines that begin with # (comments)
111 line= string.strip(line)
118 line_parts= string.split(line)
119 if line_parts is None or len(line_parts) != 8:
120 sys.stderr.write( "Skipping line %d in pcimap " \
121 "(incorrect format %s)\n" % (line_num,line) )
124 # first two parts are always vendor / device id
125 module= line_parts[0]
127 # XXX In kernel versions <2.6.14, mptscsih is the actual
128 # module that should be loaded instead of mptbase.
129 if module == "mptbase":
132 # XXX ata_piix and ahci both claim the same chipsets, and it
133 # is usually a non-visible BIOS option that decides which is
134 # appropriate. Prefer ata_piix over ahci for now.
139 vendor_id= long(line_parts[1],16)
140 except ValueError, e:
141 sys.stderr.write( "Skipping line %d in %s " \
142 "(incorrect vendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[1]))
146 device_id= long(line_parts[2],16)
147 except ValueError, e:
148 sys.stderr.write( "Skipping line %d in %s " \
149 "(incorrect device id format %s)\n" % (line_num,modules_pcimap_path,line_parts[2]))
153 subvendor_id= long(line_parts[3],16)
154 except ValueError, e:
155 sys.stderr.write( "Skipping line %d in %s " \
156 "(incorrect subvendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[3]))
160 subdevice_id= long(line_parts[4],16)
161 except ValueError, e:
162 sys.stderr.write( "Skipping line %d in %s " \
163 "(incorrect subdevice id format %s)\n" % (line_num,modules_pcimap_path,line_parts[4]))
166 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
167 if not all_modules.has_key(module):
168 # normally shouldn't get here, as the list is
169 # prepopulated with all the built modules
171 # XXX we probably shouldn't be doing this at all
172 all_modules[module] = [full_id]
174 all_modules[module].append(full_id)
176 if all_pci_ids.has_key(full_id):
177 # conflict as there are multiple modules that support
178 # particular pci device
179 all_pci_ids[full_id].append(module)
181 all_pci_ids[full_id]= [module]
185 # parse pcitable, add any more ids for the devices
186 # We make the (potentially risky) assumption that pcitable contains
187 # only unique (vendor,device,subvendor,subdevice) entries.
189 for line in pcitable_file:
192 # skip blank lines, or lines that begin with # (comments)
193 line= string.strip(line)
200 line_parts= string.split(line)
201 if line_parts is None or len(line_parts) <= 2:
202 sys.stderr.write( "Skipping line %d in pcitable " \
203 "(incorrect format 1)\n" % line_num )
206 # vendor id is always the first field, device the second. also,
207 # strip off first two chars (the 0x)
209 vendor_id= long(line_parts[0],16)
210 except ValueError, e:
211 sys.stderr.write( "Skipping vendor_id %s in %s on line %d\n" \
212 % (line_parts[0],pcitable_path,line_num))
216 device_id= long(line_parts[1],16)
217 except ValueError, e:
218 sys.stderr.write( "Skipping device %s in %s on line %d\n" \
219 % (line_parts[1],pcitable_path,line_num))
222 # if the first char of the third field is a double
223 # quote, the third field is a module, else if the first
224 # char of the third field is a 0 (zero), the fifth field is
225 # the module name. it would nice if there was any easy way
226 # to split a string on spaces, but recognize quoted strings,
227 # so they wouldn't be split up. that is the reason for this wierd check
228 if line_parts[2][0] == '"':
229 module= line_parts[2]
233 elif line_parts[2][0] == '0':
235 module= line_parts[4]
236 except ValueError, e:
237 sys.stderr.write( "Skipping line %d in pcitable " \
238 "(incorrect format 2)\n" % line_num )
241 subvendor_id= long(line_parts[2],16)
242 except ValueError, e:
243 sys.stderr.write( "Skipping line %d in pcitable " \
244 "(incorrect format 2a)\n" % line_num )
248 subdevice_id= long(line_parts[3],16)
249 except ValueError, e:
250 sys.stderr.write( "Skipping line %d in pcitable " \
251 "(incorrect format 2b)\n" % line_num )
254 sys.stderr.write( "Skipping line %d in pcitable " \
255 "(incorrect format 3)\n" % line_num )
258 # remove the first and last char of module (quote marks)
260 module= module[:len(module)-1]
262 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
264 if not all_modules.has_key(module):
265 # Do not process any modules listed in pcitable for which
266 # we do not have a prebuilt module.
269 if not full_id in all_modules[module]:
270 all_modules[module].append(full_id)
272 if all_pci_ids.has_key(full_id):
273 if not module in all_pci_ids[full_id]:
274 all_pci_ids[full_id].append(module)
276 # check if there are duplicate mappings between modules
278 if len(all_pci_ids[full_id])>1:
279 # collect the set of modules that are different than what
280 # is listed in the pcitables file
282 for other_module in all_pci_ids[full_id]:
283 if other_module != module:
284 other_modules.append(other_module)
286 # remove full_id from the set of other modules in all_modules {}
287 for other_module in other_modules:
288 all_modules[other_module].remove(full_id)
290 # ensure that there is only one full_id -> module
291 all_pci_ids[full_id] = [module]
294 all_pci_ids[full_id] = [module]
296 pcitable_file.close()
298 return (all_pci_ids,all_modules)
300 if __name__ == "__main__":
303 print( "%s <modules.dep> <modules.pcimap> " \
304 "<pcitable> [<output>]" % sys.argv[0] )
307 if len(sys.argv) < 4:
312 if len(sys.argv) > 4:
313 output_file_name= sys.argv[4]
315 output_file= file(output_file_name,"w")
317 sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
320 output_file= sys.stdout
323 (all_pci_ids,all_modules)=merge_files( sys.argv[1],
326 if all_modules is not None:
327 for module in all_modules.keys():
328 pci_ids = all_modules[module]
330 output_file.write("%s" % module)
331 for pci_id in pci_ids:
332 output_file.write(" %x:%x:%x:%x" % pci_id)
333 output_file.write(" \n")
335 sys.stderr.write( "Unable to list modules.\n" )