aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErwan Velu <erwan@r1.paris>2006-09-07 20:30:09 +0200
committerH. Peter Anvin <hpa@zytor.com>2006-09-12 21:06:55 -0700
commitc1b0bb65b97cde99e4a7be101fa4033833d17243 (patch)
tree77add7aaaa0cdfe9881f4f55dd8fd5fe9ab6261c
parent7d5d2f9bb363f95db585092f43fe5a1eefe588f1 (diff)
downloadsyslinux-c1b0bb65b97cde99e4a7be101fa4033833d17243.tar.gz
syslinux-c1b0bb65b97cde99e4a7be101fa4033833d17243.tar.xz
syslinux-c1b0bb65b97cde99e4a7be101fa4033833d17243.zip
Introducing a new com32 module to parse pci devices/busessyslinux-3.2x
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)
-rw-r--r--com32/include/sys/pci.h32
-rw-r--r--com32/modules/Makefile5
-rw-r--r--com32/modules/pci.c191
-rw-r--r--com32/modules/pcitest.c70
4 files changed, 297 insertions, 1 deletions
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 <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 {
+ 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <console.h>
+#include <sys/pci.h>
+#include <com32.h>
+#include <stdbool.h>
+
+#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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <console.h>
+#include <com32.h>
+#include <sys/pci.h>
+#include <stdbool.h>
+
+#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_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,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; bus<pci_bus_list->count;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_dev<pci_bus.pci_device_count;pci_dev++) {
+ s_pci_device pci_device=*(pci_bus.pci_device[pci_dev]);
+ printf("%s:%s#(%04x:%04x[%04x:%04x])\n",pci_device.vendor_name,pci_device.product_name,pci_device.vendor,pci_device.product,pci_device.sub_vendor,pci_device.sub_product);
+ }
+ }
+ }
+ printf("PCI: %d buses 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;
+ 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;
+}