diff mbox series

[LEDE-DEV] usbutils: Update to version 009.

Message ID 20180315020107.26960-1-rosenp@gmail.com
State Changes Requested
Delegated to: John Crispin
Headers show
Series [LEDE-DEV] usbutils: Update to version 009. | expand

Commit Message

Rosen Penev March 15, 2018, 2:01 a.m. UTC
4 patches were added to revert the libudev changes as the libudev wrapper in OpenWrt is not good enough.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 package/utils/usbutils/Makefile                    |   8 +-
 .../patches/010-remove-python-usbids.patch         |  68 ++
 .../patches/020-revert-removal-of-usb.ids.patch    | 879 +++++++++++++++++++++
 .../usbutils/patches/030-revert-port-to-hwdb.patch | 529 +++++++++++++
 .../patches/040-add-back-update-usbids.patch       |  66 ++
 5 files changed, 1547 insertions(+), 3 deletions(-)
 create mode 100644 package/utils/usbutils/patches/010-remove-python-usbids.patch
 create mode 100644 package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch
 create mode 100644 package/utils/usbutils/patches/030-revert-port-to-hwdb.patch
 create mode 100644 package/utils/usbutils/patches/040-add-back-update-usbids.patch

Comments

Bjørn Mork March 15, 2018, 6:59 a.m. UTC | #1
Great!

Note that the OpenWrt usbreset utility has been included in this version
of usbutils.  usbreset is currently packaged separately with its source.
Maybe consider merging the two source packages and start building
usbreset as part of the usbutils package?



Bjørn
Rosen Penev March 15, 2018, 2:41 p.m. UTC | #2
On Thu, Mar 15, 2018 at 2:26 AM, Karl Palsson <karlp@tweak.net.au> wrote:
>
> Rosen Penev <rosenp@gmail.com> wrote:
>> 4 patches were added to revert the libudev changes as the
>> libudev wrapper in OpenWrt is not good enough.
>
> Personally, I'd like to see substantially better descriptions in
> the patches explaining their purpose. The simple "revert xxxx"
> and the filename doesn't say much, many of it seems unrelated,
> and _none_ of them talk about libudev!
>
To be fair, I just used git format-patch on individual commits. I can
add the original commit message if needed.

usbutils switched to using hwdb which uses udev instead of a usbids file.
> Cheers,
> Karl P
>
>>
>> Signed-off-by: Rosen Penev <rosenp@gmail.com>
>> ---
>>  package/utils/usbutils/Makefile                    |   8 +-
>>  .../patches/010-remove-python-usbids.patch         |  68 ++
>>  .../patches/020-revert-removal-of-usb.ids.patch    | 879 +++++++++++++++++++++
>>  .../usbutils/patches/030-revert-port-to-hwdb.patch | 529 +++++++++++++
>>  .../patches/040-add-back-update-usbids.patch       |  66 ++
>>  5 files changed, 1547 insertions(+), 3 deletions(-)
>>  create mode 100644 package/utils/usbutils/patches/010-remove-python-usbids.patch
>>  create mode 100644 package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch
>>  create mode 100644 package/utils/usbutils/patches/030-revert-port-to-hwdb.patch
>>  create mode 100644 package/utils/usbutils/patches/040-add-back-update-usbids.patch
>>
>> diff --git a/package/utils/usbutils/Makefile
>> b/package/utils/usbutils/Makefile index 7f798954ae..3fbc4e0b50
>> 100644
>> --- a/package/utils/usbutils/Makefile
>> +++ b/package/utils/usbutils/Makefile
>> @@ -8,15 +8,17 @@
>>  include $(TOPDIR)/rules.mk
>>
>>  PKG_NAME:=usbutils
>> -PKG_VERSION:=007
>> -PKG_RELEASE:=7
>> +PKG_VERSION:=009
>> +PKG_RELEASE:=1
>>
>>  PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
>>  PKG_SOURCE_URL:=@KERNEL/linux/utils/usb/usbutils
>> -PKG_HASH:=7593a01724bbc0fd9fe48e62bc721ceb61c76654f1d7b231b3c65f6dfbbaefa4
>> +PKG_HASH:=8bbff0e54cb5f65a52be4feb9162fc0b022a97eb841b44784f7a89a9ea567160
>>  PKG_LICENSE:=GPL-2.0
>>  PKG_LICENSE_FILES:=COPYING
>>
>> +PKG_FIXUP:=autoreconf
>> +
>>  PKG_BUILD_PARALLEL:=1
>>  PKG_INSTALL:=1
>>
>> diff --git
>> a/package/utils/usbutils/patches/010-remove-python-usbids.patch
>> b/package/utils/usbutils/patches/010-remove-python-usbids.patch
>> new file mode 100644 index 0000000000..19e3cc1dd3
>> --- /dev/null
>> +++ b/package/utils/usbutils/patches/010-remove-python-usbids.patch
>> @@ -0,0 +1,68 @@
>> +From a1c2fd7bbd5b2e26f8f752fd3386a953b3b1ec37 Mon Sep 17
>> 00:00:00 2001 +From: Rosen Penev <rosenp@gmail.com> +Date: Fri,
>> 9 Mar 2018 10:31:09 -0800 +Subject: [PATCH] Revert "substitute
>> usb.id location in lsusb Python script"
>> +
>> +This reverts commit 199756013624bfa497865eb498bf7331eb07ef56.
>> +---
>> + Makefile.am             | 7 +------
>> + lsusb.py.in => lsusb.py | 4 ++--
>> + 3 files changed, 3 insertions(+), 9 deletions(-)
>> + rename lsusb.py.in => lsusb.py (99%)
>> + mode change 100644 => 100755
>> +
>> +diff --git a/Makefile.am b/Makefile.am
>> +index b18ff69..67def60 100644
>> +--- a/Makefile.am
>> ++++ b/Makefile.am
>> +@@ -39,13 +39,9 @@ EXTRA_DIST = \
>> +     lsusb.8.in \
>> +     usb-devices.1.in \
>> +     usb-devices \
>> +-    lsusb.py.in \
>> ++    lsusb.py \
>> +     usbutils.pc.in
>> +
>> +-lsusb.py: $(srcdir)/lsusb.py.in
>> +-    sed 's|VERSION|$(VERSION)|g;s|@usbids@|$(datadir)/usb.ids|g' $< >$@
>> +-    chmod 755 $@
>> +-
>> + lsusb.8: $(srcdir)/lsusb.8.in
>> +     sed 's|VERSION|$(VERSION)|g;s|@usbids@|$(datadir)/usb.ids|g' $< >$@
>> +
>> +@@ -59,7 +55,6 @@ usbutils.pc: $(srcdir)/usbutils.pc.in
>> +     sed 's|@usbids@|$(datadir)/usb.ids|g;s|@VERSION[@]|$(VERSION)|g' $< >$@
>> +
>> + DISTCLEANFILES = \
>> +-    lsusb.py \
>> +     lsusb.8 \
>> +     usb-devices.1 \
>> +     usbutils.pc
>> +diff --git a/lsusb.py.in b/lsusb.py
>> +old mode 100644
>> +new mode 100755
>> +similarity index 99%
>> +rename from lsusb.py.in
>> +rename to lsusb.py
>> +index db2e1e0..aa410fc
>> +--- a/lsusb.py.in
>> ++++ b/lsusb.py
>> +@@ -1,5 +1,5 @@
>> + #!/usr/bin/env python
>> +-# lsusb-VERSION.py
>> ++# lsusb.py
>> + # Displays your USB devices in reasonable form.
>> + # (c) Kurt Garloff <garloff@suse.de>, 2/2009, GPL v2 or v3.
>> + # (c) Kurt Garloff <kurt@garloff.de>, 9/2013, GPL v2 or v3.
>> +@@ -18,7 +18,7 @@ warnsort = False
>> + showeps = False
>> +
>> + prefix = "/sys/bus/usb/devices/"
>> +-usbids = "@usbids@"
>> ++usbids = "/usr/share/usb.ids"
>> +
>> + esc = chr(27)
>> + norm = esc + "[0;0m"
>> +--
>> +2.16.2
>> +
>> diff --git
>> a/package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch
>> b/package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch
>> new file mode 100644 index 0000000000..ae38b06a77
>> --- /dev/null
>> +++ b/package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch
>> @@ -0,0 +1,879 @@
>> +From 2bfca703b324e21aee2fabbe4f998aa663f03a15 Mon Sep 17
>> 00:00:00 2001 +From: Rosen Penev <rosenp@gmail.com> +Date: Fri,
>> 9 Mar 2018 10:31:24 -0800 +Subject: [PATCH] Revert "drop
>> dependency on usb.ids"
>> +
>> +This reverts commit 5d7ea40bc94cbf3069a25beba3146de13bcdcf02.
>> +---
>> + Makefile.am  |    27 +-
>> + configure.ac |    12 +
>> + lsusb.c      |    13 +-
>> + names.c      |   600 +-
>> + names.h      |     2 +-
>> + 5 files changed, 18559 insertions(+), 1775 deletions(-)
>> + delete mode 100644 usb-spec.h
>> + create mode 100644 usb.ids
>> +
>> +diff --git a/Makefile.am b/Makefile.am
>> +index 67def60..31afb20 100644
>> +--- a/Makefile.am
>> ++++ b/Makefile.am
>> +@@ -20,7 +20,6 @@ lsusb_SOURCES = \
>> +     lsusb-t.c \
>> +     list.h \
>> +     names.c names.h \
>> +-    usb-spec.h \
>> +     usbmisc.c usbmisc.h
>> +
>> + lsusb_CPPFLAGS = \
>> +@@ -31,17 +30,41 @@ lsusb_LDADD = \
>> +     $(LIBUSB_LIBS) \
>> +     $(UDEV_LIBS)
>> +
>> ++if HAVE_ZLIB
>> ++lsusb_CPPFLAGS += -DHAVE_LIBZ
>> ++lsusb_LDADD += -lz
>> ++endif
>> ++
>> + man_MANS = \
>> +     lsusb.8 \
>> +     usb-devices.1
>> +
>> + EXTRA_DIST = \
>> ++    usb.ids \
>> ++    update-usbids.sh.in \
>> +     lsusb.8.in \
>> +     usb-devices.1.in \
>> +     usb-devices \
>> +     lsusb.py \
>> +     usbutils.pc.in
>> +
>> ++if INSTALL_USBIDS
>> ++data_DATA += usb.ids
>> ++
>> ++if HAVE_ZLIB
>> ++data_DATA += usb.ids.gz
>> ++endif
>> ++
>> ++sbin_SCRIPTS += update-usbids.sh
>> ++
>> ++usb.ids.gz: $(srcdir)/usb.ids
>> ++    gzip -c -9 $< > $@
>> ++
>> ++update-usbids.sh: $(srcdir)/update-usbids.sh.in
>> ++    sed 's|@usbids@|$(datadir)/usb.ids|g' $< >$@
>> ++    chmod 755 $@
>> ++endif
>> ++
>> + lsusb.8: $(srcdir)/lsusb.8.in
>> +     sed 's|VERSION|$(VERSION)|g;s|@usbids@|$(datadir)/usb.ids|g' $< >$@
>> +
>> +@@ -55,8 +78,10 @@ usbutils.pc: $(srcdir)/usbutils.pc.in
>> +     sed 's|@usbids@|$(datadir)/usb.ids|g;s|@VERSION[@]|$(VERSION)|g' $< >$@
>> +
>> + DISTCLEANFILES = \
>> ++    usb.ids.gz \
>> +     lsusb.8 \
>> +     usb-devices.1 \
>> ++    update-usbids.sh \
>> +     usbutils.pc
>> +
>> + distclean-local:
>> +diff --git a/configure.ac b/configure.ac
>> +index a62748c..89d62f9 100644
>> +--- a/configure.ac
>> ++++ b/configure.ac
>> +@@ -12,6 +12,18 @@ AC_SYS_LARGEFILE
>> + AC_CHECK_HEADERS([byteswap.h])
>> + AC_CHECK_FUNCS([nl_langinfo iconv])
>> +
>> ++AC_ARG_ENABLE(zlib,
>> ++    AS_HELP_STRING(--disable-zlib,disable support for zlib))
>> ++
>> ++HAVE_ZLIB=no
>> ++AS_IF([test "x$enable_zlib" != "xno"],
>> ++    [AC_CHECK_LIB(z, inflateEnd, HAVE_ZLIB=yes)])
>> ++AM_CONDITIONAL(HAVE_ZLIB, [test "$HAVE_ZLIB" = "yes"])
>> ++
>> ++AC_ARG_ENABLE(usbids,
>> ++    AS_HELP_STRING(--disable-usbids, [disable installing usb.ids @<:@default=install@:>@]))
>> ++AM_CONDITIONAL([INSTALL_USBIDS], [test "x$enable_usbids" !=
>> "xno"])
>> ++
>> + PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.9)
>> +
>> + PKG_CHECK_MODULES(UDEV, libudev >= 196)
>> +diff --git a/lsusb.c b/lsusb.c
>> +index f611f2e..969997c 100644
>> +--- a/lsusb.c
>> ++++ b/lsusb.c
>> +@@ -4340,9 +4340,16 @@ int main(int argc, char *argv[])
>> +
>> +
>> +     /* by default, print names as well as numbers */
>> +-    if (names_init() < 0)
>> +-            fprintf(stderr, "unable to initialize usb spec");
>> +-
>> ++    err = names_init(DATADIR "/usb.ids");
>> ++#ifdef HAVE_LIBZ
>> ++    if (err != 0)
>> ++            err = names_init(DATADIR "/usb.ids.gz");
>> ++#endif
>> ++    if (err != 0)
>> ++            fprintf(stderr, "%s: cannot open \"%s\", %s\n",
>> ++                            argv[0],
>> ++                            DATADIR "/usb.ids",
>> ++                            strerror(err));
>> +     status = 0;
>> +
>> +     if (treemode) {
>> +diff --git a/names.c b/names.c
>> +index a151484..f543240 100644
>> +--- a/names.c
>> ++++ b/names.c
>> +@@ -37,13 +37,47 @@
>> +
>> + #include <libudev.h>
>> +
>> +-#include "usb-spec.h"
>> ++#ifdef HAVE_LIBZ
>> ++#include <zlib.h>
>> ++#define     usb_file                        gzFile
>> ++#define     usb_fopen(path, mode)           gzopen(path, mode)
>> ++#define usb_fgets(s, size, stream) gzgets(stream, s, size)
>> ++#define usb_close(f) gzclose(f) ++#else ++#define usb_file
>> FILE * ++#define usb_fopen(path, mode) fopen(path, mode)
>> ++#define usb_fgets(s, size, stream) fgets(s, size, stream)
>> ++#define usb_close(f) fclose(f) ++#endif
>> ++
>> + #include "names.h"
>> +
>> +
>> ++/* ---------------------------------------------------------------------- */
>> ++
>> ++struct audioterminal {
>> ++    struct audioterminal *next;
>> ++    u_int16_t termt;
>> ++    char name[1];
>> ++};
>> ++
>> ++struct videoterminal {
>> ++    struct videoterminal *next;
>> ++    u_int16_t termt;
>> ++    char name[1];
>> ++};
>> ++
>> ++struct genericstrtable {
>> ++    struct genericstrtable *next;
>> ++    unsigned int num;
>> ++    char name[1];
>> ++};
>> ++
>> ++/* ---------------------------------------------------------------------- */
>> ++
>> + #define HASH1  0x10
>> + #define HASH2  0x02
>> +-#define HASHSZ 512
>> ++#define HASHSZ 16
>> +
>> + static unsigned int hashnum(unsigned int num)
>> + {
>> +@@ -59,16 +93,16 @@ static unsigned int hashnum(unsigned int num)
>> +
>> + static struct udev *udev = NULL;
>> + static struct udev_hwdb *hwdb = NULL;
>> +-static struct audioterminal *audioterminals_hash[HASHSZ] = {
>> NULL, }; +-static struct videoterminal
>> *videoterminals_hash[HASHSZ] = { NULL, }; +-static struct
>> genericstrtable *hiddescriptors_hash[HASHSZ] = { NULL, };
>> +-static struct genericstrtable *reports_hash[HASHSZ] = { NULL,
>> }; +-static struct genericstrtable *huts_hash[HASHSZ] = { NULL,
>> }; +-static struct genericstrtable *biass_hash[HASHSZ] = {
>> NULL, }; +-static struct genericstrtable *physdess_hash[HASHSZ]
>> = { NULL, }; +-static struct genericstrtable
>> *hutus_hash[HASHSZ] = { NULL, }; +-static struct
>> genericstrtable *langids_hash[HASHSZ] = { NULL, }; +-static
>> struct genericstrtable *countrycodes_hash[HASHSZ] = { NULL, };
>> ++static struct audioterminal *audioterminals[HASHSZ] = { NULL,
>> }; ++static struct videoterminal *videoterminals[HASHSZ] = {
>> NULL, }; ++static struct genericstrtable
>> *hiddescriptors[HASHSZ] = { NULL, }; ++static struct
>> genericstrtable *reports[HASHSZ] = { NULL, }; ++static struct
>> genericstrtable *huts[HASHSZ] = { NULL, }; ++static struct
>> genericstrtable *biass[HASHSZ] = { NULL, }; ++static struct
>> genericstrtable *physdess[HASHSZ] = { NULL, }; ++static struct
>> genericstrtable *hutus[HASHSZ] = { NULL, }; ++static struct
>> genericstrtable *langids[HASHSZ] = { NULL, }; ++static struct
>> genericstrtable *countrycodes[HASHSZ] = { NULL, };
>> +
>> + /* ---------------------------------------------------------------------- */
>> +
>> +@@ -85,42 +119,42 @@ static const char *names_genericstrtable(struct genericstrtable *t[HASHSZ],
>> +
>> + const char *names_hid(u_int8_t hidd)
>> + {
>> +-    return names_genericstrtable(hiddescriptors_hash, hidd);
>> ++    return names_genericstrtable(hiddescriptors, hidd);
>> + }
>> +
>> + const char *names_reporttag(u_int8_t rt)
>> + {
>> +-    return names_genericstrtable(reports_hash, rt);
>> ++    return names_genericstrtable(reports, rt);
>> + }
>> +
>> + const char *names_huts(unsigned int data)
>> + {
>> +-    return names_genericstrtable(huts_hash, data);
>> ++    return names_genericstrtable(huts, data);
>> + }
>> +
>> + const char *names_hutus(unsigned int data)
>> + {
>> +-    return names_genericstrtable(hutus_hash, data);
>> ++    return names_genericstrtable(hutus, data);
>> + }
>> +
>> + const char *names_langid(u_int16_t langid)
>> + {
>> +-    return names_genericstrtable(langids_hash, langid);
>> ++    return names_genericstrtable(langids, langid);
>> + }
>> +
>> + const char *names_physdes(u_int8_t ph)
>> + {
>> +-    return names_genericstrtable(physdess_hash, ph);
>> ++    return names_genericstrtable(physdess, ph);
>> + }
>> +
>> + const char *names_bias(u_int8_t b)
>> + {
>> +-    return names_genericstrtable(biass_hash, b);
>> ++    return names_genericstrtable(biass, b);
>> + }
>> +
>> + const char *names_countrycode(unsigned int countrycode)
>> + {
>> +-    return names_genericstrtable(countrycodes_hash, countrycode);
>> ++    return names_genericstrtable(countrycodes, countrycode);
>> + }
>> +
>> + static const char *hwdb_get(const char *modalias, const char *key)
>> +@@ -178,7 +212,7 @@ const char *names_audioterminal(u_int16_t termt)
>> + {
>> +     struct audioterminal *at;
>> +
>> +-    at = audioterminals_hash[hashnum(termt)];
>> ++    at = audioterminals[hashnum(termt)];
>> +     for (; at; at = at->next)
>> +             if (at->termt == termt)
>> +                     return at->name;
>> +@@ -189,7 +223,7 @@ const char *names_videoterminal(u_int16_t termt)
>> + {
>> +     struct videoterminal *vt;
>> +
>> +-    vt = videoterminals_hash[hashnum(termt)];
>> ++    vt = videoterminals[hashnum(termt)];
>> +     for (; vt; vt = vt->next)
>> +             if (vt->termt == termt)
>> +                     return vt->name;
>> +@@ -248,189 +282,446 @@ int get_subclass_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls)
>> +
>> + /* ---------------------------------------------------------------------- */
>> +
>> +-static int hash_audioterminal(struct audioterminal *at)
>> ++static int new_audioterminal(const char *name, u_int16_t
>> termt)
>> + {
>> +-    struct audioterminal *at_old;
>> +-    unsigned int h = hashnum(at->termt);
>> ++    struct audioterminal *at;
>> ++    unsigned int h = hashnum(termt);
>> +
>> +-    for (at_old = audioterminals_hash[h]; at_old; at_old = at_old->next)
>> +-            if (at_old->termt == at->termt)
>> ++    at = audioterminals[h];
>> ++    for (; at; at = at->next)
>> ++            if (at->termt == termt)
>> +                     return -1;
>> +-    at->next = audioterminals_hash[h];
>> +-    audioterminals_hash[h] = at;
>> ++    at = malloc(sizeof(struct audioterminal) + strlen(name));
>> ++    if (!at)
>> ++            return -1;
>> ++    strcpy(at->name, name);
>> ++    at->termt = termt;
>> ++    at->next = audioterminals[h];
>> ++    audioterminals[h] = at;
>> +     return 0;
>> + }
>> +
>> +-static int hash_audioterminals(void)
>> +-{
>> +-    int r = 0, i, k;
>> +-
>> +-    for (i = 0; audioterminals[i].name; i++)
>> +-    {
>> +-            k = hash_audioterminal(&audioterminals[i]);
>> +-            if (k < 0)
>> +-                    r = k;
>> +-    }
>> +-
>> +-    return r;
>> +-}
>> +-
>> +-static int hash_videoterminal(struct videoterminal *vt)
>> ++static int new_videoterminal(const char *name, u_int16_t
>> termt)
>> + {
>> +-    struct videoterminal *vt_old;
>> +-    unsigned int h = hashnum(vt->termt);
>> ++    struct videoterminal *vt;
>> ++    unsigned int h = hashnum(termt);
>> +
>> +-    for (vt_old = videoterminals_hash[h]; vt_old; vt_old = vt_old->next)
>> +-            if (vt_old->termt == vt->termt)
>> ++    vt = videoterminals[h];
>> ++    for (; vt; vt = vt->next)
>> ++            if (vt->termt == termt)
>> +                     return -1;
>> +-    vt->next = videoterminals_hash[h];
>> +-    videoterminals_hash[h] = vt;
>> ++    vt = malloc(sizeof(struct videoterminal) + strlen(name));
>> ++    if (!vt)
>> ++            return -1;
>> ++    strcpy(vt->name, name);
>> ++    vt->termt = termt;
>> ++    vt->next = videoterminals[h];
>> ++    videoterminals[h] = vt;
>> +     return 0;
>> + }
>> +
>> +-static int hash_videoterminals(void)
>> +-{
>> +-    int r = 0, i, k;
>> +-
>> +-    for (i = 0; videoterminals[i].name; i++)
>> +-    {
>> +-            k = hash_videoterminal(&videoterminals[i]);
>> +-            if (k < 0)
>> +-                    r = k;
>> +-    }
>> +-
>> +-    return r;
>> +-}
>> +-
>> +-static int hash_genericstrtable(struct genericstrtable
>> *t[HASHSZ],
>> +-                           struct genericstrtable *g)
>> ++static int new_genericstrtable(struct genericstrtable
>> *t[HASHSZ],
>> ++                           const char *name, unsigned int idx)
>> + {
>> +-    struct genericstrtable *g_old;
>> +-    unsigned int h = hashnum(g->num);
>> ++    struct genericstrtable *g;
>> ++    unsigned int h = hashnum(idx);
>> +
>> +-    for (g_old = t[h]; g_old; g_old = g_old->next)
>> +-            if (g_old->num == g->num)
>> ++    for (g = t[h]; g; g = g->next)
>> ++            if (g->num == idx)
>> +                     return -1;
>> ++    g = malloc(sizeof(struct genericstrtable) + strlen(name));
>> ++    if (!g)
>> ++            return -1;
>> ++    strcpy(g->name, name);
>> ++    g->num = idx;
>> +     g->next = t[h];
>> +     t[h] = g;
>> +     return 0;
>> + }
>> +
>> +-#define HASH_EACH(array, hash) \
>> +-    for (i = 0; array[i].name; i++) { \
>> +-            k = hash_genericstrtable(hash, &array[i]); \
>> +-            if (k < 0) { \
>> +-                    r = k; \
>> +-            }\
>> +-    }
>> +-
>> +-static int hash_tables(void)
>> ++static int new_hid(const char *name, u_int8_t hidd)
>> + {
>> +-    int r = 0, k, i;
>> +-
>> +-    k = hash_audioterminals();
>> +-    if (k < 0)
>> +-            r = k;
>> +-
>> +-    k = hash_videoterminals();
>> +-    if (k < 0)
>> +-            r = k;
>> +-
>> +-    HASH_EACH(hiddescriptors, hiddescriptors_hash);
>> +-
>> +-    HASH_EACH(reports, reports_hash);
>> +-
>> +-    HASH_EACH(huts, huts_hash);
>> ++    return new_genericstrtable(hiddescriptors, name, hidd);
>> ++}
>> +
>> +-    HASH_EACH(hutus, hutus_hash);
>> ++static int new_reporttag(const char *name, u_int8_t rt)
>> ++{
>> ++    return new_genericstrtable(reports, name, rt);
>> ++}
>> +
>> +-    HASH_EACH(langids, langids_hash);
>> ++static int new_huts(const char *name, unsigned int data)
>> ++{
>> ++    return new_genericstrtable(huts, name, data);
>> ++}
>> +
>> +-    HASH_EACH(physdess, physdess_hash);
>> ++static int new_hutus(const char *name, unsigned int data)
>> ++{
>> ++    return new_genericstrtable(hutus, name, data);
>> ++}
>> +
>> +-    HASH_EACH(biass, biass_hash);
>> ++static int new_langid(const char *name, u_int16_t langid)
>> ++{
>> ++    return new_genericstrtable(langids, name, langid);
>> ++}
>> +
>> +-    HASH_EACH(countrycodes, countrycodes_hash);
>> ++static int new_physdes(const char *name, u_int8_t ph)
>> ++{
>> ++    return new_genericstrtable(physdess, name, ph);
>> ++}
>> ++static int new_bias(const char *name, u_int8_t b)
>> ++{
>> ++    return new_genericstrtable(biass, name, b);
>> ++}
>> +
>> +-    return r;
>> ++static int new_countrycode(const char *name, unsigned int
>> countrycode)
>> ++{
>> ++    return new_genericstrtable(countrycodes, name, countrycode);
>> + }
>> +
>> + /* ---------------------------------------------------------------------- */
>> +
>> +-/*
>> +-static void print_tables(void)
>> ++static void free_audioterminal(void)
>> + {
>> ++    struct audioterminal *cur, *tmp;
>> +     int i;
>> +-    struct audioterminal *at;
>> +-    struct videoterminal *vt;
>> +-    struct genericstrtable *li;
>> +-    struct genericstrtable *hu;
>> +-
>> +-
>> +-    printf("--------------------------------------------\n");
>> +-    printf("\t\t Audio Terminals\n");
>> +-    printf("--------------------------------------------\n");
>> +
>> +     for (i = 0; i < HASHSZ; i++) {
>> +-            printf("hash: %d\n", i);
>> +-            at = audioterminals_hash[i];
>> +-            for (; at; at = at->next)
>> +-                    printf("\tentry: %s\n", at->name);
>> ++            cur = audioterminals[i];
>> ++            audioterminals[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> +     }
>> ++    return;
>> ++}
>> +
>> +-    printf("--------------------------------------------\n");
>> +-    printf("\t\t Video Terminals\n");
>> +-    printf("--------------------------------------------\n");
>> ++static void free_videoterminal(void)
>> ++{
>> ++    struct videoterminal *cur, *tmp;
>> ++    int i;
>> +
>> +     for (i = 0; i < HASHSZ; i++) {
>> +-            printf("hash: %d\n", i);
>> +-            vt = videoterminals_hash[i];
>> +-            for (; vt; vt = vt->next)
>> +-                    printf("\tentry: %s\n", vt->name);
>> ++            cur = videoterminals[i];
>> ++            videoterminals[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> +     }
>> ++}
>> +
>> +-    printf("--------------------------------------------\n");
>> +-    printf("\t\t Languages\n");
>> +-    printf("--------------------------------------------\n");
>> ++static void _free_genericstrtable(struct genericstrtable
>> *t[HASHSZ])
>> ++{
>> ++    struct genericstrtable *cur, *tmp;
>> ++    int i;
>> +
>> +     for (i = 0; i < HASHSZ; i++) {
>> +-            li = langids_hash[i];
>> +-            if (li)
>> +-                    printf("hash: %d\n", i);
>> +-            for (; li; li = li->next)
>> +-                    printf("\tid: %x, entry: %s\n", li->num, li->name);
>> ++            cur = t[i];
>> ++            t[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> +     }
>> ++}
>> +
>> +-    printf("--------------------------------------------\n");
>> +-    printf("\t\t Conutry Codes\n");
>> +-    printf("--------------------------------------------\n");
>> ++static void free_genericstrtable(void)
>> ++{
>> ++    _free_genericstrtable(hiddescriptors);
>> ++    _free_genericstrtable(reports);
>> ++    _free_genericstrtable(huts);
>> ++    _free_genericstrtable(biass);
>> ++    _free_genericstrtable(physdess);
>> ++    _free_genericstrtable(hutus);
>> ++    _free_genericstrtable(langids);
>> ++    _free_genericstrtable(countrycodes);
>> ++}
>> +
>> +-    for (i = 0; i < HASHSZ; i++) {
>> +-            hu = countrycodes_hash[i];
>> +-            if (hu)
>> +-                    printf("hash: %d\n", i);
>> +-            for (; hu; hu = hu->next)
>> +-                    printf("\tid: %x, entry: %s\n", hu->num, hu->name);
>> +-    }
>> ++#define DBG(x)
>> +
>> +-    printf("--------------------------------------------\n");
>> ++static void parse(usb_file f)
>> ++{
>> ++    char buf[512], *cp;
>> ++    unsigned int linectr = 0;
>> ++    int lastvendor = -1;
>> ++    int lastclass = -1;
>> ++    int lastsubclass = -1;
>> ++    int lasthut = -1;
>> ++    int lastlang = -1;
>> ++    unsigned int u;
>> ++
>> ++    while (usb_fgets(buf, sizeof(buf), f)) {
>> ++            linectr++;
>> ++            /* remove line ends */
>> ++            cp = strchr(buf, 13);
>> ++            if (cp)
>> ++                    *cp = 0;
>> ++            cp = strchr(buf, 10);
>> ++            if (cp)
>> ++                    *cp = 0;
>> ++            if (buf[0] == '#' || !buf[0])
>> ++                    continue;
>> ++            cp = buf;
>> ++            if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && buf[3] == 'S' && buf[4] == 'D' &&
>> ++                buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ buf[7] == ' ') {
>> ++                    cp = buf + 8;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid Physdes type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid Physdes type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_physdes(cp, u))
>> ++                            fprintf(stderr, "Duplicate Physdes  type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u physdes type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++
>> ++            }
>> ++            if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
>> ++                    cp = buf + 4;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid PHY type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid PHY type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_physdes(cp, u))
>> ++                            fprintf(stderr, "Duplicate PHY type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u PHY type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++
>> ++            }
>> ++            if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
>> ++                    cp = buf + 5;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid BIAS type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid BIAS type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_bias(cp, u))
>> ++                            fprintf(stderr, "Duplicate BIAS  type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u BIAS type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++
>> ++            }
>> ++            if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
>> ++                    cp =  buf+2;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_langid(cp, u))
>> ++                            fprintf(stderr, "Duplicate LANGID spec at line %u language-id %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u LANGID %02x %s\n", linectr, u, cp));
>> ++                    lasthut = lastclass = lastvendor = lastsubclass = -1;
>> ++                    lastlang = u;
>> ++                    continue;
>> ++            }
>> ++            if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
>> ++                    /* audio terminal type spec */
>> ++                    cp = buf+3;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_audioterminal(cp, u))
>> ++                            fprintf(stderr, "Duplicate audio terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u audio terminal type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++            }
>> ++            if (buf[0] == 'V' && buf[1] == 'T' && isspace(buf[2])) {
>> ++                    /* video terminal type spec */
>> ++                    cp = buf+3;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid video terminal type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid video terminal type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_videoterminal(cp, u))
>> ++                            fprintf(stderr, "Duplicate video terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u video terminal type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++            }
>> ++            if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' && isspace(buf[3])) {
>> ++                    /* HID Descriptor bCountryCode */
>> ++                    cp =  buf+3;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid HID country code at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 10);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid HID country code at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_countrycode(cp, u))
>> ++                            fprintf(stderr, "Duplicate HID country code at line %u country %02u %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u keyboard country code %02u %s\n", linectr, u, cp));
>> ++                    continue;
>> ++            }
>> ++            if (buf[0] == '\t' && isxdigit(buf[1])) {
>> ++                    /* product or subclass spec */
>> ++                    u = strtoul(buf+1, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid product/subclass spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (lasthut != -1) {
>> ++                            if (new_hutus(cp, (lasthut << 16)+u))
>> ++                                    fprintf(stderr, "Duplicate HUT Usage Spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (lastlang != -1) {
>> ++                            if (new_langid(cp, lastlang+(u<<10)))
>> ++                                    fprintf(stderr, "Duplicate LANGID Usage Spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    fprintf(stderr, "Product/Subclass spec without prior Vendor/Class spec at line %u\n", linectr);
>> ++                    continue;
>> ++            }
>> ++            if (buf[0] == 'H' && buf[1] == 'I' && buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
>> ++                    cp = buf + 4;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid HID type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid HID type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_hid(cp, u))
>> ++                            fprintf(stderr, "Duplicate HID type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u HID type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++
>> ++            }
>> ++            if (buf[0] == 'H' && buf[1] == 'U' && buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
>> ++                    cp = buf + 4;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid HUT type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid HUT type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_huts(cp, u))
>> ++                            fprintf(stderr, "Duplicate HUT type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    lastlang = lastclass = lastvendor = lastsubclass = -1;
>> ++                    lasthut = u;
>> ++                    DBG(printf("line %5u HUT type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++
>> ++            }
>> ++            if (buf[0] == 'R' && buf[1] == ' ') {
>> ++                    cp = buf + 2;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid Report type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid Report type at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_reporttag(cp, u))
>> ++                            fprintf(stderr, "Duplicate Report type spec at line %u terminal type %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u Report type %02x %s\n", linectr, u, cp));
>> ++                    continue;
>> ++
>> ++            }
>> ++            fprintf(stderr, "Unknown line at line %u\n", linectr);
>> ++    }
>> + }
>> +-*/
>> +
>> +-int names_init(void)
>> ++/* ---------------------------------------------------------------------- */
>> ++
>> ++int names_init(char *n)
>> + {
>> +-    int r;
>> ++    usb_file f;
>> ++    int r = 0;
>> +
>> +-    udev = udev_new();
>> +-    if (!udev)
>> +-            r = -1;
>> +-    else {
>> +-            hwdb = udev_hwdb_new(udev);
>> +-            if (!hwdb)
>> +-                    r = -1;
>> +-    }
>> ++    f = usb_fopen(n, "r");
>> ++    if (!f)
>> ++            r = errno;
>> +
>> +-    r = hash_tables();
>> ++    parse(f);
>> ++    usb_close(f);
>> ++
>> ++    udev = udev_new();
>> ++    hwdb = udev_hwdb_new(udev);
>> +
>> +     return r;
>> + }
>> +@@ -439,4 +730,7 @@ void names_exit(void)
>> + {
>> +     hwdb = udev_hwdb_unref(hwdb);
>> +     udev = udev_unref(udev);
>> ++    free_audioterminal();
>> ++    free_videoterminal();
>> ++    free_genericstrtable();
>> + }
>> +diff --git a/names.h b/names.h
>> +index 32e887c..0eba890 100644
>> +--- a/names.h
>> ++++ b/names.h
>> +@@ -49,7 +49,7 @@ extern int get_product_string(char *buf, size_t size, u_int16_t vid, u_int16_t p
>> + extern int get_class_string(char *buf, size_t size, u_int8_t cls);
>> + extern int get_subclass_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls);
>> +
>> +-extern int names_init(void);
>> ++extern int names_init(char *n);
>> + extern void names_exit(void);
>> +
>> + /* ---------------------------------------------------------------------- */
>> +---
>> +-2.16.2
>> diff --git
>> a/package/utils/usbutils/patches/030-revert-port-to-hwdb.patch
>> b/package/utils/usbutils/patches/030-revert-port-to-hwdb.patch
>> new file mode 100644 index 0000000000..fc41456893
>> --- /dev/null
>> +++ b/package/utils/usbutils/patches/030-revert-port-to-hwdb.patch
>> @@ -0,0 +1,529 @@
>> +From bfb94e20c8ca6eff73e8722165994a45da7cf47c Mon Sep 17
>> 00:00:00 2001 +From: Rosen Penev <rosenp@gmail.com> +Date: Fri,
>> 9 Mar 2018 10:33:52 -0800 +Subject: [PATCH] Revert "lsusb: port
>> to hwdb"
>> +
>> +This reverts commit c6282a7a0e20fbb9c56837f055843635a43ba8b4.
>> +---
>> + Makefile.am  |   5 +-
>> + configure.ac |   2 -
>> + names.c      | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
>> + 3 files changed, 323 insertions(+), 45 deletions(-)
>> +
>> +diff --git a/Makefile.am b/Makefile.am
>> +index 31afb20..60df9a0 100644
>> +--- a/Makefile.am
>> ++++ b/Makefile.am
>> +@@ -23,12 +23,11 @@ lsusb_SOURCES = \
>> +     usbmisc.c usbmisc.h
>> +
>> + lsusb_CPPFLAGS = \
>> +-    $(AM_CPPFLAGS) $(LIBUSB_CFLAGS) $(UDEV_CFLAGS) \
>> ++    $(AM_CPPFLAGS) $(LIBUSB_CFLAGS) \
>> +     -DDATADIR=\"$(datadir)\"
>> +
>> + lsusb_LDADD = \
>> +-    $(LIBUSB_LIBS) \
>> +-    $(UDEV_LIBS)
>> ++    $(LIBUSB_LIBS)
>> +
>> + if HAVE_ZLIB
>> + lsusb_CPPFLAGS += -DHAVE_LIBZ
>> +diff --git a/configure.ac b/configure.ac
>> +index 89d62f9..4b86c9b 100644
>> +--- a/configure.ac
>> ++++ b/configure.ac
>> +@@ -26,8 +26,6 @@ AM_CONDITIONAL([INSTALL_USBIDS], [test "x$enable_usbids" != "xno"])
>> +
>> + PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.0)
>> +
>> +-PKG_CHECK_MODULES(UDEV, libudev >= 196)
>> +-
>> + AC_CONFIG_HEADERS([config.h])
>> + AC_CONFIG_FILES([
>> +     Makefile
>> +diff --git a/names.c b/names.c
>> +index f543240..12cbd60 100644
>> +--- a/names.c
>> ++++ b/names.c
>> +@@ -3,7 +3,6 @@
>> +  *      names.c  --  USB name database manipulation routines
>> +  *
>> +  *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
>> +- *      Copyright (C) 2013  Tom Gundersen (teg@jklm.no)
>> +  *
>> +  *      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
>> +@@ -35,8 +34,6 @@
>> + #include <stdio.h>
>> + #include <ctype.h>
>> +
>> +-#include <libudev.h>
>> +-
>> + #ifdef HAVE_LIBZ
>> + #include <zlib.h>
>> + #define     usb_file                        gzFile
>> +@@ -55,6 +52,36 @@
>> +
>> + /* ---------------------------------------------------------------------- */
>> +
>> ++struct vendor {
>> ++    struct vendor *next;
>> ++    u_int16_t vendorid;
>> ++    char name[1];
>> ++};
>> ++
>> ++struct product {
>> ++    struct product *next;
>> ++    u_int16_t vendorid, productid;
>> ++    char name[1];
>> ++};
>> ++
>> ++struct class {
>> ++    struct class *next;
>> ++    u_int8_t classid;
>> ++    char name[1];
>> ++};
>> ++
>> ++struct subclass {
>> ++    struct subclass *next;
>> ++    u_int8_t classid, subclassid;
>> ++    char name[1];
>> ++};
>> ++
>> ++struct protocol {
>> ++    struct protocol *next;
>> ++    u_int8_t classid, subclassid, protocolid;
>> ++    char name[1];
>> ++};
>> ++
>> + struct audioterminal {
>> +     struct audioterminal *next;
>> +     u_int16_t termt;
>> +@@ -91,8 +118,11 @@ static unsigned int hashnum(unsigned int num)
>> +
>> + /* ---------------------------------------------------------------------- */
>> +
>> +-static struct udev *udev = NULL;
>> +-static struct udev_hwdb *hwdb = NULL;
>> ++static struct vendor *vendors[HASHSZ] = { NULL, };
>> ++static struct product *products[HASHSZ] = { NULL, }; ++static
>> struct class *classes[HASHSZ] = { NULL, }; ++static struct
>> subclass *subclasses[HASHSZ] = { NULL, }; ++static struct
>> protocol *protocols[HASHSZ] = { NULL, };
>> + static struct audioterminal *audioterminals[HASHSZ] = { NULL, };
>> + static struct videoterminal *videoterminals[HASHSZ] = { NULL, };
>> + static struct genericstrtable *hiddescriptors[HASHSZ] = { NULL, };
>> +@@ -157,55 +187,59 @@ const char *names_countrycode(unsigned int countrycode)
>> +     return names_genericstrtable(countrycodes, countrycode);
>> + }
>> +
>> +-static const char *hwdb_get(const char *modalias, const char
>> *key)
>> +-{
>> +-    struct udev_list_entry *entry;
>> +-
>> +-    udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
>> +-            if (strcmp(udev_list_entry_get_name(entry), key) == 0)
>> +-                    return udev_list_entry_get_value(entry);
>> +-
>> +-    return NULL;
>> +-}
>> +-
>> + const char *names_vendor(u_int16_t vendorid)
>> + {
>> +-    char modalias[64];
>> ++    struct vendor *v;
>> +
>> +-    sprintf(modalias, "usb:v%04X*", vendorid);
>> +-    return hwdb_get(modalias, "ID_VENDOR_FROM_DATABASE");
>> ++    v = vendors[hashnum(vendorid)];
>> ++    for (; v; v = v->next)
>> ++            if (v->vendorid == vendorid)
>> ++                    return v->name;
>> ++    return NULL;
>> + }
>> +
>> + const char *names_product(u_int16_t vendorid, u_int16_t productid)
>> + {
>> +-    char modalias[64];
>> ++    struct product *p;
>> +
>> +-    sprintf(modalias, "usb:v%04Xp%04X*", vendorid, productid);
>> +-    return hwdb_get(modalias, "ID_MODEL_FROM_DATABASE");
>> ++    p = products[hashnum((vendorid << 16) | productid)];
>> ++    for (; p; p = p->next)
>> ++            if (p->vendorid == vendorid && p->productid == productid)
>> ++                    return p->name;
>> ++    return NULL;
>> + }
>> +
>> + const char *names_class(u_int8_t classid)
>> + {
>> +-    char modalias[64];
>> ++    struct class *c;
>> +
>> +-    sprintf(modalias, "usb:v*p*d*dc%02X*", classid);
>> +-    return hwdb_get(modalias, "ID_USB_CLASS_FROM_DATABASE");
>> ++    c = classes[hashnum(classid)];
>> ++    for (; c; c = c->next)
>> ++            if (c->classid == classid)
>> ++                    return c->name;
>> ++    return NULL;
>> + }
>> +
>> + const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
>> + {
>> +-    char modalias[64];
>> ++    struct subclass *s;
>> +
>> +-    sprintf(modalias, "usb:v*p*d*dc%02Xdsc%02X*", classid, subclassid);
>> +-    return hwdb_get(modalias, "ID_USB_SUBCLASS_FROM_DATABASE");
>> ++    s = subclasses[hashnum((classid << 8) | subclassid)];
>> ++    for (; s; s = s->next)
>> ++            if (s->classid == classid && s->subclassid == subclassid)
>> ++                    return s->name;
>> ++    return NULL;
>> + }
>> +
>> + const char *names_protocol(u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid)
>> + {
>> +-    char modalias[64];
>> ++    struct protocol *p;
>> +
>> +-    sprintf(modalias, "usb:v*p*d*dc%02Xdsc%02Xdp%02X*", classid, subclassid, protocolid);
>> +-    return hwdb_get(modalias, "ID_USB_PROTOCOL_FROM_DATABASE");
>> ++    p = protocols[hashnum((classid << 16) | (subclassid << 8) | protocolid)];
>> ++    for (; p; p = p->next)
>> ++            if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid)
>> ++                    return p->name;
>> ++    return NULL;
>> + }
>> +
>> + const char *names_audioterminal(u_int16_t termt)
>> +@@ -282,6 +316,105 @@ int get_subclass_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls)
>> +
>> + /* ---------------------------------------------------------------------- */
>> +
>> ++static int new_vendor(const char *name, u_int16_t vendorid)
>> ++{
>> ++    struct vendor *v;
>> ++    unsigned int h = hashnum(vendorid);
>> ++
>> ++    v = vendors[h];
>> ++    for (; v; v = v->next)
>> ++            if (v->vendorid == vendorid)
>> ++                    return -1;
>> ++    v = malloc(sizeof(struct vendor) + strlen(name));
>> ++    if (!v)
>> ++            return -1;
>> ++    strcpy(v->name, name);
>> ++    v->vendorid = vendorid;
>> ++    v->next = vendors[h];
>> ++    vendors[h] = v;
>> ++    return 0;
>> ++}
>> ++
>> ++static int new_product(const char *name, u_int16_t vendorid,
>> u_int16_t productid)
>> ++{
>> ++    struct product *p;
>> ++    unsigned int h = hashnum((vendorid << 16) | productid);
>> ++
>> ++    p = products[h];
>> ++    for (; p; p = p->next)
>> ++            if (p->vendorid == vendorid && p->productid == productid)
>> ++                    return -1;
>> ++    p = malloc(sizeof(struct product) + strlen(name));
>> ++    if (!p)
>> ++            return -1;
>> ++    strcpy(p->name, name);
>> ++    p->vendorid = vendorid;
>> ++    p->productid = productid;
>> ++    p->next = products[h];
>> ++    products[h] = p;
>> ++    return 0;
>> ++}
>> ++
>> ++static int new_class(const char *name, u_int8_t classid)
>> ++{
>> ++    struct class *c;
>> ++    unsigned int h = hashnum(classid);
>> ++
>> ++    c = classes[h];
>> ++    for (; c; c = c->next)
>> ++            if (c->classid == classid)
>> ++                    return -1;
>> ++    c = malloc(sizeof(struct class) + strlen(name));
>> ++    if (!c)
>> ++            return -1;
>> ++    strcpy(c->name, name);
>> ++    c->classid = classid;
>> ++    c->next = classes[h];
>> ++    classes[h] = c;
>> ++    return 0;
>> ++}
>> ++
>> ++static int new_subclass(const char *name, u_int8_t classid,
>> u_int8_t subclassid)
>> ++{
>> ++    struct subclass *s;
>> ++    unsigned int h = hashnum((classid << 8) | subclassid);
>> ++
>> ++    s = subclasses[h];
>> ++    for (; s; s = s->next)
>> ++            if (s->classid == classid && s->subclassid == subclassid)
>> ++                    return -1;
>> ++    s = malloc(sizeof(struct subclass) + strlen(name));
>> ++    if (!s)
>> ++            return -1;
>> ++    strcpy(s->name, name);
>> ++    s->classid = classid;
>> ++    s->subclassid = subclassid;
>> ++    s->next = subclasses[h];
>> ++    subclasses[h] = s;
>> ++    return 0;
>> ++}
>> ++
>> ++static int new_protocol(const char *name, u_int8_t classid,
>> u_int8_t subclassid, u_int8_t protocolid)
>> ++{
>> ++    struct protocol *p;
>> ++    unsigned int h = hashnum((classid << 16) | (subclassid << 8) | protocolid);
>> ++
>> ++    p = protocols[h];
>> ++    for (; p; p = p->next)
>> ++            if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid)
>> ++                    return -1;
>> ++    p = malloc(sizeof(struct protocol) + strlen(name));
>> ++    if (!p)
>> ++            return -1;
>> ++    strcpy(p->name, name);
>> ++    p->classid = classid;
>> ++    p->subclassid = subclassid;
>> ++    p->protocolid = protocolid;
>> ++    p->next = protocols[h];
>> ++    protocols[h] = p;
>> ++    return 0;
>> ++}
>> ++
>> + static int new_audioterminal(const char *name, u_int16_t termt)
>> + {
>> +     struct audioterminal *at;
>> +@@ -380,6 +513,86 @@ static int new_countrycode(const char *name, unsigned int countrycode)
>> +
>> + /* ---------------------------------------------------------------------- */
>> +
>> ++static void free_vendor(void)
>> ++{
>> ++    struct vendor *cur, *tmp;
>> ++    int i;
>> ++
>> ++    for (i = 0; i < HASHSZ; i++) {
>> ++            cur = vendors[i];
>> ++            vendors[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> ++    }
>> ++}
>> ++
>> ++static void free_product(void)
>> ++{
>> ++    struct product *cur, *tmp;
>> ++    int i;
>> ++
>> ++    for (i = 0; i < HASHSZ; i++) {
>> ++            cur = products[i];
>> ++            products[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> ++    }
>> ++}
>> ++
>> ++static void free_class(void)
>> ++{
>> ++    struct class *cur, *tmp;
>> ++    int i;
>> ++
>> ++    for (i = 0; i < HASHSZ; i++) {
>> ++            cur = classes[i];
>> ++            classes[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> ++    }
>> ++}
>> ++
>> ++static void free_subclass(void)
>> ++{
>> ++    struct subclass *cur, *tmp;
>> ++    int i;
>> ++
>> ++    for (i = 0; i < HASHSZ; i++) {
>> ++            cur = subclasses[i];
>> ++            subclasses[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> ++    }
>> ++}
>> ++
>> ++static void free_protocol(void)
>> ++{
>> ++    struct protocol *cur, *tmp;
>> ++    int i;
>> ++
>> ++    for (i = 0; i < HASHSZ; i++) {
>> ++            cur = protocols[i];
>> ++            protocols[i] = NULL;
>> ++            while (cur) {
>> ++                    tmp = cur;
>> ++                    cur = cur->next;
>> ++                    free(tmp);
>> ++            }
>> ++    }
>> ++}
>> ++
>> + static void free_audioterminal(void)
>> + {
>> +     struct audioterminal *cur, *tmp;
>> +@@ -552,6 +765,29 @@ static void parse(usb_file f)
>> +                     lastlang = u;
>> +                     continue;
>> +             }
>> ++            if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
>> ++                    /* class spec */
>> ++                    cp = buf+2;
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!isxdigit(*cp)) {
>> ++                            fprintf(stderr, "Invalid class spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid class spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_class(cp, u))
>> ++                            fprintf(stderr, "Duplicate class spec at line %u class %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u class %02x %s\n", linectr, u, cp));
>> ++                    lasthut = lastlang = lastvendor = lastsubclass = -1;
>> ++                    lastclass = u;
>> ++                    continue;
>> ++            }
>> +             if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
>> +                     /* audio terminal type spec */
>> +                     cp = buf+3;
>> +@@ -615,6 +851,22 @@ static void parse(usb_file f)
>> +                     DBG(printf("line %5u keyboard country code %02u %s\n", linectr, u, cp));
>> +                     continue;
>> +             }
>> ++            if (isxdigit(*cp)) {
>> ++                    /* vendor */
>> ++                    u = strtoul(cp, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid vendor spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (new_vendor(cp, u))
>> ++                            fprintf(stderr, "Duplicate vendor spec at line %u vendor %04x %s\n", linectr, u, cp);
>> ++                    DBG(printf("line %5u vendor %04x %s\n", linectr, u, cp));
>> ++                    lastvendor = u;
>> ++                    lasthut = lastlang = lastclass = lastsubclass = -1;
>> ++                    continue;
>> ++            }
>> +             if (buf[0] == '\t' && isxdigit(buf[1])) {
>> +                     /* product or subclass spec */
>> +                     u = strtoul(buf+1, &cp, 16);
>> +@@ -624,6 +876,19 @@ static void parse(usb_file f)
>> +                             fprintf(stderr, "Invalid product/subclass spec at line %u\n", linectr);
>> +                             continue;
>> +                     }
>> ++                    if (lastvendor != -1) {
>> ++                            if (new_product(cp, lastvendor, u))
>> ++                                    fprintf(stderr, "Duplicate product spec at line %u product %04x:%04x %s\n", linectr, lastvendor, u, cp);
>> ++                            DBG(printf("line %5u product %04x:%04x %s\n", linectr, lastvendor, u, cp));
>> ++                            continue;
>> ++                    }
>> ++                    if (lastclass != -1) {
>> ++                            if (new_subclass(cp, lastclass, u))
>> ++                                    fprintf(stderr, "Duplicate subclass spec at line %u class %02x:%02x %s\n", linectr, lastclass, u, cp);
>> ++                            DBG(printf("line %5u subclass %02x:%02x %s\n", linectr, lastclass, u, cp));
>> ++                            lastsubclass = u;
>> ++                            continue;
>> ++                    }
>> +                     if (lasthut != -1) {
>> +                             if (new_hutus(cp, (lasthut << 16)+u))
>> +                                     fprintf(stderr, "Duplicate HUT Usage Spec at line %u\n", linectr);
>> +@@ -637,6 +902,24 @@ static void parse(usb_file f)
>> +                     fprintf(stderr, "Product/Subclass spec without prior Vendor/Class spec at line %u\n", linectr);
>> +                     continue;
>> +             }
>> ++            if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
>> ++                    /* protocol spec */
>> ++                    u = strtoul(buf+2, &cp, 16);
>> ++                    while (isspace(*cp))
>> ++                            cp++;
>> ++                    if (!*cp) {
>> ++                            fprintf(stderr, "Invalid protocol spec at line %u\n", linectr);
>> ++                            continue;
>> ++                    }
>> ++                    if (lastclass != -1 && lastsubclass != -1) {
>> ++                            if (new_protocol(cp, lastclass, lastsubclass, u))
>> ++                                    fprintf(stderr, "Duplicate protocol spec at line %u class %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp);
>> ++                            DBG(printf("line %5u protocol %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp));
>> ++                            continue;
>> ++                    }
>> ++                    fprintf(stderr, "Protocol spec without prior Class and Subclass spec at line %u\n", linectr);
>> ++                    continue;
>> ++            }
>> +             if (buf[0] == 'H' && buf[1] == 'I' && buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
>> +                     cp = buf + 4;
>> +                     while (isspace(*cp))
>> +@@ -711,25 +994,23 @@ static void parse(usb_file f)
>> + int names_init(char *n)
>> + {
>> +     usb_file f;
>> +-    int r = 0;
>> +
>> +     f = usb_fopen(n, "r");
>> +     if (!f)
>> +-            r = errno;
>> ++            return errno;
>> +
>> +     parse(f);
>> +     usb_close(f);
>> +-
>> +-    udev = udev_new();
>> +-    hwdb = udev_hwdb_new(udev);
>> +-
>> +-    return r;
>> ++    return 0;
>> + }
>> +
>> + void names_exit(void)
>> + {
>> +-    hwdb = udev_hwdb_unref(hwdb);
>> +-    udev = udev_unref(udev);
>> ++    free_vendor();
>> ++    free_product();
>> ++    free_class();
>> ++    free_subclass();
>> ++    free_protocol();
>> +     free_audioterminal();
>> +     free_videoterminal();
>> +     free_genericstrtable();
>> +--
>> +2.16.2
>> +
>> diff --git
>> a/package/utils/usbutils/patches/040-add-back-update-usbids.patch
>> b/package/utils/usbutils/patches/040-add-back-update-usbids.patch
>> new file mode 100644 index 0000000000..c2df737cfc
>> --- /dev/null
>> +++ b/package/utils/usbutils/patches/040-add-back-update-usbids.patch
>> @@ -0,0 +1,66 @@
>> +From 41ae595f349cd7ceab74f5c92727abf104be164a Mon Sep 17
>> 00:00:00 2001 +From: Rosen Penev <rosenp@gmail.com> +Date: Fri,
>> 9 Mar 2018 13:10:06 -0800 +Subject: [PATCH] Revert "drop unused
>> input file for usb.ids update script"
>> +
>> +This reverts commit 15536b7ab056a960cefe0651a5d50dc558e2f66d.
>> +---
>> + update-usbids.sh.in | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>> + 1 files changed, 47 insertions(+)
>> + create mode 100755 update-usbids.sh.in
>> +
>> +diff --git a/update-usbids.sh.in b/update-usbids.sh.in +new
>> file mode 100755 +index 0000000..4a487ed
>> +--- /dev/null
>> ++++ b/update-usbids.sh.in
>> +@@ -0,0 +1,46 @@
>> ++#!/bin/sh
>> ++
>> ++# see also update-pciids.sh (fancier)
>> ++
>> ++[ "$1" = "-q" ] && quiet="true" || quiet="false"
>> ++
>> ++set -e
>> ++SRC="http://www.linux-usb.org/usb.ids"
>> ++DEST=@usbids@
>> ++
>> ++# if usb.ids is read-only (because the filesystem is read-only),
>> ++# then just skip this whole process.
>> ++if ! touch ${DEST} >&2 >/dev/null ; then
>> ++    ${quiet} || echo "${DEST} is read-only, exiting."
>> ++    exit 0
>> ++fi
>> ++
>> ++if which wget >/dev/null 2>&1 ; then
>> ++    DL="wget -O $DEST.new $SRC"
>> ++    ${quiet} && DL="$DL -q"
>> ++elif which lynx >/dev/null 2>&1 ; then
>> ++    DL="eval lynx -source $SRC >$DEST.new"
>> ++else
>> ++    echo >&2 "update-usbids: cannot find wget nor lynx"
>> ++    exit 1
>> ++fi
>> ++
>> ++if ! $DL ; then
>> ++    echo >&2 "update-usbids: download failed"
>> ++    rm -f $DEST.new
>> ++    exit 1
>> ++fi
>> ++
>> ++if ! grep >/dev/null "^C " $DEST.new ; then
>> ++    echo >&2 "update-usbids: missing class info, probably truncated file"
>> ++    exit 1
>> ++fi
>> ++
>> ++if [ -f $DEST ] ; then
>> ++    mv $DEST $DEST.old
>> ++    # --reference is supported only by chmod from GNU file, so let's ignore any errors
>> ++    chmod -f --reference=$DEST.old $DEST.new 2>/dev/null || true
>> ++fi
>> ++mv $DEST.new $DEST
>> ++
>> ++${quiet} || echo "Done."
>> +--
>> +2.16.2
>> +
Rosen Penev March 15, 2018, 11:35 p.m. UTC | #3
On Wed, Mar 14, 2018 at 11:59 PM, Bjørn Mork <bjorn@mork.no> wrote:
> Great!
>
> Note that the OpenWrt usbreset utility has been included in this version
> of usbutils.  usbreset is currently packaged separately with its source.
> Maybe consider merging the two source packages and start building
> usbreset as part of the usbutils package?
I'll ask jow what he thinks about doing so. Contingent on this getting
merged though. No idea if nbd wants this or the monstrosity that is
udev.
>
>
>
> Bjørn
>
> _______________________________________________
> Lede-dev mailing list
> Lede-dev@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev
diff mbox series

Patch

diff --git a/package/utils/usbutils/Makefile b/package/utils/usbutils/Makefile
index 7f798954ae..3fbc4e0b50 100644
--- a/package/utils/usbutils/Makefile
+++ b/package/utils/usbutils/Makefile
@@ -8,15 +8,17 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=usbutils
-PKG_VERSION:=007
-PKG_RELEASE:=7
+PKG_VERSION:=009
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=@KERNEL/linux/utils/usb/usbutils
-PKG_HASH:=7593a01724bbc0fd9fe48e62bc721ceb61c76654f1d7b231b3c65f6dfbbaefa4
+PKG_HASH:=8bbff0e54cb5f65a52be4feb9162fc0b022a97eb841b44784f7a89a9ea567160
 PKG_LICENSE:=GPL-2.0
 PKG_LICENSE_FILES:=COPYING
 
+PKG_FIXUP:=autoreconf
+
 PKG_BUILD_PARALLEL:=1
 PKG_INSTALL:=1
 
diff --git a/package/utils/usbutils/patches/010-remove-python-usbids.patch b/package/utils/usbutils/patches/010-remove-python-usbids.patch
new file mode 100644
index 0000000000..19e3cc1dd3
--- /dev/null
+++ b/package/utils/usbutils/patches/010-remove-python-usbids.patch
@@ -0,0 +1,68 @@ 
+From a1c2fd7bbd5b2e26f8f752fd3386a953b3b1ec37 Mon Sep 17 00:00:00 2001
+From: Rosen Penev <rosenp@gmail.com>
+Date: Fri, 9 Mar 2018 10:31:09 -0800
+Subject: [PATCH] Revert "substitute usb.id location in lsusb Python script"
+
+This reverts commit 199756013624bfa497865eb498bf7331eb07ef56.
+---
+ Makefile.am             | 7 +------
+ lsusb.py.in => lsusb.py | 4 ++--
+ 3 files changed, 3 insertions(+), 9 deletions(-)
+ rename lsusb.py.in => lsusb.py (99%)
+ mode change 100644 => 100755
+
+diff --git a/Makefile.am b/Makefile.am
+index b18ff69..67def60 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -39,13 +39,9 @@ EXTRA_DIST = \
+ 	lsusb.8.in \
+ 	usb-devices.1.in \
+ 	usb-devices \
+-	lsusb.py.in \
++	lsusb.py \
+ 	usbutils.pc.in
+ 
+-lsusb.py: $(srcdir)/lsusb.py.in
+-	sed 's|VERSION|$(VERSION)|g;s|@usbids@|$(datadir)/usb.ids|g' $< >$@
+-	chmod 755 $@
+-
+ lsusb.8: $(srcdir)/lsusb.8.in
+ 	sed 's|VERSION|$(VERSION)|g;s|@usbids@|$(datadir)/usb.ids|g' $< >$@
+ 
+@@ -59,7 +55,6 @@ usbutils.pc: $(srcdir)/usbutils.pc.in
+ 	sed 's|@usbids@|$(datadir)/usb.ids|g;s|@VERSION[@]|$(VERSION)|g' $< >$@
+ 
+ DISTCLEANFILES = \
+-	lsusb.py \
+ 	lsusb.8 \
+ 	usb-devices.1 \
+ 	usbutils.pc
+diff --git a/lsusb.py.in b/lsusb.py
+old mode 100644
+new mode 100755
+similarity index 99%
+rename from lsusb.py.in
+rename to lsusb.py
+index db2e1e0..aa410fc
+--- a/lsusb.py.in
++++ b/lsusb.py
+@@ -1,5 +1,5 @@
+ #!/usr/bin/env python
+-# lsusb-VERSION.py
++# lsusb.py
+ # Displays your USB devices in reasonable form.
+ # (c) Kurt Garloff <garloff@suse.de>, 2/2009, GPL v2 or v3.
+ # (c) Kurt Garloff <kurt@garloff.de>, 9/2013, GPL v2 or v3.
+@@ -18,7 +18,7 @@ warnsort = False
+ showeps = False
+ 
+ prefix = "/sys/bus/usb/devices/"
+-usbids = "@usbids@"
++usbids = "/usr/share/usb.ids"
+ 
+ esc = chr(27)
+ norm = esc + "[0;0m"
+-- 
+2.16.2
+
diff --git a/package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch b/package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch
new file mode 100644
index 0000000000..ae38b06a77
--- /dev/null
+++ b/package/utils/usbutils/patches/020-revert-removal-of-usb.ids.patch
@@ -0,0 +1,879 @@ 
+From 2bfca703b324e21aee2fabbe4f998aa663f03a15 Mon Sep 17 00:00:00 2001
+From: Rosen Penev <rosenp@gmail.com>
+Date: Fri, 9 Mar 2018 10:31:24 -0800
+Subject: [PATCH] Revert "drop dependency on usb.ids"
+
+This reverts commit 5d7ea40bc94cbf3069a25beba3146de13bcdcf02.
+---
+ Makefile.am  |    27 +-
+ configure.ac |    12 +
+ lsusb.c      |    13 +-
+ names.c      |   600 +-
+ names.h      |     2 +-
+ 5 files changed, 18559 insertions(+), 1775 deletions(-)
+ delete mode 100644 usb-spec.h
+ create mode 100644 usb.ids
+
+diff --git a/Makefile.am b/Makefile.am
+index 67def60..31afb20 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -20,7 +20,6 @@ lsusb_SOURCES = \
+ 	lsusb-t.c \
+ 	list.h \
+ 	names.c names.h \
+-	usb-spec.h \
+ 	usbmisc.c usbmisc.h
+ 
+ lsusb_CPPFLAGS = \
+@@ -31,17 +30,41 @@ lsusb_LDADD = \
+ 	$(LIBUSB_LIBS) \
+ 	$(UDEV_LIBS)
+ 
++if HAVE_ZLIB
++lsusb_CPPFLAGS += -DHAVE_LIBZ
++lsusb_LDADD += -lz
++endif
++
+ man_MANS = \
+ 	lsusb.8	\
+ 	usb-devices.1
+ 
+ EXTRA_DIST = \
++	usb.ids \
++	update-usbids.sh.in \
+ 	lsusb.8.in \
+ 	usb-devices.1.in \
+ 	usb-devices \
+ 	lsusb.py \
+ 	usbutils.pc.in
+ 
++if INSTALL_USBIDS
++data_DATA += usb.ids
++
++if HAVE_ZLIB
++data_DATA += usb.ids.gz
++endif
++
++sbin_SCRIPTS += update-usbids.sh
++
++usb.ids.gz: $(srcdir)/usb.ids
++	gzip -c -9 $< > $@
++
++update-usbids.sh: $(srcdir)/update-usbids.sh.in
++	sed 's|@usbids@|$(datadir)/usb.ids|g' $< >$@
++	chmod 755 $@
++endif
++
+ lsusb.8: $(srcdir)/lsusb.8.in
+ 	sed 's|VERSION|$(VERSION)|g;s|@usbids@|$(datadir)/usb.ids|g' $< >$@
+ 
+@@ -55,8 +78,10 @@ usbutils.pc: $(srcdir)/usbutils.pc.in
+ 	sed 's|@usbids@|$(datadir)/usb.ids|g;s|@VERSION[@]|$(VERSION)|g' $< >$@
+ 
+ DISTCLEANFILES = \
++	usb.ids.gz \
+ 	lsusb.8 \
+ 	usb-devices.1 \
++	update-usbids.sh \
+ 	usbutils.pc
+ 
+ distclean-local:
+diff --git a/configure.ac b/configure.ac
+index a62748c..89d62f9 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -12,6 +12,18 @@ AC_SYS_LARGEFILE
+ AC_CHECK_HEADERS([byteswap.h])
+ AC_CHECK_FUNCS([nl_langinfo iconv])
+ 
++AC_ARG_ENABLE(zlib,
++	AS_HELP_STRING(--disable-zlib,disable support for zlib))
++
++HAVE_ZLIB=no
++AS_IF([test "x$enable_zlib" != "xno"],
++	[AC_CHECK_LIB(z, inflateEnd, HAVE_ZLIB=yes)])
++AM_CONDITIONAL(HAVE_ZLIB, [test "$HAVE_ZLIB" = "yes"])
++
++AC_ARG_ENABLE(usbids,
++	AS_HELP_STRING(--disable-usbids, [disable installing usb.ids @<:@default=install@:>@]))
++AM_CONDITIONAL([INSTALL_USBIDS], [test "x$enable_usbids" != "xno"])
++
+ PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.9)
+ 
+ PKG_CHECK_MODULES(UDEV, libudev >= 196)
+diff --git a/lsusb.c b/lsusb.c
+index f611f2e..969997c 100644
+--- a/lsusb.c
++++ b/lsusb.c
+@@ -4340,9 +4340,16 @@ int main(int argc, char *argv[])
+ 
+ 
+ 	/* by default, print names as well as numbers */
+-	if (names_init() < 0)
+-		fprintf(stderr, "unable to initialize usb spec");
+-
++	err = names_init(DATADIR "/usb.ids");
++#ifdef HAVE_LIBZ
++	if (err != 0)
++		err = names_init(DATADIR "/usb.ids.gz");
++#endif
++	if (err != 0)
++		fprintf(stderr, "%s: cannot open \"%s\", %s\n",
++				argv[0],
++				DATADIR "/usb.ids",
++				strerror(err));
+ 	status = 0;
+ 
+ 	if (treemode) {
+diff --git a/names.c b/names.c
+index a151484..f543240 100644
+--- a/names.c
++++ b/names.c
+@@ -37,13 +37,47 @@
+ 
+ #include <libudev.h>
+ 
+-#include "usb-spec.h"
++#ifdef HAVE_LIBZ
++#include <zlib.h>
++#define 	usb_file			gzFile
++#define 	usb_fopen(path, mode) 		gzopen(path, mode)
++#define 	usb_fgets(s, size, stream)	gzgets(stream, s, size)
++#define 	usb_close(f)			gzclose(f)
++#else
++#define 	usb_file			FILE *
++#define 	usb_fopen(path, mode)		fopen(path, mode)
++#define 	usb_fgets(s, size, stream)	fgets(s, size, stream)
++#define 	usb_close(f)			fclose(f)
++#endif
++
+ #include "names.h"
+ 
+ 
++/* ---------------------------------------------------------------------- */
++
++struct audioterminal {
++	struct audioterminal *next;
++	u_int16_t termt;
++	char name[1];
++};
++
++struct videoterminal {
++	struct videoterminal *next;
++	u_int16_t termt;
++	char name[1];
++};
++
++struct genericstrtable {
++	struct genericstrtable *next;
++	unsigned int num;
++	char name[1];
++};
++
++/* ---------------------------------------------------------------------- */
++
+ #define HASH1  0x10
+ #define HASH2  0x02
+-#define HASHSZ 512
++#define HASHSZ 16
+ 
+ static unsigned int hashnum(unsigned int num)
+ {
+@@ -59,16 +93,16 @@ static unsigned int hashnum(unsigned int num)
+ 
+ static struct udev *udev = NULL;
+ static struct udev_hwdb *hwdb = NULL;
+-static struct audioterminal *audioterminals_hash[HASHSZ] = { NULL, };
+-static struct videoterminal *videoterminals_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *hiddescriptors_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *reports_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *huts_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *biass_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *physdess_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *hutus_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *langids_hash[HASHSZ] = { NULL, };
+-static struct genericstrtable *countrycodes_hash[HASHSZ] = { NULL, };
++static struct audioterminal *audioterminals[HASHSZ] = { NULL, };
++static struct videoterminal *videoterminals[HASHSZ] = { NULL, };
++static struct genericstrtable *hiddescriptors[HASHSZ] = { NULL, };
++static struct genericstrtable *reports[HASHSZ] = { NULL, };
++static struct genericstrtable *huts[HASHSZ] = { NULL, };
++static struct genericstrtable *biass[HASHSZ] = { NULL, };
++static struct genericstrtable *physdess[HASHSZ] = { NULL, };
++static struct genericstrtable *hutus[HASHSZ] = { NULL, };
++static struct genericstrtable *langids[HASHSZ] = { NULL, };
++static struct genericstrtable *countrycodes[HASHSZ] = { NULL, };
+ 
+ /* ---------------------------------------------------------------------- */
+ 
+@@ -85,42 +119,42 @@ static const char *names_genericstrtable(struct genericstrtable *t[HASHSZ],
+ 
+ const char *names_hid(u_int8_t hidd)
+ {
+-	return names_genericstrtable(hiddescriptors_hash, hidd);
++	return names_genericstrtable(hiddescriptors, hidd);
+ }
+ 
+ const char *names_reporttag(u_int8_t rt)
+ {
+-	return names_genericstrtable(reports_hash, rt);
++	return names_genericstrtable(reports, rt);
+ }
+ 
+ const char *names_huts(unsigned int data)
+ {
+-	return names_genericstrtable(huts_hash, data);
++	return names_genericstrtable(huts, data);
+ }
+ 
+ const char *names_hutus(unsigned int data)
+ {
+-	return names_genericstrtable(hutus_hash, data);
++	return names_genericstrtable(hutus, data);
+ }
+ 
+ const char *names_langid(u_int16_t langid)
+ {
+-	return names_genericstrtable(langids_hash, langid);
++	return names_genericstrtable(langids, langid);
+ }
+ 
+ const char *names_physdes(u_int8_t ph)
+ {
+-	return names_genericstrtable(physdess_hash, ph);
++	return names_genericstrtable(physdess, ph);
+ }
+ 
+ const char *names_bias(u_int8_t b)
+ {
+-	return names_genericstrtable(biass_hash, b);
++	return names_genericstrtable(biass, b);
+ }
+ 
+ const char *names_countrycode(unsigned int countrycode)
+ {
+-	return names_genericstrtable(countrycodes_hash, countrycode);
++	return names_genericstrtable(countrycodes, countrycode);
+ }
+ 
+ static const char *hwdb_get(const char *modalias, const char *key)
+@@ -178,7 +212,7 @@ const char *names_audioterminal(u_int16_t termt)
+ {
+ 	struct audioterminal *at;
+ 
+-	at = audioterminals_hash[hashnum(termt)];
++	at = audioterminals[hashnum(termt)];
+ 	for (; at; at = at->next)
+ 		if (at->termt == termt)
+ 			return at->name;
+@@ -189,7 +223,7 @@ const char *names_videoterminal(u_int16_t termt)
+ {
+ 	struct videoterminal *vt;
+ 
+-	vt = videoterminals_hash[hashnum(termt)];
++	vt = videoterminals[hashnum(termt)];
+ 	for (; vt; vt = vt->next)
+ 		if (vt->termt == termt)
+ 			return vt->name;
+@@ -248,189 +282,446 @@ int get_subclass_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls)
+ 
+ /* ---------------------------------------------------------------------- */
+ 
+-static int hash_audioterminal(struct audioterminal *at)
++static int new_audioterminal(const char *name, u_int16_t termt)
+ {
+-	struct audioterminal *at_old;
+-	unsigned int h = hashnum(at->termt);
++	struct audioterminal *at;
++	unsigned int h = hashnum(termt);
+ 
+-	for (at_old = audioterminals_hash[h]; at_old; at_old = at_old->next)
+-		if (at_old->termt == at->termt)
++	at = audioterminals[h];
++	for (; at; at = at->next)
++		if (at->termt == termt)
+ 			return -1;
+-	at->next = audioterminals_hash[h];
+-	audioterminals_hash[h] = at;
++	at = malloc(sizeof(struct audioterminal) + strlen(name));
++	if (!at)
++		return -1;
++	strcpy(at->name, name);
++	at->termt = termt;
++	at->next = audioterminals[h];
++	audioterminals[h] = at;
+ 	return 0;
+ }
+ 
+-static int hash_audioterminals(void)
+-{
+-	int r = 0, i, k;
+-
+-	for (i = 0; audioterminals[i].name; i++)
+-	{
+-		k = hash_audioterminal(&audioterminals[i]);
+-		if (k < 0)
+-			r = k;
+-	}
+-
+-	return r;
+-}
+-
+-static int hash_videoterminal(struct videoterminal *vt)
++static int new_videoterminal(const char *name, u_int16_t termt)
+ {
+-	struct videoterminal *vt_old;
+-	unsigned int h = hashnum(vt->termt);
++	struct videoterminal *vt;
++	unsigned int h = hashnum(termt);
+ 
+-	for (vt_old = videoterminals_hash[h]; vt_old; vt_old = vt_old->next)
+-		if (vt_old->termt == vt->termt)
++	vt = videoterminals[h];
++	for (; vt; vt = vt->next)
++		if (vt->termt == termt)
+ 			return -1;
+-	vt->next = videoterminals_hash[h];
+-	videoterminals_hash[h] = vt;
++	vt = malloc(sizeof(struct videoterminal) + strlen(name));
++	if (!vt)
++		return -1;
++	strcpy(vt->name, name);
++	vt->termt = termt;
++	vt->next = videoterminals[h];
++	videoterminals[h] = vt;
+ 	return 0;
+ }
+ 
+-static int hash_videoterminals(void)
+-{
+-	int r = 0, i, k;
+-
+-	for (i = 0; videoterminals[i].name; i++)
+-	{
+-		k = hash_videoterminal(&videoterminals[i]);
+-		if (k < 0)
+-			r = k;
+-	}
+-
+-	return r;
+-}
+-
+-static int hash_genericstrtable(struct genericstrtable *t[HASHSZ],
+-			       struct genericstrtable *g)
++static int new_genericstrtable(struct genericstrtable *t[HASHSZ],
++			       const char *name, unsigned int idx)
+ {
+-	struct genericstrtable *g_old;
+-	unsigned int h = hashnum(g->num);
++	struct genericstrtable *g;
++	unsigned int h = hashnum(idx);
+ 
+-	for (g_old = t[h]; g_old; g_old = g_old->next)
+-		if (g_old->num == g->num)
++	for (g = t[h]; g; g = g->next)
++		if (g->num == idx)
+ 			return -1;
++	g = malloc(sizeof(struct genericstrtable) + strlen(name));
++	if (!g)
++		return -1;
++	strcpy(g->name, name);
++	g->num = idx;
+ 	g->next = t[h];
+ 	t[h] = g;
+ 	return 0;
+ }
+ 
+-#define HASH_EACH(array, hash) \
+-	for (i = 0; array[i].name; i++) { \
+-		k = hash_genericstrtable(hash, &array[i]); \
+-		if (k < 0) { \
+-			r = k; \
+-		}\
+-	}
+-
+-static int hash_tables(void)
++static int new_hid(const char *name, u_int8_t hidd)
+ {
+-	int r = 0, k, i;
+-
+-	k = hash_audioterminals();
+-	if (k < 0)
+-		r = k;
+-
+-	k = hash_videoterminals();
+-	if (k < 0)
+-		r = k;
+-
+-	HASH_EACH(hiddescriptors, hiddescriptors_hash);
+-
+-	HASH_EACH(reports, reports_hash);
+-
+-	HASH_EACH(huts, huts_hash);
++	return new_genericstrtable(hiddescriptors, name, hidd);
++}
+ 
+-	HASH_EACH(hutus, hutus_hash);
++static int new_reporttag(const char *name, u_int8_t rt)
++{
++	return new_genericstrtable(reports, name, rt);
++}
+ 
+-	HASH_EACH(langids, langids_hash);
++static int new_huts(const char *name, unsigned int data)
++{
++	return new_genericstrtable(huts, name, data);
++}
+ 
+-	HASH_EACH(physdess, physdess_hash);
++static int new_hutus(const char *name, unsigned int data)
++{
++	return new_genericstrtable(hutus, name, data);
++}
+ 
+-	HASH_EACH(biass, biass_hash);
++static int new_langid(const char *name, u_int16_t langid)
++{
++	return new_genericstrtable(langids, name, langid);
++}
+ 
+-	HASH_EACH(countrycodes, countrycodes_hash);
++static int new_physdes(const char *name, u_int8_t ph)
++{
++	return new_genericstrtable(physdess, name, ph);
++}
++static int new_bias(const char *name, u_int8_t b)
++{
++	return new_genericstrtable(biass, name, b);
++}
+ 
+-	return r;
++static int new_countrycode(const char *name, unsigned int countrycode)
++{
++	return new_genericstrtable(countrycodes, name, countrycode);
+ }
+ 
+ /* ---------------------------------------------------------------------- */
+ 
+-/*
+-static void print_tables(void)
++static void free_audioterminal(void)
+ {
++	struct audioterminal *cur, *tmp;
+ 	int i;
+-	struct audioterminal *at;
+-	struct videoterminal *vt;
+-	struct genericstrtable *li;
+-	struct genericstrtable *hu;
+-
+-
+-	printf("--------------------------------------------\n");
+-	printf("\t\t Audio Terminals\n");
+-	printf("--------------------------------------------\n");
+ 
+ 	for (i = 0; i < HASHSZ; i++) {
+-		printf("hash: %d\n", i);
+-		at = audioterminals_hash[i];
+-		for (; at; at = at->next)
+-			printf("\tentry: %s\n", at->name);
++		cur = audioterminals[i];
++		audioterminals[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
+ 	}
++	return;
++}
+ 
+-	printf("--------------------------------------------\n");
+-	printf("\t\t Video Terminals\n");
+-	printf("--------------------------------------------\n");
++static void free_videoterminal(void)
++{
++	struct videoterminal *cur, *tmp;
++	int i;
+ 
+ 	for (i = 0; i < HASHSZ; i++) {
+-		printf("hash: %d\n", i);
+-		vt = videoterminals_hash[i];
+-		for (; vt; vt = vt->next)
+-			printf("\tentry: %s\n", vt->name);
++		cur = videoterminals[i];
++		videoterminals[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
+ 	}
++}
+ 
+-	printf("--------------------------------------------\n");
+-	printf("\t\t Languages\n");
+-	printf("--------------------------------------------\n");
++static void _free_genericstrtable(struct genericstrtable *t[HASHSZ])
++{
++	struct genericstrtable *cur, *tmp;
++	int i;
+ 
+ 	for (i = 0; i < HASHSZ; i++) {
+-		li = langids_hash[i];
+-		if (li)
+-			printf("hash: %d\n", i);
+-		for (; li; li = li->next)
+-			printf("\tid: %x, entry: %s\n", li->num, li->name);
++		cur = t[i];
++		t[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
+ 	}
++}
+ 
+-	printf("--------------------------------------------\n");
+-	printf("\t\t Conutry Codes\n");
+-	printf("--------------------------------------------\n");
++static void free_genericstrtable(void)
++{
++	_free_genericstrtable(hiddescriptors);
++	_free_genericstrtable(reports);
++	_free_genericstrtable(huts);
++	_free_genericstrtable(biass);
++	_free_genericstrtable(physdess);
++	_free_genericstrtable(hutus);
++	_free_genericstrtable(langids);
++	_free_genericstrtable(countrycodes);
++}
+ 
+-	for (i = 0; i < HASHSZ; i++) {
+-		hu = countrycodes_hash[i];
+-		if (hu)
+-			printf("hash: %d\n", i);
+-		for (; hu; hu = hu->next)
+-			printf("\tid: %x, entry: %s\n", hu->num, hu->name);
+-	}
++#define DBG(x)
+ 
+-	printf("--------------------------------------------\n");
++static void parse(usb_file f)
++{
++	char buf[512], *cp;
++	unsigned int linectr = 0;
++	int lastvendor = -1;
++	int lastclass = -1;
++	int lastsubclass = -1;
++	int lasthut = -1;
++	int lastlang = -1;
++	unsigned int u;
++
++	while (usb_fgets(buf, sizeof(buf), f)) {
++		linectr++;
++		/* remove line ends */
++		cp = strchr(buf, 13);
++		if (cp)
++			*cp = 0;
++		cp = strchr(buf, 10);
++		if (cp)
++			*cp = 0;
++		if (buf[0] == '#' || !buf[0])
++			continue;
++		cp = buf;
++		if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && buf[3] == 'S' && buf[4] == 'D' &&
++		    buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ buf[7] == ' ') {
++			cp = buf + 8;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid Physdes type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid Physdes type at line %u\n", linectr);
++				continue;
++			}
++			if (new_physdes(cp, u))
++				fprintf(stderr, "Duplicate Physdes  type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u physdes type %02x %s\n", linectr, u, cp));
++			continue;
++
++		}
++		if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
++			cp = buf + 4;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid PHY type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid PHY type at line %u\n", linectr);
++				continue;
++			}
++			if (new_physdes(cp, u))
++				fprintf(stderr, "Duplicate PHY type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u PHY type %02x %s\n", linectr, u, cp));
++			continue;
++
++		}
++		if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
++			cp = buf + 5;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid BIAS type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid BIAS type at line %u\n", linectr);
++				continue;
++			}
++			if (new_bias(cp, u))
++				fprintf(stderr, "Duplicate BIAS  type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u BIAS type %02x %s\n", linectr, u, cp));
++			continue;
++
++		}
++		if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
++			cp =  buf+2;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr);
++				continue;
++			}
++			if (new_langid(cp, u))
++				fprintf(stderr, "Duplicate LANGID spec at line %u language-id %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u LANGID %02x %s\n", linectr, u, cp));
++			lasthut = lastclass = lastvendor = lastsubclass = -1;
++			lastlang = u;
++			continue;
++		}
++		if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
++			/* audio terminal type spec */
++			cp = buf+3;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr);
++				continue;
++			}
++			if (new_audioterminal(cp, u))
++				fprintf(stderr, "Duplicate audio terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u audio terminal type %02x %s\n", linectr, u, cp));
++			continue;
++		}
++		if (buf[0] == 'V' && buf[1] == 'T' && isspace(buf[2])) {
++			/* video terminal type spec */
++			cp = buf+3;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid video terminal type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid video terminal type at line %u\n", linectr);
++				continue;
++			}
++			if (new_videoterminal(cp, u))
++				fprintf(stderr, "Duplicate video terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u video terminal type %02x %s\n", linectr, u, cp));
++			continue;
++		}
++		if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' && isspace(buf[3])) {
++			/* HID Descriptor bCountryCode */
++			cp =  buf+3;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid HID country code at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 10);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid HID country code at line %u\n", linectr);
++				continue;
++			}
++			if (new_countrycode(cp, u))
++				fprintf(stderr, "Duplicate HID country code at line %u country %02u %s\n", linectr, u, cp);
++			DBG(printf("line %5u keyboard country code %02u %s\n", linectr, u, cp));
++			continue;
++		}
++		if (buf[0] == '\t' && isxdigit(buf[1])) {
++			/* product or subclass spec */
++			u = strtoul(buf+1, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid product/subclass spec at line %u\n", linectr);
++				continue;
++			}
++			if (lasthut != -1) {
++				if (new_hutus(cp, (lasthut << 16)+u))
++					fprintf(stderr, "Duplicate HUT Usage Spec at line %u\n", linectr);
++				continue;
++			}
++			if (lastlang != -1) {
++				if (new_langid(cp, lastlang+(u<<10)))
++					fprintf(stderr, "Duplicate LANGID Usage Spec at line %u\n", linectr);
++				continue;
++			}
++			fprintf(stderr, "Product/Subclass spec without prior Vendor/Class spec at line %u\n", linectr);
++			continue;
++		}
++		if (buf[0] == 'H' && buf[1] == 'I' && buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
++			cp = buf + 4;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid HID type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid HID type at line %u\n", linectr);
++				continue;
++			}
++			if (new_hid(cp, u))
++				fprintf(stderr, "Duplicate HID type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u HID type %02x %s\n", linectr, u, cp));
++			continue;
++
++		}
++		if (buf[0] == 'H' && buf[1] == 'U' && buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
++			cp = buf + 4;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid HUT type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid HUT type at line %u\n", linectr);
++				continue;
++			}
++			if (new_huts(cp, u))
++				fprintf(stderr, "Duplicate HUT type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			lastlang = lastclass = lastvendor = lastsubclass = -1;
++			lasthut = u;
++			DBG(printf("line %5u HUT type %02x %s\n", linectr, u, cp));
++			continue;
++
++		}
++		if (buf[0] == 'R' && buf[1] == ' ') {
++			cp = buf + 2;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid Report type at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid Report type at line %u\n", linectr);
++				continue;
++			}
++			if (new_reporttag(cp, u))
++				fprintf(stderr, "Duplicate Report type spec at line %u terminal type %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u Report type %02x %s\n", linectr, u, cp));
++			continue;
++
++		}
++		fprintf(stderr, "Unknown line at line %u\n", linectr);
++	}
+ }
+-*/
+ 
+-int names_init(void)
++/* ---------------------------------------------------------------------- */
++
++int names_init(char *n)
+ {
+-	int r;
++	usb_file f;
++	int r = 0;
+ 
+-	udev = udev_new();
+-	if (!udev)
+-		r = -1;
+-	else {
+-		hwdb = udev_hwdb_new(udev);
+-		if (!hwdb)
+-			r = -1;
+-	}
++	f = usb_fopen(n, "r");
++	if (!f)
++		r = errno;
+ 
+-	r = hash_tables();
++	parse(f);
++	usb_close(f);
++
++	udev = udev_new();
++	hwdb = udev_hwdb_new(udev);
+ 
+ 	return r;
+ }
+@@ -439,4 +730,7 @@ void names_exit(void)
+ {
+ 	hwdb = udev_hwdb_unref(hwdb);
+ 	udev = udev_unref(udev);
++	free_audioterminal();
++	free_videoterminal();
++	free_genericstrtable();
+ }
+diff --git a/names.h b/names.h
+index 32e887c..0eba890 100644
+--- a/names.h
++++ b/names.h
+@@ -49,7 +49,7 @@ extern int get_product_string(char *buf, size_t size, u_int16_t vid, u_int16_t p
+ extern int get_class_string(char *buf, size_t size, u_int8_t cls);
+ extern int get_subclass_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls);
+ 
+-extern int names_init(void);
++extern int names_init(char *n);
+ extern void names_exit(void);
+ 
+ /* ---------------------------------------------------------------------- */
+--- 
+-2.16.2
diff --git a/package/utils/usbutils/patches/030-revert-port-to-hwdb.patch b/package/utils/usbutils/patches/030-revert-port-to-hwdb.patch
new file mode 100644
index 0000000000..fc41456893
--- /dev/null
+++ b/package/utils/usbutils/patches/030-revert-port-to-hwdb.patch
@@ -0,0 +1,529 @@ 
+From bfb94e20c8ca6eff73e8722165994a45da7cf47c Mon Sep 17 00:00:00 2001
+From: Rosen Penev <rosenp@gmail.com>
+Date: Fri, 9 Mar 2018 10:33:52 -0800
+Subject: [PATCH] Revert "lsusb: port to hwdb"
+
+This reverts commit c6282a7a0e20fbb9c56837f055843635a43ba8b4.
+---
+ Makefile.am  |   5 +-
+ configure.ac |   2 -
+ names.c      | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
+ 3 files changed, 323 insertions(+), 45 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 31afb20..60df9a0 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -23,12 +23,11 @@ lsusb_SOURCES = \
+ 	usbmisc.c usbmisc.h
+ 
+ lsusb_CPPFLAGS = \
+-	$(AM_CPPFLAGS) $(LIBUSB_CFLAGS) $(UDEV_CFLAGS) \
++	$(AM_CPPFLAGS) $(LIBUSB_CFLAGS) \
+ 	-DDATADIR=\"$(datadir)\"
+ 
+ lsusb_LDADD = \
+-	$(LIBUSB_LIBS) \
+-	$(UDEV_LIBS)
++	$(LIBUSB_LIBS)
+ 
+ if HAVE_ZLIB
+ lsusb_CPPFLAGS += -DHAVE_LIBZ
+diff --git a/configure.ac b/configure.ac
+index 89d62f9..4b86c9b 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -26,8 +26,6 @@ AM_CONDITIONAL([INSTALL_USBIDS], [test "x$enable_usbids" != "xno"])
+ 
+ PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.0)
+ 
+-PKG_CHECK_MODULES(UDEV, libudev >= 196)
+-
+ AC_CONFIG_HEADERS([config.h])
+ AC_CONFIG_FILES([
+ 	Makefile
+diff --git a/names.c b/names.c
+index f543240..12cbd60 100644
+--- a/names.c
++++ b/names.c
+@@ -3,7 +3,6 @@
+  *      names.c  --  USB name database manipulation routines
+  *
+  *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+- *      Copyright (C) 2013  Tom Gundersen (teg@jklm.no)
+  *
+  *      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
+@@ -35,8 +34,6 @@
+ #include <stdio.h>
+ #include <ctype.h>
+ 
+-#include <libudev.h>
+-
+ #ifdef HAVE_LIBZ
+ #include <zlib.h>
+ #define 	usb_file			gzFile
+@@ -55,6 +52,36 @@
+ 
+ /* ---------------------------------------------------------------------- */
+ 
++struct vendor {
++	struct vendor *next;
++	u_int16_t vendorid;
++	char name[1];
++};
++
++struct product {
++	struct product *next;
++	u_int16_t vendorid, productid;
++	char name[1];
++};
++
++struct class {
++	struct class *next;
++	u_int8_t classid;
++	char name[1];
++};
++
++struct subclass {
++	struct subclass *next;
++	u_int8_t classid, subclassid;
++	char name[1];
++};
++
++struct protocol {
++	struct protocol *next;
++	u_int8_t classid, subclassid, protocolid;
++	char name[1];
++};
++
+ struct audioterminal {
+ 	struct audioterminal *next;
+ 	u_int16_t termt;
+@@ -91,8 +118,11 @@ static unsigned int hashnum(unsigned int num)
+ 
+ /* ---------------------------------------------------------------------- */
+ 
+-static struct udev *udev = NULL;
+-static struct udev_hwdb *hwdb = NULL;
++static struct vendor *vendors[HASHSZ] = { NULL, };
++static struct product *products[HASHSZ] = { NULL, };
++static struct class *classes[HASHSZ] = { NULL, };
++static struct subclass *subclasses[HASHSZ] = { NULL, };
++static struct protocol *protocols[HASHSZ] = { NULL, };
+ static struct audioterminal *audioterminals[HASHSZ] = { NULL, };
+ static struct videoterminal *videoterminals[HASHSZ] = { NULL, };
+ static struct genericstrtable *hiddescriptors[HASHSZ] = { NULL, };
+@@ -157,55 +187,59 @@ const char *names_countrycode(unsigned int countrycode)
+ 	return names_genericstrtable(countrycodes, countrycode);
+ }
+ 
+-static const char *hwdb_get(const char *modalias, const char *key)
+-{
+-	struct udev_list_entry *entry;
+-
+-	udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
+-		if (strcmp(udev_list_entry_get_name(entry), key) == 0)
+-			return udev_list_entry_get_value(entry);
+-
+-	return NULL;
+-}
+-
+ const char *names_vendor(u_int16_t vendorid)
+ {
+-	char modalias[64];
++	struct vendor *v;
+ 
+-	sprintf(modalias, "usb:v%04X*", vendorid);
+-	return hwdb_get(modalias, "ID_VENDOR_FROM_DATABASE");
++	v = vendors[hashnum(vendorid)];
++	for (; v; v = v->next)
++		if (v->vendorid == vendorid)
++			return v->name;
++	return NULL;
+ }
+ 
+ const char *names_product(u_int16_t vendorid, u_int16_t productid)
+ {
+-	char modalias[64];
++	struct product *p;
+ 
+-	sprintf(modalias, "usb:v%04Xp%04X*", vendorid, productid);
+-	return hwdb_get(modalias, "ID_MODEL_FROM_DATABASE");
++	p = products[hashnum((vendorid << 16) | productid)];
++	for (; p; p = p->next)
++		if (p->vendorid == vendorid && p->productid == productid)
++			return p->name;
++	return NULL;
+ }
+ 
+ const char *names_class(u_int8_t classid)
+ {
+-	char modalias[64];
++	struct class *c;
+ 
+-	sprintf(modalias, "usb:v*p*d*dc%02X*", classid);
+-	return hwdb_get(modalias, "ID_USB_CLASS_FROM_DATABASE");
++	c = classes[hashnum(classid)];
++	for (; c; c = c->next)
++		if (c->classid == classid)
++			return c->name;
++	return NULL;
+ }
+ 
+ const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
+ {
+-	char modalias[64];
++	struct subclass *s;
+ 
+-	sprintf(modalias, "usb:v*p*d*dc%02Xdsc%02X*", classid, subclassid);
+-	return hwdb_get(modalias, "ID_USB_SUBCLASS_FROM_DATABASE");
++	s = subclasses[hashnum((classid << 8) | subclassid)];
++	for (; s; s = s->next)
++		if (s->classid == classid && s->subclassid == subclassid)
++			return s->name;
++	return NULL;
+ }
+ 
+ const char *names_protocol(u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid)
+ {
+-	char modalias[64];
++	struct protocol *p;
+ 
+-	sprintf(modalias, "usb:v*p*d*dc%02Xdsc%02Xdp%02X*", classid, subclassid, protocolid);
+-	return hwdb_get(modalias, "ID_USB_PROTOCOL_FROM_DATABASE");
++	p = protocols[hashnum((classid << 16) | (subclassid << 8) | protocolid)];
++	for (; p; p = p->next)
++		if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid)
++			return p->name;
++	return NULL;
+ }
+ 
+ const char *names_audioterminal(u_int16_t termt)
+@@ -282,6 +316,105 @@ int get_subclass_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls)
+ 
+ /* ---------------------------------------------------------------------- */
+ 
++static int new_vendor(const char *name, u_int16_t vendorid)
++{
++	struct vendor *v;
++	unsigned int h = hashnum(vendorid);
++
++	v = vendors[h];
++	for (; v; v = v->next)
++		if (v->vendorid == vendorid)
++			return -1;
++	v = malloc(sizeof(struct vendor) + strlen(name));
++	if (!v)
++		return -1;
++	strcpy(v->name, name);
++	v->vendorid = vendorid;
++	v->next = vendors[h];
++	vendors[h] = v;
++	return 0;
++}
++
++static int new_product(const char *name, u_int16_t vendorid, u_int16_t productid)
++{
++	struct product *p;
++	unsigned int h = hashnum((vendorid << 16) | productid);
++
++	p = products[h];
++	for (; p; p = p->next)
++		if (p->vendorid == vendorid && p->productid == productid)
++			return -1;
++	p = malloc(sizeof(struct product) + strlen(name));
++	if (!p)
++		return -1;
++	strcpy(p->name, name);
++	p->vendorid = vendorid;
++	p->productid = productid;
++	p->next = products[h];
++	products[h] = p;
++	return 0;
++}
++
++static int new_class(const char *name, u_int8_t classid)
++{
++	struct class *c;
++	unsigned int h = hashnum(classid);
++
++	c = classes[h];
++	for (; c; c = c->next)
++		if (c->classid == classid)
++			return -1;
++	c = malloc(sizeof(struct class) + strlen(name));
++	if (!c)
++		return -1;
++	strcpy(c->name, name);
++	c->classid = classid;
++	c->next = classes[h];
++	classes[h] = c;
++	return 0;
++}
++
++static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
++{
++	struct subclass *s;
++	unsigned int h = hashnum((classid << 8) | subclassid);
++
++	s = subclasses[h];
++	for (; s; s = s->next)
++		if (s->classid == classid && s->subclassid == subclassid)
++			return -1;
++	s = malloc(sizeof(struct subclass) + strlen(name));
++	if (!s)
++		return -1;
++	strcpy(s->name, name);
++	s->classid = classid;
++	s->subclassid = subclassid;
++	s->next = subclasses[h];
++	subclasses[h] = s;
++	return 0;
++}
++
++static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid)
++{
++	struct protocol *p;
++	unsigned int h = hashnum((classid << 16) | (subclassid << 8) | protocolid);
++
++	p = protocols[h];
++	for (; p; p = p->next)
++		if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid)
++			return -1;
++	p = malloc(sizeof(struct protocol) + strlen(name));
++	if (!p)
++		return -1;
++	strcpy(p->name, name);
++	p->classid = classid;
++	p->subclassid = subclassid;
++	p->protocolid = protocolid;
++	p->next = protocols[h];
++	protocols[h] = p;
++	return 0;
++}
++
+ static int new_audioterminal(const char *name, u_int16_t termt)
+ {
+ 	struct audioterminal *at;
+@@ -380,6 +513,86 @@ static int new_countrycode(const char *name, unsigned int countrycode)
+ 
+ /* ---------------------------------------------------------------------- */
+ 
++static void free_vendor(void)
++{
++	struct vendor *cur, *tmp;
++	int i;
++
++	for (i = 0; i < HASHSZ; i++) {
++		cur = vendors[i];
++		vendors[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
++	}
++}
++
++static void free_product(void)
++{
++	struct product *cur, *tmp;
++	int i;
++
++	for (i = 0; i < HASHSZ; i++) {
++		cur = products[i];
++		products[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
++	}
++}
++
++static void free_class(void)
++{
++	struct class *cur, *tmp;
++	int i;
++
++	for (i = 0; i < HASHSZ; i++) {
++		cur = classes[i];
++		classes[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
++	}
++}
++
++static void free_subclass(void)
++{
++	struct subclass *cur, *tmp;
++	int i;
++
++	for (i = 0; i < HASHSZ; i++) {
++		cur = subclasses[i];
++		subclasses[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
++	}
++}
++
++static void free_protocol(void)
++{
++	struct protocol *cur, *tmp;
++	int i;
++
++	for (i = 0; i < HASHSZ; i++) {
++		cur = protocols[i];
++		protocols[i] = NULL;
++		while (cur) {
++			tmp = cur;
++			cur = cur->next;
++			free(tmp);
++		}
++	}
++}
++
+ static void free_audioterminal(void)
+ {
+ 	struct audioterminal *cur, *tmp;
+@@ -552,6 +765,29 @@ static void parse(usb_file f)
+ 			lastlang = u;
+ 			continue;
+ 		}
++		if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
++			/* class spec */
++			cp = buf+2;
++			while (isspace(*cp))
++				cp++;
++			if (!isxdigit(*cp)) {
++				fprintf(stderr, "Invalid class spec at line %u\n", linectr);
++				continue;
++			}
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid class spec at line %u\n", linectr);
++				continue;
++			}
++			if (new_class(cp, u))
++				fprintf(stderr, "Duplicate class spec at line %u class %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u class %02x %s\n", linectr, u, cp));
++			lasthut = lastlang = lastvendor = lastsubclass = -1;
++			lastclass = u;
++			continue;
++		}
+ 		if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
+ 			/* audio terminal type spec */
+ 			cp = buf+3;
+@@ -615,6 +851,22 @@ static void parse(usb_file f)
+ 			DBG(printf("line %5u keyboard country code %02u %s\n", linectr, u, cp));
+ 			continue;
+ 		}
++		if (isxdigit(*cp)) {
++			/* vendor */
++			u = strtoul(cp, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid vendor spec at line %u\n", linectr);
++				continue;
++			}
++			if (new_vendor(cp, u))
++				fprintf(stderr, "Duplicate vendor spec at line %u vendor %04x %s\n", linectr, u, cp);
++			DBG(printf("line %5u vendor %04x %s\n", linectr, u, cp));
++			lastvendor = u;
++			lasthut = lastlang = lastclass = lastsubclass = -1;
++			continue;
++		}
+ 		if (buf[0] == '\t' && isxdigit(buf[1])) {
+ 			/* product or subclass spec */
+ 			u = strtoul(buf+1, &cp, 16);
+@@ -624,6 +876,19 @@ static void parse(usb_file f)
+ 				fprintf(stderr, "Invalid product/subclass spec at line %u\n", linectr);
+ 				continue;
+ 			}
++			if (lastvendor != -1) {
++				if (new_product(cp, lastvendor, u))
++					fprintf(stderr, "Duplicate product spec at line %u product %04x:%04x %s\n", linectr, lastvendor, u, cp);
++				DBG(printf("line %5u product %04x:%04x %s\n", linectr, lastvendor, u, cp));
++				continue;
++			}
++			if (lastclass != -1) {
++				if (new_subclass(cp, lastclass, u))
++					fprintf(stderr, "Duplicate subclass spec at line %u class %02x:%02x %s\n", linectr, lastclass, u, cp);
++				DBG(printf("line %5u subclass %02x:%02x %s\n", linectr, lastclass, u, cp));
++				lastsubclass = u;
++				continue;
++			}
+ 			if (lasthut != -1) {
+ 				if (new_hutus(cp, (lasthut << 16)+u))
+ 					fprintf(stderr, "Duplicate HUT Usage Spec at line %u\n", linectr);
+@@ -637,6 +902,24 @@ static void parse(usb_file f)
+ 			fprintf(stderr, "Product/Subclass spec without prior Vendor/Class spec at line %u\n", linectr);
+ 			continue;
+ 		}
++		if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
++			/* protocol spec */
++			u = strtoul(buf+2, &cp, 16);
++			while (isspace(*cp))
++				cp++;
++			if (!*cp) {
++				fprintf(stderr, "Invalid protocol spec at line %u\n", linectr);
++				continue;
++			}
++			if (lastclass != -1 && lastsubclass != -1) {
++				if (new_protocol(cp, lastclass, lastsubclass, u))
++					fprintf(stderr, "Duplicate protocol spec at line %u class %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp);
++				DBG(printf("line %5u protocol %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp));
++				continue;
++			}
++			fprintf(stderr, "Protocol spec without prior Class and Subclass spec at line %u\n", linectr);
++			continue;
++		}
+ 		if (buf[0] == 'H' && buf[1] == 'I' && buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
+ 			cp = buf + 4;
+ 			while (isspace(*cp))
+@@ -711,25 +994,23 @@ static void parse(usb_file f)
+ int names_init(char *n)
+ {
+ 	usb_file f;
+-	int r = 0;
+ 
+ 	f = usb_fopen(n, "r");
+ 	if (!f)
+-		r = errno;
++		return errno;
+ 
+ 	parse(f);
+ 	usb_close(f);
+-
+-	udev = udev_new();
+-	hwdb = udev_hwdb_new(udev);
+-
+-	return r;
++	return 0;
+ }
+ 
+ void names_exit(void)
+ {
+-	hwdb = udev_hwdb_unref(hwdb);
+-	udev = udev_unref(udev);
++	free_vendor();
++	free_product();
++	free_class();
++	free_subclass();
++	free_protocol();
+ 	free_audioterminal();
+ 	free_videoterminal();
+ 	free_genericstrtable();
+-- 
+2.16.2
+
diff --git a/package/utils/usbutils/patches/040-add-back-update-usbids.patch b/package/utils/usbutils/patches/040-add-back-update-usbids.patch
new file mode 100644
index 0000000000..c2df737cfc
--- /dev/null
+++ b/package/utils/usbutils/patches/040-add-back-update-usbids.patch
@@ -0,0 +1,66 @@ 
+From 41ae595f349cd7ceab74f5c92727abf104be164a Mon Sep 17 00:00:00 2001
+From: Rosen Penev <rosenp@gmail.com>
+Date: Fri, 9 Mar 2018 13:10:06 -0800
+Subject: [PATCH] Revert "drop unused input file for usb.ids update script"
+
+This reverts commit 15536b7ab056a960cefe0651a5d50dc558e2f66d.
+---
+ update-usbids.sh.in | 46 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 47 insertions(+)
+ create mode 100755 update-usbids.sh.in
+
+diff --git a/update-usbids.sh.in b/update-usbids.sh.in
+new file mode 100755
+index 0000000..4a487ed
+--- /dev/null
++++ b/update-usbids.sh.in
+@@ -0,0 +1,46 @@
++#!/bin/sh
++
++# see also update-pciids.sh (fancier)
++
++[ "$1" = "-q" ] && quiet="true" || quiet="false"
++
++set -e
++SRC="http://www.linux-usb.org/usb.ids"
++DEST=@usbids@
++
++# if usb.ids is read-only (because the filesystem is read-only),
++# then just skip this whole process.
++if ! touch ${DEST} >&2 >/dev/null ; then
++	${quiet} || echo "${DEST} is read-only, exiting."
++	exit 0
++fi
++
++if which wget >/dev/null 2>&1 ; then
++	DL="wget -O $DEST.new $SRC"
++	${quiet} && DL="$DL -q"
++elif which lynx >/dev/null 2>&1 ; then
++	DL="eval lynx -source $SRC >$DEST.new"
++else
++	echo >&2 "update-usbids: cannot find wget nor lynx"
++	exit 1
++fi
++
++if ! $DL ; then
++	echo >&2 "update-usbids: download failed"
++	rm -f $DEST.new
++	exit 1
++fi
++
++if ! grep >/dev/null "^C " $DEST.new ; then
++	echo >&2 "update-usbids: missing class info, probably truncated file"
++	exit 1
++fi
++
++if [ -f $DEST ] ; then
++	mv $DEST $DEST.old
++	# --reference is supported only by chmod from GNU file, so let's ignore any errors
++	chmod -f --reference=$DEST.old $DEST.new 2>/dev/null || true
++fi
++mv $DEST.new $DEST
++
++${quiet} || echo "Done."
+-- 
+2.16.2
+