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":
133 vendor_id= long(line_parts[1],16)
134 except ValueError, e:
135 sys.stderr.write( "Skipping line %d in %s " \
136 "(incorrect vendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[1]))
140 device_id= long(line_parts[2],16)
141 except ValueError, e:
142 sys.stderr.write( "Skipping line %d in %s " \
143 "(incorrect device id format %s)\n" % (line_num,modules_pcimap_path,line_parts[2]))
147 subvendor_id= long(line_parts[3],16)
148 except ValueError, e:
149 sys.stderr.write( "Skipping line %d in %s " \
150 "(incorrect subvendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[3]))
154 subdevice_id= long(line_parts[4],16)
155 except ValueError, e:
156 sys.stderr.write( "Skipping line %d in %s " \
157 "(incorrect subdevice id format %s)\n" % (line_num,modules_pcimap_path,line_parts[4]))
160 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
161 if not all_modules.has_key(module):
162 # normally shouldn't get here, as the list is
163 # prepopulated with all the built modules
165 # XXX we probably shouldn't be doing this at all
166 all_modules[module] = [full_id]
168 all_modules[module].append(full_id)
170 if all_pci_ids.has_key(full_id):
171 # conflict as there are multiple modules that support
172 # particular pci device
173 all_pci_ids[full_id].append(module)
175 all_pci_ids[full_id]= [module]
179 # parse pcitable, add any more ids for the devices
180 # We make the (potentially risky) assumption that pcitable contains
181 # only unique (vendor,device,subvendor,subdevice) entries.
183 for line in pcitable_file:
186 # skip blank lines, or lines that begin with # (comments)
187 line= string.strip(line)
194 line_parts= string.split(line)
195 if line_parts is None or len(line_parts) <= 2:
196 sys.stderr.write( "Skipping line %d in pcitable " \
197 "(incorrect format 1)\n" % line_num )
200 # vendor id is always the first field, device the second. also,
201 # strip off first two chars (the 0x)
203 vendor_id= long(line_parts[0],16)
204 except ValueError, e:
205 sys.stderr.write( "Skipping vendor_id %s in %s on line %d\n" \
206 % (line_parts[0],pcitable_path,line_num))
210 device_id= long(line_parts[1],16)
211 except ValueError, e:
212 sys.stderr.write( "Skipping device %s in %s on line %d\n" \
213 % (line_parts[1],pcitable_path,line_num))
216 # if the first char of the third field is a double
217 # quote, the third field is a module, else if the first
218 # char of the third field is a 0 (zero), the fifth field is
219 # the module name. it would nice if there was any easy way
220 # to split a string on spaces, but recognize quoted strings,
221 # so they wouldn't be split up. that is the reason for this wierd check
222 if line_parts[2][0] == '"':
223 module= line_parts[2]
227 elif line_parts[2][0] == '0':
229 module= line_parts[4]
230 except ValueError, e:
231 sys.stderr.write( "Skipping line %d in pcitable " \
232 "(incorrect format 2)\n" % line_num )
235 subvendor_id= long(line_parts[2],16)
236 except ValueError, e:
237 sys.stderr.write( "Skipping line %d in pcitable " \
238 "(incorrect format 2a)\n" % line_num )
242 subdevice_id= long(line_parts[3],16)
243 except ValueError, e:
244 sys.stderr.write( "Skipping line %d in pcitable " \
245 "(incorrect format 2b)\n" % line_num )
248 sys.stderr.write( "Skipping line %d in pcitable " \
249 "(incorrect format 3)\n" % line_num )
252 # remove the first and last char of module (quote marks)
254 module= module[:len(module)-1]
256 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
258 if not all_modules.has_key(module):
259 # Do not process any modules listed in pcitable for which
260 # we do not have a prebuilt module.
263 if not full_id in all_modules[module]:
264 all_modules[module].append(full_id)
266 if all_pci_ids.has_key(full_id):
267 if not module in all_pci_ids[full_id]:
268 all_pci_ids[full_id].append(module)
270 # check if there are duplicate mappings between modules
272 if len(all_pci_ids[full_id])>1:
273 # collect the set of modules that are different than what
274 # is listed in the pcitables file
276 for other_module in all_pci_ids[full_id]:
277 if other_module != module:
278 other_modules.append(other_module)
280 # remove full_id from the set of other modules in all_modules {}
281 for other_module in other_modules:
282 all_modules[other_module].remove(full_id)
284 # ensure that there is only one full_id -> module
285 all_pci_ids[full_id] = [module]
288 all_pci_ids[full_id] = [module]
290 pcitable_file.close()
292 return (all_pci_ids,all_modules)
294 if __name__ == "__main__":
297 print( "%s <modules.dep> <modules.pcimap> " \
298 "<pcitable> [<output>]" % sys.argv[0] )
301 if len(sys.argv) < 4:
306 if len(sys.argv) > 4:
307 output_file_name= sys.argv[4]
309 output_file= file(output_file_name,"w")
311 sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
314 output_file= sys.stdout
317 (all_pci_ids,all_modules)=merge_files( sys.argv[1],
320 if all_modules is not None:
321 for module in all_modules.keys():
322 pci_ids = all_modules[module]
324 output_file.write("%s" % module)
325 for pci_id in pci_ids:
326 output_file.write(" %x:%x:%x:%x" % pci_id)
327 output_file.write(" \n")
329 sys.stderr.write( "Unable to list modules.\n" )