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 = get_conf_long(d, PCI_REVISION_ID) >> 8; 177 word subv, subd; 178 179 #define MATCH(x, y) ((y) > 0xffff || (x) == (y)) 180 get_subid(d, &subv, &subd); 181 return 182 MATCH(dev->vendor_id, e->vendor) && 183 MATCH(dev->device_id, e->device) && 184 MATCH(subv, e->subvendor) && 185 MATCH(subd, e->subdevice) && 186 (class & e->class_mask) == e->class; 187 #undef MATCH 188 } 189 190 static const char *next_module(struct device *d) 191 { 192 static struct pcimap_entry *current; 193 194 if (!current) 195 current = pcimap_head; 196 else 197 current = current->next; 198 199 while (current) 200 { 201 if (match_pcimap(d, current)) 202 return current->module; 203 current = current->next; 204 } 205 206 return NULL; 207 } 208 209 void 210 show_kernel_cleanup(void) 211 { 212 } 213 214 #endif 215 216 #define DRIVER_BUF_SIZE 1024 217 218 static char * 219 find_driver(struct device *d, char *buf) 220 { 221 struct pci_dev *dev = d->dev; 222 char name[1024], *drv, *base; 223 int n; 224 225 if (dev->access->method != PCI_ACCESS_SYS_BUS_PCI) 226 return NULL; 227 228 base = pci_get_param(dev->access, "sysfs.path"); 229 if (!base || !base[0]) 230 return NULL; 231 232 n = snprintf(name, sizeof(name), "%s/devices/%04x:%02x:%02x.%d/driver", 233 base, dev->domain, dev->bus, dev->dev, dev->func); 234 if (n < 0 || n >= (int)sizeof(name)) 235 die("show_driver: sysfs device name too long, why?"); 236 237 n = readlink(name, buf, DRIVER_BUF_SIZE); 238 if (n < 0) 239 return NULL; 240 if (n >= DRIVER_BUF_SIZE) 241 return "<name-too-long>"; 242 buf[n] = 0; 243 244 if (drv = strrchr(buf, '/')) 245 return drv+1; 246 else 247 return buf; 248 } 249 250 static const char * 251 next_module_filtered(struct device *d) 252 { 253 static char prev_module[256]; 254 const char *module; 255 256 while (module = next_module(d)) 257 { 258 if (strcmp(module, prev_module)) 259 { 260 strncpy(prev_module, module, sizeof(prev_module)); 261 prev_module[sizeof(prev_module) - 1] = 0; 262 return module; 263 } 264 } 265 prev_module[0] = 0; 266 return NULL; 267 } 268 269 void 270 show_kernel(struct device *d) 271 { 272 char buf[DRIVER_BUF_SIZE]; 273 const char *driver, *module; 274 275 if (driver = find_driver(d, buf)) 276 printf("\tKernel driver in use: %s\n", driver); 277 278 if (!show_kernel_init()) 279 return; 280 281 int cnt = 0; 282 while (module = next_module_filtered(d)) 283 printf("%s %s", (cnt++ ? "," : "\tKernel modules:"), module); 284 if (cnt) 285 putchar('\n'); 286 } 287 288 void 289 show_kernel_machine(struct device *d) 290 { 291 char buf[DRIVER_BUF_SIZE]; 292 const char *driver, *module; 293 294 if (driver = find_driver(d, buf)) 295 printf("Driver:\t%s\n", driver); 296 297 if (!show_kernel_init()) 298 return; 299 300 while (module = next_module_filtered(d)) 301 printf("Module:\t%s\n", module); 302 } 303 304 #else 305 306 void 307 show_kernel(struct device *d UNUSED) 308 { 309 } 310 311 void 312 show_kernel_machine(struct device *d UNUSED) 313 { 314 } 315 316 void 317 show_kernel_cleanup(void) 318 { 319 } 320 321 #endif 322 323