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 class merge_hw_tables:
51 def merge_files(self, modules_dep_path, modules_pcimap_path, pcitable_path):
53 merge the three files as described above, and return a dictionary.
54 keys are module names, value is a list of pci ids for that module,
55 in the form "0e11:b178"
59 modulesdep_file= file(modules_dep_path,"r")
61 sys.stderr.write( "Unable to open modules.dep: %s\n" %
66 pcimap_file= file(modules_pcimap_path,"r")
68 sys.stderr.write( "Unable to open modules.pcimap: %s\n" %
73 pcitable_file= file(pcitable_path,"r")
75 sys.stderr.write( "Unable to open pcitable: %s\n" %
80 # associative array to store all matches of module -> ['vendor:device',..]
85 # first step, create an associative array of all the built modules
86 for line in modulesdep_file:
87 parts= string.split(line,":")
91 full_mod_path= parts[0]
92 parts= string.split(full_mod_path,"/")
93 module_name= parts[len(parts)-1]
94 module_name_len= len(module_name)
95 if module_name[module_name_len-3:] == ".ko":
96 all_modules[module_name[:-3]]= []
99 # now, parse the pcimap and add devices
101 for line in pcimap_file:
104 # skip blank lines, or lines that begin with # (comments)
105 line= string.strip(line)
112 line_parts= string.split(line)
113 if line_parts is None or len(line_parts) != 8:
114 sys.stderr.write( "Skipping line %d in pcimap " \
115 "(incorrect format)\n" % line_num )
118 # first two parts are always vendor / device id
119 module= line_parts[0]
120 vendor_id= line_parts[1]
121 device_id= line_parts[2]
124 # valid vendor and devices are 10 chars (0xXXXXXXXX) and begin with 0x
125 if len(vendor_id) != 10 or len(device_id) != 10:
126 sys.stderr.write( "Skipping line %d in pcimap " \
127 "(invalid vendor/device id length)\n" %
131 if string.lower(vendor_id[:2]) != "0x" \
132 or string.lower(device_id[:2]) != "0x":
133 sys.stderr.write( "Skipping line %d in pcimap " \
134 "(invalid vendor/device id format)\n" % line_num )
137 # cut down the ids, only need last 4 bytes
138 # start at 6 = (10 total chars - 4 last chars need)
139 vendor_id= string.lower(vendor_id[6:])
140 device_id= string.lower(device_id[6:])
142 full_id= "%s:%s" % (vendor_id, device_id)
144 if all_modules.has_key(module):
145 if full_id not in all_modules[module]:
146 all_modules[module].append( full_id )
148 # normally shouldn't get here, as the list is
149 # prepopulated with all the built modules
150 all_modules[module]= [full_id,]
153 # parse pcitable, add any more ids for the devices
155 for line in pcitable_file:
158 # skip blank lines, or lines that begin with # (comments)
159 line= string.strip(line)
166 line_parts= string.split(line)
167 if line_parts is None or len(line_parts) <= 2:
168 sys.stderr.write( "Skipping line %d in pcitable " \
169 "(incorrect format 1)\n" % line_num )
172 # vendor id is always the first field, device the second. also,
173 # strip off first two chars (the 0x)
174 vendor_id= string.lower(line_parts[0][2:])
175 device_id= string.lower(line_parts[1][2:])
177 full_id= "%s:%s" % (vendor_id, device_id)
179 # if the first char of the third field is a double
180 # quote, the third field is a module, else if the first
181 # char of the third field is a 0 (zero), the fifth field is
182 # the module name. it would nice if there was any easy way
183 # to split a string on spaces, but recognize quoted strings,
184 # so they wouldn't be split up. that is the reason for this wierd check
185 if line_parts[2][0] == '"':
186 module= line_parts[2]
187 elif line_parts[2][0] == '0':
189 module= line_parts[4]
190 except ValueError, e:
191 sys.stderr.write( "Skipping line %d in pcitable " \
192 "(incorrect format 2)\n" % line_num )
195 sys.stderr.write( "Skipping line %d in pcitable " \
196 "(incorrect format 3)\n" % line_num )
199 # remove the first and last char of module (quote marks)
201 module= module[:len(module)-1]
203 # now add it if we don't already have this module -> id mapping
204 if all_modules.has_key(module):
205 if full_id not in all_modules[module]:
206 all_modules[module].append( full_id )
208 # don't add any modules from pcitable that we don't
212 pcitable_file.close()
214 modulesdep_file.close()
220 if __name__ == "__main__":
223 print( "rewrite-pcitable.py <modules.dep> <modules.pcimap> " \
224 "<pcitable> [<output>]" )
228 if len(sys.argv) < 4:
233 if len(sys.argv) > 4:
234 output_file_name= sys.argv[4]
236 output_file= file(output_file_name,"w")
238 sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
241 output_file= sys.stdout
244 all_modules= merge_hw_tables().merge_files( sys.argv[1], sys.argv[2],
247 if all_modules is not None:
248 for module in all_modules.keys():
249 devices= all_modules[module]
251 devices_str= string.join( all_modules[module], " " )
252 output_file.write( "%s %s\n" % (module,devices_str) )
254 sys.stderr.write( "Unable to list modules.\n" )