diff options
Diffstat (limited to 'tools/usb/usbip/libsrc')
-rw-r--r-- | tools/usb/usbip/libsrc/Makefile.am | 8 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/list.h | 136 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/names.c | 504 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/names.h | 41 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/sysfs_utils.c | 31 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/sysfs_utils.h | 8 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/usbip_common.c | 285 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/usbip_common.h | 137 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/usbip_host_driver.c | 280 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/usbip_host_driver.h | 49 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/vhci_driver.c | 411 | ||||
-rw-r--r-- | tools/usb/usbip/libsrc/vhci_driver.h | 59 |
12 files changed, 1949 insertions, 0 deletions
diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am new file mode 100644 index 000000000000..7c8f8a4d54e4 --- /dev/null +++ b/tools/usb/usbip/libsrc/Makefile.am | |||
@@ -0,0 +1,8 @@ | |||
1 | libusbip_la_CPPFLAGS = -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' | ||
2 | libusbip_la_CFLAGS = @EXTRA_CFLAGS@ | ||
3 | libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@ | ||
4 | |||
5 | lib_LTLIBRARIES := libusbip.la | ||
6 | libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ | ||
7 | usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \ | ||
8 | sysfs_utils.c sysfs_utils.h | ||
diff --git a/tools/usb/usbip/libsrc/list.h b/tools/usb/usbip/libsrc/list.h new file mode 100644 index 000000000000..8d0c936e184f --- /dev/null +++ b/tools/usb/usbip/libsrc/list.h | |||
@@ -0,0 +1,136 @@ | |||
1 | #ifndef _LIST_H | ||
2 | #define _LIST_H | ||
3 | |||
4 | /* Stripped down implementation of linked list taken | ||
5 | * from the Linux Kernel. | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Simple doubly linked list implementation. | ||
10 | * | ||
11 | * Some of the internal functions ("__xxx") are useful when | ||
12 | * manipulating whole lists rather than single entries, as | ||
13 | * sometimes we already know the next/prev entries and we can | ||
14 | * generate better code by using them directly rather than | ||
15 | * using the generic single-entry routines. | ||
16 | */ | ||
17 | |||
18 | struct list_head { | ||
19 | struct list_head *next, *prev; | ||
20 | }; | ||
21 | |||
22 | #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||
23 | |||
24 | #define LIST_HEAD(name) \ | ||
25 | struct list_head name = LIST_HEAD_INIT(name) | ||
26 | |||
27 | static inline void INIT_LIST_HEAD(struct list_head *list) | ||
28 | { | ||
29 | list->next = list; | ||
30 | list->prev = list; | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Insert a new entry between two known consecutive entries. | ||
35 | * | ||
36 | * This is only for internal list manipulation where we know | ||
37 | * the prev/next entries already! | ||
38 | */ | ||
39 | static inline void __list_add(struct list_head *new, | ||
40 | struct list_head *prev, | ||
41 | struct list_head *next) | ||
42 | { | ||
43 | next->prev = new; | ||
44 | new->next = next; | ||
45 | new->prev = prev; | ||
46 | prev->next = new; | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * list_add - add a new entry | ||
51 | * @new: new entry to be added | ||
52 | * @head: list head to add it after | ||
53 | * | ||
54 | * Insert a new entry after the specified head. | ||
55 | * This is good for implementing stacks. | ||
56 | */ | ||
57 | static inline void list_add(struct list_head *new, struct list_head *head) | ||
58 | { | ||
59 | __list_add(new, head, head->next); | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Delete a list entry by making the prev/next entries | ||
64 | * point to each other. | ||
65 | * | ||
66 | * This is only for internal list manipulation where we know | ||
67 | * the prev/next entries already! | ||
68 | */ | ||
69 | static inline void __list_del(struct list_head * prev, struct list_head * next) | ||
70 | { | ||
71 | next->prev = prev; | ||
72 | prev->next = next; | ||
73 | } | ||
74 | |||
75 | #define POISON_POINTER_DELTA 0 | ||
76 | #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) | ||
77 | #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) | ||
78 | |||
79 | /** | ||
80 | * list_del - deletes entry from list. | ||
81 | * @entry: the element to delete from the list. | ||
82 | * Note: list_empty() on entry does not return true after this, the entry is | ||
83 | * in an undefined state. | ||
84 | */ | ||
85 | static inline void __list_del_entry(struct list_head *entry) | ||
86 | { | ||
87 | __list_del(entry->prev, entry->next); | ||
88 | } | ||
89 | |||
90 | static inline void list_del(struct list_head *entry) | ||
91 | { | ||
92 | __list_del(entry->prev, entry->next); | ||
93 | entry->next = LIST_POISON1; | ||
94 | entry->prev = LIST_POISON2; | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * list_entry - get the struct for this entry | ||
99 | * @ptr: the &struct list_head pointer. | ||
100 | * @type: the type of the struct this is embedded in. | ||
101 | * @member: the name of the list_struct within the struct. | ||
102 | */ | ||
103 | #define list_entry(ptr, type, member) \ | ||
104 | container_of(ptr, type, member) | ||
105 | /** | ||
106 | * list_for_each - iterate over a list | ||
107 | * @pos: the &struct list_head to use as a loop cursor. | ||
108 | * @head: the head for your list. | ||
109 | */ | ||
110 | #define list_for_each(pos, head) \ | ||
111 | for (pos = (head)->next; pos != (head); pos = pos->next) | ||
112 | |||
113 | /** | ||
114 | * list_for_each_safe - iterate over a list safe against removal of list entry | ||
115 | * @pos: the &struct list_head to use as a loop cursor. | ||
116 | * @n: another &struct list_head to use as temporary storage | ||
117 | * @head: the head for your list. | ||
118 | */ | ||
119 | #define list_for_each_safe(pos, n, head) \ | ||
120 | for (pos = (head)->next, n = pos->next; pos != (head); \ | ||
121 | pos = n, n = pos->next) | ||
122 | |||
123 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) | ||
124 | |||
125 | /** | ||
126 | * container_of - cast a member of a structure out to the containing structure | ||
127 | * @ptr: the pointer to the member. | ||
128 | * @type: the type of the container struct this is embedded in. | ||
129 | * @member: the name of the member within the struct. | ||
130 | * | ||
131 | */ | ||
132 | #define container_of(ptr, type, member) ({ \ | ||
133 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
134 | (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
135 | |||
136 | #endif | ||
diff --git a/tools/usb/usbip/libsrc/names.c b/tools/usb/usbip/libsrc/names.c new file mode 100644 index 000000000000..81ff8522405c --- /dev/null +++ b/tools/usb/usbip/libsrc/names.c | |||
@@ -0,0 +1,504 @@ | |||
1 | /* | ||
2 | * names.c -- USB name database manipulation routines | ||
3 | * | ||
4 | * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | * | ||
21 | * | ||
22 | * | ||
23 | * | ||
24 | * Copyright (C) 2005 Takahiro Hirofuchi | ||
25 | * - names_deinit() is added. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <sys/types.h> | ||
30 | #include <sys/stat.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <dirent.h> | ||
33 | #include <string.h> | ||
34 | #include <errno.h> | ||
35 | #include <stdlib.h> | ||
36 | #include <unistd.h> | ||
37 | #include <stdio.h> | ||
38 | #include <ctype.h> | ||
39 | |||
40 | #include "names.h" | ||
41 | #include "usbip_common.h" | ||
42 | |||
43 | struct vendor { | ||
44 | struct vendor *next; | ||
45 | u_int16_t vendorid; | ||
46 | char name[1]; | ||
47 | }; | ||
48 | |||
49 | struct product { | ||
50 | struct product *next; | ||
51 | u_int16_t vendorid, productid; | ||
52 | char name[1]; | ||
53 | }; | ||
54 | |||
55 | struct class { | ||
56 | struct class *next; | ||
57 | u_int8_t classid; | ||
58 | char name[1]; | ||
59 | }; | ||
60 | |||
61 | struct subclass { | ||
62 | struct subclass *next; | ||
63 | u_int8_t classid, subclassid; | ||
64 | char name[1]; | ||
65 | }; | ||
66 | |||
67 | struct protocol { | ||
68 | struct protocol *next; | ||
69 | u_int8_t classid, subclassid, protocolid; | ||
70 | char name[1]; | ||
71 | }; | ||
72 | |||
73 | struct genericstrtable { | ||
74 | struct genericstrtable *next; | ||
75 | unsigned int num; | ||
76 | char name[1]; | ||
77 | }; | ||
78 | |||
79 | |||
80 | #define HASH1 0x10 | ||
81 | #define HASH2 0x02 | ||
82 | #define HASHSZ 16 | ||
83 | |||
84 | static unsigned int hashnum(unsigned int num) | ||
85 | { | ||
86 | unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27; | ||
87 | |||
88 | for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1) | ||
89 | if (num & mask1) | ||
90 | num ^= mask2; | ||
91 | return num & (HASHSZ-1); | ||
92 | } | ||
93 | |||
94 | |||
95 | static struct vendor *vendors[HASHSZ] = { NULL, }; | ||
96 | static struct product *products[HASHSZ] = { NULL, }; | ||
97 | static struct class *classes[HASHSZ] = { NULL, }; | ||
98 | static struct subclass *subclasses[HASHSZ] = { NULL, }; | ||
99 | static struct protocol *protocols[HASHSZ] = { NULL, }; | ||
100 | |||
101 | const char *names_vendor(u_int16_t vendorid) | ||
102 | { | ||
103 | struct vendor *v; | ||
104 | |||
105 | v = vendors[hashnum(vendorid)]; | ||
106 | for (; v; v = v->next) | ||
107 | if (v->vendorid == vendorid) | ||
108 | return v->name; | ||
109 | return NULL; | ||
110 | } | ||
111 | |||
112 | const char *names_product(u_int16_t vendorid, u_int16_t productid) | ||
113 | { | ||
114 | struct product *p; | ||
115 | |||
116 | p = products[hashnum((vendorid << 16) | productid)]; | ||
117 | for (; p; p = p->next) | ||
118 | if (p->vendorid == vendorid && p->productid == productid) | ||
119 | return p->name; | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | const char *names_class(u_int8_t classid) | ||
124 | { | ||
125 | struct class *c; | ||
126 | |||
127 | c = classes[hashnum(classid)]; | ||
128 | for (; c; c = c->next) | ||
129 | if (c->classid == classid) | ||
130 | return c->name; | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | const char *names_subclass(u_int8_t classid, u_int8_t subclassid) | ||
135 | { | ||
136 | struct subclass *s; | ||
137 | |||
138 | s = subclasses[hashnum((classid << 8) | subclassid)]; | ||
139 | for (; s; s = s->next) | ||
140 | if (s->classid == classid && s->subclassid == subclassid) | ||
141 | return s->name; | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | const char *names_protocol(u_int8_t classid, u_int8_t subclassid, | ||
146 | u_int8_t protocolid) | ||
147 | { | ||
148 | struct protocol *p; | ||
149 | |||
150 | p = protocols[hashnum((classid << 16) | (subclassid << 8) | ||
151 | | protocolid)]; | ||
152 | for (; p; p = p->next) | ||
153 | if (p->classid == classid && p->subclassid == subclassid && | ||
154 | p->protocolid == protocolid) | ||
155 | return p->name; | ||
156 | return NULL; | ||
157 | } | ||
158 | |||
159 | /* add a cleanup function by takahiro */ | ||
160 | struct pool { | ||
161 | struct pool *next; | ||
162 | void *mem; | ||
163 | }; | ||
164 | |||
165 | static struct pool *pool_head; | ||
166 | |||
167 | static void *my_malloc(size_t size) | ||
168 | { | ||
169 | struct pool *p; | ||
170 | |||
171 | p = calloc(1, sizeof(struct pool)); | ||
172 | if (!p) | ||
173 | return NULL; | ||
174 | |||
175 | p->mem = calloc(1, size); | ||
176 | if (!p->mem) { | ||
177 | free(p); | ||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | p->next = pool_head; | ||
182 | pool_head = p; | ||
183 | |||
184 | return p->mem; | ||
185 | } | ||
186 | |||
187 | void names_free(void) | ||
188 | { | ||
189 | struct pool *pool; | ||
190 | |||
191 | if (!pool_head) | ||
192 | return; | ||
193 | |||
194 | for (pool = pool_head; pool != NULL; ) { | ||
195 | struct pool *tmp; | ||
196 | |||
197 | if (pool->mem) | ||
198 | free(pool->mem); | ||
199 | |||
200 | tmp = pool; | ||
201 | pool = pool->next; | ||
202 | free(tmp); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | static int new_vendor(const char *name, u_int16_t vendorid) | ||
207 | { | ||
208 | struct vendor *v; | ||
209 | unsigned int h = hashnum(vendorid); | ||
210 | |||
211 | v = vendors[h]; | ||
212 | for (; v; v = v->next) | ||
213 | if (v->vendorid == vendorid) | ||
214 | return -1; | ||
215 | v = my_malloc(sizeof(struct vendor) + strlen(name)); | ||
216 | if (!v) | ||
217 | return -1; | ||
218 | strcpy(v->name, name); | ||
219 | v->vendorid = vendorid; | ||
220 | v->next = vendors[h]; | ||
221 | vendors[h] = v; | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int new_product(const char *name, u_int16_t vendorid, | ||
226 | u_int16_t productid) | ||
227 | { | ||
228 | struct product *p; | ||
229 | unsigned int h = hashnum((vendorid << 16) | productid); | ||
230 | |||
231 | p = products[h]; | ||
232 | for (; p; p = p->next) | ||
233 | if (p->vendorid == vendorid && p->productid == productid) | ||
234 | return -1; | ||
235 | p = my_malloc(sizeof(struct product) + strlen(name)); | ||
236 | if (!p) | ||
237 | return -1; | ||
238 | strcpy(p->name, name); | ||
239 | p->vendorid = vendorid; | ||
240 | p->productid = productid; | ||
241 | p->next = products[h]; | ||
242 | products[h] = p; | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int new_class(const char *name, u_int8_t classid) | ||
247 | { | ||
248 | struct class *c; | ||
249 | unsigned int h = hashnum(classid); | ||
250 | |||
251 | c = classes[h]; | ||
252 | for (; c; c = c->next) | ||
253 | if (c->classid == classid) | ||
254 | return -1; | ||
255 | c = my_malloc(sizeof(struct class) + strlen(name)); | ||
256 | if (!c) | ||
257 | return -1; | ||
258 | strcpy(c->name, name); | ||
259 | c->classid = classid; | ||
260 | c->next = classes[h]; | ||
261 | classes[h] = c; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid) | ||
266 | { | ||
267 | struct subclass *s; | ||
268 | unsigned int h = hashnum((classid << 8) | subclassid); | ||
269 | |||
270 | s = subclasses[h]; | ||
271 | for (; s; s = s->next) | ||
272 | if (s->classid == classid && s->subclassid == subclassid) | ||
273 | return -1; | ||
274 | s = my_malloc(sizeof(struct subclass) + strlen(name)); | ||
275 | if (!s) | ||
276 | return -1; | ||
277 | strcpy(s->name, name); | ||
278 | s->classid = classid; | ||
279 | s->subclassid = subclassid; | ||
280 | s->next = subclasses[h]; | ||
281 | subclasses[h] = s; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, | ||
286 | u_int8_t protocolid) | ||
287 | { | ||
288 | struct protocol *p; | ||
289 | unsigned int h = hashnum((classid << 16) | (subclassid << 8) | ||
290 | | protocolid); | ||
291 | |||
292 | p = protocols[h]; | ||
293 | for (; p; p = p->next) | ||
294 | if (p->classid == classid && p->subclassid == subclassid | ||
295 | && p->protocolid == protocolid) | ||
296 | return -1; | ||
297 | p = my_malloc(sizeof(struct protocol) + strlen(name)); | ||
298 | if (!p) | ||
299 | return -1; | ||
300 | strcpy(p->name, name); | ||
301 | p->classid = classid; | ||
302 | p->subclassid = subclassid; | ||
303 | p->protocolid = protocolid; | ||
304 | p->next = protocols[h]; | ||
305 | protocols[h] = p; | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void parse(FILE *f) | ||
310 | { | ||
311 | char buf[512], *cp; | ||
312 | unsigned int linectr = 0; | ||
313 | int lastvendor = -1; | ||
314 | int lastclass = -1; | ||
315 | int lastsubclass = -1; | ||
316 | int lasthut = -1; | ||
317 | int lastlang = -1; | ||
318 | unsigned int u; | ||
319 | |||
320 | while (fgets(buf, sizeof(buf), f)) { | ||
321 | linectr++; | ||
322 | /* remove line ends */ | ||
323 | cp = strchr(buf, '\r'); | ||
324 | if (cp) | ||
325 | *cp = 0; | ||
326 | cp = strchr(buf, '\n'); | ||
327 | if (cp) | ||
328 | *cp = 0; | ||
329 | if (buf[0] == '#' || !buf[0]) | ||
330 | continue; | ||
331 | cp = buf; | ||
332 | if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && | ||
333 | buf[3] == 'S' && buf[4] == 'D' && | ||
334 | buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ | ||
335 | buf[7] == ' ') { | ||
336 | continue; | ||
337 | } | ||
338 | if (buf[0] == 'P' && buf[1] == 'H' && | ||
339 | buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { | ||
340 | continue; | ||
341 | } | ||
342 | if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && | ||
343 | buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { | ||
344 | continue; | ||
345 | } | ||
346 | if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { | ||
347 | lasthut = lastclass = lastvendor = lastsubclass = -1; | ||
348 | /* | ||
349 | * set 1 as pseudo-id to indicate that the parser is | ||
350 | * in a `L' section. | ||
351 | */ | ||
352 | lastlang = 1; | ||
353 | continue; | ||
354 | } | ||
355 | if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { | ||
356 | /* class spec */ | ||
357 | cp = buf+2; | ||
358 | while (isspace(*cp)) | ||
359 | cp++; | ||
360 | if (!isxdigit(*cp)) { | ||
361 | err("Invalid class spec at line %u", linectr); | ||
362 | continue; | ||
363 | } | ||
364 | u = strtoul(cp, &cp, 16); | ||
365 | while (isspace(*cp)) | ||
366 | cp++; | ||
367 | if (!*cp) { | ||
368 | err("Invalid class spec at line %u", linectr); | ||
369 | continue; | ||
370 | } | ||
371 | if (new_class(cp, u)) | ||
372 | err("Duplicate class spec at line %u class %04x %s", | ||
373 | linectr, u, cp); | ||
374 | dbg("line %5u class %02x %s", linectr, u, cp); | ||
375 | lasthut = lastlang = lastvendor = lastsubclass = -1; | ||
376 | lastclass = u; | ||
377 | continue; | ||
378 | } | ||
379 | if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { | ||
380 | /* audio terminal type spec */ | ||
381 | continue; | ||
382 | } | ||
383 | if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' | ||
384 | && isspace(buf[3])) { | ||
385 | /* HID Descriptor bCountryCode */ | ||
386 | continue; | ||
387 | } | ||
388 | if (isxdigit(*cp)) { | ||
389 | /* vendor */ | ||
390 | u = strtoul(cp, &cp, 16); | ||
391 | while (isspace(*cp)) | ||
392 | cp++; | ||
393 | if (!*cp) { | ||
394 | err("Invalid vendor spec at line %u", linectr); | ||
395 | continue; | ||
396 | } | ||
397 | if (new_vendor(cp, u)) | ||
398 | err("Duplicate vendor spec at line %u vendor %04x %s", | ||
399 | linectr, u, cp); | ||
400 | dbg("line %5u vendor %04x %s", linectr, u, cp); | ||
401 | lastvendor = u; | ||
402 | lasthut = lastlang = lastclass = lastsubclass = -1; | ||
403 | continue; | ||
404 | } | ||
405 | if (buf[0] == '\t' && isxdigit(buf[1])) { | ||
406 | /* product or subclass spec */ | ||
407 | u = strtoul(buf+1, &cp, 16); | ||
408 | while (isspace(*cp)) | ||
409 | cp++; | ||
410 | if (!*cp) { | ||
411 | err("Invalid product/subclass spec at line %u", | ||
412 | linectr); | ||
413 | continue; | ||
414 | } | ||
415 | if (lastvendor != -1) { | ||
416 | if (new_product(cp, lastvendor, u)) | ||
417 | err("Duplicate product spec at line %u product %04x:%04x %s", | ||
418 | linectr, lastvendor, u, cp); | ||
419 | dbg("line %5u product %04x:%04x %s", linectr, | ||
420 | lastvendor, u, cp); | ||
421 | continue; | ||
422 | } | ||
423 | if (lastclass != -1) { | ||
424 | if (new_subclass(cp, lastclass, u)) | ||
425 | err("Duplicate subclass spec at line %u class %02x:%02x %s", | ||
426 | linectr, lastclass, u, cp); | ||
427 | dbg("line %5u subclass %02x:%02x %s", linectr, | ||
428 | lastclass, u, cp); | ||
429 | lastsubclass = u; | ||
430 | continue; | ||
431 | } | ||
432 | if (lasthut != -1) { | ||
433 | /* do not store hut */ | ||
434 | continue; | ||
435 | } | ||
436 | if (lastlang != -1) { | ||
437 | /* do not store langid */ | ||
438 | continue; | ||
439 | } | ||
440 | err("Product/Subclass spec without prior Vendor/Class spec at line %u", | ||
441 | linectr); | ||
442 | continue; | ||
443 | } | ||
444 | if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { | ||
445 | /* protocol spec */ | ||
446 | u = strtoul(buf+2, &cp, 16); | ||
447 | while (isspace(*cp)) | ||
448 | cp++; | ||
449 | if (!*cp) { | ||
450 | err("Invalid protocol spec at line %u", | ||
451 | linectr); | ||
452 | continue; | ||
453 | } | ||
454 | if (lastclass != -1 && lastsubclass != -1) { | ||
455 | if (new_protocol(cp, lastclass, lastsubclass, | ||
456 | u)) | ||
457 | err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s", | ||
458 | linectr, lastclass, lastsubclass, | ||
459 | u, cp); | ||
460 | dbg("line %5u protocol %02x:%02x:%02x %s", | ||
461 | linectr, lastclass, lastsubclass, u, cp); | ||
462 | continue; | ||
463 | } | ||
464 | err("Protocol spec without prior Class and Subclass spec at line %u", | ||
465 | linectr); | ||
466 | continue; | ||
467 | } | ||
468 | if (buf[0] == 'H' && buf[1] == 'I' && | ||
469 | buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { | ||
470 | continue; | ||
471 | } | ||
472 | if (buf[0] == 'H' && buf[1] == 'U' && | ||
473 | buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { | ||
474 | lastlang = lastclass = lastvendor = lastsubclass = -1; | ||
475 | /* | ||
476 | * set 1 as pseudo-id to indicate that the parser is | ||
477 | * in a `HUT' section. | ||
478 | */ | ||
479 | lasthut = 1; | ||
480 | continue; | ||
481 | } | ||
482 | if (buf[0] == 'R' && buf[1] == ' ') | ||
483 | continue; | ||
484 | |||
485 | if (buf[0] == 'V' && buf[1] == 'T') | ||
486 | continue; | ||
487 | |||
488 | err("Unknown line at line %u", linectr); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | |||
493 | int names_init(char *n) | ||
494 | { | ||
495 | FILE *f; | ||
496 | |||
497 | f = fopen(n, "r"); | ||
498 | if (!f) | ||
499 | return errno; | ||
500 | |||
501 | parse(f); | ||
502 | fclose(f); | ||
503 | return 0; | ||
504 | } | ||
diff --git a/tools/usb/usbip/libsrc/names.h b/tools/usb/usbip/libsrc/names.h new file mode 100644 index 000000000000..680926512de2 --- /dev/null +++ b/tools/usb/usbip/libsrc/names.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * names.h -- USB name database manipulation routines | ||
3 | * | ||
4 | * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | * | ||
21 | * | ||
22 | * Copyright (C) 2005 Takahiro Hirofuchi | ||
23 | * - names_free() is added. | ||
24 | */ | ||
25 | |||
26 | #ifndef _NAMES_H | ||
27 | #define _NAMES_H | ||
28 | |||
29 | #include <sys/types.h> | ||
30 | |||
31 | /* used by usbip_common.c */ | ||
32 | extern const char *names_vendor(u_int16_t vendorid); | ||
33 | extern const char *names_product(u_int16_t vendorid, u_int16_t productid); | ||
34 | extern const char *names_class(u_int8_t classid); | ||
35 | extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid); | ||
36 | extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, | ||
37 | u_int8_t protocolid); | ||
38 | extern int names_init(char *n); | ||
39 | extern void names_free(void); | ||
40 | |||
41 | #endif /* _NAMES_H */ | ||
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.c b/tools/usb/usbip/libsrc/sysfs_utils.c new file mode 100644 index 000000000000..36ac88ece0b8 --- /dev/null +++ b/tools/usb/usbip/libsrc/sysfs_utils.c | |||
@@ -0,0 +1,31 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <sys/stat.h> | ||
3 | #include <fcntl.h> | ||
4 | #include <errno.h> | ||
5 | |||
6 | #include "sysfs_utils.h" | ||
7 | #include "usbip_common.h" | ||
8 | |||
9 | int write_sysfs_attribute(const char *attr_path, const char *new_value, | ||
10 | size_t len) | ||
11 | { | ||
12 | int fd; | ||
13 | int length; | ||
14 | |||
15 | fd = open(attr_path, O_WRONLY); | ||
16 | if (fd < 0) { | ||
17 | dbg("error opening attribute %s", attr_path); | ||
18 | return -1; | ||
19 | } | ||
20 | |||
21 | length = write(fd, new_value, len); | ||
22 | if (length < 0) { | ||
23 | dbg("error writing to attribute %s", attr_path); | ||
24 | close(fd); | ||
25 | return -1; | ||
26 | } | ||
27 | |||
28 | close(fd); | ||
29 | |||
30 | return 0; | ||
31 | } | ||
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.h b/tools/usb/usbip/libsrc/sysfs_utils.h new file mode 100644 index 000000000000..32ac1d105d18 --- /dev/null +++ b/tools/usb/usbip/libsrc/sysfs_utils.h | |||
@@ -0,0 +1,8 @@ | |||
1 | |||
2 | #ifndef __SYSFS_UTILS_H | ||
3 | #define __SYSFS_UTILS_H | ||
4 | |||
5 | int write_sysfs_attribute(const char *attr_path, const char *new_value, | ||
6 | size_t len); | ||
7 | |||
8 | #endif | ||
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c new file mode 100644 index 000000000000..ac73710473de --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_common.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
3 | */ | ||
4 | |||
5 | #include <libudev.h> | ||
6 | #include "usbip_common.h" | ||
7 | #include "names.h" | ||
8 | |||
9 | #undef PROGNAME | ||
10 | #define PROGNAME "libusbip" | ||
11 | |||
12 | int usbip_use_syslog; | ||
13 | int usbip_use_stderr; | ||
14 | int usbip_use_debug; | ||
15 | |||
16 | extern struct udev *udev_context; | ||
17 | |||
18 | struct speed_string { | ||
19 | int num; | ||
20 | char *speed; | ||
21 | char *desc; | ||
22 | }; | ||
23 | |||
24 | static const struct speed_string speed_strings[] = { | ||
25 | { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"}, | ||
26 | { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" }, | ||
27 | { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" }, | ||
28 | { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, | ||
29 | { USB_SPEED_WIRELESS, "53.3-480", "Wireless"}, | ||
30 | { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" }, | ||
31 | { 0, NULL, NULL } | ||
32 | }; | ||
33 | |||
34 | struct portst_string { | ||
35 | int num; | ||
36 | char *desc; | ||
37 | }; | ||
38 | |||
39 | static struct portst_string portst_strings[] = { | ||
40 | { SDEV_ST_AVAILABLE, "Device Available" }, | ||
41 | { SDEV_ST_USED, "Device in Use" }, | ||
42 | { SDEV_ST_ERROR, "Device Error"}, | ||
43 | { VDEV_ST_NULL, "Port Available"}, | ||
44 | { VDEV_ST_NOTASSIGNED, "Port Initializing"}, | ||
45 | { VDEV_ST_USED, "Port in Use"}, | ||
46 | { VDEV_ST_ERROR, "Port Error"}, | ||
47 | { 0, NULL} | ||
48 | }; | ||
49 | |||
50 | const char *usbip_status_string(int32_t status) | ||
51 | { | ||
52 | for (int i = 0; portst_strings[i].desc != NULL; i++) | ||
53 | if (portst_strings[i].num == status) | ||
54 | return portst_strings[i].desc; | ||
55 | |||
56 | return "Unknown Status"; | ||
57 | } | ||
58 | |||
59 | const char *usbip_speed_string(int num) | ||
60 | { | ||
61 | for (int i = 0; speed_strings[i].speed != NULL; i++) | ||
62 | if (speed_strings[i].num == num) | ||
63 | return speed_strings[i].desc; | ||
64 | |||
65 | return "Unknown Speed"; | ||
66 | } | ||
67 | |||
68 | |||
69 | #define DBG_UDEV_INTEGER(name)\ | ||
70 | dbg("%-20s = %x", to_string(name), (int) udev->name) | ||
71 | |||
72 | #define DBG_UINF_INTEGER(name)\ | ||
73 | dbg("%-20s = %x", to_string(name), (int) uinf->name) | ||
74 | |||
75 | void dump_usb_interface(struct usbip_usb_interface *uinf) | ||
76 | { | ||
77 | char buff[100]; | ||
78 | |||
79 | usbip_names_get_class(buff, sizeof(buff), | ||
80 | uinf->bInterfaceClass, | ||
81 | uinf->bInterfaceSubClass, | ||
82 | uinf->bInterfaceProtocol); | ||
83 | dbg("%-20s = %s", "Interface(C/SC/P)", buff); | ||
84 | } | ||
85 | |||
86 | void dump_usb_device(struct usbip_usb_device *udev) | ||
87 | { | ||
88 | char buff[100]; | ||
89 | |||
90 | dbg("%-20s = %s", "path", udev->path); | ||
91 | dbg("%-20s = %s", "busid", udev->busid); | ||
92 | |||
93 | usbip_names_get_class(buff, sizeof(buff), | ||
94 | udev->bDeviceClass, | ||
95 | udev->bDeviceSubClass, | ||
96 | udev->bDeviceProtocol); | ||
97 | dbg("%-20s = %s", "Device(C/SC/P)", buff); | ||
98 | |||
99 | DBG_UDEV_INTEGER(bcdDevice); | ||
100 | |||
101 | usbip_names_get_product(buff, sizeof(buff), | ||
102 | udev->idVendor, | ||
103 | udev->idProduct); | ||
104 | dbg("%-20s = %s", "Vendor/Product", buff); | ||
105 | |||
106 | DBG_UDEV_INTEGER(bNumConfigurations); | ||
107 | DBG_UDEV_INTEGER(bNumInterfaces); | ||
108 | |||
109 | dbg("%-20s = %s", "speed", | ||
110 | usbip_speed_string(udev->speed)); | ||
111 | |||
112 | DBG_UDEV_INTEGER(busnum); | ||
113 | DBG_UDEV_INTEGER(devnum); | ||
114 | } | ||
115 | |||
116 | |||
117 | int read_attr_value(struct udev_device *dev, const char *name, | ||
118 | const char *format) | ||
119 | { | ||
120 | const char *attr; | ||
121 | int num = 0; | ||
122 | int ret; | ||
123 | |||
124 | attr = udev_device_get_sysattr_value(dev, name); | ||
125 | if (!attr) { | ||
126 | err("udev_device_get_sysattr_value failed"); | ||
127 | goto err; | ||
128 | } | ||
129 | |||
130 | /* The client chooses the device configuration | ||
131 | * when attaching it so right after being bound | ||
132 | * to usbip-host on the server the device will | ||
133 | * have no configuration. | ||
134 | * Therefore, attributes such as bConfigurationValue | ||
135 | * and bNumInterfaces will not exist and sscanf will | ||
136 | * fail. Check for these cases and don't treat them | ||
137 | * as errors. | ||
138 | */ | ||
139 | |||
140 | ret = sscanf(attr, format, &num); | ||
141 | if (ret < 1) { | ||
142 | if (strcmp(name, "bConfigurationValue") && | ||
143 | strcmp(name, "bNumInterfaces")) { | ||
144 | err("sscanf failed for attribute %s", name); | ||
145 | goto err; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | err: | ||
150 | |||
151 | return num; | ||
152 | } | ||
153 | |||
154 | |||
155 | int read_attr_speed(struct udev_device *dev) | ||
156 | { | ||
157 | const char *speed; | ||
158 | |||
159 | speed = udev_device_get_sysattr_value(dev, "speed"); | ||
160 | if (!speed) { | ||
161 | err("udev_device_get_sysattr_value failed"); | ||
162 | goto err; | ||
163 | } | ||
164 | |||
165 | for (int i = 0; speed_strings[i].speed != NULL; i++) { | ||
166 | if (!strcmp(speed, speed_strings[i].speed)) | ||
167 | return speed_strings[i].num; | ||
168 | } | ||
169 | |||
170 | err: | ||
171 | |||
172 | return USB_SPEED_UNKNOWN; | ||
173 | } | ||
174 | |||
175 | #define READ_ATTR(object, type, dev, name, format) \ | ||
176 | do { \ | ||
177 | (object)->name = (type) read_attr_value(dev, to_string(name), \ | ||
178 | format); \ | ||
179 | } while (0) | ||
180 | |||
181 | |||
182 | int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev) | ||
183 | { | ||
184 | uint32_t busnum, devnum; | ||
185 | const char *path, *name; | ||
186 | |||
187 | READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n"); | ||
188 | READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n"); | ||
189 | READ_ATTR(udev, uint8_t, sdev, bDeviceProtocol, "%02x\n"); | ||
190 | |||
191 | READ_ATTR(udev, uint16_t, sdev, idVendor, "%04x\n"); | ||
192 | READ_ATTR(udev, uint16_t, sdev, idProduct, "%04x\n"); | ||
193 | READ_ATTR(udev, uint16_t, sdev, bcdDevice, "%04x\n"); | ||
194 | |||
195 | READ_ATTR(udev, uint8_t, sdev, bConfigurationValue, "%02x\n"); | ||
196 | READ_ATTR(udev, uint8_t, sdev, bNumConfigurations, "%02x\n"); | ||
197 | READ_ATTR(udev, uint8_t, sdev, bNumInterfaces, "%02x\n"); | ||
198 | |||
199 | READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n"); | ||
200 | udev->speed = read_attr_speed(sdev); | ||
201 | |||
202 | path = udev_device_get_syspath(sdev); | ||
203 | name = udev_device_get_sysname(sdev); | ||
204 | |||
205 | strncpy(udev->path, path, SYSFS_PATH_MAX); | ||
206 | strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE); | ||
207 | |||
208 | sscanf(name, "%u-%u", &busnum, &devnum); | ||
209 | udev->busnum = busnum; | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | int read_usb_interface(struct usbip_usb_device *udev, int i, | ||
215 | struct usbip_usb_interface *uinf) | ||
216 | { | ||
217 | char busid[SYSFS_BUS_ID_SIZE]; | ||
218 | struct udev_device *sif; | ||
219 | |||
220 | sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); | ||
221 | |||
222 | sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); | ||
223 | if (!sif) { | ||
224 | err("udev_device_new_from_subsystem_sysname %s failed", busid); | ||
225 | return -1; | ||
226 | } | ||
227 | |||
228 | READ_ATTR(uinf, uint8_t, sif, bInterfaceClass, "%02x\n"); | ||
229 | READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n"); | ||
230 | READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n"); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | int usbip_names_init(char *f) | ||
236 | { | ||
237 | return names_init(f); | ||
238 | } | ||
239 | |||
240 | void usbip_names_free(void) | ||
241 | { | ||
242 | names_free(); | ||
243 | } | ||
244 | |||
245 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, | ||
246 | uint16_t product) | ||
247 | { | ||
248 | const char *prod, *vend; | ||
249 | |||
250 | prod = names_product(vendor, product); | ||
251 | if (!prod) | ||
252 | prod = "unknown product"; | ||
253 | |||
254 | |||
255 | vend = names_vendor(vendor); | ||
256 | if (!vend) | ||
257 | vend = "unknown vendor"; | ||
258 | |||
259 | snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product); | ||
260 | } | ||
261 | |||
262 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, | ||
263 | uint8_t subclass, uint8_t protocol) | ||
264 | { | ||
265 | const char *c, *s, *p; | ||
266 | |||
267 | if (class == 0 && subclass == 0 && protocol == 0) { | ||
268 | snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | p = names_protocol(class, subclass, protocol); | ||
273 | if (!p) | ||
274 | p = "unknown protocol"; | ||
275 | |||
276 | s = names_subclass(class, subclass); | ||
277 | if (!s) | ||
278 | s = "unknown subclass"; | ||
279 | |||
280 | c = names_class(class); | ||
281 | if (!c) | ||
282 | c = "unknown class"; | ||
283 | |||
284 | snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol); | ||
285 | } | ||
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h new file mode 100644 index 000000000000..15fe792e1e96 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_common.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
3 | */ | ||
4 | |||
5 | #ifndef __USBIP_COMMON_H | ||
6 | #define __USBIP_COMMON_H | ||
7 | |||
8 | #include <libudev.h> | ||
9 | |||
10 | #include <stdint.h> | ||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | |||
15 | #include <syslog.h> | ||
16 | #include <unistd.h> | ||
17 | #include <linux/usb/ch9.h> | ||
18 | #include <linux/usbip.h> | ||
19 | |||
20 | #ifndef USBIDS_FILE | ||
21 | #define USBIDS_FILE "/usr/share/hwdata/usb.ids" | ||
22 | #endif | ||
23 | |||
24 | #ifndef VHCI_STATE_PATH | ||
25 | #define VHCI_STATE_PATH "/var/run/vhci_hcd" | ||
26 | #endif | ||
27 | |||
28 | /* kernel module names */ | ||
29 | #define USBIP_CORE_MOD_NAME "usbip-core" | ||
30 | #define USBIP_HOST_DRV_NAME "usbip-host" | ||
31 | #define USBIP_VHCI_DRV_NAME "vhci_hcd" | ||
32 | |||
33 | /* sysfs constants */ | ||
34 | #define SYSFS_MNT_PATH "/sys" | ||
35 | #define SYSFS_BUS_NAME "bus" | ||
36 | #define SYSFS_BUS_TYPE "usb" | ||
37 | #define SYSFS_DRIVERS_NAME "drivers" | ||
38 | |||
39 | #define SYSFS_PATH_MAX 256 | ||
40 | #define SYSFS_BUS_ID_SIZE 32 | ||
41 | |||
42 | extern int usbip_use_syslog; | ||
43 | extern int usbip_use_stderr; | ||
44 | extern int usbip_use_debug ; | ||
45 | |||
46 | #define PROGNAME "usbip" | ||
47 | |||
48 | #define pr_fmt(fmt) "%s: %s: " fmt "\n", PROGNAME | ||
49 | #define dbg_fmt(fmt) pr_fmt("%s:%d:[%s] " fmt), "debug", \ | ||
50 | __FILE__, __LINE__, __func__ | ||
51 | |||
52 | #define err(fmt, args...) \ | ||
53 | do { \ | ||
54 | if (usbip_use_syslog) { \ | ||
55 | syslog(LOG_ERR, pr_fmt(fmt), "error", ##args); \ | ||
56 | } \ | ||
57 | if (usbip_use_stderr) { \ | ||
58 | fprintf(stderr, pr_fmt(fmt), "error", ##args); \ | ||
59 | } \ | ||
60 | } while (0) | ||
61 | |||
62 | #define info(fmt, args...) \ | ||
63 | do { \ | ||
64 | if (usbip_use_syslog) { \ | ||
65 | syslog(LOG_INFO, pr_fmt(fmt), "info", ##args); \ | ||
66 | } \ | ||
67 | if (usbip_use_stderr) { \ | ||
68 | fprintf(stderr, pr_fmt(fmt), "info", ##args); \ | ||
69 | } \ | ||
70 | } while (0) | ||
71 | |||
72 | #define dbg(fmt, args...) \ | ||
73 | do { \ | ||
74 | if (usbip_use_debug) { \ | ||
75 | if (usbip_use_syslog) { \ | ||
76 | syslog(LOG_DEBUG, dbg_fmt(fmt), ##args); \ | ||
77 | } \ | ||
78 | if (usbip_use_stderr) { \ | ||
79 | fprintf(stderr, dbg_fmt(fmt), ##args); \ | ||
80 | } \ | ||
81 | } \ | ||
82 | } while (0) | ||
83 | |||
84 | #define BUG() \ | ||
85 | do { \ | ||
86 | err("sorry, it's a bug!"); \ | ||
87 | abort(); \ | ||
88 | } while (0) | ||
89 | |||
90 | struct usbip_usb_interface { | ||
91 | uint8_t bInterfaceClass; | ||
92 | uint8_t bInterfaceSubClass; | ||
93 | uint8_t bInterfaceProtocol; | ||
94 | uint8_t padding; /* alignment */ | ||
95 | } __attribute__((packed)); | ||
96 | |||
97 | struct usbip_usb_device { | ||
98 | char path[SYSFS_PATH_MAX]; | ||
99 | char busid[SYSFS_BUS_ID_SIZE]; | ||
100 | |||
101 | uint32_t busnum; | ||
102 | uint32_t devnum; | ||
103 | uint32_t speed; | ||
104 | |||
105 | uint16_t idVendor; | ||
106 | uint16_t idProduct; | ||
107 | uint16_t bcdDevice; | ||
108 | |||
109 | uint8_t bDeviceClass; | ||
110 | uint8_t bDeviceSubClass; | ||
111 | uint8_t bDeviceProtocol; | ||
112 | uint8_t bConfigurationValue; | ||
113 | uint8_t bNumConfigurations; | ||
114 | uint8_t bNumInterfaces; | ||
115 | } __attribute__((packed)); | ||
116 | |||
117 | #define to_string(s) #s | ||
118 | |||
119 | void dump_usb_interface(struct usbip_usb_interface *); | ||
120 | void dump_usb_device(struct usbip_usb_device *); | ||
121 | int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev); | ||
122 | int read_attr_value(struct udev_device *dev, const char *name, | ||
123 | const char *format); | ||
124 | int read_usb_interface(struct usbip_usb_device *udev, int i, | ||
125 | struct usbip_usb_interface *uinf); | ||
126 | |||
127 | const char *usbip_speed_string(int num); | ||
128 | const char *usbip_status_string(int32_t status); | ||
129 | |||
130 | int usbip_names_init(char *); | ||
131 | void usbip_names_free(void); | ||
132 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, | ||
133 | uint16_t product); | ||
134 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, | ||
135 | uint8_t subclass, uint8_t protocol); | ||
136 | |||
137 | #endif /* __USBIP_COMMON_H */ | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c new file mode 100644 index 000000000000..bef08d5c44e8 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_host_driver.c | |||
@@ -0,0 +1,280 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
3 | * 2005-2007 Takahiro Hirofuchi | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <sys/types.h> | ||
20 | #include <sys/stat.h> | ||
21 | #include <fcntl.h> | ||
22 | |||
23 | #include <errno.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include <libudev.h> | ||
27 | |||
28 | #include "usbip_common.h" | ||
29 | #include "usbip_host_driver.h" | ||
30 | #include "list.h" | ||
31 | #include "sysfs_utils.h" | ||
32 | |||
33 | #undef PROGNAME | ||
34 | #define PROGNAME "libusbip" | ||
35 | |||
36 | struct usbip_host_driver *host_driver; | ||
37 | struct udev *udev_context; | ||
38 | |||
39 | static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | ||
40 | { | ||
41 | char status_attr_path[SYSFS_PATH_MAX]; | ||
42 | int fd; | ||
43 | int length; | ||
44 | char status; | ||
45 | int value = 0; | ||
46 | |||
47 | snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", | ||
48 | udev->path); | ||
49 | |||
50 | fd = open(status_attr_path, O_RDONLY); | ||
51 | if (fd < 0) { | ||
52 | err("error opening attribute %s", status_attr_path); | ||
53 | return -1; | ||
54 | } | ||
55 | |||
56 | length = read(fd, &status, 1); | ||
57 | if (length < 0) { | ||
58 | err("error reading attribute %s", status_attr_path); | ||
59 | close(fd); | ||
60 | return -1; | ||
61 | } | ||
62 | |||
63 | value = atoi(&status); | ||
64 | |||
65 | return value; | ||
66 | } | ||
67 | |||
68 | static | ||
69 | struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath) | ||
70 | { | ||
71 | struct usbip_exported_device *edev = NULL; | ||
72 | struct usbip_exported_device *edev_old; | ||
73 | size_t size; | ||
74 | int i; | ||
75 | |||
76 | edev = calloc(1, sizeof(struct usbip_exported_device)); | ||
77 | |||
78 | edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath); | ||
79 | if (!edev->sudev) { | ||
80 | err("udev_device_new_from_syspath: %s", sdevpath); | ||
81 | goto err; | ||
82 | } | ||
83 | |||
84 | read_usb_device(edev->sudev, &edev->udev); | ||
85 | |||
86 | edev->status = read_attr_usbip_status(&edev->udev); | ||
87 | if (edev->status < 0) | ||
88 | goto err; | ||
89 | |||
90 | /* reallocate buffer to include usb interface data */ | ||
91 | size = sizeof(struct usbip_exported_device) + | ||
92 | edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); | ||
93 | |||
94 | edev_old = edev; | ||
95 | edev = realloc(edev, size); | ||
96 | if (!edev) { | ||
97 | edev = edev_old; | ||
98 | dbg("realloc failed"); | ||
99 | goto err; | ||
100 | } | ||
101 | |||
102 | for (i = 0; i < edev->udev.bNumInterfaces; i++) | ||
103 | read_usb_interface(&edev->udev, i, &edev->uinf[i]); | ||
104 | |||
105 | return edev; | ||
106 | err: | ||
107 | if (edev->sudev) | ||
108 | udev_device_unref(edev->sudev); | ||
109 | if (edev) | ||
110 | free(edev); | ||
111 | |||
112 | return NULL; | ||
113 | } | ||
114 | |||
115 | static int refresh_exported_devices(void) | ||
116 | { | ||
117 | struct usbip_exported_device *edev; | ||
118 | struct udev_enumerate *enumerate; | ||
119 | struct udev_list_entry *devices, *dev_list_entry; | ||
120 | struct udev_device *dev; | ||
121 | const char *path; | ||
122 | const char *driver; | ||
123 | |||
124 | enumerate = udev_enumerate_new(udev_context); | ||
125 | udev_enumerate_add_match_subsystem(enumerate, "usb"); | ||
126 | udev_enumerate_scan_devices(enumerate); | ||
127 | |||
128 | devices = udev_enumerate_get_list_entry(enumerate); | ||
129 | |||
130 | udev_list_entry_foreach(dev_list_entry, devices) { | ||
131 | path = udev_list_entry_get_name(dev_list_entry); | ||
132 | dev = udev_device_new_from_syspath(udev_context, path); | ||
133 | if (dev == NULL) | ||
134 | continue; | ||
135 | |||
136 | /* Check whether device uses usbip-host driver. */ | ||
137 | driver = udev_device_get_driver(dev); | ||
138 | if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) { | ||
139 | edev = usbip_exported_device_new(path); | ||
140 | if (!edev) { | ||
141 | dbg("usbip_exported_device_new failed"); | ||
142 | continue; | ||
143 | } | ||
144 | |||
145 | list_add(&edev->node, &host_driver->edev_list); | ||
146 | host_driver->ndevs++; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void usbip_exported_device_destroy(void) | ||
154 | { | ||
155 | struct list_head *i, *tmp; | ||
156 | struct usbip_exported_device *edev; | ||
157 | |||
158 | list_for_each_safe(i, tmp, &host_driver->edev_list) { | ||
159 | edev = list_entry(i, struct usbip_exported_device, node); | ||
160 | list_del(i); | ||
161 | free(edev); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | int usbip_host_driver_open(void) | ||
166 | { | ||
167 | int rc; | ||
168 | |||
169 | udev_context = udev_new(); | ||
170 | if (!udev_context) { | ||
171 | err("udev_new failed"); | ||
172 | return -1; | ||
173 | } | ||
174 | |||
175 | host_driver = calloc(1, sizeof(*host_driver)); | ||
176 | |||
177 | host_driver->ndevs = 0; | ||
178 | INIT_LIST_HEAD(&host_driver->edev_list); | ||
179 | |||
180 | rc = refresh_exported_devices(); | ||
181 | if (rc < 0) | ||
182 | goto err_free_host_driver; | ||
183 | |||
184 | return 0; | ||
185 | |||
186 | err_free_host_driver: | ||
187 | free(host_driver); | ||
188 | host_driver = NULL; | ||
189 | |||
190 | udev_unref(udev_context); | ||
191 | |||
192 | return -1; | ||
193 | } | ||
194 | |||
195 | void usbip_host_driver_close(void) | ||
196 | { | ||
197 | if (!host_driver) | ||
198 | return; | ||
199 | |||
200 | usbip_exported_device_destroy(); | ||
201 | |||
202 | free(host_driver); | ||
203 | host_driver = NULL; | ||
204 | |||
205 | udev_unref(udev_context); | ||
206 | } | ||
207 | |||
208 | int usbip_host_refresh_device_list(void) | ||
209 | { | ||
210 | int rc; | ||
211 | |||
212 | usbip_exported_device_destroy(); | ||
213 | |||
214 | host_driver->ndevs = 0; | ||
215 | INIT_LIST_HEAD(&host_driver->edev_list); | ||
216 | |||
217 | rc = refresh_exported_devices(); | ||
218 | if (rc < 0) | ||
219 | return -1; | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) | ||
225 | { | ||
226 | char attr_name[] = "usbip_sockfd"; | ||
227 | char sockfd_attr_path[SYSFS_PATH_MAX]; | ||
228 | char sockfd_buff[30]; | ||
229 | int ret; | ||
230 | |||
231 | if (edev->status != SDEV_ST_AVAILABLE) { | ||
232 | dbg("device not available: %s", edev->udev.busid); | ||
233 | switch (edev->status) { | ||
234 | case SDEV_ST_ERROR: | ||
235 | dbg("status SDEV_ST_ERROR"); | ||
236 | break; | ||
237 | case SDEV_ST_USED: | ||
238 | dbg("status SDEV_ST_USED"); | ||
239 | break; | ||
240 | default: | ||
241 | dbg("status unknown: 0x%x", edev->status); | ||
242 | } | ||
243 | return -1; | ||
244 | } | ||
245 | |||
246 | /* only the first interface is true */ | ||
247 | snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", | ||
248 | edev->udev.path, attr_name); | ||
249 | |||
250 | snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); | ||
251 | |||
252 | ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, | ||
253 | strlen(sockfd_buff)); | ||
254 | if (ret < 0) { | ||
255 | err("write_sysfs_attribute failed: sockfd %s to %s", | ||
256 | sockfd_buff, sockfd_attr_path); | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | info("connect: %s", edev->udev.busid); | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | struct usbip_exported_device *usbip_host_get_device(int num) | ||
266 | { | ||
267 | struct list_head *i; | ||
268 | struct usbip_exported_device *edev; | ||
269 | int cnt = 0; | ||
270 | |||
271 | list_for_each(i, &host_driver->edev_list) { | ||
272 | edev = list_entry(i, struct usbip_exported_device, node); | ||
273 | if (num == cnt) | ||
274 | return edev; | ||
275 | else | ||
276 | cnt++; | ||
277 | } | ||
278 | |||
279 | return NULL; | ||
280 | } | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.h b/tools/usb/usbip/libsrc/usbip_host_driver.h new file mode 100644 index 000000000000..2a31f855c616 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_host_driver.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
3 | * 2005-2007 Takahiro Hirofuchi | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef __USBIP_HOST_DRIVER_H | ||
20 | #define __USBIP_HOST_DRIVER_H | ||
21 | |||
22 | #include <stdint.h> | ||
23 | #include "usbip_common.h" | ||
24 | #include "list.h" | ||
25 | |||
26 | struct usbip_host_driver { | ||
27 | int ndevs; | ||
28 | /* list of exported device */ | ||
29 | struct list_head edev_list; | ||
30 | }; | ||
31 | |||
32 | struct usbip_exported_device { | ||
33 | struct udev_device *sudev; | ||
34 | int32_t status; | ||
35 | struct usbip_usb_device udev; | ||
36 | struct list_head node; | ||
37 | struct usbip_usb_interface uinf[]; | ||
38 | }; | ||
39 | |||
40 | extern struct usbip_host_driver *host_driver; | ||
41 | |||
42 | int usbip_host_driver_open(void); | ||
43 | void usbip_host_driver_close(void); | ||
44 | |||
45 | int usbip_host_refresh_device_list(void); | ||
46 | int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd); | ||
47 | struct usbip_exported_device *usbip_host_get_device(int num); | ||
48 | |||
49 | #endif /* __USBIP_HOST_DRIVER_H */ | ||
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c new file mode 100644 index 000000000000..ad9204773533 --- /dev/null +++ b/tools/usb/usbip/libsrc/vhci_driver.c | |||
@@ -0,0 +1,411 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
3 | */ | ||
4 | |||
5 | #include "usbip_common.h" | ||
6 | #include "vhci_driver.h" | ||
7 | #include <limits.h> | ||
8 | #include <netdb.h> | ||
9 | #include <libudev.h> | ||
10 | #include "sysfs_utils.h" | ||
11 | |||
12 | #undef PROGNAME | ||
13 | #define PROGNAME "libusbip" | ||
14 | |||
15 | struct usbip_vhci_driver *vhci_driver; | ||
16 | struct udev *udev_context; | ||
17 | |||
18 | static struct usbip_imported_device * | ||
19 | imported_device_init(struct usbip_imported_device *idev, char *busid) | ||
20 | { | ||
21 | struct udev_device *sudev; | ||
22 | |||
23 | sudev = udev_device_new_from_subsystem_sysname(udev_context, | ||
24 | "usb", busid); | ||
25 | if (!sudev) { | ||
26 | dbg("udev_device_new_from_subsystem_sysname failed: %s", busid); | ||
27 | goto err; | ||
28 | } | ||
29 | read_usb_device(sudev, &idev->udev); | ||
30 | udev_device_unref(sudev); | ||
31 | |||
32 | return idev; | ||
33 | |||
34 | err: | ||
35 | return NULL; | ||
36 | } | ||
37 | |||
38 | |||
39 | |||
40 | static int parse_status(const char *value) | ||
41 | { | ||
42 | int ret = 0; | ||
43 | char *c; | ||
44 | |||
45 | |||
46 | for (int i = 0; i < vhci_driver->nports; i++) | ||
47 | memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i])); | ||
48 | |||
49 | |||
50 | /* skip a header line */ | ||
51 | c = strchr(value, '\n'); | ||
52 | if (!c) | ||
53 | return -1; | ||
54 | c++; | ||
55 | |||
56 | while (*c != '\0') { | ||
57 | int port, status, speed, devid; | ||
58 | unsigned long socket; | ||
59 | char lbusid[SYSFS_BUS_ID_SIZE]; | ||
60 | |||
61 | ret = sscanf(c, "%d %d %d %x %lx %31s\n", | ||
62 | &port, &status, &speed, | ||
63 | &devid, &socket, lbusid); | ||
64 | |||
65 | if (ret < 5) { | ||
66 | dbg("sscanf failed: %d", ret); | ||
67 | BUG(); | ||
68 | } | ||
69 | |||
70 | dbg("port %d status %d speed %d devid %x", | ||
71 | port, status, speed, devid); | ||
72 | dbg("socket %lx lbusid %s", socket, lbusid); | ||
73 | |||
74 | |||
75 | /* if a device is connected, look at it */ | ||
76 | { | ||
77 | struct usbip_imported_device *idev = &vhci_driver->idev[port]; | ||
78 | |||
79 | idev->port = port; | ||
80 | idev->status = status; | ||
81 | |||
82 | idev->devid = devid; | ||
83 | |||
84 | idev->busnum = (devid >> 16); | ||
85 | idev->devnum = (devid & 0x0000ffff); | ||
86 | |||
87 | if (idev->status != VDEV_ST_NULL | ||
88 | && idev->status != VDEV_ST_NOTASSIGNED) { | ||
89 | idev = imported_device_init(idev, lbusid); | ||
90 | if (!idev) { | ||
91 | dbg("imported_device_init failed"); | ||
92 | return -1; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | |||
98 | /* go to the next line */ | ||
99 | c = strchr(c, '\n'); | ||
100 | if (!c) | ||
101 | break; | ||
102 | c++; | ||
103 | } | ||
104 | |||
105 | dbg("exit"); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int refresh_imported_device_list(void) | ||
111 | { | ||
112 | const char *attr_status; | ||
113 | |||
114 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, | ||
115 | "status"); | ||
116 | if (!attr_status) { | ||
117 | err("udev_device_get_sysattr_value failed"); | ||
118 | return -1; | ||
119 | } | ||
120 | |||
121 | return parse_status(attr_status); | ||
122 | } | ||
123 | |||
124 | static int get_nports(void) | ||
125 | { | ||
126 | char *c; | ||
127 | int nports = 0; | ||
128 | const char *attr_status; | ||
129 | |||
130 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, | ||
131 | "status"); | ||
132 | if (!attr_status) { | ||
133 | err("udev_device_get_sysattr_value failed"); | ||
134 | return -1; | ||
135 | } | ||
136 | |||
137 | /* skip a header line */ | ||
138 | c = strchr(attr_status, '\n'); | ||
139 | if (!c) | ||
140 | return 0; | ||
141 | c++; | ||
142 | |||
143 | while (*c != '\0') { | ||
144 | /* go to the next line */ | ||
145 | c = strchr(c, '\n'); | ||
146 | if (!c) | ||
147 | return nports; | ||
148 | c++; | ||
149 | nports += 1; | ||
150 | } | ||
151 | |||
152 | return nports; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Read the given port's record. | ||
157 | * | ||
158 | * To avoid buffer overflow we will read the entire line and | ||
159 | * validate each part's size. The initial buffer is padded by 4 to | ||
160 | * accommodate the 2 spaces, 1 newline and an additional character | ||
161 | * which is needed to properly validate the 3rd part without it being | ||
162 | * truncated to an acceptable length. | ||
163 | */ | ||
164 | static int read_record(int rhport, char *host, unsigned long host_len, | ||
165 | char *port, unsigned long port_len, char *busid) | ||
166 | { | ||
167 | int part; | ||
168 | FILE *file; | ||
169 | char path[PATH_MAX+1]; | ||
170 | char *buffer, *start, *end; | ||
171 | char delim[] = {' ', ' ', '\n'}; | ||
172 | int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE}; | ||
173 | size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4; | ||
174 | |||
175 | buffer = malloc(buffer_len); | ||
176 | if (!buffer) | ||
177 | return -1; | ||
178 | |||
179 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); | ||
180 | |||
181 | file = fopen(path, "r"); | ||
182 | if (!file) { | ||
183 | err("fopen"); | ||
184 | free(buffer); | ||
185 | return -1; | ||
186 | } | ||
187 | |||
188 | if (fgets(buffer, buffer_len, file) == NULL) { | ||
189 | err("fgets"); | ||
190 | free(buffer); | ||
191 | fclose(file); | ||
192 | return -1; | ||
193 | } | ||
194 | fclose(file); | ||
195 | |||
196 | /* validate the length of each of the 3 parts */ | ||
197 | start = buffer; | ||
198 | for (part = 0; part < 3; part++) { | ||
199 | end = strchr(start, delim[part]); | ||
200 | if (end == NULL || (end - start) > max_len[part]) { | ||
201 | free(buffer); | ||
202 | return -1; | ||
203 | } | ||
204 | start = end + 1; | ||
205 | } | ||
206 | |||
207 | if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) { | ||
208 | err("sscanf"); | ||
209 | free(buffer); | ||
210 | return -1; | ||
211 | } | ||
212 | |||
213 | free(buffer); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /* ---------------------------------------------------------------------- */ | ||
219 | |||
220 | int usbip_vhci_driver_open(void) | ||
221 | { | ||
222 | udev_context = udev_new(); | ||
223 | if (!udev_context) { | ||
224 | err("udev_new failed"); | ||
225 | return -1; | ||
226 | } | ||
227 | |||
228 | vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); | ||
229 | |||
230 | /* will be freed in usbip_driver_close() */ | ||
231 | vhci_driver->hc_device = | ||
232 | udev_device_new_from_subsystem_sysname(udev_context, | ||
233 | USBIP_VHCI_BUS_TYPE, | ||
234 | USBIP_VHCI_DRV_NAME); | ||
235 | if (!vhci_driver->hc_device) { | ||
236 | err("udev_device_new_from_subsystem_sysname failed"); | ||
237 | goto err; | ||
238 | } | ||
239 | |||
240 | vhci_driver->nports = get_nports(); | ||
241 | |||
242 | dbg("available ports: %d", vhci_driver->nports); | ||
243 | |||
244 | if (refresh_imported_device_list()) | ||
245 | goto err; | ||
246 | |||
247 | return 0; | ||
248 | |||
249 | err: | ||
250 | udev_device_unref(vhci_driver->hc_device); | ||
251 | |||
252 | if (vhci_driver) | ||
253 | free(vhci_driver); | ||
254 | |||
255 | vhci_driver = NULL; | ||
256 | |||
257 | udev_unref(udev_context); | ||
258 | |||
259 | return -1; | ||
260 | } | ||
261 | |||
262 | |||
263 | void usbip_vhci_driver_close(void) | ||
264 | { | ||
265 | if (!vhci_driver) | ||
266 | return; | ||
267 | |||
268 | udev_device_unref(vhci_driver->hc_device); | ||
269 | |||
270 | free(vhci_driver); | ||
271 | |||
272 | vhci_driver = NULL; | ||
273 | |||
274 | udev_unref(udev_context); | ||
275 | } | ||
276 | |||
277 | |||
278 | int usbip_vhci_refresh_device_list(void) | ||
279 | { | ||
280 | |||
281 | if (refresh_imported_device_list()) | ||
282 | goto err; | ||
283 | |||
284 | return 0; | ||
285 | err: | ||
286 | dbg("failed to refresh device list"); | ||
287 | return -1; | ||
288 | } | ||
289 | |||
290 | |||
291 | int usbip_vhci_get_free_port(void) | ||
292 | { | ||
293 | for (int i = 0; i < vhci_driver->nports; i++) { | ||
294 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) | ||
295 | return i; | ||
296 | } | ||
297 | |||
298 | return -1; | ||
299 | } | ||
300 | |||
301 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, | ||
302 | uint32_t speed) { | ||
303 | char buff[200]; /* what size should be ? */ | ||
304 | char attach_attr_path[SYSFS_PATH_MAX]; | ||
305 | char attr_attach[] = "attach"; | ||
306 | const char *path; | ||
307 | int ret; | ||
308 | |||
309 | snprintf(buff, sizeof(buff), "%u %d %u %u", | ||
310 | port, sockfd, devid, speed); | ||
311 | dbg("writing: %s", buff); | ||
312 | |||
313 | path = udev_device_get_syspath(vhci_driver->hc_device); | ||
314 | snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s", | ||
315 | path, attr_attach); | ||
316 | dbg("attach attribute path: %s", attach_attr_path); | ||
317 | |||
318 | ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff)); | ||
319 | if (ret < 0) { | ||
320 | dbg("write_sysfs_attribute failed"); | ||
321 | return -1; | ||
322 | } | ||
323 | |||
324 | dbg("attached port: %d", port); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static unsigned long get_devid(uint8_t busnum, uint8_t devnum) | ||
330 | { | ||
331 | return (busnum << 16) | devnum; | ||
332 | } | ||
333 | |||
334 | /* will be removed */ | ||
335 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, | ||
336 | uint8_t devnum, uint32_t speed) | ||
337 | { | ||
338 | int devid = get_devid(busnum, devnum); | ||
339 | |||
340 | return usbip_vhci_attach_device2(port, sockfd, devid, speed); | ||
341 | } | ||
342 | |||
343 | int usbip_vhci_detach_device(uint8_t port) | ||
344 | { | ||
345 | char detach_attr_path[SYSFS_PATH_MAX]; | ||
346 | char attr_detach[] = "detach"; | ||
347 | char buff[200]; /* what size should be ? */ | ||
348 | const char *path; | ||
349 | int ret; | ||
350 | |||
351 | snprintf(buff, sizeof(buff), "%u", port); | ||
352 | dbg("writing: %s", buff); | ||
353 | |||
354 | path = udev_device_get_syspath(vhci_driver->hc_device); | ||
355 | snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s", | ||
356 | path, attr_detach); | ||
357 | dbg("detach attribute path: %s", detach_attr_path); | ||
358 | |||
359 | ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff)); | ||
360 | if (ret < 0) { | ||
361 | dbg("write_sysfs_attribute failed"); | ||
362 | return -1; | ||
363 | } | ||
364 | |||
365 | dbg("detached port: %d", port); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) | ||
371 | { | ||
372 | char product_name[100]; | ||
373 | char host[NI_MAXHOST] = "unknown host"; | ||
374 | char serv[NI_MAXSERV] = "unknown port"; | ||
375 | char remote_busid[SYSFS_BUS_ID_SIZE]; | ||
376 | int ret; | ||
377 | int read_record_error = 0; | ||
378 | |||
379 | if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) | ||
380 | return 0; | ||
381 | |||
382 | ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv), | ||
383 | remote_busid); | ||
384 | if (ret) { | ||
385 | err("read_record"); | ||
386 | read_record_error = 1; | ||
387 | } | ||
388 | |||
389 | printf("Port %02d: <%s> at %s\n", idev->port, | ||
390 | usbip_status_string(idev->status), | ||
391 | usbip_speed_string(idev->udev.speed)); | ||
392 | |||
393 | usbip_names_get_product(product_name, sizeof(product_name), | ||
394 | idev->udev.idVendor, idev->udev.idProduct); | ||
395 | |||
396 | printf(" %s\n", product_name); | ||
397 | |||
398 | if (!read_record_error) { | ||
399 | printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid, | ||
400 | host, serv, remote_busid); | ||
401 | printf("%10s -> remote bus/dev %03d/%03d\n", " ", | ||
402 | idev->busnum, idev->devnum); | ||
403 | } else { | ||
404 | printf("%10s -> unknown host, remote port and remote busid\n", | ||
405 | idev->udev.busid); | ||
406 | printf("%10s -> remote bus/dev %03d/%03d\n", " ", | ||
407 | idev->busnum, idev->devnum); | ||
408 | } | ||
409 | |||
410 | return 0; | ||
411 | } | ||
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h new file mode 100644 index 000000000000..fa2316cf2cac --- /dev/null +++ b/tools/usb/usbip/libsrc/vhci_driver.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
3 | */ | ||
4 | |||
5 | #ifndef __VHCI_DRIVER_H | ||
6 | #define __VHCI_DRIVER_H | ||
7 | |||
8 | #include <libudev.h> | ||
9 | #include <stdint.h> | ||
10 | |||
11 | #include "usbip_common.h" | ||
12 | |||
13 | #define USBIP_VHCI_BUS_TYPE "platform" | ||
14 | #define MAXNPORT 128 | ||
15 | |||
16 | struct usbip_imported_device { | ||
17 | uint8_t port; | ||
18 | uint32_t status; | ||
19 | |||
20 | uint32_t devid; | ||
21 | |||
22 | uint8_t busnum; | ||
23 | uint8_t devnum; | ||
24 | |||
25 | /* usbip_class_device list */ | ||
26 | struct usbip_usb_device udev; | ||
27 | }; | ||
28 | |||
29 | struct usbip_vhci_driver { | ||
30 | |||
31 | /* /sys/devices/platform/vhci_hcd */ | ||
32 | struct udev_device *hc_device; | ||
33 | |||
34 | int nports; | ||
35 | struct usbip_imported_device idev[MAXNPORT]; | ||
36 | }; | ||
37 | |||
38 | |||
39 | extern struct usbip_vhci_driver *vhci_driver; | ||
40 | |||
41 | int usbip_vhci_driver_open(void); | ||
42 | void usbip_vhci_driver_close(void); | ||
43 | |||
44 | int usbip_vhci_refresh_device_list(void); | ||
45 | |||
46 | |||
47 | int usbip_vhci_get_free_port(void); | ||
48 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, | ||
49 | uint32_t speed); | ||
50 | |||
51 | /* will be removed */ | ||
52 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, | ||
53 | uint8_t devnum, uint32_t speed); | ||
54 | |||
55 | int usbip_vhci_detach_device(uint8_t port); | ||
56 | |||
57 | int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev); | ||
58 | |||
59 | #endif /* __VHCI_DRIVER_H */ | ||