diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -382,4 +382,5 @@ device uinput # install /dev/uinput cdev # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/arm/conf/EFIKA_MX b/sys/arm/conf/EFIKA_MX --- a/sys/arm/conf/EFIKA_MX +++ b/sys/arm/conf/EFIKA_MX @@ -117,6 +117,7 @@ device wlan_amrr # AMRR transmit rate control algorithm # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support # Flattened Device Tree diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -281,6 +281,7 @@ device aw_thermal # Allwinner Thermal Sensor Controller # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support # Flattened Device Tree diff --git a/sys/arm/conf/IMX53 b/sys/arm/conf/IMX53 --- a/sys/arm/conf/IMX53 +++ b/sys/arm/conf/IMX53 @@ -114,6 +114,7 @@ #device mmcsd # SDCard disk device # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/arm/conf/IMX6 b/sys/arm/conf/IMX6 --- a/sys/arm/conf/IMX6 +++ b/sys/arm/conf/IMX6 @@ -107,6 +107,7 @@ #device wlan_amrr # AMRR transmit rate control algorithm # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support device vt diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -90,6 +90,7 @@ device fdt_pinctrl # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support # Flattened Device Tree diff --git a/sys/arm/conf/TEGRA124 b/sys/arm/conf/TEGRA124 --- a/sys/arm/conf/TEGRA124 +++ b/sys/arm/conf/TEGRA124 @@ -131,6 +131,7 @@ #device snd_hda # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support # Flattened Device Tree diff --git a/sys/arm/conf/VYBRID b/sys/arm/conf/VYBRID --- a/sys/arm/conf/VYBRID +++ b/sys/arm/conf/VYBRID @@ -104,6 +104,7 @@ device ukbd # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support # Flattened Device Tree diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -371,4 +371,5 @@ makeoptions MODULES_EXTRA="dtb/allwinner dtb/freescale dtb/imx8 dtb/mv dtb/rockchip dtb/rpi" # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/conf/options b/sys/conf/options --- a/sys/conf/options +++ b/sys/conf/options @@ -1013,3 +1013,6 @@ # gcov support GCOV opt_global.h LINDEBUGFS + +# options for HID support +HID_DEBUG opt_hid.h diff --git a/sys/dev/hid/hid.h b/sys/dev/hid/hid.h --- a/sys/dev/hid/hid.h +++ b/sys/dev/hid/hid.h @@ -67,6 +67,7 @@ #define HUG_GAME_PAD 0x0005 #define HUG_KEYBOARD 0x0006 #define HUG_KEYPAD 0x0007 +#define HUG_MULTIAXIS_CNTROLLER 0x0008 #define HUG_X 0x0030 #define HUG_Y 0x0031 #define HUG_Z 0x0032 @@ -102,6 +103,12 @@ #define HUG_SYSTEM_MENU_LEFT 0x008b #define HUG_SYSTEM_MENU_UP 0x008c #define HUG_SYSTEM_MENU_DOWN 0x008d +#define HUG_SYSTEM_POWER_UP 0x008e +#define HUG_SYSTEM_RESTART 0x008f +#define HUG_D_PAD_UP 0x0090 +#define HUG_D_PAD_DOWN 0x0091 +#define HUG_D_PAD_RIGHT 0x0092 +#define HUG_D_PAD_LEFT 0x0093 #define HUG_APPLE_EJECT 0x00b8 /* Usages Digitizers */ @@ -147,16 +154,21 @@ #define HUD_SURFACE_SWITCH 0x0057 #define HUD_BUTTONS_SWITCH 0x0058 #define HUD_BUTTON_TYPE 0x0059 +#define HUD_SEC_BARREL_SWITCH 0x005a #define HUD_LATENCY_MODE 0x0060 /* Usages, Consumer */ +#define HUC_CONSUMER_CONTROL 0x0001 +#define HUC_HEADPHONE 0x0005 #define HUC_AC_PAN 0x0238 -#define HID_USAGE2(p,u) (((p) << 16) | (u)) +#define HID_USAGE2(p,u) (((p) << 16) | (u)) +#define HID_GET_USAGE(u) ((u) & 0xffff) +#define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff) -#define UHID_INPUT_REPORT 0x01 -#define UHID_OUTPUT_REPORT 0x02 -#define UHID_FEATURE_REPORT 0x03 +#define HID_INPUT_REPORT 0x01 +#define HID_OUTPUT_REPORT 0x02 +#define HID_FEATURE_REPORT 0x03 /* Bits in the input/output/feature items */ #define HIO_CONST 0x001 @@ -178,6 +190,36 @@ #if defined(_KERNEL) || defined(_STANDALONE) #define HID_ITEM_MAXUSAGE 4 +#define HID_MAX_AUTO_QUIRK 8 /* maximum number of dynamic quirks */ +#define HID_PNP_ID_SIZE 20 /* includes null terminator */ + +/* Declare global HID debug variable. */ +extern int hid_debug; + +/* Check if HID debugging is enabled. */ +#ifdef HID_DEBUG_VAR +#ifdef HID_DEBUG +#define DPRINTFN(n,fmt,...) do { \ + if ((HID_DEBUG_VAR) >= (n)) { \ + printf("%s: " fmt, \ + __FUNCTION__ ,##__VA_ARGS__); \ + } \ +} while (0) +#define DPRINTF(...) DPRINTFN(1, __VA_ARGS__) +#else +#define DPRINTF(...) do { } while (0) +#define DPRINTFN(...) do { } while (0) +#endif +#endif + +/* Declare parent SYSCTL HID node. */ +#ifdef SYSCTL_DECL +SYSCTL_DECL(_hw_hid); +#endif + +typedef uint32_t hid_size_t; + +#define HID_IN_POLLING_MODE() (SCHEDULER_STOPPED() || kdb_active) enum hid_kind { hid_input, hid_output, hid_feature, hid_collection, hid_endcollection @@ -223,25 +265,71 @@ struct hid_location loc; }; +struct hid_absinfo { + int32_t min; + int32_t max; + int32_t res; +}; + +struct hid_device_info { + char name[80]; + char serial[80]; + char idPnP[HID_PNP_ID_SIZE]; + uint16_t idBus; + uint16_t idVendor; + uint16_t idProduct; + uint16_t idVersion; + hid_size_t rdescsize; /* Report descriptor size */ + uint8_t autoQuirk[HID_MAX_AUTO_QUIRK]; +}; + +struct hid_rdesc_info { + void *data; + hid_size_t len; + hid_size_t isize; + hid_size_t osize; + hid_size_t fsize; + uint8_t iid; + uint8_t oid; + uint8_t fid; + /* Max sizes for HID requests supported by transport backend */ + hid_size_t rdsize; + hid_size_t wrsize; + hid_size_t grsize; + hid_size_t srsize; +}; + +typedef void hid_intr_t(void *context, void *data, hid_size_t len); +typedef bool hid_test_quirk_t(const struct hid_device_info *dev_info, + uint16_t quirk); + +extern hid_test_quirk_t *hid_test_quirk_p; + /* prototypes from "usb_hid.c" */ -struct hid_data *hid_start_parse(const void *d, usb_size_t len, int kindset); +struct hid_data *hid_start_parse(const void *d, hid_size_t len, int kindset); void hid_end_parse(struct hid_data *s); int hid_get_item(struct hid_data *s, struct hid_item *h); -int hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, +int hid_report_size(const void *buf, hid_size_t len, enum hid_kind k, + uint8_t id); +int hid_report_size_max(const void *buf, hid_size_t len, enum hid_kind k, uint8_t *id); -int hid_locate(const void *desc, usb_size_t size, int32_t usage, +int hid_locate(const void *desc, hid_size_t size, int32_t usage, enum hid_kind kind, uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id); -int32_t hid_get_data(const uint8_t *buf, usb_size_t len, +int32_t hid_get_data(const uint8_t *buf, hid_size_t len, struct hid_location *loc); -uint32_t hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, +uint32_t hid_get_udata(const uint8_t *buf, hid_size_t len, struct hid_location *loc); -void hid_put_data_unsigned(uint8_t *buf, usb_size_t len, +void hid_put_udata(uint8_t *buf, hid_size_t len, struct hid_location *loc, unsigned int value); -int hid_is_collection(const void *desc, usb_size_t size, int32_t usage); +int hid_is_collection(const void *desc, hid_size_t size, int32_t usage); int32_t hid_item_resolution(struct hid_item *hi); int hid_is_mouse(const void *d_ptr, uint16_t d_len); int hid_is_keyboard(const void *d_ptr, uint16_t d_len); +bool hid_test_quirk(const struct hid_device_info *dev_info, uint16_t quirk); +int hid_add_dynamic_quirk(struct hid_device_info *dev_info, + uint16_t quirk); +void hid_quirk_unload(void *arg); #endif /* _KERNEL || _STANDALONE */ #endif /* _HID_HID_H_ */ diff --git a/sys/dev/hid/hid.c b/sys/dev/hid/hid.c --- a/sys/dev/hid/hid.c +++ b/sys/dev/hid/hid.c @@ -32,45 +32,36 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifdef USB_GLOBAL_INCLUDE_FILE -#include USB_GLOBAL_INCLUDE_FILE -#else -#include -#include +#include "opt_hid.h" + #include -#include -#include -#include -#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 -#define USB_DEBUG_VAR usb_debug +/* + * Define this unconditionally in case a kernel module is loaded that + * has been compiled with debugging options. + */ +int hid_debug = 0; -#include -#include -#include -#include -#include -#endif /* USB_GLOBAL_INCLUDE_FILE */ +SYSCTL_NODE(_hw, OID_AUTO, hid, CTLFLAG_RW, 0, "HID debugging"); +SYSCTL_INT(_hw_hid, OID_AUTO, debug, CTLFLAG_RWTUN, + &hid_debug, 0, "Debug level"); static void hid_clear_local(struct hid_item *); static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize); +static hid_test_quirk_t hid_test_quirk_w; +hid_test_quirk_t *hid_test_quirk_p = &hid_test_quirk_w; + #define MAXUSAGE 64 #define MAXPUSH 4 #define MAXID 16 @@ -180,7 +171,7 @@ * hid_start_parse *------------------------------------------------------------------------*/ struct hid_data * -hid_start_parse(const void *d, usb_size_t len, int kindset) +hid_start_parse(const void *d, hid_size_t len, int kindset) { struct hid_data *s; @@ -574,7 +565,47 @@ * hid_report_size *------------------------------------------------------------------------*/ int -hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, uint8_t *id) +hid_report_size(const void *buf, hid_size_t len, enum hid_kind k, uint8_t id) +{ + struct hid_data *d; + struct hid_item h; + uint32_t temp; + uint32_t hpos; + uint32_t lpos; + int report_id = 0; + + hpos = 0; + lpos = 0xFFFFFFFF; + + for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) { + if (h.kind == k && h.report_ID == id) { + /* compute minimum */ + if (lpos > h.loc.pos) + lpos = h.loc.pos; + /* compute end position */ + temp = h.loc.pos + (h.loc.size * h.loc.count); + /* compute maximum */ + if (hpos < temp) + hpos = temp; + if (h.report_ID != 0) + report_id = 1; + } + } + hid_end_parse(d); + + /* safety check - can happen in case of currupt descriptors */ + if (lpos > hpos) + temp = 0; + else + temp = hpos - lpos; + + /* return length in bytes rounded up */ + return ((temp + 7) / 8 + report_id); +} + +int +hid_report_size_max(const void *buf, hid_size_t len, enum hid_kind k, + uint8_t *id) { struct hid_data *d; struct hid_item h; @@ -627,7 +658,7 @@ * hid_locate *------------------------------------------------------------------------*/ int -hid_locate(const void *desc, usb_size_t size, int32_t u, enum hid_kind k, +hid_locate(const void *desc, hid_size_t size, int32_t u, enum hid_kind k, uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id) { struct hid_data *d; @@ -664,7 +695,7 @@ * hid_get_data *------------------------------------------------------------------------*/ static uint32_t -hid_get_data_sub(const uint8_t *buf, usb_size_t len, struct hid_location *loc, +hid_get_data_sub(const uint8_t *buf, hid_size_t len, struct hid_location *loc, int is_signed) { uint32_t hpos = loc->pos; @@ -708,13 +739,13 @@ } int32_t -hid_get_data(const uint8_t *buf, usb_size_t len, struct hid_location *loc) +hid_get_data(const uint8_t *buf, hid_size_t len, struct hid_location *loc) { return (hid_get_data_sub(buf, len, loc, 1)); } uint32_t -hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, struct hid_location *loc) +hid_get_udata(const uint8_t *buf, hid_size_t len, struct hid_location *loc) { return (hid_get_data_sub(buf, len, loc, 0)); } @@ -723,7 +754,7 @@ * hid_put_data *------------------------------------------------------------------------*/ void -hid_put_data_unsigned(uint8_t *buf, usb_size_t len, +hid_put_udata(uint8_t *buf, hid_size_t len, struct hid_location *loc, unsigned int value) { uint32_t hpos = loc->pos; @@ -760,7 +791,7 @@ * hid_is_collection *------------------------------------------------------------------------*/ int -hid_is_collection(const void *desc, usb_size_t size, int32_t usage) +hid_is_collection(const void *desc, hid_size_t size, int32_t usage) { struct hid_data *hd; struct hid_item hi; @@ -929,4 +960,69 @@ return (0); } +/*------------------------------------------------------------------------* + * hid_test_quirk - test a device for a given quirk + * + * Return values: + * false: The HID device does not have the given quirk. + * true: The HID device has the given quirk. + *------------------------------------------------------------------------*/ +bool +hid_test_quirk(const struct hid_device_info *dev_info, uint16_t quirk) +{ + bool found; + uint8_t x; + + if (quirk == HQ_NONE) + return (false); + + /* search the automatic per device quirks first */ + for (x = 0; x != HID_MAX_AUTO_QUIRK; x++) { + if (dev_info->autoQuirk[x] == quirk) + return (true); + } + + /* search global quirk table, if any */ + found = (hid_test_quirk_p) (dev_info, quirk); + + return (found); +} + +static bool +hid_test_quirk_w(const struct hid_device_info *dev_info, uint16_t quirk) +{ + return (false); /* no match */ +} + +int +hid_add_dynamic_quirk(struct hid_device_info *dev_info, uint16_t quirk) +{ + uint8_t x; + + for (x = 0; x != HID_MAX_AUTO_QUIRK; x++) { + if (dev_info->autoQuirk[x] == 0 || + dev_info->autoQuirk[x] == quirk) { + dev_info->autoQuirk[x] = quirk; + return (0); /* success */ + } + } + return (ENOSPC); +} + +void +hid_quirk_unload(void *arg) +{ + /* reset function pointer */ + hid_test_quirk_p = &hid_test_quirk_w; +#ifdef NOT_YET + hidquirk_ioctl_p = &hidquirk_ioctl_w; +#endif + + /* wait for CPU to exit the loaded functions, if any */ + + /* XXX this is a tradeoff */ + + pause("WAIT", hz); +} + MODULE_VERSION(hid, 1); diff --git a/sys/dev/hid/hidquirk.h b/sys/dev/hid/hidquirk.h new file mode 100644 --- /dev/null +++ b/sys/dev/hid/hidquirk.h @@ -0,0 +1,74 @@ +/* $FreeBSD$ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * 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. + */ + +/* + * Screening of all content of this file except HID_QUIRK_LIST is a kind of + * hack that allows multiple HID_QUIRK_LIST inclusion with different HQ() + * wrappers. That save us splitting hidquirk.h on two header files. + */ +#ifndef HQ +#ifndef _HID_QUIRK_H_ +#define _HID_QUIRK_H_ +#endif + +/* + * Keep in sync with share/man/man4/hidquirk.4 + */ +#define HID_QUIRK_LIST(...) \ + HQ(NONE), /* not a valid quirk */ \ + \ + HQ(MATCH_VENDOR_ONLY), /* match quirk on vendor only */ \ + \ + /* Autoquirks */ \ + HQ(HAS_KBD_BOOTPROTO), /* device supports keyboard boot protocol */ \ + HQ(HAS_MS_BOOTPROTO), /* device supports mouse boot protocol */ \ + HQ(IS_XBOX360GP), /* device is XBox 360 GamePad */ \ + HQ(NOWRITE), /* device does not support writes */ \ + HQ(IICHID_SAMPLING), /* IIC backend runs in sampling mode */ \ + \ + /* Various quirks */ \ + HQ(HID_IGNORE), /* device should be ignored by hid class */ \ + HQ(KBD_BOOTPROTO), /* device should set the boot protocol */ \ + HQ(MS_BOOTPROTO), /* device should set the boot protocol */ \ + HQ(MS_BAD_CLASS), /* doesn't identify properly */ \ + HQ(MS_LEADING_BYTE), /* mouse sends an unknown leading byte */ \ + HQ(MS_REVZ), /* mouse has Z-axis reversed */ \ + HQ(SPUR_BUT_UP), /* spurious mouse button up events */ \ + HQ(MT_TIMESTAMP) /* Multitouch device exports HW timestamps */ + +#ifndef HQ +#define HQ(x) HQ_##x +enum { + HID_QUIRK_LIST(), + HID_QUIRK_MAX +}; +#undef HQ + +#endif /* _HID_QUIRK_H_ */ +#endif /* HQ */ diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -69,6 +69,8 @@ #include #include +#include + #include "usbdevs.h" #include #include @@ -6145,7 +6147,7 @@ } /* check if there is an ID byte */ - hid_report_size(d_ptr, d_len, hid_input, &id); + hid_report_size_max(d_ptr, d_len, hid_input, &id); if (id != 0) sc->sc_hid.flags |= UAUDIO_HID_HAS_ID; diff --git a/sys/dev/usb/input/atp.c b/sys/dev/usb/input/atp.c --- a/sys/dev/usb/input/atp.c +++ b/sys/dev/usb/input/atp.c @@ -79,6 +79,8 @@ #include #include +#include + #include #include #include @@ -2204,7 +2206,7 @@ return (ENXIO); /* Get HID report descriptor length */ - sc->sc_expected_sensor_data_len = hid_report_size(descriptor_ptr, + sc->sc_expected_sensor_data_len = hid_report_size_max(descriptor_ptr, descriptor_len, hid_input, NULL); free(descriptor_ptr, M_TEMP); diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c --- a/sys/dev/usb/input/uhid.c +++ b/sys/dev/usb/input/uhid.c @@ -64,6 +64,8 @@ #include #include +#include + #include "usbdevs.h" #include #include @@ -828,13 +830,13 @@ DPRINTF("set idle failed, error=%s (ignored)\n", usbd_errstr(error)); } - sc->sc_isize = hid_report_size + sc->sc_isize = hid_report_size_max (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid); - sc->sc_osize = hid_report_size + sc->sc_osize = hid_report_size_max (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid); - sc->sc_fsize = hid_report_size + sc->sc_fsize = hid_report_size_max (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid); if (sc->sc_isize > UHID_BSIZE) { diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c --- a/sys/dev/usb/input/ukbd.c +++ b/sys/dev/usb/input/ukbd.c @@ -62,6 +62,8 @@ #include #include +#include + #include #include #include @@ -717,7 +719,7 @@ tmp_loc.count = UKBD_NKEYCODE; while (tmp_loc.count--) { uint32_t key = - hid_get_data_unsigned(sc->sc_buffer, len, &tmp_loc); + hid_get_udata(sc->sc_buffer, len, &tmp_loc); /* advance to next location */ tmp_loc.pos += tmp_loc.size; if (modifiers & MOD_FN) @@ -816,7 +818,7 @@ if (sc->sc_flags & UKBD_FLAG_NUMLOCK) { if (sc->sc_leds & NLKED) { - hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, + hid_put_udata(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, &sc->sc_loc_numlock, 1); } id = sc->sc_id_numlock; @@ -825,7 +827,7 @@ if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) { if (sc->sc_leds & SLKED) { - hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, + hid_put_udata(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, &sc->sc_loc_scrolllock, 1); } id = sc->sc_id_scrolllock; @@ -834,7 +836,7 @@ if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) { if (sc->sc_leds & CLKED) { - hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, + hid_put_udata(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1, &sc->sc_loc_capslock, 1); } id = sc->sc_id_capslock; @@ -983,7 +985,7 @@ memset(sc->sc_loc_key_valid, 0, sizeof(sc->sc_loc_key_valid)); /* check if there is an ID byte */ - sc->sc_kbd_size = hid_report_size(ptr, len, + sc->sc_kbd_size = hid_report_size_max(ptr, len, hid_input, &sc->sc_kbd_id); /* investigate if this is an Apple Keyboard */ @@ -1033,7 +1035,7 @@ } /* figure out leds on keyboard */ - sc->sc_led_size = hid_report_size(ptr, len, + sc->sc_led_size = hid_report_size_max(ptr, len, hid_output, NULL); if (hid_locate(ptr, len, diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c --- a/sys/dev/usb/input/ums.c +++ b/sys/dev/usb/input/ums.c @@ -61,6 +61,8 @@ #include #include +#include + #include #include #include @@ -614,7 +616,7 @@ goto detach; } - isize = hid_report_size(d_ptr, d_len, hid_input, &sc->sc_iid); + isize = hid_report_size_max(d_ptr, d_len, hid_input, &sc->sc_iid); /* * The Microsoft Wireless Notebook Optical Mouse seems to be in worse diff --git a/sys/dev/usb/input/wmt.c b/sys/dev/usb/input/wmt.c --- a/sys/dev/usb/input/wmt.c +++ b/sys/dev/usb/input/wmt.c @@ -45,6 +45,8 @@ #include #include +#include + #include "usbdevs.h" #include #include @@ -352,7 +354,7 @@ sc->cont_max_rlen, uaa->info.bIfaceIndex, UHID_FEATURE_REPORT, sc->cont_max_rid); if (err == USB_ERR_NORMAL_COMPLETION) { - cont_count_max = hid_get_data_unsigned(sc->buf + 1, + cont_count_max = hid_get_udata(sc->buf + 1, sc->cont_max_rlen - 1, &sc->cont_max_loc); /* * Feature report is a primary source of @@ -377,7 +379,7 @@ } if (sc->btn_type_rlen > 1) { if (err == 0) - sc->is_clickpad = hid_get_data_unsigned(sc->buf + 1, + sc->is_clickpad = hid_get_udata(sc->buf + 1, sc->btn_type_rlen - 1, &sc->btn_type_loc) == 0; else DPRINTF("usbd_req_get_report error=%d\n", err); @@ -522,7 +524,7 @@ * report with contactid=0 but contactids are zero-based, find * contactcount first. */ - cont_count = hid_get_data_unsigned(buf, len, &sc->cont_count_loc); + cont_count = hid_get_udata(buf, len, &sc->cont_count_loc); /* * "In Hybrid mode, the number of contacts that can be reported in one * report is less than the maximum number of contacts that the device @@ -559,7 +561,7 @@ bzero(slot_data, sizeof(sc->slot_data)); WMT_FOREACH_USAGE(sc->caps, usage) { if (sc->locs[cont][usage].size > 0) - slot_data[usage] = hid_get_data_unsigned( + slot_data[usage] = hid_get_udata( buf, len, &sc->locs[cont][usage]); } @@ -611,8 +613,7 @@ sc->nconts_todo -= cont_count; if (sc->do_timestamps && sc->nconts_todo == 0) { /* HUD_SCAN_TIME is measured in 100us, convert to us. */ - scan_time = - hid_get_data_unsigned(buf, len, &sc->scan_time_loc); + scan_time = hid_get_udata(buf, len, &sc->scan_time_loc); if (sc->prev_touch) { delta = scan_time - sc->scan_time; if (delta < 0) @@ -747,46 +748,6 @@ } #endif -/* port of userland hid_report_size() from usbhid(3) to kernel */ -static int -wmt_hid_report_size(const void *buf, uint16_t len, enum hid_kind k, uint8_t id) -{ - struct hid_data *d; - struct hid_item h; - uint32_t temp; - uint32_t hpos; - uint32_t lpos; - int report_id = 0; - - hpos = 0; - lpos = 0xFFFFFFFF; - - for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) { - if (h.kind == k && h.report_ID == id) { - /* compute minimum */ - if (lpos > h.loc.pos) - lpos = h.loc.pos; - /* compute end position */ - temp = h.loc.pos + (h.loc.size * h.loc.count); - /* compute maximum */ - if (hpos < temp) - hpos = temp; - if (h.report_ID != 0) - report_id = 1; - } - } - hid_end_parse(d); - - /* safety check - can happen in case of currupt descriptors */ - if (lpos > hpos) - temp = 0; - else - temp = hpos - lpos; - - /* return length in bytes rounded up */ - return ((temp + 7) / 8 + report_id); -} - static enum wmt_type wmt_hid_parse(struct wmt_softc *sc, const void *d_ptr, uint16_t d_len) { @@ -1000,16 +961,16 @@ sc->ai[WMT_ORIENTATION].max = 1; } - sc->isize = hid_report_size(d_ptr, d_len, hid_input, NULL); - sc->report_len = wmt_hid_report_size(d_ptr, d_len, hid_input, + sc->isize = hid_report_size_max(d_ptr, d_len, hid_input, NULL); + sc->report_len = hid_report_size(d_ptr, d_len, hid_input, report_id); - sc->cont_max_rlen = wmt_hid_report_size(d_ptr, d_len, hid_feature, + sc->cont_max_rlen = hid_report_size(d_ptr, d_len, hid_feature, sc->cont_max_rid); if (sc->btn_type_rid > 0) - sc->btn_type_rlen = wmt_hid_report_size(d_ptr, d_len, + sc->btn_type_rlen = hid_report_size(d_ptr, d_len, hid_feature, sc->btn_type_rid); if (sc->thqa_cert_rid > 0) - sc->thqa_cert_rlen = wmt_hid_report_size(d_ptr, d_len, + sc->thqa_cert_rlen = hid_report_size(d_ptr, d_len, hid_feature, sc->thqa_cert_rid); sc->report_id = report_id; @@ -1039,7 +1000,7 @@ bzero(sc->buf + 1, sc->input_mode_rlen - 1); sc->buf[0] = sc->input_mode_rid; - hid_put_data_unsigned(sc->buf + 1, sc->input_mode_rlen - 1, + hid_put_udata(sc->buf + 1, sc->input_mode_rlen - 1, &sc->input_mode_loc, mode); err = usbd_req_set_report(uaa->device, NULL, sc->buf, sc->input_mode_rlen, uaa->info.bIfaceIndex, diff --git a/sys/dev/usb/input/wsp.c b/sys/dev/usb/input/wsp.c --- a/sys/dev/usb/input/wsp.c +++ b/sys/dev/usb/input/wsp.c @@ -44,6 +44,8 @@ #include #include +#include + #include #include #include @@ -733,7 +735,8 @@ if (err == USB_ERR_NORMAL_COMPLETION) { /* Get HID report descriptor length */ - sc->tp_datalen = hid_report_size(d_ptr, d_len, hid_input, NULL); + sc->tp_datalen = hid_report_size_max(d_ptr, d_len, hid_input, + NULL); free(d_ptr, M_TEMP); if (sc->tp_datalen <= 0 || sc->tp_datalen > WSP_BUFFER_MAX) { diff --git a/sys/dev/usb/misc/ugold.c b/sys/dev/usb/misc/ugold.c --- a/sys/dev/usb/misc/ugold.c +++ b/sys/dev/usb/misc/ugold.c @@ -42,6 +42,8 @@ #include #include +#include + #include #include #include @@ -227,7 +229,7 @@ if (error) goto detach; - (void)hid_report_size(d_ptr, d_len, hid_input, &sc->sc_report_id); + (void)hid_report_size_max(d_ptr, d_len, hid_input, &sc->sc_report_id); free(d_ptr, M_TEMP); diff --git a/sys/dev/usb/serial/ucycom.c b/sys/dev/usb/serial/ucycom.c --- a/sys/dev/usb/serial/ucycom.c +++ b/sys/dev/usb/serial/ucycom.c @@ -55,6 +55,8 @@ #include #include +#include + #include #include #include @@ -249,9 +251,9 @@ } /* get report sizes */ - sc->sc_flen = hid_report_size(urd_ptr, urd_len, hid_feature, &sc->sc_fid); - sc->sc_ilen = hid_report_size(urd_ptr, urd_len, hid_input, &sc->sc_iid); - sc->sc_olen = hid_report_size(urd_ptr, urd_len, hid_output, &sc->sc_oid); + sc->sc_flen = hid_report_size_max(urd_ptr, urd_len, hid_feature, &sc->sc_fid); + sc->sc_ilen = hid_report_size_max(urd_ptr, urd_len, hid_input, &sc->sc_iid); + sc->sc_olen = hid_report_size_max(urd_ptr, urd_len, hid_output, &sc->sc_oid); if ((sc->sc_ilen > UCYCOM_MAX_IOLEN) || (sc->sc_ilen < 1) || (sc->sc_olen > UCYCOM_MAX_IOLEN) || (sc->sc_olen < 2) || diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h --- a/sys/dev/usb/usbhid.h +++ b/sys/dev/usb/usbhid.h @@ -63,9 +63,31 @@ #define USB_HID_DESCRIPTOR_SIZE(n) (9+((n)*3)) +#define UHID_INPUT_REPORT HID_INPUT_REPORT +#define UHID_OUTPUT_REPORT HID_OUTPUT_REPORT +#define UHID_FEATURE_REPORT HID_FEATURE_REPORT + #if defined(_KERNEL) || defined(_STANDALONE) struct usb_config_descriptor; +#ifdef COMPAT_USBHID12 +/* FreeBSD <= 12 compat shims */ +#define hid_report_size(buf, len, kind, id) \ + hid_report_size_max(buf, len, kind, id) +static __inline uint32_t +hid_get_data_unsigned(const uint8_t *buf, hid_size_t len, + struct hid_location *loc) +{ + return (hid_get_udata(buf, len, loc)); +} +static __inline void +hid_put_data_unsigned(uint8_t *buf, hid_size_t len, struct hid_location *loc, + unsigned int value) +{ + return (hid_put_udata(buf, len, loc, value)); +} +#endif + struct usb_hid_descriptor *hid_get_descriptor_from_usb( struct usb_config_descriptor *cd, struct usb_interface_descriptor *id); diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -350,4 +350,5 @@ device uinput # install /dev/uinput cdev # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/mips/conf/ERL b/sys/mips/conf/ERL --- a/sys/mips/conf/ERL +++ b/sys/mips/conf/ERL @@ -214,4 +214,5 @@ #device hwpmc # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/mips/conf/JZ4780 b/sys/mips/conf/JZ4780 --- a/sys/mips/conf/JZ4780 +++ b/sys/mips/conf/JZ4780 @@ -110,6 +110,7 @@ device ums # Mouse # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support # FDT support diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -239,4 +239,5 @@ #device hwpmc # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/modules/hid/hid/Makefile b/sys/modules/hid/hid/Makefile --- a/sys/modules/hid/hid/Makefile +++ b/sys/modules/hid/hid/Makefile @@ -4,6 +4,6 @@ KMOD= hid SRCS= hid.c -SRCS+= opt_usb.h +SRCS+= opt_hid.h .include diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -241,4 +241,5 @@ device virtio_balloon # VirtIO Memory Balloon device # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -271,4 +271,5 @@ device virtio_balloon # VirtIO Memory Balloon device # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/powerpc/conf/GENERIC64LE b/sys/powerpc/conf/GENERIC64LE --- a/sys/powerpc/conf/GENERIC64LE +++ b/sys/powerpc/conf/GENERIC64LE @@ -252,4 +252,5 @@ device virtio_balloon # VirtIO Memory Balloon device # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/powerpc/conf/MPC85XX b/sys/powerpc/conf/MPC85XX --- a/sys/powerpc/conf/MPC85XX +++ b/sys/powerpc/conf/MPC85XX @@ -119,4 +119,5 @@ device fbd # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/powerpc/conf/MPC85XXSPE b/sys/powerpc/conf/MPC85XXSPE --- a/sys/powerpc/conf/MPC85XXSPE +++ b/sys/powerpc/conf/MPC85XXSPE @@ -120,4 +120,5 @@ device fbd # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support diff --git a/sys/powerpc/conf/QORIQ64 b/sys/powerpc/conf/QORIQ64 --- a/sys/powerpc/conf/QORIQ64 +++ b/sys/powerpc/conf/QORIQ64 @@ -122,4 +122,5 @@ device ums # HID support +options HID_DEBUG # enable debug msgs device hid # Generic HID support