diff options
author | Hans de Goede <hdegoede@redhat.com> | 2012-02-09 13:03:29 +0100 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2012-02-20 16:14:49 +0100 |
commit | e41a11d1b77bcab1bc654e5b9294264bc7df9ba7 (patch) | |
tree | 5dd8abaf74647118fea65906bd316cdc2e989db8 | |
parent | 97648e4d0769f01800af21e43aeffee50aca503d (diff) |
usbutil: Add support for getting strings from usb.ids
Unfortunately not all device makers go to the "trouble" of adding device
identification strings to a device's descriptors. This patch makes spice-gtk
translate vid/pid into strings if the device lacks the strings.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | configure.ac | 21 | ||||
-rw-r--r-- | gtk/Makefile.am | 1 | ||||
-rw-r--r-- | gtk/usbutil.c | 150 |
3 files changed, 172 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index 28b3418..5cd49bc 100644 --- a/configure.ac +++ b/configure.ac @@ -426,6 +426,27 @@ AC_ARG_WITH([usb-acl-helper-dir], [ACL_HELPER_DIR="${bindir}/"]) AC_SUBST([ACL_HELPER_DIR]) +AC_ARG_WITH([usb-ids-path], + AC_HELP_STRING([--with-usb-ids-path], + [Specify the path to usb.ids @<:@default=auto@:>@]), + [USB_IDS="$with_usb_ids_path"], + [USB_IDS="auto"]) +AC_MSG_CHECKING([for usb.ids]) +if test "x$USB_IDS" = "xauto"; then + if test -n "$PKG_CONFIG"; then + USB_IDS=$($PKG_CONFIG --variable=usbids usbutils) + else + USB_IDS= + fi +fi +if test -n "$USB_IDS"; then + AC_MSG_RESULT([$USB_IDS]) + AC_SUBST(USB_IDS) + AC_DEFINE(WITH_USBIDS, [1], [Define if compiling with usb.ids support]) +else + AC_MSG_RESULT([not found]) +fi + AC_ARG_WITH([coroutine], AS_HELP_STRING([--with-coroutine=@<:@ucontext/gthread/winfiber/auto@:>@], [use ucontext or GThread for coroutines @<:@default=auto@:>@]), diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 2ad4494..fd2e477 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -60,6 +60,7 @@ SPICE_COMMON_CPPFLAGS = \ -DSW_CANVAS_CACHE \ -DSPICE_GTK_LOCALEDIR=\"${SPICE_GTK_LOCALEDIR}\" \ -DPNP_IDS=\""$(PNP_IDS)"\"\ + -DUSB_IDS=\""$(USB_IDS)"\"\ \ -I$(COMMON_DIR) \ -I$(CLIENT_DIR) \ diff --git a/gtk/usbutil.c b/gtk/usbutil.c index 0d1361e..704f973 100644 --- a/gtk/usbutil.c +++ b/gtk/usbutil.c @@ -23,6 +23,8 @@ #include <glib-object.h> #include <glib/gi18n.h> +#include <ctype.h> +#include <stdlib.h> #include "glib-compat.h" @@ -35,6 +37,27 @@ #endif #include "usbutil.h" +#ifdef WITH_USBIDS +#define VENDOR_NAME_LEN (122 - sizeof(void *)) +#define PRODUCT_NAME_LEN 126 + +typedef struct _usb_product_info { + guint16 product_id; + char name[PRODUCT_NAME_LEN]; +} usb_product_info; + +typedef struct _usb_vendor_info { + usb_product_info *product_info; + int product_count; + guint16 vendor_id; + char name[VENDOR_NAME_LEN]; +} usb_vendor_info; + +GStaticMutex usbids_parse_mutex = G_STATIC_MUTEX_INIT; +int usbids_vendor_count; +usb_vendor_info *usbids_vendor_info; +#endif + G_GNUC_INTERNAL const char *spice_usbutil_libusb_strerror(enum libusb_error error_code) { @@ -98,11 +121,112 @@ static gchar *spice_usbutil_get_sysfs_attribute(int bus, int address, } #endif +#ifdef WITH_USBIDS +static void spice_usbutil_parse_usbids(void) +{ + gchar *contents, *line, **lines; + usb_product_info *product_info; + int i, j, id, product_count = 0; + + g_static_mutex_lock(&usbids_parse_mutex); + if (usbids_vendor_count) + goto leave; + + if (!g_file_get_contents(USB_IDS, &contents, NULL, NULL)) { + usbids_vendor_count = -1; + goto leave; + } + lines = g_strsplit(contents, "\n", -1); + + for (i = 0; lines[i]; i++) { + if (!isxdigit(lines[i][0]) || !isxdigit(lines[i][1])) + continue; + + for (j = 1; lines[i + j] && + (lines[i + j][0] == '\t' || + lines[i + j][0] == '#' || + lines[i + j][0] == '\0'); j++) { + if (lines[i + j][0] == '\t' && isxdigit(lines[i + j][1])) + product_count++; + } + i += j - 1; + + usbids_vendor_count++; + } + + usbids_vendor_info = g_new(usb_vendor_info, usbids_vendor_count); + product_info = g_new(usb_product_info, product_count); + + usbids_vendor_count = 0; + for (i = 0; lines[i]; i++) { + line = lines[i]; + + if (!isxdigit(line[0]) || !isxdigit(line[1])) + continue; + + id = strtoul(line, &line, 16); + while(isspace(line[0])) + line++; + usbids_vendor_info[usbids_vendor_count].vendor_id = id; + snprintf(usbids_vendor_info[usbids_vendor_count].name, + VENDOR_NAME_LEN, "%s", line); + + product_count = 0; + for (j = 1; lines[i + j] && + (lines[i + j][0] == '\t' || + lines[i + j][0] == '#' || + lines[i + j][0] == '\0'); j++) { + line = lines[i + j]; + + if (line[0] != '\t' || !isxdigit(line[1])) + continue; + + id = strtoul(line + 1, &line, 16); + while(isspace(line[0])) + line++; + product_info[product_count].product_id = id; + snprintf(product_info[product_count].name, + PRODUCT_NAME_LEN, "%s", line); + + product_count++; + } + i += j - 1; + + usbids_vendor_info[usbids_vendor_count].product_count = product_count; + usbids_vendor_info[usbids_vendor_count].product_info = product_info; + product_info += product_count; + usbids_vendor_count++; + } + + g_strfreev(lines); + g_free(contents); + +#if 0 /* Testing only */ + for (i = 0; i < usbids_vendor_count; i++) { + printf("%04x %s\n", usbids_vendor_info[i].vendor_id, + usbids_vendor_info[i].name); + product_info = usbids_vendor_info[i].product_info; + for (j = 0; j < usbids_vendor_info[i].product_count; j++) { + printf("\t%04x %s\n", product_info[j].product_id, + product_info[j].name); + } + } +#endif +leave: + g_static_mutex_unlock(&usbids_parse_mutex); +} +#endif + G_GNUC_INTERNAL void spice_usb_util_get_device_strings(int bus, int address, int vendor_id, int product_id, gchar **manufacturer, gchar **product) { +#ifdef WITH_USBIDS + usb_product_info *product_info; + int i, j; +#endif + g_return_if_fail(manufacturer != NULL); g_return_if_fail(product != NULL); @@ -113,6 +237,32 @@ void spice_usb_util_get_device_strings(int bus, int address, *manufacturer = spice_usbutil_get_sysfs_attribute(bus, address, "manufacturer"); *product = spice_usbutil_get_sysfs_attribute(bus, address, "product"); #endif + +#ifdef WITH_USBIDS + if (!*manufacturer || !*product) { + spice_usbutil_parse_usbids(); + + for (i = 0; i < usbids_vendor_count; i++) { + if ((int)usbids_vendor_info[i].vendor_id != vendor_id) + continue; + + if (!*manufacturer && usbids_vendor_info[i].name[0]) + *manufacturer = g_strdup(usbids_vendor_info[i].name); + + product_info = usbids_vendor_info[i].product_info; + for (j = 0; j < usbids_vendor_info[i].product_count; j++) { + if ((int)product_info[j].product_id != product_id) + continue; + + if (!*product && product_info[j].name[0]) + *product = g_strdup(product_info[j].name); + + break; + } + break; + } + } +#endif if (!*manufacturer) *manufacturer = g_strdup(_("USB")); if (!*product) |