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