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]
121 vendor_id= long(line_parts[1],16)
122 except ValueError, e:
123 sys.stderr.write( "Skipping line %d in %s " \
124 "(incorrect vendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[1]))
128 device_id= long(line_parts[2],16)
129 except ValueError, e:
130 sys.stderr.write( "Skipping line %d in %s " \
131 "(incorrect device id format %s)\n" % (line_num,modules_pcimap_path,line_parts[2]))
135 subvendor_id= long(line_parts[3],16)
136 except ValueError, e:
137 sys.stderr.write( "Skipping line %d in %s " \
138 "(incorrect subvendor id format %s)\n" % (line_num,modules_pcimap_path,line_parts[3]))
142 subdevice_id= long(line_parts[4],16)
143 except ValueError, e:
144 sys.stderr.write( "Skipping line %d in %s " \
145 "(incorrect subdevice id format %s)\n" % (line_num,modules_pcimap_path,line_parts[4]))
148 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
149 if not all_modules.has_key(module):
150 # normally shouldn't get here, as the list is
151 # prepopulated with all the built modules
153 # XXX we probably shouldn't be doing this at all
154 all_modules[module] = [full_id]
156 all_modules[module].append(full_id)
158 if all_pci_ids.has_key(full_id):
159 # conflict as there are multiple modules that support
160 # particular pci device
161 all_pci_ids[full_id].append(module)
163 all_pci_ids[full_id]= [module]
167 # parse pcitable, add any more ids for the devices
168 # We make the (potentially risky) assumption that pcitable contains
169 # only unique (vendor,device,subvendor,subdevice) entries.
171 for line in pcitable_file:
174 # skip blank lines, or lines that begin with # (comments)
175 line= string.strip(line)
182 line_parts= string.split(line)
183 if line_parts is None or len(line_parts) <= 2:
184 sys.stderr.write( "Skipping line %d in pcitable " \
185 "(incorrect format 1)\n" % line_num )
188 # vendor id is always the first field, device the second. also,
189 # strip off first two chars (the 0x)
191 vendor_id= long(line_parts[0],16)
192 except ValueError, e:
193 sys.stderr.write( "Skipping vendor_id %s in %s on line %d\n" \
194 % (line_parts[0],pcitable_path,line_num))
198 device_id= long(line_parts[1],16)
199 except ValueError, e:
200 sys.stderr.write( "Skipping device %s in %s on line %d\n" \
201 % (line_parts[1],pcitable_path,line_num))
204 # if the first char of the third field is a double
205 # quote, the third field is a module, else if the first
206 # char of the third field is a 0 (zero), the fifth field is
207 # the module name. it would nice if there was any easy way
208 # to split a string on spaces, but recognize quoted strings,
209 # so they wouldn't be split up. that is the reason for this wierd check
210 if line_parts[2][0] == '"':
211 module= line_parts[2]
215 elif line_parts[2][0] == '0':
217 module= line_parts[4]
218 except ValueError, e:
219 sys.stderr.write( "Skipping line %d in pcitable " \
220 "(incorrect format 2)\n" % line_num )
223 subvendor_id= long(line_parts[2],16)
224 except ValueError, e:
225 sys.stderr.write( "Skipping line %d in pcitable " \
226 "(incorrect format 2a)\n" % line_num )
230 subdevice_id= long(line_parts[3],16)
231 except ValueError, e:
232 sys.stderr.write( "Skipping line %d in pcitable " \
233 "(incorrect format 2b)\n" % line_num )
236 sys.stderr.write( "Skipping line %d in pcitable " \
237 "(incorrect format 3)\n" % line_num )
240 # remove the first and last char of module (quote marks)
242 module= module[:len(module)-1]
244 full_id= (vendor_id, device_id, subvendor_id, subdevice_id)
246 if not all_modules.has_key(module):
247 # Do not process any modules listed in pcitable for which
248 # we do not have a prebuilt module.
251 if not full_id in all_modules[module]:
252 all_modules[module].append(full_id)
254 if all_pci_ids.has_key(full_id):
255 if not module in all_pci_ids[full_id]:
256 all_pci_ids[full_id].append(module)
258 # check if there are duplicate mappings between modules
260 if len(all_pci_ids[full_id])>1:
261 # collect the set of modules that are different than what
262 # is listed in the pcitables file
264 for other_module in all_pci_ids[full_id]:
265 if other_module != module:
266 other_modules.append(other_module)
268 # remove full_id from the set of other modules in all_modules {}
269 for other_module in other_modules:
270 all_modules[other_module].remove(full_id)
272 # ensure that there is only one full_id -> module
273 all_pci_ids[full_id] = [module]
276 all_pci_ids[full_id] = [module]
278 pcitable_file.close()
280 return (all_pci_ids,all_modules)
282 if __name__ == "__main__":
285 print( "%s <modules.dep> <modules.pcimap> " \
286 "<pcitable> [<output>]" % sys.argv[0] )
289 if len(sys.argv) < 4:
294 if len(sys.argv) > 4:
295 output_file_name= sys.argv[4]
297 output_file= file(output_file_name,"w")
299 sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
302 output_file= sys.stdout
305 (all_pci_ids,all_modules)=merge_files( sys.argv[1],
308 if all_modules is not None:
309 for module in all_modules.keys():
310 pci_ids = all_modules[module]
312 output_file.write("%s" % module)
313 for pci_id in pci_ids:
314 output_file.write(" %x:%x:%x:%x" % pci_id)
315 output_file.write(" \n")
317 sys.stderr.write( "Unable to list modules.\n" )