diff options
author | Valentina Manea <valentina.manea.m@gmail.com> | 2014-08-20 07:30:59 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-08-25 10:38:56 -0700 |
commit | 588b48caf65c4a92af567948ec0025065e749ddf (patch) | |
tree | 6cf9771e522864db1685ffd7cabd31439fe93305 /tools/usb/usbip/libsrc | |
parent | 1ddb55275d8489d0ecd4722a997531cf26a035cb (diff) | |
download | linux-588b48caf65c4a92af567948ec0025065e749ddf.tar.gz linux-588b48caf65c4a92af567948ec0025065e749ddf.tar.bz2 linux-588b48caf65c4a92af567948ec0025065e749ddf.zip |
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 @@ +libusbip_la_CPPFLAGS = -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' +libusbip_la_CFLAGS = @EXTRA_CFLAGS@ +libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@ + +lib_LTLIBRARIES := libusbip.la +libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ + usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \ + 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 @@ +#ifndef _LIST_H +#define _LIST_H + +/* Stripped down implementation of linked list taken + * from the Linux Kernel. + */ + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +#define POISON_POINTER_DELTA 0 +#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) +#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#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 @@ +/* + * names.c -- USB name database manipulation routines + * + * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * + * + * + * Copyright (C) 2005 Takahiro Hirofuchi + * - names_deinit() is added. + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <ctype.h> + +#include "names.h" +#include "usbip_common.h" + +struct vendor { + struct vendor *next; + u_int16_t vendorid; + char name[1]; +}; + +struct product { + struct product *next; + u_int16_t vendorid, productid; + char name[1]; +}; + +struct class { + struct class *next; + u_int8_t classid; + char name[1]; +}; + +struct subclass { + struct subclass *next; + u_int8_t classid, subclassid; + char name[1]; +}; + +struct protocol { + struct protocol *next; + u_int8_t classid, subclassid, protocolid; + char name[1]; +}; + +struct genericstrtable { + struct genericstrtable *next; + unsigned int num; + char name[1]; +}; + + +#define HASH1 0x10 +#define HASH2 0x02 +#define HASHSZ 16 + +static unsigned int hashnum(unsigned int num) +{ + unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27; + + for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1) + if (num & mask1) + num ^= mask2; + return num & (HASHSZ-1); +} + + +static struct vendor *vendors[HASHSZ] = { NULL, }; +static struct product *products[HASHSZ] = { NULL, }; +static struct class *classes[HASHSZ] = { NULL, }; +static struct subclass *subclasses[HASHSZ] = { NULL, }; +static struct protocol *protocols[HASHSZ] = { NULL, }; + +const char *names_vendor(u_int16_t vendorid) +{ + struct vendor *v; + + v = vendors[hashnum(vendorid)]; + for (; v; v = v->next) + if (v->vendorid == vendorid) + return v->name; + return NULL; +} + +const char *names_product(u_int16_t vendorid, u_int16_t productid) +{ + struct product *p; + + p = products[hashnum((vendorid << 16) | productid)]; + for (; p; p = p->next) + if (p->vendorid == vendorid && p->productid == productid) + return p->name; + return NULL; +} + +const char *names_class(u_int8_t classid) +{ + struct class *c; + + c = classes[hashnum(classid)]; + for (; c; c = c->next) + if (c->classid == classid) + return c->name; + return NULL; +} + +const char *names_subclass(u_int8_t classid, u_int8_t subclassid) +{ + struct subclass *s; + + s = subclasses[hashnum((classid << 8) | subclassid)]; + for (; s; s = s->next) + if (s->classid == classid && s->subclassid == subclassid) + return s->name; + return NULL; +} + +const char *names_protocol(u_int8_t classid, u_int8_t subclassid, + u_int8_t protocolid) +{ + struct protocol *p; + + p = protocols[hashnum((classid << 16) | (subclassid << 8) + | protocolid)]; + for (; p; p = p->next) + if (p->classid == classid && p->subclassid == subclassid && + p->protocolid == protocolid) + return p->name; + return NULL; +} + +/* add a cleanup function by takahiro */ +struct pool { + struct pool *next; + void *mem; +}; + +static struct pool *pool_head; + +static void *my_malloc(size_t size) +{ + struct pool *p; + + p = calloc(1, sizeof(struct pool)); + if (!p) + return NULL; + + p->mem = calloc(1, size); + if (!p->mem) { + free(p); + return NULL; + } + + p->next = pool_head; + pool_head = p; + + return p->mem; +} + +void names_free(void) +{ + struct pool *pool; + + if (!pool_head) + return; + + for (pool = pool_head; pool != NULL; ) { + struct pool *tmp; + + if (pool->mem) + free(pool->mem); + + tmp = pool; + pool = pool->next; + free(tmp); + } +} + +static int new_vendor(const char *name, u_int16_t vendorid) +{ + struct vendor *v; + unsigned int h = hashnum(vendorid); + + v = vendors[h]; + for (; v; v = v->next) + if (v->vendorid == vendorid) + return -1; + v = my_malloc(sizeof(struct vendor) + strlen(name)); + if (!v) + return -1; + strcpy(v->name, name); + v->vendorid = vendorid; + v->next = vendors[h]; + vendors[h] = v; + return 0; +} + +static int new_product(const char *name, u_int16_t vendorid, + u_int16_t productid) +{ + struct product *p; + unsigned int h = hashnum((vendorid << 16) | productid); + + p = products[h]; + for (; p; p = p->next) + if (p->vendorid == vendorid && p->productid == productid) + return -1; + p = my_malloc(sizeof(struct product) + strlen(name)); + if (!p) + return -1; + strcpy(p->name, name); + p->vendorid = vendorid; + p->productid = productid; + p->next = products[h]; + products[h] = p; + return 0; +} + +static int new_class(const char *name, u_int8_t classid) +{ + struct class *c; + unsigned int h = hashnum(classid); + + c = classes[h]; + for (; c; c = c->next) + if (c->classid == classid) + return -1; + c = my_malloc(sizeof(struct class) + strlen(name)); + if (!c) + return -1; + strcpy(c->name, name); + c->classid = classid; + c->next = classes[h]; + classes[h] = c; + return 0; +} + +static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid) +{ + struct subclass *s; + unsigned int h = hashnum((classid << 8) | subclassid); + + s = subclasses[h]; + for (; s; s = s->next) + if (s->classid == classid && s->subclassid == subclassid) + return -1; + s = my_malloc(sizeof(struct subclass) + strlen(name)); + if (!s) + return -1; + strcpy(s->name, name); + s->classid = classid; + s->subclassid = subclassid; + s->next = subclasses[h]; + subclasses[h] = s; + return 0; +} + +static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, + u_int8_t protocolid) +{ + struct protocol *p; + unsigned int h = hashnum((classid << 16) | (subclassid << 8) + | protocolid); + + p = protocols[h]; + for (; p; p = p->next) + if (p->classid == classid && p->subclassid == subclassid + && p->protocolid == protocolid) + return -1; + p = my_malloc(sizeof(struct protocol) + strlen(name)); + if (!p) + return -1; + strcpy(p->name, name); + p->classid = classid; + p->subclassid = subclassid; + p->protocolid = protocolid; + p->next = protocols[h]; + protocols[h] = p; + return 0; +} + +static void parse(FILE *f) +{ + char buf[512], *cp; + unsigned int linectr = 0; + int lastvendor = -1; + int lastclass = -1; + int lastsubclass = -1; + int lasthut = -1; + int lastlang = -1; + unsigned int u; + + while (fgets(buf, sizeof(buf), f)) { + linectr++; + /* remove line ends */ + cp = strchr(buf, '\r'); + if (cp) + *cp = 0; + cp = strchr(buf, '\n'); + if (cp) + *cp = 0; + if (buf[0] == '#' || !buf[0]) + continue; + cp = buf; + if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && + buf[3] == 'S' && buf[4] == 'D' && + buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ + buf[7] == ' ') { + continue; + } + if (buf[0] == 'P' && buf[1] == 'H' && + buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { + continue; + } + if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && + buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { + continue; + } + if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { + lasthut = lastclass = lastvendor = lastsubclass = -1; + /* + * set 1 as pseudo-id to indicate that the parser is + * in a `L' section. + */ + lastlang = 1; + continue; + } + if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { + /* class spec */ + cp = buf+2; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + err("Invalid class spec at line %u", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + err("Invalid class spec at line %u", linectr); + continue; + } + if (new_class(cp, u)) + err("Duplicate class spec at line %u class %04x %s", + linectr, u, cp); + dbg("line %5u class %02x %s", linectr, u, cp); + lasthut = lastlang = lastvendor = lastsubclass = -1; + lastclass = u; + continue; + } + if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { + /* audio terminal type spec */ + continue; + } + if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' + && isspace(buf[3])) { + /* HID Descriptor bCountryCode */ + continue; + } + if (isxdigit(*cp)) { + /* vendor */ + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + err("Invalid vendor spec at line %u", linectr); + continue; + } + if (new_vendor(cp, u)) + err("Duplicate vendor spec at line %u vendor %04x %s", + linectr, u, cp); + dbg("line %5u vendor %04x %s", linectr, u, cp); + lastvendor = u; + lasthut = lastlang = lastclass = lastsubclass = -1; + continue; + } + if (buf[0] == '\t' && isxdigit(buf[1])) { + /* product or subclass spec */ + u = strtoul(buf+1, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + err("Invalid product/subclass spec at line %u", + linectr); + continue; + } + if (lastvendor != -1) { + if (new_product(cp, lastvendor, u)) + err("Duplicate product spec at line %u product %04x:%04x %s", + linectr, lastvendor, u, cp); + dbg("line %5u product %04x:%04x %s", linectr, + lastvendor, u, cp); + continue; + } + if (lastclass != -1) { + if (new_subclass(cp, lastclass, u)) + err("Duplicate subclass spec at line %u class %02x:%02x %s", + linectr, lastclass, u, cp); + dbg("line %5u subclass %02x:%02x %s", linectr, + lastclass, u, cp); + lastsubclass = u; + continue; + } + if (lasthut != -1) { + /* do not store hut */ + continue; + } + if (lastlang != -1) { + /* do not store langid */ + continue; + } + err("Product/Subclass spec without prior Vendor/Class spec at line %u", + linectr); + continue; + } + if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { + /* protocol spec */ + u = strtoul(buf+2, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + err("Invalid protocol spec at line %u", + linectr); + continue; + } + if (lastclass != -1 && lastsubclass != -1) { + if (new_protocol(cp, lastclass, lastsubclass, + u)) + err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s", + linectr, lastclass, lastsubclass, + u, cp); + dbg("line %5u protocol %02x:%02x:%02x %s", + linectr, lastclass, lastsubclass, u, cp); + continue; + } + err("Protocol spec without prior Class and Subclass spec at line %u", + linectr); + continue; + } + if (buf[0] == 'H' && buf[1] == 'I' && + buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { + continue; + } + if (buf[0] == 'H' && buf[1] == 'U' && + buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { + lastlang = lastclass = lastvendor = lastsubclass = -1; + /* + * set 1 as pseudo-id to indicate that the parser is + * in a `HUT' section. + */ + lasthut = 1; + continue; + } + if (buf[0] == 'R' && buf[1] == ' ') + continue; + + if (buf[0] == 'V' && buf[1] == 'T') + continue; + + err("Unknown line at line %u", linectr); + } +} + + +int names_init(char *n) +{ + FILE *f; + + f = fopen(n, "r"); + if (!f) + return errno; + + parse(f); + fclose(f); + return 0; +} 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 @@ +/* + * names.h -- USB name database manipulation routines + * + * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * + * Copyright (C) 2005 Takahiro Hirofuchi + * - names_free() is added. + */ + +#ifndef _NAMES_H +#define _NAMES_H + +#include <sys/types.h> + +/* used by usbip_common.c */ +extern const char *names_vendor(u_int16_t vendorid); +extern const char *names_product(u_int16_t vendorid, u_int16_t productid); +extern const char *names_class(u_int8_t classid); +extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid); +extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, + u_int8_t protocolid); +extern int names_init(char *n); +extern void names_free(void); + +#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 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include "sysfs_utils.h" +#include "usbip_common.h" + +int write_sysfs_attribute(const char *attr_path, const char *new_value, + size_t len) +{ + int fd; + int length; + + fd = open(attr_path, O_WRONLY); + if (fd < 0) { + dbg("error opening attribute %s", attr_path); + return -1; + } + + length = write(fd, new_value, len); + if (length < 0) { + dbg("error writing to attribute %s", attr_path); + close(fd); + return -1; + } + + close(fd); + + return 0; +} 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 @@ + +#ifndef __SYSFS_UTILS_H +#define __SYSFS_UTILS_H + +int write_sysfs_attribute(const char *attr_path, const char *new_value, + size_t len); + +#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 @@ +/* + * Copyright (C) 2005-2007 Takahiro Hirofuchi + */ + +#include <libudev.h> +#include "usbip_common.h" +#include "names.h" + +#undef PROGNAME +#define PROGNAME "libusbip" + +int usbip_use_syslog; +int usbip_use_stderr; +int usbip_use_debug; + +extern struct udev *udev_context; + +struct speed_string { + int num; + char *speed; + char *desc; +}; + +static const struct speed_string speed_strings[] = { + { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"}, + { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" }, + { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" }, + { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, + { USB_SPEED_WIRELESS, "53.3-480", "Wireless"}, + { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" }, + { 0, NULL, NULL } +}; + +struct portst_string { + int num; + char *desc; +}; + +static struct portst_string portst_strings[] = { + { SDEV_ST_AVAILABLE, "Device Available" }, + { SDEV_ST_USED, "Device in Use" }, + { SDEV_ST_ERROR, "Device Error"}, + { VDEV_ST_NULL, "Port Available"}, + { VDEV_ST_NOTASSIGNED, "Port Initializing"}, + { VDEV_ST_USED, "Port in Use"}, + { VDEV_ST_ERROR, "Port Error"}, + { 0, NULL} +}; + +const char *usbip_status_string(int32_t status) +{ + for (int i = 0; portst_strings[i].desc != NULL; i++) + if (portst_strings[i].num == status) + return portst_strings[i].desc; + + return "Unknown Status"; +} + +const char *usbip_speed_string(int num) +{ + for (int i = 0; speed_strings[i].speed != NULL; i++) + if (speed_strings[i].num == num) + return speed_strings[i].desc; + + return "Unknown Speed"; +} + + +#define DBG_UDEV_INTEGER(name)\ + dbg("%-20s = %x", to_string(name), (int) udev->name) + +#define DBG_UINF_INTEGER(name)\ + dbg("%-20s = %x", to_string(name), (int) uinf->name) + +void dump_usb_interface(struct usbip_usb_interface *uinf) +{ + char buff[100]; + + usbip_names_get_class(buff, sizeof(buff), + uinf->bInterfaceClass, + uinf->bInterfaceSubClass, + uinf->bInterfaceProtocol); + dbg("%-20s = %s", "Interface(C/SC/P)", buff); +} + +void dump_usb_device(struct usbip_usb_device *udev) +{ + char buff[100]; + + dbg("%-20s = %s", "path", udev->path); + dbg("%-20s = %s", "busid", udev->busid); + + usbip_names_get_class(buff, sizeof(buff), + udev->bDeviceClass, + udev->bDeviceSubClass, + udev->bDeviceProtocol); + dbg("%-20s = %s", "Device(C/SC/P)", buff); + + DBG_UDEV_INTEGER(bcdDevice); + + usbip_names_get_product(buff, sizeof(buff), + udev->idVendor, + udev->idProduct); + dbg("%-20s = %s", "Vendor/Product", buff); + + DBG_UDEV_INTEGER(bNumConfigurations); + DBG_UDEV_INTEGER(bNumInterfaces); + + dbg("%-20s = %s", "speed", + usbip_speed_string(udev->speed)); + + DBG_UDEV_INTEGER(busnum); + DBG_UDEV_INTEGER(devnum); +} + + +int read_attr_value(struct udev_device *dev, const char *name, + const char *format) +{ + const char *attr; + int num = 0; + int ret; + + attr = udev_device_get_sysattr_value(dev, name); + if (!attr) { + err("udev_device_get_sysattr_value failed"); + goto err; + } + + /* The client chooses the device configuration + * when attaching it so right after being bound + * to usbip-host on the server the device will + * have no configuration. + * Therefore, attributes such as bConfigurationValue + * and bNumInterfaces will not exist and sscanf will + * fail. Check for these cases and don't treat them + * as errors. + */ + + ret = sscanf(attr, format, &num); + if (ret < 1) { + if (strcmp(name, "bConfigurationValue") && + strcmp(name, "bNumInterfaces")) { + err("sscanf failed for attribute %s", name); + goto err; + } + } + +err: + + return num; +} + + +int read_attr_speed(struct udev_device *dev) +{ + const char *speed; + + speed = udev_device_get_sysattr_value(dev, "speed"); + if (!speed) { + err("udev_device_get_sysattr_value failed"); + goto err; + } + + for (int i = 0; speed_strings[i].speed != NULL; i++) { + if (!strcmp(speed, speed_strings[i].speed)) + return speed_strings[i].num; + } + +err: + + return USB_SPEED_UNKNOWN; +} + +#define READ_ATTR(object, type, dev, name, format) \ + do { \ + (object)->name = (type) read_attr_value(dev, to_string(name), \ + format); \ + } while (0) + + +int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev) +{ + uint32_t busnum, devnum; + const char *path, *name; + + READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n"); + READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n"); + READ_ATTR(udev, uint8_t, sdev, bDeviceProtocol, "%02x\n"); + + READ_ATTR(udev, uint16_t, sdev, idVendor, "%04x\n"); + READ_ATTR(udev, uint16_t, sdev, idProduct, "%04x\n"); + READ_ATTR(udev, uint16_t, sdev, bcdDevice, "%04x\n"); + + READ_ATTR(udev, uint8_t, sdev, bConfigurationValue, "%02x\n"); + READ_ATTR(udev, uint8_t, sdev, bNumConfigurations, "%02x\n"); + READ_ATTR(udev, uint8_t, sdev, bNumInterfaces, "%02x\n"); + + READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n"); + udev->speed = read_attr_speed(sdev); + + path = udev_device_get_syspath(sdev); + name = udev_device_get_sysname(sdev); + + strncpy(udev->path, path, SYSFS_PATH_MAX); + strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE); + + sscanf(name, "%u-%u", &busnum, &devnum); + udev->busnum = busnum; + + return 0; +} + +int read_usb_interface(struct usbip_usb_device *udev, int i, + struct usbip_usb_interface *uinf) +{ + char busid[SYSFS_BUS_ID_SIZE]; + struct udev_device *sif; + + sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); + + sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); + if (!sif) { + err("udev_device_new_from_subsystem_sysname %s failed", busid); + return -1; + } + + READ_ATTR(uinf, uint8_t, sif, bInterfaceClass, "%02x\n"); + READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n"); + READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n"); + + return 0; +} + +int usbip_names_init(char *f) +{ + return names_init(f); +} + +void usbip_names_free(void) +{ + names_free(); +} + +void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, + uint16_t product) +{ + const char *prod, *vend; + + prod = names_product(vendor, product); + if (!prod) + prod = "unknown product"; + + + vend = names_vendor(vendor); + if (!vend) + vend = "unknown vendor"; + + snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product); +} + +void usbip_names_get_class(char *buff, size_t size, uint8_t class, + uint8_t subclass, uint8_t protocol) +{ + const char *c, *s, *p; + + if (class == 0 && subclass == 0 && protocol == 0) { + snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol); + return; + } + + p = names_protocol(class, subclass, protocol); + if (!p) + p = "unknown protocol"; + + s = names_subclass(class, subclass); + if (!s) + s = "unknown subclass"; + + c = names_class(class); + if (!c) + c = "unknown class"; + + snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol); +} 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 @@ +/* + * Copyright (C) 2005-2007 Takahiro Hirofuchi + */ + +#ifndef __USBIP_COMMON_H +#define __USBIP_COMMON_H + +#include <libudev.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <syslog.h> +#include <unistd.h> +#include <linux/usb/ch9.h> +#include "../../uapi/usbip.h" + +#ifndef USBIDS_FILE +#define USBIDS_FILE "/usr/share/hwdata/usb.ids" +#endif |