diff options
author | Lennart Poettering <lennart@poettering.net> | 2009-02-26 01:59:45 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2009-02-26 03:18:22 +0100 |
commit | 4cbf05876a0dd309e7e617bc2a14a463d083fefa (patch) | |
tree | d6a691f69f709c61dd944fef259a663c892fc329 /usb-db | |
parent | 460dfb712078121fff0a25ec7b91bbaf069a14c8 (diff) |
add usb-db for reading usb vendor/product data from usb.ids
Diffstat (limited to 'usb-db')
-rw-r--r-- | usb-db/.gitignore | 1 | ||||
-rw-r--r-- | usb-db/Makefile.am | 11 | ||||
-rw-r--r-- | usb-db/usb-db.c | 222 |
3 files changed, 234 insertions, 0 deletions
diff --git a/usb-db/.gitignore b/usb-db/.gitignore new file mode 100644 index 0000000..156b3fc --- /dev/null +++ b/usb-db/.gitignore @@ -0,0 +1 @@ +usb-db diff --git a/usb-db/Makefile.am b/usb-db/Makefile.am new file mode 100644 index 0000000..46c5abb --- /dev/null +++ b/usb-db/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/Makefile.am.inc + +udevhomedir = $(udev_prefix)/lib/udev +udevhome_PROGRAMS = usb-db + +usb_db_SOURCES = usb-db.c +usb_db_CPPFLAGS = $(AM_CPPFLAGS) $(LIBUDEV_CFLAGS) -DUSB_DATABASE=\"/usr/share/hwdata/usb.ids\" +usb_db_LDADD = $(LIBUDEV_LIBS) + +#udevrulesdir = $(udev_prefix)/lib/udev/rules.d +#dist_udevrules_DATA = 77-probe-modem-capabilities.rules diff --git a/usb-db/usb-db.c b/usb-db/usb-db.c new file mode 100644 index 0000000..58713ee --- /dev/null +++ b/usb-db/usb-db.c @@ -0,0 +1,222 @@ +/*-*- linux-c -*-*/ + +/* + * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net> + * + * 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: + */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <inttypes.h> +#include <ctype.h> +#include <stdlib.h> + +#include <libudev.h> + +static int get_vid_pid( + struct udev_device *usb, + uint16_t *vid, + uint16_t *pid) { + + const char *t; + + if ((t = udev_device_get_sysattr_value(usb, "idVendor"))) { + unsigned u; + + if (sscanf(t, "%04x", &u) != 1 || u <= 0 || u > 0xFFFFU) { + fprintf(stderr, "Failed to parse idVendor on %s.\n", udev_device_get_syspath(usb)); + return -1; + } + + *vid = (uint16_t) u; + } + + if ((t = udev_device_get_sysattr_value(usb, "idProduct"))) { + unsigned u; + + if (sscanf(t, "%04x", &u) != 1 || u > 0xFFFFU) { + fprintf(stderr, "Failed to parse idProduct on %s.\n", udev_device_get_syspath(usb)); + return -1; + } + + *pid = (uint16_t) u; + } + + return 0; +} + +static void rstrip(char *n) { + size_t i; + + for (i = strlen(n); i > 0 && isspace(n[i-1]); i--) + n[i-1] = 0; +} + +#define HEXCHARS "0123456789abcdefABCDEF" +#define WHITESPACE " \t\n\r" + +static int lookup_vid_pid( + uint16_t vid, + uint16_t pid, + char **vendor, + char **product) { + + FILE *f; + int ret = -1; + int found_vendor = 0; + char *line = NULL; + + *vendor = *product = NULL; + + if (!(f = fopen(USB_DATABASE, "r"))) { + fprintf(stderr, "Failed to open database file "USB_DATABASE": %s", strerror(errno)); + return -1; + } + + for (;;) { + size_t n; + + if (line) { + free(line); + line = NULL; + } + + if (getline(&line, &n, f) < 0) + break; + + rstrip(line); + + if (line[0] == '#' || line[0] == 0) + continue; + + if (strspn(line, HEXCHARS) == 4) { + unsigned u; + + if (found_vendor) + break; + + if (sscanf(line, "%04x", &u) == 1 && u == vid) { + char *t; + + t = line+4; + t += strspn(t, WHITESPACE); + + if (!(*vendor = strdup(t))) { + fprintf(stderr, "Out of memory.\n"); + goto finish; + } + + found_vendor = 1; + } + + continue; + } + + if (found_vendor && line[0] == '\t' && strspn(line+1, HEXCHARS) == 4) { + unsigned u; + + if (sscanf(line+1, "%04x", &u) == 1 && u == pid) { + char *t; + + t = line+5; + t += strspn(t, WHITESPACE); + + if (!(*product = strdup(t))) { + fprintf(stderr, "Out of memory.\n"); + goto finish; + } + + break; + } + } + } + + ret = 0; + +finish: + free(line); + + fclose(f); + + if (ret < 0) { + free(*product); + free(*vendor); + + *product = *vendor = NULL; + } + + return ret; +} + +int main(int argc, char*argv[]) { + + struct udev *udev = NULL; + int ret = 1; + char *sp; + struct udev_device *dev = NULL, *usb = NULL; + uint16_t vid = 0, pid = 0; + char *vendor = NULL, *product = NULL; + + if (argc < 2) { + fprintf(stderr, "Need to pass sysfs path.\n"); + goto finish; + } + + if (!(udev = udev_new())) + goto finish; + + if (asprintf(&sp, "%s/%s", udev_get_sys_path(udev), argv[1]) < 0) { + fprintf(stderr, "Failed to allocate sysfs path.\n"); + goto finish; + } + + dev = udev_device_new_from_syspath(udev, sp); + free(sp); + + if (!dev) { + fprintf(stderr, "Failed to access %s.\n", argv[1]); + goto finish; + } + + if (!(usb = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"))) { + fprintf(stderr, "Failed to find usb_device.\n"); + goto finish; + } + + if (get_vid_pid(usb, &vid, &pid) < 0) + goto finish; + + if (lookup_vid_pid(vid, pid, &vendor, &product) < 0) + goto finish; + + if (vendor) + printf("ID_VENDOR_FROM_DATABASE=%s\n", vendor); + + if (product) + printf("ID_MODEL_FROM_DATABASE=%s\n", product); + + ret = 0; + +finish: + if (dev) + udev_device_unref(dev); + + if (udev) + udev_unref(udev); + + free(vendor); + free(product); + + return ret; + +} |