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