From c1b0bb65b97cde99e4a7be101fa4033833d17243 Mon Sep 17 00:00:00 2001 From: Erwan Velu Date: Thu, 7 Sep 2006 20:30:09 +0200 Subject: [PATCH] Introducing a new com32 module to parse pci devices/buses The pcitest module implements an example of use the pci module If you like to use the string name just put a pci.ids file in the root directory (cherry picked from 85bb6facf0100592c89d5c3c5c17b25e7b0006b3 commit) --- com32/include/sys/pci.h | 32 ++++++++ com32/modules/Makefile | 5 +- com32/modules/pci.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++ com32/modules/pcitest.c | 70 ++++++++++++++++++ 4 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 com32/modules/pci.c create mode 100644 com32/modules/pcitest.c diff --git a/com32/include/sys/pci.h b/com32/include/sys/pci.h index f1c1eb55..b3099584 100644 --- a/com32/include/sys/pci.h +++ b/com32/include/sys/pci.h @@ -4,8 +4,39 @@ #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 { + char vendor_name[MAX_VENDOR_NAME_SIZE]; + uint16_t vendor; + char product_name[MAX_PRODUCT_NAME_SIZE]; + uint16_t product; + uint16_t sub_vendor; + uint16_t sub_product; + uint8_t revision; +} s_pci_device; + +typedef struct { + uint16_t id; + s_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]; + uint8_t count; +} s_pci_device_list; + +typedef struct { + s_pci_bus pci_bus[MAX_PCI_BUSES]; + uint8_t count; +} s_pci_bus_list; + static inline pciaddr_t pci_mkaddr(uint32_t bus, uint32_t dev, uint32_t func, uint32_t reg) { @@ -30,4 +61,5 @@ 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); #endif /* _SYS_PCI_H */ diff --git a/com32/modules/Makefile b/com32/modules/Makefile index efba4c36..f7f5340e 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -44,7 +44,7 @@ AUXDIR = $(LIBDIR)/syslinux INCDIR = /usr/include COM32DIR = $(AUXDIR)/com32 -MODULES = chain.c32 menu.c32 ethersel.c32 mboot.c32 dmitest.c32 cpuidtest.c32 +MODULES = chain.c32 menu.c32 ethersel.c32 mboot.c32 dmitest.c32 cpuidtest.c32 pcitest.c32 TESTFILES = menu.lnx all: $(MODULES) $(TESTFILES) @@ -76,6 +76,9 @@ all: $(MODULES) $(TESTFILES) %.c32: %.elf $(OBJCOPY) -O binary $< $@ +pcitest.elf : pcitest.o pci.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + cpuidtest.elf : cpuidtest.o cpuid.o $(LIBS) $(LD) $(LDFLAGS) -o $@ $^ diff --git a/com32/modules/pci.c b/com32/modules/pci.c new file mode 100644 index 00000000..48fba303 --- /dev/null +++ b/com32/modules/pci.c @@ -0,0 +1,191 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2006 Erwan Velu - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * pci.c + * + * A module to extract pci informations + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +#define MAX_LINE 512 +static char * +skipspace(char *p) +{ + while ( *p && *p <= ' ' ) + p++; + + return p; +} + +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; +} + +int hex_to_int(char *hexa) +{ + int i; + sscanf(hexa,"%x",&i); + return i; +} + +void get_name_from_pci_ids(s_pci_device *pci_device) +{ + 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; + + f=fopen("pci.ids","r"); + if (!f) + return; + + strcpy(pci_device->vendor_name,"Unknown"); + strcpy(pci_device->product_name,"Unknown"); + strcpy(vendor_id,"0000"); + strcpy(product_id,"0000"); + strcpy(sub_product_id,"0000"); + strcpy(sub_vendor_id,"0000"); + + + while ( fgets(line, sizeof line, f) ) { + if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 'C') || (line[0] == 10)) + continue; + if (line[0] != '\t') { + strncpy(vendor_id,line,4); + vendor_id[4]=0; + vendor=strdup(skipspace(strstr(line," "))); + remove_eol(vendor); + strcpy(product_id,"0000"); + strcpy(sub_product_id,"0000"); + strcpy(sub_vendor_id,"0000"); + if (strstr(vendor_id,"ffff")) break; + if (hex_to_int(vendor_id)==pci_device->vendor) strcpy(pci_device->vendor_name,vendor); + } else if ((line[0] == '\t') && (line[1] != '\t')) { + product=strdup(skipspace(strstr(line," "))); + remove_eol(product); + strncpy(product_id,&line[1],4); + product_id[4]=0; + strcpy(sub_product_id,"0000"); + strcpy(sub_vendor_id,"0000"); + if ((hex_to_int(vendor_id)==pci_device->vendor) && (hex_to_int(product_id)==pci_device->product)) strcpy(pci_device->product_name,product); + } else if ((line[0] == '\t') && (line[1] == '\t')) { + product=skipspace(strstr(line," ")); + product=strdup(skipspace(strstr(product," "))); + remove_eol(product); + strncpy(sub_vendor_id,&line[2],4); + sub_vendor_id[4]=0; + strncpy(sub_product_id,&line[7],4); + sub_product_id[4]=0; + 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)) strcpy(pci_device->product_name,product); + } + } + fclose(f); +} + +int pci_scan(s_pci_bus_list *pci_bus_list, s_pci_device_list *pci_device_list) +{ + unsigned int bus, dev, func, maxfunc; + uint32_t did, sid; + uint8_t hdrtype, rid; + pciaddr_t a; + int cfgtype; + + pci_device_list->count=0; + +#ifdef DEBUG + outl(~0, 0xcf8); + printf("Poking at port CF8 = %#08x\n", inl(0xcf8)); + outl(0, 0xcf8); +#endif + + cfgtype = pci_set_config_type(PCI_CFG_AUTO); + (void)cfgtype; + + dprintf("PCI configuration type %d\n", cfgtype); + printf("Scanning PCI Buses\n"); + + for ( bus = 0 ; bus <= 0xff ; bus++ ) { + + dprintf("Probing bus 0x%02x... \n", bus); + + pci_bus_list->pci_bus[bus].id=bus; + pci_bus_list->pci_bus[bus].pci_device_count=0; + pci_bus_list->count=0;; + + for ( dev = 0 ; dev <= 0x1f ; dev++ ) { + maxfunc = 0; + for ( func = 0 ; func <= maxfunc ; func++ ) { + a = pci_mkaddr(bus, dev, func, 0); + + did = pci_readl(a); + + if ( did == 0xffffffff || did == 0xffff0000 || + did == 0x0000ffff || did == 0x00000000 ) + continue; + + hdrtype = pci_readb(a + 0x0e); + + if ( hdrtype & 0x80 ) + maxfunc = 7; /* Multifunction device */ + +// if ( hdrtype & 0x7f ) +// continue; /* Ignore bridge devices */ + + rid = pci_readb(a + 0x08); + sid = pci_readl(a + 0x2c); + s_pci_device *pci_device = &pci_device_list->pci_device[pci_device_list->count]; + pci_device->product=did>>16; + pci_device->sub_product=sid>>16; + pci_device->vendor=(did<<16)>>16; + pci_device->sub_vendor=(sid<<16)>>16; + pci_device->revision=rid; + pci_device_list->count++; + get_name_from_pci_ids(pci_device); + dprintf("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n", bus, did, did>>16, (did<<16)>>16 , sid, rid); + /* Adding the detected pci device to the bus*/ + pci_bus_list->pci_bus[bus].pci_device[pci_bus_list->pci_bus[bus].pci_device_count]=pci_device; + pci_bus_list->pci_bus[bus].pci_device_count++; + } + } + } + + /* Detecting pci buses that have pci devices connected*/ + for (bus=0;bus<=0xff;bus++) { + + if (pci_bus_list->pci_bus[bus].pci_device_count>0) { + pci_bus_list->count++; + } + } + return 0; +} diff --git a/com32/modules/pcitest.c b/com32/modules/pcitest.c new file mode 100644 index 00000000..2b0b6be2 --- /dev/null +++ b/com32/modules/pcitest.c @@ -0,0 +1,70 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2006 Erwan Velu - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * pcitest.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +char display_line; +#define moreprintf(...) do { display_line++; if (display_line == 24) { char tempbuf[10]; display_line=0; printf("Press enter to continue\n"); fgets(tempbuf, sizeof tempbuf, stdin);} printf ( __VA_ARGS__); } while (0); + +void display_pci_devices(s_pci_device_list *pci_device_list) { + int pci_dev; + for (pci_dev=0; pci_devcount;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,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) { + int bus; + for (bus=0; buscount;bus++) { + s_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_devcount); +} + +int main(int argc, char *argv[]) +{ + s_pci_device_list pci_device_list; + s_pci_bus_list pci_bus_list; + openconsole(&dev_null_r, &dev_stdcon_w); + pci_scan(&pci_bus_list,&pci_device_list); +// display_pci_devices(&pci_device_list); + display_pci_bus(&pci_bus_list,true); + return 1; +} -- 2.11.4.GIT