From d97d5c0ce89da10c1de150e0555774dec2ed7aed Mon Sep 17 00:00:00 2001 From: Vladimir Kondratyev Date: Thu, 15 Oct 2020 01:02:15 +0300 Subject: [PATCH] hid: Import hidmap-based drivers written by Greg V This change includes: hpen - Generic / MS Windows compatible HID pen tablet driver. hgame - Generic game controller and joystick driver. xb360gp - Xbox360-compatible game controller driver. Submitted by: Greg V Reviewed by: hselasky (as part of D27993) --- share/man/man4/Makefile | 3 + share/man/man4/hgame.4 | 105 +++++++++++++ share/man/man4/hpen.4 | 112 ++++++++++++++ share/man/man4/xb360gp.4 | 98 ++++++++++++ sys/conf/files | 3 + sys/dev/hid/hgame.c | 200 ++++++++++++++++++++++++ sys/dev/hid/hgame.h | 45 ++++++ sys/dev/hid/hpen.c | 256 +++++++++++++++++++++++++++++++ sys/dev/hid/xb360gp.c | 183 ++++++++++++++++++++++ sys/modules/hid/Makefile | 5 +- sys/modules/hid/hgame/Makefile | 9 ++ sys/modules/hid/hpen/Makefile | 9 ++ sys/modules/hid/xb360gp/Makefile | 9 ++ 13 files changed, 1036 insertions(+), 1 deletion(-) create mode 100644 share/man/man4/hgame.4 create mode 100644 share/man/man4/hpen.4 create mode 100644 share/man/man4/xb360gp.4 create mode 100644 sys/dev/hid/hgame.c create mode 100644 sys/dev/hid/hgame.h create mode 100644 sys/dev/hid/hpen.c create mode 100644 sys/dev/hid/xb360gp.c create mode 100644 sys/modules/hid/hgame/Makefile create mode 100644 sys/modules/hid/hpen/Makefile create mode 100644 sys/modules/hid/xb360gp/Makefile diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 60c1b5f19a9b..b905d97d80d0 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -181,6 +181,7 @@ MAN= aac.4 \ h_ertt.4 \ hconf.4 \ hcons.4 \ + hgame.4 \ hidbus.4 \ hidquirk.4 \ hidraw.4 \ @@ -188,6 +189,7 @@ MAN= aac.4 \ hkbd.4 \ hms.4 \ hmt.4 \ + hpen.4 \ hpet.4 \ ${_hpt27xx.4} \ ${_hptiop.4} \ @@ -592,6 +594,7 @@ MAN= aac.4 \ wmt.4 \ ${_wpi.4} \ wsp.4 \ + xb360gp.4 \ ${_xen.4} \ xhci.4 \ xl.4 \ diff --git a/share/man/man4/hgame.4 b/share/man/man4/hgame.4 new file mode 100644 index 000000000000..addf14d9f5c5 --- /dev/null +++ b/share/man/man4/hgame.4 @@ -0,0 +1,105 @@ +.\" 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$ +.\" +.Dd September 14, 2020 +.Dt HGAME 4 +.Os +.Sh NAME +.Nm hgame +.Nd Generic HID game controller (joystick/gamepad) driver +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device hgame" +.Cd "device hid" +.Cd "device hidbus" +.Cd "device hidmap" +.Cd "device evdev" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +hgame_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for generic game controllers (joysticks/gamepads) +that attach to the HID transport backend. +See +.Xr iichid 4 +or +.Xr usbhid 4 . +.Pp +The +.Pa /dev/input/event* +device presents the game controller as a +.Ar evdev +type device. +.Sh SYSCTL VARIABLES +The following variable is available as both +.Xr sysctl 8 +variable and +.Xr loader 8 +tunable: +.Bl -tag -width indent +.It Va dev.hgame.X.debug +Debug output level, where 0 is debugging disabled and larger values increase +debug message verbosity. +Default is 0. +.El +.Pp +It's default value is set with +.Xr loader 8 +tunable: +.Bl -tag -width indent +.It Va hw.hid.hgame.debug +.El +.Sh FILES +.Bl -tag -width /dev/input/event* -compact +.It Pa /dev/input/event* +input event device node. +.El +.Sh SEE ALSO +.Xr iichid 4 , +.Xr usbhid 4 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 13.0. +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Greg V Aq Mt greg@unrelenting.technology . +.Pp +This manual page was written by +.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org . diff --git a/share/man/man4/hpen.4 b/share/man/man4/hpen.4 new file mode 100644 index 000000000000..a043169895ec --- /dev/null +++ b/share/man/man4/hpen.4 @@ -0,0 +1,112 @@ +.\" 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$ +.\" +.Dd September 14, 2020 +.Dt HPEN 4 +.Os +.Sh NAME +.Nm hpen +.Nd MS Windows compatible HID pen tablet driver +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device hpen" +.Cd "device hid" +.Cd "device hidbus" +.Cd "device hidmap" +.Cd "device evdev" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +hpen_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for generic MS Windows compatible HID pen tablet +and digitizer that attach to the HID transport backend. +See +.Xr iichid 4 +or +.Xr usbhid 4 . +.Pp +The +.Pa /dev/input/event* +device presents the pen as a +.Ar evdev +type device. +.Sh SYSCTL VARIABLES +The following variable is available as both +.Xr sysctl 8 +variable and +.Xr loader 8 +tunable: +.Bl -tag -width indent +.It Va dev.hpen.X.debug +Debug output level, where 0 is debugging disabled and larger values increase +debug message verbosity. +Default is 0. +.El +.Pp +It's default value is set with +.Xr loader 8 +tunable: +.Bl -tag -width indent +.It Va hw.hid.hpen.debug +.El +.Sh FILES +.Bl -tag -width /dev/input/event* -compact +.It Pa /dev/input/event* +input event device node. +.El +.Sh SEE ALSO +.Xr iichid 4 , +.Xr usbhid 4 , +.Xr xorg.conf 5 Pq Pa ports/x11/xorg +.Sh BUGS +.Nm +cannot act like +.Xr sysmouse 4 . +.Pp +Pen battery charge level reporting is not supported. +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 13.0. +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Greg V Aq Mt greg@unrelenting.technology . +.Pp +This manual page was written by +.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org . diff --git a/share/man/man4/xb360gp.4 b/share/man/man4/xb360gp.4 new file mode 100644 index 000000000000..b19334cc3a0b --- /dev/null +++ b/share/man/man4/xb360gp.4 @@ -0,0 +1,98 @@ +.\" 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$ +.\" +.Dd September 16, 2020 +.Dt XB360GP 4 +.Os +.Sh NAME +.Nm xb360gp +.Nd XBox 360 gamepad driver +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device xb360gp" +.Cd "device hgame" +.Cd "device hid" +.Cd "device hidbus" +.Cd "device hidmap" +.Cd "device evdev" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +xb360gp_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for XBox 360 gamepad driver. +.Pp +The +.Pa /dev/input/event* +device presents the game controller as a +.Ar evdev +type device. +.Sh SYSCTL VARIABLES +The following variable is available as both +.Xr sysctl 8 +variable and +.Xr loader 8 +tunable: +.Bl -tag -width indent +.It Va dev.xb360gp.X.debug +Debug output level, where 0 is debugging disabled and larger values increase +debug message verbosity. +Default is 0. +.El +.Pp +It's default value is set with +.Xr loader 8 +tunable: +.Bl -tag -width indent +.It Va hw.hid.xb360gp.debug +.El +.Sh FILES +.Bl -tag -width /dev/input/event* -compact +.It Pa /dev/input/event* +input event device node. +.El +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 13.0. +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Greg V Aq Mt greg@unrelenting.technology . +.Pp +This manual page was written by +.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org . diff --git a/sys/conf/files b/sys/conf/files index 31a06150a329..6597d9e471a4 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1817,6 +1817,7 @@ dev/gpio/gpiopps.c optional gpiopps fdt dev/gpio/ofw_gpiobus.c optional fdt gpio dev/hid/hconf.c optional hconf dev/hid/hcons.c optional hcons +dev/hid/hgame.c optional hgame dev/hid/hid.c optional hid dev/hid/hid_if.m optional hid dev/hid/hidbus.c optional hidbus @@ -1826,8 +1827,10 @@ dev/hid/hidraw.c optional hidraw dev/hid/hkbd.c optional hkbd dev/hid/hms.c optional hms dev/hid/hmt.c optional hmt hconf +dev/hid/hpen.c optional hpen dev/hid/hsctrl.c optional hsctrl dev/hid/ps4dshock.c optional ps4dshock +dev/hid/xb360gp.c optional xb360gp 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/hgame.c b/sys/dev/hid/hgame.c new file mode 100644 index 000000000000..099af092a4e5 --- /dev/null +++ b/sys/dev/hid/hgame.c @@ -0,0 +1,200 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Vladimir Kondratyev + * Copyright (c) 2020 Greg V + * + * 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 +__FBSDID("$FreeBSD$"); + +/* + * Generic HID game controller (joystick/gamepad) driver, + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#define HGAME_MAP_BRG(number_from, number_to, code) \ + { HIDMAP_KEY_RANGE(HUP_BUTTON, number_from, number_to, code) } +#define HGAME_MAP_ABS(usage, code) \ + { HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code) } +#define HGAME_MAP_CRG(usage_from, usage_to, callback) \ + { HIDMAP_ANY_CB_RANGE(HUP_GENERIC_DESKTOP, \ + HUG_##usage_from, HUG_##usage_to, callback) } +#define HGAME_FINALCB(cb) \ + { HIDMAP_FINAL_CB(&cb) } + +static const struct hidmap_item hgame_map[] = { + HGAME_MAP_BRG(1, 16, BTN_TRIGGER), + HGAME_MAP_ABS(X, ABS_X), + HGAME_MAP_ABS(Y, ABS_Y), + HGAME_MAP_ABS(Z, ABS_Z), + HGAME_MAP_ABS(RX, ABS_RX), + HGAME_MAP_ABS(RY, ABS_RY), + HGAME_MAP_ABS(RZ, ABS_RZ), + HGAME_MAP_ABS(HAT_SWITCH, ABS_HAT0X), + HGAME_MAP_CRG(D_PAD_UP, D_PAD_LEFT, hgame_dpad_cb), + HGAME_MAP_BRG(17, 57, BTN_TRIGGER_HAPPY), + HGAME_FINALCB( hgame_final_cb), +}; + +static const struct hid_device_id hgame_devs[] = { + { HID_TLC(HUP_GENERIC_DESKTOP, HUG_JOYSTICK), + HID_DRIVER_INFO(HUG_JOYSTICK) }, + { HID_TLC(HUP_GENERIC_DESKTOP, HUG_GAME_PAD), + HID_DRIVER_INFO(HUG_GAME_PAD) }, +}; + +/* + * Emulate the hat switch report via the D-pad usages + * found on XInput/XBox style devices + */ +int +hgame_dpad_cb(HIDMAP_CB_ARGS) +{ + struct hgame_softc *sc = HIDMAP_CB_GET_SOFTC(); + struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV(); + int32_t data; + + switch (HIDMAP_CB_GET_STATE()) { + case HIDMAP_CB_IS_ATTACHING: + HIDMAP_CB_UDATA64 = HID_GET_USAGE(ctx.hi->usage); + evdev_support_event(evdev, EV_ABS); + evdev_support_abs(evdev, ABS_HAT0X, -1, 1, 0, 0, 0); + evdev_support_abs(evdev, ABS_HAT0Y, -1, 1, 0, 0, 0); + break; + + case HIDMAP_CB_IS_RUNNING: + data = ctx.data; + switch (HIDMAP_CB_UDATA64) { + case HUG_D_PAD_UP: + if (sc->dpad_down) + return (ENOMSG); + evdev_push_abs(evdev, ABS_HAT0Y, (data == 0) ? 0 : -1); + sc->dpad_up = (data != 0); + break; + case HUG_D_PAD_DOWN: + if (sc->dpad_up) + return (ENOMSG); + evdev_push_abs(evdev, ABS_HAT0Y, (data == 0) ? 0 : 1); + sc->dpad_down = (data != 0); + break; + case HUG_D_PAD_RIGHT: + if (sc->dpad_left) + return (ENOMSG); + evdev_push_abs(evdev, ABS_HAT0X, (data == 0) ? 0 : 1); + sc->dpad_right = (data != 0); + break; + case HUG_D_PAD_LEFT: + if (sc->dpad_right) + return (ENOMSG); + evdev_push_abs(evdev, ABS_HAT0X, (data == 0) ? 0 : -1); + sc->dpad_left = (data != 0); + break; + } + } + + return (0); +} + +int +hgame_final_cb(HIDMAP_CB_ARGS) +{ + struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV(); + + if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING) + evdev_support_prop(evdev, INPUT_PROP_DIRECT); + + /* Do not execute callback at interrupt handler and detach */ + return (ENOSYS); +} + +static int +hgame_probe(device_t dev) +{ + const struct hid_device_info *hw = hid_get_device_info(dev); + struct hgame_softc *sc = device_get_softc(dev); + int error; + + if (hid_test_quirk(hw, HQ_IS_XBOX360GP)) + return(ENXIO); + + error = HIDMAP_PROBE(&sc->hm, dev, hgame_devs, hgame_map, NULL); + if (error > 0) + return (error); + + hidbus_set_desc(dev, hidbus_get_driver_info(dev) == HUG_GAME_PAD ? + "Gamepad" : "Joystick"); + + return (BUS_PROBE_GENERIC); +} + + + +static int +hgame_attach(device_t dev) +{ + struct hgame_softc *sc = device_get_softc(dev); + + return (hidmap_attach(&sc->hm)); +} + +static int +hgame_detach(device_t dev) +{ + struct hgame_softc *sc = device_get_softc(dev); + + return (hidmap_detach(&sc->hm)); +} + +static devclass_t hgame_devclass; +static device_method_t hgame_methods[] = { + DEVMETHOD(device_probe, hgame_probe), + DEVMETHOD(device_attach, hgame_attach), + DEVMETHOD(device_detach, hgame_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(hgame, hgame_driver, hgame_methods, sizeof(struct hgame_softc)); +DRIVER_MODULE(hgame, hidbus, hgame_driver, hgame_devclass, NULL, 0); +MODULE_DEPEND(hgame, hid, 1, 1, 1); +MODULE_DEPEND(hgame, hidbus, 1, 1, 1); +MODULE_DEPEND(hgame, hidmap, 1, 1, 1); +MODULE_DEPEND(hgame, evdev, 1, 1, 1); +MODULE_VERSION(hgame, 1); +HID_PNP_INFO(hgame_devs); diff --git a/sys/dev/hid/hgame.h b/sys/dev/hid/hgame.h new file mode 100644 index 000000000000..32086ec4923c --- /dev/null +++ b/sys/dev/hid/hgame.h @@ -0,0 +1,45 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Vladimir Kondratyev + * Copyright (c) 2020 Greg V + * + * 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. + */ + +#ifndef _HID_HGAME_H_ +#define _HID_HGAME_H_ + +#include + +hidmap_cb_t hgame_dpad_cb; +hidmap_cb_t hgame_final_cb; + +struct hgame_softc { + struct hidmap hm; + bool dpad_up; + bool dpad_down; + bool dpad_right; + bool dpad_left; +}; + +#endif /* !_HGAME_H_ */ diff --git a/sys/dev/hid/hpen.c b/sys/dev/hid/hpen.c new file mode 100644 index 000000000000..430461d87727 --- /dev/null +++ b/sys/dev/hid/hpen.c @@ -0,0 +1,256 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Vladimir Kondratyev + * Copyright (c) 2019 Greg V + * + * 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 +__FBSDID("$FreeBSD$"); + +/* + * Generic / MS Windows compatible HID pen tablet driver: + * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/required-hid-top-level-collections + * + * Tested on: Wacom WCOM50C1 (Google Pixelbook "eve") + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "usbdevs.h" + +static const uint8_t hpen_graphire_report_descr[] = + { HID_GRAPHIRE_REPORT_DESCR() }; +static const uint8_t hpen_graphire3_4x5_report_descr[] = + { HID_GRAPHIRE3_4X5_REPORT_DESCR() }; + +static hidmap_cb_t hpen_battery_strenght_cb; +static hidmap_cb_t hpen_final_digi_cb; +static hidmap_cb_t hpen_final_pen_cb; + +#define HPEN_MAP_BUT(usage, code) \ + HIDMAP_KEY(HUP_DIGITIZERS, HUD_##usage, code) +#define HPEN_MAP_ABS(usage, code) \ + HIDMAP_ABS(HUP_DIGITIZERS, HUD_##usage, code) +#define HPEN_MAP_ABS_GD(usage, code) \ + HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code) +#define HPEN_MAP_ABS_CB(usage, cb) \ + HIDMAP_ABS_CB(HUP_DIGITIZERS, HUD_##usage, &cb) + +/* Generic map digitizer page map according to hut1_12v2.pdf */ +static const struct hidmap_item hpen_map_digi[] = { + { HPEN_MAP_ABS_GD(X, ABS_X), .required = true }, + { HPEN_MAP_ABS_GD(Y, ABS_Y), .required = true }, + { HPEN_MAP_ABS( TIP_PRESSURE, ABS_PRESSURE) }, + { HPEN_MAP_ABS( X_TILT, ABS_TILT_X) }, + { HPEN_MAP_ABS( Y_TILT, ABS_TILT_Y) }, + { HPEN_MAP_ABS_CB(BATTERY_STRENGTH, hpen_battery_strenght_cb) }, + { HPEN_MAP_BUT( TOUCH, BTN_TOUCH) }, + { HPEN_MAP_BUT( TIP_SWITCH, BTN_TOUCH) }, + { HPEN_MAP_BUT( SEC_TIP_SWITCH, BTN_TOUCH) }, + { HPEN_MAP_BUT( IN_RANGE, BTN_TOOL_PEN) }, + { HPEN_MAP_BUT( BARREL_SWITCH, BTN_STYLUS) }, + { HPEN_MAP_BUT( INVERT, BTN_TOOL_RUBBER) }, + { HPEN_MAP_BUT( ERASER, BTN_TOUCH) }, + { HPEN_MAP_BUT( TABLET_PICK, BTN_STYLUS2) }, + { HPEN_MAP_BUT( SEC_BARREL_SWITCH,BTN_STYLUS2) }, + { HIDMAP_FINAL_CB( &hpen_final_digi_cb) }, +}; + +/* Microsoft-standardized pen support */ +static const struct hidmap_item hpen_map_pen[] = { + { HPEN_MAP_ABS_GD(X, ABS_X), .required = true }, + { HPEN_MAP_ABS_GD(Y, ABS_Y), .required = true }, + { HPEN_MAP_ABS( TIP_PRESSURE, ABS_PRESSURE), .required = true }, + { HPEN_MAP_ABS( X_TILT, ABS_TILT_X) }, + { HPEN_MAP_ABS( Y_TILT, ABS_TILT_Y) }, + { HPEN_MAP_ABS_CB(BATTERY_STRENGTH, hpen_battery_strenght_cb) }, + { HPEN_MAP_BUT( TIP_SWITCH, BTN_TOUCH), .required = true }, + { HPEN_MAP_BUT( IN_RANGE, BTN_TOOL_PEN), .required = true }, + { HPEN_MAP_BUT( BARREL_SWITCH, BTN_STYLUS) }, + { HPEN_MAP_BUT( INVERT, BTN_TOOL_RUBBER), .required = true }, + { HPEN_MAP_BUT( ERASER, BTN_TOUCH), .required = true }, + { HIDMAP_FINAL_CB( &hpen_final_pen_cb) }, +}; + +static const struct hid_device_id hpen_devs[] = { + { HID_TLC(HUP_DIGITIZERS, HUD_DIGITIZER) }, + { HID_TLC(HUP_DIGITIZERS, HUD_PEN) }, +}; + +static int +hpen_battery_strenght_cb(HIDMAP_CB_ARGS) +{ + struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV(); + int32_t data; + + switch (HIDMAP_CB_GET_STATE()) { + case HIDMAP_CB_IS_ATTACHING: + evdev_support_event(evdev, EV_PWR); + /* TODO */ + break; + case HIDMAP_CB_IS_RUNNING: + data = ctx.data; + /* TODO */ + } + + return (0); +} + +static int +hpen_final_digi_cb(HIDMAP_CB_ARGS) +{ + struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV(); + + if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING) + evdev_support_prop(evdev, INPUT_PROP_POINTER); + + /* Do not execute callback at interrupt handler and detach */ + return (ENOSYS); +} + +static int +hpen_final_pen_cb(HIDMAP_CB_ARGS) +{ + struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV(); + + if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING) + evdev_support_prop(evdev, INPUT_PROP_DIRECT); + + /* Do not execute callback at interrupt handler and detach */ + return (ENOSYS); +} + +static void +hpen_identify(driver_t *driver, device_t parent) +{ + const struct hid_device_info *hw = hid_get_device_info(parent); + + /* the report descriptor for the Wacom Graphire is broken */ + if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM) { + switch (hw->idProduct) { + case USB_PRODUCT_WACOM_GRAPHIRE: + hid_set_report_descr(parent, + hpen_graphire_report_descr, + sizeof(hpen_graphire_report_descr)); + break; + + case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: + hid_set_report_descr(parent, + hpen_graphire3_4x5_report_descr, + sizeof(hpen_graphire3_4x5_report_descr)); + break; + } + } +} + +static int +hpen_probe(device_t dev) +{ + struct hidmap *hm = device_get_softc(dev); + int error; + bool is_pen; + + error = HIDBUS_LOOKUP_DRIVER_INFO(dev, hpen_devs); + if (error != 0) + return (error); + + hidmap_set_dev(hm, dev); + + /* Check if report descriptor belongs to a HID tablet device */ + is_pen = hidbus_get_usage(dev) == HID_USAGE2(HUP_DIGITIZERS, HUD_PEN); + error = is_pen + ? HIDMAP_ADD_MAP(hm, hpen_map_pen, NULL) + : HIDMAP_ADD_MAP(hm, hpen_map_digi, NULL); + if (error != 0) + return (error); + + hidbus_set_desc(dev, is_pen ? "Pen" : "Digitizer"); + + return (BUS_PROBE_DEFAULT); +} + +static int +hpen_attach(device_t dev) +{ + const struct hid_device_info *hw = hid_get_device_info(dev); + struct hidmap *hm = device_get_softc(dev); + int error; + + if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM && + hw->idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) { + /* + * The Graphire3 needs 0x0202 to be written to + * feature report ID 2 before it'll start + * returning digitizer data. + */ + static const uint8_t reportbuf[3] = {2, 2, 2}; + error = hid_set_report(dev, reportbuf, sizeof(reportbuf), + HID_FEATURE_REPORT, reportbuf[0]); + if (error) + device_printf(dev, "set feature report failed, " + "error=%d (ignored)\n", error); + } + + return (hidmap_attach(hm)); +} + +static int +hpen_detach(device_t dev) +{ + return (hidmap_detach(device_get_softc(dev))); +} + + +static devclass_t hpen_devclass; +static device_method_t hpen_methods[] = { + DEVMETHOD(device_identify, hpen_identify), + DEVMETHOD(device_probe, hpen_probe), + DEVMETHOD(device_attach, hpen_attach), + DEVMETHOD(device_detach, hpen_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(hpen, hpen_driver, hpen_methods, sizeof(struct hidmap)); +DRIVER_MODULE(hpen, hidbus, hpen_driver, hpen_devclass, NULL, 0); +MODULE_DEPEND(hpen, hid, 1, 1, 1); +MODULE_DEPEND(hpen, hidbus, 1, 1, 1); +MODULE_DEPEND(hpen, hidmap, 1, 1, 1); +MODULE_DEPEND(hpen, evdev, 1, 1, 1); +MODULE_VERSION(hpen, 1); +HID_PNP_INFO(hpen_devs); diff --git a/sys/dev/hid/xb360gp.c b/sys/dev/hid/xb360gp.c new file mode 100644 index 000000000000..f255c110f47c --- /dev/null +++ b/sys/dev/hid/xb360gp.c @@ -0,0 +1,183 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Vladimir Kondratyev + * Copyright (c) 2020 Greg V + * + * 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 +__FBSDID("$FreeBSD$"); + +/* + * XBox 360 gamepad driver thanks to the custom descriptor in usbhid. + * + * Tested on: SVEN GC-5070 in both XInput (XBox 360) and DirectInput modes + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +static const uint8_t xb360gp_rdesc[] = {HID_XB360GP_REPORT_DESCR()}; + +#define XB360GP_MAP_BUT(number, code) \ + { HIDMAP_KEY(HUP_BUTTON, number, code) } +#define XB360GP_MAP_ABS(usage, code) \ + { HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code) } +#define XB360GP_MAP_ABS_FLT(usage, code) \ + { HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code), \ + .fuzz = 16, .flat = 128 } +#define XB360GP_MAP_ABS_INV(usage, code) \ + { HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code), \ + .fuzz = 16, .flat = 128, .invert_value = true } +#define XB360GP_MAP_CRG(usage_from, usage_to, callback) \ + { HIDMAP_ANY_CB_RANGE(HUP_GENERIC_DESKTOP, \ + HUG_##usage_from, HUG_##usage_to, callback) } +#define XB360GP_FINALCB(cb) \ + { HIDMAP_FINAL_CB(&cb) } + +/* Customized to match usbhid's XBox 360 descriptor */ +static const struct hidmap_item xb360gp_map[] = { + XB360GP_MAP_BUT(1, BTN_SOUTH), + XB360GP_MAP_BUT(2, BTN_EAST), + XB360GP_MAP_BUT(3, BTN_WEST), + XB360GP_MAP_BUT(4, BTN_NORTH), + XB360GP_MAP_BUT(5, BTN_TL), + XB360GP_MAP_BUT(6, BTN_TR), + XB360GP_MAP_BUT(7, BTN_SELECT), + XB360GP_MAP_BUT(8, BTN_START), + XB360GP_MAP_BUT(9, BTN_THUMBL), + XB360GP_MAP_BUT(10, BTN_THUMBR), + XB360GP_MAP_BUT(11, BTN_MODE), + XB360GP_MAP_CRG(D_PAD_UP, D_PAD_LEFT, hgame_dpad_cb), + XB360GP_MAP_ABS_FLT(X, ABS_X), + XB360GP_MAP_ABS_INV(Y, ABS_Y), + XB360GP_MAP_ABS(Z, ABS_Z), + XB360GP_MAP_ABS_FLT(RX, ABS_RX), + XB360GP_MAP_ABS_INV(RY, ABS_RY), + XB360GP_MAP_ABS(RZ, ABS_RZ), + XB360GP_FINALCB( hgame_final_cb), +}; + +static const STRUCT_USB_HOST_ID xb360gp_devs[] = { + /* the Xbox 360 gamepad doesn't use the HID class */ + {USB_IFACE_CLASS(UICLASS_VENDOR), + USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER), + USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),}, +}; + +static void +xb360gp_identify(driver_t *driver, device_t parent) +{ + const struct hid_device_info *hw = hid_get_device_info(parent); + + /* the Xbox 360 gamepad has no report descriptor */ + if (hid_test_quirk(hw, HQ_IS_XBOX360GP)) + hid_set_report_descr(parent, xb360gp_rdesc, + sizeof(xb360gp_rdesc)); +} + +static int +xb360gp_probe(device_t dev) +{ + struct hgame_softc *sc = device_get_softc(dev); + const struct hid_device_info *hw = hid_get_device_info(dev); + int error; + + if (!hid_test_quirk(hw, HQ_IS_XBOX360GP)) + return (ENXIO); + + hidmap_set_dev(&sc->hm, dev); + + error = HIDMAP_ADD_MAP(&sc->hm, xb360gp_map, NULL); + if (error != 0) + return (error); + + device_set_desc(dev, "XBox 360 Gamepad"); + + return (BUS_PROBE_DEFAULT); +} + +static int +xb360gp_attach(device_t dev) +{ + struct hgame_softc *sc = device_get_softc(dev); + int error; + + /* + * Turn off the four LEDs on the gamepad which + * are blinking by default: + */ + static const uint8_t reportbuf[3] = {1, 3, 0}; + error = hid_set_report(dev, reportbuf, sizeof(reportbuf), + HID_OUTPUT_REPORT, 0); + if (error) + device_printf(dev, "set output report failed, error=%d " + "(ignored)\n", error); + + return (hidmap_attach(&sc->hm)); +} + +static int +xb360gp_detach(device_t dev) +{ + struct hgame_softc *sc = device_get_softc(dev); + + return (hidmap_detach(&sc->hm)); +} + +static devclass_t xb360gp_devclass; +static device_method_t xb360gp_methods[] = { + DEVMETHOD(device_identify, xb360gp_identify), + DEVMETHOD(device_probe, xb360gp_probe), + DEVMETHOD(device_attach, xb360gp_attach), + DEVMETHOD(device_detach, xb360gp_detach), + DEVMETHOD_END +}; + +DEFINE_CLASS_0(xb360gp, xb360gp_driver, xb360gp_methods, + sizeof(struct hgame_softc)); +DRIVER_MODULE(xb360gp, hidbus, xb360gp_driver, xb360gp_devclass, NULL, 0); +MODULE_DEPEND(xb360gp, hid, 1, 1, 1); +MODULE_DEPEND(xb360gp, hidbus, 1, 1, 1); +MODULE_DEPEND(xb360gp, hidmap, 1, 1, 1); +MODULE_DEPEND(xb360gp, hgame, 1, 1, 1); +MODULE_DEPEND(xb360gp, evdev, 1, 1, 1); +MODULE_VERSION(xb360gp, 1); +USB_PNP_HOST_INFO(xb360gp_devs); diff --git a/sys/modules/hid/Makefile b/sys/modules/hid/Makefile index 20ae0b3b9302..7d5515480bc0 100644 --- a/sys/modules/hid/Makefile +++ b/sys/modules/hid/Makefile @@ -10,10 +10,13 @@ SUBDIR = \ SUBDIR += \ hconf \ hcons \ + hgame \ hkbd \ hms \ hmt \ + hpen \ hsctrl \ - ps4dshock + ps4dshock \ + xb360gp .include diff --git a/sys/modules/hid/hgame/Makefile b/sys/modules/hid/hgame/Makefile new file mode 100644 index 000000000000..38016de4c326 --- /dev/null +++ b/sys/modules/hid/hgame/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/hid + +KMOD= hgame +SRCS= hgame.c +SRCS+= bus_if.h device_if.h + +.include diff --git a/sys/modules/hid/hpen/Makefile b/sys/modules/hid/hpen/Makefile new file mode 100644 index 000000000000..7c485c8fd7ce --- /dev/null +++ b/sys/modules/hid/hpen/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/hid + +KMOD= hpen +SRCS= hpen.c +SRCS+= bus_if.h device_if.h usbdevs.h + +.include diff --git a/sys/modules/hid/xb360gp/Makefile b/sys/modules/hid/xb360gp/Makefile new file mode 100644 index 000000000000..2b3e012f8491 --- /dev/null +++ b/sys/modules/hid/xb360gp/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/hid + +KMOD= xb360gp +SRCS= xb360gp.c +SRCS+= bus_if.h device_if.h opt_usb.h + +.include