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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define HID_DEBUG_VAR hid_debug +#include +#include +#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 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 +# +# 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