aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--hardinfo/usb_util.c185
-rw-r--r--includes/usb_util.h35
-rw-r--r--modules/devices.c7
-rw-r--r--modules/devices/usb.c92
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();
}