Adding upstream version 4.00~pre54+dfsg.
[syslinux-debian/hramrach.git] / com32 / lib / pci / scan.c
blob65d8015793c31512e1f77267378014411538504e
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>
42 #include <syslinux/zio.h>
44 #ifdef DEBUG
45 # define dprintf printf
46 #else
47 # define dprintf(...) ((void)0)
48 #endif
50 #define MAX_LINE 512
52 /* searching the next char that is not a space */
53 static char *skipspace(char *p)
55 while (*p && *p <= ' ')
56 p++;
58 return p;
61 /* removing any \n found in a string */
62 static void remove_eol(char *string)
64 int j = strlen(string);
65 int i = 0;
66 for (i = 0; i < j; i++)
67 if (string[i] == '\n')
68 string[i] = 0;
71 /* converting a hexa string into its numerical value */
72 static int hex_to_int(char *hexa)
74 return strtoul(hexa, NULL, 16);
77 /* Replace char 'old' by char 'new' in source */
78 void chr_replace(char *source, char old, char new)
80 while (*source) {
81 source++;
82 if (source[0] == old) source[0]=new;
86 /* Try to match any pci device to the appropriate kernel module */
87 /* it uses the modules.pcimap from the boot device */
88 int get_module_name_from_pcimap(struct pci_domain *domain,
89 char *modules_pcimap_path)
91 char line[MAX_LINE];
92 char module_name[21]; // the module name field is 21 char long
93 char delims[]=" "; // colums are separated by spaces
94 char vendor_id[16];
95 char product_id[16];
96 char sub_vendor_id[16];
97 char sub_product_id[16];
98 FILE *f;
99 struct pci_device *dev=NULL;
101 /* Intializing the linux_kernel_module for each pci device to "unknown" */
102 /* adding a dev_info member if needed */
103 for_each_pci_func(dev, domain) {
104 /* initialize the dev_info structure if it doesn't exist yet. */
105 if (! dev->dev_info) {
106 dev->dev_info = zalloc(sizeof *dev->dev_info);
107 if (!dev->dev_info)
108 return -1;
110 for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) {
111 if (strlen(dev->dev_info->linux_kernel_module[i])==0)
112 strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7);
116 /* Opening the modules.pcimap (of a linux kernel) from the boot device */
117 f=zfopen(modules_pcimap_path, "r");
118 if (!f)
119 return -ENOMODULESPCIMAP;
121 strcpy(vendor_id,"0000");
122 strcpy(product_id,"0000");
123 strcpy(sub_product_id,"0000");
124 strcpy(sub_vendor_id,"0000");
126 /* for each line we found in the modules.pcimap */
127 while ( fgets(line, sizeof line, f) ) {
128 /* skipping unecessary lines */
129 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10))
130 continue;
132 char *result = NULL;
133 int field=0;
135 /* looking for the next field */
136 result = strtok(line, delims);
137 while( result != NULL ) {
138 /* if the column is larger than 1 char */
139 /* multiple spaces generates some empty fields */
140 if (strlen(result)>1) {
141 switch (field) {
142 /* About case 0, the kernel module name is featuring '_' or '-'
143 * in the module name whereas modules.alias is only using '_'.
144 * To avoid kernel modules duplication, let's rename all '-' in '_'
145 * to match what modules.alias provides */
146 case 0:chr_replace(result,'-','_');strcpy(module_name,result); break;
147 case 1:strcpy(vendor_id,result); break;
148 case 2:strcpy(product_id,result); break;
149 case 3:strcpy(sub_vendor_id,result); break;
150 case 4:strcpy(sub_product_id,result); break;
152 field++;
154 /* Searching the next field */
155 result = strtok( NULL, delims );
157 int int_vendor_id=hex_to_int(vendor_id);
158 int int_sub_vendor_id=hex_to_int(sub_vendor_id);
159 int int_product_id=hex_to_int(product_id);
160 int int_sub_product_id=hex_to_int(sub_product_id);
161 /* if a pci_device matches an entry, fill the linux_kernel_module with
162 the appropriate kernel module */
163 for_each_pci_func(dev, domain) {
164 if (int_vendor_id == dev->vendor &&
165 int_product_id == dev->product &&
166 (int_sub_product_id & dev->sub_product)
167 == dev->sub_product &&
168 (int_sub_vendor_id & dev->sub_vendor)
169 == dev->sub_vendor) {
170 bool found=false;
172 /* Scan all known kernel modules for this pci device */
173 for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) {
175 /* Try to detect if we already knew the same kernel module*/
176 if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) {
177 found=true;
178 break;
181 /* If we don't have this kernel module, let's add it */
182 if (!found) {
183 strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name);
184 dev->dev_info->linux_kernel_module_count++;
189 fclose(f);
190 return 0;
193 /* Try to match any pci device to the appropriate class name */
194 /* it uses the pci.ids from the boot device */
195 int get_class_name_from_pci_ids(struct pci_domain *domain, char *pciids_path)
197 char line[MAX_LINE];
198 char class_name[PCI_CLASS_NAME_SIZE];
199 char sub_class_name[PCI_CLASS_NAME_SIZE];
200 char class_id_str[5];
201 char sub_class_id_str[5];
202 FILE *f;
203 struct pci_device *dev;
204 bool class_mode = false;
206 /* Intializing the vendor/product name for each pci device to "unknown" */
207 /* adding a dev_info member if needed */
208 for_each_pci_func(dev, domain) {
209 /* initialize the dev_info structure if it doesn't exist yet. */
210 if (!dev->dev_info) {
211 dev->dev_info = zalloc(sizeof *dev->dev_info);
212 if (!dev->dev_info)
213 return -1;
215 strlcpy(dev->dev_info->class_name, "unknown", 7);
218 /* Opening the pci.ids from the boot device */
219 f = zfopen(pciids_path, "r");
220 if (!f)
221 return -ENOPCIIDS;
223 /* for each line we found in the pci.ids */
224 while (fgets(line, sizeof line, f)) {
225 /* Skipping uncessary lines */
226 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10))
227 continue;
229 /* Until we found a line starting with a 'C', we are not parsing classes */
230 if (line[0] == 'C')
231 class_mode = true;
232 if (class_mode == false)
233 continue;
234 strlcpy(class_name, "unknown", 7);
235 /* If the line doesn't start with a tab, it means that's a class name */
236 if (line[0] != '\t') {
238 /* ignore the two first char and then copy 2 chars (class id) */
239 strlcpy(class_id_str, &line[2], 2);
240 class_id_str[2] = 0;
242 /* the class name is the next field */
243 strlcpy(class_name, skipspace(strstr(line, " ")),
244 PCI_CLASS_NAME_SIZE - 1);
245 remove_eol(class_name);
247 int int_class_id_str = hex_to_int(class_id_str);
248 /* assign the class_name to any matching pci device */
249 for_each_pci_func(dev, domain) {
250 if (int_class_id_str == dev->class[2]) {
251 strlcpy(dev->dev_info->class_name, class_name,
252 PCI_CLASS_NAME_SIZE - 1);
253 /* This value is usually the main category */
254 strlcpy(dev->dev_info->category_name, class_name + 4,
255 PCI_CLASS_NAME_SIZE - 1);
258 /* if we have a tab + a char, it means this is a sub class name */
259 } else if ((line[0] == '\t') && (line[1] != '\t')) {
261 /* the sub class name the second field */
262 strlcpy(sub_class_name, skipspace(strstr(line, " ")),
263 PCI_CLASS_NAME_SIZE - 1);
264 remove_eol(sub_class_name);
266 /* the sub class id is first field */
267 strlcpy(sub_class_id_str, &line[1], 2);
268 sub_class_id_str[2] = 0;
270 int int_class_id_str = hex_to_int(class_id_str);
271 int int_sub_class_id_str = hex_to_int(sub_class_id_str);
272 /* assign the product_name to any matching pci device */
273 for_each_pci_func(dev, domain) {
274 if (int_class_id_str == dev->class[2] &&
275 int_sub_class_id_str == dev->class[1])
276 strlcpy(dev->dev_info->class_name, sub_class_name,
277 PCI_CLASS_NAME_SIZE - 1);
282 fclose(f);
283 return 0;
286 /* Try to match any pci device to the appropriate vendor and product name */
287 /* it uses the pci.ids from the boot device */
288 int get_name_from_pci_ids(struct pci_domain *domain, char *pciids_path)
290 char line[MAX_LINE];
291 char vendor[PCI_VENDOR_NAME_SIZE];
292 char vendor_id[5];
293 char product[PCI_PRODUCT_NAME_SIZE];
294 char product_id[5];
295 char sub_product_id[5];
296 char sub_vendor_id[5];
297 FILE *f;
298 struct pci_device *dev;
299 bool skip_to_next_vendor = false;
300 uint16_t int_vendor_id;
301 uint16_t int_product_id;
302 uint16_t int_sub_product_id;
303 uint16_t int_sub_vendor_id;
305 /* Intializing the vendor/product name for each pci device to "unknown" */
306 /* adding a dev_info member if needed */
307 for_each_pci_func(dev, domain) {
308 /* initialize the dev_info structure if it doesn't exist yet. */
309 if (!dev->dev_info) {
310 dev->dev_info = zalloc(sizeof *dev->dev_info);
311 if (!dev->dev_info)
312 return -1;
314 strlcpy(dev->dev_info->vendor_name, "unknown", 7);
315 strlcpy(dev->dev_info->product_name, "unknown", 7);
318 /* Opening the pci.ids from the boot device */
319 f = zfopen(pciids_path, "r");
320 if (!f)
321 return -ENOPCIIDS;
323 strlcpy(vendor_id, "0000", 4);
324 strlcpy(product_id, "0000", 4);
325 strlcpy(sub_product_id, "0000", 4);
326 strlcpy(sub_vendor_id, "0000", 4);
328 /* for each line we found in the pci.ids */
329 while (fgets(line, sizeof line, f)) {
330 /* Skipping uncessary lines */
331 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 'C') ||
332 (line[0] == 10))
333 continue;
335 /* If the line doesn't start with a tab, it means that's a vendor id */
336 if (line[0] != '\t') {
338 /* the 4 first chars are the vendor_id */
339 strlcpy(vendor_id, line, 4);
341 /* the vendor name is the next field */
342 vendor_id[4] = 0;
343 strlcpy(vendor, skipspace(strstr(line, " ")),
344 PCI_VENDOR_NAME_SIZE - 1);
346 remove_eol(vendor);
347 /* init product_id, sub_product and sub_vendor */
348 strlcpy(product_id, "0000", 4);
349 strlcpy(sub_product_id, "0000", 4);
350 strlcpy(sub_vendor_id, "0000", 4);
352 /* Unless we found a matching device, we have to skip to the next vendor */
353 skip_to_next_vendor = true;
355 int_vendor_id = hex_to_int(vendor_id);
356 /* Iterate in all pci devices to find a matching vendor */
357 for_each_pci_func(dev, domain) {
358 /* if one device that match this vendor */
359 if (int_vendor_id == dev->vendor) {
360 /* copy the vendor name for this device */
361 strlcpy(dev->dev_info->vendor_name, vendor,
362 PCI_VENDOR_NAME_SIZE - 1);
363 /* Some pci devices match this vendor, so we have to found them */
364 skip_to_next_vendor = false;
365 /* Let's loop on the other devices as some may have the same vendor */
368 /* if we have a tab + a char, it means this is a product id
369 * but we only look at it if we own some pci devices of the current vendor*/
370 } else if ((line[0] == '\t') && (line[1] != '\t')
371 && (skip_to_next_vendor == false)) {
373 /* the product name the second field */
374 strlcpy(product, skipspace(strstr(line, " ")),
375 PCI_PRODUCT_NAME_SIZE - 1);
376 remove_eol(product);
378 /* the product id is first field */
379 strlcpy(product_id, &line[1], 4);
380 product_id[4] = 0;
382 /* init sub_product and sub_vendor */
383 strlcpy(sub_product_id, "0000", 4);
384 strlcpy(sub_vendor_id, "0000", 4);
386 int_vendor_id = hex_to_int(vendor_id);
387 int_product_id = hex_to_int(product_id);
388 /* assign the product_name to any matching pci device */
389 for_each_pci_func(dev, domain) {
390 if (int_vendor_id == dev->vendor &&
391 int_product_id == dev->product) {
392 strlcpy(dev->dev_info->vendor_name, vendor,
393 PCI_VENDOR_NAME_SIZE - 1);
394 strlcpy(dev->dev_info->product_name, product,
395 PCI_PRODUCT_NAME_SIZE - 1);
399 /* if we have two tabs, it means this is a sub product
400 * but we only look at it if we own some pci devices of the current vendor*/
401 } else if ((line[0] == '\t') && (line[1] == '\t')
402 && (skip_to_next_vendor == false)) {
404 /* the product name is last field */
405 strlcpy(product, skipspace(strstr(line, " ")),
406 PCI_PRODUCT_NAME_SIZE - 1);
407 strlcpy(product, skipspace(strstr(product, " ")),
408 PCI_PRODUCT_NAME_SIZE - 1);
409 remove_eol(product);
411 /* the sub_vendor id is first field */
412 strlcpy(sub_vendor_id, &line[2], 4);
413 sub_vendor_id[4] = 0;
415 /* the sub_vendor id is second field */
416 strlcpy(sub_product_id, &line[7], 4);
417 sub_product_id[4] = 0;
419 int_vendor_id = hex_to_int(vendor_id);
420 int_sub_vendor_id = hex_to_int(sub_vendor_id);
421 int_product_id = hex_to_int(product_id);
422 int_sub_product_id = hex_to_int(sub_product_id);
423 /* assign the product_name to any matching pci device */
424 for_each_pci_func(dev, domain) {
425 if (int_vendor_id == dev->vendor &&
426 int_product_id == dev->product &&
427 int_sub_product_id == dev->sub_product &&
428 int_sub_vendor_id == dev->sub_vendor) {
429 strlcpy(dev->dev_info->vendor_name, vendor,
430 PCI_VENDOR_NAME_SIZE - 1);
431 strlcpy(dev->dev_info->product_name, product,
432 PCI_PRODUCT_NAME_SIZE - 1);
437 fclose(f);
438 return 0;
441 /* searching if any pcidevice match our query */
442 struct match *find_pci_device(const struct pci_domain *domain,
443 struct match *list)
445 uint32_t did, sid;
446 struct match *m;
447 const struct pci_device *dev;
449 /* for all matches we have to search */
450 for (m = list; m; m = m->next) {
451 /* for each pci device we know */
452 for_each_pci_func(dev, domain) {
453 /* sid & did are the easiest way to compare devices */
454 /* they are made of vendor/product subvendor/subproduct ids */
455 sid = dev->svid_sdid;
456 did = dev->vid_did;
457 /* if the current device match */
458 if (((did ^ m->did) & m->did_mask) == 0 &&
459 ((sid ^ m->sid) & m->sid_mask) == 0 &&
460 dev->revision >= m->rid_min && dev->revision <= m->rid_max) {
461 dprintf
462 ("PCI Match: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n",
463 dev->vendor, dev->product, dev->sub_vendor,
464 dev->sub_product, dev->revision);
465 /* returning the matched pci device */
466 return m;
470 return NULL;
473 /* scanning the pci bus to find pci devices */
474 struct pci_domain *pci_scan(void)
476 struct pci_domain *domain = NULL;
477 struct pci_bus *bus = NULL;
478 struct pci_slot *slot = NULL;
479 struct pci_device *func = NULL;
480 unsigned int nbus, ndev, nfunc, maxfunc;
481 uint32_t did, sid, rcid;
482 uint8_t hdrtype;
483 pciaddr_t a;
484 int cfgtype;
486 cfgtype = pci_set_config_type(PCI_CFG_AUTO);
488 dprintf("PCI configuration type %d\n", cfgtype);
490 if (cfgtype == PCI_CFG_NONE)
491 return NULL;
493 dprintf("Scanning PCI Buses\n");
495 for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) {
496 dprintf("Probing bus 0x%02x... \n", nbus);
497 bus = NULL;
499 for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) {
500 maxfunc = 1; /* Assume a single-function device */
501 slot = NULL;
503 for (nfunc = 0; nfunc < maxfunc; nfunc++) {
504 a = pci_mkaddr(nbus, ndev, nfunc, 0);
505 did = pci_readl(a);
507 if (did == 0xffffffff || did == 0xffff0000 ||
508 did == 0x0000ffff || did == 0x00000000)
509 continue;
511 hdrtype = pci_readb(a + 0x0e);
513 if (hdrtype & 0x80)
514 maxfunc = MAX_PCI_FUNC; /* Multifunction device */
516 rcid = pci_readl(a + 0x08);
517 sid = pci_readl(a + 0x2c);
519 if (!domain) {
520 domain = zalloc(sizeof *domain);
521 if (!domain)
522 goto bail;
524 if (!bus) {
525 bus = zalloc(sizeof *bus);
526 if (!bus)
527 goto bail;
528 domain->bus[nbus] = bus;
530 if (!slot) {
531 slot = zalloc(sizeof *slot);
532 if (!slot)
533 goto bail;
534 bus->slot[ndev] = slot;
536 func = zalloc(sizeof *func);
537 if (!func)
538 goto bail;
540 slot->func[nfunc] = func;
542 func->vid_did = did;
543 func->svid_sdid = sid;
544 func->rid_class = rcid;
546 dprintf
547 ("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n",
548 nbus, did, did >> 16, (did << 16) >> 16, sid, rcid & 0xff);
553 return domain;
555 bail:
556 free_pci_domain(domain);
557 return NULL;
560 /* gathering additional configuration*/
561 void gather_additional_pci_config(struct pci_domain *domain)
563 struct pci_device *dev;
564 pciaddr_t pci_addr;
565 int cfgtype;
567 cfgtype = pci_set_config_type(PCI_CFG_AUTO);
568 if (cfgtype == PCI_CFG_NONE)
569 return;
571 for_each_pci_func3(dev, domain, pci_addr) {
572 if (!dev->dev_info) {
573 dev->dev_info = zalloc(sizeof *dev->dev_info);
574 if (!dev->dev_info) {
575 return;
578 dev->dev_info->irq = pci_readb(pci_addr + 0x3c);
579 dev->dev_info->latency = pci_readb(pci_addr + 0x0d);
583 void free_pci_domain(struct pci_domain *domain)
585 struct pci_bus *bus;
586 struct pci_slot *slot;
587 struct pci_device *func;
588 unsigned int nbus, ndev, nfunc;
590 if (domain) {
591 for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) {
592 bus = domain->bus[nbus];
593 if (bus) {
594 for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) {
595 slot = bus->slot[ndev];
596 if (slot) {
597 for (nfunc = 0; nfunc < MAX_PCI_FUNC; nfunc++) {
598 func = slot->func[nfunc];
599 if (func) {
600 if (func->dev_info)
601 free(func->dev_info);
602 free(func);
604 free(slot);
607 free(bus);
610 free(domain);
615 /* Try to match any pci device to the appropriate kernel module */
616 /* it uses the modules.alias from the boot device */
617 int get_module_name_from_alias(struct pci_domain *domain, char *modules_alias_path)
619 char line[MAX_LINE];
620 char module_name[21]; // the module name field is 21 char long
621 char delims[]="*"; // colums are separated by spaces
622 char vendor_id[16];
623 char product_id[16];
624 char sub_vendor_id[16];
625 char sub_product_id[16];
626 FILE *f;
627 struct pci_device *dev=NULL;
629 /* Intializing the linux_kernel_module for each pci device to "unknown" */
630 /* adding a dev_info member if needed */
631 for_each_pci_func(dev, domain) {
632 /* initialize the dev_info structure if it doesn't exist yet. */
633 if (! dev->dev_info) {
634 dev->dev_info = zalloc(sizeof *dev->dev_info);
635 if (!dev->dev_info)
636 return -1;
638 for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) {
639 if (strlen(dev->dev_info->linux_kernel_module[i])==0)
640 strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7);
644 /* Opening the modules.pcimap (of a linux kernel) from the boot device */
645 f=zfopen(modules_alias_path, "r");
646 if (!f)
647 return -ENOMODULESALIAS;
649 /* for each line we found in the modules.pcimap */
650 while ( fgets(line, sizeof line, f) ) {
651 /* skipping unecessary lines */
652 if ((line[0] == '#') || (strstr(line,"alias pci:v")==NULL))
653 continue;
655 /* Resetting temp buffer*/
656 memset(module_name,0,sizeof(module_name));
657 memset(vendor_id,0,sizeof(vendor_id));
658 memset(sub_vendor_id,0,sizeof(sub_vendor_id));
659 memset(product_id,0,sizeof(product_id));
660 memset(sub_product_id,0,sizeof(sub_product_id));
661 strcpy(vendor_id,"0000");
662 strcpy(product_id,"0000");
663 /* ffff will be used to match any device as in modules.alias
664 * a missing subvendor/product have to be considered as 0xFFFF*/
665 strcpy(sub_product_id,"ffff");
666 strcpy(sub_vendor_id,"ffff");
668 char *result = NULL;
669 int field=0;
671 /* looking for the next field */
672 result = strtok(line+strlen("alias pci:v"), delims);
673 while( result != NULL ) {
674 if (field==0) {
676 /* Searching for the vendor separator*/
677 char *temp = strstr(result,"d");
678 if (temp != NULL) {
679 strncpy(vendor_id,result,temp-result);
680 result+=strlen(vendor_id)+1;
683 /* Searching for the product separator*/
684 temp = strstr(result,"sv");
685 if (temp != NULL) {
686 strncpy(product_id,result,temp-result);
687 result+=strlen(product_id)+1;
690 /* Searching for the sub vendor separator*/
691 temp = strstr(result,"sd");
692 if (temp != NULL) {
693 strncpy(sub_vendor_id,result,temp-result);
694 result+=strlen(sub_vendor_id)+1;
697 /* Searching for the sub product separator*/
698 temp = strstr(result,"bc");
699 if (temp != NULL) {
700 strncpy(sub_product_id,result,temp-result);
701 result+=strlen(sub_product_id)+1;
703 /* That's the module name */
704 } else if ((strlen(result)>2) &&
705 (result[0]==0x20))
706 strcpy(module_name,result+1);
707 /* We have to replace \n by \0*/
708 module_name[strlen(module_name)-1]='\0';
709 field++;
711 /* Searching the next field */
712 result = strtok( NULL, delims );
715 /* Now we have extracted informations from the modules.alias
716 * Let's compare it with the devices we know*/
717 int int_vendor_id=hex_to_int(vendor_id);
718 int int_sub_vendor_id=hex_to_int(sub_vendor_id);
719 int int_product_id=hex_to_int(product_id);
720 int int_sub_product_id=hex_to_int(sub_product_id);
721 /* if a pci_device matches an entry, fill the linux_kernel_module with
722 the appropriate kernel module */
723 for_each_pci_func(dev, domain) {
724 if (int_vendor_id == dev->vendor &&
725 int_product_id == dev->product &&
726 (int_sub_product_id & dev->sub_product)
727 == dev->sub_product &&
728 (int_sub_vendor_id & dev->sub_vendor)
729 == dev->sub_vendor) {
730 bool found=false;
732 /* Scan all known kernel modules for this pci device */
733 for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) {
735 /* Try to detect if we already knew the same kernel module*/
736 if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) {
737 found=true;
738 break;
741 /* If we don't have this kernel module, let's add it */
742 if (!found) {
743 strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name);
744 dev->dev_info->linux_kernel_module_count++;
749 fclose(f);
750 return 0;