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 static const char * 215 next_module_filtered(struct device *d) 216 { 217 static char prev_module[256]; 218 const char *module; 219 220 while (module = next_module(d)) 221 { 222 if (strcmp(module, prev_module)) 223 { 224 strncpy(prev_module, module, sizeof(prev_module)); 225 prev_module[sizeof(prev_module) - 1] = 0; 226 return module; 227 } 228 } 229 prev_module[0] = 0; 230 return NULL; 231 } 232 233 void 234 show_kernel(struct device *d) 235 { 236 const char *driver, *module; 237 238 pci_fill_info(d->dev, PCI_FILL_DRIVER); 239 if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) 240 printf("\tKernel driver in use: %s\n", driver); 241 242 if (!show_kernel_init()) 243 return; 244 245 int cnt = 0; 246 while (module = next_module_filtered(d)) 247 printf("%s %s", (cnt++ ? "," : "\tKernel modules:"), module); 248 if (cnt) 249 putchar('\n'); 250 } 251 252 void 253 show_kernel_machine(struct device *d) 254 { 255 const char *driver, *module; 256 257 pci_fill_info(d->dev, PCI_FILL_DRIVER); 258 if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) 259 printf("Driver:\t%s\n", driver); 260 261 if (!show_kernel_init()) 262 return; 263 264 while (module = next_module_filtered(d)) 265 printf("Module:\t%s\n", module); 266 } 267 268 #else 269 270 void 271 show_kernel(struct device *d) 272 { 273 const char *driver; 274 275 pci_fill_info(d->dev, PCI_FILL_DRIVER); 276 if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) 277 printf("\tDriver in use: %s\n", driver); 278 } 279 280 void 281 show_kernel_machine(struct device *d) 282 { 283 const char *driver; 284 285 pci_fill_info(d->dev, PCI_FILL_DRIVER); 286 if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) 287 printf("Driver:\t%s\n", driver); 288 } 289 290 void 291 show_kernel_cleanup(void) 292 { 293 } 294 295 #endif 296 297