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
57 def merge_files(modules_dep_path, modules_pcimap_path, pcitable_path):
59 merge the three files as described above, and return a dictionary.
60 keys are module names, value is a list of pci ids for that module,
61 in the form "0e11:b178"
65 modulesdep_file= file(modules_dep_path,"r")
67 sys.stderr.write( "Unable to open modules.dep: %s\n" %
72 pcimap_file= file(modules_pcimap_path,"r")
74 sys.stderr.write( "Unable to open modules.pcimap: %s\n" %
79 pcitable_file= file(pcitable_path,"r")
81 sys.stderr.write( "Unable to open pcitable: %s\n" %
83 pcitable_file=StringIO.StringIO()
85 # associative array to store all matches of module -> ['vendor:device',..]
90 # first step, create an associative array of all the built modules
91 for line in modulesdep_file:
92 parts= string.split(line,":")
96 full_mod_path= parts[0]
97 parts= string.split(full_mod_path,"/")
98 module= parts[len(parts)-1]
99 module_len= len(module)
100 if module[module_len-3:] == ".ko":
102 all_modules[module]= []
104 modulesdep_file.close()
106 # now, parse the pcimap and add devices
108 for line in pcimap_file:
111 # skip blank lines, or lines that begin with # (comments)
112 line= string.strip(line)
119 line_parts= string.split(line)
120 if line_parts is None or len(line_parts) != 8:
121 sys.stderr.write( "Skipping line %d in pcimap " \
122 "(incorrect format %s)\n" % (line_num,line) )
125 # first two parts are always vendor / device id
126 module= line_parts[0]
128 # XXX In kernel versions <2.6.14, mptscsih is the actual
129 # module that should be loaded instead of mptbase.
130 if module == "mptbase":
134 vendor_id= long(line_parts[1],16)
135 except ValueError, e:
136 sys.stderr.write( "Skipping line %d in %s " \
137 "(incorrect vendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[1]))
141 device_id= long(line_parts[2],16)
142 except ValueError, e:
143 sys.stderr.write( "Skipping line %d in %s " \
144 "(incorrect device id format %s)\n" % (line_num,modules_pcimap_path,line_parts[2]))
148 subvendor_id= long(line_parts[3],16)
149 except ValueError, e:
150 sys.stderr.write( "Skipping line %d in %s " \
151 "(incorrect subvendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[3]))
155 subdevice_id= long(line_parts[4],16)
156 except ValueError, e:
157 sys.stderr.write( "Skipping line %d in %s " \
158 "(incorrect subdevice id format %s)\n" % (line_num,modules_pcimap_path,line_parts[4]))
161 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
162 if not all_modules.has_key(module):
163 # normally shouldn't get here, as the list is
164 # prepopulated with all the built modules
166 # XXX we probably shouldn't be doing this at all
167 all_modules[module] = [full_id]
169 all_modules[module].append(full_id)
171 if all_pci_ids.has_key(full_id):
172 # conflict as there are multiple modules that support
173 # particular pci device
174 all_pci_ids[full_id].append(module)
176 all_pci_ids[full_id]= [module]
180 # parse pcitable, add any more ids for the devices
181 # We make the (potentially risky) assumption that pcitable contains
182 # only unique (vendor,device,subvendor,subdevice) entries.
184 for line in pcitable_file:
187 # skip blank lines, or lines that begin with # (comments)
188 line= string.strip(line)
195 line_parts= string.split(line)
196 if line_parts is None or len(line_parts) <= 2:
197 sys.stderr.write( "Skipping line %d in pcitable " \
198 "(incorrect format 1)\n" % line_num )
201 # vendor id is always the first field, device the second. also,
202 # strip off first two chars (the 0x)
204 vendor_id= long(line_parts[0],16)
205 except ValueError, e:
206 sys.stderr.write( "Skipping vendor_id %s in %s on line %d\n" \
207 % (line_parts[0],pcitable_path,line_num))
211 device_id= long(line_parts[1],16)
212 except ValueError, e:
213 sys.stderr.write( "Skipping device %s in %s on line %d\n" \
214 % (line_parts[1],pcitable_path,line_num))
217 # if the first char of the third field is a double
218 # quote, the third field is a module, else if the first
219 # char of the third field is a 0 (zero), the fifth field is
220 # the module name. it would nice if there was any easy way
221 # to split a string on spaces, but recognize quoted strings,
222 # so they wouldn't be split up. that is the reason for this wierd check
223 if line_parts[2][0] == '"':
224 module= line_parts[2]
228 elif line_parts[2][0] == '0':
230 module= line_parts[4]
231 except ValueError, e:
232 sys.stderr.write( "Skipping line %d in pcitable " \
233 "(incorrect format 2)\n" % line_num )
236 subvendor_id= long(line_parts[2],16)
237 except ValueError, e:
238 sys.stderr.write( "Skipping line %d in pcitable " \
239 "(incorrect format 2a)\n" % line_num )
243 subdevice_id= long(line_parts[3],16)
244 except ValueError, e:
245 sys.stderr.write( "Skipping line %d in pcitable " \
246 "(incorrect format 2b)\n" % line_num )
249 sys.stderr.write( "Skipping line %d in pcitable " \
250 "(incorrect format 3)\n" % line_num )
253 # remove the first and last char of module (quote marks)
255 module= module[:len(module)-1]
257 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
259 if not all_modules.has_key(module):
260 # Do not process any modules listed in pcitable for which
261 # we do not have a prebuilt module.
264 if not full_id in all_modules[module]:
265 all_modules[module].append(full_id)
267 if all_pci_ids.has_key(full_id):
268 if not module in all_pci_ids[full_id]:
269 all_pci_ids[full_id].append(module)
271 # check if there are duplicate mappings between modules
273 if len(all_pci_ids[full_id])>1:
274 # collect the set of modules that are different than what
275 # is listed in the pcitables file
277 for other_module in all_pci_ids[full_id]:
278 if other_module != module:
279 other_modules.append(other_module)
281 # remove full_id from the set of other modules in all_modules {}
282 for other_module in other_modules:
283 all_modules[other_module].remove(full_id)
285 # ensure that there is only one full_id -> module
286 all_pci_ids[full_id] = [module]
289 all_pci_ids[full_id] = [module]
291 pcitable_file.close()
293 return (all_pci_ids,all_modules)
295 if __name__ == "__main__":
298 print( "%s <modules.dep> <modules.pcimap> " \
299 "<pcitable> [<output>]" % sys.argv[0] )
302 if len(sys.argv) < 4:
307 if len(sys.argv) > 4:
308 output_file_name= sys.argv[4]
310 output_file= file(output_file_name,"w")
312 sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
315 output_file= sys.stdout
318 (all_pci_ids,all_modules)=merge_files( sys.argv[1],
321 if all_modules is not None:
322 for module in all_modules.keys():
323 pci_ids = all_modules[module]
325 output_file.write("%s" % module)
326 for pci_id in pci_ids:
327 output_file.write(" %x:%x:%x:%x" % pci_id)
328 output_file.write(" \n")
330 sys.stderr.write( "Unable to list modules.\n" )