X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ls-kernel.c;h=b90a469f7056f69c5d3adc72b1674002b7aecedf;hb=d462e89c81b9bb0986087abf30a8ea62dcc123a3;hp=41afefe4430e34163ebad6fc457728f8e854ac02;hpb=c7a349934e4b9160d5788c60f168bae1f0b6dd9d;p=pciutils.git diff --git a/ls-kernel.c b/ls-kernel.c index 41afefe..b90a469 100644 --- a/ls-kernel.c +++ b/ls-kernel.c @@ -1,14 +1,13 @@ /* * The PCI Utilities -- Show Kernel Drivers * - * Copyright (c) 1997--2008 Martin Mares + * Copyright (c) 1997--2013 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ #include #include -#include #include "lspci.h" @@ -16,6 +15,88 @@ #include +#ifdef PCI_USE_LIBKMOD + +#include + +static struct kmod_ctx *kmod_ctx; + +static int +show_kernel_init(void) +{ + static int show_kernel_inited = -1; + if (show_kernel_inited >= 0) + return show_kernel_inited; + + kmod_ctx = kmod_new(NULL, NULL); + if (!kmod_ctx) + { + fprintf(stderr, "lspci: Unable to initialize libkmod context\n"); + goto failed; + } + + int err; + if ((err = kmod_load_resources(kmod_ctx)) < 0) + { + fprintf(stderr, "lspci: Unable to load libkmod resources: error %d\n", err); + goto failed; + } + + show_kernel_inited = 1; + return 1; + +failed: + show_kernel_inited = 0; + return 0; +} + +void +show_kernel_cleanup(void) +{ + if (kmod_ctx) + kmod_unref(kmod_ctx); +} + +static const char *next_module(struct device *d) +{ + static struct kmod_list *klist, *kcurrent; + static struct kmod_module *kmodule; + + if (kmodule) + { + kmod_module_unref(kmodule); + kmodule = NULL; + } + + if (!klist) + { + pci_fill_info(d->dev, PCI_FILL_MODULE_ALIAS); + if (!d->dev->module_alias) + return NULL; + int err = kmod_module_new_from_lookup(kmod_ctx, d->dev->module_alias, &klist); + if (err < 0) + { + fprintf(stderr, "lspci: libkmod lookup failed: error %d\n", err); + return NULL; + } + kcurrent = klist; + } + else + kcurrent = kmod_list_next(klist, kcurrent); + + if (kcurrent) + { + kmodule = kmod_module_get_module(kcurrent); + return kmod_module_get_name(kmodule); + } + + kmod_module_unref_list(klist); + klist = NULL; + return NULL; +} + +#else + struct pcimap_entry { struct pcimap_entry *next; unsigned int vendor, device; @@ -26,8 +107,8 @@ struct pcimap_entry { static struct pcimap_entry *pcimap_head; -static void -load_pcimap(void) +static int +show_kernel_init(void) { static int tried_pcimap; struct utsname uts; @@ -35,7 +116,7 @@ load_pcimap(void) FILE *f; if (tried_pcimap) - return; + return 1; tried_pcimap = 1; if (name = opt_pcimap) @@ -52,7 +133,7 @@ load_pcimap(void) sprintf(name, "/lib/modules/%s/modules.pcimap", uts.release); f = fopen(name, "r"); if (!f) - return; + return 1; } while (fgets(line, sizeof(line), f)) @@ -84,109 +165,130 @@ load_pcimap(void) strcpy(e->module, line); } fclose(f); + + return 1; } static int match_pcimap(struct device *d, struct pcimap_entry *e) { struct pci_dev *dev = d->dev; - unsigned int class = get_conf_long(d, PCI_REVISION_ID) >> 8; - word subv, subd; + unsigned int class = (((unsigned int)dev->device_class << 8) | dev->prog_if); #define MATCH(x, y) ((y) > 0xffff || (x) == (y)) - get_subid(d, &subv, &subd); return MATCH(dev->vendor_id, e->vendor) && MATCH(dev->device_id, e->device) && - MATCH(subv, e->subvendor) && - MATCH(subd, e->subdevice) && + MATCH(dev->subsys_vendor_id, e->subvendor) && + MATCH(dev->subsys_id, e->subdevice) && (class & e->class_mask) == e->class; #undef MATCH } -#define DRIVER_BUF_SIZE 1024 - -static char * -find_driver(struct device *d, char *buf) +static const char *next_module(struct device *d) { - struct pci_dev *dev = d->dev; - char name[1024], *drv, *base; - int n; - - if (dev->access->method != PCI_ACCESS_SYS_BUS_PCI) - return NULL; - - base = pci_get_param(dev->access, "sysfs.path"); - if (!base || !base[0]) - return NULL; - - n = snprintf(name, sizeof(name), "%s/devices/%04x:%02x:%02x.%d/driver", - base, dev->domain, dev->bus, dev->dev, dev->func); - if (n < 0 || n >= (int)sizeof(name)) - die("show_driver: sysfs device name too long, why?"); - - n = readlink(name, buf, DRIVER_BUF_SIZE); - if (n < 0) - return NULL; - if (n >= DRIVER_BUF_SIZE) - return ""; - buf[n] = 0; - - if (drv = strrchr(buf, '/')) - return drv+1; + static struct pcimap_entry *current; + + if (!current) + current = pcimap_head; else - return buf; + current = current->next; + + while (current) + { + if (match_pcimap(d, current)) + return current->module; + current = current->next; + } + + return NULL; +} + +void +show_kernel_cleanup(void) +{ +} + +#endif + +static const char * +next_module_filtered(struct device *d) +{ + static char prev_module[256]; + const char *module; + + while (module = next_module(d)) + { + if (strcmp(module, prev_module)) + { + strncpy(prev_module, module, sizeof(prev_module)); + prev_module[sizeof(prev_module) - 1] = 0; + return module; + } + } + prev_module[0] = 0; + return NULL; } void show_kernel(struct device *d) { - char buf[DRIVER_BUF_SIZE]; - char *driver; - struct pcimap_entry *e, *last = NULL; + const char *driver, *module; - if (driver = find_driver(d, buf)) + pci_fill_info(d->dev, PCI_FILL_DRIVER); + if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) printf("\tKernel driver in use: %s\n", driver); - load_pcimap(); - for (e=pcimap_head; e; e=e->next) - if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module))) - { - printf("%s %s", (last ? "," : "\tKernel modules:"), e->module); - last = e; - } - if (last) + if (!show_kernel_init()) + return; + + int cnt = 0; + while (module = next_module_filtered(d)) + printf("%s %s", (cnt++ ? "," : "\tKernel modules:"), module); + if (cnt) putchar('\n'); } void show_kernel_machine(struct device *d) { - char buf[DRIVER_BUF_SIZE]; - char *driver; - struct pcimap_entry *e, *last = NULL; + const char *driver, *module; - if (driver = find_driver(d, buf)) + pci_fill_info(d->dev, PCI_FILL_DRIVER); + if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) printf("Driver:\t%s\n", driver); - load_pcimap(); - for (e=pcimap_head; e; e=e->next) - if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module))) - { - printf("Module:\t%s\n", e->module); - last = e; - } + if (!show_kernel_init()) + return; + + while (module = next_module_filtered(d)) + printf("Module:\t%s\n", module); } #else void -show_kernel(struct device *d UNUSED) +show_kernel(struct device *d) { + const char *driver; + + pci_fill_info(d->dev, PCI_FILL_DRIVER); + if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) + printf("\tDriver in use: %s\n", driver); +} + +void +show_kernel_machine(struct device *d) +{ + const char *driver; + + pci_fill_info(d->dev, PCI_FILL_DRIVER); + if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER)) + printf("Driver:\t%s\n", driver); } void -show_kernel_machine(struct device *d UNUSED) +show_kernel_cleanup(void) { }