Adding upstream version 3.53.
[syslinux-debian/hramrach.git] / com32 / lib / pci / scan.c
blob0add9f9ce1d36077f9cfd6956cc7b63491b63643
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2006-2007 Erwan Velu - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
12 * conditions:
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * ----------------------------------------------------------------------- */
29 * pci.c
31 * A module to extract pci informations
34 #include <inttypes.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <console.h>
39 #include <sys/pci.h>
40 #include <com32.h>
41 #include <stdbool.h>
43 #ifdef DEBUG
44 # define dprintf printf
45 #else
46 # define dprintf(...) ((void)0)
47 #endif
49 #define MAX_LINE 512
51 /* searching the next char that is not a space */
52 static char *skipspace(char *p)
54 while (*p && *p <= ' ')
55 p++;
57 return p;
60 /* removing any \n found in a string */
61 static void remove_eol(char *string)
63 int j = strlen(string);
64 int i = 0;
65 for(i = 0; i < j; i++) if(string[i] == '\n') string[i] = 0;
68 /* converting a hexa string into its numerical value*/
69 static int hex_to_int(char *hexa)
71 return strtoul(hexa, NULL, 16);
74 /* Try to match any pci device to the appropriate kernel module */
75 /* it uses the modules.pcimap from the boot device*/
76 void get_module_name_from_pci_ids(struct pci_device_list *pci_device_list)
78 char line[MAX_LINE];
79 char module_name[21]; // the module name field is 21 char long
80 char delims[]=" "; // colums are separated by spaces
81 char vendor_id[16];
82 char product_id[16];
83 char sub_vendor_id[16];
84 char sub_product_id[16];
85 FILE *f;
86 int pci_dev;
88 /* Intializing the linux_kernel_module for each pci device to "unknow" */
89 /* adding a pci_dev_info member if needed*/
90 for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
91 struct pci_device *pci_device = &(pci_device_list->pci_device[pci_dev]);
93 /* initialize the pci_dev_info structure if it doesn't exist yet. */
94 if (! pci_device->pci_dev_info) {
95 pci_device->pci_dev_info = calloc(1,sizeof (struct pci_device));
96 if (!pci_device->pci_dev_info) {
97 printf("Can't allocate memory\n");
98 return;
101 pci_device->pci_dev_info->linux_kernel_module=strdup("unknown");
104 /* Opening the modules.pcimap (ofa linux kernel) from the boot device*/
105 f=fopen("modules.pcimap","r");
106 if (!f)
107 return;
109 strcpy(vendor_id,"0000");
110 strcpy(product_id,"0000");
111 strcpy(sub_product_id,"0000");
112 strcpy(sub_vendor_id,"0000");
114 /* for each line we found in the modules.pcimap*/
115 while ( fgets(line, sizeof line, f) ) {
116 /*skipping unecessary lines */
117 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10))
118 continue;
120 char *result = NULL;
121 int field=0;
123 /* looking for the next field */
124 result = strtok(line, delims);
125 while( result != NULL ) {
126 /* if the column is larger than 1 char */
127 /* multiple spaces generates some empty fields*/
128 if (strlen(result)>1) {
129 switch (field) {
130 case 0:strcpy(module_name,result); break;
131 case 1:strcpy(vendor_id,result); break;
132 case 2:strcpy(product_id,result); break;
133 case 3:strcpy(sub_vendor_id,result); break;
134 case 4:strcpy(sub_product_id,result); break;
136 field++;
138 /* Searching the next field*/
139 result = strtok( NULL, delims );
141 /* if a pci_device match an entry, fill the linux_kernel_module with
142 the appropriate kernel module */
143 for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
144 struct pci_device *pci_device =
145 &pci_device_list->pci_device[pci_dev];
147 if (hex_to_int(vendor_id) == pci_device->vendor &&
148 hex_to_int(product_id) == pci_device->product &&
149 (hex_to_int(sub_product_id) & pci_device->sub_product)
150 == pci_device->sub_product &&
151 (hex_to_int(sub_vendor_id) & pci_device->sub_vendor)
152 == pci_device->sub_vendor)
153 strcpy(pci_device->pci_dev_info->linux_kernel_module,
154 module_name);
157 fclose(f);
160 /* Try to match any pci device to the appropriate vendor and product name */
161 /* it uses the pci.ids from the boot device*/
162 void get_name_from_pci_ids(struct pci_device_list *pci_device_list)
164 char line[MAX_LINE];
165 char *vendor=NULL;
166 char vendor_id[5];
167 char *product=NULL;
168 char product_id[5];
169 char sub_product_id[5];
170 char sub_vendor_id[5];
171 FILE *f;
172 int pci_dev;
174 /* Intializing the vendor/product name for each pci device to "unknow" */
175 /* adding a pci_dev_info member if needed*/
176 for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
177 struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev];
179 /* initialize the pci_dev_info structure if it doesn't exist yet. */
180 if (! pci_device->pci_dev_info) {
181 pci_device->pci_dev_info = calloc(1,sizeof (struct pci_device));
183 if (!pci_device->pci_dev_info) {
184 printf("Can't allocate memory\n");
185 return;
189 pci_device->pci_dev_info->vendor_name=strdup("unknown");
190 pci_device->pci_dev_info->product_name=strdup("unknown");
193 /* Opening the pci.ids from the boot device*/
194 f=fopen("pci.ids","r");
195 if (!f)
196 return;
198 strcpy(vendor_id,"0000");
199 strcpy(product_id,"0000");
200 strcpy(sub_product_id,"0000");
201 strcpy(sub_vendor_id,"0000");
204 /* for each line we found in the pci.ids*/
205 while ( fgets(line, sizeof line, f) ) {
207 /* Skipping uncessary lines */
208 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 'C') ||
209 (line[0] == 10))
210 continue;
211 /* If the line doesn't start with a tab, it means that's a vendor id */
212 if (line[0] != '\t') {
214 /* the 4th first chars are the vendor_id */
215 strncpy(vendor_id,line,4);
217 /* the vendor name is the next field*/
218 vendor_id[4]=0;
219 vendor=strdup(skipspace(strstr(line," ")));
220 remove_eol(vendor);
222 /* init product_id, sub_product and sub_vendor */
223 strcpy(product_id,"0000");
224 strcpy(sub_product_id,"0000");
225 strcpy(sub_vendor_id,"0000");
227 /* ffff is an invalid vendor id */
228 if (strstr(vendor_id,"ffff")) break;
230 /* assign the vendor_name to any matching pci device*/
231 for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
232 struct pci_device *pci_device =
233 &pci_device_list->pci_device[pci_dev];
235 if (hex_to_int(vendor_id) == pci_device->vendor)
236 pci_device->pci_dev_info->vendor_name=strdup(vendor);
238 /* if we have a tab + a char, it means this is a product id */
239 } else if ((line[0] == '\t') && (line[1] != '\t')) {
241 /* the product name the second field */
242 product=strdup(skipspace(strstr(line," ")));
243 remove_eol(product);
245 /* the product id is first field */
246 strncpy(product_id,&line[1],4);
247 product_id[4]=0;
249 /* init sub_product and sub_vendor */
250 strcpy(sub_product_id,"0000");
251 strcpy(sub_vendor_id,"0000");
253 /* assign the product_name to any matching pci device*/
254 for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
255 struct pci_device *pci_device =
256 &pci_device_list->pci_device[pci_dev];
257 if (hex_to_int(vendor_id) == pci_device->vendor &&
258 hex_to_int(product_id) == pci_device->product)
259 pci_device->pci_dev_info->product_name=strdup(product);
262 /* if we have two tabs, it means this is a sub product */
263 } else if ((line[0] == '\t') && (line[1] == '\t')) {
265 /* the product name is last field */
266 product=skipspace(strstr(line," "));
267 product=strdup(skipspace(strstr(product," ")));
268 remove_eol(product);
270 /* the sub_vendor id is first field */
271 strncpy(sub_vendor_id,&line[2],4);
272 sub_vendor_id[4]=0;
274 /* the sub_vendor id is second field */
275 strncpy(sub_product_id,&line[7],4);
276 sub_product_id[4]=0;
278 /* assign the product_name to any matching pci device*/
279 for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
280 struct pci_device *pci_device =
281 &pci_device_list->pci_device[pci_dev];
283 if (hex_to_int(vendor_id) == pci_device->vendor &&
284 hex_to_int(product_id) == pci_device->product &&
285 hex_to_int(sub_product_id) == pci_device->sub_product &&
286 hex_to_int(sub_vendor_id) == pci_device->sub_vendor)
287 pci_device->pci_dev_info->product_name=strdup(product);
291 fclose(f);
294 /* searching if any pcidevice match our query */
295 struct match *find_pci_device(struct pci_device_list * pci_device_list,
296 struct match *list)
298 int pci_dev;
299 uint32_t did, sid;
300 struct match *m;
301 /* for all matches we have to search */
302 for (m = list; m; m = m->next) {
303 /* for each pci device we know */
304 for (pci_dev = 0; pci_dev < pci_device_list->count; pci_dev++) {
305 struct pci_device *pci_device =
306 &pci_device_list->pci_device[pci_dev];
308 /* sid & did are the easiest way to compare devices */
309 /* they are made of vendor/product subvendor/subproduct ids */
310 sid =
311 ((pci_device->sub_product) << 16 | (pci_device->
312 sub_vendor));
313 did = ((pci_device->product << 16) | (pci_device->vendor));
315 /*if the current device match */
316 if (((did ^ m->did) & m->did_mask) == 0 &&
317 ((sid ^ m->sid) & m->sid_mask) == 0 &&
318 pci_device->revision >= m->rid_min
319 && pci_device->revision <= m->rid_max) {
320 dprintf("PCI Match: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n",
321 pci_device->vendor, pci_device->product,
322 pci_device->sub_vendor,
323 pci_device->sub_product,
324 pci_device->revision);
325 /* returning the matched pci device */
326 return m;
330 return NULL;
333 /* scanning the pci bus to find pci devices */
334 int pci_scan(struct pci_bus_list * pci_bus_list, struct pci_device_list * pci_device_list)
336 unsigned int bus, dev, func, maxfunc;
337 uint32_t did, sid;
338 uint8_t hdrtype, rid;
339 pciaddr_t a;
340 int cfgtype;
342 pci_device_list->count = 0;
344 #ifdef DEBUG
345 outl(~0, 0xcf8);
346 printf("Poking at port CF8 = %#08x\n", inl(0xcf8));
347 outl(0, 0xcf8);
348 #endif
350 cfgtype = pci_set_config_type(PCI_CFG_AUTO);
351 (void)cfgtype;
353 dprintf("PCI configuration type %d\n", cfgtype);
354 dprintf("Scanning PCI Buses\n");
356 /* We try to detect 255 buses */
357 for (bus = 0; bus <= MAX_PCI_BUSES; bus++) {
359 dprintf("Probing bus 0x%02x... \n", bus);
361 pci_bus_list->pci_bus[bus].id = bus;
362 pci_bus_list->pci_bus[bus].pci_device_count = 0;
363 pci_bus_list->count = 0;;
365 for (dev = 0; dev <= 0x1f; dev++) {
366 maxfunc = 0;
367 for (func = 0; func <= maxfunc; func++) {
368 a = pci_mkaddr(bus, dev, func, 0);
370 did = pci_readl(a);
372 if (did == 0xffffffff || did == 0xffff0000 ||
373 did == 0x0000ffff || did == 0x00000000)
374 continue;
376 hdrtype = pci_readb(a + 0x0e);
378 if (hdrtype & 0x80)
379 maxfunc = 7; /* Multifunction device */
381 rid = pci_readb(a + 0x08);
382 sid = pci_readl(a + 0x2c);
383 struct pci_device *pci_device =
384 &pci_device_list->
385 pci_device[pci_device_list->count];
386 pci_device->product = did >> 16;
387 pci_device->sub_product = sid >> 16;
388 pci_device->vendor = (did << 16) >> 16;
389 pci_device->sub_vendor = (sid << 16) >> 16;
390 pci_device->revision = rid;
391 pci_device_list->count++;
392 dprintf
393 ("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n",
394 bus, did, did >> 16, (did << 16) >> 16,
395 sid, rid);
396 /* Adding the detected pci device to the bus */
397 pci_bus_list->pci_bus[bus].
398 pci_device[pci_bus_list->pci_bus[bus].
399 pci_device_count] = pci_device;
400 pci_bus_list->pci_bus[bus].pci_device_count++;
405 /* Detecting pci buses that have pci devices connected */
406 for (bus = 0; bus <= 0xff; bus++) {
407 if (pci_bus_list->pci_bus[bus].pci_device_count > 0) {
408 pci_bus_list->count++;
411 return 0;