diff options
Diffstat (limited to 'contrib/syslinux-4.02/com32/lib/pci/scan.c')
-rw-r--r-- | contrib/syslinux-4.02/com32/lib/pci/scan.c | 751 |
1 files changed, 751 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/com32/lib/pci/scan.c b/contrib/syslinux-4.02/com32/lib/pci/scan.c new file mode 100644 index 0000000..2577b32 --- /dev/null +++ b/contrib/syslinux-4.02/com32/lib/pci/scan.c @@ -0,0 +1,751 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2006-2007 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * pci.c + * + * A module to extract pci informations + */ + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <console.h> +#include <sys/pci.h> +#include <com32.h> +#include <stdbool.h> +#include <syslinux/zio.h> + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +#define MAX_LINE 512 + +/* searching the next char that is not a space */ +static char *skipspace(char *p) +{ + while (*p && *p <= ' ') + p++; + + return p; +} + +/* removing any \n found in a string */ +static void remove_eol(char *string) +{ + int j = strlen(string); + int i = 0; + for (i = 0; i < j; i++) + if (string[i] == '\n') + string[i] = 0; +} + +/* converting a hexa string into its numerical value */ +static int hex_to_int(char *hexa) +{ + return strtoul(hexa, NULL, 16); +} + +/* Replace char 'old' by char 'new' in source */ +void chr_replace(char *source, char old, char new) +{ + while (*source) { + source++; + if (source[0] == old) source[0]=new; + } +} + +/* Try to match any pci device to the appropriate kernel module */ +/* it uses the modules.pcimap from the boot device */ +int get_module_name_from_pcimap(struct pci_domain *domain, + char *modules_pcimap_path) +{ + char line[MAX_LINE]; + char module_name[21]; // the module name field is 21 char long + char delims[]=" "; // colums are separated by spaces + char vendor_id[16]; + char product_id[16]; + char sub_vendor_id[16]; + char sub_product_id[16]; + FILE *f; + struct pci_device *dev=NULL; + + /* Intializing the linux_kernel_module for each pci device to "unknown" */ + /* adding a dev_info member if needed */ + for_each_pci_func(dev, domain) { + /* initialize the dev_info structure if it doesn't exist yet. */ + if (! dev->dev_info) { + dev->dev_info = zalloc(sizeof *dev->dev_info); + if (!dev->dev_info) + return -1; + } + for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) { + if (strlen(dev->dev_info->linux_kernel_module[i])==0) + strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7); + } + } + + /* Opening the modules.pcimap (of a linux kernel) from the boot device */ + f=zfopen(modules_pcimap_path, "r"); + if (!f) + return -ENOMODULESPCIMAP; + + strcpy(vendor_id,"0000"); + strcpy(product_id,"0000"); + strcpy(sub_product_id,"0000"); + strcpy(sub_vendor_id,"0000"); + + /* for each line we found in the modules.pcimap */ + while ( fgets(line, sizeof line, f) ) { + /* skipping unecessary lines */ + if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10)) + continue; + + char *result = NULL; + int field=0; + + /* looking for the next field */ + result = strtok(line, delims); + while( result != NULL ) { + /* if the column is larger than 1 char */ + /* multiple spaces generates some empty fields */ + if (strlen(result)>1) { + switch (field) { + /* About case 0, the kernel module name is featuring '_' or '-' + * in the module name whereas modules.alias is only using '_'. + * To avoid kernel modules duplication, let's rename all '-' in '_' + * to match what modules.alias provides */ + case 0:chr_replace(result,'-','_');strcpy(module_name,result); break; + case 1:strcpy(vendor_id,result); break; + case 2:strcpy(product_id,result); break; + case 3:strcpy(sub_vendor_id,result); break; + case 4:strcpy(sub_product_id,result); break; + } + field++; + } + /* Searching the next field */ + result = strtok( NULL, delims ); + } + int int_vendor_id=hex_to_int(vendor_id); + int int_sub_vendor_id=hex_to_int(sub_vendor_id); + int int_product_id=hex_to_int(product_id); + int int_sub_product_id=hex_to_int(sub_product_id); + /* if a pci_device matches an entry, fill the linux_kernel_module with + the appropriate kernel module */ + for_each_pci_func(dev, domain) { + if (int_vendor_id == dev->vendor && + int_product_id == dev->product && + (int_sub_product_id & dev->sub_product) + == dev->sub_product && + (int_sub_vendor_id & dev->sub_vendor) + == dev->sub_vendor) { + bool found=false; + + /* Scan all known kernel modules for this pci device */ + for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) { + + /* Try to detect if we already knew the same kernel module*/ + if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) { + found=true; + break; + } + } + /* If we don't have this kernel module, let's add it */ + if (!found) { + strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name); + dev->dev_info->linux_kernel_module_count++; + } + } + } + } + fclose(f); + return 0; +} + +/* Try to match any pci device to the appropriate class name */ +/* it uses the pci.ids from the boot device */ +int get_class_name_from_pci_ids(struct pci_domain *domain, char *pciids_path) +{ + char line[MAX_LINE]; + char class_name[PCI_CLASS_NAME_SIZE]; + char sub_class_name[PCI_CLASS_NAME_SIZE]; + char class_id_str[5]; + char sub_class_id_str[5]; + FILE *f; + struct pci_device *dev; + bool class_mode = false; + + /* Intializing the vendor/product name for each pci device to "unknown" */ + /* adding a dev_info member if needed */ + for_each_pci_func(dev, domain) { + /* initialize the dev_info structure if it doesn't exist yet. */ + if (!dev->dev_info) { + dev->dev_info = zalloc(sizeof *dev->dev_info); + if (!dev->dev_info) + return -1; + } + strlcpy(dev->dev_info->class_name, "unknown", 7); + } + + /* Opening the pci.ids from the boot device */ + f = zfopen(pciids_path, "r"); + if (!f) + return -ENOPCIIDS; + + /* for each line we found in the pci.ids */ + while (fgets(line, sizeof line, f)) { + /* Skipping uncessary lines */ + if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10)) + continue; + + /* Until we found a line starting with a 'C', we are not parsing classes */ + if (line[0] == 'C') + class_mode = true; + if (class_mode == false) + continue; + strlcpy(class_name, "unknown", 7); + /* If the line doesn't start with a tab, it means that's a class name */ + if (line[0] != '\t') { + + /* ignore the two first char and then copy 2 chars (class id) */ + strlcpy(class_id_str, &line[2], 2); + class_id_str[2] = 0; + + /* the class name is the next field */ + strlcpy(class_name, skipspace(strstr(line, " ")), + PCI_CLASS_NAME_SIZE - 1); + remove_eol(class_name); + + int int_class_id_str = hex_to_int(class_id_str); + /* assign the class_name to any matching pci device */ + for_each_pci_func(dev, domain) { + if (int_class_id_str == dev->class[2]) { + strlcpy(dev->dev_info->class_name, class_name, + PCI_CLASS_NAME_SIZE - 1); + /* This value is usually the main category */ + strlcpy(dev->dev_info->category_name, class_name + 4, + PCI_CLASS_NAME_SIZE - 1); + } + } + /* if we have a tab + a char, it means this is a sub class name */ + } else if ((line[0] == '\t') && (line[1] != '\t')) { + + /* the sub class name the second field */ + strlcpy(sub_class_name, skipspace(strstr(line, " ")), + PCI_CLASS_NAME_SIZE - 1); + remove_eol(sub_class_name); + + /* the sub class id is first field */ + strlcpy(sub_class_id_str, &line[1], 2); + sub_class_id_str[2] = 0; + + int int_class_id_str = hex_to_int(class_id_str); + int int_sub_class_id_str = hex_to_int(sub_class_id_str); + /* assign the product_name to any matching pci device */ + for_each_pci_func(dev, domain) { + if (int_class_id_str == dev->class[2] && + int_sub_class_id_str == dev->class[1]) + strlcpy(dev->dev_info->class_name, sub_class_name, + PCI_CLASS_NAME_SIZE - 1); + } + + } + } + fclose(f); + return 0; +} + +/* Try to match any pci device to the appropriate vendor and product name */ +/* it uses the pci.ids from the boot device */ +int get_name_from_pci_ids(struct pci_domain *domain, char *pciids_path) +{ + char line[MAX_LINE]; + char vendor[PCI_VENDOR_NAME_SIZE]; + char vendor_id[5]; + char product[PCI_PRODUCT_NAME_SIZE]; + char product_id[5]; + char sub_product_id[5]; + char sub_vendor_id[5]; + FILE *f; + struct pci_device *dev; + bool skip_to_next_vendor = false; + uint16_t int_vendor_id; + uint16_t int_product_id; + uint16_t int_sub_product_id; + uint16_t int_sub_vendor_id; + + /* Intializing the vendor/product name for each pci device to "unknown" */ + /* adding a dev_info member if needed */ + for_each_pci_func(dev, domain) { + /* initialize the dev_info structure if it doesn't exist yet. */ + if (!dev->dev_info) { + dev->dev_info = zalloc(sizeof *dev->dev_info); + if (!dev->dev_info) + return -1; + } + strlcpy(dev->dev_info->vendor_name, "unknown", 7); + strlcpy(dev->dev_info->product_name, "unknown", 7); + } + + /* Opening the pci.ids from the boot device */ + f = zfopen(pciids_path, "r"); + if (!f) + return -ENOPCIIDS; + + strlcpy(vendor_id, "0000", 4); + strlcpy(product_id, "0000", 4); + strlcpy(sub_product_id, "0000", 4); + strlcpy(sub_vendor_id, "0000", 4); + + /* for each line we found in the pci.ids */ + while (fgets(line, sizeof line, f)) { + /* Skipping uncessary lines */ + if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 'C') || + (line[0] == 10)) + continue; + + /* If the line doesn't start with a tab, it means that's a vendor id */ + if (line[0] != '\t') { + + /* the 4 first chars are the vendor_id */ + strlcpy(vendor_id, line, 4); + + /* the vendor name is the next field */ + vendor_id[4] = 0; + strlcpy(vendor, skipspace(strstr(line, " ")), + PCI_VENDOR_NAME_SIZE - 1); + + remove_eol(vendor); + /* init product_id, sub_product and sub_vendor */ + strlcpy(product_id, "0000", 4); + strlcpy(sub_product_id, "0000", 4); + strlcpy(sub_vendor_id, "0000", 4); + + /* Unless we found a matching device, we have to skip to the next vendor */ + skip_to_next_vendor = true; + + int_vendor_id = hex_to_int(vendor_id); + /* Iterate in all pci devices to find a matching vendor */ + for_each_pci_func(dev, domain) { + /* if one device that match this vendor */ + if (int_vendor_id == dev->vendor) { + /* copy the vendor name for this device */ + strlcpy(dev->dev_info->vendor_name, vendor, + PCI_VENDOR_NAME_SIZE - 1); + /* Some pci devices match this vendor, so we have to found them */ + skip_to_next_vendor = false; + /* Let's loop on the other devices as some may have the same vendor */ + } + } + /* if we have a tab + a char, it means this is a product id + * but we only look at it if we own some pci devices of the current vendor*/ + } else if ((line[0] == '\t') && (line[1] != '\t') + && (skip_to_next_vendor == false)) { + + /* the product name the second field */ + strlcpy(product, skipspace(strstr(line, " ")), + PCI_PRODUCT_NAME_SIZE - 1); + remove_eol(product); + + /* the product id is first field */ + strlcpy(product_id, &line[1], 4); + product_id[4] = 0; + + /* init sub_product and sub_vendor */ + strlcpy(sub_product_id, "0000", 4); + strlcpy(sub_vendor_id, "0000", 4); + + int_vendor_id = hex_to_int(vendor_id); + int_product_id = hex_to_int(product_id); + /* assign the product_name to any matching pci device */ + for_each_pci_func(dev, domain) { + if (int_vendor_id == dev->vendor && + int_product_id == dev->product) { + strlcpy(dev->dev_info->vendor_name, vendor, + PCI_VENDOR_NAME_SIZE - 1); + strlcpy(dev->dev_info->product_name, product, + PCI_PRODUCT_NAME_SIZE - 1); + } + } + + /* if we have two tabs, it means this is a sub product + * but we only look at it if we own some pci devices of the current vendor*/ + } else if ((line[0] == '\t') && (line[1] == '\t') + && (skip_to_next_vendor == false)) { + + /* the product name is last field */ + strlcpy(product, skipspace(strstr(line, " ")), + PCI_PRODUCT_NAME_SIZE - 1); + strlcpy(product, skipspace(strstr(product, " ")), + PCI_PRODUCT_NAME_SIZE - 1); + remove_eol(product); + + /* the sub_vendor id is first field */ + strlcpy(sub_vendor_id, &line[2], 4); + sub_vendor_id[4] = 0; + + /* the sub_vendor id is second field */ + strlcpy(sub_product_id, &line[7], 4); + sub_product_id[4] = 0; + + int_vendor_id = hex_to_int(vendor_id); + int_sub_vendor_id = hex_to_int(sub_vendor_id); + int_product_id = hex_to_int(product_id); + int_sub_product_id = hex_to_int(sub_product_id); + /* assign the product_name to any matching pci device */ + for_each_pci_func(dev, domain) { + if (int_vendor_id == dev->vendor && + int_product_id == dev->product && + int_sub_product_id == dev->sub_product && + int_sub_vendor_id == dev->sub_vendor) { + strlcpy(dev->dev_info->vendor_name, vendor, + PCI_VENDOR_NAME_SIZE - 1); + strlcpy(dev->dev_info->product_name, product, + PCI_PRODUCT_NAME_SIZE - 1); + } + } + } + } + fclose(f); + return 0; +} + +/* searching if any pcidevice match our query */ +struct match *find_pci_device(const struct pci_domain *domain, + struct match *list) +{ + uint32_t did, sid; + struct match *m; + const struct pci_device *dev; + + /* for all matches we have to search */ + for (m = list; m; m = m->next) { + /* for each pci device we know */ + for_each_pci_func(dev, domain) { + /* sid & did are the easiest way to compare devices */ + /* they are made of vendor/product subvendor/subproduct ids */ + sid = dev->svid_sdid; + did = dev->vid_did; + /* if the current device match */ + if (((did ^ m->did) & m->did_mask) == 0 && + ((sid ^ m->sid) & m->sid_mask) == 0 && + dev->revision >= m->rid_min && dev->revision <= m->rid_max) { + dprintf + ("PCI Match: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n", + dev->vendor, dev->product, dev->sub_vendor, + dev->sub_product, dev->revision); + /* returning the matched pci device */ + return m; + } + } + } + return NULL; +} + +/* scanning the pci bus to find pci devices */ +struct pci_domain *pci_scan(void) +{ + struct pci_domain *domain = NULL; + struct pci_bus *bus = NULL; + struct pci_slot *slot = NULL; + struct pci_device *func = NULL; + unsigned int nbus, ndev, nfunc, maxfunc; + uint32_t did, sid, rcid; + uint8_t hdrtype; + pciaddr_t a; + int cfgtype; + + cfgtype = pci_set_config_type(PCI_CFG_AUTO); + + dprintf("PCI configuration type %d\n", cfgtype); + + if (cfgtype == PCI_CFG_NONE) + return NULL; + + dprintf("Scanning PCI Buses\n"); + + for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) { + dprintf("Probing bus 0x%02x... \n", nbus); + bus = NULL; + + for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) { + maxfunc = 1; /* Assume a single-function device */ + slot = NULL; + + for (nfunc = 0; nfunc < maxfunc; nfunc++) { + a = pci_mkaddr(nbus, ndev, nfunc, 0); + did = pci_readl(a); + + if (did == 0xffffffff || did == 0xffff0000 || + did == 0x0000ffff || did == 0x00000000) + continue; + + hdrtype = pci_readb(a + 0x0e); + + if (hdrtype & 0x80) + maxfunc = MAX_PCI_FUNC; /* Multifunction device */ + + rcid = pci_readl(a + 0x08); + sid = pci_readl(a + 0x2c); + + if (!domain) { + domain = zalloc(sizeof *domain); + if (!domain) + goto bail; + } + if (!bus) { + bus = zalloc(sizeof *bus); + if (!bus) + goto bail; + domain->bus[nbus] = bus; + } + if (!slot) { + slot = zalloc(sizeof *slot); + if (!slot) + goto bail; + bus->slot[ndev] = slot; + } + func = zalloc(sizeof *func); + if (!func) + goto bail; + + slot->func[nfunc] = func; + + func->vid_did = did; + func->svid_sdid = sid; + func->rid_class = rcid; + + dprintf + ("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n", + nbus, did, did >> 16, (did << 16) >> 16, sid, rcid & 0xff); + } + } + } + + return domain; + +bail: + free_pci_domain(domain); + return NULL; +} + +/* gathering additional configuration*/ +void gather_additional_pci_config(struct pci_domain *domain) +{ + struct pci_device *dev; + pciaddr_t pci_addr; + int cfgtype; + + cfgtype = pci_set_config_type(PCI_CFG_AUTO); + if (cfgtype == PCI_CFG_NONE) + return; + + for_each_pci_func3(dev, domain, pci_addr) { + if (!dev->dev_info) { + dev->dev_info = zalloc(sizeof *dev->dev_info); + if (!dev->dev_info) { + return; + } + } + dev->dev_info->irq = pci_readb(pci_addr + 0x3c); + dev->dev_info->latency = pci_readb(pci_addr + 0x0d); + } +} + +void free_pci_domain(struct pci_domain *domain) +{ + struct pci_bus *bus; + struct pci_slot *slot; + struct pci_device *func; + unsigned int nbus, ndev, nfunc; + + if (domain) { + for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) { + bus = domain->bus[nbus]; + if (bus) { + for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) { + slot = bus->slot[ndev]; + if (slot) { + for (nfunc = 0; nfunc < MAX_PCI_FUNC; nfunc++) { + func = slot->func[nfunc]; + if (func) { + if (func->dev_info) + free(func->dev_info); + free(func); + } + free(slot); + } + } + free(bus); + } + } + free(domain); + } + } +} + +/* Try to match any pci device to the appropriate kernel module */ +/* it uses the modules.alias from the boot device */ +int get_module_name_from_alias(struct pci_domain *domain, char *modules_alias_path) +{ + char line[MAX_LINE]; + char module_name[21]; // the module name field is 21 char long + char delims[]="*"; // colums are separated by spaces + char vendor_id[16]; + char product_id[16]; + char sub_vendor_id[16]; + char sub_product_id[16]; + FILE *f; + struct pci_device *dev=NULL; + + /* Intializing the linux_kernel_module for each pci device to "unknown" */ + /* adding a dev_info member if needed */ + for_each_pci_func(dev, domain) { + /* initialize the dev_info structure if it doesn't exist yet. */ + if (! dev->dev_info) { + dev->dev_info = zalloc(sizeof *dev->dev_info); + if (!dev->dev_info) + return -1; + } + for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) { + if (strlen(dev->dev_info->linux_kernel_module[i])==0) + strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7); + } + } + + /* Opening the modules.pcimap (of a linux kernel) from the boot device */ + f=zfopen(modules_alias_path, "r"); + if (!f) + return -ENOMODULESALIAS; + + /* for each line we found in the modules.pcimap */ + while ( fgets(line, sizeof line, f) ) { + /* skipping unecessary lines */ + if ((line[0] == '#') || (strstr(line,"alias pci:v")==NULL)) + continue; + + /* Resetting temp buffer*/ + memset(module_name,0,sizeof(module_name)); + memset(vendor_id,0,sizeof(vendor_id)); + memset(sub_vendor_id,0,sizeof(sub_vendor_id)); + memset(product_id,0,sizeof(product_id)); + memset(sub_product_id,0,sizeof(sub_product_id)); + strcpy(vendor_id,"0000"); + strcpy(product_id,"0000"); + /* ffff will be used to match any device as in modules.alias + * a missing subvendor/product have to be considered as 0xFFFF*/ + strcpy(sub_product_id,"ffff"); + strcpy(sub_vendor_id,"ffff"); + + char *result = NULL; + int field=0; + + /* looking for the next field */ + result = strtok(line+strlen("alias pci:v"), delims); + while( result != NULL ) { + if (field==0) { + + /* Searching for the vendor separator*/ + char *temp = strstr(result,"d"); + if (temp != NULL) { + strlcpy(vendor_id,result,temp-result); + result+=strlen(vendor_id)+1; + } + + /* Searching for the product separator*/ + temp = strstr(result,"sv"); + if (temp != NULL) { + strlcpy(product_id,result,temp-result); + result+=strlen(product_id)+1; + } + + /* Searching for the sub vendor separator*/ + temp = strstr(result,"sd"); + if (temp != NULL) { + strlcpy(sub_vendor_id,result,temp-result); + result+=strlen(sub_vendor_id)+1; + } + + /* Searching for the sub product separator*/ + temp = strstr(result,"bc"); + if (temp != NULL) { + strlcpy(sub_product_id,result,temp-result); + result+=strlen(sub_product_id)+1; + } + /* That's the module name */ + } else if ((strlen(result)>2) && + (result[0]==0x20)) + strcpy(module_name,result+1); + /* We have to replace \n by \0*/ + module_name[strlen(module_name)-1]='\0'; + field++; + + /* Searching the next field */ + result = strtok( NULL, delims ); + } + + /* Now we have extracted informations from the modules.alias + * Let's compare it with the devices we know*/ + int int_vendor_id=hex_to_int(vendor_id); + int int_sub_vendor_id=hex_to_int(sub_vendor_id); + int int_product_id=hex_to_int(product_id); + int int_sub_product_id=hex_to_int(sub_product_id); + /* if a pci_device matches an entry, fill the linux_kernel_module with + the appropriate kernel module */ + for_each_pci_func(dev, domain) { + if (int_vendor_id == dev->vendor && + int_product_id == dev->product && + (int_sub_product_id & dev->sub_product) + == dev->sub_product && + (int_sub_vendor_id & dev->sub_vendor) + == dev->sub_vendor) { + bool found=false; + + /* Scan all known kernel modules for this pci device */ + for (int i=0; i<dev->dev_info->linux_kernel_module_count; i++) { + + /* Try to detect if we already knew the same kernel module*/ + if (strstr(dev->dev_info->linux_kernel_module[i], module_name)) { + found=true; + break; + } + } + /* If we don't have this kernel module, let's add it */ + if (!found) { + strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name); + dev->dev_info->linux_kernel_module_count++; + } + } + } + } + fclose(f); + return 0; +} |