summaryrefslogtreecommitdiff
path: root/gusb/gusb-context.c
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2015-01-05 15:59:10 +0000
committerRichard Hughes <richard@hughsie.com>2015-01-05 15:59:10 +0000
commitc82ad302b129c50c60df633e7a9c6909d11b2d1c (patch)
treed9507b3f20cbec05cc999e1d63dfc82353889a10 /gusb/gusb-context.c
parent1475a82804db825ea56726287620449fb054feda (diff)
downloadgusb-c82ad302b129c50c60df633e7a9c6909d11b2d1c.tar.gz
context: Load usb.ids if required
Diffstat (limited to 'gusb/gusb-context.c')
-rw-r--r--gusb/gusb-context.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/gusb/gusb-context.c b/gusb/gusb-context.c
index d952f5c..a91899c 100644
--- a/gusb/gusb-context.c
+++ b/gusb/gusb-context.c
@@ -30,6 +30,7 @@
#include <libusb-1.0/libusb.h>
+#include "gusb-cleanup.h"
#include "gusb-context.h"
#include "gusb-context-private.h"
#include "gusb-device-private.h"
@@ -56,6 +57,7 @@ enum {
struct _GUsbContextPrivate
{
GPtrArray *devices;
+ GHashTable *dict_usb_ids;
GThread *thread_event;
gboolean done_enumerate;
volatile gint thread_event_run;
@@ -102,6 +104,7 @@ g_usb_context_dispose (GObject *object)
}
g_clear_pointer (&priv->devices, g_ptr_array_unref);
+ g_clear_pointer (&priv->dict_usb_ids, g_hash_table_unref);
g_clear_pointer (&priv->ctx, libusb_exit);
G_OBJECT_CLASS (g_usb_context_parent_class)->dispose (object);
@@ -446,6 +449,7 @@ g_usb_context_init (GUsbContext *context)
priv = context->priv = g_usb_context_get_instance_private (context);
priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ priv->dict_usb_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
}
static gboolean
@@ -674,6 +678,125 @@ g_usb_context_find_by_vid_pid (GUsbContext *context,
return device;
}
+static gboolean
+g_usb_context_load_usb_ids (GUsbContext *context, GError **error)
+{
+ guint16 pid;
+ guint16 vid = 0x0000;
+ guint i;
+ _cleanup_free_ gchar *data = NULL;
+ _cleanup_strv_free_ gchar **lines = NULL;
+
+ /* already loaded */
+ if (g_hash_table_size (context->priv->dict_usb_ids) > 0)
+ return TRUE;
+
+ /* parse */
+ if (!g_file_get_contents ("/usr/share/hwdata/usb.ids", &data, NULL, error))
+ return FALSE;
+ lines = g_strsplit (data, "\n", -1);
+ for (i = 0; lines[i] != NULL; i++) {
+ if (lines[i][0] == '#')
+ continue;
+ if (lines[i][0] == '\0')
+ continue;
+ if (lines[i][0] != '\t') {
+ lines[i][4] = '\0';
+ vid = g_ascii_strtoull (lines[i], NULL, 16);
+ if (vid == 0)
+ break;
+ g_hash_table_insert (context->priv->dict_usb_ids,
+ g_strdup (lines[i]),
+ g_strdup (lines[i] + 6));
+ } else {
+ if (vid == 0x0000)
+ break;
+ lines[i][5] = '\0';
+ pid = g_ascii_strtoull (lines[i] + 1, NULL, 16);
+ g_hash_table_insert (context->priv->dict_usb_ids,
+ g_strdup_printf ("%04x:%04x", vid, pid),
+ g_strdup (lines[i] + 7));
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * _g_usb_context_lookup_vendor:
+ * @context: a #GUsbContext
+ * @vid: a USB vendor ID
+ * @error: a #GError, or %NULL
+ *
+ * Returns the vendor name using usb.ids.
+ *
+ * Return value: the description, or %NULL
+ *
+ * Since: 0.1.5
+ **/
+const gchar *
+_g_usb_context_lookup_vendor (GUsbContext *context, guint16 vid, GError **error)
+{
+ const gchar *tmp;
+ _cleanup_free_ gchar *key = NULL;
+
+ g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ /* load */
+ if (!g_usb_context_load_usb_ids (context, error))
+ return NULL;
+
+ /* find */
+ key = g_strdup_printf ("%04x", vid);
+ tmp = g_hash_table_lookup (context->priv->dict_usb_ids, key);
+ if (tmp == NULL) {
+ g_set_error (error,
+ G_USB_CONTEXT_ERROR,
+ G_USB_CONTEXT_ERROR_INTERNAL,
+ "failed to find vid %s", key);
+ return NULL;
+ }
+ return tmp;
+}
+
+/**
+ * _g_usb_context_lookup_product:
+ * @context: a #GUsbContext
+ * @vid: a USB vendor ID
+ * @pid: a USB product ID
+ * @error: a #GError, or %NULL
+ *
+ * Returns the product name using usb.ids.
+ *
+ * Return value: the description, or %NULL
+ *
+ * Since: 0.1.5
+ **/
+const gchar *
+_g_usb_context_lookup_product (GUsbContext *context, guint16 vid, guint16 pid, GError **error)
+{
+ const gchar *tmp;
+ _cleanup_free_ gchar *key = NULL;
+
+ g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ /* load */
+ if (!g_usb_context_load_usb_ids (context, error))
+ return NULL;
+
+ /* find */
+ key = g_strdup_printf ("%04x:%04x", vid, pid);
+ tmp = g_hash_table_lookup (context->priv->dict_usb_ids, key);
+ if (tmp == NULL) {
+ g_set_error (error,
+ G_USB_CONTEXT_ERROR,
+ G_USB_CONTEXT_ERROR_INTERNAL,
+ "failed to find vid %s", key);
+ return NULL;
+ }
+ return tmp;
+}
/**
* g_usb_context_get_devices: