4 The point of this small utility is to take a file in the format
5 of /lib/modules/`uname -r`/modules.pcimap and /usr/share/hwdata/pcitable
6 and output a condensed, more easily used format for module detection. This is
7 done by first getting a list of all the built modules, then loading the
8 pci ids for each of those modules from modules.pcimap, then finally merging
9 in the contents of pcitable (for built modules only). The result should be
10 a file with a pretty comprehensive mapping of pci ids to module names.
12 The output is used by the PlanetLab boot cd (3.0+) and the pl_hwinit script
13 to load all the applicable modules by scanning lspci output.
17 Expected format of file modules.dep includes lines of:
19 /full/module/path/mod.ko: <dependencies>
21 Expected format of file modules.pcimap includes lines of:
23 # pci_module vendor device subvendor subdevice class class_mask driver_data
24 cciss 0x00000e11 0x0000b060 0x00000e11 0x00004070 0x00000000 0x00000000 0x0
25 cciss 0x00000e11 0x0000b178 0x00000e11 0x00004070 0x00000000 0x00000000 0x0
27 Expected format of file pcitable includes lines of:
29 # ("%d\t%d\t%s\t"%s"\n", vendid, devid, moduleName, cardDescription)
30 # or ("%d\t%d\t%d\t%d\t%s\t"%s"\n", vendid, devid, subvendid, subdevid, moduleNa
31 # me, cardDescription)
32 0x0e11 0x0508 "tmspci" "Compaq|Netelligent 4/16 Token Ring"
33 0x1000 0x0407 0x8086 0x0532 "megaraid" "Storage RAID Controller SRCU42X"
35 Lines listing a module name of ignore or unknown from pcitable are skipped
39 Output format, for each line that matches the above lines:
40 cciss 0e11:b060 0e11:b178
49 def merge_files(modules_dep_path, modules_pcimap_path, pcitable_path):
51 merge the three files as described above, and return a dictionary.
52 keys are module names, value is a list of pci ids for that module,
53 in the form "0e11:b178"
57 modulesdep_file= file(modules_dep_path,"r")
59 sys.stderr.write( "Unable to open modules.dep: %s\n" %
64 pcimap_file= file(modules_pcimap_path,"r")
66 sys.stderr.write( "Unable to open modules.pcimap: %s\n" %
71 pcitable_file= file(pcitable_path,"r")
73 sys.stderr.write( "Unable to open pcitable: %s\n" %
77 # associative array to store all matches of module -> ['vendor:device',..]
82 # first step, create an associative array of all the built modules
83 for line in modulesdep_file:
84 parts= string.split(line,":")
88 full_mod_path= parts[0]
89 parts= string.split(full_mod_path,"/")
90 module= parts[len(parts)-1]
91 module_len= len(module)
92 if module[module_len-3:] == ".ko":
94 all_modules[module]= []
96 modulesdep_file.close()
98 # now, parse the pcimap and add devices
100 for line in pcimap_file:
103 # skip blank lines, or lines that begin with # (comments)
104 line= string.strip(line)
111 line_parts= string.split(line)
112 if line_parts is None or len(line_parts) != 8:
113 sys.stderr.write( "Skipping line %d in pcimap " \
114 "(incorrect format %s)\n" % (line_num,line) )
117 # first two parts are always vendor / device id
118 module= line_parts[0]
120 # XXX In kernel versions <2.6.14, mptscsih is the actual
121 # module that should be loaded instead of mptbase.
122 if module == "mptbase":
126 vendor_id= long(line_parts[1],16)
127 except ValueError, e:
128 sys.stderr.write( "Skipping line %d in %s " \
129 "(incorrect vendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[1]))
133 device_id= long(line_parts[2],16)
134 except ValueError, e:
135 sys.stderr.write( "Skipping line %d in %s " \
136 "(incorrect device id format %s)\n" % (line_num,modules_pcimap_path,line_parts[2]))
140 subvendor_id= long(line_parts[3],16)
141 except ValueError, e:
142 sys.stderr.write( "Skipping line %d in %s " \
143 "(incorrect subvendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[3]))
147 subdevice_id= long(line_parts[4],16)
148 except ValueError, e:
149 sys.stderr.write( "Skipping line %d in %s " \
150 "(incorrect subdevice id format %s)\n" % (line_num,modules_pcimap_path,line_parts[4]))
153 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
154 if not all_modules.has_key(module):
155 # normally shouldn't get here, as the list is
156 # prepopulated with all the built modules
158 # XXX we probably shouldn't be doing this at all
159 all_modules[module] = [full_id]
161 all_modules[module].append(full_id)
163 if all_pci_ids.has_key(full_id):
164 # conflict as there are multiple modules that support
165 # particular pci device
166 all_pci_ids[full_id].append(module)
168 all_pci_ids[full_id]= [module]
172 # parse pcitable, add any more ids for the devices
173 # We make the (potentially risky) assumption that pcitable contains
174 # only unique (vendor,device,subvendor,subdevice) entries.
176 for line in pcitable_file:
179 # skip blank lines, or lines that begin with # (comments)
180 line= string.strip(line)
187 line_parts= string.split(line)
188 if line_parts is None or len(line_parts) <= 2:
189 sys.stderr.write( "Skipping line %d in pcitable " \
190 "(incorrect format 1)\n" % line_num )
193 # vendor id is always the first field, device the second. also,
194 # strip off first two chars (the 0x)
196 vendor_id= long(line_parts[0],16)
197 except ValueError, e:
198 sys.stderr.write( "Skipping vendor_id %s in %s on line %d\n" \
199 % (line_parts[0],pcitable_path,line_num))
203 device_id= long(line_parts[1],16)
204 except ValueError, e:
205 sys.stderr.write( "Skipping device %s in %s on line %d\n" \
206 % (line_parts[1],pcitable_path,line_num))
209 # if the first char of the third field is a double
210 # quote, the third field is a module, else if the first
211 # char of the third field is a 0 (zero), the fifth field is
212 # the module name. it would nice if there was any easy way
213 # to split a string on spaces, but recognize quoted strings,
214 # so they wouldn't be split up. that is the reason for this wierd check
215 if line_parts[2][0] == '"':
216 module= line_parts[2]
220 elif line_parts[2][0] == '0':
222 module= line_parts[4]
223 except ValueError, e:
224 sys.stderr.write( "Skipping line %d in pcitable " \
225 "(incorrect format 2)\n" % line_num )
228 subvendor_id= long(line_parts[2],16)
229 except ValueError, e:
230 sys.stderr.write( "Skipping line %d in pcitable " \
231 "(incorrect format 2a)\n" % line_num )
235 subdevice_id= long(line_parts[3],16)
236 except ValueError, e:
237 sys.stderr.write( "Skipping line %d in pcitable " \
238 "(incorrect format 2b)\n" % line_num )
241 sys.stderr.write( "Skipping line %d in pcitable " \
242 "(incorrect format 3)\n" % line_num )
245 # remove the first and last char of module (quote marks)
247 module= module[:len(module)-1]
249 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
251 if not all_modules.has_key(module):
252 # Do not process any modules listed in pcitable for which
253 # we do not have a prebuilt module.
256 if not full_id in all_modules[module]:
257 all_modules[module].append(full_id)
259 if all_pci_ids.has_key(full_id):
260 if not module in all_pci_ids[full_id]:
261 all_pci_ids[full_id].append(module)
263 # check if there are duplicate mappings between modules
265 if len(all_pci_ids[full_id])>1:
266 # collect the set of modules that are different than what
267 # is listed in the pcitables file
269 for other_module in all_pci_ids[full_id]:
270 if other_module != module:
271 other_modules.append(other_module)
273 # remove full_id from the set of other modules in all_modules {}
274 for other_module in other_modules:
275 all_modules[other_module].remove(full_id)
277 # ensure that there is only one full_id -> module
278 all_pci_ids[full_id] = [module]
281 all_pci_ids[full_id] = [module]
283 pcitable_file.close()
285 return (all_pci_ids,all_modules)
287 if __name__ == "__main__":
290 print( "%s <modules.dep> <modules.pcimap> " \
291 "<pcitable> [<output>]" % sys.argv[0] )
294 if len(sys.argv) < 4:
299 if len(sys.argv) > 4:
300 output_file_name= sys.argv[4]
302 output_file= file(output_file_name,"w")
304 sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
307 output_file= sys.stdout
310 (all_pci_ids,all_modules)=merge_files( sys.argv[1],
313 if all_modules is not None:
314 for module in all_modules.keys():
315 pci_ids = all_modules[module]
317 output_file.write("%s" % module)
318 for pci_id in pci_ids:
319 output_file.write(" %x:%x:%x:%x" % pci_id)
320 output_file.write(" \n")
322 sys.stderr.write( "Unable to list modules.\n" )