Page MenuHomeFreeBSD

D16698.id48366.diff
No OneTemporary

D16698.id48366.diff

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

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)

Event Timeline