diff options
author | Burt P <pburt0@gmail.com> | 2017-08-18 02:14:47 -0500 |
---|---|---|
committer | Leandro A. F. Pereira <leandro@hardinfo.org> | 2018-03-12 09:20:16 -0700 |
commit | fdb1a05b6b5c84b67e3df107288f5046b763647e (patch) | |
tree | 57a18f80dac7cd11b5a571eef0d3a69ae096edcc | |
parent | 9154a9ab51a62180298dbd71c3cdac3f07f7b2a1 (diff) |
usb_util.c
A set of functions for getting information for a single USB device,
or a list of all devices.
The only implemented method is using `lsusb`, which is slow. A
method using sysfs would be much better. The existing sysfs and
procfs methods in devices/usb.c do not appear to work, so it would
have to be something new.
devices/usb.c modified to use usb_util, but all the old code is
still there.
Signed-off-by: Burt P <pburt0@gmail.com>
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | hardinfo/usb_util.c | 185 | ||||
-rw-r--r-- | includes/usb_util.h | 35 | ||||
-rw-r--r-- | modules/devices.c | 7 | ||||
-rw-r--r-- | modules/devices/usb.c | 92 |
5 files changed, 313 insertions, 8 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8038aead..bc480146 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,6 +214,7 @@ endif() if (HARDINFO_GTK3) add_executable(hardinfo + hardinfo/usb_util.c hardinfo/binreloc.c hardinfo/expr.c hardinfo/hardinfo.c @@ -242,6 +243,7 @@ target_link_libraries(hardinfo ) else() add_executable(hardinfo + hardinfo/usb_util.c hardinfo/binreloc.c hardinfo/expr.c hardinfo/hardinfo.c diff --git a/hardinfo/usb_util.c b/hardinfo/usb_util.c new file mode 100644 index 00000000..e1db2777 --- /dev/null +++ b/hardinfo/usb_util.c @@ -0,0 +1,185 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2017 Leandro A. F. Pereira <leandro@hardinfo.org> + * This file + * Copyright (C) 2017 Burt P. <pburt0@gmail.com> + * + * 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, version 2. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hardinfo.h" +#include "usb_util.h" + +usbd *usbd_new() { + usbd *s = malloc(sizeof(usbd)); + if (s) { + memset(s, 0, sizeof(usbd)); + } + return s; +} + +void usbd_free(usbd *s) { + if (s) { + free(s->vendor); + free(s->product); + free(s->usb_version); + free(s->device_version); + free(s->dev_class_str); + free(s->dev_subclass_str); + free(s); + } +} + +void usbd_list_free(usbd *s) { + usbd *n; + while(s != NULL) { + n = s->next; + usbd_free(s); + s = n; + } +} + +/* returns number of items after append */ +int usbd_list_append(usbd *l, usbd *n) { + int c = 0; + while(l != NULL) { + c++; + if (l->next == NULL) { + if (n != NULL) { + l->next = n; + c++; + } + break; + } + l = l->next; + } + return c; +} + +int usbd_list_count(usbd *s) { + return usbd_list_append(s, NULL); +} + +char *_lsusb_lv(char *line, const char *prefix) { + if ( g_str_has_prefix(line, prefix) ) { + line += strlen(prefix) + 1; + return g_strstrip(line); + } else + return NULL; +} + +int usb_get_device_lsusb(int bus, int dev, usbd *s) { + gboolean spawned; + gchar *out, *err, *p, *l, *t, *next_nl; + gchar *lsusb_cmd = g_strdup_printf("lsusb -s %d:%d -v", bus, dev); + + s->bus = bus; + s->dev = dev; + + spawned = g_spawn_command_line_sync(lsusb_cmd, + &out, &err, NULL, NULL); + g_free(lsusb_cmd); + if (spawned) { + if (strstr(err, "information will be missing")) { + s->user_scan = 1; + } + p = out; + while(next_nl = strchr(p, '\n')) { + strend(p, '\n'); + g_strstrip(p); + if (l = _lsusb_lv(p, "idVendor")) { + s->vendor_id = strtol(l, NULL, 0); + if (t = strchr(l, ' ')) + s->vendor = strdup(t + 1); + } else if (l = _lsusb_lv(p, "idProduct")) { + s->product_id = strtol(l, NULL, 0); + if (t = strchr(l, ' ')) + s->product = strdup(t + 1); + } else if (l = _lsusb_lv(p, "MaxPower")) { + s->max_curr_ma = atoi(l); + } else if (l = _lsusb_lv(p, "bcdUSB")) { + s->usb_version = strdup(l); + } else if (l = _lsusb_lv(p, "bcdDevice")) { + s->device_version = strdup(l); + } else if (l = _lsusb_lv(p, "bDeviceClass")) { + s->dev_class = atoi(l); + if (t = strchr(l, ' ')) + s->dev_class_str = strdup(t + 1); + } else if (l = _lsusb_lv(p, "bDeviceSubClass")) { + s->dev_subclass = atoi(l); + if (t = strchr(l, ' ')) + s->dev_subclass_str = strdup(t + 1); + } + /* TODO: speed_mbs + * WISHLIST: interfaces, drivers */ + p = next_nl + 1; + } + g_free(out); + g_free(err); + return 1; + } + return 0; +} + +usbd *usb_get_device(int bus, int dev) { + usbd *s = usbd_new(); + int ok = 0; + if (s) { + /* try lsusb */ + ok = usb_get_device_lsusb(bus, dev, s); + + /* TODO: other methods */ + + if (!ok) { + usbd_free(s); + s = NULL; + } + } + return s; +} + +usbd *usb_get_device_list_lsusb() { + gboolean spawned; + gchar *out, *err, *p, *next_nl; + usbd *head = NULL, *nd; + int bus, dev, vend, prod, ec; + + spawned = g_spawn_command_line_sync("lsusb", + &out, &err, NULL, NULL); + if (spawned) { + p = out; + while(next_nl = strchr(p, '\n')) { + strend(p, '\n'); + if (ec = sscanf(p, "Bus %d Device %d: ID %x:%x", &bus, &dev, &vend, &prod) ) { + nd = usb_get_device(bus, dev); + if (head == NULL) { + head = nd; + } else { + usbd_list_append(head, nd); + } + } + p = next_nl + 1; + } + g_free(out); + g_free(err); + } + return head; +} + +usbd *usb_get_device_list() { + /* try lsusb */ + return usb_get_device_list_lsusb(); + + /* TODO: other methods */ +} diff --git a/includes/usb_util.h b/includes/usb_util.h new file mode 100644 index 00000000..5d7f55bf --- /dev/null +++ b/includes/usb_util.h @@ -0,0 +1,35 @@ +#ifndef __USB_UTIL_H__ +#define __USB_UTIL_H__ + +/* this is a linked list */ +typedef struct usbd { + int bus, dev; + int vendor_id, product_id; + char *vendor; + char *product; + + int dev_class; + int dev_subclass; + char *dev_class_str; + char *dev_subclass_str; + + char *usb_version; + char *device_version; /* bcdDevice */ + + int max_curr_ma; + + int speed_mbs; /* TODO: */ + + int user_scan; /* not scanned as root */ + + struct usbd *next; +} usbd; + +usbd *usb_get_device_list(); +int usbd_list_count(usbd *); +void usbd_list_free(usbd *); + +usbd *usb_get_device(int bus, int dev); +void usbd_free(usbd *); + +#endif diff --git a/modules/devices.c b/modules/devices.c index 152b6831..5e757c15 100644 --- a/modules/devices.c +++ b/modules/devices.c @@ -635,9 +635,10 @@ gchar *callback_input() gchar *callback_usb() { return g_strdup_printf("%s" - "[$ShellParam$]\n" - "ViewType=1\n" - "ReloadInterval=5000\n", usb_list); + "[$ShellParam$]\n" + "ViewType=1\n" + "ReloadInterval=5000\n", usb_list); + } ModuleEntry *hi_module_get_entries(void) diff --git a/modules/devices/usb.c b/modules/devices/usb.c index 9366c7ce..27b3c13e 100644 --- a/modules/devices/usb.c +++ b/modules/devices/usb.c @@ -24,6 +24,7 @@ #include "hardinfo.h" #include "devices.h" +#include "usb_util.h" gchar *usb_list = NULL; @@ -426,11 +427,92 @@ gboolean __scan_usb_lsusb(void) return usb_device_number > 0; } -void __scan_usb(void) -{ - if (!__scan_usb_procfs()) { - if (!__scan_usb_sysfs()) { - __scan_usb_lsusb(); +#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)"); + +void _usb_dev(const usbd *u) { + gchar *name, *key, *v_str, *str; + gchar *product, *vendor, *dev_class_str, *dev_subclass_str; /* don't free */ + + vendor = UNKIFNULL_AC(u->vendor); + product = UNKIFNULL_AC(u->product); + dev_class_str = UNKIFNULL_AC(u->dev_class_str); + dev_subclass_str = UNKIFNULL_AC(u->dev_subclass_str); + + name = g_strdup_printf("%s %s", vendor, product); + key = g_strdup_printf("USB%03d:%03d:%03d", u->bus, u->dev, 0); + + usb_list = h_strdup_cprintf("$%s$%03d:%03d=%s\n", usb_list, key, u->bus, u->dev, name); + + const gchar *v_url = vendor_get_url(vendor); + const gchar *v_name = vendor_get_name(vendor); + if (v_url != NULL) { + v_str = g_strdup_printf("%s (%s)", v_name, v_url); + } else { + v_str = g_strdup_printf("%s", vendor ); + } + + str = g_strdup_printf("[%s]\n" + /* Product */ "%s=[0x%04x] %s\n" + /* Manufacturer */ "%s=[0x%04x] %s\n" + /* Max Current */ "%s=%d %s\n" + /* USB Version */ "%s=%s\n" + /* Class */ "%s=[%d] %s\n" + /* Sub-class */ "%s=[%d] %s\n" + /* Dev Version */ "%s=%s\n" + "[%s]\n" + /* Bus */ "%s=%03d\n" + /* Device */ "%s=%03d\n", + _("Device Information"), + _("Product"), u->product_id, product, + _("Vendor"), u->vendor_id, v_str, + _("Max Current"), u->max_curr_ma, _("mA"), + _("USB Version"), u->usb_version, + _("Class"), u->dev_class, dev_class_str, + _("Sub-class"), u->dev_subclass, dev_subclass_str, + _("Device Version"), u->device_version, + _("Connection"), + _("Bus"), u->bus, + _("Device"), u->dev + ); + + moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */ + + g_free(v_str); + g_free(name); + g_free(key); +} + +gboolean __scan_usb_util(void) { + usbd *list = usb_get_device_list(); + usbd *curr = list; + + int c = usbd_list_count(list); + + if (c > 0) { + if (usb_list) { + moreinfo_del_with_prefix("DEV:USB"); + g_free(usb_list); + } + usb_list = g_strdup_printf("[%s]\n", _("USB Devices")); + + while(curr) { + //printf("USB: Bus %03d Dev %03d Ven %04x Prod %04x %s %s\n", + // curr->bus, curr->dev, curr->vendor_id, curr->product_id, curr->vendor, curr->product); + _usb_dev(curr); + c++; + curr=curr->next; } + + usbd_list_free(list); + return TRUE; } + return FALSE; +} + +void __scan_usb(void) +{ + if (!__scan_usb_util()) + if (!__scan_usb_procfs()) + if (!__scan_usb_sysfs()) + __scan_usb_lsusb(); } |