1d5add41dSVladimir Kondratyev /*- 2d5add41dSVladimir Kondratyev * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3d5add41dSVladimir Kondratyev * 4d5add41dSVladimir Kondratyev * Copyright (c) 2020, 2022 Vladimir Kondratyev <wulf@FreeBSD.org> 5d5add41dSVladimir Kondratyev * 6d5add41dSVladimir Kondratyev * Redistribution and use in source and binary forms, with or without 7d5add41dSVladimir Kondratyev * modification, are permitted provided that the following conditions 8d5add41dSVladimir Kondratyev * are met: 9d5add41dSVladimir Kondratyev * 1. Redistributions of source code must retain the above copyright 10d5add41dSVladimir Kondratyev * notice, this list of conditions and the following disclaimer. 11d5add41dSVladimir Kondratyev * 2. Redistributions in binary form must reproduce the above copyright 12d5add41dSVladimir Kondratyev * notice, this list of conditions and the following disclaimer in the 13d5add41dSVladimir Kondratyev * documentation and/or other materials provided with the distribution. 14d5add41dSVladimir Kondratyev * 15d5add41dSVladimir Kondratyev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16d5add41dSVladimir Kondratyev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17d5add41dSVladimir Kondratyev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18d5add41dSVladimir Kondratyev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19d5add41dSVladimir Kondratyev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20d5add41dSVladimir Kondratyev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21d5add41dSVladimir Kondratyev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22d5add41dSVladimir Kondratyev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23d5add41dSVladimir Kondratyev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24d5add41dSVladimir Kondratyev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25d5add41dSVladimir Kondratyev * SUCH DAMAGE. 26d5add41dSVladimir Kondratyev */ 27d5add41dSVladimir Kondratyev 28d5add41dSVladimir Kondratyev /* 29d5add41dSVladimir Kondratyev * Elan I2C Touchpad driver. Based on Linux driver. 30d5add41dSVladimir Kondratyev * https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/input/mouse/elan_i2c_core.c 31d5add41dSVladimir Kondratyev */ 32d5add41dSVladimir Kondratyev 33d5add41dSVladimir Kondratyev #include <sys/cdefs.h> 34d5add41dSVladimir Kondratyev __FBSDID("$FreeBSD$"); 35d5add41dSVladimir Kondratyev 36d5add41dSVladimir Kondratyev #include <sys/param.h> 37d5add41dSVladimir Kondratyev #include <sys/bus.h> 38d5add41dSVladimir Kondratyev #include <sys/endian.h> 39d5add41dSVladimir Kondratyev #include <sys/kernel.h> 40d5add41dSVladimir Kondratyev #include <sys/lock.h> 41d5add41dSVladimir Kondratyev #include <sys/malloc.h> 42d5add41dSVladimir Kondratyev #include <sys/module.h> 43d5add41dSVladimir Kondratyev #include <sys/mutex.h> 44d5add41dSVladimir Kondratyev #include <sys/sysctl.h> 45d5add41dSVladimir Kondratyev #include <sys/systm.h> 46d5add41dSVladimir Kondratyev 47d5add41dSVladimir Kondratyev #include <dev/evdev/evdev.h> 48d5add41dSVladimir Kondratyev #include <dev/evdev/input.h> 49d5add41dSVladimir Kondratyev 50d5add41dSVladimir Kondratyev #include <dev/iicbus/iic.h> 51d5add41dSVladimir Kondratyev #include <dev/iicbus/iicbus.h> 52d5add41dSVladimir Kondratyev 53d5add41dSVladimir Kondratyev #define HID_DEBUG_VAR ietp_debug 54d5add41dSVladimir Kondratyev #include <dev/hid/hid.h> 55d5add41dSVladimir Kondratyev #include <dev/hid/hidbus.h> 56d5add41dSVladimir Kondratyev #include <dev/hid/hidquirk.h> 57d5add41dSVladimir Kondratyev 58d5add41dSVladimir Kondratyev #ifdef HID_DEBUG 59d5add41dSVladimir Kondratyev static SYSCTL_NODE(_hw_hid, OID_AUTO, ietp, CTLFLAG_RW, 0, 60d5add41dSVladimir Kondratyev "Elantech Touchpad"); 61d5add41dSVladimir Kondratyev static int ietp_debug = 1; 62d5add41dSVladimir Kondratyev SYSCTL_INT(_hw_hid_ietp, OID_AUTO, debug, CTLFLAG_RWTUN, 63d5add41dSVladimir Kondratyev &ietp_debug, 1, "Debug level"); 64d5add41dSVladimir Kondratyev #endif 65d5add41dSVladimir Kondratyev 66d5add41dSVladimir Kondratyev #define IETP_PATTERN 0x0100 67d5add41dSVladimir Kondratyev #define IETP_UNIQUEID 0x0101 68d5add41dSVladimir Kondratyev #define IETP_FW_VERSION 0x0102 69d5add41dSVladimir Kondratyev #define IETP_IC_TYPE 0x0103 70d5add41dSVladimir Kondratyev #define IETP_OSM_VERSION 0x0103 71d5add41dSVladimir Kondratyev #define IETP_NSM_VERSION 0x0104 72d5add41dSVladimir Kondratyev #define IETP_TRACENUM 0x0105 73d5add41dSVladimir Kondratyev #define IETP_MAX_X_AXIS 0x0106 74d5add41dSVladimir Kondratyev #define IETP_MAX_Y_AXIS 0x0107 75d5add41dSVladimir Kondratyev #define IETP_RESOLUTION 0x0108 76d5add41dSVladimir Kondratyev #define IETP_PRESSURE 0x010A 77d5add41dSVladimir Kondratyev 78d5add41dSVladimir Kondratyev #define IETP_CONTROL 0x0300 79d5add41dSVladimir Kondratyev #define IETP_CTRL_ABSOLUTE 0x0001 80d5add41dSVladimir Kondratyev #define IETP_CTRL_STANDARD 0x0000 81d5add41dSVladimir Kondratyev 82d5add41dSVladimir Kondratyev #define IETP_REPORT_LEN_LO 32 83d5add41dSVladimir Kondratyev #define IETP_REPORT_LEN_HI 37 84d5add41dSVladimir Kondratyev #define IETP_MAX_FINGERS 5 85d5add41dSVladimir Kondratyev 86d5add41dSVladimir Kondratyev #define IETP_REPORT_ID_LO 0x5D 87d5add41dSVladimir Kondratyev #define IETP_REPORT_ID_HI 0x60 88d5add41dSVladimir Kondratyev 89d5add41dSVladimir Kondratyev #define IETP_TOUCH_INFO 1 90d5add41dSVladimir Kondratyev #define IETP_FINGER_DATA 2 91d5add41dSVladimir Kondratyev #define IETP_FINGER_DATA_LEN 5 92d5add41dSVladimir Kondratyev #define IETP_HOVER_INFO 28 93d5add41dSVladimir Kondratyev #define IETP_WH_DATA 31 94d5add41dSVladimir Kondratyev 95d5add41dSVladimir Kondratyev #define IETP_TOUCH_LMB (1 << 0) 96d5add41dSVladimir Kondratyev #define IETP_TOUCH_RMB (1 << 1) 97d5add41dSVladimir Kondratyev #define IETP_TOUCH_MMB (1 << 2) 98d5add41dSVladimir Kondratyev 99d5add41dSVladimir Kondratyev #define IETP_MAX_PRESSURE 255 100d5add41dSVladimir Kondratyev #define IETP_FWIDTH_REDUCE 90 101d5add41dSVladimir Kondratyev #define IETP_FINGER_MAX_WIDTH 15 102d5add41dSVladimir Kondratyev #define IETP_PRESSURE_BASE 25 103d5add41dSVladimir Kondratyev 104d5add41dSVladimir Kondratyev struct ietp_softc { 105d5add41dSVladimir Kondratyev device_t dev; 106d5add41dSVladimir Kondratyev 107d5add41dSVladimir Kondratyev struct evdev_dev *evdev; 108d5add41dSVladimir Kondratyev uint8_t report_id; 109d5add41dSVladimir Kondratyev hid_size_t report_len; 110d5add41dSVladimir Kondratyev 111d5add41dSVladimir Kondratyev uint16_t product_id; 112d5add41dSVladimir Kondratyev uint16_t ic_type; 113d5add41dSVladimir Kondratyev 114d5add41dSVladimir Kondratyev int32_t pressure_base; 115d5add41dSVladimir Kondratyev uint16_t max_x; 116d5add41dSVladimir Kondratyev uint16_t max_y; 117d5add41dSVladimir Kondratyev uint16_t trace_x; 118d5add41dSVladimir Kondratyev uint16_t trace_y; 119d5add41dSVladimir Kondratyev uint16_t res_x; /* dots per mm */ 120d5add41dSVladimir Kondratyev uint16_t res_y; 121d5add41dSVladimir Kondratyev bool hi_precission; 122d5add41dSVladimir Kondratyev bool is_clickpad; 123d5add41dSVladimir Kondratyev bool has_3buttons; 124d5add41dSVladimir Kondratyev }; 125d5add41dSVladimir Kondratyev 126d5add41dSVladimir Kondratyev static evdev_open_t ietp_ev_open; 127d5add41dSVladimir Kondratyev static evdev_close_t ietp_ev_close; 128d5add41dSVladimir Kondratyev static hid_intr_t ietp_intr; 129d5add41dSVladimir Kondratyev 130d5add41dSVladimir Kondratyev static int ietp_probe(struct ietp_softc *); 131d5add41dSVladimir Kondratyev static int ietp_attach(struct ietp_softc *); 132d5add41dSVladimir Kondratyev static int ietp_detach(struct ietp_softc *); 133d5add41dSVladimir Kondratyev static int32_t ietp_res2dpmm(uint8_t, bool); 134d5add41dSVladimir Kondratyev 135d5add41dSVladimir Kondratyev static device_probe_t ietp_iic_probe; 136d5add41dSVladimir Kondratyev static device_attach_t ietp_iic_attach; 137d5add41dSVladimir Kondratyev static device_detach_t ietp_iic_detach; 138d5add41dSVladimir Kondratyev static device_resume_t ietp_iic_resume; 139d5add41dSVladimir Kondratyev 140d5add41dSVladimir Kondratyev static int ietp_iic_read_reg(device_t, uint16_t, size_t, void *); 141d5add41dSVladimir Kondratyev static int ietp_iic_write_reg(device_t, uint16_t, uint16_t); 142d5add41dSVladimir Kondratyev static int ietp_iic_set_absolute_mode(device_t, bool); 143d5add41dSVladimir Kondratyev 144d5add41dSVladimir Kondratyev #define IETP_IIC_DEV(pnp) \ 145d5add41dSVladimir Kondratyev { HID_TLC(HUP_GENERIC_DESKTOP, HUG_MOUSE), HID_BUS(BUS_I2C), HID_PNP(pnp) } 146d5add41dSVladimir Kondratyev 147d5add41dSVladimir Kondratyev static const struct hid_device_id ietp_iic_devs[] = { 148d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0000"), 149d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0100"), 150d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0600"), 151d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0601"), 152d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0602"), 153d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0603"), 154d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0604"), 155d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0605"), 156d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0606"), 157d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0607"), 158d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0608"), 159d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0609"), 160d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN060B"), 161d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN060C"), 162d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN060F"), 163d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0610"), 164d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0611"), 165d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0612"), 166d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0615"), 167d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0616"), 168d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0617"), 169d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0618"), 170d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0619"), 171d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN061A"), 172d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN061B"), 173d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN061C"), 174d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN061D"), 175d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN061E"), 176d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN061F"), 177d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0620"), 178d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0621"), 179d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0622"), 180d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0623"), 181d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0624"), 182d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0625"), 183d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0626"), 184d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0627"), 185d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0628"), 186d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0629"), 187d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN062A"), 188d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN062B"), 189d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN062C"), 190d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN062D"), 191d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN062E"), /* Lenovo V340 Whiskey Lake U */ 192d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN062F"), /* Lenovo V340 Comet Lake U */ 193d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0631"), 194d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0632"), 195d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0633"), /* Lenovo S145 */ 196d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0634"), /* Lenovo V340 Ice lake */ 197d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0635"), /* Lenovo V1415-IIL */ 198d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0636"), /* Lenovo V1415-Dali */ 199d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN0637"), /* Lenovo V1415-IGLR */ 200d5add41dSVladimir Kondratyev IETP_IIC_DEV("ELAN1000"), 201d5add41dSVladimir Kondratyev }; 202d5add41dSVladimir Kondratyev 203d5add41dSVladimir Kondratyev static const struct evdev_methods ietp_evdev_methods = { 204d5add41dSVladimir Kondratyev .ev_open = &ietp_ev_open, 205d5add41dSVladimir Kondratyev .ev_close = &ietp_ev_close, 206d5add41dSVladimir Kondratyev }; 207d5add41dSVladimir Kondratyev 208d5add41dSVladimir Kondratyev static int 209d5add41dSVladimir Kondratyev ietp_ev_open(struct evdev_dev *evdev) 210d5add41dSVladimir Kondratyev { 211d5add41dSVladimir Kondratyev return (hidbus_intr_start(evdev_get_softc(evdev))); 212d5add41dSVladimir Kondratyev } 213d5add41dSVladimir Kondratyev 214d5add41dSVladimir Kondratyev static int 215d5add41dSVladimir Kondratyev ietp_ev_close(struct evdev_dev *evdev) 216d5add41dSVladimir Kondratyev { 217d5add41dSVladimir Kondratyev return (hidbus_intr_stop(evdev_get_softc(evdev))); 218d5add41dSVladimir Kondratyev } 219d5add41dSVladimir Kondratyev 220d5add41dSVladimir Kondratyev static int 221d5add41dSVladimir Kondratyev ietp_probe(struct ietp_softc *sc) 222d5add41dSVladimir Kondratyev { 223d5add41dSVladimir Kondratyev if (hidbus_find_child(device_get_parent(sc->dev), 224d5add41dSVladimir Kondratyev HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD)) != NULL) { 225d5add41dSVladimir Kondratyev DPRINTFN(5, "Ignore HID-compatible touchpad on %s\n", 226d5add41dSVladimir Kondratyev device_get_nameunit(device_get_parent(sc->dev))); 227d5add41dSVladimir Kondratyev return (ENXIO); 228d5add41dSVladimir Kondratyev } 229d5add41dSVladimir Kondratyev 230d5add41dSVladimir Kondratyev device_set_desc(sc->dev, "Elan Touchpad"); 231d5add41dSVladimir Kondratyev 232d5add41dSVladimir Kondratyev return (BUS_PROBE_DEFAULT); 233d5add41dSVladimir Kondratyev } 234d5add41dSVladimir Kondratyev 235d5add41dSVladimir Kondratyev static int 236d5add41dSVladimir Kondratyev ietp_attach(struct ietp_softc *sc) 237d5add41dSVladimir Kondratyev { 238d5add41dSVladimir Kondratyev const struct hid_device_info *hw = hid_get_device_info(sc->dev); 239d5add41dSVladimir Kondratyev void *d_ptr; 240d5add41dSVladimir Kondratyev hid_size_t d_len; 241d5add41dSVladimir Kondratyev int32_t minor, major; 242d5add41dSVladimir Kondratyev int error; 243d5add41dSVladimir Kondratyev 244d5add41dSVladimir Kondratyev sc->report_id = sc->hi_precission ? 245d5add41dSVladimir Kondratyev IETP_REPORT_ID_HI : IETP_REPORT_ID_LO; 246d5add41dSVladimir Kondratyev sc->report_len = sc->hi_precission ? 247d5add41dSVladimir Kondratyev IETP_REPORT_LEN_HI : IETP_REPORT_LEN_LO; 248d5add41dSVladimir Kondratyev 249d5add41dSVladimir Kondratyev /* Try to detect 3-rd button by relative mouse TLC */ 250d5add41dSVladimir Kondratyev if (!sc->is_clickpad) { 251d5add41dSVladimir Kondratyev error = hid_get_report_descr(sc->dev, &d_ptr, &d_len); 252d5add41dSVladimir Kondratyev if (error != 0) { 253d5add41dSVladimir Kondratyev device_printf(sc->dev, "could not retrieve report " 254d5add41dSVladimir Kondratyev "descriptor from device: %d\n", error); 255d5add41dSVladimir Kondratyev return (ENXIO); 256d5add41dSVladimir Kondratyev } 257d5add41dSVladimir Kondratyev if (hidbus_locate(d_ptr, d_len, HID_USAGE2(HUP_BUTTON, 3), 258d5add41dSVladimir Kondratyev hid_input, hidbus_get_index(sc->dev), 0, NULL, NULL, NULL, 259d5add41dSVladimir Kondratyev NULL)) 260d5add41dSVladimir Kondratyev sc->has_3buttons = true; 261d5add41dSVladimir Kondratyev } 262d5add41dSVladimir Kondratyev 263d5add41dSVladimir Kondratyev sc->evdev = evdev_alloc(); 264d5add41dSVladimir Kondratyev evdev_set_name(sc->evdev, device_get_desc(sc->dev)); 265d5add41dSVladimir Kondratyev evdev_set_phys(sc->evdev, device_get_nameunit(sc->dev)); 266d5add41dSVladimir Kondratyev evdev_set_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct, 267d5add41dSVladimir Kondratyev hw->idVersion); 268d5add41dSVladimir Kondratyev evdev_set_serial(sc->evdev, hw->serial); 269d5add41dSVladimir Kondratyev evdev_set_methods(sc->evdev, sc->dev, &ietp_evdev_methods); 270d5add41dSVladimir Kondratyev evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT); 271d5add41dSVladimir Kondratyev evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */ 272d5add41dSVladimir Kondratyev 273d5add41dSVladimir Kondratyev evdev_support_event(sc->evdev, EV_SYN); 274d5add41dSVladimir Kondratyev evdev_support_event(sc->evdev, EV_ABS); 275d5add41dSVladimir Kondratyev evdev_support_event(sc->evdev, EV_KEY); 276d5add41dSVladimir Kondratyev evdev_support_prop(sc->evdev, INPUT_PROP_POINTER); 277d5add41dSVladimir Kondratyev evdev_support_key(sc->evdev, BTN_LEFT); 278d5add41dSVladimir Kondratyev if (sc->is_clickpad) { 279d5add41dSVladimir Kondratyev evdev_support_prop(sc->evdev, INPUT_PROP_BUTTONPAD); 280d5add41dSVladimir Kondratyev } else { 281d5add41dSVladimir Kondratyev evdev_support_key(sc->evdev, BTN_RIGHT); 282d5add41dSVladimir Kondratyev if (sc->has_3buttons) 283d5add41dSVladimir Kondratyev evdev_support_key(sc->evdev, BTN_MIDDLE); 284d5add41dSVladimir Kondratyev } 285d5add41dSVladimir Kondratyev 286d5add41dSVladimir Kondratyev major = IETP_FINGER_MAX_WIDTH * MAX(sc->trace_x, sc->trace_y); 287d5add41dSVladimir Kondratyev minor = IETP_FINGER_MAX_WIDTH * MIN(sc->trace_x, sc->trace_y); 288d5add41dSVladimir Kondratyev 289d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_SLOT, 290d5add41dSVladimir Kondratyev 0, IETP_MAX_FINGERS - 1, 0, 0, 0); 291d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_TRACKING_ID, 292d5add41dSVladimir Kondratyev -1, IETP_MAX_FINGERS - 1, 0, 0, 0); 293d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_POSITION_X, 294d5add41dSVladimir Kondratyev 0, sc->max_x, 0, 0, sc->res_x); 295d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_POSITION_Y, 296d5add41dSVladimir Kondratyev 0, sc->max_y, 0, 0, sc->res_y); 297d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_PRESSURE, 298d5add41dSVladimir Kondratyev 0, IETP_MAX_PRESSURE, 0, 0, 0); 299d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_ORIENTATION, 0, 1, 0, 0, 0); 300d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_TOUCH_MAJOR, 0, major, 0, 0, 0); 301d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_MT_TOUCH_MINOR, 0, minor, 0, 0, 0); 302d5add41dSVladimir Kondratyev evdev_support_abs(sc->evdev, ABS_DISTANCE, 0, 1, 0, 0, 0); 303d5add41dSVladimir Kondratyev 304d5add41dSVladimir Kondratyev error = evdev_register(sc->evdev); 305d5add41dSVladimir Kondratyev if (error != 0) { 306d5add41dSVladimir Kondratyev ietp_detach(sc); 307d5add41dSVladimir Kondratyev return (ENOMEM); 308d5add41dSVladimir Kondratyev } 309d5add41dSVladimir Kondratyev 310d5add41dSVladimir Kondratyev hidbus_set_intr(sc->dev, ietp_intr, sc); 311d5add41dSVladimir Kondratyev 312d5add41dSVladimir Kondratyev device_printf(sc->dev, "[%d:%d], %s\n", sc->max_x, sc->max_y, 313d5add41dSVladimir Kondratyev sc->is_clickpad ? "clickpad" : 314d5add41dSVladimir Kondratyev sc->has_3buttons ? "3 buttons" : "2 buttons"); 315d5add41dSVladimir Kondratyev 316d5add41dSVladimir Kondratyev return (0); 317d5add41dSVladimir Kondratyev } 318d5add41dSVladimir Kondratyev 319d5add41dSVladimir Kondratyev static int 320d5add41dSVladimir Kondratyev ietp_detach(struct ietp_softc *sc) 321d5add41dSVladimir Kondratyev { 322d5add41dSVladimir Kondratyev evdev_free(sc->evdev); 323d5add41dSVladimir Kondratyev 324d5add41dSVladimir Kondratyev return (0); 325d5add41dSVladimir Kondratyev } 326d5add41dSVladimir Kondratyev 327d5add41dSVladimir Kondratyev static void 328d5add41dSVladimir Kondratyev ietp_intr(void *context, void *buf, hid_size_t len) 329d5add41dSVladimir Kondratyev { 330d5add41dSVladimir Kondratyev struct ietp_softc *sc = context; 331d5add41dSVladimir Kondratyev union evdev_mt_slot slot_data; 332d5add41dSVladimir Kondratyev uint8_t *report, *fdata; 333d5add41dSVladimir Kondratyev int32_t finger; 334d5add41dSVladimir Kondratyev int32_t x, y, w, h, wh; 335d5add41dSVladimir Kondratyev 336d5add41dSVladimir Kondratyev /* we seem to get 0 length reports sometimes, ignore them */ 337d5add41dSVladimir Kondratyev report = buf; 338d5add41dSVladimir Kondratyev if (*report != sc->report_id || len < sc->report_len) 339d5add41dSVladimir Kondratyev return; 340d5add41dSVladimir Kondratyev 341d5add41dSVladimir Kondratyev for (finger = 0, fdata = report + IETP_FINGER_DATA; 342d5add41dSVladimir Kondratyev finger < IETP_MAX_FINGERS; 343d5add41dSVladimir Kondratyev finger++, fdata += IETP_FINGER_DATA_LEN) { 344d5add41dSVladimir Kondratyev if ((report[IETP_TOUCH_INFO] & (1 << (finger + 3))) != 0) { 345d5add41dSVladimir Kondratyev if (sc->hi_precission) { 346d5add41dSVladimir Kondratyev x = fdata[0] << 8 | fdata[1]; 347d5add41dSVladimir Kondratyev y = fdata[2] << 8 | fdata[3]; 348d5add41dSVladimir Kondratyev wh = report[IETP_WH_DATA + finger]; 349d5add41dSVladimir Kondratyev } else { 350d5add41dSVladimir Kondratyev x = (fdata[0] & 0xf0) << 4 | fdata[1]; 351d5add41dSVladimir Kondratyev y = (fdata[0] & 0x0f) << 8 | fdata[2]; 352d5add41dSVladimir Kondratyev wh = fdata[3]; 353d5add41dSVladimir Kondratyev } 354d5add41dSVladimir Kondratyev 355d5add41dSVladimir Kondratyev if (x > sc->max_x || y > sc->max_y) { 356d5add41dSVladimir Kondratyev DPRINTF("[%d] x=%d y=%d over max (%d, %d)", 357d5add41dSVladimir Kondratyev finger, x, y, sc->max_x, sc->max_y); 358d5add41dSVladimir Kondratyev continue; 359d5add41dSVladimir Kondratyev } 360d5add41dSVladimir Kondratyev 361d5add41dSVladimir Kondratyev /* Reduce trace size to not treat large finger as palm */ 362d5add41dSVladimir Kondratyev w = (wh & 0x0F) * (sc->trace_x - IETP_FWIDTH_REDUCE); 363d5add41dSVladimir Kondratyev h = (wh >> 4) * (sc->trace_y - IETP_FWIDTH_REDUCE); 364d5add41dSVladimir Kondratyev 365d5add41dSVladimir Kondratyev slot_data = (union evdev_mt_slot) { 366d5add41dSVladimir Kondratyev .id = finger, 367d5add41dSVladimir Kondratyev .x = x, 368d5add41dSVladimir Kondratyev .y = sc->max_y - y, 369d5add41dSVladimir Kondratyev .p = MIN((int32_t)fdata[4] + sc->pressure_base, 370d5add41dSVladimir Kondratyev IETP_MAX_PRESSURE), 371d5add41dSVladimir Kondratyev .ori = w > h ? 1 : 0, 372d5add41dSVladimir Kondratyev .maj = MAX(w, h), 373d5add41dSVladimir Kondratyev .min = MIN(w, h), 374d5add41dSVladimir Kondratyev }; 375d5add41dSVladimir Kondratyev evdev_mt_push_slot(sc->evdev, finger, &slot_data); 376d5add41dSVladimir Kondratyev } else { 377d5add41dSVladimir Kondratyev evdev_push_abs(sc->evdev, ABS_MT_SLOT, finger); 378d5add41dSVladimir Kondratyev evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1); 379d5add41dSVladimir Kondratyev } 380d5add41dSVladimir Kondratyev } 381d5add41dSVladimir Kondratyev 382d5add41dSVladimir Kondratyev evdev_push_key(sc->evdev, BTN_LEFT, 383d5add41dSVladimir Kondratyev report[IETP_TOUCH_INFO] & IETP_TOUCH_LMB); 384d5add41dSVladimir Kondratyev evdev_push_key(sc->evdev, BTN_MIDDLE, 385d5add41dSVladimir Kondratyev report[IETP_TOUCH_INFO] & IETP_TOUCH_MMB); 386d5add41dSVladimir Kondratyev evdev_push_key(sc->evdev, BTN_RIGHT, 387d5add41dSVladimir Kondratyev report[IETP_TOUCH_INFO] & IETP_TOUCH_RMB); 388d5add41dSVladimir Kondratyev evdev_push_abs(sc->evdev, ABS_DISTANCE, 389d5add41dSVladimir Kondratyev (report[IETP_HOVER_INFO] & 0x40) >> 6); 390d5add41dSVladimir Kondratyev 391d5add41dSVladimir Kondratyev evdev_sync(sc->evdev); 392d5add41dSVladimir Kondratyev } 393d5add41dSVladimir Kondratyev 394d5add41dSVladimir Kondratyev static int32_t 395d5add41dSVladimir Kondratyev ietp_res2dpmm(uint8_t res, bool hi_precission) 396d5add41dSVladimir Kondratyev { 397d5add41dSVladimir Kondratyev int32_t dpi; 398d5add41dSVladimir Kondratyev 399d5add41dSVladimir Kondratyev dpi = hi_precission ? 300 + res * 100 : 790 + res * 10; 400d5add41dSVladimir Kondratyev 401d5add41dSVladimir Kondratyev return (dpi * 10 /254); 402d5add41dSVladimir Kondratyev } 403d5add41dSVladimir Kondratyev 404d5add41dSVladimir Kondratyev static int 405d5add41dSVladimir Kondratyev ietp_iic_probe(device_t dev) 406d5add41dSVladimir Kondratyev { 407d5add41dSVladimir Kondratyev struct ietp_softc *sc = device_get_softc(dev); 408d5add41dSVladimir Kondratyev device_t iichid; 409d5add41dSVladimir Kondratyev int error; 410d5add41dSVladimir Kondratyev 411d5add41dSVladimir Kondratyev error = HIDBUS_LOOKUP_DRIVER_INFO(dev, ietp_iic_devs); 412d5add41dSVladimir Kondratyev if (error != 0) 413d5add41dSVladimir Kondratyev return (error); 414d5add41dSVladimir Kondratyev 415d5add41dSVladimir Kondratyev iichid = device_get_parent(device_get_parent(dev)); 416d5add41dSVladimir Kondratyev if (device_get_devclass(iichid) != devclass_find("iichid")) 417d5add41dSVladimir Kondratyev return (ENXIO); 418d5add41dSVladimir Kondratyev 419d5add41dSVladimir Kondratyev sc->dev = dev; 420d5add41dSVladimir Kondratyev 421d5add41dSVladimir Kondratyev return (ietp_probe(sc)); 422d5add41dSVladimir Kondratyev } 423d5add41dSVladimir Kondratyev 424d5add41dSVladimir Kondratyev static int 425d5add41dSVladimir Kondratyev ietp_iic_attach(device_t dev) 426d5add41dSVladimir Kondratyev { 427d5add41dSVladimir Kondratyev struct ietp_softc *sc = device_get_softc(dev); 428d5add41dSVladimir Kondratyev uint16_t buf, reg; 429d5add41dSVladimir Kondratyev uint8_t *buf8; 430d5add41dSVladimir Kondratyev uint8_t pattern; 431d5add41dSVladimir Kondratyev 432d5add41dSVladimir Kondratyev buf8 = (uint8_t *)&buf; 433d5add41dSVladimir Kondratyev 434d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_UNIQUEID, sizeof(buf), &buf) != 0) { 435d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading product ID\n"); 436d5add41dSVladimir Kondratyev return (EIO); 437d5add41dSVladimir Kondratyev } 438d5add41dSVladimir Kondratyev sc->product_id = le16toh(buf); 439d5add41dSVladimir Kondratyev 440d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_PATTERN, sizeof(buf), &buf) != 0) { 441d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading pattern\n"); 442d5add41dSVladimir Kondratyev return (EIO); 443d5add41dSVladimir Kondratyev } 444d5add41dSVladimir Kondratyev pattern = buf == 0xFFFF ? 0 : buf8[1]; 445d5add41dSVladimir Kondratyev sc->hi_precission = pattern >= 0x02; 446d5add41dSVladimir Kondratyev 447d5add41dSVladimir Kondratyev reg = pattern >= 0x01 ? IETP_IC_TYPE : IETP_OSM_VERSION; 448d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, reg, sizeof(buf), &buf) != 0) { 449d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading IC type\n"); 450d5add41dSVladimir Kondratyev return (EIO); 451d5add41dSVladimir Kondratyev } 452d5add41dSVladimir Kondratyev sc->ic_type = pattern >= 0x01 ? be16toh(buf) : buf8[1]; 453d5add41dSVladimir Kondratyev 454d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_NSM_VERSION, sizeof(buf), &buf) != 0) { 455d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading SM version\n"); 456d5add41dSVladimir Kondratyev return (EIO); 457d5add41dSVladimir Kondratyev } 458d5add41dSVladimir Kondratyev sc->is_clickpad = (buf8[0] & 0x10) != 0; 459d5add41dSVladimir Kondratyev 460d5add41dSVladimir Kondratyev if (ietp_iic_set_absolute_mode(dev, true) != 0) { 461d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed to set absolute mode\n"); 462d5add41dSVladimir Kondratyev return (EIO); 463d5add41dSVladimir Kondratyev } 464d5add41dSVladimir Kondratyev 465d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_MAX_X_AXIS, sizeof(buf), &buf) != 0) { 466d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading max x\n"); 467d5add41dSVladimir Kondratyev return (EIO); 468d5add41dSVladimir Kondratyev } 469d5add41dSVladimir Kondratyev sc->max_x = le16toh(buf); 470d5add41dSVladimir Kondratyev 471d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_MAX_Y_AXIS, sizeof(buf), &buf) != 0) { 472d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading max y\n"); 473d5add41dSVladimir Kondratyev return (EIO); 474d5add41dSVladimir Kondratyev } 475d5add41dSVladimir Kondratyev sc->max_y = le16toh(buf); 476d5add41dSVladimir Kondratyev 477d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_TRACENUM, sizeof(buf), &buf) != 0) { 478d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading trace info\n"); 479d5add41dSVladimir Kondratyev return (EIO); 480d5add41dSVladimir Kondratyev } 481d5add41dSVladimir Kondratyev sc->trace_x = sc->max_x / buf8[0]; 482d5add41dSVladimir Kondratyev sc->trace_y = sc->max_y / buf8[1]; 483d5add41dSVladimir Kondratyev 484d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_PRESSURE, sizeof(buf), &buf) != 0) { 485d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading pressure format\n"); 486d5add41dSVladimir Kondratyev return (EIO); 487d5add41dSVladimir Kondratyev } 488d5add41dSVladimir Kondratyev sc->pressure_base = (buf8[0] & 0x10) ? 0 : IETP_PRESSURE_BASE; 489d5add41dSVladimir Kondratyev 490d5add41dSVladimir Kondratyev if (ietp_iic_read_reg(dev, IETP_RESOLUTION, sizeof(buf), &buf) != 0) { 491d5add41dSVladimir Kondratyev device_printf(sc->dev, "failed reading resolution\n"); 492d5add41dSVladimir Kondratyev return (EIO); 493d5add41dSVladimir Kondratyev } 494d5add41dSVladimir Kondratyev /* Conversion from internal format to dot per mm */ 495d5add41dSVladimir Kondratyev sc->res_x = ietp_res2dpmm(buf8[0], sc->hi_precission); 496d5add41dSVladimir Kondratyev sc->res_y = ietp_res2dpmm(buf8[1], sc->hi_precission); 497d5add41dSVladimir Kondratyev 498d5add41dSVladimir Kondratyev return (ietp_attach(sc)); 499d5add41dSVladimir Kondratyev } 500d5add41dSVladimir Kondratyev 501d5add41dSVladimir Kondratyev static int 502d5add41dSVladimir Kondratyev ietp_iic_detach(device_t dev) 503d5add41dSVladimir Kondratyev { 504d5add41dSVladimir Kondratyev struct ietp_softc *sc = device_get_softc(dev); 505d5add41dSVladimir Kondratyev 506d5add41dSVladimir Kondratyev if (ietp_iic_set_absolute_mode(dev, false) != 0) 507d5add41dSVladimir Kondratyev device_printf(dev, "failed setting standard mode\n"); 508d5add41dSVladimir Kondratyev 509d5add41dSVladimir Kondratyev return (ietp_detach(sc)); 510d5add41dSVladimir Kondratyev } 511d5add41dSVladimir Kondratyev 512d5add41dSVladimir Kondratyev static int 513d5add41dSVladimir Kondratyev ietp_iic_resume(device_t dev) 514d5add41dSVladimir Kondratyev { 515d5add41dSVladimir Kondratyev if (ietp_iic_set_absolute_mode(dev, true) != 0) { 516d5add41dSVladimir Kondratyev device_printf(dev, "reset when resuming failed: \n"); 517d5add41dSVladimir Kondratyev return (EIO); 518d5add41dSVladimir Kondratyev } 519d5add41dSVladimir Kondratyev 520d5add41dSVladimir Kondratyev return (0); 521d5add41dSVladimir Kondratyev } 522d5add41dSVladimir Kondratyev 523d5add41dSVladimir Kondratyev static int 524d5add41dSVladimir Kondratyev ietp_iic_set_absolute_mode(device_t dev, bool enable) 525d5add41dSVladimir Kondratyev { 526d5add41dSVladimir Kondratyev struct ietp_softc *sc = device_get_softc(dev); 527d5add41dSVladimir Kondratyev static const struct { 528d5add41dSVladimir Kondratyev uint16_t ic_type; 529d5add41dSVladimir Kondratyev uint16_t product_id; 530d5add41dSVladimir Kondratyev } special_fw[] = { 531d5add41dSVladimir Kondratyev { 0x0E, 0x05 }, { 0x0E, 0x06 }, { 0x0E, 0x07 }, { 0x0E, 0x09 }, 532d5add41dSVladimir Kondratyev { 0x0E, 0x13 }, { 0x08, 0x26 }, 533d5add41dSVladimir Kondratyev }; 534d5add41dSVladimir Kondratyev uint16_t val; 535d5add41dSVladimir Kondratyev int i, error; 536d5add41dSVladimir Kondratyev bool require_wakeup; 537d5add41dSVladimir Kondratyev 538d5add41dSVladimir Kondratyev error = 0; 539d5add41dSVladimir Kondratyev 540d5add41dSVladimir Kondratyev /* 541d5add41dSVladimir Kondratyev * Some ASUS touchpads need to be powered on to enter absolute mode. 542d5add41dSVladimir Kondratyev */ 543d5add41dSVladimir Kondratyev require_wakeup = false; 544d5add41dSVladimir Kondratyev for (i = 0; i < nitems(special_fw); i++) { 545d5add41dSVladimir Kondratyev if (sc->ic_type == special_fw[i].ic_type && 546d5add41dSVladimir Kondratyev sc->product_id == special_fw[i].product_id) { 547d5add41dSVladimir Kondratyev require_wakeup = true; 548d5add41dSVladimir Kondratyev break; 549d5add41dSVladimir Kondratyev } 550d5add41dSVladimir Kondratyev } 551d5add41dSVladimir Kondratyev 552d5add41dSVladimir Kondratyev if (require_wakeup && hidbus_intr_start(dev) != 0) { 553d5add41dSVladimir Kondratyev device_printf(dev, "failed writing poweron command\n"); 554d5add41dSVladimir Kondratyev return (EIO); 555d5add41dSVladimir Kondratyev } 556d5add41dSVladimir Kondratyev 557d5add41dSVladimir Kondratyev val = enable ? IETP_CTRL_ABSOLUTE : IETP_CTRL_STANDARD; 558d5add41dSVladimir Kondratyev if (ietp_iic_write_reg(dev, IETP_CONTROL, val) != 0) { 559d5add41dSVladimir Kondratyev device_printf(dev, "failed setting absolute mode\n"); 560d5add41dSVladimir Kondratyev error = EIO; 561d5add41dSVladimir Kondratyev } 562d5add41dSVladimir Kondratyev 563d5add41dSVladimir Kondratyev if (require_wakeup && hidbus_intr_stop(dev) != 0) { 564d5add41dSVladimir Kondratyev device_printf(dev, "failed writing poweroff command\n"); 565d5add41dSVladimir Kondratyev error = EIO; 566d5add41dSVladimir Kondratyev } 567d5add41dSVladimir Kondratyev 568d5add41dSVladimir Kondratyev return (error); 569d5add41dSVladimir Kondratyev } 570d5add41dSVladimir Kondratyev 571d5add41dSVladimir Kondratyev static int 572d5add41dSVladimir Kondratyev ietp_iic_read_reg(device_t dev, uint16_t reg, size_t len, void *val) 573d5add41dSVladimir Kondratyev { 574d5add41dSVladimir Kondratyev device_t iichid = device_get_parent(device_get_parent(dev)); 575d5add41dSVladimir Kondratyev uint16_t addr = iicbus_get_addr(iichid) << 1; 576d5add41dSVladimir Kondratyev uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff }; 577d5add41dSVladimir Kondratyev struct iic_msg msgs[2] = { 578d5add41dSVladimir Kondratyev { addr, IIC_M_WR | IIC_M_NOSTOP, sizeof(cmd), cmd }, 579d5add41dSVladimir Kondratyev { addr, IIC_M_RD, len, val }, 580d5add41dSVladimir Kondratyev }; 581d5add41dSVladimir Kondratyev struct iic_rdwr_data ird = { msgs, nitems(msgs) }; 582d5add41dSVladimir Kondratyev int error; 583d5add41dSVladimir Kondratyev 584d5add41dSVladimir Kondratyev DPRINTF("Read reg 0x%04x with size %zu\n", reg, len); 585d5add41dSVladimir Kondratyev 586d5add41dSVladimir Kondratyev error = hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird); 587d5add41dSVladimir Kondratyev if (error != 0) 588d5add41dSVladimir Kondratyev return (error); 589d5add41dSVladimir Kondratyev 590d5add41dSVladimir Kondratyev DPRINTF("Response: %*D\n", (int)len, val, " "); 591d5add41dSVladimir Kondratyev 592d5add41dSVladimir Kondratyev return (0); 593d5add41dSVladimir Kondratyev } 594d5add41dSVladimir Kondratyev 595d5add41dSVladimir Kondratyev static int 596d5add41dSVladimir Kondratyev ietp_iic_write_reg(device_t dev, uint16_t reg, uint16_t val) 597d5add41dSVladimir Kondratyev { 598d5add41dSVladimir Kondratyev device_t iichid = device_get_parent(device_get_parent(dev)); 599d5add41dSVladimir Kondratyev uint16_t addr = iicbus_get_addr(iichid) << 1; 600d5add41dSVladimir Kondratyev uint8_t cmd[4] = { reg & 0xff, (reg >> 8) & 0xff, 601d5add41dSVladimir Kondratyev val & 0xff, (val >> 8) & 0xff }; 602d5add41dSVladimir Kondratyev struct iic_msg msgs[1] = { 603d5add41dSVladimir Kondratyev { addr, IIC_M_WR, sizeof(cmd), cmd }, 604d5add41dSVladimir Kondratyev }; 605d5add41dSVladimir Kondratyev struct iic_rdwr_data ird = { msgs, nitems(msgs) }; 606d5add41dSVladimir Kondratyev 607d5add41dSVladimir Kondratyev DPRINTF("Write reg 0x%04x with value 0x%04x\n", reg, val); 608d5add41dSVladimir Kondratyev 609d5add41dSVladimir Kondratyev return (hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird)); 610d5add41dSVladimir Kondratyev } 611d5add41dSVladimir Kondratyev 612d5add41dSVladimir Kondratyev static device_method_t ietp_methods[] = { 613d5add41dSVladimir Kondratyev DEVMETHOD(device_probe, ietp_iic_probe), 614d5add41dSVladimir Kondratyev DEVMETHOD(device_attach, ietp_iic_attach), 615d5add41dSVladimir Kondratyev DEVMETHOD(device_detach, ietp_iic_detach), 616d5add41dSVladimir Kondratyev DEVMETHOD(device_resume, ietp_iic_resume), 617d5add41dSVladimir Kondratyev DEVMETHOD_END 618d5add41dSVladimir Kondratyev }; 619d5add41dSVladimir Kondratyev 620d5add41dSVladimir Kondratyev static driver_t ietp_driver = { 621d5add41dSVladimir Kondratyev .name = "ietp", 622d5add41dSVladimir Kondratyev .methods = ietp_methods, 623d5add41dSVladimir Kondratyev .size = sizeof(struct ietp_softc), 624d5add41dSVladimir Kondratyev }; 625d5add41dSVladimir Kondratyev 626*7eeede15SJohn Baldwin DRIVER_MODULE(ietp, hidbus, ietp_driver, NULL, NULL); 627d5add41dSVladimir Kondratyev MODULE_DEPEND(ietp, hidbus, 1, 1, 1); 628d5add41dSVladimir Kondratyev MODULE_DEPEND(ietp, hid, 1, 1, 1); 629d5add41dSVladimir Kondratyev MODULE_DEPEND(ietp, evdev, 1, 1, 1); 630d5add41dSVladimir Kondratyev MODULE_VERSION(ietp, 1); 631d5add41dSVladimir Kondratyev HID_PNP_INFO(ietp_iic_devs); 632