mirror of
https://github.com/openwrt/packages.git
synced 2026-05-31 06:51:51 +08:00
93759026fd
Replace the four stub udev_hwdb_*() functions with a working
implementation that looks up vendor and product names from
/usr/share/hwdata/usb.ids, so callers using the standard libudev
hwdb API benefit without needing package-specific patches.
The patch is a clean backport of upstream commit 2bebebc9e0444
("udev: implement hwdb USB ID lookup from usb.ids (#80)") merged
to illiliti/libudev-zero master on 2026-05-19, post-1.0.3. Drop
when the package is bumped to the next libudev-zero release.
Upstream now defaults USB_IDS_PATH to ${SHAREDIR}/hwdata/usb.ids
with SHAREDIR=${PREFIX}/share, so the explicit
USB_IDS_PATH=/usr/share/hwdata/usb.ids in MAKE_FLAGS is no longer
needed and is dropped.
Fixes: https://github.com/openwrt/packages/issues/29386
Signed-off-by: Alexandru Ardelean <alex@shruggie.ro>
217 lines
6.2 KiB
Diff
217 lines
6.2 KiB
Diff
From 2bebebc9e0444ec53afd7f1f37aa80ff6b95f5f7 Mon Sep 17 00:00:00 2001
|
|
From: Alexandru Ardelean <ardeleanalex@gmail.com>
|
|
Date: Tue, 19 May 2026 17:52:47 +0300
|
|
Subject: [PATCH] udev: implement hwdb USB ID lookup from usb.ids (#80)
|
|
|
|
Replace the four stub udev_hwdb_*() functions with a working
|
|
implementation that looks up vendor and product names from a
|
|
usb.ids database file (e.g. provided by the hwdata package).
|
|
|
|
udev_hwdb_get_properties_list_entry() parses the file for USB
|
|
modalias strings of the form "usb:vVVVVpPPPP" (product lookup)
|
|
or "usb:vVVVV" (vendor lookup), and populates the entry list with
|
|
ID_MODEL_FROM_DATABASE or ID_VENDOR_FROM_DATABASE properties.
|
|
|
|
Lines are read via POSIX getline() so the buffer grows as needed
|
|
on long usb.ids entries.
|
|
|
|
The path to the usb.ids file is set at build time via the
|
|
USB_IDS_PATH Makefile variable, which defaults to
|
|
${SHAREDIR}/hwdata/usb.ids.
|
|
---
|
|
Makefile | 3 ++
|
|
udev.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
|
|
2 files changed, 144 insertions(+), 7 deletions(-)
|
|
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -3,9 +3,12 @@
|
|
|
|
PREFIX = /usr/local
|
|
LIBDIR = ${PREFIX}/lib
|
|
+SHAREDIR = ${PREFIX}/share
|
|
INCLUDEDIR = ${PREFIX}/include
|
|
PKGCONFIGDIR = ${LIBDIR}/pkgconfig
|
|
+USB_IDS_PATH = ${SHAREDIR}/hwdata/usb.ids
|
|
XCFLAGS = ${CPPFLAGS} ${CFLAGS} -std=c99 -fPIC -D_XOPEN_SOURCE=700 \
|
|
+ -DUSB_IDS_PATH=\"${USB_IDS_PATH}\" \
|
|
-Wall -Wextra -Wpedantic -Wmissing-prototypes -Wstrict-prototypes \
|
|
-Wno-unused-parameter
|
|
XLDFLAGS = ${LDFLAGS} -shared -Wl,-soname,libudev.so.1
|
|
--- a/udev.c
|
|
+++ b/udev.c
|
|
@@ -15,9 +15,13 @@
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
+#include <stdio.h>
|
|
+#include <stdint.h>
|
|
#include <stdlib.h>
|
|
+#include <string.h>
|
|
|
|
#include "udev.h"
|
|
+#include "udev_list.h"
|
|
|
|
struct udev {
|
|
int refcount;
|
|
@@ -76,22 +80,152 @@ int udev_get_log_priority(struct udev *u
|
|
return 0;
|
|
}
|
|
|
|
-/* XXX NOT IMPLEMENTED */ struct udev_hwdb *udev_hwdb_new(struct udev *udev)
|
|
+struct udev_hwdb {
|
|
+ struct udev_list_entry head;
|
|
+ int refcount;
|
|
+};
|
|
+
|
|
+static int usb_ids_lookup_vendor(uint16_t vendorid, char *buf, size_t buflen)
|
|
{
|
|
- return NULL;
|
|
+ char *line = NULL, *name;
|
|
+ size_t cap = 0, len;
|
|
+ unsigned int id;
|
|
+ FILE *f;
|
|
+
|
|
+ f = fopen(USB_IDS_PATH, "r");
|
|
+ if (!f) {
|
|
+ return 0;
|
|
+ }
|
|
+ while (getline(&line, &cap, f) != -1) {
|
|
+ if (line[0] == '#' || line[0] == '\t' || line[0] == '\n') {
|
|
+ continue;
|
|
+ }
|
|
+ if (sscanf(line, "%04x", &id) != 1 || id != vendorid) {
|
|
+ continue;
|
|
+ }
|
|
+ name = strchr(line, ' ');
|
|
+ if (name) {
|
|
+ while (*name == ' ') {
|
|
+ name++;
|
|
+ }
|
|
+ len = strlen(name);
|
|
+ while (len > 0 && (name[len - 1] == '\n' || name[len - 1] == '\r')) {
|
|
+ name[--len] = '\0';
|
|
+ }
|
|
+ snprintf(buf, buflen, "%s", name);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ free(line);
|
|
+ fclose(f);
|
|
+ return buf[0] != '\0';
|
|
+}
|
|
+
|
|
+static int usb_ids_lookup_product(uint16_t vendorid, uint16_t productid, char *buf, size_t buflen)
|
|
+{
|
|
+ char *line = NULL, *name;
|
|
+ size_t cap = 0, len;
|
|
+ int in_vendor = 0;
|
|
+ unsigned int id;
|
|
+ FILE *f;
|
|
+
|
|
+ f = fopen(USB_IDS_PATH, "r");
|
|
+ if (!f) {
|
|
+ return 0;
|
|
+ }
|
|
+ while (getline(&line, &cap, f) != -1) {
|
|
+ if (line[0] == '#' || line[0] == '\n') {
|
|
+ continue;
|
|
+ }
|
|
+ if (in_vendor) {
|
|
+ if (line[0] != '\t') {
|
|
+ break;
|
|
+ }
|
|
+ if (line[1] == '\t') {
|
|
+ continue;
|
|
+ }
|
|
+ if (sscanf(line + 1, "%04x", &id) != 1 || id != productid) {
|
|
+ continue;
|
|
+ }
|
|
+ name = strchr(line + 1, ' ');
|
|
+ if (name) {
|
|
+ while (*name == ' ') {
|
|
+ name++;
|
|
+ }
|
|
+ len = strlen(name);
|
|
+ while (len > 0 && (name[len - 1] == '\n' || name[len - 1] == '\r')) {
|
|
+ name[--len] = '\0';
|
|
+ }
|
|
+ snprintf(buf, buflen, "%s", name);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ if (line[0] == '\t') {
|
|
+ continue;
|
|
+ }
|
|
+ if (sscanf(line, "%04x", &id) != 1 || id != vendorid) {
|
|
+ continue;
|
|
+ }
|
|
+ in_vendor = 1;
|
|
+ }
|
|
+ free(line);
|
|
+ fclose(f);
|
|
+ return buf[0] != '\0';
|
|
}
|
|
|
|
-/* XXX NOT IMPLEMENTED */ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb)
|
|
+struct udev_hwdb *udev_hwdb_new(struct udev *udev)
|
|
{
|
|
- return NULL;
|
|
+ struct udev_hwdb *hwdb;
|
|
+
|
|
+ hwdb = calloc(1, sizeof(*hwdb));
|
|
+ if (!hwdb) {
|
|
+ return NULL;
|
|
+ }
|
|
+ hwdb->refcount = 1;
|
|
+ return hwdb;
|
|
}
|
|
|
|
-/* XXX NOT IMPLEMENTED */ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb)
|
|
+struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb)
|
|
{
|
|
- return NULL;
|
|
+ if (!hwdb) {
|
|
+ return NULL;
|
|
+ }
|
|
+ hwdb->refcount++;
|
|
+ return hwdb;
|
|
}
|
|
|
|
-/* XXX NOT IMPLEMENTED */ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags)
|
|
+struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb)
|
|
{
|
|
+ if (!hwdb) {
|
|
+ return NULL;
|
|
+ }
|
|
+ if (--hwdb->refcount > 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+ udev_list_entry_free_all(&hwdb->head);
|
|
+ free(hwdb);
|
|
return NULL;
|
|
}
|
|
+
|
|
+struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags)
|
|
+{
|
|
+ unsigned int vendorid, productid;
|
|
+ char name[64];
|
|
+
|
|
+ if (!hwdb || !modalias) {
|
|
+ return NULL;
|
|
+ }
|
|
+ udev_list_entry_free_all(&hwdb->head);
|
|
+ hwdb->head.next = NULL;
|
|
+ name[0] = '\0';
|
|
+ if (sscanf(modalias, "usb:v%4xp%4x", &vendorid, &productid) == 2) {
|
|
+ if (usb_ids_lookup_product((uint16_t)vendorid, (uint16_t)productid, name, sizeof(name))) {
|
|
+ udev_list_entry_add(&hwdb->head, "ID_MODEL_FROM_DATABASE", name, 0);
|
|
+ }
|
|
+ } else if (sscanf(modalias, "usb:v%4x", &vendorid) == 1) {
|
|
+ if (usb_ids_lookup_vendor((uint16_t)vendorid, name, sizeof(name))) {
|
|
+ udev_list_entry_add(&hwdb->head, "ID_VENDOR_FROM_DATABASE", name, 0);
|
|
+ }
|
|
+ }
|
|
+ return hwdb->head.next;
|
|
+}
|