/[soft]/ldetect/trunk/pciusb.c
ViewVC logotype

Contents of /ldetect/trunk/pciusb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5820 - (show annotations) (download)
Wed Sep 12 10:37:40 2012 UTC (11 years, 7 months ago) by tv
File MIME type: text/plain
File size: 5667 byte(s)
make ldetect 3x faster (and even faster on machines quite quite a lot
of devices such as servers)

(modalias_init) split it out of modalias_resolve_module()

(modalias_cleanup) move libkmod related cleanups here

(hid_probe,find_modules_through_aliases) only initialize libkmod once
(which reduces user time from 0.26 to 0.08s & elapsed time from 0.28 to
0.9s)
1 #define _GNU_SOURCE
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <sys/wait.h>
5 #include <sys/utsname.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <dirent.h>
12 #include <libkmod.h>
13 #include "common.h"
14
15 static void set_modules_from_modalias_file(struct kmod_ctx *ctx, struct pciusb_entry *e, char *modalias_path) {
16 FILE *file;
17 file = fopen(modalias_path, "r");
18 if (file) {
19 char *modalias = NULL;
20 size_t n, size;
21 if (-1 == getline(&modalias, &n, file)) {
22 fprintf(stderr, "Unable to read modalias from %s\n", modalias_path);
23 fclose(file);
24 return;
25 }
26 fclose(file);
27 size = strlen(modalias);
28 if (size)
29 modalias[size-1] = 0;
30
31 ifree(e->module);
32 e->module = modalias_resolve_module(ctx, modalias);
33 free(modalias);
34 } else {
35 fprintf(stderr, "Unable to read modalias from %s\n", modalias_path);
36 return;
37 }
38 }
39
40 static void find_pci_modules_through_aliases(struct kmod_ctx *ctx, struct pciusb_entry *e) {
41 char *modalias_path;
42 asprintf(&modalias_path,
43 "/sys/bus/pci/devices/%04x:%02x:%02x.%x/modalias",
44 e->pci_domain, e->pci_bus, e->pci_device, e->pci_function);
45 set_modules_from_modalias_file(ctx, e, modalias_path);
46 free(modalias_path);
47 }
48
49 static void find_usb_modules_through_aliases(struct kmod_ctx *ctx, struct pciusb_entry *e) {
50 char *usb_prefix, *sysfs_path;
51 DIR *dir;
52 struct dirent *dent;
53
54 asprintf(&usb_prefix, "%d-", e->pci_bus);
55 /* USB port is indexed from 0 in procfs, from 1 in sysfs */
56 asprintf(&sysfs_path, "/sys/bus/usb/devices/%d-%d", e->pci_bus, e->usb_port + 1);
57
58 dir = opendir(sysfs_path);
59 if (!dir) {
60 goto end;
61 }
62 while ((dent = readdir(dir)) != NULL) {
63 if ((dent->d_type == DT_DIR) &&
64 !strncmp(usb_prefix, dent->d_name, strlen(usb_prefix))) {
65 char *modalias_path;
66 asprintf(&modalias_path, "%s/%s/modalias", sysfs_path, dent->d_name);
67 set_modules_from_modalias_file(ctx, e, modalias_path);
68 free(modalias_path);
69 /* maybe we would need a "other_modules" field in pciusb_entry
70 to list modules from all USB interfaces */
71 if (e->module)
72 break;
73 }
74 }
75 closedir(dir);
76 end:
77 free(sysfs_path);
78 free(usb_prefix);
79 }
80
81 static void find_modules_through_aliases_one(struct kmod_ctx *ctx, const char *bus, struct pciusb_entry *e) {
82 if (!strcmp("pci", bus)) {
83 find_pci_modules_through_aliases(ctx, e);
84 } else if (!strcmp("usb", bus)) {
85 find_usb_modules_through_aliases(ctx, e);
86 }
87 }
88
89 static void find_modules_through_aliases(const char *bus, struct pciusb_entries *entries) {
90 unsigned int i;
91 struct kmod_ctx *ctx = modalias_init();
92 for (i = 0; i < entries->nb; i++) {
93 struct pciusb_entry *e = &entries->entries[i];
94
95 // No special case found in pcitable ? Then lookup modalias for PCI devices
96 if (e->module && strcmp(e->module, "unknown"))
97 continue;
98 find_modules_through_aliases_one(ctx, bus, e);
99 }
100
101 modalias_cleanup(ctx);
102 }
103
104 extern int pciusb_find_modules(struct pciusb_entries *entries, const char *fpciusbtable, const descr_lookup descr_lookup, int is_pci) {
105 fh f;
106 char buf[2048];
107 int line;
108
109 f = fh_open(fpciusbtable);
110
111 for (line = 1; fh_gets(buf, sizeof(buf) - 1, &f); line++) {
112 unsigned short vendor, device, subvendor, subdevice;
113 char *p = NULL, *q = NULL;
114 int offset; unsigned int i;
115 int nb;
116 if (buf[0]=='#')
117 continue; // skip comments
118
119 nb = sscanf(buf, "0x%hx\t0x%hx\t0x%hx\t0x%hx\t%n", &vendor, &device, &subvendor, &subdevice, &offset);
120 if (nb != 4) {
121 nb = sscanf(buf, "0x%hx\t0x%hx\t%n", &vendor, &device, &offset);
122 if (nb != 2) {
123 fprintf(stderr, "%s %d: bad line\n", fpciusbtable, line);
124 continue; // skip bad line
125 }
126 }
127 for (i = 0; i < entries->nb; i++) {
128 struct pciusb_entry *e = &entries->entries[i];
129 if (e->already_found)
130 continue; // skip since already found with sub ids
131 if (vendor != e->vendor || device != e->device)
132 continue; // main ids differ
133
134 if (nb == 4 && !(subvendor == e->subvendor && subdevice == e->subdevice))
135 continue; // subids differ
136
137 if (!p) { // only calc text & module if not already done
138 p = buf + offset + 1;
139 q = strchr(p, '\t');
140 if (!q) // no description field?
141 q = strchr(p, '\0') - 1;
142 }
143 if (strncmp(p, "unknown", q-p-1)) {
144 ifree(e->module);
145 e->module = strndup(p,q-p-1);
146 }
147 /* special case for buggy 0x0 usb entry */
148 if (descr_lookup == LOAD && strlen(q) > 1 && 2 < strlen(q+2) && vendor != 0 && device != 0 && e->class_id != 0x90000d) { /* Hub class */
149 ifree(e->text); /* usb.c set it so that we display something when usbtable doesn't refer that hw*/
150 e->text = strndup(q+2, strlen(q)-4);
151 }
152 /* if subids read on pcitable line, we know that subids matches :
153 (see "subids differ" test above) */
154 if (nb == 4)
155 e->already_found = 1;
156 }
157 }
158 fh_close(&f);
159
160 /* If no special case in pcitable, then lookup modalias for devices */
161 const char *bus = is_pci ? "pci" : "usb";
162 find_modules_through_aliases(bus, entries);
163
164 return 1;
165 }
166
167 extern void pciusb_initialize(struct pciusb_entry *e) {
168 e->vendor = 0xffff;
169 e->device = 0xffff;
170 e->subvendor = 0xffff;
171 e->subdevice = 0xffff;
172 e->class_id = 0;
173 e->pci_bus = 0xff;
174 e->pci_device = 0xff;
175 e->pci_function = 0xff;
176 e->pci_revision = 0;
177 e->usb_port = 0xffff;
178 e->module = NULL;
179 e->text = NULL;
180 e->class = NULL;
181 e->already_found = 0;
182 e->is_pciexpress = 0;
183 }
184
185 extern void pciusb_free(struct pciusb_entries *entries) {
186 unsigned int i;
187 for (i = 0; i < entries->nb; i++) {
188 struct pciusb_entry *e = &entries->entries[i];
189 ifree(e->module);
190 ifree(e->text);
191 ifree(e->class);
192 }
193 if (entries->nb) ifree(entries->entries);
194 }

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.30