in generating the pci table lookup for hardware detection, we now
[bootcd.git] / scripts / rewrite-pcitable.py
1 #!/usr/bin/env python
2
3 """
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.
11
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.
14
15
16
17 Expected format of file modules.dep includes lines of:
18
19 /full/module/path/mod.ko: <dependencies>
20
21 Expected format of file modules.pcimap includes lines of:
22
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
26
27 Expected format of file pcitable includes lines of:
28
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"
34
35 Lines listing a module name of ignore or unknown from pcitable are skipped
36
37
38
39 Output format, for each line that matches the above lines:
40 cciss 0e11:b060 0e11:b178
41
42 If no pci ids are found for a particular module:
43
44 sd_mod none:none
45 """
46
47 import os, sys
48 import string
49
50
51 def usage():
52     print( "\nUsage:" )
53     print( "rewrite-pcitable.py <modules.dep> <modules.pcimap> " \
54            "<pcitable> [<output>]" )
55     print( "" )
56
57
58 if len(sys.argv) < 4:
59     usage()
60     sys.exit(1)
61
62
63 # open modules.dep (for list of built modules)
64 modulesdep_file_name= sys.argv[1]
65 try:
66     modulesdep_file= file(modulesdep_file_name,"r")
67 except IOError:
68     sys.stderr.write( "Unable to open modules.dep: %s\n" % modulesdep_file_name )
69     usage()
70     sys.exit(1)
71     
72 # open modules.pcimap
73 pcimap_file_name= sys.argv[2]
74 try:
75     pcimap_file= file(pcimap_file_name,"r")
76 except IOError:
77     sys.stderr.write( "Unable to open modules.pcimap: %s\n" % pcimap_file_name )
78     usage()
79     sys.exit(1)
80
81 # open pcitable
82 pcitable_file_name= sys.argv[3]
83 try:
84     pcitable_file= file(pcitable_file_name,"r")
85 except IOError:
86     sys.stderr.write( "Unable to open pcitable: %s\n" % pcitable_file_name )
87     usage()
88     sys.exit(1)
89     
90 # finally, if we are supposed to output to a file, open that too
91 if len(sys.argv) > 4:
92     output_file_name= sys.argv[4]
93     try:
94         output_file= file(output_file_name,"w")
95     except IOError:
96         sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
97         sys.exit(1)
98 else:
99     output_file= sys.stdout
100
101
102 # associative array to store all matches of module -> ['vendor:device',..]
103 # entries
104 all_modules= {}
105
106
107 # first step, create an associative array of all the built modules
108 for line in modulesdep_file_name:
109     parts= string.split(line,":")
110     if len(parts) < 2:
111         continue
112
113     full_mod_path= parts[0]
114     parts= string.split(full_mod_path,"/")
115     module_name= parts[len(parts)-1]
116     module_name_len= len(module_name)
117     if module_name[module_name_len-3:] == ".ko":
118         all_modules[module_name[:3]]= []
119
120
121 # now, parse the pcimap and add devices
122 line_num= 0
123 for line in pcimap_file:
124     line_num= line_num+1
125     
126     # skip blank lines, or lines that begin with # (comments)
127     line= string.strip(line)
128     if len(line) == 0:
129         continue
130     
131     if line[0] == "#":
132         continue
133
134     line_parts= string.split(line)
135     if line_parts is None or len(line_parts) != 8:
136         sys.stderr.write( "Skipping line %d in pcimap (incorrect format)\n" %
137                           line_num )
138         continue
139
140     # first two parts are always vendor / device id
141     module= line_parts[0]
142     vendor_id= line_parts[1]
143     device_id= line_parts[2]
144     
145
146     # valid vendor and devices are 10 chars (0xXXXXXXXX) and begin with 0x
147     if len(vendor_id) != 10 or len(device_id) != 10:
148         sys.stderr.write( "Skipping line %d in pcimap (invalid vendor/device " \
149                           "id length)\n" % line_num )
150         continue
151
152     if string.lower(vendor_id[:2]) != "0x" \
153            or string.lower(device_id[:2]) != "0x":
154         sys.stderr.write( "Skipping line %d in pcimap (invalid vendor/device " \
155                           "id format)\n" % line_num )
156         continue
157
158     # cut down the ids, only need last 4 bytes
159     # start at 6 = (10 total chars - 4 last chars need)
160     vendor_id= string.lower(vendor_id[6:])
161     device_id= string.lower(device_id[6:])
162
163     full_id= "%s:%s" % (vendor_id, device_id)
164
165     if all_modules.has_key(module):
166         if full_id not in all_modules[module]:
167             all_modules[module].append( full_id )
168     else:
169         # normally shouldn't get here, as the list is prepopulated with all
170         # the built modules
171         all_modules[module]= [full_id,]
172
173
174 # parse pcitable, add any more ids for the devices
175 line_num= 0
176 for line in pcitable_file:
177     line_num= line_num+1
178     
179     # skip blank lines, or lines that begin with # (comments)
180     line= string.strip(line)
181     if len(line) == 0:
182         continue
183     
184     if line[0] == "#":
185         continue
186
187     line_parts= string.split(line)
188     if line_parts is None or len(line_parts) < 4:
189         sys.stderr.write( "Skipping line %d in pcitable (incorrect format)\n" %
190                           line_num )
191         continue
192
193     # vendor id is always the first field, device the second. also,
194     # strip off first two chars (the 0x)
195     vendor_id= string.lower(line_parts[0][2:])
196     device_id= string.lower(line_parts[1][2:])
197
198     full_id= "%s:%s" % (vendor_id, device_id)
199
200     # if the first char of the third field is a double quote, the third field
201     # is a module, else if the first char of the third field is a 0 (zero),
202     # the fifth field is the module name.
203     # it would nice if there was any easy way to split a string on spaces,
204     # but recognize quoted strings, so they wouldn't be split up. that is
205     # the reason for this wierd check
206     if line_parts[2][0] == '"':
207         module= line_parts[2]
208     elif line_parts[2][0] == '0':
209         module= line_parts[4]
210     else:
211         sys.stderr.write( "Skipping line %d in pcitable (incorrect format)\n" %
212                           line_num )
213         continue
214
215     # remove the first and last char of module (quote marks)
216     module= module[1:]
217     module= module[:len(module)-1]
218
219     # now add it if we don't already have this module -> id mapping
220     if all_modules.has_key(module):
221         if full_id not in all_modules[module]:
222             all_modules[module].append( full_id )
223     else:
224         # don't add any modules from pcitable that we don't already know about
225         pass
226         
227
228 for module in all_modules.keys():
229     devices= all_modules[module]
230     if len(devices) > 0:
231         devices_str= string.join( all_modules[module], " " )
232         output_file.write( "%s %s\n" % (module,devices_str) )
233
234     
235 output_file.close()
236 pcitable_file.close()
237 pcimap_file.close()
238 modulesdep_file.close()
239