diff options
| author | Valentina Manea <valentina.manea.m@gmail.com> | 2014-08-20 00:30:59 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-08-25 13:38:56 -0400 |
| commit | 588b48caf65c4a92af567948ec0025065e749ddf (patch) | |
| tree | 6cf9771e522864db1685ffd7cabd31439fe93305 /tools/usb/usbip/libsrc | |
| parent | 1ddb55275d8489d0ecd4722a997531cf26a035cb (diff) | |
usbip: move usbip userspace code out of staging
At this point, USB/IP userspace code is fully functional
and can be moved out of staging.
Signed-off-by: Valentina Manea <valentina.manea.m@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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..5a0e95edf4df --- /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 "../../uapi/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 */ | ||
