1 /* 2 * The PCI Utilities -- Show Kernel Drivers 3 * 4 * Copyright (c) 1997--2013 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 #ifdef PCI_USE_LIBKMOD 20 21 #include <libkmod.h> 22 23 static struct kmod_ctx *kmod_ctx; 24 25 static int 26 show_kernel_init(void) 27 { 28 static int show_kernel_inited = -1; 29 if (show_kernel_inited >= 0) 30 return show_kernel_inited; 31 32 kmod_ctx = kmod_new(NULL, NULL); 33 if (!kmod_ctx) 34 { 35 fprintf(stderr, "lspci: Unable to initialize libkmod context\n"); 36 goto failed; 37 } 38 39 int err; 40 if ((err = kmod_load_resources(kmod_ctx)) < 0) 41 { 42 fprintf(stderr, "lspci: Unable to load libkmod resources: error %d\n", err); 43 goto failed; 44 } 45 46 show_kernel_inited = 1; 47 return 1; 48 49 failed: 50 show_kernel_inited = 0; 51 return 0; 52 } 53 54 void 55 show_kernel_cleanup(void) 56 { 57 if (kmod_ctx) 58 kmod_unref(kmod_ctx); 59 } 60 61 static const char *next_module(struct device *d) 62 { 63 static struct kmod_list *klist, *kcurrent; 64 static struct kmod_module *kmodule; 65 66 if (kmodule) 67 { 68 kmod_module_unref(kmodule); 69 kmodule = NULL; 70 } 71 72 if (!klist) 73 { 74 pci_fill_info(d->dev, PCI_FILL_MODULE_ALIAS); 75 if (!d->dev->module_alias) 76 return NULL; 77 int err = kmod_module_new_from_lookup(kmod_ctx, d->dev->module_alias, &klist); 78 if (err < 0) 79 { 80 fprintf(stderr, "lspci: libkmod lookup failed: error %d\n", err); 81 return NULL; 82 } 83 kcurrent = klist; 84 } 85 else 86 kcurrent = kmod_list_next(klist, kcurrent); 87 88 if (kcurrent) 89 { 90 kmodule = kmod_module_get_module(kcurrent); 91 return kmod_module_get_name(kmodule); 92 } 93 94 kmod_module_unref_list(klist); 95 klist = NULL; 96 return NULL; 97 } 98 99 #else 100 101 struct pcimap_entry { 102 struct pcimap_entry *next; 103 unsigned int vendor, device; 104 unsigned int subvendor, subdevice; 105 unsigned int class, class_mask; 106 char module[1]; 107 }; 108 109 static struct pcimap_entry *pcimap_head; 110 111 static int 112 show_kernel_init(void) 113 { 114 static int tried_pcimap; 115 struct utsname uts; 116 char *name, line[1024]; 117 FILE *f; 118 119 if (tried_pcimap) 120 return 1; 121 tried_pcimap = 1; 122 123 if (name = opt_pcimap) 124 { 125 f = fopen(name, "r"); 126 if (!f) 127 die("Cannot open pcimap file %s: %m", name); 128 } 129 else 130 { 131 if (uname(&uts) < 0) 132 die("uname() failed: %m"); 133 name = alloca(64 + strlen(uts.release)); 134 sprintf(name, "/lib/modules/%s/modules.pcimap", uts.release); 135 f = fopen(name, "r"); 136 if (!f) 137 return 1; 138 } 139 140 while (fgets(line, sizeof(line), f)) 141 { 142 char *c = strchr(line, '\n'); 143 struct pcimap_entry *e; 144 145 if (!c) 146 die("Unterminated or too long line in %s", name); 147 *c = 0; 148 if (!line[0] || line[0] == '#') 149 continue; 150 151 c = line; 152 while (*c && *c != ' ' && *c != '\t') 153 c++; 154 if (!*c) 155 continue; /* FIXME: Emit warnings! */ 156 *c++ = 0; 157 158 e = xmalloc(sizeof(*e) + strlen(line)); 159 if (sscanf(c, "%i%i%i%i%i%i", 160 &e->vendor, &e->device, 161 &e->subvendor, &e->subdevice, 162 &e->class, &e->class_mask) != 6) 163 continue; 164 e->next = pcimap_head; 165 pcimap_head = e; 166 strcpy(e->module, line); 167 } 168 fclose(f); 169 170 return 1; 171 } 172 173 static int 174 match_pcimap(struct device *d, struct pcimap_entry *e) 175 { 176 struct pci_dev *dev = d->dev; 177 unsigned int class = get_conf_long(d, PCI_REVISION_ID) >> 8; 178 word subv, subd; 179 180 #define MATCH(x, y) ((y) > 0xffff || (x) == (y)) 181 get_subid(d, &subv, &subd); 182 return 183 MATCH(dev->vendor_id, e->vendor) && 184 MATCH(dev->device_id, e->device) && 185 MATCH(subv, e->subvendor) && 186 MATCH(subd, e->subdevice) && 187 (class & e->class_mask) == e->class; 188 #undef MATCH 189 } 190 191 static const char *next_module(struct device *d) 192 { 193 static struct pcimap_entry *current; 194 195 if (!current) 196 current = pcimap_head; 197 else 198 current = current->next; 199 200 while (current) 201 { 202 if (match_pcimap(d, current)) 203 return current->module; 204 current = current->next; 205 } 206 207 return NULL; 208 } 209 210 void 211 show_kernel_cleanup(void) 212 { 213 } 214 215 #endif 216 217 #define DRIVER_BUF_SIZE 1024 218 219 static char * 220 find_driver(struct device *d, char *buf) 221 { 222 struct pci_dev *dev = d->dev; 223 char name[1024], *drv, *base; 224 int n; 225 226 if (dev->access->method != PCI_ACCESS_SYS_BUS_PCI) 227 return NULL; 228 229 base = pci_get_param(dev->access, "sysfs.path"); 230 if (!base || !base[0]) 231 return NULL; 232 233 n = snprintf(name, sizeof(name), "%s/devices/%04x:%02x:%02x.%d/driver", 234 base, dev->domain, dev->bus, dev->dev, dev->func); 235 if (n < 0 || n >= (int)sizeof(name)) 236 die("show_driver: sysfs device name too long, why?"); 237 238 n = readlink(name, buf, DRIVER_BUF_SIZE); 239 if (n < 0) 240 return NULL; 241 if (n >= DRIVER_BUF_SIZE) 242 return "<name-too-long>"; 243 buf[n] = 0; 244 245 if (drv = strrchr(buf, '/')) 246 return drv+1; 247 else 248 return buf; 249 } 250 251 static const char * 252 next_module_filtered(struct device *d) 253 { 254 static char prev_module[256]; 255 const char *module; 256 257 while (module = next_module(d)) 258 { 259 if (strcmp(module, prev_module)) 260 { 261 strncpy(prev_module, module, sizeof(prev_module)); 262 prev_module[sizeof(prev_module) - 1] = 0; 263 return module; 264 } 265 } 266 prev_module[0] = 0; 267 return NULL; 268 } 269 270 void 271 show_kernel(struct device *d) 272 { 273 char buf[DRIVER_BUF_SIZE]; 274 const char *driver, *module; 275 276 if (driver = find_driver(d, buf)) 277 printf("\tKernel driver in use: %s\n", driver); 278 279 if (!show_kernel_init()) 280 return; 281 282 int cnt = 0; 283 while (module = next_module_filtered(d)) 284 printf("%s %s", (cnt++ ? "," : "\tKernel modules:"), module); 285 if (cnt) 286 putchar('\n'); 287 } 288 289 void 290 show_kernel_machine(struct device *d) 291 { 292 char buf[DRIVER_BUF_SIZE]; 293 const char *driver, *module; 294 295 if (driver = find_driver(d, buf)) 296 printf("Driver:\t%s\n", driver); 297 298 if (!show_kernel_init()) 299 return; 300 301 while (module = next_module_filtered(d)) 302 printf("Module:\t%s\n", module); 303 } 304 305 #else 306 307 void 308 show_kernel(struct device *d UNUSED) 309 { 310 } 311 312 void 313 show_kernel_machine(struct device *d UNUSED) 314 { 315 } 316 317 void 318 show_kernel_cleanup(void) 319 { 320 } 321 322 #endif 323 324