1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2006-2007 Erwan Velu - All Rights Reserved 4 * 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: 13 * 14 * The above copyright notice and this permission notice shall 15 * be included in all copies or substantial portions of the Software. 16 * 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. 25 * 26 * ----------------------------------------------------------------------- */ 27 28 /* 29 * pci.c 30 * 31 * A module to extract pci informations 32 */ 33 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 <ctype.h> 43 #include <syslinux/zio.h> 44 #include <dprintf.h> 45 46 #define MAX_LINE 512 47 48 /* removing any \n found in a string */ 49 static void remove_eol(char *string) 50 { 51 int j = strlen(string); 52 int i = 0; 53 for (i = 0; i < j; i++) 54 if (string[i] == '\n') 55 string[i] = 0; 56 } 57 58 /* converting a hexa string into its numerical value */ 59 static int hex_to_int(char *hexa) 60 { 61 return strtoul(hexa, NULL, 16); 62 } 63 64 /* Try to match any pci device to the appropriate kernel module */ 65 /* it uses the modules.pcimap from the boot device */ 66 int get_module_name_from_pcimap(struct pci_domain *domain, 67 char *modules_pcimap_path) 68 { 69 char line[MAX_LINE]; 70 char module_name[21]; // the module name field is 21 char long 71 char delims[]=" "; // colums are separated by spaces 72 char vendor_id[16]; 73 char product_id[16]; 74 char sub_vendor_id[16]; 75 char sub_product_id[16]; 76 FILE *f; 77 struct pci_device *dev=NULL; 78 79 /* Intializing the linux_kernel_module for each pci device to "unknown" */ 80 /* adding a dev_info member if needed */ 81 for_each_pci_func(dev, domain) { 82 /* initialize the dev_info structure if it doesn't exist yet. */ 83 if (! dev->dev_info) { 84 dev->dev_info = zalloc(sizeof *dev->dev_info); 85 if (!dev->dev_info) 86 return -1; 87 } 88 for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) { 89 if (strlen(dev->dev_info->linux_kernel_module[i])==0) 90 strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7); 91 } 92 } 93 94 /* Opening the modules.pcimap (of a linux kernel) from the boot device */ 95 f=zfopen(modules_pcimap_path, "r"); 96 if (!f) 97 return -ENOMODULESPCIMAP; 98 99 strcpy(vendor_id,"0000"); 100 strcpy(product_id,"0000"); 101 strcpy(sub_product_id,"0000"); 102 strcpy(sub_vendor_id,"0000"); 103 104 /* for each line we found in the modules.pcimap */ 105 while ( fgets(line, sizeof line, f) ) { 106 /* skipping unecessary lines */ 107 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10)) 108 continue; 109 110 char *result = NULL; 111 int field=0; 112 113 /* looking for the next field */ 114 result = strtok(line, delims); 115 while( result != NULL ) { 116 /* if the column is larger than 1 char */ 117 /* multiple spaces generates some empty fields */ 118 if (strlen(result)>1) { 119 switch (field) { 120 /* About case 0, the kernel module name is featuring '_' or '-' 121 * in the module name whereas modules.alias is only using '_'. 122 * To avoid kernel modules duplication, let's rename all '-' in '_' 123 * to match what modules.alias provides */ 124 case 0:chrreplace(result,'-','_');strcpy(module_name,result); break; 125 case 1:strcpy(vendor_id,result); break; 126 case 2:strcpy(product_id,result); break; 127 case 3:strcpy(sub_vendor_id,result); break; 128 case 4:strcpy(sub_product_id,result); break; 129 } 130 field++; 131 } 132 /* Searching the next field */ 133 result = strtok( NULL, delims ); 134 } 135 int int_vendor_id=hex_to_int(vendor_id); 136 int int_sub_vendor_id=hex_to_int(sub_vendor_id); 137 int int_product_id=hex_to_int(product_id); 138 int int_sub_product_id=hex_to_int(sub_product_id); 139 /* if a pci_device matches an entry, fill the linux_kernel_module with 140 the appropriate kernel module */ 141 for_each_pci_func(dev, domain) { 142 if (int_vendor_id == dev->vendor && 143 int_product_id == dev->product && 144 (int_sub_product_id & dev->sub_product) 145 == dev->sub_product && 146 (int_sub_vendor_id & dev->sub_vendor) 147 == dev->sub_vendor) { 148 bool found=false; 149 150 /* Scan all known kernel modules for this pci device */ 151 for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) { 152 153 /* Try to detect if we already knew the same kernel module*/ 154 if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) { 155 found=true; 156 break; 157 } 158 } 159 /* If we don't have this kernel module, let's add it */ 160 if (!found) { 161 strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name); 162 dev->dev_info->linux_kernel_module_count++; 163 } 164 } 165 } 166 } 167 fclose(f); 168 return 0; 169 } 170 171 /* Try to match any pci device to the appropriate class name */ 172 /* it uses the pci.ids from the boot device */ 173 int get_class_name_from_pci_ids(struct pci_domain *domain, char *pciids_path) 174 { 175 char line[MAX_LINE]; 176 char class_name[PCI_CLASS_NAME_SIZE]; 177 char sub_class_name[PCI_CLASS_NAME_SIZE]; 178 char class_id_str[5]; 179 char sub_class_id_str[5]; 180 FILE *f; 181 struct pci_device *dev; 182 bool class_mode = false; 183 184 /* Intializing the vendor/product name for each pci device to "unknown" */ 185 /* adding a dev_info member if needed */ 186 for_each_pci_func(dev, domain) { 187 /* initialize the dev_info structure if it doesn't exist yet. */ 188 if (!dev->dev_info) { 189 dev->dev_info = zalloc(sizeof *dev->dev_info); 190 if (!dev->dev_info) 191 return -1; 192 } 193 strlcpy(dev->dev_info->class_name, "unknown", 7); 194 } 195 196 /* Opening the pci.ids from the boot device */ 197 f = zfopen(pciids_path, "r"); 198 if (!f) 199 return -ENOPCIIDS; 200 201 /* for each line we found in the pci.ids */ 202 while (fgets(line, sizeof line, f)) { 203 /* Skipping uncessary lines */ 204 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10)) 205 continue; 206 207 /* Until we found a line starting with a 'C', we are not parsing classes */ 208 if (line[0] == 'C') 209 class_mode = true; 210 if (class_mode == false) 211 continue; 212 strlcpy(class_name, "unknown", 7); 213 /* If the line doesn't start with a tab, it means that's a class name */ 214 if (line[0] != '\t') { 215 216 /* ignore the two first char and then copy 2 chars (class id) */ 217 strlcpy(class_id_str, &line[2], 2); 218 class_id_str[2] = 0; 219 220 /* the class name is the next field */ 221 strlcpy(class_name, skipspace(strstr(line, " ")), 222 PCI_CLASS_NAME_SIZE - 1); 223 remove_eol(class_name); 224 225 int int_class_id_str = hex_to_int(class_id_str); 226 /* assign the class_name to any matching pci device */ 227 for_each_pci_func(dev, domain) { 228 if (int_class_id_str == dev->class[2]) { 229 strlcpy(dev->dev_info->class_name, class_name, 230 PCI_CLASS_NAME_SIZE - 1); 231 /* This value is usually the main category */ 232 strlcpy(dev->dev_info->category_name, class_name + 4, 233 PCI_CLASS_NAME_SIZE - 1); 234 } 235 } 236 /* if we have a tab + a char, it means this is a sub class name */ 237 } else if ((line[0] == '\t') && (line[1] != '\t')) { 238 239 /* the sub class name the second field */ 240 strlcpy(sub_class_name, skipspace(strstr(line, " ")), 241 PCI_CLASS_NAME_SIZE - 1); 242 remove_eol(sub_class_name); 243 244 /* the sub class id is first field */ 245 strlcpy(sub_class_id_str, &line[1], 2); 246 sub_class_id_str[2] = 0; 247 248 int int_class_id_str = hex_to_int(class_id_str); 249 int int_sub_class_id_str = hex_to_int(sub_class_id_str); 250 /* assign the product_name to any matching pci device */ 251 for_each_pci_func(dev, domain) { 252 if (int_class_id_str == dev->class[2] && 253 int_sub_class_id_str == dev->class[1]) 254 strlcpy(dev->dev_info->class_name, sub_class_name, 255 PCI_CLASS_NAME_SIZE - 1); 256 } 257 258 } 259 } 260 fclose(f); 261 return 0; 262 } 263 264 /* Try to match any pci device to the appropriate vendor and product name */ 265 /* it uses the pci.ids from the boot device */ 266 int get_name_from_pci_ids(struct pci_domain *domain, char *pciids_path) 267 { 268 char line[MAX_LINE]; 269 char vendor[PCI_VENDOR_NAME_SIZE]; 270 char vendor_id[5]; 271 char product[PCI_PRODUCT_NAME_SIZE]; 272 char product_id[5]; 273 char sub_product_id[5]; 274 char sub_vendor_id[5]; 275 FILE *f; 276 struct pci_device *dev; 277 bool skip_to_next_vendor = false; 278 uint16_t int_vendor_id; 279 uint16_t int_product_id; 280 uint16_t int_sub_product_id; 281 uint16_t int_sub_vendor_id; 282 283 /* Intializing the vendor/product name for each pci device to "unknown" */ 284 /* adding a dev_info member if needed */ 285 for_each_pci_func(dev, domain) { 286 /* initialize the dev_info structure if it doesn't exist yet. */ 287 if (!dev->dev_info) { 288 dev->dev_info = zalloc(sizeof *dev->dev_info); 289 if (!dev->dev_info) 290 return -1; 291 } 292 strlcpy(dev->dev_info->vendor_name, "unknown", 7); 293 strlcpy(dev->dev_info->product_name, "unknown", 7); 294 } 295 296 /* Opening the pci.ids from the boot device */ 297 f = zfopen(pciids_path, "r"); 298 if (!f) 299 return -ENOPCIIDS; 300 301 strlcpy(vendor_id, "0000", 4); 302 strlcpy(product_id, "0000", 4); 303 strlcpy(sub_product_id, "0000", 4); 304 strlcpy(sub_vendor_id, "0000", 4); 305 306 /* for each line we found in the pci.ids */ 307 while (fgets(line, sizeof line, f)) { 308 /* Skipping uncessary lines */ 309 if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 'C') || 310 (line[0] == 10)) 311 continue; 312 313 /* If the line doesn't start with a tab, it means that's a vendor id */ 314 if (line[0] != '\t') { 315 316 /* the 4 first chars are the vendor_id */ 317 strlcpy(vendor_id, line, 4); 318 319 /* the vendor name is the next field */ 320 vendor_id[4] = 0; 321 strlcpy(vendor, skipspace(strstr(line, " ")), 322 PCI_VENDOR_NAME_SIZE - 1); 323 324 remove_eol(vendor); 325 /* init product_id, sub_product and sub_vendor */ 326 strlcpy(product_id, "0000", 4); 327 strlcpy(sub_product_id, "0000", 4); 328 strlcpy(sub_vendor_id, "0000", 4); 329 330 /* Unless we found a matching device, we have to skip to the next vendor */ 331 skip_to_next_vendor = true; 332 333 int_vendor_id = hex_to_int(vendor_id); 334 /* Iterate in all pci devices to find a matching vendor */ 335 for_each_pci_func(dev, domain) { 336 /* if one device that match this vendor */ 337 if (int_vendor_id == dev->vendor) { 338 /* copy the vendor name for this device */ 339 strlcpy(dev->dev_info->vendor_name, vendor, 340 PCI_VENDOR_NAME_SIZE - 1); 341 /* Some pci devices match this vendor, so we have to found them */ 342 skip_to_next_vendor = false; 343 /* Let's loop on the other devices as some may have the same vendor */ 344 } 345 } 346 /* if we have a tab + a char, it means this is a product id 347 * but we only look at it if we own some pci devices of the current vendor*/ 348 } else if ((line[0] == '\t') && (line[1] != '\t') 349 && (skip_to_next_vendor == false)) { 350 351 /* the product name the second field */ 352 strlcpy(product, skipspace(strstr(line, " ")), 353 PCI_PRODUCT_NAME_SIZE - 1); 354 remove_eol(product); 355 356 /* the product id is first field */ 357 strlcpy(product_id, &line[1], 4); 358 product_id[4] = 0; 359 360 /* init sub_product and sub_vendor */ 361 strlcpy(sub_product_id, "0000", 4); 362 strlcpy(sub_vendor_id, "0000", 4); 363 364 int_vendor_id = hex_to_int(vendor_id); 365 int_product_id = hex_to_int(product_id); 366 /* assign the product_name to any matching pci device */ 367 for_each_pci_func(dev, domain) { 368 if (int_vendor_id == dev->vendor && 369 int_product_id == dev->product) { 370 strlcpy(dev->dev_info->vendor_name, vendor, 371 PCI_VENDOR_NAME_SIZE - 1); 372 strlcpy(dev->dev_info->product_name, product, 373 PCI_PRODUCT_NAME_SIZE - 1); 374 } 375 } 376 377 /* if we have two tabs, it means this is a sub product 378 * but we only look at it if we own some pci devices of the current vendor*/ 379 } else if ((line[0] == '\t') && (line[1] == '\t') 380 && (skip_to_next_vendor == false)) { 381 382 /* the product name is last field */ 383 strlcpy(product, skipspace(strstr(line, " ")), 384 PCI_PRODUCT_NAME_SIZE - 1); 385 strlcpy(product, skipspace(strstr(product, " ")), 386 PCI_PRODUCT_NAME_SIZE - 1); 387 remove_eol(product); 388 389 /* the sub_vendor id is first field */ 390 strlcpy(sub_vendor_id, &line[2], 4); 391 sub_vendor_id[4] = 0; 392 393 /* the sub_vendor id is second field */ 394 strlcpy(sub_product_id, &line[7], 4); 395 sub_product_id[4] = 0; 396 397 int_vendor_id = hex_to_int(vendor_id); 398 int_sub_vendor_id = hex_to_int(sub_vendor_id); 399 int_product_id = hex_to_int(product_id); 400 int_sub_product_id = hex_to_int(sub_product_id); 401 /* assign the product_name to any matching pci device */ 402 for_each_pci_func(dev, domain) { 403 if (int_vendor_id == dev->vendor && 404 int_product_id == dev->product && 405 int_sub_product_id == dev->sub_product && 406 int_sub_vendor_id == dev->sub_vendor) { 407 strlcpy(dev->dev_info->vendor_name, vendor, 408 PCI_VENDOR_NAME_SIZE - 1); 409 strlcpy(dev->dev_info->product_name, product, 410 PCI_PRODUCT_NAME_SIZE - 1); 411 } 412 } 413 } 414 } 415 fclose(f); 416 return 0; 417 } 418 419 /* searching if any pcidevice match our query */ 420 struct match *find_pci_device(const struct pci_domain *domain, 421 struct match *list) 422 { 423 uint32_t did, sid; 424 struct match *m; 425 const struct pci_device *dev; 426 427 /* for all matches we have to search */ 428 for (m = list; m; m = m->next) { 429 /* for each pci device we know */ 430 for_each_pci_func(dev, domain) { 431 /* sid & did are the easiest way to compare devices */ 432 /* they are made of vendor/product subvendor/subproduct ids */ 433 sid = dev->svid_sdid; 434 did = dev->vid_did; 435 /* if the current device match */ 436 if (((did ^ m->did) & m->did_mask) == 0 && 437 ((sid ^ m->sid) & m->sid_mask) == 0 && 438 dev->revision >= m->rid_min && dev->revision <= m->rid_max) { 439 dprintf 440 ("PCI Match: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n", 441 dev->vendor, dev->product, dev->sub_vendor, 442 dev->sub_product, dev->revision); 443 /* returning the matched pci device */ 444 return m; 445 } 446 } 447 } 448 return NULL; 449 } 450 451 /* scanning the pci bus to find pci devices */ 452 struct pci_domain *pci_scan(void) 453 { 454 struct pci_domain *domain = NULL; 455 struct pci_bus *bus = NULL; 456 struct pci_slot *slot = NULL; 457 struct pci_device *func = NULL; 458 unsigned int nbus, ndev, nfunc, maxfunc; 459 uint32_t did, sid, rcid; 460 uint8_t hdrtype; 461 pciaddr_t a; 462 int cfgtype; 463 464 cfgtype = pci_set_config_type(PCI_CFG_AUTO); 465 466 dprintf("PCI configuration type %d\n", cfgtype); 467 468 if (cfgtype == PCI_CFG_NONE) 469 return NULL; 470 471 dprintf("Scanning PCI Buses\n"); 472 473 for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) { 474 dprintf("Probing bus 0x%02x... \n", nbus); 475 bus = NULL; 476 477 for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) { 478 maxfunc = 1; /* Assume a single-function device */ 479 slot = NULL; 480 481 for (nfunc = 0; nfunc < maxfunc; nfunc++) { 482 a = pci_mkaddr(nbus, ndev, nfunc, 0); 483 did = pci_readl(a); 484 485 if (did == 0xffffffff || did == 0xffff0000 || 486 did == 0x0000ffff || did == 0x00000000) 487 continue; 488 489 hdrtype = pci_readb(a + 0x0e); 490 491 if (hdrtype & 0x80) 492 maxfunc = MAX_PCI_FUNC; /* Multifunction device */ 493 494 rcid = pci_readl(a + 0x08); 495 sid = pci_readl(a + 0x2c); 496 497 if (!domain) { 498 domain = zalloc(sizeof *domain); 499 if (!domain) 500 goto bail; 501 } 502 if (!bus) { 503 bus = zalloc(sizeof *bus); 504 if (!bus) 505 goto bail; 506 domain->bus[nbus] = bus; 507 } 508 if (!slot) { 509 slot = zalloc(sizeof *slot); 510 if (!slot) 511 goto bail; 512 bus->slot[ndev] = slot; 513 } 514 func = zalloc(sizeof *func); 515 if (!func) 516 goto bail; 517 518 slot->func[nfunc] = func; 519 520 func->vid_did = did; 521 func->svid_sdid = sid; 522 func->rid_class = rcid; 523 524 dprintf 525 ("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n", 526 nbus, did, did >> 16, (did << 16) >> 16, sid, rcid & 0xff); 527 } 528 } 529 } 530 531 return domain; 532 533 bail: 534 free_pci_domain(domain); 535 return NULL; 536 } 537 538 /* gathering additional configuration*/ 539 void gather_additional_pci_config(struct pci_domain *domain) 540 { 541 struct pci_device *dev; 542 pciaddr_t pci_addr; 543 int cfgtype; 544 545 cfgtype = pci_set_config_type(PCI_CFG_AUTO); 546 if (cfgtype == PCI_CFG_NONE) 547 return; 548 549 for_each_pci_func3(dev, domain, pci_addr) { 550 if (!dev->dev_info) { 551 dev->dev_info = zalloc(sizeof *dev->dev_info); 552 if (!dev->dev_info) { 553 return; 554 } 555 } 556 dev->dev_info->irq = pci_readb(pci_addr + 0x3c); 557 dev->dev_info->latency = pci_readb(pci_addr + 0x0d); 558 } 559 } 560 561 void free_pci_domain(struct pci_domain *domain) 562 { 563 struct pci_bus *bus; 564 struct pci_slot *slot; 565 struct pci_device *func; 566 unsigned int nbus, ndev, nfunc; 567 568 if (domain) { 569 for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) { 570 bus = domain->bus[nbus]; 571 if (bus) { 572 for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) { 573 slot = bus->slot[ndev]; 574 if (slot) { 575 for (nfunc = 0; nfunc < MAX_PCI_FUNC; nfunc++) { 576 func = slot->func[nfunc]; 577 if (func) { 578 if (func->dev_info) 579 free(func->dev_info); 580 free(func); 581 } 582 } 583 free(slot); 584 } 585 } 586 free(bus); 587 } 588 } 589 free(domain); 590 } 591 } 592 593 /* Try to match any pci device to the appropriate kernel module */ 594 /* it uses the modules.alias from the boot device */ 595 int get_module_name_from_alias(struct pci_domain *domain, char *modules_alias_path) 596 { 597 char line[MAX_LINE]; 598 char module_name[21]; // the module name field is 21 char long 599 char delims[]="*"; // colums are separated by spaces 600 char vendor_id[16]; 601 char product_id[16]; 602 char sub_vendor_id[16]; 603 char sub_product_id[16]; 604 FILE *f; 605 struct pci_device *dev=NULL; 606 607 /* Intializing the linux_kernel_module for each pci device to "unknown" */ 608 /* adding a dev_info member if needed */ 609 for_each_pci_func(dev, domain) { 610 /* initialize the dev_info structure if it doesn't exist yet. */ 611 if (! dev->dev_info) { 612 dev->dev_info = zalloc(sizeof *dev->dev_info); 613 if (!dev->dev_info) 614 return -1; 615 } 616 for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) { 617 if (strlen(dev->dev_info->linux_kernel_module[i])==0) 618 strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7); 619 } 620 } 621 622 /* Opening the modules.pcimap (of a linux kernel) from the boot device */ 623 f=zfopen(modules_alias_path, "r"); 624 if (!f) 625 return -ENOMODULESALIAS; 626 627 /* for each line we found in the modules.pcimap */ 628 while ( fgets(line, sizeof line, f) ) { 629 /* skipping unecessary lines */ 630 if ((line[0] == '#') || (strstr(line,"alias pci:v")==NULL)) 631 continue; 632 633 /* Resetting temp buffer*/ 634 memset(module_name,0,sizeof(module_name)); 635 memset(vendor_id,0,sizeof(vendor_id)); 636 memset(sub_vendor_id,0,sizeof(sub_vendor_id)); 637 memset(product_id,0,sizeof(product_id)); 638 memset(sub_product_id,0,sizeof(sub_product_id)); 639 strcpy(vendor_id,"0000"); 640 strcpy(product_id,"0000"); 641 /* ffff will be used to match any device as in modules.alias 642 * a missing subvendor/product have to be considered as 0xFFFF*/ 643 strcpy(sub_product_id,"ffff"); 644 strcpy(sub_vendor_id,"ffff"); 645 646 char *result = NULL; 647 int field=0; 648 649 /* looking for the next field */ 650 result = strtok(line+strlen("alias pci:v"), delims); 651 while( result != NULL ) { 652 if (field==0) { 653 654 /* Searching for the vendor separator*/ 655 char *temp = strstr(result,"d"); 656 if (temp != NULL) { 657 strlcpy(vendor_id,result,temp-result); 658 result+=strlen(vendor_id)+1; 659 } 660 661 /* Searching for the product separator*/ 662 temp = strstr(result,"sv"); 663 if (temp != NULL) { 664 strlcpy(product_id,result,temp-result); 665 result+=strlen(product_id)+1; 666 } 667 668 /* Searching for the sub vendor separator*/ 669 temp = strstr(result,"sd"); 670 if (temp != NULL) { 671 strlcpy(sub_vendor_id,result,temp-result); 672 result+=strlen(sub_vendor_id)+1; 673 } 674 675 /* Searching for the sub product separator*/ 676 temp = strstr(result,"bc"); 677 if (temp != NULL) { 678 strlcpy(sub_product_id,result,temp-result); 679 result+=strlen(sub_product_id)+1; 680 } 681 /* That's the module name */ 682 } else if ((strlen(result)>2) && 683 (result[0]==0x20)) 684 strcpy(module_name,result+1); 685 /* We have to replace \n by \0*/ 686 module_name[strlen(module_name)-1]='\0'; 687 field++; 688 689 /* Searching the next field */ 690 result = strtok( NULL, delims ); 691 } 692 693 /* Now we have extracted informations from the modules.alias 694 * Let's compare it with the devices we know*/ 695 int int_vendor_id=hex_to_int(vendor_id); 696 int int_sub_vendor_id=hex_to_int(sub_vendor_id); 697 int int_product_id=hex_to_int(product_id); 698 int int_sub_product_id=hex_to_int(sub_product_id); 699 /* if a pci_device matches an entry, fill the linux_kernel_module with 700 the appropriate kernel module */ 701 for_each_pci_func(dev, domain) { 702 if (int_vendor_id == dev->vendor && 703 int_product_id == dev->product && 704 (int_sub_product_id & dev->sub_product) 705 == dev->sub_product && 706 (int_sub_vendor_id & dev->sub_vendor) 707 == dev->sub_vendor) { 708 bool found=false; 709 710 /* Scan all known kernel modules for this pci device */ 711 for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) { 712 713 /* Try to detect if we already knew the same kernel module*/ 714 if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) { 715 found=true; 716 break; 717 } 718 } 719 /* If we don't have this kernel module, let's add it */ 720 if (!found) { 721 strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name); 722 dev->dev_info->linux_kernel_module_count++; 723 } 724 } 725 } 726 } 727 fclose(f); 728 return 0; 729 } 730