1# PCI Header script
2#
3# Copyright 2006, Haiku.
4# Distributed under the terms of the MIT License.
5#
6# Authors:
7#		John Drinkwater, john@nextraweb.com
8#
9# Use with http://pciids.sourceforge.net/pci.ids
10# run as: awk -v HEADERFILE=pcihdr.h -f pci-header.awk pci.ids
11
12BEGIN {
13
14	# field separator, defining because user could have overridden
15	FS = " "
16
17	# Pass this in from outside with -v HEADERFILE=filenametouse
18	# we require pcihdr.h for our system
19	ofile = HEADERFILE
20
21	# possibly use this in the future
22	cleanvalues = "[^A-Za-z0-9{}\"'&@?!*.,:;+<> \\t\\/_\\[\\]=#()-]"
23	# ToDo: currently IDs aren't checked, we dumbly assume the source is clean
24
25	# descriptive output header
26	print "#if 0" > ofile
27	print "#\tPCIHDR.H: PCI Vendors, Devices, and Class Type information\n#" > ofile
28	print "#\tGenerated by pci-header.awk, source data from the following URI:\n#\thttp://pciids.sourceforge.net/pci.ids\n#" > ofile
29	print "#\tHeader created on " strftime( "%A, %d %b %Y %H:%M:%S %Z", systime() ) > ofile
30	print "#endif" > ofile
31
32	# and we start with vendors..
33	print "\ntypedef struct _PCI_VENTABLE\n{\n\tunsigned short\tVenId ;\n\tconst char *\tVenFull ;\n\tconst char *\tVenShort ;\n}  PCI_VENTABLE, *PPCI_VENTABLE ;\n" > ofile
34	print "PCI_VENTABLE\tPciVenTable [] =\n{" > ofile
35}
36
37# matches vendor - starts with an id as first thing on the line
38# because this occurs first in the header file, we output it without worry
39/^[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]] / { 
40
41	if ( vendorcount++ > 0 ) { 
42		formatting = ",\n"
43	} else {
44		formatting = ""
45	}
46
47	# store vendor ID for possible devices afterwards
48	vendorid = $1
49	vendor = substr($0, 7)
50	gsub( /\"/, "&&", vendor )
51
52	# Remove double interrogation points that may be interpreted as trigraphs
53	gsub( /\?\?\?/, "xxx", vendor )
54	gsub( /\?\?/, "xx", vendor )
55
56	printf formatting "\t{ 0x" vendorid ", \"" vendor "\", \"\" }" > ofile
57}
58
59# matches device 
60/^\t[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]] / { 
61
62	device = substr($0, 8)
63	gsub( /\\/, "&&", device )
64	gsub( /\"/, "&&", device )
65
66	# Remove double interrogation points that may be interpreted as trigraphs
67	gsub( /\?\?\?/, "xxx", device )
68	gsub( /\?\?/, "xx", device )
69
70	# store device ID for possible devices afterwards
71	deviceid = $1
72	devicecount++
73	devices[devicecount, 1] = vendorid
74	devices[devicecount, 2] = $1
75	devices[devicecount, 3] = 0
76	devices[devicecount, 4] = 0
77	devices[devicecount, 5] = device 
78}
79
80# matches subvendor device
81/^\t\t[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]] / { 
82
83	device = substr($0, 14)
84	gsub( /\"/, "\\\"", device )
85
86	devicecount++
87	devices[devicecount, 1] = vendorid
88	devices[devicecount, 2] = deviceid
89	devices[devicecount, 3] = $1 
90	devices[devicecount, 4] = $2
91	devices[devicecount, 5] = device 
92}
93
94# match device class - store data for later
95/^C [[:xdigit:]][[:xdigit:]]  / { 
96
97	class = $2
98	classname = substr($0, 7)
99	gsub( /\"/, "\\\"", classname )
100}
101
102# match subclass, use device class data captured earlier, and output
103/^\t[[:xdigit:]][[:xdigit:]]  / {
104
105	subclass = $1
106	subclassname = substr($0, 6)
107	gsub( /\"/, "\\\"", subclassname )
108
109	classcount++
110	classes[classcount, 1] = class
111	classes[classcount, 2] = subclass
112	classes[classcount, 3] = "00"
113	classes[classcount, 4] = classname
114	classes[classcount, 5] = subclassname
115	classes[classcount, 6] = ""
116} 
117
118# match programming interface
119/^\t\t[[:xdigit:]][[:xdigit:]]  / {
120
121	proginterface = $1
122	proginterfacename = substr($0, 7)
123	gsub( /\"/, "\\\"", proginterfacename )
124
125	classcount++
126	classes[classcount, 1] = class
127	classes[classcount, 2] = subclass
128	classes[classcount, 3] = proginterface
129	classes[classcount, 4] = classname
130	classes[classcount, 5] = subclassname
131	classes[classcount, 6] = proginterfacename
132} 
133
134# We've processed the file, now output.
135END {
136
137	print "\n};\n\n// Use this value for loop control during searching:\n#define\tPCI_VENTABLE_LEN\t(sizeof(PciVenTable)/sizeof(PCI_VENTABLE))\n" > ofile
138
139	if ( devicecount > 0 ) {
140
141		print "typedef struct _PCI_DEVTABLE\n{\n\tunsigned short	VenId ;\n\tunsigned short	DevId ;\n\tunsigned short\tSubVenId ;\n\tunsigned short\tSubDevId ;\n\tconst char *\tChipDesc ;\n}  PCI_DEVTABLE, *PPCI_DEVTABLE ;\n"  > ofile
142		print "PCI_DEVTABLE\tPciDevTable [] =\n{" > ofile
143		for (i = 1; i <= devicecount; i++) {
144
145			if (i != 1) {
146				formatting = ",\n"
147			} else {
148				formatting = ""
149			}
150			printf formatting "\t{ 0x" devices[i, 1] ", 0x" devices[i, 2] ", 0x" devices[i, 3] ", 0x" devices[i, 4] ", \"" devices[i, 5] "\" }" > ofile
151		}
152		print "\n} ;\n\n// Use this value for loop control during searching:\n#define	PCI_DEVTABLE_LEN	(sizeof(PciDevTable)/sizeof(PCI_DEVTABLE))\n" > ofile
153
154	}
155	
156	if ( classcount > 0 ) {
157		print "typedef struct _PCI_CLASSCODETABLE\n{\n\tunsigned char	BaseClass ;\n\tunsigned char	SubClass ;\n\tunsigned char	ProgIf ;" > ofile
158		print "\tconst char *\t\tBaseDesc ;\n\tconst char *\t\tSubDesc ;\n\tconst char *\t\tProgDesc ;\n}  PCI_CLASSCODETABLE, *PPCI_CLASSCODETABLE ;\n" > ofile
159		print "PCI_CLASSCODETABLE PciClassCodeTable [] =\n{" > ofile
160		currentclass = classes[1, 1]
161		for (i = 1; i <= classcount; i++) {
162			
163			if (i != 1) { 
164				formatting = ",\n"
165			} else { 
166				formatting = ""
167			}
168
169			# pretty print separate classes
170			if ( currentclass != classes[i, 1] ) { 
171				formatting = formatting "\n"
172				currentclass = classes[i, 1]
173			}
174			
175			# if the next item has the same details, we know we're to skip ourselves 
176			# this is because the programming interface name needs to be used, and we dont have it ourselves
177			if ( ( classes[i, 1] != classes[i+1, 1] ) || ( classes[i, 2] != classes[i+1, 2] ) || ( classes[i, 3] != classes[i+1, 3] ) ) {
178				printf formatting "\t{ 0x" classes[i, 1] ", 0x" classes[i, 2] ", 0x" classes[i, 3] ", \"" classes[i, 4] "\", \"" classes[i, 5]  "\", \"" classes[i, 6] "\" }" > ofile
179			}
180		}
181		print "\n} ;\n\n// Use this value for loop control during searching:\n#define	PCI_CLASSCODETABLE_LEN	(sizeof(PciClassCodeTable)/sizeof(PCI_CLASSCODETABLE))\n" > ofile
182
183	}
184
185	# this is rather ugly, maybe we should include this in a seperate file, and pull it in ?
186	print "const char *\tPciCommandFlags [] =\n{\n\t\"I/O Access\",\n\t\"Memory Access\",\n\t\"Bus Mastering\",\n\t\"Special Cycles\",\n\t\"Memory Write & Invalidate\",\n\t\"Palette Snoop\",\n\t\"Parity Errors\",\n\t\"Wait Cycles\",\n\t\"System Errors\",\n\t\"Fast Back-To-Back\",\n\t\"Reserved 10\",\n\t\"Reserved 11\",\n\t\"Reserved 12\",\n\t\"Reserved 13\",\n\t\"Reserved 14\",\n\t\"Reserved 15\"\n} ;\n" > ofile
187	print "// Use this value for loop control during searching:\n#define	PCI_COMMANDFLAGS_LEN	(sizeof(PciCommandFlags)/sizeof(char *))\n" > ofile
188	print "const char *\tPciStatusFlags [] =\n{\n\t\"Reserved 0\",\n\t\"Reserved 1\",\n\t\"Reserved 2\",\n\t\"Reserved 3\",\n\t\"Reserved 4\",\n\t\"66 MHz Capable\",\n\t\"User-Defined Features\",\n\t\"Fast Back-To-Back\",\n\t\"Data Parity Reported\",\n\t\"\",\n\t\"\",\n\t\"Signalled Target Abort\",\n\t\"Received Target Abort\",\n\t\"Received Master Abort\",\n\t\"Signalled System Error\",\n\t\"Detected Parity Error\"\n} ;\n" > ofile
189	print "// Use this value for loop control during searching:\n#define	PCI_STATUSFLAGS_LEN	(sizeof(PciStatusFlags)/sizeof(char *))\n" > ofile
190	print "const char *\tPciDevSelFlags [] =\n{\n\t\"Fast Devsel Speed\",\n\t\"Medium Devsel Speed\",\n\t\"Slow Devsel Speed\",\n\t\"Reserved 9&10\"\n} ;\n" > ofile
191	print "// Use this value for loop control during searching:\n#define	PCI_DEVSELFLAGS_LEN	(sizeof(PciDevSelFlags)/sizeof(char *))\n\n" > ofile
192
193	close(ofile)
194}
195
196
197