syslinux/com32/lib/pci/scan.c
<<
>>
Prefs
   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 */
  49static 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 */
  59static 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 */
  66int 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 */
 173int 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 */
 266int 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 */
 420struct 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 */
 452struct 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
 533bail:
 534    free_pci_domain(domain);
 535    return NULL;
 536}
 537
 538/* gathering additional configuration*/
 539void 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
 561void 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                            free(slot);
 583                        }
 584                    }
 585                    free(bus);
 586                }
 587            }
 588            free(domain);
 589        }
 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 */
 595int 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.