1afd590d9SVladimir Kondratyev /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3afd590d9SVladimir Kondratyev * 4afd590d9SVladimir Kondratyev * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org> 5afd590d9SVladimir Kondratyev * 6afd590d9SVladimir Kondratyev * Redistribution and use in source and binary forms, with or without 7afd590d9SVladimir Kondratyev * modification, are permitted provided that the following conditions 8afd590d9SVladimir Kondratyev * are met: 9afd590d9SVladimir Kondratyev * 1. Redistributions of source code must retain the above copyright 10afd590d9SVladimir Kondratyev * notice, this list of conditions and the following disclaimer. 11afd590d9SVladimir Kondratyev * 2. Redistributions in binary form must reproduce the above copyright 12afd590d9SVladimir Kondratyev * notice, this list of conditions and the following disclaimer in the 13afd590d9SVladimir Kondratyev * documentation and/or other materials provided with the distribution. 14afd590d9SVladimir Kondratyev * 15afd590d9SVladimir Kondratyev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16afd590d9SVladimir Kondratyev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17afd590d9SVladimir Kondratyev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18afd590d9SVladimir Kondratyev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19afd590d9SVladimir Kondratyev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20afd590d9SVladimir Kondratyev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21afd590d9SVladimir Kondratyev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22afd590d9SVladimir Kondratyev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23afd590d9SVladimir Kondratyev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24afd590d9SVladimir Kondratyev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25afd590d9SVladimir Kondratyev * SUCH DAMAGE. 26afd590d9SVladimir Kondratyev */ 27afd590d9SVladimir Kondratyev 28afd590d9SVladimir Kondratyev #include <sys/cdefs.h> 29afd590d9SVladimir Kondratyev /* 30afd590d9SVladimir Kondratyev * HID spec: https://www.usb.org/sites/default/files/documents/hid1_11.pdf 31afd590d9SVladimir Kondratyev */ 32afd590d9SVladimir Kondratyev 333e954a8bSVladimir Kondratyev #include "opt_hid.h" 343e954a8bSVladimir Kondratyev 35afd590d9SVladimir Kondratyev #include <sys/param.h> 36afd590d9SVladimir Kondratyev #include <sys/bus.h> 37afd590d9SVladimir Kondratyev #include <sys/kernel.h> 38afd590d9SVladimir Kondratyev #include <sys/malloc.h> 39afd590d9SVladimir Kondratyev #include <sys/module.h> 40afd590d9SVladimir Kondratyev #include <sys/sysctl.h> 41afd590d9SVladimir Kondratyev 42afd590d9SVladimir Kondratyev #include <dev/evdev/input.h> 43afd590d9SVladimir Kondratyev #include <dev/evdev/evdev.h> 44afd590d9SVladimir Kondratyev 45afd590d9SVladimir Kondratyev #include <dev/hid/hid.h> 46afd590d9SVladimir Kondratyev #include <dev/hid/hidbus.h> 47afd590d9SVladimir Kondratyev #include <dev/hid/hidmap.h> 48afd590d9SVladimir Kondratyev #include <dev/hid/hidquirk.h> 49afd590d9SVladimir Kondratyev #include <dev/hid/hidrdesc.h> 50afd590d9SVladimir Kondratyev 51afd590d9SVladimir Kondratyev static const uint8_t hms_boot_desc[] = { HID_MOUSE_BOOTPROTO_DESCR() }; 52afd590d9SVladimir Kondratyev 53afd590d9SVladimir Kondratyev enum { 54afd590d9SVladimir Kondratyev HMS_REL_X, 55afd590d9SVladimir Kondratyev HMS_REL_Y, 56afd590d9SVladimir Kondratyev HMS_REL_Z, 57afd590d9SVladimir Kondratyev HMS_ABS_X, 58afd590d9SVladimir Kondratyev HMS_ABS_Y, 59afd590d9SVladimir Kondratyev HMS_ABS_Z, 60afd590d9SVladimir Kondratyev HMS_HWHEEL, 61afd590d9SVladimir Kondratyev HMS_BTN, 62afd590d9SVladimir Kondratyev HMS_FINAL_CB, 63afd590d9SVladimir Kondratyev }; 64afd590d9SVladimir Kondratyev 65afd590d9SVladimir Kondratyev static hidmap_cb_t hms_final_cb; 663e954a8bSVladimir Kondratyev #ifdef IICHID_SAMPLING 673e954a8bSVladimir Kondratyev static hid_intr_t hms_intr; 683e954a8bSVladimir Kondratyev #endif 69afd590d9SVladimir Kondratyev 70afd590d9SVladimir Kondratyev #define HMS_MAP_BUT_RG(usage_from, usage_to, code) \ 71afd590d9SVladimir Kondratyev { HIDMAP_KEY_RANGE(HUP_BUTTON, usage_from, usage_to, code) } 72afd590d9SVladimir Kondratyev #define HMS_MAP_BUT_MS(usage, code) \ 73afd590d9SVladimir Kondratyev { HIDMAP_KEY(HUP_MICROSOFT, usage, code) } 74afd590d9SVladimir Kondratyev #define HMS_MAP_ABS(usage, code) \ 75afd590d9SVladimir Kondratyev { HIDMAP_ABS(HUP_GENERIC_DESKTOP, usage, code) } 76afd590d9SVladimir Kondratyev #define HMS_MAP_REL(usage, code) \ 77afd590d9SVladimir Kondratyev { HIDMAP_REL(HUP_GENERIC_DESKTOP, usage, code) } 78afd590d9SVladimir Kondratyev #define HMS_MAP_REL_REV(usage, code) \ 79afd590d9SVladimir Kondratyev { HIDMAP_REL(HUP_GENERIC_DESKTOP, usage, code), .invert_value = true } 80afd590d9SVladimir Kondratyev #define HMS_MAP_REL_CN(usage, code) \ 81afd590d9SVladimir Kondratyev { HIDMAP_REL(HUP_CONSUMER, usage, code) } 82afd590d9SVladimir Kondratyev #define HMS_FINAL_CB(cb) \ 83afd590d9SVladimir Kondratyev { HIDMAP_FINAL_CB(&cb) } 84afd590d9SVladimir Kondratyev 85afd590d9SVladimir Kondratyev static const struct hidmap_item hms_map[] = { 86afd590d9SVladimir Kondratyev [HMS_REL_X] = HMS_MAP_REL(HUG_X, REL_X), 87afd590d9SVladimir Kondratyev [HMS_REL_Y] = HMS_MAP_REL(HUG_Y, REL_Y), 88afd590d9SVladimir Kondratyev [HMS_REL_Z] = HMS_MAP_REL(HUG_Z, REL_Z), 89afd590d9SVladimir Kondratyev [HMS_ABS_X] = HMS_MAP_ABS(HUG_X, ABS_X), 90afd590d9SVladimir Kondratyev [HMS_ABS_Y] = HMS_MAP_ABS(HUG_Y, ABS_Y), 91afd590d9SVladimir Kondratyev [HMS_ABS_Z] = HMS_MAP_ABS(HUG_Z, ABS_Z), 92afd590d9SVladimir Kondratyev [HMS_HWHEEL] = HMS_MAP_REL_CN(HUC_AC_PAN, REL_HWHEEL), 93afd590d9SVladimir Kondratyev [HMS_BTN] = HMS_MAP_BUT_RG(1, 16, BTN_MOUSE), 94afd590d9SVladimir Kondratyev [HMS_FINAL_CB] = HMS_FINAL_CB(hms_final_cb), 95afd590d9SVladimir Kondratyev }; 96afd590d9SVladimir Kondratyev 97afd590d9SVladimir Kondratyev static const struct hidmap_item hms_map_wheel[] = { 98afd590d9SVladimir Kondratyev HMS_MAP_REL(HUG_WHEEL, REL_WHEEL), 99afd590d9SVladimir Kondratyev }; 100afd590d9SVladimir Kondratyev static const struct hidmap_item hms_map_wheel_rev[] = { 101afd590d9SVladimir Kondratyev HMS_MAP_REL_REV(HUG_WHEEL, REL_WHEEL), 102afd590d9SVladimir Kondratyev }; 103afd590d9SVladimir Kondratyev 1040661cf74SVladimir Kondratyev static const struct hidmap_item hms_map_kensington_slimblade[] = { 1050661cf74SVladimir Kondratyev HMS_MAP_BUT_MS(1, BTN_RIGHT), 1060661cf74SVladimir Kondratyev HMS_MAP_BUT_MS(2, BTN_MIDDLE), 1070661cf74SVladimir Kondratyev }; 1080661cf74SVladimir Kondratyev 109afd590d9SVladimir Kondratyev /* A match on these entries will load hms */ 110afd590d9SVladimir Kondratyev static const struct hid_device_id hms_devs[] = { 1119b78891dSVladimir Kondratyev { HID_TLC(HUP_GENERIC_DESKTOP, HUG_POINTER) }, 112afd590d9SVladimir Kondratyev { HID_TLC(HUP_GENERIC_DESKTOP, HUG_MOUSE) }, 113afd590d9SVladimir Kondratyev }; 114afd590d9SVladimir Kondratyev 115afd590d9SVladimir Kondratyev struct hms_softc { 116afd590d9SVladimir Kondratyev struct hidmap hm; 117afd590d9SVladimir Kondratyev HIDMAP_CAPS(caps, hms_map); 1183e954a8bSVladimir Kondratyev #ifdef IICHID_SAMPLING 1193e954a8bSVladimir Kondratyev bool iichid_sampling; 1203e954a8bSVladimir Kondratyev void *last_ir; 1213e954a8bSVladimir Kondratyev hid_size_t last_irsize; 1223e954a8bSVladimir Kondratyev hid_size_t isize; 1233e954a8bSVladimir Kondratyev uint32_t drift_cnt; 1243e954a8bSVladimir Kondratyev uint32_t drift_thresh; 125*c0a5ee95SEdward Tomasz Napierala struct hid_location wheel_loc; 1263e954a8bSVladimir Kondratyev #endif 127afd590d9SVladimir Kondratyev }; 128afd590d9SVladimir Kondratyev 1293e954a8bSVladimir Kondratyev #ifdef IICHID_SAMPLING 1303e954a8bSVladimir Kondratyev static void 1313e954a8bSVladimir Kondratyev hms_intr(void *context, void *buf, hid_size_t len) 1323e954a8bSVladimir Kondratyev { 1333e954a8bSVladimir Kondratyev struct hidmap *hm = context; 1343e954a8bSVladimir Kondratyev struct hms_softc *sc = device_get_softc(hm->dev); 135*c0a5ee95SEdward Tomasz Napierala int32_t wheel; 1363e954a8bSVladimir Kondratyev 1373e954a8bSVladimir Kondratyev if (len > sc->isize) 1383e954a8bSVladimir Kondratyev len = sc->isize; 1393e954a8bSVladimir Kondratyev 1403e954a8bSVladimir Kondratyev /* 1413e954a8bSVladimir Kondratyev * Many I2C "compatibility" mouse devices found on touchpads continue 1423e954a8bSVladimir Kondratyev * to return last report data in sampling mode even after touch has 1433e954a8bSVladimir Kondratyev * been ended. That results in cursor drift. Filter out such a 1443e954a8bSVladimir Kondratyev * reports through comparing with previous one. 145*c0a5ee95SEdward Tomasz Napierala * 146*c0a5ee95SEdward Tomasz Napierala * Except this results in dropping consecutive mouse wheel events, 147*c0a5ee95SEdward Tomasz Napierala * because differently from cursor movement they always move by the 148*c0a5ee95SEdward Tomasz Napierala * same amount. So, don't do it when there's mouse wheel movement. 1493e954a8bSVladimir Kondratyev */ 150*c0a5ee95SEdward Tomasz Napierala if (sc->wheel_loc.size != 0) 151*c0a5ee95SEdward Tomasz Napierala wheel = hid_get_data(buf, len, &sc->wheel_loc); 152*c0a5ee95SEdward Tomasz Napierala else 153*c0a5ee95SEdward Tomasz Napierala wheel = 0; 154*c0a5ee95SEdward Tomasz Napierala 155*c0a5ee95SEdward Tomasz Napierala if (len == sc->last_irsize && memcmp(buf, sc->last_ir, len) == 0 && 156*c0a5ee95SEdward Tomasz Napierala wheel == 0) { 1573e954a8bSVladimir Kondratyev sc->drift_cnt++; 1583e954a8bSVladimir Kondratyev if (sc->drift_thresh != 0 && sc->drift_cnt >= sc->drift_thresh) 1593e954a8bSVladimir Kondratyev return; 1603e954a8bSVladimir Kondratyev } else { 1613e954a8bSVladimir Kondratyev sc->drift_cnt = 0; 1623e954a8bSVladimir Kondratyev sc->last_irsize = len; 1633e954a8bSVladimir Kondratyev bcopy(buf, sc->last_ir, len); 1643e954a8bSVladimir Kondratyev } 1653e954a8bSVladimir Kondratyev 1663e954a8bSVladimir Kondratyev hidmap_intr(context, buf, len); 1673e954a8bSVladimir Kondratyev } 1683e954a8bSVladimir Kondratyev #endif 1693e954a8bSVladimir Kondratyev 170afd590d9SVladimir Kondratyev static int 171afd590d9SVladimir Kondratyev hms_final_cb(HIDMAP_CB_ARGS) 172afd590d9SVladimir Kondratyev { 173afd590d9SVladimir Kondratyev struct hms_softc *sc = HIDMAP_CB_GET_SOFTC(); 174afd590d9SVladimir Kondratyev struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV(); 175afd590d9SVladimir Kondratyev 176afd590d9SVladimir Kondratyev if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING) { 177afd590d9SVladimir Kondratyev if (hidmap_test_cap(sc->caps, HMS_ABS_X) || 178afd590d9SVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_ABS_Y)) 179afd590d9SVladimir Kondratyev evdev_support_prop(evdev, INPUT_PROP_DIRECT); 180afd590d9SVladimir Kondratyev else 181afd590d9SVladimir Kondratyev evdev_support_prop(evdev, INPUT_PROP_POINTER); 1823e954a8bSVladimir Kondratyev #ifdef IICHID_SAMPLING 1833e954a8bSVladimir Kondratyev /* Overload interrupt handler to skip identical reports */ 1843e954a8bSVladimir Kondratyev if (sc->iichid_sampling) 1853e954a8bSVladimir Kondratyev hidbus_set_intr(sc->hm.dev, hms_intr, &sc->hm); 1863e954a8bSVladimir Kondratyev #endif 187afd590d9SVladimir Kondratyev } 188afd590d9SVladimir Kondratyev 189afd590d9SVladimir Kondratyev /* Do not execute callback at interrupt handler and detach */ 190afd590d9SVladimir Kondratyev return (ENOSYS); 191afd590d9SVladimir Kondratyev } 192afd590d9SVladimir Kondratyev 193afd590d9SVladimir Kondratyev static void 194afd590d9SVladimir Kondratyev hms_identify(driver_t *driver, device_t parent) 195afd590d9SVladimir Kondratyev { 196afd590d9SVladimir Kondratyev const struct hid_device_info *hw = hid_get_device_info(parent); 197afd590d9SVladimir Kondratyev void *d_ptr; 198afd590d9SVladimir Kondratyev hid_size_t d_len; 199afd590d9SVladimir Kondratyev int error; 200afd590d9SVladimir Kondratyev 201afd590d9SVladimir Kondratyev /* 202afd590d9SVladimir Kondratyev * If device claimed boot protocol support but do not have report 203afd590d9SVladimir Kondratyev * descriptor, load one defined in "Appendix B.2" of HID1_11.pdf 204afd590d9SVladimir Kondratyev */ 205afd590d9SVladimir Kondratyev error = hid_get_report_descr(parent, &d_ptr, &d_len); 206afd590d9SVladimir Kondratyev if ((error != 0 && hid_test_quirk(hw, HQ_HAS_MS_BOOTPROTO)) || 207afd590d9SVladimir Kondratyev (error == 0 && hid_test_quirk(hw, HQ_MS_BOOTPROTO) && 208afd590d9SVladimir Kondratyev hid_is_mouse(d_ptr, d_len))) 209afd590d9SVladimir Kondratyev (void)hid_set_report_descr(parent, hms_boot_desc, 210afd590d9SVladimir Kondratyev sizeof(hms_boot_desc)); 211afd590d9SVladimir Kondratyev } 212afd590d9SVladimir Kondratyev 213afd590d9SVladimir Kondratyev static int 214afd590d9SVladimir Kondratyev hms_probe(device_t dev) 215afd590d9SVladimir Kondratyev { 216afd590d9SVladimir Kondratyev struct hms_softc *sc = device_get_softc(dev); 217afd590d9SVladimir Kondratyev int error; 218afd590d9SVladimir Kondratyev 219afd590d9SVladimir Kondratyev error = HIDBUS_LOOKUP_DRIVER_INFO(dev, hms_devs); 220afd590d9SVladimir Kondratyev if (error != 0) 221afd590d9SVladimir Kondratyev return (error); 222afd590d9SVladimir Kondratyev 223afd590d9SVladimir Kondratyev hidmap_set_dev(&sc->hm, dev); 224afd590d9SVladimir Kondratyev 225afd590d9SVladimir Kondratyev /* Check if report descriptor belongs to mouse */ 226afd590d9SVladimir Kondratyev error = HIDMAP_ADD_MAP(&sc->hm, hms_map, sc->caps); 227afd590d9SVladimir Kondratyev if (error != 0) 228afd590d9SVladimir Kondratyev return (error); 229afd590d9SVladimir Kondratyev 230afd590d9SVladimir Kondratyev /* There should be at least one X or Y axis */ 231afd590d9SVladimir Kondratyev if (!hidmap_test_cap(sc->caps, HMS_REL_X) && 2326f7b5d5dSYuri !hidmap_test_cap(sc->caps, HMS_REL_Y) && 233afd590d9SVladimir Kondratyev !hidmap_test_cap(sc->caps, HMS_ABS_X) && 234afd590d9SVladimir Kondratyev !hidmap_test_cap(sc->caps, HMS_ABS_Y)) 235afd590d9SVladimir Kondratyev return (ENXIO); 236afd590d9SVladimir Kondratyev 237afd590d9SVladimir Kondratyev if (hidmap_test_cap(sc->caps, HMS_ABS_X) || 238afd590d9SVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_ABS_Y)) 239afd590d9SVladimir Kondratyev hidbus_set_desc(dev, "Tablet"); 240afd590d9SVladimir Kondratyev else 241afd590d9SVladimir Kondratyev hidbus_set_desc(dev, "Mouse"); 242afd590d9SVladimir Kondratyev 24342e2a173SVladimir Kondratyev return (BUS_PROBE_GENERIC); 244afd590d9SVladimir Kondratyev } 245afd590d9SVladimir Kondratyev 246afd590d9SVladimir Kondratyev static int 247afd590d9SVladimir Kondratyev hms_attach(device_t dev) 248afd590d9SVladimir Kondratyev { 249afd590d9SVladimir Kondratyev struct hms_softc *sc = device_get_softc(dev); 250afd590d9SVladimir Kondratyev const struct hid_device_info *hw = hid_get_device_info(dev); 251afd590d9SVladimir Kondratyev struct hidmap_hid_item *hi; 252afd590d9SVladimir Kondratyev HIDMAP_CAPS(cap_wheel, hms_map_wheel); 253afd590d9SVladimir Kondratyev void *d_ptr; 254afd590d9SVladimir Kondratyev hid_size_t d_len; 255afd590d9SVladimir Kondratyev bool set_report_proto; 256afd590d9SVladimir Kondratyev int error, nbuttons = 0; 257afd590d9SVladimir Kondratyev 258afd590d9SVladimir Kondratyev /* 259afd590d9SVladimir Kondratyev * Set the report (non-boot) protocol if report descriptor has not been 260afd590d9SVladimir Kondratyev * overloaded with boot protocol report descriptor. 261afd590d9SVladimir Kondratyev * 262afd590d9SVladimir Kondratyev * Mice without boot protocol support may choose not to implement 263afd590d9SVladimir Kondratyev * Set_Protocol at all; Ignore any error. 264afd590d9SVladimir Kondratyev */ 265afd590d9SVladimir Kondratyev error = hid_get_report_descr(dev, &d_ptr, &d_len); 266afd590d9SVladimir Kondratyev set_report_proto = !(error == 0 && d_len == sizeof(hms_boot_desc) && 267afd590d9SVladimir Kondratyev memcmp(d_ptr, hms_boot_desc, sizeof(hms_boot_desc)) == 0); 268afd590d9SVladimir Kondratyev (void)hid_set_protocol(dev, set_report_proto ? 1 : 0); 269afd590d9SVladimir Kondratyev 270afd590d9SVladimir Kondratyev if (hid_test_quirk(hw, HQ_MS_REVZ)) 271afd590d9SVladimir Kondratyev HIDMAP_ADD_MAP(&sc->hm, hms_map_wheel_rev, cap_wheel); 272afd590d9SVladimir Kondratyev else 273afd590d9SVladimir Kondratyev HIDMAP_ADD_MAP(&sc->hm, hms_map_wheel, cap_wheel); 274afd590d9SVladimir Kondratyev 2750661cf74SVladimir Kondratyev if (hid_test_quirk(hw, HQ_MS_VENDOR_BTN)) 2760661cf74SVladimir Kondratyev HIDMAP_ADD_MAP(&sc->hm, hms_map_kensington_slimblade, NULL); 2770661cf74SVladimir Kondratyev 2783e954a8bSVladimir Kondratyev #ifdef IICHID_SAMPLING 2793e954a8bSVladimir Kondratyev if (hid_test_quirk(hw, HQ_IICHID_SAMPLING) && 2803e954a8bSVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_REL_X) && 2813e954a8bSVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_REL_Y)) { 2823e954a8bSVladimir Kondratyev sc->iichid_sampling = true; 2833e954a8bSVladimir Kondratyev sc->isize = hid_report_size_max(d_ptr, d_len, hid_input, NULL); 2843e954a8bSVladimir Kondratyev sc->last_ir = malloc(sc->isize, M_DEVBUF, M_WAITOK | M_ZERO); 2853e954a8bSVladimir Kondratyev sc->drift_thresh = 2; 2863e954a8bSVladimir Kondratyev SYSCTL_ADD_U32(device_get_sysctl_ctx(dev), 2873e954a8bSVladimir Kondratyev SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 2883e954a8bSVladimir Kondratyev "drift_thresh", CTLFLAG_RW, &sc->drift_thresh, 0, 2894b4850aeSGordon Bergling "drift detection threshold"); 2903e954a8bSVladimir Kondratyev } 2913e954a8bSVladimir Kondratyev #endif 2923e954a8bSVladimir Kondratyev 293afd590d9SVladimir Kondratyev error = hidmap_attach(&sc->hm); 294afd590d9SVladimir Kondratyev if (error) 295afd590d9SVladimir Kondratyev return (error); 296afd590d9SVladimir Kondratyev 297afd590d9SVladimir Kondratyev /* Count number of input usages of variable type mapped to buttons */ 298afd590d9SVladimir Kondratyev for (hi = sc->hm.hid_items; 299afd590d9SVladimir Kondratyev hi < sc->hm.hid_items + sc->hm.nhid_items; 300*c0a5ee95SEdward Tomasz Napierala hi++) { 301afd590d9SVladimir Kondratyev if (hi->type == HIDMAP_TYPE_VARIABLE && hi->evtype == EV_KEY) 302afd590d9SVladimir Kondratyev nbuttons++; 303*c0a5ee95SEdward Tomasz Napierala #ifdef IICHID_SAMPLING 304*c0a5ee95SEdward Tomasz Napierala /* 305*c0a5ee95SEdward Tomasz Napierala * Make note of which part of the report descriptor is the wheel. 306*c0a5ee95SEdward Tomasz Napierala */ 307*c0a5ee95SEdward Tomasz Napierala if (hi->type == HIDMAP_TYPE_VARIABLE && 308*c0a5ee95SEdward Tomasz Napierala hi->evtype == EV_REL && hi->code == REL_WHEEL) { 309*c0a5ee95SEdward Tomasz Napierala sc->wheel_loc = hi->loc; 310*c0a5ee95SEdward Tomasz Napierala /* 311*c0a5ee95SEdward Tomasz Napierala * Account for the leading Report ID byte 312*c0a5ee95SEdward Tomasz Napierala * if it is a multi-report device. 313*c0a5ee95SEdward Tomasz Napierala */ 314*c0a5ee95SEdward Tomasz Napierala if (hi->id != 0) 315*c0a5ee95SEdward Tomasz Napierala sc->wheel_loc.pos += 8; 316*c0a5ee95SEdward Tomasz Napierala } 317*c0a5ee95SEdward Tomasz Napierala #endif 318*c0a5ee95SEdward Tomasz Napierala } 319afd590d9SVladimir Kondratyev 320afd590d9SVladimir Kondratyev /* announce information about the mouse */ 321afd590d9SVladimir Kondratyev device_printf(dev, "%d buttons and [%s%s%s%s%s] coordinates ID=%u\n", 322afd590d9SVladimir Kondratyev nbuttons, 323afd590d9SVladimir Kondratyev (hidmap_test_cap(sc->caps, HMS_REL_X) || 324afd590d9SVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_ABS_X)) ? "X" : "", 325afd590d9SVladimir Kondratyev (hidmap_test_cap(sc->caps, HMS_REL_Y) || 326afd590d9SVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_ABS_Y)) ? "Y" : "", 327afd590d9SVladimir Kondratyev (hidmap_test_cap(sc->caps, HMS_REL_Z) || 328afd590d9SVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_ABS_Z)) ? "Z" : "", 329afd590d9SVladimir Kondratyev hidmap_test_cap(cap_wheel, 0) ? "W" : "", 330afd590d9SVladimir Kondratyev hidmap_test_cap(sc->caps, HMS_HWHEEL) ? "H" : "", 331afd590d9SVladimir Kondratyev sc->hm.hid_items[0].id); 332afd590d9SVladimir Kondratyev 333afd590d9SVladimir Kondratyev return (0); 334afd590d9SVladimir Kondratyev } 335afd590d9SVladimir Kondratyev 336afd590d9SVladimir Kondratyev static int 337afd590d9SVladimir Kondratyev hms_detach(device_t dev) 338afd590d9SVladimir Kondratyev { 339afd590d9SVladimir Kondratyev struct hms_softc *sc = device_get_softc(dev); 3403e954a8bSVladimir Kondratyev int error; 341afd590d9SVladimir Kondratyev 3423e954a8bSVladimir Kondratyev error = hidmap_detach(&sc->hm); 3433e954a8bSVladimir Kondratyev #ifdef IICHID_SAMPLING 3443e954a8bSVladimir Kondratyev if (error == 0) 3453e954a8bSVladimir Kondratyev free(sc->last_ir, M_DEVBUF); 3463e954a8bSVladimir Kondratyev #endif 3473e954a8bSVladimir Kondratyev return (error); 348afd590d9SVladimir Kondratyev } 349afd590d9SVladimir Kondratyev 350afd590d9SVladimir Kondratyev static device_method_t hms_methods[] = { 351afd590d9SVladimir Kondratyev DEVMETHOD(device_identify, hms_identify), 352afd590d9SVladimir Kondratyev DEVMETHOD(device_probe, hms_probe), 353afd590d9SVladimir Kondratyev DEVMETHOD(device_attach, hms_attach), 354afd590d9SVladimir Kondratyev DEVMETHOD(device_detach, hms_detach), 355afd590d9SVladimir Kondratyev 356afd590d9SVladimir Kondratyev DEVMETHOD_END 357afd590d9SVladimir Kondratyev }; 358afd590d9SVladimir Kondratyev 359afd590d9SVladimir Kondratyev DEFINE_CLASS_0(hms, hms_driver, hms_methods, sizeof(struct hms_softc)); 3607eeede15SJohn Baldwin DRIVER_MODULE(hms, hidbus, hms_driver, NULL, NULL); 361afd590d9SVladimir Kondratyev MODULE_DEPEND(hms, hid, 1, 1, 1); 362afd590d9SVladimir Kondratyev MODULE_DEPEND(hms, hidbus, 1, 1, 1); 363afd590d9SVladimir Kondratyev MODULE_DEPEND(hms, hidmap, 1, 1, 1); 364afd590d9SVladimir Kondratyev MODULE_DEPEND(hms, evdev, 1, 1, 1); 365afd590d9SVladimir Kondratyev MODULE_VERSION(hms, 1); 366afd590d9SVladimir Kondratyev HID_PNP_INFO(hms_devs); 367