Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F112013220
D16698.id48366.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
98 KB
Referenced Files
None
Subscribers
None
D16698.id48366.diff
View Options
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1846,6 +1846,7 @@
dev/iicbus/iicbb_if.m optional iicbb
dev/iicbus/iicbus.c optional iicbus
dev/iicbus/iicbus_if.m optional iicbus
+dev/iicubs/iichid.c optional iichid acpi iicbus
dev/iicbus/iiconf.c optional iicbus
dev/iicbus/iicsmb.c optional iicsmb \
dependency "iicbus_if.h"
@@ -3276,6 +3277,7 @@
dev/usb/usb_generic.c optional usb
dev/usb/usb_handle_request.c optional usb
dev/usb/usb_hid.c optional usb
+dev/usb/hid.c optional usb
dev/usb/usb_hub.c optional usb
dev/usb/usb_if.m optional usb
dev/usb/usb_lookup.c optional usb
@@ -3388,6 +3390,7 @@
#
dev/usb/input/atp.c optional atp
dev/usb/input/uep.c optional uep
+dev/usb/hid.c optional ukbd | uhid
dev/usb/input/uhid.c optional uhid
dev/usb/input/uhid_snes.c optional uhid_snes
dev/usb/input/ukbd.c optional ukbd
Index: sys/dev/iicbus/input/acpi_iichid.c
===================================================================
--- /dev/null
+++ sys/dev/iicbus/input/acpi_iichid.c
@@ -0,0 +1,522 @@
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <sys/malloc.h>
+
+#include <dev/iicbus/input/iichid.h>
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+
+#include <dev/acpica/acpivar.h>
+
+static device_probe_t acpi_iichid_probe;
+static device_attach_t acpi_iichid_attach;
+static device_detach_t acpi_iichid_detach;
+
+static devclass_t acpi_iichid_devclass;
+
+static device_method_t acpi_iichid_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, acpi_iichid_probe),
+ DEVMETHOD(device_attach, acpi_iichid_attach),
+ DEVMETHOD(device_detach, acpi_iichid_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t acpi_iichid_driver = {
+ .name = "acpi_iichid",
+ .methods = acpi_iichid_methods,
+ .size = sizeof(struct acpi_iichid_softc),
+};
+
+static char *acpi_iichid_ids[] = {
+ "PNP0C50",
+ "ACPI0C50",
+ NULL
+};
+
+static ACPI_STATUS
+acpi_iichid_walk_handler(ACPI_RESOURCE *res, void *context)
+{
+ struct acpi_iichid_softc *sc;
+
+ sc = context;
+
+ switch(res->Type) {
+ case ACPI_RESOURCE_TYPE_SERIAL_BUS:
+ //device_printf(sc->dev, " - serial bus: ");
+ if (res->Data.CommonSerialBus.Type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+ device_printf(sc->dev, "wrong bus type, should be %d is %d\n", ACPI_RESOURCE_SERIAL_TYPE_I2C, res->Data.CommonSerialBus.Type);
+ return (AE_TYPE);
+ } else {
+ //device_printf(sc->dev, "0x%x on %s\n", le16toh(res->Data.I2cSerialBus.SlaveAddress), res->Data.CommonSerialBus.ResourceSource.StringPtr);
+ sc->hw.device_addr = res->Data.I2cSerialBus.SlaveAddress;
+ }
+ break;
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ if (res->Data.ExtendedIrq.InterruptCount > 0) {
+ device_printf(sc->dev, " - irq: %d\n", (int)res->Data.ExtendedIrq.Interrupts[0]);
+ sc->irq = res->Data.ExtendedIrq.Interrupts[0];
+ }
+
+ break;
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ //device_printf(sc->dev, " - end parsing\n");
+ break;
+
+ default:
+ device_printf(sc->dev, "unexpected type %d while parsing Current Resource Settings (_CSR)\n", res->Type);
+ break;
+ }
+
+ return AE_OK;
+}
+
+static int
+acpi_iichid_probe(device_t dev)
+{
+ if (acpi_disabled("iichid") || ACPI_ID_PROBE(device_get_parent(dev), dev, acpi_iichid_ids) == NULL)
+ return (ENXIO);
+
+ device_set_desc(dev, "HID over I2C (ACPI)");
+
+ return (BUS_PROBE_VENDOR);
+}
+
+static void
+periodic_or_intr(void *context)
+{
+ struct acpi_iichid_softc *sc;
+
+ sc = context;
+ taskqueue_enqueue(sc->taskqueue, &sc->event_task);
+}
+
+static void
+event_task(void *context, int pending)
+{
+ struct acpi_iichid_softc *sc;
+
+ sc = context;
+
+ mtx_lock(&sc->lock);
+
+ struct iichid_softc *dsc;
+ dsc = sc->iichid_sc;
+
+ mtx_unlock(&sc->lock);
+
+ dsc->event_handler(dsc, pending);
+
+ mtx_lock(&sc->lock);
+ if (sc->callout_setup && sc->sampling_rate > 0 && !callout_pending(&sc->periodic_callout) )
+ callout_reset(&sc->periodic_callout, hz / sc->sampling_rate, periodic_or_intr, sc);
+ mtx_unlock(&sc->lock);
+}
+
+static int
+acpi_iichid_setup_callout(device_t dev, struct acpi_iichid_softc *sc)
+{
+ if (sc->sampling_rate < 0)
+ {
+ device_printf(dev, "sampling_rate is below 0, can't setup callout\n");
+ return (EINVAL);
+ }
+
+ callout_init(&sc->periodic_callout, 1);
+ sc->callout_setup=true;
+ device_printf(dev, "successfully setup callout");
+ return (0);
+}
+
+static int
+acpi_iichid_reset_callout(device_t dev, struct acpi_iichid_softc *sc)
+{
+ if (sc->sampling_rate <= 0)
+ {
+ device_printf(dev, "sampling_rate is below or equal to 0, can't reset callout\n");
+ return (EINVAL);
+ }
+
+ if (sc->callout_setup)
+ callout_reset(&sc->periodic_callout, hz / sc->sampling_rate, periodic_or_intr, sc);
+ else
+ return (EINVAL);
+ return (0);
+}
+
+static void
+acpi_iichid_teardown_callout(device_t dev, struct acpi_iichid_softc *sc)
+{
+ callout_drain(&sc->periodic_callout);
+ sc->callout_setup=false;
+ device_printf(dev, "tore callout down\n");
+}
+
+static int
+acpi_iichid_setup_interrupt(device_t dev, struct acpi_iichid_softc *sc)
+{
+ sc->irq_rid = 0;
+ sc->irq_cookie = 0;
+ sc->irq_res = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE);
+
+ if( sc->irq_res != NULL )
+ {
+ device_printf(dev, "allocated irq at 0x%lx and rid %d\n", (uint64_t)sc->irq_res, sc->irq_rid);
+ int error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_TTY | INTR_MPSAFE, NULL, periodic_or_intr, sc, &sc->irq_cookie);
+ if (error != 0)
+ {
+ device_printf(dev, "Could not setup interrupt handler\n");
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
+ return error;
+ } else
+ device_printf(dev, "successfully setup interrupt\n");
+
+ } else {
+ device_printf(dev, "could not allocate IRQ resource\n");
+ }
+
+ return (0);
+}
+
+static void
+acpi_iichid_teardown_interrupt(device_t dev, struct acpi_iichid_softc *sc)
+{
+ if (sc->irq_cookie)
+ {
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie);
+ }
+
+ if (sc->irq_res)
+ {
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
+ }
+ sc->irq_rid = 0;
+ sc->irq_cookie = 0;
+ sc->irq_res = 0;
+}
+
+static int
+sysctl_sampling_rate_handler(SYSCTL_HANDLER_ARGS)
+{
+ int err, value, oldval;
+ struct acpi_iichid_softc *sc;
+
+ sc = arg1;
+
+ mtx_lock(&sc->lock);
+
+ value = sc->sampling_rate;
+ oldval = sc->sampling_rate;
+ err = sysctl_handle_int(oidp, &value, 0, req);
+
+ if (err != 0 || req->newptr == NULL || value == sc->sampling_rate)
+ {
+ mtx_unlock(&sc->lock);
+ return (err);
+ }
+
+ sc->sampling_rate = value;
+
+ if( oldval < 0 && value >= 0 )
+ {
+ acpi_iichid_teardown_interrupt(sc->dev, sc);
+ acpi_iichid_setup_callout(sc->dev, sc);
+ } else if ( oldval >=0 && value < 0)
+ {
+ acpi_iichid_teardown_callout(sc->dev, sc);
+ acpi_iichid_setup_interrupt(sc->dev, sc);
+ }
+
+ if( value > 0 )
+ acpi_iichid_reset_callout(sc->dev, sc);
+
+ device_printf(sc->dev, "new sampling_rate value: %d\n", value);
+
+ mtx_unlock(&sc->lock);
+
+ return (0);
+}
+
+static int
+acpi_iichid_attach(device_t dev)
+{
+ struct acpi_iichid_softc *sc;
+ sc = device_get_softc(dev);
+
+ mtx_init(&sc->lock, "HID over I2C (ACPI) lock", NULL, MTX_DEF);
+
+ sc->dev = dev;
+
+ sc->irq = 0;
+ sc->irq_rid = 0;
+ sc->irq_res = 0;
+ sc->irq_cookie = 0;
+ sc->sampling_rate = -1;
+ sc->taskqueue = 0;
+ sc->iichid_sc = 0;
+ sc->callout_setup = false;
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "sampling_rate", CTLTYPE_INT | CTLFLAG_RWTUN,
+ sc, 0,
+ sysctl_sampling_rate_handler, "I", "sampling rate in num/second");
+
+ //get ACPI handles for current device and its parent
+ ACPI_HANDLE ahnd = acpi_get_handle(dev),
+ phnd = NULL;
+
+ if (!ahnd) {
+ device_printf(dev, "Could not retrieve ACPI handle\n");
+ mtx_destroy(&sc->lock);
+ return (ENXIO);
+ }
+
+ //besides the ACPI parent handle, get the newbus parent
+ device_t parent;
+
+ if (ACPI_SUCCESS(AcpiGetParent(ahnd, &phnd)) && (parent = acpi_get_device(phnd)) && device_is_attached(parent))
+ {
+ //device_printf(dev, "my parent is a %s and its ACPI path is %s\n", device_get_driver(parent)->name, acpi_name(phnd));
+ } else {
+ device_printf(dev, "could not retrieve parent device or parent is not attached (driver loaded?)");
+ mtx_destroy(&sc->lock);
+ return (ENXIO);
+ }
+
+
+ //function (_DSM) to be evaluated to retrieve the address of the configuration register of the hi device
+ /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
+ static uint8_t acpi_iichid_dsm_guid[] = {
+ 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
+ 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
+ };
+
+ //prepare 4 arguments
+ ACPI_OBJECT obj[4];
+ ACPI_OBJECT_LIST acpi_arg;
+
+ ACPI_BUFFER acpi_buf;
+
+ acpi_buf.Pointer = NULL;
+ acpi_buf.Length = ACPI_ALLOCATE_BUFFER;
+
+ acpi_arg.Pointer = &obj[0];
+ acpi_arg.Count = 4;
+
+ obj[0].Type = ACPI_TYPE_BUFFER;
+ obj[0].Buffer.Length = sizeof(acpi_iichid_dsm_guid);
+ obj[0].Buffer.Pointer = &acpi_iichid_dsm_guid[0];
+
+ obj[1].Type = ACPI_TYPE_INTEGER;
+ obj[1].Integer.Value = 1;
+
+ obj[2].Type = ACPI_TYPE_INTEGER;
+ obj[2].Integer.Value = 1;
+
+ obj[3].Type = ACPI_TYPE_PACKAGE;
+ obj[3].Package.Count = 0;
+
+ //evaluate
+ ACPI_STATUS status = ACPI_EVALUATE_OBJECT(device_get_parent(dev), dev, "_DSM", &acpi_arg, &acpi_buf);
+
+ if (ACPI_FAILURE(status)) {
+ device_printf(dev, "error evaluating _DSM\n");
+ if (acpi_buf.Pointer != NULL)
+ AcpiOsFree(acpi_buf.Pointer);
+ mtx_destroy(&sc->lock);
+ return (ENXIO);
+ }
+
+ //the result will contain the register address (int type)
+ ACPI_OBJECT *result = (ACPI_OBJECT*)acpi_buf.Pointer;
+ if( result->Type != ACPI_TYPE_INTEGER ) {
+ device_printf(dev, "_DSM should return descriptor register address as integer\n");
+ AcpiOsFree(result);
+ mtx_destroy(&sc->lock);
+ return (ENXIO);
+ }
+
+ //take it (much work done for one byte -.-)
+ device_printf(dev, "descriptor register address is %lx\n", result->Integer.Value);
+ sc->hw.config_reg = result->Integer.Value;
+
+ //cleanup
+ AcpiOsFree(result);
+
+ //_CSR holds more data (device address and irq) and only needs a callback to evaluate its data
+ status = AcpiWalkResources(ahnd, "_CRS", acpi_iichid_walk_handler, sc);
+
+ if (ACPI_FAILURE(status)) {
+ device_printf(dev, "could not evaluate _CRS\n");
+ mtx_destroy(&sc->lock);
+ return (ENXIO);
+ }
+
+ //get the full ACPI pathname of dev's parent
+ acpi_buf.Pointer = NULL;
+ acpi_buf.Length = ACPI_ALLOCATE_BUFFER;
+ AcpiGetName(phnd, ACPI_FULL_PATHNAME, &acpi_buf);
+
+ device_printf(dev, "parent device is \"%s\"\n", (const char*)acpi_buf.Pointer);
+ AcpiOsFree(acpi_buf.Pointer);
+
+ //padev will hold the newbus device handle of this (dev) devices ACPI parent, which is not necessarily the same as this (dev) devices parent.
+ //I.e. both parent devices might even be on different branches of the device tree. The ACPI parent is most likely a iicbus
+ //device (e.g. ig4's ig4iic_pci0), while the newbus parent of dev will in most cases acpi0.
+ device_t padev = acpi_get_device(phnd); //ACPI parent, the one we are interested in because it is a iicbus
+#if 0
+ device_t pbdev = device_get_parent(dev); //newbus parent, just for reference
+
+ device_printf(dev, "parent devices: 0x%lx (ACPI, %s) and 0x%lx (Newbus, %s)\n", (uint64_t)padev, device_get_name(padev), (uint64_t)pbdev, device_get_name(padev));
+#endif
+ //look below padev whether there already is a iichid device that can be reused or create a new one
+ if (padev)
+ {
+ //the should be a iicbus device, nevertheless no KASSERT here since the system will continue to function
+ // only iichid device won't operate
+ device_t iicbus_dev = device_find_child(padev, "iicbus", -1);
+ if (iicbus_dev)
+ {
+ device_t *children;
+ int ccount;
+
+ device_t dnew = NULL;
+
+ //get a list of all children below iicbus and check if parameters match
+ if (device_get_children(iicbus_dev, &children, &ccount) == 0)
+ {
+ for(int i=0; i<ccount; i++)
+ {
+ driver_t *drv = device_get_driver(children[i]);
+ if (!drv)
+ continue;
+
+ if (strcmp(drv->name, "iichid") == 0)
+ {
+ struct iichid_softc *dsc = (struct iichid_softc*)device_get_softc(children[i]);
+ if ( dsc->hw.device_addr == sc->hw.device_addr
+ && dsc->hw.config_reg == sc->hw.config_reg )
+ {
+ //reuse this child, there shouldn't be more than one
+ //if there are more devices matching that is observable in dmesg
+ dnew = children[i];
+ device_printf(dev, "device %s ADDR 0x%x REG 0x%x already present on %s\n", device_get_nameunit(children[i]), dsc->hw.device_addr, dsc->hw.config_reg, device_get_nameunit(iicbus_dev));
+ }
+ }
+ }
+ free(children, M_TEMP);
+ }
+
+ //no iichid device found to be reused, so one is created and parameters are set
+ if ( dnew == NULL )
+ {
+ //add child of type iichid below iicbus
+ dnew = BUS_ADD_CHILD(iicbus_dev, 0, "iichid", -1);
+ if (dnew)
+ {
+ //config register and device address via resource_list/ivars
+ bus_set_resource(dnew, SYS_RES_IOPORT, 0, sc->hw.config_reg, 2);
+ BUS_WRITE_IVAR(iicbus_dev, dnew, IICBUS_IVAR_ADDR, sc->hw.device_addr);
+
+ //try and attach:
+ if (device_probe_and_attach(dnew) == 0)
+ {
+ // success? print status and device configuration
+ struct iichid_softc *dsc = (struct iichid_softc*)device_get_softc(dnew);
+ device_printf(dev, "added %s ADDR 0x%x REG 0x%x to %s\n", device_get_nameunit(dnew), dsc->hw.device_addr, dsc->hw.config_reg, device_get_nameunit(iicbus_dev));
+ } else {
+ //failure? remove child, print error and leave
+ device_printf(dev, "probe or attach failed for %s! (ADDR: 0x%x, REG: 0x%x)\n", device_get_nameunit(dnew), sc->hw.device_addr, sc->hw.config_reg);
+ device_delete_child(iicbus_dev, dnew);
+ mtx_destroy(&sc->lock);
+ return (ENXIO);
+ }
+ } else {
+ device_printf(dev, "could not attach iichid device to %s! (ADDR: 0x%x, REG: 0x%x)\n", device_get_nameunit(iicbus_dev), sc->hw.device_addr, sc->hw.config_reg);
+ mtx_destroy(&sc->lock);
+ return (ENXIO);
+ }
+ }
+
+ if ( dnew != NULL )
+ {
+ struct iichid_softc *dsc = (struct iichid_softc*)device_get_softc(dnew);
+ if (dsc)
+ {
+ sc->iichid_sc = dsc;
+ TASK_INIT(&sc->event_task, 0, event_task, sc);
+
+ sc->taskqueue = taskqueue_create("iichid_tq", M_NOWAIT | M_ZERO, taskqueue_thread_enqueue, &sc->taskqueue);
+ if( sc->taskqueue == NULL )
+ {
+ return (ENXIO);
+ }else{
+ taskqueue_start_threads(&sc->taskqueue, 1, PI_TTY, "%s taskq", device_get_nameunit(sc->dev));
+ }
+
+ int error;
+ if (sc->sampling_rate >= 0)
+ {
+ error = acpi_iichid_setup_callout(dev, sc);
+ if (error != 0)
+ {
+ device_printf(dev, "please consider setting the sampling_rate sysctl to -1");
+ }
+ } else {
+ error = acpi_iichid_setup_interrupt(dev, sc);
+ if (error != 0)
+ {
+ device_printf(dev, "please consider setting the sampling_rate sysctl greater than 0.");
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ return (0); /* success */
+}
+
+static int
+acpi_iichid_detach(device_t dev)
+{
+ //we leave the added devices below iicbus instances intact, since this module is only needed to parameterize
+ // them. Afterwards they function without this
+ struct acpi_iichid_softc *sc;
+ sc = device_get_softc(dev);
+
+ mtx_lock(&sc->lock);
+
+ if (sc->taskqueue)
+ {
+ taskqueue_block(sc->taskqueue);
+ taskqueue_drain(sc->taskqueue, &sc->event_task);
+ taskqueue_free(sc->taskqueue);
+ }
+
+ acpi_iichid_teardown_callout(dev, sc);
+ acpi_iichid_teardown_interrupt(dev, sc);
+
+ mtx_unlock(&sc->lock);
+ mtx_destroy(&sc->lock);
+ return (0);
+}
+
+DRIVER_MODULE(acpi_iichid, acpi, acpi_iichid_driver, acpi_iichid_devclass, NULL, 0);
+MODULE_DEPEND(acpi_iichid, acpi, 1, 1, 1);
+MODULE_DEPEND(acpi_iichid, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
+MODULE_DEPEND(acpi_iichid, iichid, 1, 1, 1);
+MODULE_VERSION(acpi_iichid, 1);
Index: sys/dev/iicbus/input/iichid.h
===================================================================
--- /dev/null
+++ sys/dev/iicbus/input/iichid.h
@@ -0,0 +1,150 @@
+/* $OpenBSD: iichid.h,v 1.4 2016/01/31 18:24:35 jcs Exp $ */
+/*
+ * HID-over-i2c driver
+ *
+ * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
+ *
+ * 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.
+ */
+
+#ifndef _IIC_HID_H_
+#define _IIC_HID_H_
+
+#include <dev/usb/hid.h>
+#include <sys/mouse.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+
+/* 5.1.1 - HID Descriptor Format */
+struct i2c_hid_desc {
+ uint16_t wHIDDescLength;
+ uint16_t bcdVersion;
+ uint16_t wReportDescLength;
+ uint16_t wReportDescRegister;
+ uint16_t wInputRegister;
+ uint16_t wMaxInputLength;
+ uint16_t wOutputRegister;
+ uint16_t wMaxOutputLength;
+ uint16_t wCommandRegister;
+ uint16_t wDataRegister;
+ uint16_t wVendorID;
+ uint16_t wProductID;
+ uint16_t wVersionID;
+ uint32_t reserved;
+} __packed;
+
+#define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
+#define MOUSE_FLAGS (HIO_RELATIVE)
+
+#define MS_BUF_SIZE 8 /* bytes */
+#define MS_BUFQ_MAXLEN 100 /* units */
+#define MS_BUTTON_MAX 31 /* exclusive, must be less than 32 */
+#define MS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
+#define MS_INFO_MAX 2 /* maximum number of HID sets */
+
+struct ms_info {
+ struct hid_location sc_loc_w;
+ struct hid_location sc_loc_x;
+ struct hid_location sc_loc_y;
+ struct hid_location sc_loc_z;
+ struct hid_location sc_loc_t;
+ struct hid_location sc_loc_btn[MS_BUTTON_MAX];
+
+ uint32_t sc_flags;
+#define MS_FLAG_X_AXIS 0x0001
+#define MS_FLAG_Y_AXIS 0x0002
+#define MS_FLAG_Z_AXIS 0x0004
+#define MS_FLAG_T_AXIS 0x0008
+#define MS_FLAG_SBU 0x0010 /* spurious button up events */
+#define MS_FLAG_REVZ 0x0020 /* Z-axis is reversed */
+#define MS_FLAG_W_AXIS 0x0040
+
+ uint8_t sc_iid_w;
+ uint8_t sc_iid_x;
+ uint8_t sc_iid_y;
+ uint8_t sc_iid_z;
+ uint8_t sc_iid_t;
+ uint8_t sc_iid_btn[MS_BUTTON_MAX];
+ uint8_t sc_buttons;
+};
+
+struct iichid_hw {
+ uint8_t device_addr;
+ uint16_t config_reg;
+};
+
+struct ms_tx_entry {
+ STAILQ_ENTRY(ms_tx_entry) next;
+ uint8_t buf[MS_BUF_SIZE];
+};
+
+STAILQ_HEAD(ms_tx_buf, ms_tx_entry);
+
+struct iichid_softc {
+ device_t dev;
+ struct cdev *cdev;
+ bool isopen;
+ struct ms_tx_entry rbuf;
+ uint8_t bytesread;
+
+ struct ms_tx_buf ms_unused_blocks;
+ struct ms_tx_buf ms_queue;
+
+ struct iichid_hw hw;
+
+ task_fn_t *event_handler;
+
+ struct i2c_hid_desc desc;
+ struct ms_info info[MS_INFO_MAX];
+ uint8_t sc_iid;
+ mousehw_t sc_hw;
+ mousestatus_t sc_status;
+ mousemode_t sc_mode;
+ struct mtx lock;
+
+ struct cv cv;
+ bool detaching;
+
+ int invert;
+
+ uint8_t *input_buf;
+ int input_size;
+};
+
+struct acpi_iichid_softc {
+ device_t dev;
+ struct cdev *sc_devnode;
+
+ struct iichid_hw hw;
+
+ uint16_t irq;
+ int irq_rid;
+ struct resource* irq_res;
+ void* irq_cookie;
+ struct iichid_softc* iichid_sc;
+
+ int sampling_rate;
+ struct callout periodic_callout;
+ bool callout_setup;
+
+ struct taskqueue* taskqueue;
+ struct task event_task;
+
+ struct mtx lock;
+};
+
+int acpi_iichid_get_report(device_t dev, struct i2c_hid_desc* hid_desc, enum hid_kind type, int id, void *data, int len);
+
+
+#endif /* _IIC_HID_H_ */
Index: sys/dev/iicbus/input/iichid.c
===================================================================
--- /dev/null
+++ sys/dev/iicbus/input/iichid.c
@@ -0,0 +1,797 @@
+#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 <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/sbuf.h>
+#include <sys/endian.h>
+#include <sys/rman.h>
+#include <sys/uio.h>
+#include <machine/resource.h>
+
+#include <sys/ioccom.h>
+#include <sys/filio.h>
+#include <sys/tty.h>
+#include <sys/mouse.h>
+#include <dev/iicbus/input/iichid.h>
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iic.h>
+#include <dev/iicbus/iiconf.h>
+
+#include "iicbus_if.h"
+
+static device_probe_t iichid_probe;
+static device_attach_t iichid_attach;
+static device_detach_t iichid_detach;
+
+static devclass_t iichid_devclass;
+
+static device_method_t iichid_methods[] = {
+ DEVMETHOD(device_probe, iichid_probe),
+ DEVMETHOD(device_attach, iichid_attach),
+ DEVMETHOD(device_detach, iichid_detach),
+
+ DEVMETHOD_END
+};
+
+static d_open_t iichid_open;
+static d_close_t iichid_close;
+static d_read_t iichid_read;
+static d_write_t iichid_write;
+static d_ioctl_t iichid_ioctl;
+
+static struct cdevsw iichid_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = iichid_open,
+ .d_close = iichid_close,
+ .d_read = iichid_read,
+ .d_write = iichid_write,
+ .d_ioctl = iichid_ioctl,
+ .d_name = "iichid"
+};
+
+static driver_t iichid_driver = {
+ .name = "iichid",
+ .methods = iichid_methods,
+ .size = sizeof(struct iichid_softc),
+};
+
+static int
+iichid_fetch_buffer(device_t dev, uint8_t* cmd, int cmdlen, uint8_t *buf, int buflen)
+{
+ uint16_t addr = iicbus_get_addr(dev);
+ struct iic_msg msgs[] = {
+ { addr << 1, IIC_M_WR | IIC_M_NOSTOP, cmdlen, cmd },
+ { addr << 1, IIC_M_RD, buflen, buf },
+ };
+
+ return (iicbus_transfer(dev, msgs, nitems(msgs)));
+}
+
+static int
+iichid_fetch_report(device_t dev, struct i2c_hid_desc* hid_desc, uint8_t *data, int len, int *actual_len)
+{
+ struct iichid_softc* sc;
+ sc = device_get_softc(dev);
+
+ mtx_assert(&sc->lock, MA_OWNED);
+
+ *actual_len = 0;
+
+ uint16_t dtareg = htole16(hid_desc->wInputRegister);
+
+ uint8_t cmd[] = {dtareg & 0xff, dtareg >> 8};
+ int cmdlen = 2;
+ uint8_t buf[len];
+
+ mtx_unlock(&sc->lock);
+
+ int error = iichid_fetch_buffer(dev, cmd, cmdlen, buf, len);
+
+ mtx_lock(&sc->lock);
+
+ memcpy(data, buf, len);
+
+ if (error != 0)
+ {
+ device_printf(dev, "could not retrieve input report (%d)\n", error);
+ return error;
+ }
+
+ *actual_len = data[0] | data[1] << 8;
+
+ return 0;
+}
+
+static int fetch_hid_descriptor(device_t dev)
+{
+ struct iichid_softc *sc = device_get_softc(dev);
+
+ uint16_t cr = sc->hw.config_reg;
+ return (iichid_fetch_buffer(dev, (uint8_t*)&cr, sizeof(cr), (uint8_t*)&sc->desc, sizeof(struct i2c_hid_desc)));
+}
+
+static int fetch_report_descriptor(device_t dev, uint8_t **buf, int *len)
+{
+ struct iichid_softc *sc = device_get_softc(dev);
+
+ if (sc->desc.wHIDDescLength != 30)
+ return -1;
+
+ *buf = malloc(sc->desc.wReportDescLength, M_TEMP, M_NOWAIT | M_ZERO);
+ *len = sc->desc.wReportDescLength;
+
+ uint16_t rdr = sc->desc.wReportDescRegister;
+
+ int error = (iichid_fetch_buffer(dev, (uint8_t*)&rdr, sizeof(rdr), *buf, sc->desc.wReportDescLength));
+
+ return error;
+}
+
+static void
+ms_hid_parse(device_t dev, const uint8_t *buf, uint16_t len, struct ms_info *info, uint8_t index)
+{
+ uint32_t flags;
+ uint8_t i;
+ uint8_t j;
+
+ if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
+ hid_input, index, &info->sc_loc_x, &flags, &info->sc_iid_x)) {
+
+ if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
+ info->sc_flags |= MS_FLAG_X_AXIS;
+ }
+ }
+ if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
+ hid_input, index, &info->sc_loc_y, &flags, &info->sc_iid_y)) {
+
+ if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
+ info->sc_flags |= MS_FLAG_Y_AXIS;
+ }
+ }
+ /* Try the wheel first as the Z activator since it's tradition. */
+ if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
+ HUG_WHEEL), hid_input, index, &info->sc_loc_z, &flags,
+ &info->sc_iid_z) ||
+ hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
+ HUG_TWHEEL), hid_input, index, &info->sc_loc_z, &flags,
+ &info->sc_iid_z)) {
+ if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
+ info->sc_flags |= MS_FLAG_Z_AXIS;
+ }
+ /*
+ * We might have both a wheel and Z direction, if so put
+ * put the Z on the W coordinate.
+ */
+ if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
+ HUG_Z), hid_input, index, &info->sc_loc_w, &flags,
+ &info->sc_iid_w)) {
+
+ if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
+ info->sc_flags |= MS_FLAG_W_AXIS;
+ }
+ }
+ } else if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
+ HUG_Z), hid_input, index, &info->sc_loc_z, &flags,
+ &info->sc_iid_z)) {
+
+ if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
+ info->sc_flags |= MS_FLAG_Z_AXIS;
+ }
+ }
+ /*
+ * The Microsoft Wireless Intellimouse 2.0 reports it's wheel
+ * using 0x0048, which is HUG_TWHEEL, and seems to expect you
+ * to know that the byte after the wheel is the tilt axis.
+ * There are no other HID axis descriptors other than X,Y and
+ * TWHEEL
+ */
+ if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
+ HUG_TWHEEL), hid_input, index, &info->sc_loc_t,
+ &flags, &info->sc_iid_t)) {
+
+ info->sc_loc_t.pos += 8;
+
+ if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
+ info->sc_flags |= MS_FLAG_T_AXIS;
+ }
+ } else if (hid_locate(buf, len, HID_USAGE2(HUP_CONSUMER,
+ HUC_AC_PAN), hid_input, index, &info->sc_loc_t,
+ &flags, &info->sc_iid_t)) {
+
+ if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS)
+ info->sc_flags |= MS_FLAG_T_AXIS;
+ }
+ /* figure out the number of buttons */
+
+ for (i = 0; i < MS_BUTTON_MAX; i++) {
+ if (!hid_locate(buf, len, HID_USAGE2(HUP_BUTTON, (i + 1)),
+ hid_input, index, &info->sc_loc_btn[i], NULL,
+ &info->sc_iid_btn[i])) {
+ break;
+ }
+ }
+
+ /* detect other buttons */
+
+ for (j = 0; (i < MS_BUTTON_MAX) && (j < 2); i++, j++) {
+ if (!hid_locate(buf, len, HID_USAGE2(HUP_MICROSOFT, (j + 1)),
+ hid_input, index, &info->sc_loc_btn[i], NULL,
+ &info->sc_iid_btn[i])) {
+ break;
+ }
+ }
+
+ info->sc_buttons = i;
+
+ if (info->sc_flags == 0)
+ return;
+
+ /* announce information about the mouse */
+ device_printf(dev, "%d buttons and [%s%s%s%s%s] coordinates ID=%u\n",
+ (info->sc_buttons),
+ (info->sc_flags & MS_FLAG_X_AXIS) ? "X" : "",
+ (info->sc_flags & MS_FLAG_Y_AXIS) ? "Y" : "",
+ (info->sc_flags & MS_FLAG_Z_AXIS) ? "Z" : "",
+ (info->sc_flags & MS_FLAG_T_AXIS) ? "T" : "",
+ (info->sc_flags & MS_FLAG_W_AXIS) ? "W" : "",
+ info->sc_iid_x);
+}
+
+static int
+iichid_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct iichid_softc *sc = dev->si_drv1;
+
+ mtx_lock(&sc->lock);
+ if (sc->isopen)
+ {
+ mtx_unlock(&sc->lock);
+ return (EBUSY);
+ }
+
+ sc->isopen = true;
+ sc->bytesread = sc->sc_mode.packetsize;
+
+
+ while (!STAILQ_EMPTY(&sc->ms_queue))
+ {
+ struct ms_tx_entry *u = STAILQ_FIRST(&sc->ms_queue);
+ STAILQ_REMOVE_HEAD(&sc->ms_queue, next);
+ STAILQ_INSERT_HEAD(&sc->ms_unused_blocks, u, next);
+ }
+
+ mtx_unlock(&sc->lock);
+
+ return 0;
+}
+
+static int
+iichid_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
+{
+ struct iichid_softc *sc = dev->si_drv1;
+
+ cv_broadcastpri(&sc->cv, 0);
+
+ mtx_lock(&sc->lock);
+ sc->isopen=false;
+ mtx_unlock(&sc->lock);
+
+ return 0;
+}
+
+static int
+iichid_write(struct cdev *dev, struct uio *uio, int ioflags)
+{
+ return 0;
+}
+
+static int
+iichid_read(struct cdev *dev, struct uio* uio, int ioflags)
+{
+ struct iichid_softc *sc = dev->si_drv1;
+
+ mtx_lock(&sc->lock);
+
+ while (!sc->detaching && STAILQ_EMPTY(&sc->ms_queue) && sc->bytesread == sc->sc_mode.packetsize)
+ {
+ int error = cv_wait_sig(&sc->cv, &sc->lock);
+ if (error != 0)
+ {
+ mtx_unlock(&sc->lock);
+ return error;
+ }
+ }
+
+ if (sc->detaching)
+ {
+ mtx_unlock(&sc->lock);
+ return ENXIO;
+ }
+
+ if (sc->bytesread == sc->sc_mode.packetsize && !STAILQ_EMPTY(&sc->ms_queue))
+ {
+ struct ms_tx_entry *u = STAILQ_FIRST(&sc->ms_queue);
+ STAILQ_REMOVE_HEAD(&sc->ms_queue, next);
+ memcpy(&sc->rbuf, u, sizeof(struct ms_tx_entry));
+ sc->bytesread = 0;
+
+ STAILQ_INSERT_TAIL(&sc->ms_unused_blocks, u, next);
+ }
+ mtx_unlock(&sc->lock);
+
+ int error = uiomove(sc->rbuf.buf+sc->bytesread, 1, uio);
+ sc->bytesread++;
+ if (error != 0)
+ device_printf(sc->dev, "I could not be read from");
+
+ return 0;
+}
+
+static int
+iichid_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
+{
+ struct iichid_softc *sc = dev->si_drv1;
+ int error = 0;
+ mousemode_t mode;
+
+ mtx_lock(&sc->lock);
+
+ switch (cmd) {
+ case MOUSE_SETMODE:
+ mode = *(mousemode_t*)data;
+
+ if (mode.level == -1) {
+ /* don't change the current setting */
+ } else if ((mode.level < 0) || (mode.level > 1)) {
+ error = EINVAL;
+ break;
+ } else {
+ sc->sc_mode.level = mode.level;
+ }
+
+ if (sc->sc_mode.level == 0) {
+ if (sc->sc_hw.buttons > MOUSE_MSC_MAXBUTTON)
+ sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
+
+ sc->sc_mode.protocol = MOUSE_PROTO_MSC;
+ sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
+ sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
+ sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
+ } else if (sc->sc_mode.level == 1) {
+ if (sc->sc_hw.buttons > MOUSE_SYS_MAXBUTTON)
+ sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON;
+
+ sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
+ sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
+ sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
+ sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
+ }
+ break;
+ case MOUSE_SETLEVEL:
+ if (*(int *)data < 0 || *(int *)data > 1) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_mode.level = *(int *)data;
+
+ if (sc->sc_mode.level == 0) {
+ if (sc->sc_hw.buttons > MOUSE_MSC_MAXBUTTON)
+ sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
+
+ sc->sc_mode.protocol = MOUSE_PROTO_MSC;
+ sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
+ sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
+ sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
+ } else if (sc->sc_mode.level == 1) {
+ if (sc->sc_hw.buttons > MOUSE_SYS_MAXBUTTON)
+ sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON;
+
+ sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
+ sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
+ sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
+ sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
+ }
+ break;
+ case MOUSE_GETHWINFO:
+ *(mousehw_t *)data = sc->sc_hw;
+ break;
+
+ case MOUSE_GETMODE:
+ *(mousemode_t *)data = sc->sc_mode;
+ break;
+
+ case MOUSE_GETLEVEL:
+ *(int *)data = sc->sc_mode.level;
+ break;
+
+ case MOUSE_GETSTATUS:{
+ mousestatus_t *status = (mousestatus_t *)data;
+
+ *status = sc->sc_status;
+ sc->sc_status.obutton = sc->sc_status.button;
+ sc->sc_status.button = 0;
+ sc->sc_status.dx = 0;
+ sc->sc_status.dy = 0;
+ sc->sc_status.dz = 0;
+ /* sc->sc_status.dt = 0; */
+
+ if (status->dx || status->dy || status->dz /* || status->dt */ ) {
+ status->flags |= MOUSE_POSCHANGED;
+ }
+ if (status->button != status->obutton) {
+ status->flags |= MOUSE_BUTTONSCHANGED;
+ }
+ break;
+ }
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ mtx_unlock(&sc->lock);
+ return (error);
+}
+
+static void
+ms_put_queue(struct iichid_softc *sc, int32_t dx, int32_t dy,
+ int32_t dz, int32_t dt, int32_t buttons)
+{
+ if (dx > 254)
+ dx = 254;
+ if (dx < -256)
+ dx = -256;
+ if (dy > 254)
+ dy = 254;
+ if (dy < -256)
+ dy = -256;
+ if (dz > 126)
+ dz = 126;
+ if (dz < -128)
+ dz = -128;
+ if (dt > 126)
+ dt = 126;
+ if (dt < -128)
+ dt = -128;
+
+ if (sc->invert != 0)
+ dz = -dz;
+ if (!STAILQ_EMPTY(&sc->ms_unused_blocks))
+ {
+ struct ms_tx_entry *u = STAILQ_FIRST(&sc->ms_unused_blocks);
+ STAILQ_REMOVE_HEAD(&sc->ms_unused_blocks, next);
+
+ u->buf[0] = MOUSE_MSC_SYNC;
+ u->buf[0] |= (~buttons) & MOUSE_MSC_BUTTONS;
+ u->buf[1] = dx >> 1;
+ u->buf[2] = dy >> 1;
+ u->buf[3] = dx - (dx >> 1);
+ u->buf[4] = dy - (dy >> 1);
+
+ if (sc->sc_mode.level == 1) {
+ u->buf[5] = dz >> 1;
+ u->buf[6] = dz - (dz >> 1);
+ u->buf[7] = (((~buttons) >> 3) & MOUSE_SYS_EXTBUTTONS);
+ }
+
+ STAILQ_INSERT_TAIL(&sc->ms_queue, u, next);
+ } else {
+ device_printf(sc->dev, "no blocks available\n");
+ }
+}
+
+static void
+iichid_event(void* context, int pending)
+{
+ struct iichid_softc *sc = context;
+
+ mtx_lock(&sc->lock);
+
+ int actual = 0;
+ int error = iichid_fetch_report(sc->dev, &sc->desc, sc->input_buf, sc->input_size, &actual);
+
+ if (error != 0)
+ {
+ device_printf(sc->dev, "an error occured\n");
+ mtx_unlock(&sc->lock);
+ return;
+ }
+
+ if (actual <= 0)
+ {
+ device_printf(sc->dev, "no data received\n");
+ mtx_unlock(&sc->lock);
+ return;
+ }
+
+ int32_t dw = 0;
+ int32_t dx = 0;
+ int32_t dy = 0;
+ int32_t dz = 0;
+ int32_t dt = 0;
+ int32_t buttons = 0;
+ int32_t buttons_found = 0;
+ uint8_t id = 0;
+
+ uint8_t *buf = sc->input_buf;
+ buf++; buf++;
+ int len = actual;
+
+ if (sc->sc_iid)
+ {
+ id = *buf;
+ buf++;
+ len--;
+ }
+
+// device_printf(sc->dev, "id: %d\n", id);
+
+ for(int i=0; i<MS_INFO_MAX; i++)
+ {
+ struct ms_info *info = &sc->info[i];
+ if ((info->sc_flags & MS_FLAG_W_AXIS) &&
+ (id == info->sc_iid_w))
+ dw += hid_get_data(buf, len, &info->sc_loc_w);
+
+ if ((info->sc_flags & MS_FLAG_X_AXIS) &&
+ (id == info->sc_iid_x))
+ dx += hid_get_data(buf, len, &info->sc_loc_x);
+
+ if ((info->sc_flags & MS_FLAG_Y_AXIS) &&
+ (id == info->sc_iid_y))
+ dy -= hid_get_data(buf, len, &info->sc_loc_y);
+
+ if ((info->sc_flags & MS_FLAG_Z_AXIS) &&
+ (id == info->sc_iid_z)) {
+ int32_t temp;
+ temp = hid_get_data(buf, len, &info->sc_loc_z);
+ dz -= temp;
+ }
+
+ if ((info->sc_flags & MS_FLAG_T_AXIS) &&
+ (id == info->sc_iid_t)) {
+ dt -= hid_get_data(buf, len, &info->sc_loc_t);
+ /* T-axis is translated into button presses */
+ buttons_found |= (1UL << 5) | (1UL << 6);
+ }
+
+ for (i = 0; i < info->sc_buttons; i++) {
+ uint32_t mask;
+ mask = 1UL << MS_BUT(i);
+ /* check for correct button ID */
+ if (id != info->sc_iid_btn[i])
+ continue;
+ /* check for button pressed */
+ if (hid_get_data(buf, len, &info->sc_loc_btn[i]))
+ buttons |= mask;
+ /* register button mask */
+ buttons_found |= mask;
+ }
+
+ buttons |= sc->sc_status.button & ~buttons_found;
+
+ if (dx || dy || dz || dt || dw ||
+ (buttons != sc->sc_status.button)) {
+
+ /* translate T-axis into button presses until further */
+ if (dt > 0) {
+ ms_put_queue(sc, 0, 0, 0, 0, buttons);
+ buttons |= 1UL << 5;
+ } else if (dt < 0) {
+ ms_put_queue(sc, 0, 0, 0, 0, buttons);
+ buttons |= 1UL << 6;
+ }
+
+ sc->sc_status.button = buttons;
+ sc->sc_status.dx += dx;
+ sc->sc_status.dy += dy;
+ sc->sc_status.dz += dz;
+
+ //device_printf(sc->dev, "dx: %d, dy: %d, dz: %d, dt: %d, dw: %d, btn: 0x%2x\n", dx, dy, dz, dt, dw, buttons);
+
+ ms_put_queue(sc, dx, dy, dz, dt, buttons);
+ }
+ }
+
+// device_printf(sc->dev, "read: %d/%d\n", actual, sc->desc.wMaxInputLength);
+ mtx_unlock(&sc->lock);
+
+ cv_signal(&sc->cv);
+}
+
+static int
+iichid_probe(device_t dev)
+{
+ device_t pdev = device_get_parent(dev);
+
+ if (!pdev)
+ return (ENXIO);
+
+ driver_t *pdrv = device_get_driver(pdev);
+
+ if (!pdrv)
+ return (ENXIO);
+
+ if (strcmp(pdrv->name, "iicbus") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "HID over I2C");
+
+ return (BUS_PROBE_VENDOR);
+}
+
+static int
+sysctl_invert_handler(SYSCTL_HANDLER_ARGS)
+{
+ int err, value;
+ struct iichid_softc *sc;
+
+ sc = arg1;
+
+ mtx_lock(&sc->lock);
+
+ value = sc->invert;
+ err = sysctl_handle_int(oidp, &value, 0, req);
+
+ if (err != 0 || req->newptr == NULL || value == sc->invert)
+ {
+ mtx_unlock(&sc->lock);
+ return (err);
+ }
+
+ sc->invert = value;
+
+ mtx_unlock(&sc->lock);
+
+ return (0);
+}
+
+static int
+iichid_attach(device_t dev)
+{
+ struct iichid_softc *sc = device_get_softc(dev);
+
+ uintptr_t addr = 0, cr = 0;
+ int error;
+
+ sc->dev = dev;
+ sc->detaching = false;
+ sc->input_buf = NULL;
+ sc->isopen = 0;
+ sc->invert = 0;
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "invert_scroll", CTLTYPE_INT | CTLFLAG_RWTUN,
+ sc, 0,
+ sysctl_invert_handler, "I", "invert mouse axis");
+
+ // the config register is passed as resources, while the device address will always have a place in the iicbus child's (ivars) heart
+ bus_get_resource(dev, SYS_RES_IOPORT, 0, (rman_res_t*)&cr, NULL);
+ BUS_READ_IVAR(device_get_parent(dev), dev, IICBUS_IVAR_ADDR, &addr);
+
+ // store the value in device's softc to have easy access
+ // values only have 1 byte length, still make the casts explicit
+ sc->hw.device_addr = (uint8_t)addr;
+ sc->hw.config_reg = (uint16_t)cr;
+
+ sc->event_handler = iichid_event;
+
+ sc->cdev = make_dev(&iichid_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "ims%d", device_get_unit(dev));
+ sc->cdev->si_drv1 = sc;
+
+ device_printf(dev, "ADDR 0x%x REG 0x%x\n", sc->hw.device_addr, sc->hw.config_reg);
+
+ if ( (error = fetch_hid_descriptor(dev)) != 0 )
+ {
+ iichid_detach(dev);
+ device_printf(dev, "could not retrieve HID descriptor from device: %d\n", error);
+ }
+
+ uint8_t *rdesc;
+ int len;
+
+ if ( (error = fetch_report_descriptor(dev, &rdesc, &len)) != 0 )
+ {
+ iichid_detach(dev);
+ device_printf(dev, "could not retrieve report descriptor from device: %d\n", error);
+ }
+
+ sc->input_size = sc->desc.wMaxInputLength;
+ sc->input_buf = malloc(sc->desc.wMaxInputLength, M_DEVBUF, M_NOWAIT | M_ZERO);
+
+ for (int i = 0; i < MS_INFO_MAX; i++) {
+ ms_hid_parse(dev, rdesc, len, &sc->info[0], 0);
+ }
+
+ int isize = hid_report_size(rdesc, len, hid_input, &sc->sc_iid);
+
+
+ if (isize+2 != sc->desc.wMaxInputLength)
+ device_printf(dev, "determined (len=%d) and described (len=%d) input report lengths mismatch\n", isize+2, sc->desc.wMaxInputLength);
+
+ mtx_init(&sc->lock, "iichid spin-lock", NULL, MTX_DEF);
+ cv_init(&sc->cv, "iichid cv");
+
+ sc->sc_hw.buttons = -1;
+ sc->sc_hw.iftype = MOUSE_IF_SYSMOUSE;
+ sc->sc_hw.type = MOUSE_MOUSE;
+ sc->sc_hw.model = MOUSE_MODEL_GENERIC;
+ sc->sc_hw.hwid = sc->desc.wVendorID;
+
+ sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
+ sc->sc_mode.rate = -1;
+ sc->sc_mode.resolution = -1;
+ sc->sc_mode.accelfactor = 1;
+ sc->sc_mode.level = 0;
+ sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
+
+ STAILQ_INIT(&sc->ms_queue);
+ STAILQ_INIT(&sc->ms_unused_blocks);
+ for(int i=0; i<MS_BUFQ_MAXLEN; i++)
+ {
+ struct ms_tx_entry *u = malloc(sizeof(struct ms_tx_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
+ STAILQ_INSERT_TAIL(&sc->ms_unused_blocks, u, next);
+ }
+
+// device_printf(dev, "len: %d\nbcdVer: %d\nreport len: %d\ninput len: %d\nvid: 0x%x\npid: 0x%x\n", hid_desc.wHIDDescLength, hid_desc.bcdVersion, hid_desc.wReportDescLength, hid_desc.wMaxInputLength, hid_desc.wVendorID, hid_desc.wProductID);
+
+ return (0); /* success */
+}
+
+static int
+iichid_detach(device_t dev)
+{
+ struct iichid_softc *sc = device_get_softc(dev);
+ if (sc)
+ {
+ if (sc->isopen)
+ return (EBUSY);
+
+ mtx_lock(&sc->lock);
+ sc->detaching = true;
+ mtx_unlock(&sc->lock);
+ cv_broadcastpri(&sc->cv,0);
+ if (mtx_initialized(&sc->lock))
+ {
+ mtx_destroy(&sc->lock);
+ }
+
+ struct ms_tx_buf* queues[2] = {&sc->ms_queue, &sc->ms_unused_blocks};
+ for(int i=0; i<2; i++)
+ {
+ while (!STAILQ_EMPTY(queues[i]))
+ {
+ struct ms_tx_entry *u = STAILQ_FIRST(queues[i]);
+ STAILQ_REMOVE_HEAD(queues[i], next);
+ free(u, M_DEVBUF);
+ }
+ }
+
+ if (sc->cdev)
+ destroy_dev(sc->cdev);
+
+ if (sc->input_buf)
+ free(sc->input_buf, M_DEVBUF);
+ }
+ return (0);
+}
+
+DRIVER_MODULE(iichid, iicbus, iichid_driver, iichid_devclass, NULL, 0);
+MODULE_DEPEND(iichid, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
+MODULE_VERSION(iichid, 1);
Index: sys/dev/usb/hid.h
===================================================================
--- /dev/null
+++ sys/dev/usb/hid.h
@@ -0,0 +1,240 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
+ * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.
+ * Copyright (c) 1998 Lennart Augustsson. All rights reserved.
+ *
+ * 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_H_
+#define _HID_H_
+
+#define UR_GET_HID_DESCRIPTOR 0x06
+#define UDESC_HID 0x21
+#define UDESC_REPORT 0x22
+#define UDESC_PHYSICAL 0x23
+#define UR_SET_HID_DESCRIPTOR 0x07
+#define UR_GET_REPORT 0x01
+#define UR_SET_REPORT 0x09
+#define UR_GET_IDLE 0x02
+#define UR_SET_IDLE 0x0a
+#define UR_GET_PROTOCOL 0x03
+#define UR_SET_PROTOCOL 0x0b
+
+struct hid_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bcdHID[2];
+ uint8_t bCountryCode;
+ uint8_t bNumDescriptors;
+ struct {
+ uint8_t bDescriptorType;
+ uint8_t wDescriptorLength[2];
+ } descrs[1];
+} __packed;
+
+#define HID_DESCRIPTOR_SIZE(n) (9+((n)*3))
+
+/* Usage pages */
+#define HUP_UNDEFINED 0x0000
+#define HUP_GENERIC_DESKTOP 0x0001
+#define HUP_SIMULATION 0x0002
+#define HUP_VR_CONTROLS 0x0003
+#define HUP_SPORTS_CONTROLS 0x0004
+#define HUP_GAMING_CONTROLS 0x0005
+#define HUP_KEYBOARD 0x0007
+#define HUP_LEDS 0x0008
+#define HUP_BUTTON 0x0009
+#define HUP_ORDINALS 0x000a
+#define HUP_TELEPHONY 0x000b
+#define HUP_CONSUMER 0x000c
+#define HUP_DIGITIZERS 0x000d
+#define HUP_PHYSICAL_IFACE 0x000e
+#define HUP_UNICODE 0x0010
+#define HUP_ALPHANUM_DISPLAY 0x0014
+#define HUP_MONITOR 0x0080
+#define HUP_MONITOR_ENUM_VAL 0x0081
+#define HUP_VESA_VC 0x0082
+#define HUP_VESA_CMD 0x0083
+#define HUP_POWER 0x0084
+#define HUP_BATTERY_SYSTEM 0x0085
+#define HUP_BARCODE_SCANNER 0x008b
+#define HUP_SCALE 0x008c
+#define HUP_CAMERA_CONTROL 0x0090
+#define HUP_ARCADE 0x0091
+#define HUP_MICROSOFT 0xff00
+
+/* Usages, generic desktop */
+#define HUG_POINTER 0x0001
+#define HUG_MOUSE 0x0002
+#define HUG_JOYSTICK 0x0004
+#define HUG_GAME_PAD 0x0005
+#define HUG_KEYBOARD 0x0006
+#define HUG_KEYPAD 0x0007
+#define HUG_X 0x0030
+#define HUG_Y 0x0031
+#define HUG_Z 0x0032
+#define HUG_RX 0x0033
+#define HUG_RY 0x0034
+#define HUG_RZ 0x0035
+#define HUG_SLIDER 0x0036
+#define HUG_DIAL 0x0037
+#define HUG_WHEEL 0x0038
+#define HUG_HAT_SWITCH 0x0039
+#define HUG_COUNTED_BUFFER 0x003a
+#define HUG_BYTE_COUNT 0x003b
+#define HUG_MOTION_WAKEUP 0x003c
+#define HUG_VX 0x0040
+#define HUG_VY 0x0041
+#define HUG_VZ 0x0042
+#define HUG_VBRX 0x0043
+#define HUG_VBRY 0x0044
+#define HUG_VBRZ 0x0045
+#define HUG_VNO 0x0046
+#define HUG_TWHEEL 0x0048 /* M$ Wireless Intellimouse Wheel */
+#define HUG_SYSTEM_CONTROL 0x0080
+#define HUG_SYSTEM_POWER_DOWN 0x0081
+#define HUG_SYSTEM_SLEEP 0x0082
+#define HUG_SYSTEM_WAKEUP 0x0083
+#define HUG_SYSTEM_CONTEXT_MENU 0x0084
+#define HUG_SYSTEM_MAIN_MENU 0x0085
+#define HUG_SYSTEM_APP_MENU 0x0086
+#define HUG_SYSTEM_MENU_HELP 0x0087
+#define HUG_SYSTEM_MENU_EXIT 0x0088
+#define HUG_SYSTEM_MENU_SELECT 0x0089
+#define HUG_SYSTEM_MENU_RIGHT 0x008a
+#define HUG_SYSTEM_MENU_LEFT 0x008b
+#define HUG_SYSTEM_MENU_UP 0x008c
+#define HUG_SYSTEM_MENU_DOWN 0x008d
+#define HUG_APPLE_EJECT 0x00b8
+
+/* Usages Digitizers */
+#define HUD_UNDEFINED 0x0000
+#define HUD_TIP_PRESSURE 0x0030
+#define HUD_BARREL_PRESSURE 0x0031
+#define HUD_IN_RANGE 0x0032
+#define HUD_TOUCH 0x0033
+#define HUD_UNTOUCH 0x0034
+#define HUD_TAP 0x0035
+#define HUD_QUALITY 0x0036
+#define HUD_DATA_VALID 0x0037
+#define HUD_TRANSDUCER_INDEX 0x0038
+#define HUD_TABLET_FKEYS 0x0039
+#define HUD_PROGRAM_CHANGE_KEYS 0x003a
+#define HUD_BATTERY_STRENGTH 0x003b
+#define HUD_INVERT 0x003c
+#define HUD_X_TILT 0x003d
+#define HUD_Y_TILT 0x003e
+#define HUD_AZIMUTH 0x003f
+#define HUD_ALTITUDE 0x0040
+#define HUD_TWIST 0x0041
+#define HUD_TIP_SWITCH 0x0042
+#define HUD_SEC_TIP_SWITCH 0x0043
+#define HUD_BARREL_SWITCH 0x0044
+#define HUD_ERASER 0x0045
+#define HUD_TABLET_PICK 0x0046
+
+/* Usages, Consumer */
+#define HUC_AC_PAN 0x0238
+
+#define HID_USAGE2(p,u) (((p) << 16) | (u))
+
+#define UHID_INPUT_REPORT 0x01
+#define UHID_OUTPUT_REPORT 0x02
+#define UHID_FEATURE_REPORT 0x03
+
+/* Bits in the input/output/feature items */
+#define HIO_CONST 0x001
+#define HIO_VARIABLE 0x002
+#define HIO_RELATIVE 0x004
+#define HIO_WRAP 0x008
+#define HIO_NONLINEAR 0x010
+#define HIO_NOPREF 0x020
+#define HIO_NULLSTATE 0x040
+#define HIO_VOLATILE 0x080
+#define HIO_BUFBYTES 0x100
+
+#ifdef _KERNEL
+
+enum hid_kind {
+ hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
+};
+
+struct hid_location {
+ uint32_t size;
+ uint32_t count;
+ uint32_t pos;
+};
+
+struct hid_item {
+ /* Global */
+ int32_t _usage_page;
+ int32_t logical_minimum;
+ int32_t logical_maximum;
+ int32_t physical_minimum;
+ int32_t physical_maximum;
+ int32_t unit_exponent;
+ int32_t unit;
+ int32_t report_ID;
+ /* Local */
+ int32_t usage;
+ int32_t usage_minimum;
+ int32_t usage_maximum;
+ int32_t designator_index;
+ int32_t designator_minimum;
+ int32_t designator_maximum;
+ int32_t string_index;
+ int32_t string_minimum;
+ int32_t string_maximum;
+ int32_t set_delimiter;
+ /* Misc */
+ int32_t collection;
+ int collevel;
+ enum hid_kind kind;
+ uint32_t flags;
+ /* Location */
+ struct hid_location loc;
+};
+
+/* prototypes from "hid.c" */
+
+struct hid_data *hid_start_parse(const void *d, 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, size_t len, enum hid_kind k,
+ uint8_t *id);
+int hid_locate(const void *desc, 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, size_t len,
+ struct hid_location *loc);
+uint32_t hid_get_data_unsigned(const uint8_t *buf, size_t len,
+ struct hid_location *loc);
+void hid_put_data_unsigned(uint8_t *buf, size_t len,
+ struct hid_location *loc, unsigned int value);
+int hid_is_collection(const void *desc, 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);
+#endif /* _KERNEL */
+#endif /* _HID_H_ */
Index: sys/dev/usb/hid.c
===================================================================
--- /dev/null
+++ sys/dev/usb/hid.c
@@ -0,0 +1,916 @@
+/* $FreeBSD$ */
+/* $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ */
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/usb/hid.h>
+
+#define HID_DEBUG_VAR hid_debug
+
+#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
+
+static void hid_clear_local(struct hid_item *);
+static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize);
+
+#define MAXUSAGE 64
+#define MAXPUSH 4
+#define MAXID 16
+#define MAXLOCCNT 1024
+
+struct hid_pos_data {
+ int32_t rid;
+ uint32_t pos;
+};
+
+struct hid_data {
+ const uint8_t *start;
+ const uint8_t *end;
+ const uint8_t *p;
+ struct hid_item cur[MAXPUSH];
+ struct hid_pos_data last_pos[MAXID];
+ int32_t usages_min[MAXUSAGE];
+ int32_t usages_max[MAXUSAGE];
+ int32_t usage_last; /* last seen usage */
+ uint32_t loc_size; /* last seen size */
+ uint32_t loc_count; /* last seen count */
+ uint8_t ncount; /* end usage item count */
+ uint8_t icount; /* current usage item count */
+ uint8_t kindset; /* we have 5 kinds so 8 bits are enough */
+ uint8_t pushlevel; /* current pushlevel */
+ uint8_t nusage; /* end "usages_min/max" index */
+ uint8_t iusage; /* current "usages_min/max" index */
+ uint8_t ousage; /* current "usages_min/max" offset */
+ uint8_t susage; /* usage set flags */
+};
+
+/*------------------------------------------------------------------------*
+ * hid_clear_local
+ *------------------------------------------------------------------------*/
+static void
+hid_clear_local(struct hid_item *c)
+{
+
+ c->loc.count = 0;
+ c->loc.size = 0;
+ c->usage = 0;
+ c->usage_minimum = 0;
+ c->usage_maximum = 0;
+ c->designator_index = 0;
+ c->designator_minimum = 0;
+ c->designator_maximum = 0;
+ c->string_index = 0;
+ c->string_minimum = 0;
+ c->string_maximum = 0;
+ c->set_delimiter = 0;
+}
+
+static void
+hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
+{
+ uint8_t i;
+
+ /* check for same report ID - optimise */
+
+ if (c->report_ID == next_rID)
+ return;
+
+ /* save current position for current rID */
+
+ if (c->report_ID == 0) {
+ i = 0;
+ } else {
+ for (i = 1; i != MAXID; i++) {
+ if (s->last_pos[i].rid == c->report_ID)
+ break;
+ if (s->last_pos[i].rid == 0)
+ break;
+ }
+ }
+ if (i != MAXID) {
+ s->last_pos[i].rid = c->report_ID;
+ s->last_pos[i].pos = c->loc.pos;
+ }
+
+ /* store next report ID */
+
+ c->report_ID = next_rID;
+
+ /* lookup last position for next rID */
+
+ if (next_rID == 0) {
+ i = 0;
+ } else {
+ for (i = 1; i != MAXID; i++) {
+ if (s->last_pos[i].rid == next_rID)
+ break;
+ if (s->last_pos[i].rid == 0)
+ break;
+ }
+ }
+ if (i != MAXID) {
+ s->last_pos[i].rid = next_rID;
+ c->loc.pos = s->last_pos[i].pos;
+ } else {
+ DPRINTF("Out of RID entries, position is set to zero!\n");
+ c->loc.pos = 0;
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * hid_start_parse
+ *------------------------------------------------------------------------*/
+struct hid_data *
+hid_start_parse(const void *d, size_t len, int kindset)
+{
+ struct hid_data *s;
+
+ if ((kindset-1) & kindset) {
+ DPRINTFN(0, "Only one bit can be "
+ "set in the kindset\n");
+ return (NULL);
+ }
+
+ s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
+ s->start = s->p = d;
+ s->end = ((const uint8_t *)d) + len;
+ s->kindset = kindset;
+ return (s);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_end_parse
+ *------------------------------------------------------------------------*/
+void
+hid_end_parse(struct hid_data *s)
+{
+ if (s == NULL)
+ return;
+
+ free(s, M_TEMP);
+}
+
+/*------------------------------------------------------------------------*
+ * get byte from HID descriptor
+ *------------------------------------------------------------------------*/
+static uint8_t
+hid_get_byte(struct hid_data *s, const uint16_t wSize)
+{
+ const uint8_t *ptr;
+ uint8_t retval;
+
+ ptr = s->p;
+
+ /* check if end is reached */
+ if (ptr == s->end)
+ return (0);
+
+ /* read out a byte */
+ retval = *ptr;
+
+ /* check if data pointer can be advanced by "wSize" bytes */
+ if ((s->end - ptr) < wSize)
+ ptr = s->end;
+ else
+ ptr += wSize;
+
+ /* update pointer */
+ s->p = ptr;
+
+ return (retval);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_get_item
+ *------------------------------------------------------------------------*/
+int
+hid_get_item(struct hid_data *s, struct hid_item *h)
+{
+ struct hid_item *c;
+ unsigned int bTag, bType, bSize;
+ uint32_t oldpos;
+ int32_t mask;
+ int32_t dval;
+
+ if (s == NULL)
+ return (0);
+
+ c = &s->cur[s->pushlevel];
+
+ top:
+ /* check if there is an array of items */
+ if (s->icount < s->ncount) {
+ /* get current usage */
+ if (s->iusage < s->nusage) {
+ dval = s->usages_min[s->iusage] + s->ousage;
+ c->usage = dval;
+ s->usage_last = dval;
+ if (dval == s->usages_max[s->iusage]) {
+ s->iusage ++;
+ s->ousage = 0;
+ } else {
+ s->ousage ++;
+ }
+ } else {
+ DPRINTFN(1, "Using last usage\n");
+ dval = s->usage_last;
+ }
+ s->icount ++;
+ /*
+ * Only copy HID item, increment position and return
+ * if correct kindset!
+ */
+ if (s->kindset & (1 << c->kind)) {
+ *h = *c;
+ DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
+ h->loc.size, h->loc.count);
+ c->loc.pos += c->loc.size * c->loc.count;
+ return (1);
+ }
+ }
+
+ /* reset state variables */
+ s->icount = 0;
+ s->ncount = 0;
+ s->iusage = 0;
+ s->nusage = 0;
+ s->susage = 0;
+ s->ousage = 0;
+ hid_clear_local(c);
+
+ /* get next item */
+ while (s->p != s->end) {
+
+ bSize = hid_get_byte(s, 1);
+ if (bSize == 0xfe) {
+ /* long item */
+ bSize = hid_get_byte(s, 1);
+ bSize |= hid_get_byte(s, 1) << 8;
+ bTag = hid_get_byte(s, 1);
+ bType = 0xff; /* XXX what should it be */
+ } else {
+ /* short item */
+ bTag = bSize >> 4;
+ bType = (bSize >> 2) & 3;
+ bSize &= 3;
+ if (bSize == 3)
+ bSize = 4;
+ }
+ switch (bSize) {
+ case 0:
+ dval = 0;
+ mask = 0;
+ break;
+ case 1:
+ dval = (int8_t)hid_get_byte(s, 1);
+ mask = 0xFF;
+ break;
+ case 2:
+ dval = hid_get_byte(s, 1);
+ dval |= hid_get_byte(s, 1) << 8;
+ dval = (int16_t)dval;
+ mask = 0xFFFF;
+ break;
+ case 4:
+ dval = hid_get_byte(s, 1);
+ dval |= hid_get_byte(s, 1) << 8;
+ dval |= hid_get_byte(s, 1) << 16;
+ dval |= hid_get_byte(s, 1) << 24;
+ mask = 0xFFFFFFFF;
+ break;
+ default:
+ dval = hid_get_byte(s, bSize);
+ DPRINTFN(0, "bad length %u (data=0x%02x)\n",
+ bSize, dval);
+ continue;
+ }
+
+ switch (bType) {
+ case 0: /* Main */
+ switch (bTag) {
+ case 8: /* Input */
+ c->kind = hid_input;
+ ret:
+ c->loc.count = s->loc_count;
+ c->loc.size = s->loc_size;
+
+ if (c->flags & HIO_VARIABLE) {
+ /* range check usage count */
+ if (c->loc.count > MAXLOCCNT) {
+ DPRINTFN(0, "Number of "
+ "items(%u) truncated to %u\n",
+ (unsigned)(c->loc.count),
+ MAXLOCCNT);
+ s->ncount = MAXLOCCNT;
+ } else
+ s->ncount = c->loc.count;
+
+ /*
+ * The "top" loop will return
+ * one and one item:
+ */
+ c->loc.count = 1;
+ } else {
+ s->ncount = 1;
+ }
+ goto top;
+
+ case 9: /* Output */
+ c->kind = hid_output;
+ goto ret;
+ case 10: /* Collection */
+ c->kind = hid_collection;
+ c->collection = dval;
+ c->collevel++;
+ c->usage = s->usage_last;
+ *h = *c;
+ return (1);
+ case 11: /* Feature */
+ c->kind = hid_feature;
+ goto ret;
+ case 12: /* End collection */
+ c->kind = hid_endcollection;
+ if (c->collevel == 0) {
+ DPRINTFN(0, "invalid end collection\n");
+ return (0);
+ }
+ c->collevel--;
+ *h = *c;
+ return (1);
+ default:
+ DPRINTFN(0, "Main bTag=%d\n", bTag);
+ break;
+ }
+ break;
+ case 1: /* Global */
+ switch (bTag) {
+ case 0:
+ c->_usage_page = dval << 16;
+ break;
+ case 1:
+ c->logical_minimum = dval;
+ break;
+ case 2:
+ c->logical_maximum = dval;
+ break;
+ case 3:
+ c->physical_minimum = dval;
+ break;
+ case 4:
+ c->physical_maximum = dval;
+ break;
+ case 5:
+ c->unit_exponent = dval;
+ break;
+ case 6:
+ c->unit = dval;
+ break;
+ case 7:
+ /* mask because value is unsigned */
+ s->loc_size = dval & mask;
+ break;
+ case 8:
+ hid_switch_rid(s, c, dval & mask);
+ break;
+ case 9:
+ /* mask because value is unsigned */
+ s->loc_count = dval & mask;
+ break;
+ case 10: /* Push */
+ s->pushlevel ++;
+ if (s->pushlevel < MAXPUSH) {
+ s->cur[s->pushlevel] = *c;
+ /* store size and count */
+ c->loc.size = s->loc_size;
+ c->loc.count = s->loc_count;
+ /* update current item pointer */
+ c = &s->cur[s->pushlevel];
+ } else {
+ DPRINTFN(0, "Cannot push "
+ "item @ %d\n", s->pushlevel);
+ }
+ break;
+ case 11: /* Pop */
+ s->pushlevel --;
+ if (s->pushlevel < MAXPUSH) {
+ /* preserve position */
+ oldpos = c->loc.pos;
+ c = &s->cur[s->pushlevel];
+ /* restore size and count */
+ s->loc_size = c->loc.size;
+ s->loc_count = c->loc.count;
+ /* set default item location */
+ c->loc.pos = oldpos;
+ c->loc.size = 0;
+ c->loc.count = 0;
+ } else {
+ DPRINTFN(0, "Cannot pop "
+ "item @ %d\n", s->pushlevel);
+ }
+ break;
+ default:
+ DPRINTFN(0, "Global bTag=%d\n", bTag);
+ break;
+ }
+ break;
+ case 2: /* Local */
+ switch (bTag) {
+ case 0:
+ if (bSize != 4)
+ dval = (dval & mask) | c->_usage_page;
+
+ /* set last usage, in case of a collection */
+ s->usage_last = dval;
+
+ if (s->nusage < MAXUSAGE) {
+ s->usages_min[s->nusage] = dval;
+ s->usages_max[s->nusage] = dval;
+ s->nusage ++;
+ } else {
+ DPRINTFN(0, "max usage reached\n");
+ }
+
+ /* clear any pending usage sets */
+ s->susage = 0;
+ break;
+ case 1:
+ s->susage |= 1;
+
+ if (bSize != 4)
+ dval = (dval & mask) | c->_usage_page;
+ c->usage_minimum = dval;
+
+ goto check_set;
+ case 2:
+ s->susage |= 2;
+
+ if (bSize != 4)
+ dval = (dval & mask) | c->_usage_page;
+ c->usage_maximum = dval;
+
+ check_set:
+ if (s->susage != 3)
+ break;
+
+ /* sanity check */
+ if ((s->nusage < MAXUSAGE) &&
+ (c->usage_minimum <= c->usage_maximum)) {
+ /* add usage range */
+ s->usages_min[s->nusage] =
+ c->usage_minimum;
+ s->usages_max[s->nusage] =
+ c->usage_maximum;
+ s->nusage ++;
+ } else {
+ DPRINTFN(0, "Usage set dropped\n");
+ }
+ s->susage = 0;
+ break;
+ case 3:
+ c->designator_index = dval;
+ break;
+ case 4:
+ c->designator_minimum = dval;
+ break;
+ case 5:
+ c->designator_maximum = dval;
+ break;
+ case 7:
+ c->string_index = dval;
+ break;
+ case 8:
+ c->string_minimum = dval;
+ break;
+ case 9:
+ c->string_maximum = dval;
+ break;
+ case 10:
+ c->set_delimiter = dval;
+ break;
+ default:
+ DPRINTFN(0, "Local bTag=%d\n", bTag);
+ break;
+ }
+ break;
+ default:
+ DPRINTFN(0, "default bType=%d\n", bType);
+ break;
+ }
+ }
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_report_size
+ *------------------------------------------------------------------------*/
+int
+hid_report_size(const void *buf, 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;
+ uint8_t any_id;
+
+ any_id = 0;
+ hpos = 0;
+ lpos = 0xFFFFFFFF;
+
+ for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
+ if (h.kind == k) {
+ /* check for ID-byte presence */
+ if ((h.report_ID != 0) && !any_id) {
+ if (id != NULL)
+ *id = h.report_ID;
+ any_id = 1;
+ }
+ /* 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;
+ }
+ }
+ hid_end_parse(d);
+
+ /* safety check - can happen in case of currupt descriptors */
+ if (lpos > hpos)
+ temp = 0;
+ else
+ temp = hpos - lpos;
+
+ /* check for ID byte */
+ if (any_id)
+ temp += 8;
+ else if (id != NULL)
+ *id = 0;
+
+ /* return length in bytes rounded up */
+ return ((temp + 7) / 8);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_locate
+ *------------------------------------------------------------------------*/
+int
+hid_locate(const void *desc, 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;
+ struct hid_item h;
+
+ for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
+ if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
+ if (index--)
+ continue;
+ if (loc != NULL)
+ *loc = h.loc;
+ if (flags != NULL)
+ *flags = h.flags;
+ if (id != NULL)
+ *id = h.report_ID;
+ hid_end_parse(d);
+ return (1);
+ }
+ }
+ if (loc != NULL)
+ loc->size = 0;
+ if (flags != NULL)
+ *flags = 0;
+ if (id != NULL)
+ *id = 0;
+ hid_end_parse(d);
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_get_data
+ *------------------------------------------------------------------------*/
+static uint32_t
+hid_get_data_sub(const uint8_t *buf, size_t len, struct hid_location *loc,
+ int is_signed)
+{
+ uint32_t hpos = loc->pos;
+ uint32_t hsize = loc->size;
+ uint32_t data;
+ uint32_t rpos;
+ uint8_t n;
+
+ DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
+
+ /* Range check and limit */
+ if (hsize == 0)
+ return (0);
+ if (hsize > 32)
+ hsize = 32;
+
+ /* Get data in a safe way */
+ data = 0;
+ rpos = (hpos / 8);
+ n = (hsize + 7) / 8;
+ rpos += n;
+ while (n--) {
+ rpos--;
+ if (rpos < len)
+ data |= buf[rpos] << (8 * n);
+ }
+
+ /* Correctly shift down data */
+ data = (data >> (hpos % 8));
+ n = 32 - hsize;
+
+ /* Mask and sign extend in one */
+ if (is_signed != 0)
+ data = (int32_t)((int32_t)data << n) >> n;
+ else
+ data = (uint32_t)((uint32_t)data << n) >> n;
+
+ DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
+ loc->pos, loc->size, (long)data);
+ return (data);
+}
+
+int32_t
+hid_get_data(const uint8_t *buf, 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, size_t len, struct hid_location *loc)
+{
+ return (hid_get_data_sub(buf, len, loc, 0));
+}
+
+/*------------------------------------------------------------------------*
+ * hid_put_data
+ *------------------------------------------------------------------------*/
+void
+hid_put_data_unsigned(uint8_t *buf, size_t len,
+ struct hid_location *loc, unsigned int value)
+{
+ uint32_t hpos = loc->pos;
+ uint32_t hsize = loc->size;
+ uint64_t data;
+ uint64_t mask;
+ uint32_t rpos;
+ uint8_t n;
+
+ DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
+
+ /* Range check and limit */
+ if (hsize == 0)
+ return;
+ if (hsize > 32)
+ hsize = 32;
+
+ /* Put data in a safe way */
+ rpos = (hpos / 8);
+ n = (hsize + 7) / 8;
+ data = ((uint64_t)value) << (hpos % 8);
+ mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
+ rpos += n;
+ while (n--) {
+ rpos--;
+ if (rpos < len) {
+ buf[rpos] &= ~(mask >> (8 * n));
+ buf[rpos] |= (data >> (8 * n));
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * hid_is_collection
+ *------------------------------------------------------------------------*/
+int
+hid_is_collection(const void *desc, size_t size, int32_t usage)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+ int err;
+
+ hd = hid_start_parse(desc, size, hid_input);
+ if (hd == NULL)
+ return (0);
+
+ while ((err = hid_get_item(hd, &hi))) {
+ if (hi.kind == hid_collection &&
+ hi.usage == usage)
+ break;
+ }
+ hid_end_parse(hd);
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * calculate HID item resolution. unit/mm for distances, unit/rad for angles
+ *------------------------------------------------------------------------*/
+int32_t
+hid_item_resolution(struct hid_item *hi)
+{
+ /*
+ * hid unit scaling table according to HID Usage Table Review
+ * Request 39 Tbl 17 http://www.usb.org/developers/hidpage/HUTRR39b.pdf
+ */
+ static const int64_t scale[0x10][2] = {
+ [0x00] = { 1, 1 },
+ [0x01] = { 1, 10 },
+ [0x02] = { 1, 100 },
+ [0x03] = { 1, 1000 },
+ [0x04] = { 1, 10000 },
+ [0x05] = { 1, 100000 },
+ [0x06] = { 1, 1000000 },
+ [0x07] = { 1, 10000000 },
+ [0x08] = { 100000000, 1 },
+ [0x09] = { 10000000, 1 },
+ [0x0A] = { 1000000, 1 },
+ [0x0B] = { 100000, 1 },
+ [0x0C] = { 10000, 1 },
+ [0x0D] = { 1000, 1 },
+ [0x0E] = { 100, 1 },
+ [0x0F] = { 10, 1 },
+ };
+ int64_t logical_size;
+ int64_t physical_size;
+ int64_t multiplier;
+ int64_t divisor;
+ int64_t resolution;
+
+ switch (hi->unit) {
+ case HUM_CENTIMETER:
+ multiplier = 1;
+ divisor = 10;
+ break;
+ case HUM_INCH:
+ multiplier = 10;
+ divisor = 254;
+ break;
+ case HUM_RADIAN:
+ multiplier = 1;
+ divisor = 1;
+ break;
+ case HUM_DEGREE:
+ multiplier = 573;
+ divisor = 10;
+ break;
+ default:
+ return (0);
+ }
+
+ if ((hi->logical_maximum <= hi->logical_minimum) ||
+ (hi->physical_maximum <= hi->physical_minimum) ||
+ (hi->unit_exponent < 0) || (hi->unit_exponent >= nitems(scale)))
+ return (0);
+
+ logical_size = (int64_t)hi->logical_maximum -
+ (int64_t)hi->logical_minimum;
+ physical_size = (int64_t)hi->physical_maximum -
+ (int64_t)hi->physical_minimum;
+ /* Round to ceiling */
+ resolution = logical_size * multiplier * scale[hi->unit_exponent][0] /
+ (physical_size * divisor * scale[hi->unit_exponent][1]);
+
+ if (resolution > INT32_MAX)
+ return (0);
+
+ return (resolution);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_is_mouse
+ *
+ * This function will decide if a USB descriptor belongs to a USB mouse.
+ *
+ * Return values:
+ * Zero: Not a USB mouse.
+ * Else: Is a USB mouse.
+ *------------------------------------------------------------------------*/
+int
+hid_is_mouse(const void *d_ptr, uint16_t d_len)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+ int mdepth;
+ int found;
+
+ hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
+ if (hd == NULL)
+ return (0);
+
+ mdepth = 0;
+ found = 0;
+
+ while (hid_get_item(hd, &hi)) {
+ switch (hi.kind) {
+ case hid_collection:
+ if (mdepth != 0)
+ mdepth++;
+ else if (hi.collection == 1 &&
+ hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
+ mdepth++;
+ break;
+ case hid_endcollection:
+ if (mdepth != 0)
+ mdepth--;
+ break;
+ case hid_input:
+ if (mdepth == 0)
+ break;
+ if (hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ found++;
+ if (hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ found++;
+ break;
+ default:
+ break;
+ }
+ }
+ hid_end_parse(hd);
+ return (found);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_is_keyboard
+ *
+ * This function will decide if a USB descriptor belongs to a USB keyboard.
+ *
+ * Return values:
+ * Zero: Not a USB keyboard.
+ * Else: Is a USB keyboard.
+ *------------------------------------------------------------------------*/
+int
+hid_is_keyboard(const void *d_ptr, uint16_t d_len)
+{
+ if (hid_is_collection(d_ptr, d_len,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
+ return (1);
+ return (0);
+}
Index: sys/dev/usb/usb_hid.c
===================================================================
--- sys/dev/usb/usb_hid.c
+++ sys/dev/usb/usb_hid.c
@@ -68,703 +68,6 @@
#include <dev/usb/usb_request.h>
#endif /* USB_GLOBAL_INCLUDE_FILE */
-static void hid_clear_local(struct hid_item *);
-static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize);
-
-#define MAXUSAGE 64
-#define MAXPUSH 4
-#define MAXID 16
-#define MAXLOCCNT 1024
-
-struct hid_pos_data {
- int32_t rid;
- uint32_t pos;
-};
-
-struct hid_data {
- const uint8_t *start;
- const uint8_t *end;
- const uint8_t *p;
- struct hid_item cur[MAXPUSH];
- struct hid_pos_data last_pos[MAXID];
- int32_t usages_min[MAXUSAGE];
- int32_t usages_max[MAXUSAGE];
- int32_t usage_last; /* last seen usage */
- uint32_t loc_size; /* last seen size */
- uint32_t loc_count; /* last seen count */
- uint32_t ncount; /* end usage item count */
- uint32_t icount; /* current usage item count */
- uint8_t kindset; /* we have 5 kinds so 8 bits are enough */
- uint8_t pushlevel; /* current pushlevel */
- uint8_t nusage; /* end "usages_min/max" index */
- uint8_t iusage; /* current "usages_min/max" index */
- uint8_t ousage; /* current "usages_min/max" offset */
- uint8_t susage; /* usage set flags */
-};
-
-/*------------------------------------------------------------------------*
- * hid_clear_local
- *------------------------------------------------------------------------*/
-static void
-hid_clear_local(struct hid_item *c)
-{
-
- c->loc.count = 0;
- c->loc.size = 0;
- c->usage = 0;
- c->usage_minimum = 0;
- c->usage_maximum = 0;
- c->designator_index = 0;
- c->designator_minimum = 0;
- c->designator_maximum = 0;
- c->string_index = 0;
- c->string_minimum = 0;
- c->string_maximum = 0;
- c->set_delimiter = 0;
-}
-
-static void
-hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
-{
- uint8_t i;
-
- /* check for same report ID - optimise */
-
- if (c->report_ID == next_rID)
- return;
-
- /* save current position for current rID */
-
- if (c->report_ID == 0) {
- i = 0;
- } else {
- for (i = 1; i != MAXID; i++) {
- if (s->last_pos[i].rid == c->report_ID)
- break;
- if (s->last_pos[i].rid == 0)
- break;
- }
- }
- if (i != MAXID) {
- s->last_pos[i].rid = c->report_ID;
- s->last_pos[i].pos = c->loc.pos;
- }
-
- /* store next report ID */
-
- c->report_ID = next_rID;
-
- /* lookup last position for next rID */
-
- if (next_rID == 0) {
- i = 0;
- } else {
- for (i = 1; i != MAXID; i++) {
- if (s->last_pos[i].rid == next_rID)
- break;
- if (s->last_pos[i].rid == 0)
- break;
- }
- }
- if (i != MAXID) {
- s->last_pos[i].rid = next_rID;
- c->loc.pos = s->last_pos[i].pos;
- } else {
- DPRINTF("Out of RID entries, position is set to zero!\n");
- c->loc.pos = 0;
- }
-}
-
-/*------------------------------------------------------------------------*
- * hid_start_parse
- *------------------------------------------------------------------------*/
-struct hid_data *
-hid_start_parse(const void *d, usb_size_t len, int kindset)
-{
- struct hid_data *s;
-
- if ((kindset-1) & kindset) {
- DPRINTFN(0, "Only one bit can be "
- "set in the kindset\n");
- return (NULL);
- }
-
- s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
- s->start = s->p = d;
- s->end = ((const uint8_t *)d) + len;
- s->kindset = kindset;
- return (s);
-}
-
-/*------------------------------------------------------------------------*
- * hid_end_parse
- *------------------------------------------------------------------------*/
-void
-hid_end_parse(struct hid_data *s)
-{
- if (s == NULL)
- return;
-
- free(s, M_TEMP);
-}
-
-/*------------------------------------------------------------------------*
- * get byte from HID descriptor
- *------------------------------------------------------------------------*/
-static uint8_t
-hid_get_byte(struct hid_data *s, const uint16_t wSize)
-{
- const uint8_t *ptr;
- uint8_t retval;
-
- ptr = s->p;
-
- /* check if end is reached */
- if (ptr == s->end)
- return (0);
-
- /* read out a byte */
- retval = *ptr;
-
- /* check if data pointer can be advanced by "wSize" bytes */
- if ((s->end - ptr) < wSize)
- ptr = s->end;
- else
- ptr += wSize;
-
- /* update pointer */
- s->p = ptr;
-
- return (retval);
-}
-
-/*------------------------------------------------------------------------*
- * hid_get_item
- *------------------------------------------------------------------------*/
-int
-hid_get_item(struct hid_data *s, struct hid_item *h)
-{
- struct hid_item *c;
- unsigned int bTag, bType, bSize;
- uint32_t oldpos;
- int32_t mask;
- int32_t dval;
-
- if (s == NULL)
- return (0);
-
- c = &s->cur[s->pushlevel];
-
- top:
- /* check if there is an array of items */
- if (s->icount < s->ncount) {
- /* get current usage */
- if (s->iusage < s->nusage) {
- dval = s->usages_min[s->iusage] + s->ousage;
- c->usage = dval;
- s->usage_last = dval;
- if (dval == s->usages_max[s->iusage]) {
- s->iusage ++;
- s->ousage = 0;
- } else {
- s->ousage ++;
- }
- } else {
- DPRINTFN(1, "Using last usage\n");
- dval = s->usage_last;
- }
- s->icount ++;
- /*
- * Only copy HID item, increment position and return
- * if correct kindset!
- */
- if (s->kindset & (1 << c->kind)) {
- *h = *c;
- DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
- h->loc.size, h->loc.count);
- c->loc.pos += c->loc.size * c->loc.count;
- return (1);
- }
- }
-
- /* reset state variables */
- s->icount = 0;
- s->ncount = 0;
- s->iusage = 0;
- s->nusage = 0;
- s->susage = 0;
- s->ousage = 0;
- hid_clear_local(c);
-
- /* get next item */
- while (s->p != s->end) {
-
- bSize = hid_get_byte(s, 1);
- if (bSize == 0xfe) {
- /* long item */
- bSize = hid_get_byte(s, 1);
- bSize |= hid_get_byte(s, 1) << 8;
- bTag = hid_get_byte(s, 1);
- bType = 0xff; /* XXX what should it be */
- } else {
- /* short item */
- bTag = bSize >> 4;
- bType = (bSize >> 2) & 3;
- bSize &= 3;
- if (bSize == 3)
- bSize = 4;
- }
- switch (bSize) {
- case 0:
- dval = 0;
- mask = 0;
- break;
- case 1:
- dval = (int8_t)hid_get_byte(s, 1);
- mask = 0xFF;
- break;
- case 2:
- dval = hid_get_byte(s, 1);
- dval |= hid_get_byte(s, 1) << 8;
- dval = (int16_t)dval;
- mask = 0xFFFF;
- break;
- case 4:
- dval = hid_get_byte(s, 1);
- dval |= hid_get_byte(s, 1) << 8;
- dval |= hid_get_byte(s, 1) << 16;
- dval |= hid_get_byte(s, 1) << 24;
- mask = 0xFFFFFFFF;
- break;
- default:
- dval = hid_get_byte(s, bSize);
- DPRINTFN(0, "bad length %u (data=0x%02x)\n",
- bSize, dval);
- continue;
- }
-
- switch (bType) {
- case 0: /* Main */
- switch (bTag) {
- case 8: /* Input */
- c->kind = hid_input;
- ret:
- c->flags = dval;
- c->loc.count = s->loc_count;
- c->loc.size = s->loc_size;
-
- if (c->flags & HIO_VARIABLE) {
- /* range check usage count */
- if (c->loc.count > MAXLOCCNT) {
- DPRINTFN(0, "Number of "
- "items(%u) truncated to %u\n",
- (unsigned)(c->loc.count),
- MAXLOCCNT);
- s->ncount = MAXLOCCNT;
- } else
- s->ncount = c->loc.count;
-
- /*
- * The "top" loop will return
- * one and one item:
- */
- c->loc.count = 1;
- } else {
- s->ncount = 1;
- }
- goto top;
-
- case 9: /* Output */
- c->kind = hid_output;
- goto ret;
- case 10: /* Collection */
- c->kind = hid_collection;
- c->collection = dval;
- c->collevel++;
- c->usage = s->usage_last;
- *h = *c;
- return (1);
- case 11: /* Feature */
- c->kind = hid_feature;
- goto ret;
- case 12: /* End collection */
- c->kind = hid_endcollection;
- if (c->collevel == 0) {
- DPRINTFN(0, "invalid end collection\n");
- return (0);
- }
- c->collevel--;
- *h = *c;
- return (1);
- default:
- DPRINTFN(0, "Main bTag=%d\n", bTag);
- break;
- }
- break;
- case 1: /* Global */
- switch (bTag) {
- case 0:
- c->_usage_page = dval << 16;
- break;
- case 1:
- c->logical_minimum = dval;
- break;
- case 2:
- c->logical_maximum = dval;
- break;
- case 3:
- c->physical_minimum = dval;
- break;
- case 4:
- c->physical_maximum = dval;
- break;
- case 5:
- c->unit_exponent = dval;
- break;
- case 6:
- c->unit = dval;
- break;
- case 7:
- /* mask because value is unsigned */
- s->loc_size = dval & mask;
- break;
- case 8:
- hid_switch_rid(s, c, dval & mask);
- break;
- case 9:
- /* mask because value is unsigned */
- s->loc_count = dval & mask;
- break;
- case 10: /* Push */
- s->pushlevel ++;
- if (s->pushlevel < MAXPUSH) {
- s->cur[s->pushlevel] = *c;
- /* store size and count */
- c->loc.size = s->loc_size;
- c->loc.count = s->loc_count;
- /* update current item pointer */
- c = &s->cur[s->pushlevel];
- } else {
- DPRINTFN(0, "Cannot push "
- "item @ %d\n", s->pushlevel);
- }
- break;
- case 11: /* Pop */
- s->pushlevel --;
- if (s->pushlevel < MAXPUSH) {
- /* preserve position */
- oldpos = c->loc.pos;
- c = &s->cur[s->pushlevel];
- /* restore size and count */
- s->loc_size = c->loc.size;
- s->loc_count = c->loc.count;
- /* set default item location */
- c->loc.pos = oldpos;
- c->loc.size = 0;
- c->loc.count = 0;
- } else {
- DPRINTFN(0, "Cannot pop "
- "item @ %d\n", s->pushlevel);
- }
- break;
- default:
- DPRINTFN(0, "Global bTag=%d\n", bTag);
- break;
- }
- break;
- case 2: /* Local */
- switch (bTag) {
- case 0:
- if (bSize != 4)
- dval = (dval & mask) | c->_usage_page;
-
- /* set last usage, in case of a collection */
- s->usage_last = dval;
-
- if (s->nusage < MAXUSAGE) {
- s->usages_min[s->nusage] = dval;
- s->usages_max[s->nusage] = dval;
- s->nusage ++;
- } else {
- DPRINTFN(0, "max usage reached\n");
- }
-
- /* clear any pending usage sets */
- s->susage = 0;
- break;
- case 1:
- s->susage |= 1;
-
- if (bSize != 4)
- dval = (dval & mask) | c->_usage_page;
- c->usage_minimum = dval;
-
- goto check_set;
- case 2:
- s->susage |= 2;
-
- if (bSize != 4)
- dval = (dval & mask) | c->_usage_page;
- c->usage_maximum = dval;
-
- check_set:
- if (s->susage != 3)
- break;
-
- /* sanity check */
- if ((s->nusage < MAXUSAGE) &&
- (c->usage_minimum <= c->usage_maximum)) {
- /* add usage range */
- s->usages_min[s->nusage] =
- c->usage_minimum;
- s->usages_max[s->nusage] =
- c->usage_maximum;
- s->nusage ++;
- } else {
- DPRINTFN(0, "Usage set dropped\n");
- }
- s->susage = 0;
- break;
- case 3:
- c->designator_index = dval;
- break;
- case 4:
- c->designator_minimum = dval;
- break;
- case 5:
- c->designator_maximum = dval;
- break;
- case 7:
- c->string_index = dval;
- break;
- case 8:
- c->string_minimum = dval;
- break;
- case 9:
- c->string_maximum = dval;
- break;
- case 10:
- c->set_delimiter = dval;
- break;
- default:
- DPRINTFN(0, "Local bTag=%d\n", bTag);
- break;
- }
- break;
- default:
- DPRINTFN(0, "default bType=%d\n", bType);
- break;
- }
- }
- return (0);
-}
-
-/*------------------------------------------------------------------------*
- * hid_report_size
- *------------------------------------------------------------------------*/
-int
-hid_report_size(const void *buf, usb_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;
- uint8_t any_id;
-
- any_id = 0;
- hpos = 0;
- lpos = 0xFFFFFFFF;
-
- for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
- if (h.kind == k) {
- /* check for ID-byte presence */
- if ((h.report_ID != 0) && !any_id) {
- if (id != NULL)
- *id = h.report_ID;
- any_id = 1;
- }
- /* 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;
- }
- }
- hid_end_parse(d);
-
- /* safety check - can happen in case of currupt descriptors */
- if (lpos > hpos)
- temp = 0;
- else
- temp = hpos - lpos;
-
- /* check for ID byte */
- if (any_id)
- temp += 8;
- else if (id != NULL)
- *id = 0;
-
- /* return length in bytes rounded up */
- return ((temp + 7) / 8);
-}
-
-/*------------------------------------------------------------------------*
- * hid_locate
- *------------------------------------------------------------------------*/
-int
-hid_locate(const void *desc, usb_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;
- struct hid_item h;
-
- for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
- if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
- if (index--)
- continue;
- if (loc != NULL)
- *loc = h.loc;
- if (flags != NULL)
- *flags = h.flags;
- if (id != NULL)
- *id = h.report_ID;
- hid_end_parse(d);
- return (1);
- }
- }
- if (loc != NULL)
- loc->size = 0;
- if (flags != NULL)
- *flags = 0;
- if (id != NULL)
- *id = 0;
- hid_end_parse(d);
- return (0);
-}
-
-/*------------------------------------------------------------------------*
- * hid_get_data
- *------------------------------------------------------------------------*/
-static uint32_t
-hid_get_data_sub(const uint8_t *buf, usb_size_t len, struct hid_location *loc,
- int is_signed)
-{
- uint32_t hpos = loc->pos;
- uint32_t hsize = loc->size;
- uint32_t data;
- uint32_t rpos;
- uint8_t n;
-
- DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
-
- /* Range check and limit */
- if (hsize == 0)
- return (0);
- if (hsize > 32)
- hsize = 32;
-
- /* Get data in a safe way */
- data = 0;
- rpos = (hpos / 8);
- n = (hsize + 7) / 8;
- rpos += n;
- while (n--) {
- rpos--;
- if (rpos < len)
- data |= buf[rpos] << (8 * n);
- }
-
- /* Correctly shift down data */
- data = (data >> (hpos % 8));
- n = 32 - hsize;
-
- /* Mask and sign extend in one */
- if (is_signed != 0)
- data = (int32_t)((int32_t)data << n) >> n;
- else
- data = (uint32_t)((uint32_t)data << n) >> n;
-
- DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
- loc->pos, loc->size, (long)data);
- return (data);
-}
-
-int32_t
-hid_get_data(const uint8_t *buf, usb_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)
-{
- return (hid_get_data_sub(buf, len, loc, 0));
-}
-
-/*------------------------------------------------------------------------*
- * hid_put_data
- *------------------------------------------------------------------------*/
-void
-hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
- struct hid_location *loc, unsigned int value)
-{
- uint32_t hpos = loc->pos;
- uint32_t hsize = loc->size;
- uint64_t data;
- uint64_t mask;
- uint32_t rpos;
- uint8_t n;
-
- DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
-
- /* Range check and limit */
- if (hsize == 0)
- return;
- if (hsize > 32)
- hsize = 32;
-
- /* Put data in a safe way */
- rpos = (hpos / 8);
- n = (hsize + 7) / 8;
- data = ((uint64_t)value) << (hpos % 8);
- mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
- rpos += n;
- while (n--) {
- rpos--;
- if (rpos < len) {
- buf[rpos] &= ~(mask >> (8 * n));
- buf[rpos] |= (data >> (8 * n));
- }
- }
-}
-
-/*------------------------------------------------------------------------*
- * hid_is_collection
- *------------------------------------------------------------------------*/
-int
-hid_is_collection(const void *desc, usb_size_t size, int32_t usage)
-{
- struct hid_data *hd;
- struct hid_item hi;
- int err;
-
- hd = hid_start_parse(desc, size, hid_input);
- if (hd == NULL)
- return (0);
-
- while ((err = hid_get_item(hd, &hi))) {
- if (hi.kind == hid_collection &&
- hi.usage == usage)
- break;
- }
- hid_end_parse(hd);
- return (err);
-}
-
/*------------------------------------------------------------------------*
* hid_get_descriptor_from_usb
*
@@ -775,7 +78,7 @@
* NULL: No more HID descriptors.
* Else: Pointer to HID descriptor.
*------------------------------------------------------------------------*/
-struct usb_hid_descriptor *
+struct hid_descriptor *
hid_get_descriptor_from_usb(struct usb_config_descriptor *cd,
struct usb_interface_descriptor *id)
{
@@ -786,7 +89,7 @@
}
while ((desc = usb_desc_foreach(cd, desc))) {
if ((desc->bDescriptorType == UDESC_HID) &&
- (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
+ (desc->bLength >= HID_DESCRIPTOR_SIZE(0))) {
return (void *)desc;
}
if (desc->bDescriptorType == UDESC_INTERFACE) {
@@ -812,7 +115,7 @@
struct malloc_type *mem, uint8_t iface_index)
{
struct usb_interface *iface = usbd_get_iface(udev, iface_index);
- struct usb_hid_descriptor *hid;
+ struct hid_descriptor *hid;
usb_error_t err;
if ((iface == NULL) || (iface->idesc == NULL)) {
@@ -850,152 +153,3 @@
return (USB_ERR_NORMAL_COMPLETION);
}
-/*------------------------------------------------------------------------*
- * calculate HID item resolution. unit/mm for distances, unit/rad for angles
- *------------------------------------------------------------------------*/
-int32_t
-hid_item_resolution(struct hid_item *hi)
-{
- /*
- * hid unit scaling table according to HID Usage Table Review
- * Request 39 Tbl 17 http://www.usb.org/developers/hidpage/HUTRR39b.pdf
- */
- static const int64_t scale[0x10][2] = {
- [0x00] = { 1, 1 },
- [0x01] = { 1, 10 },
- [0x02] = { 1, 100 },
- [0x03] = { 1, 1000 },
- [0x04] = { 1, 10000 },
- [0x05] = { 1, 100000 },
- [0x06] = { 1, 1000000 },
- [0x07] = { 1, 10000000 },
- [0x08] = { 100000000, 1 },
- [0x09] = { 10000000, 1 },
- [0x0A] = { 1000000, 1 },
- [0x0B] = { 100000, 1 },
- [0x0C] = { 10000, 1 },
- [0x0D] = { 1000, 1 },
- [0x0E] = { 100, 1 },
- [0x0F] = { 10, 1 },
- };
- int64_t logical_size;
- int64_t physical_size;
- int64_t multiplier;
- int64_t divisor;
- int64_t resolution;
-
- switch (hi->unit) {
- case HUM_CENTIMETER:
- multiplier = 1;
- divisor = 10;
- break;
- case HUM_INCH:
- multiplier = 10;
- divisor = 254;
- break;
- case HUM_RADIAN:
- multiplier = 1;
- divisor = 1;
- break;
- case HUM_DEGREE:
- multiplier = 573;
- divisor = 10;
- break;
- default:
- return (0);
- }
-
- if ((hi->logical_maximum <= hi->logical_minimum) ||
- (hi->physical_maximum <= hi->physical_minimum) ||
- (hi->unit_exponent < 0) || (hi->unit_exponent >= nitems(scale)))
- return (0);
-
- logical_size = (int64_t)hi->logical_maximum -
- (int64_t)hi->logical_minimum;
- physical_size = (int64_t)hi->physical_maximum -
- (int64_t)hi->physical_minimum;
- /* Round to ceiling */
- resolution = logical_size * multiplier * scale[hi->unit_exponent][0] /
- (physical_size * divisor * scale[hi->unit_exponent][1]);
-
- if (resolution > INT32_MAX)
- return (0);
-
- return (resolution);
-}
-
-/*------------------------------------------------------------------------*
- * hid_is_mouse
- *
- * This function will decide if a USB descriptor belongs to a USB mouse.
- *
- * Return values:
- * Zero: Not a USB mouse.
- * Else: Is a USB mouse.
- *------------------------------------------------------------------------*/
-int
-hid_is_mouse(const void *d_ptr, uint16_t d_len)
-{
- struct hid_data *hd;
- struct hid_item hi;
- int mdepth;
- int found;
-
- hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
- if (hd == NULL)
- return (0);
-
- mdepth = 0;
- found = 0;
-
- while (hid_get_item(hd, &hi)) {
- switch (hi.kind) {
- case hid_collection:
- if (mdepth != 0)
- mdepth++;
- else if (hi.collection == 1 &&
- hi.usage ==
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
- mdepth++;
- break;
- case hid_endcollection:
- if (mdepth != 0)
- mdepth--;
- break;
- case hid_input:
- if (mdepth == 0)
- break;
- if (hi.usage ==
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
- (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
- found++;
- if (hi.usage ==
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
- (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
- found++;
- break;
- default:
- break;
- }
- }
- hid_end_parse(hd);
- return (found);
-}
-
-/*------------------------------------------------------------------------*
- * hid_is_keyboard
- *
- * This function will decide if a USB descriptor belongs to a USB keyboard.
- *
- * Return values:
- * Zero: Not a USB keyboard.
- * Else: Is a USB keyboard.
- *------------------------------------------------------------------------*/
-int
-hid_is_keyboard(const void *d_ptr, uint16_t d_len)
-{
- if (hid_is_collection(d_ptr, d_len,
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
- return (1);
- return (0);
-}
Index: sys/dev/usb/usbhid.h
===================================================================
--- sys/dev/usb/usbhid.h
+++ sys/dev/usb/usbhid.h
@@ -35,241 +35,18 @@
#include <dev/usb/usb_endian.h>
#endif
-#define UR_GET_HID_DESCRIPTOR 0x06
-#define UDESC_HID 0x21
-#define UDESC_REPORT 0x22
-#define UDESC_PHYSICAL 0x23
-#define UR_SET_HID_DESCRIPTOR 0x07
-#define UR_GET_REPORT 0x01
-#define UR_SET_REPORT 0x09
-#define UR_GET_IDLE 0x02
-#define UR_SET_IDLE 0x0a
-#define UR_GET_PROTOCOL 0x03
-#define UR_SET_PROTOCOL 0x0b
-
-struct usb_hid_descriptor {
- uByte bLength;
- uByte bDescriptorType;
- uWord bcdHID;
- uByte bCountryCode;
- uByte bNumDescriptors;
- struct {
- uByte bDescriptorType;
- uWord wDescriptorLength;
- } descrs[1];
-} __packed;
-
-#define USB_HID_DESCRIPTOR_SIZE(n) (9+((n)*3))
-
-/* Usage pages */
-#define HUP_UNDEFINED 0x0000
-#define HUP_GENERIC_DESKTOP 0x0001
-#define HUP_SIMULATION 0x0002
-#define HUP_VR_CONTROLS 0x0003
-#define HUP_SPORTS_CONTROLS 0x0004
-#define HUP_GAMING_CONTROLS 0x0005
-#define HUP_KEYBOARD 0x0007
-#define HUP_LEDS 0x0008
-#define HUP_BUTTON 0x0009
-#define HUP_ORDINALS 0x000a
-#define HUP_TELEPHONY 0x000b
-#define HUP_CONSUMER 0x000c
-#define HUP_DIGITIZERS 0x000d
-#define HUP_PHYSICAL_IFACE 0x000e
-#define HUP_UNICODE 0x0010
-#define HUP_ALPHANUM_DISPLAY 0x0014
-#define HUP_MONITOR 0x0080
-#define HUP_MONITOR_ENUM_VAL 0x0081
-#define HUP_VESA_VC 0x0082
-#define HUP_VESA_CMD 0x0083
-#define HUP_POWER 0x0084
-#define HUP_BATTERY_SYSTEM 0x0085
-#define HUP_BARCODE_SCANNER 0x008b
-#define HUP_SCALE 0x008c
-#define HUP_CAMERA_CONTROL 0x0090
-#define HUP_ARCADE 0x0091
-#define HUP_MICROSOFT 0xff00
-
-/* Usages, generic desktop */
-#define HUG_POINTER 0x0001
-#define HUG_MOUSE 0x0002
-#define HUG_JOYSTICK 0x0004
-#define HUG_GAME_PAD 0x0005
-#define HUG_KEYBOARD 0x0006
-#define HUG_KEYPAD 0x0007
-#define HUG_X 0x0030
-#define HUG_Y 0x0031
-#define HUG_Z 0x0032
-#define HUG_RX 0x0033
-#define HUG_RY 0x0034
-#define HUG_RZ 0x0035
-#define HUG_SLIDER 0x0036
-#define HUG_DIAL 0x0037
-#define HUG_WHEEL 0x0038
-#define HUG_HAT_SWITCH 0x0039
-#define HUG_COUNTED_BUFFER 0x003a
-#define HUG_BYTE_COUNT 0x003b
-#define HUG_MOTION_WAKEUP 0x003c
-#define HUG_VX 0x0040
-#define HUG_VY 0x0041
-#define HUG_VZ 0x0042
-#define HUG_VBRX 0x0043
-#define HUG_VBRY 0x0044
-#define HUG_VBRZ 0x0045
-#define HUG_VNO 0x0046
-#define HUG_TWHEEL 0x0048 /* M$ Wireless Intellimouse Wheel */
-#define HUG_SYSTEM_CONTROL 0x0080
-#define HUG_SYSTEM_POWER_DOWN 0x0081
-#define HUG_SYSTEM_SLEEP 0x0082
-#define HUG_SYSTEM_WAKEUP 0x0083
-#define HUG_SYSTEM_CONTEXT_MENU 0x0084
-#define HUG_SYSTEM_MAIN_MENU 0x0085
-#define HUG_SYSTEM_APP_MENU 0x0086
-#define HUG_SYSTEM_MENU_HELP 0x0087
-#define HUG_SYSTEM_MENU_EXIT 0x0088
-#define HUG_SYSTEM_MENU_SELECT 0x0089
-#define HUG_SYSTEM_MENU_RIGHT 0x008a
-#define HUG_SYSTEM_MENU_LEFT 0x008b
-#define HUG_SYSTEM_MENU_UP 0x008c
-#define HUG_SYSTEM_MENU_DOWN 0x008d
-#define HUG_APPLE_EJECT 0x00b8
-
-/* Usages Digitizers */
-#define HUD_UNDEFINED 0x0000
-#define HUD_DIGITIZER 0x0001
-#define HUD_PEN 0x0002
-#define HUD_TOUCHSCREEN 0x0004
-#define HUD_TOUCHPAD 0x0005
-#define HUD_CONFIG 0x000e
-#define HUD_FINGER 0x0022
-#define HUD_TIP_PRESSURE 0x0030
-#define HUD_BARREL_PRESSURE 0x0031
-#define HUD_IN_RANGE 0x0032
-#define HUD_TOUCH 0x0033
-#define HUD_UNTOUCH 0x0034
-#define HUD_TAP 0x0035
-#define HUD_QUALITY 0x0036
-#define HUD_DATA_VALID 0x0037
-#define HUD_TRANSDUCER_INDEX 0x0038
-#define HUD_TABLET_FKEYS 0x0039
-#define HUD_PROGRAM_CHANGE_KEYS 0x003a
-#define HUD_BATTERY_STRENGTH 0x003b
-#define HUD_INVERT 0x003c
-#define HUD_X_TILT 0x003d
-#define HUD_Y_TILT 0x003e
-#define HUD_AZIMUTH 0x003f
-#define HUD_ALTITUDE 0x0040
-#define HUD_TWIST 0x0041
-#define HUD_TIP_SWITCH 0x0042
-#define HUD_SEC_TIP_SWITCH 0x0043
-#define HUD_BARREL_SWITCH 0x0044
-#define HUD_ERASER 0x0045
-#define HUD_TABLET_PICK 0x0046
-#define HUD_CONFIDENCE 0x0047
-#define HUD_WIDTH 0x0048
-#define HUD_HEIGHT 0x0049
-#define HUD_CONTACTID 0x0051
-#define HUD_INPUT_MODE 0x0052
-#define HUD_DEVICE_INDEX 0x0053
-#define HUD_CONTACTCOUNT 0x0054
-#define HUD_CONTACT_MAX 0x0055
-#define HUD_SCAN_TIME 0x0056
-#define HUD_BUTTON_TYPE 0x0059
-
-/* Usages, Consumer */
-#define HUC_AC_PAN 0x0238
-
-#define HID_USAGE2(p,u) (((p) << 16) | (u))
-
-#define UHID_INPUT_REPORT 0x01
-#define UHID_OUTPUT_REPORT 0x02
-#define UHID_FEATURE_REPORT 0x03
-
-/* Bits in the input/output/feature items */
-#define HIO_CONST 0x001
-#define HIO_VARIABLE 0x002
-#define HIO_RELATIVE 0x004
-#define HIO_WRAP 0x008
-#define HIO_NONLINEAR 0x010
-#define HIO_NOPREF 0x020
-#define HIO_NULLSTATE 0x040
-#define HIO_VOLATILE 0x080
-#define HIO_BUFBYTES 0x100
-
-/* Units of Measure */
-#define HUM_CENTIMETER 0x11
-#define HUM_RADIAN 0x12
-#define HUM_INCH 0x13
-#define HUM_DEGREE 0x14
+#include <dev/usb/hid.h>
#ifdef _KERNEL
struct usb_config_descriptor;
-enum hid_kind {
- hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
-};
-
-struct hid_location {
- uint32_t size;
- uint32_t count;
- uint32_t pos;
-};
-
-struct hid_item {
- /* Global */
- int32_t _usage_page;
- int32_t logical_minimum;
- int32_t logical_maximum;
- int32_t physical_minimum;
- int32_t physical_maximum;
- int32_t unit_exponent;
- int32_t unit;
- int32_t report_ID;
- /* Local */
- int32_t usage;
- int32_t usage_minimum;
- int32_t usage_maximum;
- int32_t designator_index;
- int32_t designator_minimum;
- int32_t designator_maximum;
- int32_t string_index;
- int32_t string_minimum;
- int32_t string_maximum;
- int32_t set_delimiter;
- /* Misc */
- int32_t collection;
- int collevel;
- enum hid_kind kind;
- uint32_t flags;
- /* Location */
- struct hid_location loc;
-};
-
/* prototypes from "usb_hid.c" */
-struct hid_data *hid_start_parse(const void *d, usb_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,
- uint8_t *id);
-int hid_locate(const void *desc, usb_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,
- struct hid_location *loc);
-uint32_t hid_get_data_unsigned(const uint8_t *buf, usb_size_t len,
- struct hid_location *loc);
-void hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
- struct hid_location *loc, unsigned int value);
-int hid_is_collection(const void *desc, usb_size_t size, int32_t usage);
-struct usb_hid_descriptor *hid_get_descriptor_from_usb(
+struct hid_descriptor *hid_get_descriptor_from_usb(
struct usb_config_descriptor *cd,
struct usb_interface_descriptor *id);
usb_error_t usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
void **descp, uint16_t *sizep, struct malloc_type *mem,
uint8_t iface_index);
-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);
#endif /* _KERNEL */
#endif /* _USB_HID_H_ */
Index: sys/modules/acpi/acpi_iichid/Makefile
===================================================================
--- /dev/null
+++ sys/modules/acpi/acpi_iichid/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/dev/iicbus/input
+KMOD = acpi_iichid
+SRCS = acpi_iichid.c device_if.h bus_if.h iicbus_if.h vnode_if.h opt_acpi.h acpi_if.h
+
+.include <bsd.kmod.mk>
Index: sys/modules/i2c/Makefile
===================================================================
--- sys/modules/i2c/Makefile
+++ sys/modules/i2c/Makefile
@@ -12,6 +12,7 @@
iic \
iicbb \
iicbus \
+ iichid \
iicsmb \
isl \
isl12xx \
Index: sys/modules/i2c/iichid/Makefile
===================================================================
--- /dev/null
+++ sys/modules/i2c/iichid/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/dev/iicbus/input
+KMOD = iichid
+SRCS = iichid.c device_if.h bus_if.h iicbus_if.h vnode_if.h
+
+.include <bsd.kmod.mk>
Index: sys/modules/usb/ukbd/Makefile
===================================================================
--- sys/modules/usb/ukbd/Makefile
+++ sys/modules/usb/ukbd/Makefile
@@ -32,6 +32,6 @@
KMOD= ukbd
SRCS= opt_bus.h opt_evdev.h opt_kbd.h opt_ukbd.h opt_usb.h \
device_if.h bus_if.h usb_if.h usbdevs.h \
- ukbd.c
+ ../hid.c ukbd.c
.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 12, 2:01 PM (4 m, 35 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17120677
Default Alt Text
D16698.id48366.diff (98 KB)
Attached To
Mode
D16698: First draft HID over I2C support (Mouse only)
Attached
Detach File
Event Timeline
Log In to Comment