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

Contents of /ldetect/trunk/pciusb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1357 - (show annotations) (download)
Tue May 17 09:21:22 2011 UTC (12 years, 10 months ago) by dmorgan
File MIME type: text/plain
File size: 5487 byte(s)
Import  ldetect
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 <modprobe.h>
12 #include <dirent.h>
13 #include "common.h"
14
15 static void set_modules_from_modalias_file(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(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 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(e, modalias_path);
46 free(modalias_path);
47 }
48
49 static void find_usb_modules_through_aliases(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(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(const char *bus, struct pciusb_entry *e) {
82 if (!strcmp("pci", bus)) {
83 find_pci_modules_through_aliases(e);
84 } else if (!strcmp("usb", bus)) {
85 find_usb_modules_through_aliases(e);
86 }
87 }
88
89 static void find_modules_through_aliases(const char *bus, struct pciusb_entries *entries) {
90 unsigned int i;
91 for (i = 0; i < entries->nb; i++) {
92 struct pciusb_entry *e = &entries->entries[i];
93
94 // No special case found in pcitable ? Then lookup modalias for PCI devices
95 if (e->module && strcmp(e->module, "unknown"))
96 continue;
97 find_modules_through_aliases_one(bus, e);
98 }
99
100 modalias_cleanup();
101 }
102
103 extern int pciusb_find_modules(struct pciusb_entries *entries, const char *fpciusbtable, const descr_lookup descr_lookup, int is_pci) {
104 fh f;
105 char buf[2048];
106 int line;
107
108 f = fh_open(fpciusbtable);
109
110 for (line = 1; fh_gets(buf, sizeof(buf) - 1, &f); line++) {
111 unsigned short vendor, device, subvendor, subdevice;
112 char *p = NULL, *q = NULL;
113 int offset; unsigned int i;
114 int nb;
115 if (buf[0]=='#')
116 continue; // skip comments
117
118 nb = sscanf(buf, "0x%hx\t0x%hx\t0x%hx\t0x%hx\t%n", &vendor, &device, &subvendor, &subdevice, &offset);
119 if (nb != 4) {
120 nb = sscanf(buf, "0x%hx\t0x%hx\t%n", &vendor, &device, &offset);
121 if (nb != 2) {
122 fprintf(stderr, "%s %d: bad line\n", fpciusbtable, line);
123 continue; // skip bad line
124 }
125 }
126 for (i = 0; i < entries->nb; i++) {
127 struct pciusb_entry *e = &entries->entries[i];
128 if (e->already_found)
129 continue; // skip since already found with sub ids
130 if (vendor != e->vendor || device != e->device)
131 continue; // main ids differ
132
133 if (nb == 4 && !(subvendor == e->subvendor && subdevice == e->subdevice))
134 continue; // subids differ
135
136 if (!p) { // only calc text & module if not already done
137 p = buf + offset + 1;
138 q = strchr(p, '\t');
139 if (!q) // no description field?
140 q = strchr(p, '\0') - 1;
141 }
142 if (strncmp(p, "unknown", q-p-1)) {
143 ifree(e->module);
144 e->module = strndup(p,q-p-1);
145 }
146 /* special case for buggy 0x0 usb entry */
147 if (descr_lookup == LOAD && strlen(q) > 1 && 2 < strlen(q+2) && vendor != 0 && device != 0 && e->class_id != 0x90000d) { /* Hub class */
148 ifree(e->text); /* usb.c set it so that we display something when usbtable doesn't refer that hw*/
149 e->text = strndup(q+2, strlen(q)-4);
150 }
151 /* if subids read on pcitable line, we know that subids matches :
152 (see "subids differ" test above) */
153 if (nb == 4)
154 e->already_found = 1;
155 }
156 }
157 fh_close(&f);
158
159 /* If no special case in pcitable, then lookup modalias for devices */
160 const char *bus = is_pci ? "pci" : "usb";
161 find_modules_through_aliases(bus, entries);
162
163 return 1;
164 }
165
166 extern void pciusb_initialize(struct pciusb_entry *e) {
167 e->vendor = 0xffff;
168 e->device = 0xffff;
169 e->subvendor = 0xffff;
170 e->subdevice = 0xffff;
171 e->class_id = 0;
172 e->pci_bus = 0xff;
173 e->pci_device = 0xff;
174 e->pci_function = 0xff;
175 e->pci_revision = 0;
176 e->usb_port = 0xffff;
177 e->module = NULL;
178 e->text = NULL;
179 e->class = NULL;
180 e->already_found = 0;
181 e->is_pciexpress = 0;
182 }
183
184 extern void pciusb_free(struct pciusb_entries *entries) {
185 unsigned int i;
186 for (i = 0; i < entries->nb; i++) {
187 struct pciusb_entry *e = &entries->entries[i];
188 ifree(e->module);
189 ifree(e->text);
190 }
191 if (entries->nb) ifree(entries->entries);
192 }

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.30