1 /* 2 * The PCI Utilities -- Show Kernel Drivers 3 * 4 * Copyright (c) 1997--2008 Martin Mares <[email protected]> 5 * 6 * Can be freely distributed and used under the terms of the GNU GPL. 7 */ 8 9 #include <stdio.h> 10 #include <string.h> 11 #include <unistd.h> 12 13 #include "lspci.h" 14 15 #ifdef PCI_OS_LINUX 16 17 #include <sys/utsname.h> 18 19 struct pcimap_entry { 20 struct pcimap_entry *next; 21 unsigned int vendor, device; 22 unsigned int subvendor, subdevice; 23 unsigned int class, class_mask; 24 char module[1]; 25 }; 26 27 static struct pcimap_entry *pcimap_head; 28 29 static void 30 load_pcimap(void) 31 { 32 static int tried_pcimap; 33 struct utsname uts; 34 char *name, line[1024]; 35 FILE *f; 36 37 if (tried_pcimap) 38 return; 39 tried_pcimap = 1; 40 41 if (name = opt_pcimap) 42 { 43 f = fopen(name, "r"); 44 if (!f) 45 die("Cannot open pcimap file %s: %m", name); 46 } 47 else 48 { 49 if (uname(&uts) < 0) 50 die("uname() failed: %m"); 51 name = alloca(64 + strlen(uts.release)); 52 sprintf(name, "/lib/modules/%s/modules.pcimap", uts.release); 53 f = fopen(name, "r"); 54 if (!f) 55 return; 56 } 57 58 while (fgets(line, sizeof(line), f)) 59 { 60 char *c = strchr(line, '\n'); 61 struct pcimap_entry *e; 62 63 if (!c) 64 die("Unterminated or too long line in %s", name); 65 *c = 0; 66 if (!line[0] || line[0] == '#') 67 continue; 68 69 c = line; 70 while (*c && *c != ' ' && *c != '\t') 71 c++; 72 if (!*c) 73 continue; /* FIXME: Emit warnings! */ 74 *c++ = 0; 75 76 e = xmalloc(sizeof(*e) + strlen(line)); 77 if (sscanf(c, "%i%i%i%i%i%i", 78 &e->vendor, &e->device, 79 &e->subvendor, &e->subdevice, 80 &e->class, &e->class_mask) != 6) 81 continue; 82 e->next = pcimap_head; 83 pcimap_head = e; 84 strcpy(e->module, line); 85 } 86 fclose(f); 87 } 88 89 static int 90 match_pcimap(struct device *d, struct pcimap_entry *e) 91 { 92 struct pci_dev *dev = d->dev; 93 unsigned int class = get_conf_long(d, PCI_REVISION_ID) >> 8; 94 word subv, subd; 95 96 #define MATCH(x, y) ((y) > 0xffff || (x) == (y)) 97 get_subid(d, &subv, &subd); 98 return 99 MATCH(dev->vendor_id, e->vendor) && 100 MATCH(dev->device_id, e->device) && 101 MATCH(subv, e->subvendor) && 102 MATCH(subd, e->subdevice) && 103 (class & e->class_mask) == e->class; 104 #undef MATCH 105 } 106 107 #define DRIVER_BUF_SIZE 1024 108 109 static char * 110 find_driver(struct device *d, char *buf) 111 { 112 struct pci_dev *dev = d->dev; 113 char name[1024], *drv, *base; 114 int n; 115 116 if (dev->access->method != PCI_ACCESS_SYS_BUS_PCI) 117 return NULL; 118 119 base = pci_get_param(dev->access, "sysfs.path"); 120 if (!base || !base[0]) 121 return NULL; 122 123 n = snprintf(name, sizeof(name), "%s/devices/%04x:%02x:%02x.%d/driver", 124 base, dev->domain, dev->bus, dev->dev, dev->func); 125 if (n < 0 || n >= (int)sizeof(name)) 126 die("show_driver: sysfs device name too long, why?"); 127 128 n = readlink(name, buf, DRIVER_BUF_SIZE); 129 if (n < 0) 130 return NULL; 131 if (n >= DRIVER_BUF_SIZE) 132 return "<name-too-long>"; 133 buf[n] = 0; 134 135 if (drv = strrchr(buf, '/')) 136 return drv+1; 137 else 138 return buf; 139 } 140 141 void 142 show_kernel(struct device *d) 143 { 144 char buf[DRIVER_BUF_SIZE]; 145 char *driver; 146 struct pcimap_entry *e, *last = NULL; 147 148 if (driver = find_driver(d, buf)) 149 printf("\tKernel driver in use: %s\n", driver); 150 151 load_pcimap(); 152 for (e=pcimap_head; e; e=e->next) 153 if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module))) 154 { 155 printf("%s %s", (last ? "," : "\tKernel modules:"), e->module); 156 last = e; 157 } 158 if (last) 159 putchar('\n'); 160 } 161 162 void 163 show_kernel_machine(struct device *d) 164 { 165 char buf[DRIVER_BUF_SIZE]; 166 char *driver; 167 struct pcimap_entry *e, *last = NULL; 168 169 if (driver = find_driver(d, buf)) 170 printf("Driver:\t%s\n", driver); 171 172 load_pcimap(); 173 for (e=pcimap_head; e; e=e->next) 174 if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module))) 175 { 176 printf("Module:\t%s\n", e->module); 177 last = e; 178 } 179 } 180 181 #else 182 183 void 184 show_kernel(struct device *d UNUSED) 185 { 186 } 187 188 void 189 show_kernel_machine(struct device *d UNUSED) 190 { 191 } 192 193 #endif 194 195