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

Contents of /ldetect/trunk/usb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7094 - (show annotations) (download)
Mon Jan 14 20:27:04 2013 UTC (11 years, 3 months ago) by tv
File MIME type: text/plain
File size: 4733 byte(s)
add spacing
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include "libldetect.h"
7 #include "common.h"
8 #include "names.h"
9
10 static char *proc_usb_path_default = "/sys/kernel/debug/usb/devices";
11 char *proc_usb_path = NULL;
12
13 static void build_text(struct pciusb_entry *e, char *vendor_text, char *product_text) {
14 if(e) {
15 if(!vendor_text) {
16 char const* vendorname;
17 vendorname = names_vendor(e->vendor);
18 if(vendorname) {
19 vendor_text = malloc(strlen(vendorname)+2);
20 sprintf(vendor_text, "%s|", vendorname);
21 } else
22 vendor_text = strdup("Unknown|");
23 }
24 if(!product_text) {
25 char const* productname;
26 productname = names_product(e->vendor, e->device);
27 if(productname) {
28 product_text = strdup(productname);
29 } else
30 product_text = strdup("Unknown");
31 }
32 vendor_text = realloc(vendor_text, strlen(vendor_text)+strlen(product_text)+1);
33 e->text = vendor_text;
34 strcat(e->text, product_text);
35 free(product_text);
36 }
37 }
38
39
40 extern struct pciusb_entries usb_probe(void) {
41 FILE *f;
42 char buf[BUF_SIZE];
43 int line;
44 struct pciusb_entries r;
45 struct pciusb_entry *e = NULL;
46 char *vendor_text = NULL, *product_text = NULL;
47 size_t allocated = MAX_DEVICES;
48 r.nb = 0;
49
50 names_init("/usr/share/usb.ids");
51 if (!(f = fopen(proc_usb_path ? proc_usb_path : proc_usb_path_default, "r"))) {
52 if (proc_usb_path) {
53 char *err_msg;
54 asprintf(&err_msg, "unable to open \"%s\"\n"
55 "You may have passed a wrong argument to the \"-u\" option.\n"
56 "fopen() sets errno to", proc_usb_path);
57 perror(err_msg);
58 free(err_msg);
59 }
60 r.entries = NULL;
61 goto exit;
62 }
63
64 r.entries = malloc(sizeof(struct pciusb_entry) * MAX_DEVICES);
65 /* for further information on the format parsed by this state machine,
66 * read /usr/share/doc/kernel-doc-X.Y.Z/usb/proc_usb_info.txt */
67 for (line = 1; fgets(buf, sizeof(buf) - 1, f); line++) {
68 if (r.nb >= allocated) {
69 allocated = r.nb*2;
70 r.entries = realloc(r.entries, sizeof(struct pciusb_entry) * allocated);
71 }
72
73 switch (buf[0]) {
74 case 'T': {
75 unsigned short pci_bus, pci_device, usb_port;
76 build_text(e, vendor_text, product_text);
77 vendor_text = NULL;
78 product_text = NULL;
79 e = &r.entries[r.nb++];
80 pciusb_initialize(e);
81
82 if (sscanf(buf, "T: Bus=%02hd Lev=%*02d Prnt=%*04d Port=%02hd Cnt=%*02d Dev#=%3hd Spd=%*3s MxCh=%*2d", &pci_bus, &usb_port, &pci_device) == 3) {
83 e->pci_bus = pci_bus;
84 e->pci_device = pci_device;
85 e->usb_port = usb_port;
86 } else fprintf(stderr, "%s %d: unknown ``T'' line\n", proc_usb_path, line);
87 break;
88 }
89 case 'P': {
90 unsigned short vendor, device;
91 if (sscanf(buf, "P: Vendor=%hx ProdID=%hx", &vendor, &device) == 2) {
92 e->vendor = vendor;
93 e->device = device;
94 } else fprintf(stderr, "%s %d: unknown ``P'' line\n", proc_usb_path, line);
95 break;
96 }
97 case 'I': if (e->class_id == 0 || e->module == NULL) {
98 char driver[50];
99 int class_id, sub, prot = 0;
100 if (sscanf(buf, "I:* If#=%*2d Alt=%*2d #EPs=%*2d Cls=%02x(%*5c) Sub=%02x Prot=%02x Driver=%s", &class_id, &sub, &prot, driver) >= 3) {
101 unsigned long cid = (class_id * 0x100 + sub) * 0x100 + prot;
102 if (e->class_id == 0)
103 e->class_id = cid;
104 if (strncmp(driver, "(none)", 6)) {
105 char *p;
106 /* Get current class if we are on the first one having used by a driver */
107 e->class_id = cid;
108 e->module = strdup(driver);
109 /* replace '-' characters with '_' to be compliant with modnames from modaliases */
110 p = e->module;
111 while (p && *p) {
112 if (*p == '-') *p = '_';
113 p++;
114 }
115 }
116 /* see linux/sound/usb/usbaudio.c::usb_audio_ids */
117 if (e->class_id == (0x1*0x100+ 0x01)) /* USB_AUDIO_CLASS*0x100 + USB_SUBCLASS_AUDIO_CONTROL*/
118 e->module = strdup("snd_usb_audio");
119
120 } else if (sscanf(buf, "I: If#=%*2d Alt=%*2d #EPs=%*2d Cls=%02x(%*5c) Sub=%02x Prot=%02x Driver=%s", &class_id, &sub, &prot, driver) >= 3) {
121 /* Ignore interfaces not active */
122 } else fprintf(stderr, "%s %d: unknown ``I'' line\n", proc_usb_path, line);
123 break;
124 }
125 case 'S': {
126 int offset;
127 char dummy;
128 size_t length = strlen(buf) -1;
129 if (sscanf(buf, "S: Manufacturer=%n%c", &offset, &dummy) == 1) {
130 buf[length] = '|'; /* replacing '\n' by '|' */
131 vendor_text = strdup(buf + offset);
132 } else if (sscanf(buf, "S: Product=%n%c", &offset, &dummy) == 1) {
133 buf[length] = 0; /* removing '\n' */
134 product_text = strdup(buf + offset);
135 }
136 }
137 }
138 }
139
140 build_text(e, vendor_text, product_text);
141
142 fclose(f);
143
144 /* shrink to real size */
145 r.entries = realloc(r.entries, sizeof(struct pciusb_entry) * r.nb);
146
147 pciusb_find_modules(&r, "usbtable", DO_NOT_LOAD, 0);
148
149 exit:
150 names_exit();
151 return r;
152 }
153

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.30