From 4e9956bf1b587df39590aa620be0940b30269a53 Mon Sep 17 00:00:00 2001 From: Erwan Velu Date: Mon, 13 Aug 2007 17:16:03 +0200 Subject: [PATCH] Improving PCI collected informations This patch - add a new pci_dev_info structure : It contains additional informations about the pci devices like the product/vendor name and the associated linux kernel module - add a get_name_from_pci_ids() function in pci/scan.c This function reads a pci.ids file from the boot device. Then it assign for each pci device, its vendor/product name. You just have to put this file in the root directory of your isolinux/pxelinux (i.e the root directory of your tfptboot server if you are using pxelinux). - add a get_module_name_from_pci_ids() function in pci/scan.c This function reads a modules.pcimap file from the boot device. Then it assign for each pci_device its linux kernel module. You just have to put this file in the root directory of your isolinux/pxelinux (i.e the root directory of your tfptboot server if you are using pxelinux). - Add a call to get_name_from_pci_ids() into the pcitest COM32 module - Add a call to get_module_name_from_pci_ids() into the pcitest COM32 module - Fixing typedef struct { ... } s_pci...; by struct pci... {}; - Improving comments - Fixing the memory allocation to prevent leaks With this patch, pcitest.c32 act like lspci plus a bonus by displaying the linux kernel module assiocated to each pci device. Signed-off-by:Erwan Velu Signed-off-by: H. Peter Anvin --- com32/include/sys/pci.h | 39 +++++--- com32/lib/pci/scan.c | 252 +++++++++++++++++++++++++++++++++++++++++++++-- com32/modules/ethersel.c | 4 +- com32/modules/pcitest.c | 36 ++++--- 4 files changed, 295 insertions(+), 36 deletions(-) diff --git a/com32/include/sys/pci.h b/com32/include/sys/pci.h index b511477..3f9b0d9 100644 --- a/com32/include/sys/pci.h +++ b/com32/include/sys/pci.h @@ -4,36 +4,43 @@ #include #include -#define MAX_VENDOR_NAME_SIZE 255 -#define MAX_PRODUCT_NAME_SIZE 255 #define MAX_PCI_DEVICES 32 #define MAX_PCI_BUSES 255 typedef uint32_t pciaddr_t; -typedef struct { +/* a structure for extended pci information */ +struct pci_dev_info { + char *vendor_name; + char *product_name; + char *linux_kernel_module; +}; + +/* a struct to represent a pci device */ +struct pci_device { uint16_t vendor; uint16_t product; uint16_t sub_vendor; uint16_t sub_product; uint8_t revision; -} s_pci_device; + struct pci_dev_info *pci_dev_info; +}; -typedef struct { +struct pci_bus { uint16_t id; - s_pci_device *pci_device[MAX_PCI_DEVICES]; + struct pci_device *pci_device[MAX_PCI_DEVICES]; uint8_t pci_device_count; -} s_pci_bus; +}; -typedef struct { - s_pci_device pci_device[MAX_PCI_DEVICES]; +struct pci_device_list { + struct pci_device pci_device[MAX_PCI_DEVICES]; uint8_t count; -} s_pci_device_list; +}; -typedef struct { - s_pci_bus pci_bus[MAX_PCI_BUSES]; +struct pci_bus_list { + struct pci_bus pci_bus[MAX_PCI_BUSES]; uint8_t count; -} s_pci_bus_list; +}; struct match { struct match *next; @@ -69,6 +76,8 @@ void pci_writeb(uint8_t, pciaddr_t); void pci_writew(uint16_t, pciaddr_t); void pci_writel(uint32_t, pciaddr_t); -extern int pci_scan(s_pci_bus_list *pci_bus_list, s_pci_device_list *pci_device_list); -extern struct match * find_pci_device(s_pci_device_list *pci_device_list, struct match *list); +extern int pci_scan(struct pci_bus_list *pci_bus_list, struct pci_device_list *pci_device_list); +extern struct match * find_pci_device(struct pci_device_list *pci_device_list, struct match *list); +extern void get_name_from_pci_ids(struct pci_device_list *pci_device_list); +extern void get_module_name_from_pci_ids(struct pci_device_list *pci_device_list); #endif /* _SYS_PCI_H */ diff --git a/com32/lib/pci/scan.c b/com32/lib/pci/scan.c index 2b41fdf..3bd98ce 100644 --- a/com32/lib/pci/scan.c +++ b/com32/lib/pci/scan.c @@ -47,6 +47,8 @@ #endif #define MAX_LINE 512 + +/* searching the next char that is not a space */ static char *skipspace(char *p) { while (*p && *p <= ' ') @@ -55,20 +57,255 @@ static char *skipspace(char *p) return p; } -struct match *find_pci_device(s_pci_device_list * pci_device_list, +/* removing any \n found in a string */ +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*/ +int hex_to_int(char *hexa) +{ + int i; + sscanf(hexa,"%x",&i); + return i; +} + +/* Try to match any pci device to the appropriate kernel module */ +/* it uses the modules.pcimap from the boot device*/ +void get_module_name_from_pci_ids(struct pci_device_list *pci_device_list) +{ + 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; + int pci_dev; + + /* Intializing the linux_kernel_module for each pci device to "unknow" */ + /* adding a pci_dev_info member if needed*/ + for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) { + struct pci_device *pci_device = &(pci_device_list->pci_device[pci_dev]); + + /* initialize the pci_dev_info structure if it doesn't exist yet. */ + if (! pci_device->pci_dev_info) { + pci_device->pci_dev_info=calloc(1,sizeof (struct pci_device)); + if (pci_device->pci_dev_info == NULL) { + printf("Can't allocate memory\n"); + return; + } + } + pci_device->pci_dev_info->linux_kernel_module=strdup("unknown"); + //printf("%04x:%04x %s %s\n",pci_device->vendor,pci_device->product,pci_device->pci_dev_info->vendor_name,pci_device->pci_dev_info->vendor_name); + + } + + /* Opening the modules.pcimap (ofa linux kernel) from the boot device*/ + f=fopen("modules.pcimap","r"); + if (!f) + return; + + 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) { + case 0: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 ); + } + /* if a pci_device match an entry, fill the linux_kernel_module with the appropriate kernel module */ + for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) { + struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev]; + if ((hex_to_int(vendor_id)==pci_device->vendor) && (hex_to_int(product_id)==pci_device->product) &&\ + ((hex_to_int(sub_product_id) & pci_device->sub_product)==pci_device->sub_product) &&\ + ((hex_to_int(sub_vendor_id) & pci_device->sub_vendor)==pci_device->sub_vendor)) { +// printf("module=%s#%s#\n",module_name,pci_device->pci_dev_info->product_name); + strcpy(pci_device->pci_dev_info->linux_kernel_module,module_name); + } + } + } + fclose(f); +} + +/* Try to match any pci device to the appropriate vendor and product name */ +/* it uses the pci.ids from the boot device*/ +void get_name_from_pci_ids(struct pci_device_list *pci_device_list) +{ + char line[MAX_LINE]; + char *vendor=NULL; + char vendor_id[5]; + char *product=NULL; + char product_id[5]; + char sub_product_id[5]; + char sub_vendor_id[5]; + FILE *f; + int pci_dev; + + /* Intializing the vendor/product name for each pci device to "unknow" */ + /* adding a pci_dev_info member if needed*/ + for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) { + struct pci_device *pci_device = &(pci_device_list->pci_device[pci_dev]); + + /* initialize the pci_dev_info structure if it doesn't exist yet. */ + if (! pci_device->pci_dev_info) { + pci_device->pci_dev_info=calloc(1,sizeof (struct pci_device)); + if (pci_device->pci_dev_info == NULL) { + printf("Can't allocate memory\n"); + return; + } + } + + pci_device->pci_dev_info->vendor_name=strdup("unknown"); + pci_device->pci_dev_info->product_name=strdup("unknown"); + } + + /* Opening the pci.ids from the boot device*/ + f=fopen("pci.ids","r"); + if (!f) + return; + + 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 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 4th first chars are the vendor_id */ + strncpy(vendor_id,line,4); + + /* the vendor name is the next field*/ + vendor_id[4]=0; + vendor=strdup(skipspace(strstr(line," "))); + remove_eol(vendor); + + /* init product_id, sub_product and sub_vendor */ + strcpy(product_id,"0000"); + strcpy(sub_product_id,"0000"); + strcpy(sub_vendor_id,"0000"); + + /* ffff is an invalid vendor id */ + if (strstr(vendor_id,"ffff")) break; + + /* assign the vendor_name to any matching pci device*/ + for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) { + struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev]; + if (hex_to_int(vendor_id)==pci_device->vendor) { + pci_device->pci_dev_info->vendor_name=strdup(vendor); + } + } + /* if we have a tab + a char, it means this is a product id */ + } else if ((line[0] == '\t') && (line[1] != '\t')) { + + /* the product name the second field */ + product=strdup(skipspace(strstr(line," "))); + remove_eol(product); + + /* the product id is first field */ + strncpy(product_id,&line[1],4); + product_id[4]=0; + + /* init sub_product and sub_vendor */ + strcpy(sub_product_id,"0000"); + strcpy(sub_vendor_id,"0000"); + + /* assign the product_name to any matching pci device*/ + for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) { + struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev]; + if ((hex_to_int(vendor_id)==pci_device->vendor) && (hex_to_int(product_id)==pci_device->product)) { + pci_device->pci_dev_info->product_name=strdup(product); + } + } + + /* if we have two tabs, it means this is a sub product */ + } else if ((line[0] == '\t') && (line[1] == '\t')) { + + /* the product name is last field */ + product=skipspace(strstr(line," ")); + product=strdup(skipspace(strstr(product," "))); + remove_eol(product); + + /* the sub_vendor id is first field */ + strncpy(sub_vendor_id,&line[2],4); + sub_vendor_id[4]=0; + + /* the sub_vendor id is second field */ + strncpy(sub_product_id,&line[7],4); + sub_product_id[4]=0; + + /* assign the product_name to any matching pci device*/ + for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) { + struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev]; + if ((hex_to_int(vendor_id)==pci_device->vendor) && (hex_to_int(product_id)==pci_device->product) && + (hex_to_int(sub_product_id)==pci_device->sub_product) && + (hex_to_int(sub_vendor_id)==pci_device->sub_vendor)) { + pci_device->pci_dev_info->product_name=strdup(product); + } + } + } + } + fclose(f); +} + +/* searching if any pcidevice match our query */ +struct match *find_pci_device(struct pci_device_list * pci_device_list, struct match *list) { int pci_dev; uint32_t did, sid; struct match *m; + /* for all matches we have to search */ for (m = list; m; m = m->next) { + /* for each pci device we know */ for (pci_dev = 0; pci_dev < pci_device_list->count; pci_dev++) { - s_pci_device *pci_device = + struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev]; + + /* sid & did are the easiest way to compare devices */ + /* they are made of vendor/product subvendor/subproduct ids */ sid = ((pci_device->sub_product) << 16 | (pci_device-> sub_vendor)); did = ((pci_device->product << 16) | (pci_device->vendor)); + + /*if the current device match */ if (((did ^ m->did) & m->did_mask) == 0 && ((sid ^ m->sid) & m->sid_mask) == 0 && pci_device->revision >= m->rid_min @@ -78,6 +315,7 @@ struct match *find_pci_device(s_pci_device_list * pci_device_list, pci_device->sub_vendor, pci_device->sub_product, pci_device->revision); + /* returning the matched pci device */ return m; } } @@ -85,7 +323,8 @@ struct match *find_pci_device(s_pci_device_list * pci_device_list, return NULL; } -int pci_scan(s_pci_bus_list * pci_bus_list, s_pci_device_list * pci_device_list) +/* scanning the pci bus to find pci devices */ +int pci_scan(struct pci_bus_list * pci_bus_list, struct pci_device_list * pci_device_list) { unsigned int bus, dev, func, maxfunc; uint32_t did, sid; @@ -105,9 +344,10 @@ int pci_scan(s_pci_bus_list * pci_bus_list, s_pci_device_list * pci_device_list) (void)cfgtype; dprintf("PCI configuration type %d\n", cfgtype); - printf("Scanning PCI Buses\n"); + dprintf("Scanning PCI Buses\n"); - for (bus = 0; bus <= 0xff; bus++) { + /* We try to detect 255 buses */ + for (bus = 0; bus <= MAX_PCI_BUSES; bus++) { dprintf("Probing bus 0x%02x... \n", bus); @@ -133,7 +373,7 @@ int pci_scan(s_pci_bus_list * pci_bus_list, s_pci_device_list * pci_device_list) rid = pci_readb(a + 0x08); sid = pci_readl(a + 0x2c); - s_pci_device *pci_device = + struct pci_device *pci_device = &pci_device_list-> pci_device[pci_device_list->count]; pci_device->product = did >> 16; diff --git a/com32/modules/ethersel.c b/com32/modules/ethersel.c index 924ec56..ad1d052 100644 --- a/com32/modules/ethersel.c +++ b/com32/modules/ethersel.c @@ -214,8 +214,8 @@ execute(const char *cmdline) int main(int argc, char *argv[]) { struct match *list, *match; - s_pci_device_list pci_device_list; - s_pci_bus_list pci_bus_list; + struct pci_device_list pci_device_list; + struct pci_bus_list pci_bus_list; openconsole(&dev_null_r, &dev_stdcon_w); pci_scan(&pci_bus_list,&pci_device_list); diff --git a/com32/modules/pcitest.c b/com32/modules/pcitest.c index c5e72e3..e28aad9 100644 --- a/com32/modules/pcitest.c +++ b/com32/modules/pcitest.c @@ -43,43 +43,53 @@ char display_line; printf ( __VA_ARGS__); \ } while (0); -void display_pci_devices(s_pci_device_list *pci_device_list) { +void display_pci_devices(struct pci_device_list *pci_device_list) { int pci_dev; for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) { - s_pci_device *pci_device = &pci_device_list->pci_device[pci_dev]; - printf("PCI: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n", - pci_device->vendor, pci_device->product, + struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev]; + printf("PCI: Vendor=%04x(%s) Product=%04x(%s) Sub_vendor=%04x Sub_Product=%04x Release=%02x\n", + pci_device->vendor,pci_device->pci_dev_info->vendor_name, pci_device->product, pci_device->pci_dev_info->product_name, pci_device->sub_vendor, pci_device->sub_product, pci_device->revision); } printf("PCI: %d devices found\n",pci_device_list->count); } -void display_pci_bus(s_pci_bus_list *pci_bus_list, bool display_pci_devices) { +void display_pci_bus(struct pci_bus_list *pci_bus_list, bool display_pci_devices) { int bus; for (bus=0; buscount;bus++) { - s_pci_bus pci_bus = pci_bus_list->pci_bus[bus]; + struct pci_bus pci_bus = pci_bus_list->pci_bus[bus]; printf("\nPCI BUS No %d:\n", pci_bus.id); if (display_pci_devices) { int pci_dev; for (pci_dev=0; pci_dev < pci_bus.pci_device_count; pci_dev++) { - s_pci_device pci_device=*(pci_bus.pci_device[pci_dev]); - printf("#(%04x:%04x[%04x:%04x])\n", + struct pci_device pci_device=*(pci_bus.pci_device[pci_dev]); + printf("%s :%04x:%04x[%04x:%04x]) %s:%s\n", + pci_device.pci_dev_info->linux_kernel_module, pci_device.vendor, pci_device.product, - pci_device.sub_vendor, pci_device.sub_product); + pci_device.sub_vendor, pci_device.sub_product, pci_device.pci_dev_info->vendor_name,pci_device.pci_dev_info->product_name); } } } - printf("PCI: %d buses found\n",pci_bus_list->count); + printf("PCI: %d buse(s) found\n",pci_bus_list->count); } int main(int argc, char *argv[]) { - s_pci_device_list pci_device_list; - s_pci_bus_list pci_bus_list; + struct pci_device_list pci_device_list; + struct pci_bus_list pci_bus_list; openconsole(&dev_null_r, &dev_stdcon_w); + + /* Scanning to detect pci buses and devices */ pci_scan(&pci_bus_list,&pci_device_list); -// display_pci_devices(&pci_device_list); + + /* Assigning product & vendor name for each device*/ + get_name_from_pci_ids(&pci_device_list); + + /* Detecting which kernel module should match each device */ + get_module_name_from_pci_ids(&pci_device_list); + + /* display the pci devices we found */ display_pci_bus(&pci_bus_list,true); return 1; } -- 2.7.4