summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErwan Velu <erwan@seanodes.com>2007-08-13 17:16:03 +0200
committerH. Peter Anvin <hpa@zytor.com>2007-08-16 18:13:25 -0700
commit4e9956bf1b587df39590aa620be0940b30269a53 (patch)
treefe68ac6e95a455553e0c6caa11fca7e57ea8972e
parentb85529420d2618222d9157866ab41a00e9f4fad9 (diff)
downloadsyslinux-4e9956bf1b587df39590aa620be0940b30269a53.tar.gz
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 <erwan.velu@free.fr> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--com32/include/sys/pci.h39
-rw-r--r--com32/lib/pci/scan.c252
-rw-r--r--com32/modules/ethersel.c4
-rw-r--r--com32/modules/pcitest.c36
4 files changed, 295 insertions, 36 deletions
diff --git a/com32/include/sys/pci.h b/com32/include/sys/pci.h
index b511477b..3f9b0d97 100644
--- a/com32/include/sys/pci.h
+++ b/com32/include/sys/pci.h
@@ -4,36 +4,43 @@
#include <inttypes.h>
#include <sys/io.h>
-#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 2b41fdf7..3bd98ceb 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 924ec56b..ad1d052d 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 c5e72e34..e28aad93 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; bus<pci_bus_list->count;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;
}