xref: /pciutils/ls-kernel.c (revision 61829219)
1c7a34993SMartin Mares /*
2c7a34993SMartin Mares  *	The PCI Utilities -- Show Kernel Drivers
3c7a34993SMartin Mares  *
417ec7e70SMartin Mares  *	Copyright (c) 1997--2013 Martin Mares <[email protected]>
5c7a34993SMartin Mares  *
6*61829219SMartin Mares  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7*61829219SMartin Mares  *
8*61829219SMartin Mares  *	SPDX-License-Identifier: GPL-2.0-or-later
9c7a34993SMartin Mares  */
10c7a34993SMartin Mares 
11c7a34993SMartin Mares #include <stdio.h>
12c7a34993SMartin Mares #include <string.h>
13c7a34993SMartin Mares 
14c7a34993SMartin Mares #include "lspci.h"
15c7a34993SMartin Mares 
16c7a34993SMartin Mares #ifdef PCI_OS_LINUX
17c7a34993SMartin Mares 
18c7a34993SMartin Mares #include <sys/utsname.h>
19c7a34993SMartin Mares 
2017ec7e70SMartin Mares #ifdef PCI_USE_LIBKMOD
2117ec7e70SMartin Mares 
2217ec7e70SMartin Mares #include <libkmod.h>
2317ec7e70SMartin Mares 
2417ec7e70SMartin Mares static struct kmod_ctx *kmod_ctx;
2517ec7e70SMartin Mares 
2617ec7e70SMartin Mares static int
show_kernel_init(void)2717ec7e70SMartin Mares show_kernel_init(void)
2817ec7e70SMartin Mares {
2917ec7e70SMartin Mares   static int show_kernel_inited = -1;
3017ec7e70SMartin Mares   if (show_kernel_inited >= 0)
3117ec7e70SMartin Mares     return show_kernel_inited;
3217ec7e70SMartin Mares 
33cc840156SVladimír Čunát   kmod_ctx = kmod_new(NULL, NULL);
3417ec7e70SMartin Mares   if (!kmod_ctx)
3517ec7e70SMartin Mares     {
3617ec7e70SMartin Mares       fprintf(stderr, "lspci: Unable to initialize libkmod context\n");
3717ec7e70SMartin Mares       goto failed;
3817ec7e70SMartin Mares     }
3917ec7e70SMartin Mares 
4017ec7e70SMartin Mares   int err;
4117ec7e70SMartin Mares   if ((err = kmod_load_resources(kmod_ctx)) < 0)
4217ec7e70SMartin Mares     {
4317ec7e70SMartin Mares       fprintf(stderr, "lspci: Unable to load libkmod resources: error %d\n", err);
4417ec7e70SMartin Mares       goto failed;
4517ec7e70SMartin Mares     }
4617ec7e70SMartin Mares 
4717ec7e70SMartin Mares   show_kernel_inited = 1;
4817ec7e70SMartin Mares   return 1;
4917ec7e70SMartin Mares 
5017ec7e70SMartin Mares failed:
5117ec7e70SMartin Mares   show_kernel_inited = 0;
5217ec7e70SMartin Mares   return 0;
5317ec7e70SMartin Mares }
5417ec7e70SMartin Mares 
5517ec7e70SMartin Mares void
show_kernel_cleanup(void)5617ec7e70SMartin Mares show_kernel_cleanup(void)
5717ec7e70SMartin Mares {
5817ec7e70SMartin Mares   if (kmod_ctx)
5917ec7e70SMartin Mares     kmod_unref(kmod_ctx);
6017ec7e70SMartin Mares }
6117ec7e70SMartin Mares 
next_module(struct device * d)6217ec7e70SMartin Mares static const char *next_module(struct device *d)
6317ec7e70SMartin Mares {
6417ec7e70SMartin Mares   static struct kmod_list *klist, *kcurrent;
6517ec7e70SMartin Mares   static struct kmod_module *kmodule;
6617ec7e70SMartin Mares 
6717ec7e70SMartin Mares   if (kmodule)
6817ec7e70SMartin Mares     {
6917ec7e70SMartin Mares       kmod_module_unref(kmodule);
7017ec7e70SMartin Mares       kmodule = NULL;
7117ec7e70SMartin Mares     }
7217ec7e70SMartin Mares 
7317ec7e70SMartin Mares   if (!klist)
7417ec7e70SMartin Mares     {
7517ec7e70SMartin Mares       pci_fill_info(d->dev, PCI_FILL_MODULE_ALIAS);
7617ec7e70SMartin Mares       if (!d->dev->module_alias)
7717ec7e70SMartin Mares 	return NULL;
7817ec7e70SMartin Mares       int err = kmod_module_new_from_lookup(kmod_ctx, d->dev->module_alias, &klist);
7917ec7e70SMartin Mares       if (err < 0)
8017ec7e70SMartin Mares 	{
8117ec7e70SMartin Mares 	  fprintf(stderr, "lspci: libkmod lookup failed: error %d\n", err);
8217ec7e70SMartin Mares 	  return NULL;
8317ec7e70SMartin Mares 	}
8417ec7e70SMartin Mares       kcurrent = klist;
8517ec7e70SMartin Mares     }
8617ec7e70SMartin Mares   else
8717ec7e70SMartin Mares     kcurrent = kmod_list_next(klist, kcurrent);
8817ec7e70SMartin Mares 
8917ec7e70SMartin Mares   if (kcurrent)
9017ec7e70SMartin Mares     {
9117ec7e70SMartin Mares       kmodule = kmod_module_get_module(kcurrent);
9217ec7e70SMartin Mares       return kmod_module_get_name(kmodule);
9317ec7e70SMartin Mares     }
9417ec7e70SMartin Mares 
9517ec7e70SMartin Mares   kmod_module_unref_list(klist);
9617ec7e70SMartin Mares   klist = NULL;
9717ec7e70SMartin Mares   return NULL;
9817ec7e70SMartin Mares }
9917ec7e70SMartin Mares 
10017ec7e70SMartin Mares #else
10117ec7e70SMartin Mares 
102c7a34993SMartin Mares struct pcimap_entry {
103c7a34993SMartin Mares   struct pcimap_entry *next;
104c7a34993SMartin Mares   unsigned int vendor, device;
105c7a34993SMartin Mares   unsigned int subvendor, subdevice;
106c7a34993SMartin Mares   unsigned int class, class_mask;
107c7a34993SMartin Mares   char module[1];
108c7a34993SMartin Mares };
109c7a34993SMartin Mares 
110c7a34993SMartin Mares static struct pcimap_entry *pcimap_head;
111c7a34993SMartin Mares 
11217ec7e70SMartin Mares static int
show_kernel_init(void)11317ec7e70SMartin Mares show_kernel_init(void)
114c7a34993SMartin Mares {
115c7a34993SMartin Mares   static int tried_pcimap;
116c7a34993SMartin Mares   struct utsname uts;
117c7a34993SMartin Mares   char *name, line[1024];
118c7a34993SMartin Mares   FILE *f;
119c7a34993SMartin Mares 
120c7a34993SMartin Mares   if (tried_pcimap)
12117ec7e70SMartin Mares     return 1;
122c7a34993SMartin Mares   tried_pcimap = 1;
123c7a34993SMartin Mares 
124c7a34993SMartin Mares   if (name = opt_pcimap)
125c7a34993SMartin Mares     {
126c7a34993SMartin Mares       f = fopen(name, "r");
127c7a34993SMartin Mares       if (!f)
128c7a34993SMartin Mares 	die("Cannot open pcimap file %s: %m", name);
129c7a34993SMartin Mares     }
130c7a34993SMartin Mares   else
131c7a34993SMartin Mares     {
132c7a34993SMartin Mares       if (uname(&uts) < 0)
133c7a34993SMartin Mares 	die("uname() failed: %m");
134c7a34993SMartin Mares       name = alloca(64 + strlen(uts.release));
135c7a34993SMartin Mares       sprintf(name, "/lib/modules/%s/modules.pcimap", uts.release);
136c7a34993SMartin Mares       f = fopen(name, "r");
137c7a34993SMartin Mares       if (!f)
13817ec7e70SMartin Mares 	return 1;
139c7a34993SMartin Mares     }
140c7a34993SMartin Mares 
141c7a34993SMartin Mares   while (fgets(line, sizeof(line), f))
142c7a34993SMartin Mares     {
143c7a34993SMartin Mares       char *c = strchr(line, '\n');
144c7a34993SMartin Mares       struct pcimap_entry *e;
145c7a34993SMartin Mares 
146c7a34993SMartin Mares       if (!c)
147c7a34993SMartin Mares 	die("Unterminated or too long line in %s", name);
148c7a34993SMartin Mares       *c = 0;
149c7a34993SMartin Mares       if (!line[0] || line[0] == '#')
150c7a34993SMartin Mares 	continue;
151c7a34993SMartin Mares 
152c7a34993SMartin Mares       c = line;
153c7a34993SMartin Mares       while (*c && *c != ' ' && *c != '\t')
154c7a34993SMartin Mares 	c++;
155c7a34993SMartin Mares       if (!*c)
156c7a34993SMartin Mares 	continue;	/* FIXME: Emit warnings! */
157c7a34993SMartin Mares       *c++ = 0;
158c7a34993SMartin Mares 
159c7a34993SMartin Mares       e = xmalloc(sizeof(*e) + strlen(line));
160c7a34993SMartin Mares       if (sscanf(c, "%i%i%i%i%i%i",
161c7a34993SMartin Mares 		 &e->vendor, &e->device,
162c7a34993SMartin Mares 		 &e->subvendor, &e->subdevice,
163c7a34993SMartin Mares 		 &e->class, &e->class_mask) != 6)
164c7a34993SMartin Mares 	continue;
165c7a34993SMartin Mares       e->next = pcimap_head;
166c7a34993SMartin Mares       pcimap_head = e;
167c7a34993SMartin Mares       strcpy(e->module, line);
168c7a34993SMartin Mares     }
169c7a34993SMartin Mares   fclose(f);
17017ec7e70SMartin Mares 
17117ec7e70SMartin Mares   return 1;
172c7a34993SMartin Mares }
173c7a34993SMartin Mares 
174c7a34993SMartin Mares static int
match_pcimap(struct device * d,struct pcimap_entry * e)175c7a34993SMartin Mares match_pcimap(struct device *d, struct pcimap_entry *e)
176c7a34993SMartin Mares {
177c7a34993SMartin Mares   struct pci_dev *dev = d->dev;
178fb570ee3SPali Rohár   unsigned int class = (((unsigned int)dev->device_class << 8) | dev->prog_if);
179c7a34993SMartin Mares 
180c7a34993SMartin Mares #define MATCH(x, y) ((y) > 0xffff || (x) == (y))
181c7a34993SMartin Mares   return
182c7a34993SMartin Mares     MATCH(dev->vendor_id, e->vendor) &&
183c7a34993SMartin Mares     MATCH(dev->device_id, e->device) &&
184fb570ee3SPali Rohár     MATCH(dev->subsys_vendor_id, e->subvendor) &&
185fb570ee3SPali Rohár     MATCH(dev->subsys_id, e->subdevice) &&
186c7a34993SMartin Mares     (class & e->class_mask) == e->class;
187c7a34993SMartin Mares #undef MATCH
188c7a34993SMartin Mares }
189c7a34993SMartin Mares 
next_module(struct device * d)19017ec7e70SMartin Mares static const char *next_module(struct device *d)
19117ec7e70SMartin Mares {
192b069b79aSMartin Mares   static struct pcimap_entry *current;
19317ec7e70SMartin Mares 
19417ec7e70SMartin Mares   if (!current)
19517ec7e70SMartin Mares     current = pcimap_head;
19617ec7e70SMartin Mares   else
19717ec7e70SMartin Mares     current = current->next;
19817ec7e70SMartin Mares 
19917ec7e70SMartin Mares   while (current)
20017ec7e70SMartin Mares     {
201b069b79aSMartin Mares       if (match_pcimap(d, current))
20217ec7e70SMartin Mares 	return current->module;
20317ec7e70SMartin Mares       current = current->next;
20417ec7e70SMartin Mares     }
20517ec7e70SMartin Mares 
20617ec7e70SMartin Mares   return NULL;
20717ec7e70SMartin Mares }
20817ec7e70SMartin Mares 
20917ec7e70SMartin Mares void
show_kernel_cleanup(void)21017ec7e70SMartin Mares show_kernel_cleanup(void)
21117ec7e70SMartin Mares {
21217ec7e70SMartin Mares }
21317ec7e70SMartin Mares 
21417ec7e70SMartin Mares #endif
21517ec7e70SMartin Mares 
216b069b79aSMartin Mares static const char *
next_module_filtered(struct device * d)217b069b79aSMartin Mares next_module_filtered(struct device *d)
218b069b79aSMartin Mares {
219b069b79aSMartin Mares   static char prev_module[256];
220b069b79aSMartin Mares   const char *module;
221b069b79aSMartin Mares 
222b069b79aSMartin Mares   while (module = next_module(d))
223b069b79aSMartin Mares     {
224b069b79aSMartin Mares       if (strcmp(module, prev_module))
225b069b79aSMartin Mares 	{
226b069b79aSMartin Mares 	  strncpy(prev_module, module, sizeof(prev_module));
227b069b79aSMartin Mares 	  prev_module[sizeof(prev_module) - 1] = 0;
228b069b79aSMartin Mares 	  return module;
229b069b79aSMartin Mares 	}
230b069b79aSMartin Mares     }
231b069b79aSMartin Mares   prev_module[0] = 0;
232b069b79aSMartin Mares   return NULL;
233b069b79aSMartin Mares }
234b069b79aSMartin Mares 
235c7a34993SMartin Mares void
show_kernel(struct device * d)236c7a34993SMartin Mares show_kernel(struct device *d)
237c7a34993SMartin Mares {
23817ec7e70SMartin Mares   const char *driver, *module;
239c7a34993SMartin Mares 
240d994587fSPali Rohár   pci_fill_info(d->dev, PCI_FILL_DRIVER);
241d994587fSPali Rohár   if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER))
242c7a34993SMartin Mares     printf("\tKernel driver in use: %s\n", driver);
243c7a34993SMartin Mares 
24417ec7e70SMartin Mares   if (!show_kernel_init())
24517ec7e70SMartin Mares     return;
24617ec7e70SMartin Mares 
24717ec7e70SMartin Mares   int cnt = 0;
248b069b79aSMartin Mares   while (module = next_module_filtered(d))
24917ec7e70SMartin Mares     printf("%s %s", (cnt++ ? "," : "\tKernel modules:"), module);
25017ec7e70SMartin Mares   if (cnt)
251c7a34993SMartin Mares     putchar('\n');
252c7a34993SMartin Mares }
253c7a34993SMartin Mares 
254c7a34993SMartin Mares void
show_kernel_machine(struct device * d)255c7a34993SMartin Mares show_kernel_machine(struct device *d)
256c7a34993SMartin Mares {
25717ec7e70SMartin Mares   const char *driver, *module;
258c7a34993SMartin Mares 
259d994587fSPali Rohár   pci_fill_info(d->dev, PCI_FILL_DRIVER);
260d994587fSPali Rohár   if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER))
261c7a34993SMartin Mares     printf("Driver:\t%s\n", driver);
262c7a34993SMartin Mares 
26317ec7e70SMartin Mares   if (!show_kernel_init())
26417ec7e70SMartin Mares     return;
26517ec7e70SMartin Mares 
266b069b79aSMartin Mares   while (module = next_module_filtered(d))
26717ec7e70SMartin Mares     printf("Module:\t%s\n", module);
268c7a34993SMartin Mares }
269c7a34993SMartin Mares 
270c7a34993SMartin Mares #else
271c7a34993SMartin Mares 
272c7a34993SMartin Mares void
show_kernel(struct device * d)273d994587fSPali Rohár show_kernel(struct device *d)
274c7a34993SMartin Mares {
275d994587fSPali Rohár   const char *driver;
276d994587fSPali Rohár 
277d994587fSPali Rohár   pci_fill_info(d->dev, PCI_FILL_DRIVER);
278d994587fSPali Rohár   if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER))
279d994587fSPali Rohár     printf("\tDriver in use: %s\n", driver);
280c7a34993SMartin Mares }
281c7a34993SMartin Mares 
282c7a34993SMartin Mares void
show_kernel_machine(struct device * d)283d994587fSPali Rohár show_kernel_machine(struct device *d)
284c7a34993SMartin Mares {
285d994587fSPali Rohár   const char *driver;
286d994587fSPali Rohár 
287d994587fSPali Rohár   pci_fill_info(d->dev, PCI_FILL_DRIVER);
288d994587fSPali Rohár   if (driver = pci_get_string_property(d->dev, PCI_FILL_DRIVER))
289d994587fSPali Rohár     printf("Driver:\t%s\n", driver);
290c7a34993SMartin Mares }
291c7a34993SMartin Mares 
29217ec7e70SMartin Mares void
show_kernel_cleanup(void)29317ec7e70SMartin Mares show_kernel_cleanup(void)
29417ec7e70SMartin Mares {
29517ec7e70SMartin Mares }
29617ec7e70SMartin Mares 
297c7a34993SMartin Mares #endif
298c7a34993SMartin Mares 
299