Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F140141811
D27890.id81499.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
D27890.id81499.diff
View Options
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -180,6 +180,7 @@
gre.4 \
h_ertt.4 \
hidbus.4 \
+ hidquirk.4 \
hifn.4 \
hpet.4 \
${_hpt27xx.4} \
diff --git a/share/man/man4/hidquirk.4 b/share/man/man4/hidquirk.4
new file mode 100644
--- /dev/null
+++ b/share/man/man4/hidquirk.4
@@ -0,0 +1,143 @@
+.\"
+.\" Copyright (c) 2010 AnyWi Technologies
+.\" All rights reserved.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 16, 2020
+.Dt HIDQUIRK 4
+.Os
+.Sh NAME
+.Nm hidquirk
+.Nd HID quirks module
+.Sh SYNOPSIS
+To compile this module into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device hid"
+.Ed
+.Pp
+Alternatively, to load the module at boot
+time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hidquirk_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+module provides support for adding quirks for HID devices
+.Bl -tag -width Ds
+.It HQ_HID_IGNORE
+device should be ignored by hid class
+.It HQ_KBD_BOOTPROTO
+device should set the boot protocol
+.It HQ_MS_BOOTPROTO
+device should set the boot protocol
+.It HQ_MS_BAD_CLASS
+doesn't identify properly
+.It HQ_MS_LEADING_BYTE
+mouse sends an unknown leading byte
+.It HQ_MS_REVZ
+mouse has Z-axis reversed
+.It HQ_SPUR_BUT_UP
+spurious mouse button up events
+.It HQ_MT_TIMESTAMP
+Multitouch device exports HW timestamps
+.Dv 0x1b5a01
+.El
+.Pp
+See
+.Pa /sys/dev/hid/hidquirk.h
+for the complete list of supported quirks.
+.Sh LOADER TUNABLE
+The following tunable can be set at the
+.Xr loader 8
+prompt before booting the kernel, or stored in
+.Xr loader.conf 5 .
+.Bl -tag -width indent
+.It Va hw.hid.quirk.%d
+The value is a string whose format is:
+.Bd -literal -offset indent
+.Qo BusId VendorId ProductId LowRevision HighRevision HQ_QUIRK,... Qc
+.Ed
+.Pp
+Installs the quirks
+.Ic HQ_QUIRK,...
+for all HID devices matching
+.Ic BusId
+and
+.Ic VendorId
+and
+.Ic ProductId
+which have a hardware revision between and including
+.Ic LowRevision
+and
+.Ic HighRevision .
+.Pp
+.Ic BusId ,
+.Ic VendorId ,
+.Ic ProductId ,
+.Ic LowRevision
+and
+.Ic HighRevision
+are all 16 bits numbers which can be decimal or hexadecimal based.
+.Pp
+A maximum of 100 variables
+.Ic hw.hid.quirk.0, .1, ..., .99
+can be defined.
+.Pp
+If a matching entry is found in the kernel's internal quirks table, it
+is replaced by the new definition.
+.Pp
+Else a new entry is created given that the quirk table is not full.
+.Pp
+The kernel iterates over the
+.Ic hw.hid.quirk.N
+variables starting at
+.Ic N = 0
+and stops at
+.Ic N = 99
+or the first non-existing one.
+.El
+.Sh EXAMPLES
+To install a quirk at boot time, place one or several lines like the
+following in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.hid.quirk.0="0x18 0x6cb 0x1941 0 0xffff HQ_MT_TIMESTAMP"
+.Ed
+.Sh HISTORY
+The
+.Nm
+module appeared in
+.Fx 13.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Hans Petter Selasky Aq Mt hselasky@FreeBSD.org
+for
+.Xr usb 4
+subsystem and adopted to
+.Xr hid 4
+by
+.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
+This manual page is based on
+.Xr usb_quirk 4
+manual page written by
+.An Nick Hibma Aq Mt n_hibma@FreeBSD.org .
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1818,6 +1818,7 @@
dev/hid/hid.c optional hid
dev/hid/hid_if.m optional hid
dev/hid/hidbus.c optional hidbus
+dev/hid/hidquirk.c optional hid
dev/hifn/hifn7751.c optional hifn
dev/hptiop/hptiop.c optional hptiop scbus
dev/hwpmc/hwpmc_logging.c optional hwpmc
diff --git a/sys/dev/hid/hidquirk.c b/sys/dev/hid/hidquirk.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/hid/hidquirk.c
@@ -0,0 +1,437 @@
+/* $FreeBSD$ */
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-NetBSD
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.
+ * Copyright (c) 1998 Lennart Augustsson. All rights reserved.
+ * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
+ * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/evdev/input.h>
+
+#define HID_DEBUG_VAR hid_debug
+#include <dev/hid/hid.h>
+#include <dev/hid/hidquirk.h>
+#include "usbdevs.h"
+
+
+MODULE_DEPEND(hidquirk, hid, 1, 1, 1);
+MODULE_VERSION(hidquirk, 1);
+
+#define HID_DEV_QUIRKS_MAX 384
+#define HID_SUB_QUIRKS_MAX 8
+#define HID_QUIRK_ENVROOT "hw.hid.quirk."
+
+struct hidquirk_entry {
+ uint16_t bus;
+ uint16_t vid;
+ uint16_t pid;
+ uint16_t lo_rev;
+ uint16_t hi_rev;
+ uint16_t quirks[HID_SUB_QUIRKS_MAX];
+};
+
+static struct mtx hidquirk_mtx;
+
+#define HID_QUIRK_VP(b,v,p,l,h,...) \
+ { .bus = (b), .vid = (v), .pid = (p), .lo_rev = (l), .hi_rev = (h), \
+ .quirks = { __VA_ARGS__ } }
+#define USB_QUIRK(v,p,l,h,...) \
+ HID_QUIRK_VP(BUS_USB, USB_VENDOR_##v, USB_PRODUCT_##v##_##p, l, h, __VA_ARGS__)
+
+static struct hidquirk_entry hidquirks[HID_DEV_QUIRKS_MAX] = {
+ USB_QUIRK(ASUS, LCM, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(QTRONIX, 980N, 0x110, 0x110, HQ_SPUR_BUT_UP),
+ USB_QUIRK(ALCOR2, KBD_HUB, 0x001, 0x001, HQ_SPUR_BUT_UP),
+ USB_QUIRK(LOGITECH, G510S, 0x0000, 0xFFFF, HQ_KBD_BOOTPROTO),
+ /* Devices which should be ignored by usbhid */
+ USB_QUIRK(APC, UPS, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6H375USB, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C550AVR, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C1250TWRK, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C1500TWRK, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C900UNV, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C100UNV, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C120UNV, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C800UNV, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(BELKIN, F6C1100UNV, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(CYBERPOWER, BC900D, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(CYBERPOWER, 1500CAVRLCD, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(CYBERPOWER, OR2200LCDRM2U, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(DELL2, VARIOUS_UPS, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(CYPRESS, SILVERSHIELD, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(DELORME, EARTHMATE, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(DREAMLINK, DL100B, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(MICROCHIP, PICOLCD20X2, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(MICROCHIP, PICOLCD4X20, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(LIEBERT, POWERSURE_PXT, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(LIEBERT2, PSI1000, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(LIEBERT2, POWERSURE_PSA, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(MGE, UPS1, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(MGE, UPS2, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(POWERCOM, IMPERIAL_SERIES, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(POWERCOM, SMART_KING_PRO, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(POWERCOM, WOW, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(POWERCOM, VANGUARD, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(POWERCOM, BLACK_KNIGHT_PRO, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, AVR550U, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, AVR750U, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, ECO550UPS, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, T750_INTL, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, RT_2200_INTL, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, OMNI1000LCD, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, OMNI900LCD, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, SMART_2200RMXL2U, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, UPS_3014, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, SU1500RTXL2UA, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, SU6000RT4U, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(TRIPPLITE2, SU1500RTXL2UA_2, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(APPLE, IPHONE, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(APPLE, IPHONE_3G, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(MEGATEC, UPS, 0x0000, 0xffff, HQ_HID_IGNORE),
+ /* Devices which should be ignored by both ukbd and uhid */
+ USB_QUIRK(CYPRESS, WISPY1A, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(METAGEEK, WISPY1B, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(METAGEEK, WISPY24X, 0x0000, 0xffff, HQ_HID_IGNORE),
+ USB_QUIRK(METAGEEK2, WISPYDBX, 0x0000, 0xffff, HQ_HID_IGNORE),
+ /* MS keyboards do weird things */
+ USB_QUIRK(MICROSOFT, NATURAL4000, 0x0000, 0xFFFF, HQ_KBD_BOOTPROTO),
+ USB_QUIRK(MICROSOFT, WLINTELLIMOUSE, 0x0000, 0xffff, HQ_MS_LEADING_BYTE),
+ /* Quirk for Corsair Vengeance K60 keyboard */
+ USB_QUIRK(CORSAIR, K60, 0x0000, 0xffff, HQ_KBD_BOOTPROTO),
+ /* Quirk for Corsair Gaming K68 keyboard */
+ USB_QUIRK(CORSAIR, K68, 0x0000, 0xffff, HQ_KBD_BOOTPROTO),
+ /* Quirk for Corsair Vengeance K70 keyboard */
+ USB_QUIRK(CORSAIR, K70, 0x0000, 0xffff, HQ_KBD_BOOTPROTO),
+ /* Quirk for Corsair K70 RGB keyboard */
+ USB_QUIRK(CORSAIR, K70_RGB, 0x0000, 0xffff, HQ_KBD_BOOTPROTO),
+ /* Quirk for Corsair STRAFE Gaming keyboard */
+ USB_QUIRK(CORSAIR, STRAFE, 0x0000, 0xffff, HQ_KBD_BOOTPROTO),
+ USB_QUIRK(CORSAIR, STRAFE2, 0x0000, 0xffff, HQ_KBD_BOOTPROTO),
+ /* Holtek USB gaming keyboard */
+ USB_QUIRK(HOLTEK, F85, 0x0000, 0xffff, HQ_KBD_BOOTPROTO),
+};
+#undef HID_QUIRK_VP
+#undef USB_QUIRK
+
+/* hidquirk.h exposes only HID_QUIRK_LIST macro when HQ() is defined */
+#define HQ(x) [HQ_##x] = "HQ_"#x
+#include "hidquirk.h"
+static const char *hidquirk_str[HID_QUIRK_MAX] = { HID_QUIRK_LIST() };
+#undef HQ
+
+static hid_test_quirk_t hid_test_quirk_by_info;
+
+/*------------------------------------------------------------------------*
+ * hidquirkstr
+ *
+ * This function converts an USB quirk code into a string.
+ *------------------------------------------------------------------------*/
+static const char *
+hidquirkstr(uint16_t quirk)
+{
+ return ((quirk < HID_QUIRK_MAX && hidquirk_str[quirk] != NULL) ?
+ hidquirk_str[quirk] : "HQ_UNKNOWN");
+}
+
+/*------------------------------------------------------------------------*
+ * hid_strquirk
+ *
+ * This function converts a string into a HID quirk code.
+ *
+ * Returns:
+ * Less than HID_QUIRK_MAX: Quirk code
+ * Else: Quirk code not found
+ *------------------------------------------------------------------------*/
+static uint16_t
+hid_strquirk(const char *str, size_t len)
+{
+ const char *quirk;
+ uint16_t x;
+
+ for (x = 0; x != HID_QUIRK_MAX; x++) {
+ quirk = hidquirkstr(x);
+ if (strncmp(str, quirk, len) == 0 &&
+ quirk[len] == 0)
+ break;
+ }
+ return (x);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_test_quirk_by_info
+ *
+ * Returns:
+ * false: Quirk not found
+ * true: Quirk found
+ *------------------------------------------------------------------------*/
+bool
+hid_test_quirk_by_info(const struct hid_device_info *info, uint16_t quirk)
+{
+ uint16_t x;
+ uint16_t y;
+
+ if (quirk == HQ_NONE)
+ goto done;
+
+ mtx_lock(&hidquirk_mtx);
+
+ for (x = 0; x != HID_DEV_QUIRKS_MAX; x++) {
+ /* see if quirk information does not match */
+ if ((hidquirks[x].bus != info->idBus) ||
+ (hidquirks[x].vid != info->idVendor) ||
+ (hidquirks[x].lo_rev > info->idVersion) ||
+ (hidquirks[x].hi_rev < info->idVersion)) {
+ continue;
+ }
+ /* see if quirk only should match vendor ID */
+ if (hidquirks[x].pid != info->idProduct) {
+ if (hidquirks[x].pid != 0)
+ continue;
+
+ for (y = 0; y != HID_SUB_QUIRKS_MAX; y++) {
+ if (hidquirks[x].quirks[y] == HQ_MATCH_VENDOR_ONLY)
+ break;
+ }
+ if (y == HID_SUB_QUIRKS_MAX)
+ continue;
+ }
+ /* lookup quirk */
+ for (y = 0; y != HID_SUB_QUIRKS_MAX; y++) {
+ if (hidquirks[x].quirks[y] == quirk) {
+ mtx_unlock(&hidquirk_mtx);
+ DPRINTF("Found quirk '%s'.\n", hidquirkstr(quirk));
+ return (true);
+ }
+ }
+ }
+ mtx_unlock(&hidquirk_mtx);
+done:
+ return (false); /* no quirk match */
+}
+
+static struct hidquirk_entry *
+hidquirk_get_entry(uint16_t bus, uint16_t vid, uint16_t pid,
+ uint16_t lo_rev, uint16_t hi_rev, uint8_t do_alloc)
+{
+ uint16_t x;
+
+ mtx_assert(&hidquirk_mtx, MA_OWNED);
+
+ if ((bus | vid | pid | lo_rev | hi_rev) == 0) {
+ /* all zero - special case */
+ return (hidquirks + HID_DEV_QUIRKS_MAX - 1);
+ }
+ /* search for an existing entry */
+ for (x = 0; x != HID_DEV_QUIRKS_MAX; x++) {
+ /* see if quirk information does not match */
+ if ((hidquirks[x].bus != bus) ||
+ (hidquirks[x].vid != vid) ||
+ (hidquirks[x].pid != pid) ||
+ (hidquirks[x].lo_rev != lo_rev) ||
+ (hidquirks[x].hi_rev != hi_rev)) {
+ continue;
+ }
+ return (hidquirks + x);
+ }
+
+ if (do_alloc == 0) {
+ /* no match */
+ return (NULL);
+ }
+ /* search for a free entry */
+ for (x = 0; x != HID_DEV_QUIRKS_MAX; x++) {
+ /* see if quirk information does not match */
+ if ((hidquirks[x].bus |
+ hidquirks[x].vid |
+ hidquirks[x].pid |
+ hidquirks[x].lo_rev |
+ hidquirks[x].hi_rev) != 0) {
+ continue;
+ }
+ hidquirks[x].bus = bus;
+ hidquirks[x].vid = vid;
+ hidquirks[x].pid = pid;
+ hidquirks[x].lo_rev = lo_rev;
+ hidquirks[x].hi_rev = hi_rev;
+
+ return (hidquirks + x);
+ }
+
+ /* no entry found */
+ return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_quirk_strtou16
+ *
+ * Helper function to scan a 16-bit integer.
+ *------------------------------------------------------------------------*/
+static uint16_t
+hidquirk_strtou16(const char **pptr, const char *name, const char *what)
+{
+ unsigned long value;
+ char *end;
+
+ value = strtoul(*pptr, &end, 0);
+ if (value > 65535 || *pptr == end || (*end != ' ' && *end != '\t')) {
+ printf("%s: %s 16-bit %s value set to zero\n",
+ name, what, *end == 0 ? "incomplete" : "invalid");
+ return (0);
+ }
+ *pptr = end + 1;
+ return ((uint16_t)value);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_quirk_add_entry_from_str
+ *
+ * Add a USB quirk entry from string.
+ * "VENDOR PRODUCT LO_REV HI_REV QUIRK[,QUIRK[,...]]"
+ *------------------------------------------------------------------------*/
+static void
+hidquirk_add_entry_from_str(const char *name, const char *env)
+{
+ struct hidquirk_entry entry = { };
+ struct hidquirk_entry *new;
+ uint16_t quirk_idx;
+ uint16_t quirk;
+ const char *end;
+
+ /* check for invalid environment variable */
+ if (name == NULL || env == NULL)
+ return;
+
+ if (bootverbose)
+ printf("Adding HID QUIRK '%s' = '%s'\n", name, env);
+
+ /* parse device information */
+ entry.bus = hidquirk_strtou16(&env, name, "Bus ID");
+ entry.vid = hidquirk_strtou16(&env, name, "Vendor ID");
+ entry.pid = hidquirk_strtou16(&env, name, "Product ID");
+ entry.lo_rev = hidquirk_strtou16(&env, name, "Low revision");
+ entry.hi_rev = hidquirk_strtou16(&env, name, "High revision");
+
+ /* parse quirk information */
+ quirk_idx = 0;
+ while (*env != 0 && quirk_idx != HID_SUB_QUIRKS_MAX) {
+ /* skip whitespace before quirks */
+ while (*env == ' ' || *env == '\t')
+ env++;
+
+ /* look for quirk separation character */
+ end = strchr(env, ',');
+ if (end == NULL)
+ end = env + strlen(env);
+
+ /* lookup quirk in string table */
+ quirk = hid_strquirk(env, end - env);
+ if (quirk < HID_QUIRK_MAX) {
+ entry.quirks[quirk_idx++] = quirk;
+ } else {
+ printf("%s: unknown HID quirk '%.*s' (skipped)\n",
+ name, (int)(end - env), env);
+ }
+ env = end;
+
+ /* skip quirk delimiter, if any */
+ if (*env != 0)
+ env++;
+ }
+
+ /* register quirk */
+ if (quirk_idx != 0) {
+ if (*env != 0) {
+ printf("%s: Too many HID quirks, only %d allowed!\n",
+ name, HID_SUB_QUIRKS_MAX);
+ }
+ mtx_lock(&hidquirk_mtx);
+ new = hidquirk_get_entry(entry.bus, entry.vid, entry.pid,
+ entry.lo_rev, entry.hi_rev, 1);
+ if (new == NULL)
+ printf("%s: HID quirks table is full!\n", name);
+ else
+ memcpy(new->quirks, entry.quirks, sizeof(entry.quirks));
+ mtx_unlock(&hidquirk_mtx);
+ } else {
+ printf("%s: No USB quirks found!\n", name);
+ }
+}
+
+static void
+hidquirk_init(void *arg)
+{
+ char envkey[sizeof(HID_QUIRK_ENVROOT) + 2]; /* 2 digits max, 0 to 99 */
+ int i;
+
+ /* initialize mutex */
+ mtx_init(&hidquirk_mtx, "HID quirk", NULL, MTX_DEF);
+
+ /* look for quirks defined by the environment variable */
+ for (i = 0; i != 100; i++) {
+ snprintf(envkey, sizeof(envkey), HID_QUIRK_ENVROOT "%d", i);
+
+ /* Stop at first undefined var */
+ if (!testenv(envkey))
+ break;
+
+ /* parse environment variable */
+ hidquirk_add_entry_from_str(envkey, kern_getenv(envkey));
+ }
+
+ /* register our function */
+ hid_test_quirk_p = &hid_test_quirk_by_info;
+}
+
+static void
+hidquirk_uninit(void *arg)
+{
+ hid_quirk_unload(arg);
+
+ /* destroy mutex */
+ mtx_destroy(&hidquirk_mtx);
+}
+
+SYSINIT(hidquirk_init, SI_SUB_LOCK, SI_ORDER_FIRST, hidquirk_init, NULL);
+SYSUNINIT(hidquirk_uninit, SI_SUB_LOCK, SI_ORDER_ANY, hidquirk_uninit, NULL);
diff --git a/sys/modules/hid/Makefile b/sys/modules/hid/Makefile
--- a/sys/modules/hid/Makefile
+++ b/sys/modules/hid/Makefile
@@ -2,6 +2,7 @@
SUBDIR = \
hid \
- hidbus
+ hidbus \
+ hidquirk
.include <bsd.subdir.mk>
diff --git a/sys/modules/hid/hidquirk/Makefile b/sys/modules/hid/hidquirk/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/hid/hidquirk/Makefile
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+.PATH: ${SRCTOP}/sys/dev/hid
+
+KMOD= hidquirk
+SRCS= hidquirk.c
+SRCS+= bus_if.h device_if.h usbdevs.h
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 21, 7:00 PM (7 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27103647
Default Alt Text
D27890.id81499.diff (20 KB)
Attached To
Mode
D27890: hid: Import quirk subsystem.
Attached
Detach File
Event Timeline
Log In to Comment