hid: Import quirk subsystem.

hidquirk(4) is derived from usb_quirk(4) and inherits all its HID-related
functionality. It does not support ioctl(2) interface yet.

Reviewed by:	hselasky
Differential revision:	https://reviews.freebsd.org/D27890
This commit is contained in:
Vladimir Kondratyev 2020-10-05 13:42:53 +03:00
parent 2b4464b0b1
commit e49fa9f6f3
6 changed files with 618 additions and 1 deletions

View File

@ -180,6 +180,7 @@ MAN= aac.4 \
gre.4 \
h_ertt.4 \
hidbus.4 \
hidquirk.4 \
hifn.4 \
hpet.4 \
${_hpt27xx.4} \

143
share/man/man4/hidquirk.4 Normal file
View File

@ -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 .

View File

@ -1818,6 +1818,7 @@ dev/gpio/ofw_gpiobus.c optional fdt gpio
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

437
sys/dev/hid/hidquirk.c Normal file
View File

@ -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);

View File

@ -2,6 +2,7 @@
SUBDIR = \
hid \
hidbus
hidbus \
hidquirk
.include <bsd.subdir.mk>

View File

@ -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>