1 1.34 thorpej /* $NetBSD: ihidev.c,v 1.34 2025/09/17 13:51:47 thorpej Exp $ */ 2 1.1 bouyer /* $OpenBSD ihidev.c,v 1.13 2017/04/08 02:57:23 deraadt Exp $ */ 3 1.1 bouyer 4 1.1 bouyer /*- 5 1.1 bouyer * Copyright (c) 2017 The NetBSD Foundation, Inc. 6 1.1 bouyer * All rights reserved. 7 1.1 bouyer * 8 1.1 bouyer * This code is derived from software contributed to The NetBSD Foundation 9 1.1 bouyer * by Manuel Bouyer. 10 1.1 bouyer * 11 1.1 bouyer * Redistribution and use in source and binary forms, with or without 12 1.1 bouyer * modification, are permitted provided that the following conditions 13 1.1 bouyer * are met: 14 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 15 1.1 bouyer * notice, this list of conditions and the following disclaimer. 16 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 18 1.1 bouyer * documentation and/or other materials provided with the distribution. 19 1.1 bouyer * 20 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 bouyer * POSSIBILITY OF SUCH DAMAGE. 31 1.1 bouyer */ 32 1.1 bouyer 33 1.1 bouyer /* 34 1.1 bouyer * Copyright (c) 2015, 2016 joshua stein <jcs (at) openbsd.org> 35 1.1 bouyer * 36 1.1 bouyer * Permission to use, copy, modify, and distribute this software for any 37 1.1 bouyer * purpose with or without fee is hereby granted, provided that the above 38 1.1 bouyer * copyright notice and this permission notice appear in all copies. 39 1.1 bouyer * 40 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 41 1.1 bouyer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 42 1.1 bouyer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 43 1.1 bouyer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 44 1.1 bouyer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 45 1.1 bouyer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 46 1.1 bouyer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 47 1.1 bouyer */ 48 1.1 bouyer 49 1.1 bouyer /* 50 1.1 bouyer * HID-over-i2c driver 51 1.1 bouyer * 52 1.1 bouyer * https://msdn.microsoft.com/en-us/library/windows/hardware/dn642101%28v=vs.85%29.aspx 53 1.1 bouyer * 54 1.1 bouyer */ 55 1.1 bouyer 56 1.31 jmcneill #include "gpio.h" 57 1.31 jmcneill #include "acpica.h" 58 1.31 jmcneill 59 1.1 bouyer #include <sys/cdefs.h> 60 1.34 thorpej __KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1.34 2025/09/17 13:51:47 thorpej Exp $"); 61 1.1 bouyer 62 1.1 bouyer #include <sys/param.h> 63 1.1 bouyer #include <sys/systm.h> 64 1.1 bouyer #include <sys/device.h> 65 1.1 bouyer #include <sys/kmem.h> 66 1.21 riastrad #include <sys/workqueue.h> 67 1.1 bouyer 68 1.1 bouyer #include <dev/i2c/i2cvar.h> 69 1.1 bouyer #include <dev/i2c/ihidev.h> 70 1.1 bouyer 71 1.1 bouyer #include <dev/hid/hid.h> 72 1.1 bouyer 73 1.1 bouyer #if NACPICA > 0 74 1.12 thorpej #include <dev/acpi/acpivar.h> 75 1.1 bouyer #include <dev/acpi/acpi_intr.h> 76 1.31 jmcneill #include <dev/acpi/acpi_gpio.h> 77 1.31 jmcneill #endif 78 1.31 jmcneill #if NGPIO > 0 79 1.31 jmcneill #include <dev/gpio/gpiovar.h> 80 1.1 bouyer #endif 81 1.1 bouyer 82 1.1 bouyer #include "locators.h" 83 1.1 bouyer 84 1.1 bouyer /* #define IHIDEV_DEBUG */ 85 1.1 bouyer 86 1.1 bouyer #ifdef IHIDEV_DEBUG 87 1.1 bouyer #define DPRINTF(x) printf x 88 1.1 bouyer #else 89 1.1 bouyer #define DPRINTF(x) 90 1.1 bouyer #endif 91 1.1 bouyer 92 1.1 bouyer /* 7.2 */ 93 1.1 bouyer enum { 94 1.1 bouyer I2C_HID_CMD_DESCR = 0x0, 95 1.1 bouyer I2C_HID_CMD_RESET = 0x1, 96 1.1 bouyer I2C_HID_CMD_GET_REPORT = 0x2, 97 1.1 bouyer I2C_HID_CMD_SET_REPORT = 0x3, 98 1.1 bouyer I2C_HID_CMD_GET_IDLE = 0x4, 99 1.1 bouyer I2C_HID_CMD_SET_IDLE = 0x5, 100 1.1 bouyer I2C_HID_CMD_GET_PROTO = 0x6, 101 1.1 bouyer I2C_HID_CMD_SET_PROTO = 0x7, 102 1.1 bouyer I2C_HID_CMD_SET_POWER = 0x8, 103 1.1 bouyer 104 1.1 bouyer /* pseudo commands */ 105 1.1 bouyer I2C_HID_REPORT_DESCR = 0x100, 106 1.1 bouyer }; 107 1.1 bouyer 108 1.1 bouyer static int I2C_HID_POWER_ON = 0x0; 109 1.1 bouyer static int I2C_HID_POWER_OFF = 0x1; 110 1.1 bouyer 111 1.1 bouyer static int ihidev_match(device_t, cfdata_t, void *); 112 1.1 bouyer static void ihidev_attach(device_t, device_t, void *); 113 1.1 bouyer static int ihidev_detach(device_t, int); 114 1.1 bouyer CFATTACH_DECL_NEW(ihidev, sizeof(struct ihidev_softc), 115 1.1 bouyer ihidev_match, ihidev_attach, ihidev_detach, NULL); 116 1.1 bouyer 117 1.21 riastrad static bool ihidev_intr_init(struct ihidev_softc *); 118 1.21 riastrad static void ihidev_intr_fini(struct ihidev_softc *); 119 1.12 thorpej 120 1.1 bouyer static bool ihidev_suspend(device_t, const pmf_qual_t *); 121 1.1 bouyer static bool ihidev_resume(device_t, const pmf_qual_t *); 122 1.1 bouyer static int ihidev_hid_command(struct ihidev_softc *, int, void *, bool); 123 1.30 andvar #if NACPICA > 0 124 1.7 jmcneill static int ihidev_intr(void *); 125 1.21 riastrad static void ihidev_work(struct work *, void *); 126 1.30 andvar #endif 127 1.33 jmcneill static int ihidev_poweron(struct ihidev_softc *, bool); 128 1.1 bouyer static int ihidev_reset(struct ihidev_softc *, bool); 129 1.1 bouyer static int ihidev_hid_desc_parse(struct ihidev_softc *); 130 1.1 bouyer 131 1.1 bouyer static int ihidev_maxrepid(void *, int); 132 1.1 bouyer static int ihidev_print(void *, const char *); 133 1.1 bouyer static int ihidev_submatch(device_t, cfdata_t, const int *, void *); 134 1.1 bouyer 135 1.17 thorpej static bool ihidev_acpi_get_info(struct ihidev_softc *); 136 1.17 thorpej 137 1.5 thorpej static const struct device_compatible_entry compat_data[] = { 138 1.16 thorpej { .compat = "PNP0C50" }, 139 1.16 thorpej { .compat = "ACPI0C50" }, 140 1.13 thorpej { .compat = "hid-over-i2c" }, 141 1.18 thorpej DEVICE_COMPAT_EOL 142 1.4 thorpej }; 143 1.4 thorpej 144 1.1 bouyer static int 145 1.1 bouyer ihidev_match(device_t parent, cfdata_t match, void *aux) 146 1.1 bouyer { 147 1.1 bouyer struct i2c_attach_args * const ia = aux; 148 1.3 thorpej int match_result; 149 1.3 thorpej 150 1.5 thorpej if (iic_use_direct_match(ia, match, compat_data, &match_result)) 151 1.29 riastrad return match_result; 152 1.1 bouyer 153 1.1 bouyer return 0; 154 1.1 bouyer } 155 1.1 bouyer 156 1.1 bouyer static void 157 1.1 bouyer ihidev_attach(device_t parent, device_t self, void *aux) 158 1.1 bouyer { 159 1.1 bouyer struct ihidev_softc *sc = device_private(self); 160 1.1 bouyer struct i2c_attach_args *ia = aux; 161 1.1 bouyer struct ihidev_attach_arg iha; 162 1.1 bouyer device_t dev; 163 1.1 bouyer int repid, repsz; 164 1.1 bouyer int isize; 165 1.1 bouyer int locs[IHIDBUSCF_NLOCS]; 166 1.1 bouyer 167 1.1 bouyer sc->sc_dev = self; 168 1.1 bouyer sc->sc_tag = ia->ia_tag; 169 1.1 bouyer sc->sc_addr = ia->ia_addr; 170 1.21 riastrad mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 171 1.1 bouyer 172 1.34 thorpej if (devhandle_type(device_handle(self)) != DEVHANDLE_TYPE_ACPI) { 173 1.17 thorpej aprint_error(": unsupported device tree type\n"); 174 1.17 thorpej return; 175 1.17 thorpej } 176 1.21 riastrad if (!ihidev_acpi_get_info(sc)) { 177 1.1 bouyer return; 178 1.1 bouyer } 179 1.1 bouyer 180 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_DESCR, NULL, false) || 181 1.1 bouyer ihidev_hid_desc_parse(sc)) { 182 1.1 bouyer aprint_error(": failed fetching initial HID descriptor\n"); 183 1.1 bouyer return; 184 1.1 bouyer } 185 1.1 bouyer 186 1.1 bouyer aprint_naive("\n"); 187 1.1 bouyer aprint_normal(": vendor 0x%x product 0x%x, %s\n", 188 1.1 bouyer le16toh(sc->hid_desc.wVendorID), le16toh(sc->hid_desc.wProductID), 189 1.1 bouyer ia->ia_name); 190 1.1 bouyer 191 1.1 bouyer sc->sc_nrepid = ihidev_maxrepid(sc->sc_report, sc->sc_reportlen); 192 1.1 bouyer if (sc->sc_nrepid < 0) 193 1.1 bouyer return; 194 1.1 bouyer 195 1.1 bouyer aprint_normal_dev(self, "%d report id%s\n", sc->sc_nrepid, 196 1.1 bouyer sc->sc_nrepid > 1 ? "s" : ""); 197 1.1 bouyer 198 1.1 bouyer sc->sc_nrepid++; 199 1.1 bouyer sc->sc_subdevs = kmem_zalloc(sc->sc_nrepid * sizeof(struct ihidev *), 200 1.9 chs KM_SLEEP); 201 1.1 bouyer 202 1.1 bouyer /* find largest report size and allocate memory for input buffer */ 203 1.1 bouyer sc->sc_isize = le16toh(sc->hid_desc.wMaxInputLength); 204 1.1 bouyer for (repid = 0; repid < sc->sc_nrepid; repid++) { 205 1.1 bouyer repsz = hid_report_size(sc->sc_report, sc->sc_reportlen, 206 1.1 bouyer hid_input, repid); 207 1.1 bouyer 208 1.1 bouyer isize = repsz + 2; /* two bytes for the length */ 209 1.1 bouyer isize += (sc->sc_nrepid != 1); /* one byte for the report ID */ 210 1.1 bouyer if (isize > sc->sc_isize) 211 1.1 bouyer sc->sc_isize = isize; 212 1.1 bouyer 213 1.28 riastrad DPRINTF(("%s: repid %d size %d\n", 214 1.28 riastrad device_xname(sc->sc_dev), repid, repsz)); 215 1.1 bouyer } 216 1.9 chs sc->sc_ibuf = kmem_zalloc(sc->sc_isize, KM_SLEEP); 217 1.21 riastrad if (!ihidev_intr_init(sc)) { 218 1.12 thorpej return; 219 1.1 bouyer } 220 1.1 bouyer 221 1.1 bouyer iha.iaa = ia; 222 1.1 bouyer iha.parent = sc; 223 1.1 bouyer 224 1.1 bouyer /* Look for a driver claiming all report IDs first. */ 225 1.1 bouyer iha.reportid = IHIDEV_CLAIM_ALLREPORTID; 226 1.1 bouyer locs[IHIDBUSCF_REPORTID] = IHIDEV_CLAIM_ALLREPORTID; 227 1.19 thorpej dev = config_found(self, &iha, ihidev_print, 228 1.20 thorpej CFARGS(.submatch = ihidev_submatch, 229 1.31 jmcneill .locators = locs, 230 1.31 jmcneill .iattr = "ihidbus")); 231 1.1 bouyer if (dev != NULL) { 232 1.1 bouyer for (repid = 0; repid < sc->sc_nrepid; repid++) 233 1.1 bouyer sc->sc_subdevs[repid] = device_private(dev); 234 1.1 bouyer return; 235 1.1 bouyer } 236 1.1 bouyer 237 1.1 bouyer for (repid = 0; repid < sc->sc_nrepid; repid++) { 238 1.1 bouyer if (hid_report_size(sc->sc_report, sc->sc_reportlen, hid_input, 239 1.1 bouyer repid) == 0 && 240 1.1 bouyer hid_report_size(sc->sc_report, sc->sc_reportlen, 241 1.1 bouyer hid_output, repid) == 0 && 242 1.1 bouyer hid_report_size(sc->sc_report, sc->sc_reportlen, 243 1.1 bouyer hid_feature, repid) == 0) 244 1.1 bouyer continue; 245 1.1 bouyer 246 1.1 bouyer iha.reportid = repid; 247 1.1 bouyer locs[IHIDBUSCF_REPORTID] = repid; 248 1.19 thorpej dev = config_found(self, &iha, ihidev_print, 249 1.20 thorpej CFARGS(.submatch = ihidev_submatch, 250 1.31 jmcneill .locators = locs, 251 1.31 jmcneill .iattr = "ihidbus")); 252 1.1 bouyer sc->sc_subdevs[repid] = device_private(dev); 253 1.1 bouyer } 254 1.1 bouyer 255 1.1 bouyer /* power down until we're opened */ 256 1.21 riastrad if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF, 257 1.21 riastrad false)) { 258 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power down\n"); 259 1.1 bouyer return; 260 1.1 bouyer } 261 1.1 bouyer if (!pmf_device_register(self, ihidev_suspend, ihidev_resume)) 262 1.1 bouyer aprint_error_dev(self, "couldn't establish power handler\n"); 263 1.1 bouyer } 264 1.1 bouyer 265 1.1 bouyer static int 266 1.1 bouyer ihidev_detach(device_t self, int flags) 267 1.1 bouyer { 268 1.1 bouyer struct ihidev_softc *sc = device_private(self); 269 1.21 riastrad int error; 270 1.21 riastrad 271 1.21 riastrad error = config_detach_children(self, flags); 272 1.21 riastrad if (error) 273 1.21 riastrad return error; 274 1.21 riastrad 275 1.21 riastrad pmf_device_deregister(self); 276 1.21 riastrad ihidev_intr_fini(sc); 277 1.21 riastrad 278 1.21 riastrad if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF, 279 1.21 riastrad true)) 280 1.21 riastrad aprint_error_dev(sc->sc_dev, "failed to power down\n"); 281 1.1 bouyer 282 1.1 bouyer if (sc->sc_ibuf != NULL) { 283 1.1 bouyer kmem_free(sc->sc_ibuf, sc->sc_isize); 284 1.1 bouyer sc->sc_ibuf = NULL; 285 1.1 bouyer } 286 1.1 bouyer 287 1.1 bouyer if (sc->sc_report != NULL) 288 1.1 bouyer kmem_free(sc->sc_report, sc->sc_reportlen); 289 1.1 bouyer 290 1.21 riastrad mutex_destroy(&sc->sc_lock); 291 1.21 riastrad 292 1.21 riastrad return 0; 293 1.1 bouyer } 294 1.1 bouyer 295 1.1 bouyer static bool 296 1.1 bouyer ihidev_suspend(device_t self, const pmf_qual_t *q) 297 1.1 bouyer { 298 1.1 bouyer struct ihidev_softc *sc = device_private(self); 299 1.1 bouyer 300 1.21 riastrad mutex_enter(&sc->sc_lock); 301 1.1 bouyer if (sc->sc_refcnt > 0) { 302 1.1 bouyer printf("ihidev power off\n"); 303 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 304 1.1 bouyer &I2C_HID_POWER_OFF, true)) 305 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power down\n"); 306 1.1 bouyer } 307 1.21 riastrad mutex_exit(&sc->sc_lock); 308 1.1 bouyer return true; 309 1.1 bouyer } 310 1.1 bouyer 311 1.1 bouyer static bool 312 1.1 bouyer ihidev_resume(device_t self, const pmf_qual_t *q) 313 1.1 bouyer { 314 1.1 bouyer struct ihidev_softc *sc = device_private(self); 315 1.1 bouyer 316 1.21 riastrad mutex_enter(&sc->sc_lock); 317 1.1 bouyer if (sc->sc_refcnt > 0) { 318 1.1 bouyer printf("ihidev power reset\n"); 319 1.1 bouyer ihidev_reset(sc, true); 320 1.1 bouyer } 321 1.21 riastrad mutex_exit(&sc->sc_lock); 322 1.1 bouyer return true; 323 1.1 bouyer } 324 1.1 bouyer 325 1.1 bouyer static int 326 1.1 bouyer ihidev_hid_command(struct ihidev_softc *sc, int hidcmd, void *arg, bool poll) 327 1.1 bouyer { 328 1.1 bouyer int i, res = 1; 329 1.1 bouyer int flags = poll ? I2C_F_POLL : 0; 330 1.1 bouyer 331 1.1 bouyer iic_acquire_bus(sc->sc_tag, flags); 332 1.1 bouyer 333 1.1 bouyer switch (hidcmd) { 334 1.1 bouyer case I2C_HID_CMD_DESCR: { 335 1.1 bouyer /* 336 1.1 bouyer * 5.2.2 - HID Descriptor Retrieval 337 1.1 bouyer * register is passed from the controller 338 1.1 bouyer */ 339 1.1 bouyer uint8_t cmd[] = { 340 1.1 bouyer htole16(sc->sc_hid_desc_addr) & 0xff, 341 1.1 bouyer htole16(sc->sc_hid_desc_addr) >> 8, 342 1.1 bouyer }; 343 1.1 bouyer 344 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_DESCR at 0x%x\n", 345 1.28 riastrad device_xname(sc->sc_dev), htole16(sc->sc_hid_desc_addr))); 346 1.1 bouyer 347 1.1 bouyer /* 20 00 */ 348 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 349 1.1 bouyer &cmd, sizeof(cmd), &sc->hid_desc_buf, 350 1.1 bouyer sizeof(struct i2c_hid_desc), flags); 351 1.1 bouyer 352 1.28 riastrad DPRINTF(("%s: HID descriptor:", device_xname(sc->sc_dev))); 353 1.1 bouyer for (i = 0; i < sizeof(struct i2c_hid_desc); i++) 354 1.1 bouyer DPRINTF((" %.2x", sc->hid_desc_buf[i])); 355 1.1 bouyer DPRINTF(("\n")); 356 1.1 bouyer 357 1.1 bouyer break; 358 1.1 bouyer } 359 1.1 bouyer case I2C_HID_CMD_RESET: { 360 1.1 bouyer uint8_t cmd[] = { 361 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff, 362 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8, 363 1.1 bouyer 0, 364 1.1 bouyer I2C_HID_CMD_RESET, 365 1.1 bouyer }; 366 1.1 bouyer 367 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_RESET\n", 368 1.28 riastrad device_xname(sc->sc_dev))); 369 1.1 bouyer 370 1.1 bouyer /* 22 00 00 01 */ 371 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 372 1.1 bouyer &cmd, sizeof(cmd), NULL, 0, flags); 373 1.1 bouyer 374 1.1 bouyer break; 375 1.1 bouyer } 376 1.1 bouyer case I2C_HID_CMD_GET_REPORT: { 377 1.1 bouyer struct i2c_hid_report_request *rreq = 378 1.1 bouyer (struct i2c_hid_report_request *)arg; 379 1.1 bouyer 380 1.1 bouyer uint8_t cmd[] = { 381 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff, 382 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8, 383 1.1 bouyer 0, 384 1.1 bouyer I2C_HID_CMD_GET_REPORT, 385 1.1 bouyer 0, 0, 0, 386 1.1 bouyer }; 387 1.1 bouyer int cmdlen = 7; 388 1.1 bouyer int dataoff = 4; 389 1.1 bouyer int report_id = rreq->id; 390 1.1 bouyer int report_id_len = 1; 391 1.1 bouyer int report_len = rreq->len + 2; 392 1.1 bouyer int d; 393 1.1 bouyer uint8_t *tmprep; 394 1.1 bouyer 395 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_GET_REPORT %d " 396 1.28 riastrad "(type %d, len %d)\n", device_xname(sc->sc_dev), report_id, 397 1.1 bouyer rreq->type, rreq->len)); 398 1.1 bouyer 399 1.1 bouyer /* 400 1.1 bouyer * 7.2.2.4 - "The protocol is optimized for Report < 15. If a 401 1.1 bouyer * report ID >= 15 is necessary, then the Report ID in the Low 402 1.1 bouyer * Byte must be set to 1111 and a Third Byte is appended to the 403 1.1 bouyer * protocol. This Third Byte contains the entire/actual report 404 1.1 bouyer * ID." 405 1.1 bouyer */ 406 1.1 bouyer if (report_id >= 15) { 407 1.1 bouyer cmd[dataoff++] = report_id; 408 1.1 bouyer report_id = 15; 409 1.1 bouyer report_id_len = 2; 410 1.1 bouyer } else 411 1.1 bouyer cmdlen--; 412 1.1 bouyer 413 1.1 bouyer cmd[2] = report_id | rreq->type << 4; 414 1.1 bouyer 415 1.1 bouyer cmd[dataoff++] = sc->hid_desc.wDataRegister & 0xff; 416 1.1 bouyer cmd[dataoff] = sc->hid_desc.wDataRegister >> 8; 417 1.1 bouyer 418 1.1 bouyer /* 419 1.1 bouyer * 7.2.2.2 - Response will be a 2-byte length value, the report 420 1.1 bouyer * id with length determined above, and then the report. 421 1.1 bouyer * Allocate rreq->len + 2 + 2 bytes, read into that temporary 422 1.1 bouyer * buffer, and then copy only the report back out to 423 1.1 bouyer * rreq->data. 424 1.1 bouyer */ 425 1.1 bouyer report_len += report_id_len; 426 1.1 bouyer tmprep = kmem_zalloc(report_len, KM_NOSLEEP); 427 1.23 riastrad if (tmprep == NULL) { 428 1.23 riastrad /* XXX pool or preallocate? */ 429 1.23 riastrad DPRINTF(("%s: out of memory\n", 430 1.23 riastrad device_xname(sc->sc_dev))); 431 1.23 riastrad res = ENOMEM; 432 1.23 riastrad break; 433 1.23 riastrad } 434 1.1 bouyer 435 1.1 bouyer /* type 3 id 8: 22 00 38 02 23 00 */ 436 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 437 1.1 bouyer &cmd, cmdlen, tmprep, report_len, flags); 438 1.1 bouyer 439 1.1 bouyer d = tmprep[0] | tmprep[1] << 8; 440 1.1 bouyer if (d != report_len) { 441 1.1 bouyer DPRINTF(("%s: response size %d != expected length %d\n", 442 1.28 riastrad device_xname(sc->sc_dev), d, report_len)); 443 1.1 bouyer } 444 1.1 bouyer 445 1.1 bouyer if (report_id_len == 2) 446 1.1 bouyer d = tmprep[2] | tmprep[3] << 8; 447 1.1 bouyer else 448 1.1 bouyer d = tmprep[2]; 449 1.1 bouyer 450 1.1 bouyer if (d != rreq->id) { 451 1.1 bouyer DPRINTF(("%s: response report id %d != %d\n", 452 1.28 riastrad device_xname(sc->sc_dev), d, rreq->id)); 453 1.1 bouyer iic_release_bus(sc->sc_tag, 0); 454 1.1 bouyer kmem_free(tmprep, report_len); 455 1.1 bouyer return (1); 456 1.1 bouyer } 457 1.1 bouyer 458 1.28 riastrad DPRINTF(("%s: response:", device_xname(sc->sc_dev))); 459 1.1 bouyer for (i = 0; i < report_len; i++) 460 1.1 bouyer DPRINTF((" %.2x", tmprep[i])); 461 1.1 bouyer DPRINTF(("\n")); 462 1.1 bouyer 463 1.1 bouyer memcpy(rreq->data, tmprep + 2 + report_id_len, rreq->len); 464 1.1 bouyer kmem_free(tmprep, report_len); 465 1.1 bouyer 466 1.1 bouyer break; 467 1.1 bouyer } 468 1.1 bouyer case I2C_HID_CMD_SET_REPORT: { 469 1.1 bouyer struct i2c_hid_report_request *rreq = 470 1.1 bouyer (struct i2c_hid_report_request *)arg; 471 1.1 bouyer 472 1.1 bouyer uint8_t cmd[] = { 473 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff, 474 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8, 475 1.1 bouyer 0, 476 1.1 bouyer I2C_HID_CMD_SET_REPORT, 477 1.1 bouyer 0, 0, 0, 0, 0, 0, 478 1.1 bouyer }; 479 1.1 bouyer int cmdlen = 10; 480 1.1 bouyer int report_id = rreq->id; 481 1.1 bouyer int report_len = 2 + (report_id ? 1 : 0) + rreq->len; 482 1.1 bouyer int dataoff; 483 1.1 bouyer uint8_t *finalcmd; 484 1.1 bouyer 485 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_SET_REPORT %d " 486 1.28 riastrad "(type %d, len %d):", device_xname(sc->sc_dev), report_id, 487 1.1 bouyer rreq->type, rreq->len)); 488 1.1 bouyer for (i = 0; i < rreq->len; i++) 489 1.1 bouyer DPRINTF((" %.2x", ((uint8_t *)rreq->data)[i])); 490 1.1 bouyer DPRINTF(("\n")); 491 1.1 bouyer 492 1.1 bouyer /* 493 1.1 bouyer * 7.2.2.4 - "The protocol is optimized for Report < 15. If a 494 1.1 bouyer * report ID >= 15 is necessary, then the Report ID in the Low 495 1.1 bouyer * Byte must be set to 1111 and a Third Byte is appended to the 496 1.1 bouyer * protocol. This Third Byte contains the entire/actual report 497 1.1 bouyer * ID." 498 1.1 bouyer */ 499 1.1 bouyer dataoff = 4; 500 1.1 bouyer if (report_id >= 15) { 501 1.1 bouyer cmd[dataoff++] = report_id; 502 1.1 bouyer report_id = 15; 503 1.1 bouyer } else 504 1.1 bouyer cmdlen--; 505 1.1 bouyer 506 1.1 bouyer cmd[2] = report_id | rreq->type << 4; 507 1.1 bouyer 508 1.1 bouyer if (rreq->type == I2C_HID_REPORT_TYPE_FEATURE) { 509 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister) 510 1.1 bouyer & 0xff; 511 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister) 512 1.1 bouyer >> 8; 513 1.1 bouyer } else { 514 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister) 515 1.1 bouyer & 0xff; 516 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister) 517 1.1 bouyer >> 8; 518 1.1 bouyer } 519 1.1 bouyer 520 1.1 bouyer cmd[dataoff++] = report_len & 0xff; 521 1.1 bouyer cmd[dataoff++] = report_len >> 8; 522 1.1 bouyer cmd[dataoff] = rreq->id; 523 1.1 bouyer 524 1.1 bouyer finalcmd = kmem_zalloc(cmdlen + rreq->len, KM_NOSLEEP); 525 1.23 riastrad if (finalcmd == NULL) { 526 1.23 riastrad res = ENOMEM; 527 1.23 riastrad break; 528 1.23 riastrad } 529 1.1 bouyer 530 1.1 bouyer memcpy(finalcmd, cmd, cmdlen); 531 1.1 bouyer memcpy(finalcmd + cmdlen, rreq->data, rreq->len); 532 1.1 bouyer 533 1.1 bouyer /* type 3 id 4: 22 00 34 03 23 00 04 00 04 03 */ 534 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 535 1.1 bouyer finalcmd, cmdlen + rreq->len, NULL, 0, flags); 536 1.1 bouyer kmem_free(finalcmd, cmdlen + rreq->len); 537 1.1 bouyer 538 1.1 bouyer break; 539 1.1 bouyer } 540 1.1 bouyer 541 1.1 bouyer case I2C_HID_CMD_SET_POWER: { 542 1.1 bouyer int power = *(int *)arg; 543 1.1 bouyer uint8_t cmd[] = { 544 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff, 545 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8, 546 1.1 bouyer power, 547 1.1 bouyer I2C_HID_CMD_SET_POWER, 548 1.1 bouyer }; 549 1.1 bouyer 550 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_SET_POWER(%d)\n", 551 1.28 riastrad device_xname(sc->sc_dev), power)); 552 1.1 bouyer 553 1.1 bouyer /* 22 00 00 08 */ 554 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 555 1.1 bouyer &cmd, sizeof(cmd), NULL, 0, flags); 556 1.1 bouyer 557 1.1 bouyer break; 558 1.1 bouyer } 559 1.1 bouyer case I2C_HID_REPORT_DESCR: { 560 1.1 bouyer uint8_t cmd[] = { 561 1.1 bouyer htole16(sc->hid_desc.wReportDescRegister) & 0xff, 562 1.1 bouyer htole16(sc->hid_desc.wReportDescRegister) >> 8, 563 1.1 bouyer }; 564 1.1 bouyer 565 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_REPORT_DESCR at 0x%x with " 566 1.28 riastrad "size %d\n", device_xname(sc->sc_dev), cmd[0], 567 1.1 bouyer sc->sc_reportlen)); 568 1.1 bouyer 569 1.1 bouyer /* 20 00 */ 570 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 571 1.1 bouyer &cmd, sizeof(cmd), sc->sc_report, sc->sc_reportlen, flags); 572 1.1 bouyer 573 1.28 riastrad DPRINTF(("%s: HID report descriptor:", 574 1.28 riastrad device_xname(sc->sc_dev))); 575 1.1 bouyer for (i = 0; i < sc->sc_reportlen; i++) 576 1.1 bouyer DPRINTF((" %.2x", sc->sc_report[i])); 577 1.1 bouyer DPRINTF(("\n")); 578 1.1 bouyer 579 1.1 bouyer break; 580 1.1 bouyer } 581 1.1 bouyer default: 582 1.1 bouyer aprint_error_dev(sc->sc_dev, "unknown command %d\n", 583 1.1 bouyer hidcmd); 584 1.1 bouyer } 585 1.1 bouyer 586 1.1 bouyer iic_release_bus(sc->sc_tag, flags); 587 1.1 bouyer 588 1.1 bouyer return (res); 589 1.1 bouyer } 590 1.1 bouyer 591 1.1 bouyer static int 592 1.33 jmcneill ihidev_poweron(struct ihidev_softc *sc, bool poll) 593 1.1 bouyer { 594 1.33 jmcneill DPRINTF(("%s: poweron\n", device_xname(sc->sc_dev))); 595 1.1 bouyer 596 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 597 1.1 bouyer &I2C_HID_POWER_ON, poll)) { 598 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power on\n"); 599 1.1 bouyer return (1); 600 1.1 bouyer } 601 1.1 bouyer 602 1.1 bouyer DELAY(1000); 603 1.1 bouyer 604 1.33 jmcneill return (0); 605 1.33 jmcneill } 606 1.33 jmcneill 607 1.33 jmcneill static int 608 1.33 jmcneill ihidev_reset(struct ihidev_softc *sc, bool poll) 609 1.33 jmcneill { 610 1.33 jmcneill DPRINTF(("%s: resetting\n", device_xname(sc->sc_dev))); 611 1.33 jmcneill 612 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_RESET, 0, poll)) { 613 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to reset hardware\n"); 614 1.1 bouyer 615 1.1 bouyer ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 616 1.1 bouyer &I2C_HID_POWER_OFF, poll); 617 1.1 bouyer 618 1.1 bouyer return (1); 619 1.1 bouyer } 620 1.1 bouyer 621 1.1 bouyer DELAY(1000); 622 1.1 bouyer 623 1.1 bouyer return (0); 624 1.1 bouyer } 625 1.1 bouyer 626 1.1 bouyer /* 627 1.1 bouyer * 5.2.2 - HID Descriptor Retrieval 628 1.1 bouyer * 629 1.1 bouyer * parse HID Descriptor that has already been read into hid_desc with 630 1.1 bouyer * I2C_HID_CMD_DESCR 631 1.1 bouyer */ 632 1.1 bouyer static int 633 1.1 bouyer ihidev_hid_desc_parse(struct ihidev_softc *sc) 634 1.1 bouyer { 635 1.1 bouyer int retries = 3; 636 1.1 bouyer 637 1.1 bouyer /* must be v01.00 */ 638 1.1 bouyer if (le16toh(sc->hid_desc.bcdVersion) != 0x0100) { 639 1.1 bouyer aprint_error_dev(sc->sc_dev, 640 1.1 bouyer "bad HID descriptor bcdVersion (0x%x)\n", 641 1.1 bouyer le16toh(sc->hid_desc.bcdVersion)); 642 1.1 bouyer return (1); 643 1.1 bouyer } 644 1.1 bouyer 645 1.1 bouyer /* must be 30 bytes for v1.00 */ 646 1.1 bouyer if (le16toh(sc->hid_desc.wHIDDescLength != 647 1.1 bouyer sizeof(struct i2c_hid_desc))) { 648 1.1 bouyer aprint_error_dev(sc->sc_dev, 649 1.1 bouyer "bad HID descriptor size (%d != %zu)\n", 650 1.1 bouyer le16toh(sc->hid_desc.wHIDDescLength), 651 1.1 bouyer sizeof(struct i2c_hid_desc)); 652 1.1 bouyer return (1); 653 1.1 bouyer } 654 1.1 bouyer 655 1.1 bouyer if (le16toh(sc->hid_desc.wReportDescLength) <= 0) { 656 1.1 bouyer aprint_error_dev(sc->sc_dev, 657 1.1 bouyer "bad HID report descriptor size (%d)\n", 658 1.1 bouyer le16toh(sc->hid_desc.wReportDescLength)); 659 1.1 bouyer return (1); 660 1.1 bouyer } 661 1.1 bouyer 662 1.1 bouyer while (retries-- > 0) { 663 1.1 bouyer if (ihidev_reset(sc, false)) { 664 1.1 bouyer if (retries == 0) 665 1.1 bouyer return(1); 666 1.1 bouyer 667 1.1 bouyer DELAY(1000); 668 1.1 bouyer } 669 1.1 bouyer else 670 1.1 bouyer break; 671 1.1 bouyer } 672 1.1 bouyer 673 1.1 bouyer sc->sc_reportlen = le16toh(sc->hid_desc.wReportDescLength); 674 1.22 riastrad sc->sc_report = kmem_zalloc(sc->sc_reportlen, KM_SLEEP); 675 1.1 bouyer 676 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_REPORT_DESCR, 0, false)) { 677 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed fetching HID report\n"); 678 1.1 bouyer return (1); 679 1.1 bouyer } 680 1.1 bouyer 681 1.1 bouyer return (0); 682 1.1 bouyer } 683 1.1 bouyer 684 1.12 thorpej static bool 685 1.21 riastrad ihidev_intr_init(struct ihidev_softc *sc) 686 1.12 thorpej { 687 1.12 thorpej #if NACPICA > 0 688 1.34 thorpej ACPI_HANDLE hdl = devhandle_to_acpi(device_handle(sc->sc_dev)); 689 1.12 thorpej struct acpi_resources res; 690 1.12 thorpej ACPI_STATUS rv; 691 1.12 thorpej char buf[100]; 692 1.12 thorpej 693 1.12 thorpej rv = acpi_resource_parse(sc->sc_dev, hdl, "_CRS", &res, 694 1.12 thorpej &acpi_resource_parse_ops_quiet); 695 1.12 thorpej if (ACPI_FAILURE(rv)) { 696 1.12 thorpej aprint_error_dev(sc->sc_dev, "can't parse '_CRS'\n"); 697 1.12 thorpej return false; 698 1.12 thorpej } 699 1.12 thorpej 700 1.12 thorpej const struct acpi_irq * const irq = acpi_res_irq(&res, 0); 701 1.12 thorpej if (irq == NULL) { 702 1.31 jmcneill aprint_debug_dev(sc->sc_dev, "no IRQ resource\n"); 703 1.12 thorpej acpi_resource_cleanup(&res); 704 1.31 jmcneill #if NGPIO > 0 705 1.31 jmcneill goto try_gpioint; 706 1.31 jmcneill #else 707 1.12 thorpej return false; 708 1.31 jmcneill #endif 709 1.12 thorpej } 710 1.12 thorpej 711 1.12 thorpej sc->sc_intr_type = 712 1.12 thorpej irq->ar_type == ACPI_EDGE_SENSITIVE ? IST_EDGE : IST_LEVEL; 713 1.12 thorpej 714 1.12 thorpej acpi_resource_cleanup(&res); 715 1.12 thorpej 716 1.34 thorpej sc->sc_ih = acpi_intr_establish(sc->sc_dev, 717 1.34 thorpej (uint64_t)(uintptr_t)hdl, 718 1.34 thorpej IPL_TTY, false, ihidev_intr, sc, device_xname(sc->sc_dev)); 719 1.12 thorpej if (sc->sc_ih == NULL) { 720 1.12 thorpej aprint_error_dev(sc->sc_dev, "can't establish interrupt\n"); 721 1.12 thorpej return false; 722 1.12 thorpej } 723 1.12 thorpej aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", 724 1.12 thorpej acpi_intr_string(sc->sc_ih, buf, sizeof(buf))); 725 1.12 thorpej 726 1.31 jmcneill #if NGPIO > 0 727 1.31 jmcneill try_gpioint: 728 1.31 jmcneill if (sc->sc_ih == NULL) { 729 1.31 jmcneill int pin, irqmode, error; 730 1.31 jmcneill 731 1.31 jmcneill rv = acpi_gpio_get_int(hdl, 0, &sc->sc_ih_gpio, &pin, &irqmode); 732 1.31 jmcneill if (ACPI_FAILURE(rv)) { 733 1.31 jmcneill aprint_error_dev(sc->sc_dev, 734 1.31 jmcneill "can't find gpioint resource\n"); 735 1.31 jmcneill return false; 736 1.31 jmcneill } 737 1.31 jmcneill 738 1.31 jmcneill sc->sc_ih_gpiomap.pm_map = sc->sc_ih_gpiopins; 739 1.31 jmcneill error = gpio_pin_map(sc->sc_ih_gpio, pin, 1, 740 1.31 jmcneill &sc->sc_ih_gpiomap); 741 1.31 jmcneill if (error) { 742 1.31 jmcneill aprint_error_dev(sc->sc_dev, "can't map pin %d\n", pin); 743 1.31 jmcneill return false; 744 1.31 jmcneill } 745 1.31 jmcneill 746 1.31 jmcneill sc->sc_ih = gpio_intr_establish(sc->sc_ih_gpio, 747 1.31 jmcneill &sc->sc_ih_gpiomap, 0, IPL_VM, irqmode, ihidev_intr, sc); 748 1.31 jmcneill if (sc->sc_ih == NULL) { 749 1.31 jmcneill aprint_error_dev(sc->sc_dev, 750 1.31 jmcneill "can't establish gpio interrupt\n"); 751 1.31 jmcneill return false; 752 1.31 jmcneill } 753 1.31 jmcneill 754 1.31 jmcneill sc->sc_intr_type = (irqmode & GPIO_INTR_LEVEL_MASK) ? 755 1.31 jmcneill IST_LEVEL : IST_EDGE; 756 1.31 jmcneill 757 1.31 jmcneill gpio_intr_str(sc->sc_ih_gpio, &sc->sc_ih_gpiomap, 0, 758 1.31 jmcneill irqmode, buf, sizeof(buf)); 759 1.31 jmcneill aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", buf); 760 1.31 jmcneill } 761 1.31 jmcneill #endif 762 1.31 jmcneill 763 1.21 riastrad if (workqueue_create(&sc->sc_wq, device_xname(sc->sc_dev), ihidev_work, 764 1.21 riastrad sc, PRI_NONE, IPL_TTY, WQ_MPSAFE)) { 765 1.12 thorpej aprint_error_dev(sc->sc_dev, 766 1.21 riastrad "can't establish workqueue\n"); 767 1.12 thorpej return false; 768 1.12 thorpej } 769 1.21 riastrad sc->sc_work_pending = 0; 770 1.12 thorpej 771 1.12 thorpej return true; 772 1.12 thorpej #else 773 1.12 thorpej aprint_error_dev(sc->sc_dev, "can't establish interrupt\n"); 774 1.12 thorpej return false; 775 1.12 thorpej #endif 776 1.12 thorpej } 777 1.12 thorpej 778 1.12 thorpej static void 779 1.21 riastrad ihidev_intr_fini(struct ihidev_softc *sc) 780 1.12 thorpej { 781 1.12 thorpej #if NACPICA > 0 782 1.12 thorpej if (sc->sc_ih != NULL) { 783 1.31 jmcneill if (sc->sc_ih_gpio != NULL) { 784 1.31 jmcneill #if NGPIO > 0 785 1.31 jmcneill gpio_intr_disestablish(sc->sc_ih_gpio, sc->sc_ih); 786 1.31 jmcneill #endif 787 1.31 jmcneill } else { 788 1.31 jmcneill acpi_intr_disestablish(sc->sc_ih); 789 1.31 jmcneill } 790 1.12 thorpej } 791 1.21 riastrad if (sc->sc_wq != NULL) { 792 1.21 riastrad workqueue_destroy(sc->sc_wq); 793 1.12 thorpej } 794 1.12 thorpej #endif 795 1.12 thorpej } 796 1.12 thorpej 797 1.30 andvar #if NACPICA > 0 798 1.12 thorpej static void 799 1.12 thorpej ihidev_intr_mask(struct ihidev_softc * const sc) 800 1.12 thorpej { 801 1.12 thorpej 802 1.12 thorpej if (sc->sc_intr_type == IST_LEVEL) { 803 1.31 jmcneill if (sc->sc_ih_gpio != NULL) { 804 1.31 jmcneill #if NGPIO > 0 805 1.31 jmcneill gpio_intr_mask(sc->sc_ih_gpio, sc->sc_ih); 806 1.31 jmcneill #endif 807 1.31 jmcneill } else { 808 1.31 jmcneill acpi_intr_mask(sc->sc_ih); 809 1.31 jmcneill } 810 1.12 thorpej } 811 1.12 thorpej } 812 1.12 thorpej 813 1.12 thorpej static void 814 1.12 thorpej ihidev_intr_unmask(struct ihidev_softc * const sc) 815 1.12 thorpej { 816 1.12 thorpej 817 1.12 thorpej if (sc->sc_intr_type == IST_LEVEL) { 818 1.31 jmcneill if (sc->sc_ih_gpio != NULL) { 819 1.31 jmcneill #if NGPIO > 0 820 1.31 jmcneill gpio_intr_unmask(sc->sc_ih_gpio, sc->sc_ih); 821 1.31 jmcneill #endif 822 1.31 jmcneill } else { 823 1.31 jmcneill acpi_intr_unmask(sc->sc_ih); 824 1.31 jmcneill } 825 1.12 thorpej } 826 1.12 thorpej } 827 1.12 thorpej 828 1.7 jmcneill static int 829 1.1 bouyer ihidev_intr(void *arg) 830 1.1 bouyer { 831 1.12 thorpej struct ihidev_softc * const sc = arg; 832 1.12 thorpej 833 1.12 thorpej /* 834 1.21 riastrad * Schedule our work. If we're using a level-triggered 835 1.21 riastrad * interrupt, we have to mask it off while we wait for service. 836 1.12 thorpej */ 837 1.21 riastrad if (atomic_swap_uint(&sc->sc_work_pending, 1) == 0) 838 1.21 riastrad workqueue_enqueue(sc->sc_wq, &sc->sc_work, NULL); 839 1.12 thorpej ihidev_intr_mask(sc); 840 1.12 thorpej 841 1.12 thorpej return 1; 842 1.12 thorpej } 843 1.12 thorpej 844 1.12 thorpej static void 845 1.21 riastrad ihidev_work(struct work *wk, void *arg) 846 1.12 thorpej { 847 1.12 thorpej struct ihidev_softc * const sc = arg; 848 1.1 bouyer struct ihidev *scd; 849 1.1 bouyer u_int psize; 850 1.1 bouyer int res, i; 851 1.1 bouyer u_char *p; 852 1.1 bouyer u_int rep = 0; 853 1.1 bouyer 854 1.21 riastrad atomic_store_relaxed(&sc->sc_work_pending, 0); 855 1.21 riastrad 856 1.21 riastrad mutex_enter(&sc->sc_lock); 857 1.21 riastrad 858 1.12 thorpej iic_acquire_bus(sc->sc_tag, 0); 859 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0, 860 1.12 thorpej sc->sc_ibuf, sc->sc_isize, 0); 861 1.12 thorpej iic_release_bus(sc->sc_tag, 0); 862 1.1 bouyer if (res != 0) 863 1.12 thorpej goto out; 864 1.1 bouyer 865 1.1 bouyer /* 866 1.1 bouyer * 6.1.1 - First two bytes are the packet length, which must be less 867 1.1 bouyer * than or equal to wMaxInputLength 868 1.1 bouyer */ 869 1.1 bouyer psize = sc->sc_ibuf[0] | sc->sc_ibuf[1] << 8; 870 1.1 bouyer if (!psize || psize > sc->sc_isize) { 871 1.1 bouyer DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n", 872 1.28 riastrad device_xname(sc->sc_dev), __func__, psize, sc->sc_isize)); 873 1.12 thorpej goto out; 874 1.1 bouyer } 875 1.1 bouyer 876 1.1 bouyer /* 3rd byte is the report id */ 877 1.1 bouyer p = sc->sc_ibuf + 2; 878 1.1 bouyer psize -= 2; 879 1.1 bouyer if (sc->sc_nrepid != 1) 880 1.1 bouyer rep = *p++, psize--; 881 1.1 bouyer 882 1.1 bouyer if (rep >= sc->sc_nrepid) { 883 1.1 bouyer aprint_error_dev(sc->sc_dev, "%s: bad report id %d\n", 884 1.1 bouyer __func__, rep); 885 1.12 thorpej goto out; 886 1.1 bouyer } 887 1.1 bouyer 888 1.28 riastrad DPRINTF(("%s: %s: hid input (rep %d):", device_xname(sc->sc_dev), 889 1.12 thorpej __func__, rep)); 890 1.1 bouyer for (i = 0; i < sc->sc_isize; i++) 891 1.1 bouyer DPRINTF((" %.2x", sc->sc_ibuf[i])); 892 1.1 bouyer DPRINTF(("\n")); 893 1.1 bouyer 894 1.1 bouyer scd = sc->sc_subdevs[rep]; 895 1.1 bouyer if (scd == NULL || !(scd->sc_state & IHIDEV_OPEN)) 896 1.12 thorpej goto out; 897 1.1 bouyer 898 1.1 bouyer scd->sc_intr(scd, p, psize); 899 1.1 bouyer 900 1.12 thorpej out: 901 1.21 riastrad mutex_exit(&sc->sc_lock); 902 1.21 riastrad 903 1.12 thorpej /* 904 1.12 thorpej * If our interrupt is level-triggered, re-enable it now. 905 1.12 thorpej */ 906 1.12 thorpej ihidev_intr_unmask(sc); 907 1.1 bouyer } 908 1.30 andvar #endif 909 1.1 bouyer 910 1.1 bouyer static int 911 1.1 bouyer ihidev_maxrepid(void *buf, int len) 912 1.1 bouyer { 913 1.1 bouyer struct hid_data *d; 914 1.1 bouyer struct hid_item h; 915 1.1 bouyer int maxid; 916 1.1 bouyer 917 1.1 bouyer maxid = -1; 918 1.1 bouyer h.report_ID = 0; 919 1.1 bouyer for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); ) 920 1.6 jakllsch if ((int)h.report_ID > maxid) 921 1.1 bouyer maxid = h.report_ID; 922 1.1 bouyer hid_end_parse(d); 923 1.1 bouyer 924 1.1 bouyer return (maxid); 925 1.1 bouyer } 926 1.1 bouyer 927 1.1 bouyer static int 928 1.1 bouyer ihidev_print(void *aux, const char *pnp) 929 1.1 bouyer { 930 1.1 bouyer struct ihidev_attach_arg *iha = aux; 931 1.1 bouyer 932 1.1 bouyer if (iha->reportid == IHIDEV_CLAIM_ALLREPORTID) 933 1.1 bouyer return (QUIET); 934 1.21 riastrad 935 1.1 bouyer if (pnp) 936 1.1 bouyer aprint_normal("hid at %s", pnp); 937 1.1 bouyer 938 1.1 bouyer if (iha->reportid != 0) 939 1.1 bouyer aprint_normal(" reportid %d", iha->reportid); 940 1.1 bouyer 941 1.1 bouyer return (UNCONF); 942 1.1 bouyer } 943 1.1 bouyer 944 1.1 bouyer static int 945 1.1 bouyer ihidev_submatch(device_t parent, cfdata_t cf, const int *locs, void *aux) 946 1.1 bouyer { 947 1.1 bouyer struct ihidev_attach_arg *iha = aux; 948 1.1 bouyer 949 1.1 bouyer if (cf->ihidevcf_reportid != IHIDEV_UNK_REPORTID && 950 1.1 bouyer cf->ihidevcf_reportid != iha->reportid) 951 1.1 bouyer return (0); 952 1.1 bouyer 953 1.1 bouyer return config_match(parent, cf, aux); 954 1.1 bouyer } 955 1.1 bouyer 956 1.1 bouyer int 957 1.1 bouyer ihidev_open(struct ihidev *scd) 958 1.1 bouyer { 959 1.1 bouyer struct ihidev_softc *sc = scd->sc_parent; 960 1.24 riastrad int error; 961 1.1 bouyer 962 1.28 riastrad DPRINTF(("%s: %s: state=%d refcnt=%d\n", device_xname(sc->sc_dev), 963 1.1 bouyer __func__, scd->sc_state, sc->sc_refcnt)); 964 1.1 bouyer 965 1.24 riastrad mutex_enter(&sc->sc_lock); 966 1.24 riastrad 967 1.25 riastrad if (scd->sc_state & IHIDEV_OPEN || sc->sc_refcnt == INT_MAX) { 968 1.24 riastrad error = EBUSY; 969 1.24 riastrad goto out; 970 1.24 riastrad } 971 1.1 bouyer 972 1.1 bouyer scd->sc_state |= IHIDEV_OPEN; 973 1.1 bouyer 974 1.24 riastrad if (sc->sc_refcnt++ || sc->sc_isize == 0) { 975 1.24 riastrad error = 0; 976 1.24 riastrad goto out; 977 1.24 riastrad } 978 1.1 bouyer 979 1.1 bouyer /* power on */ 980 1.33 jmcneill ihidev_poweron(sc, false); 981 1.24 riastrad error = 0; 982 1.1 bouyer 983 1.24 riastrad out: mutex_exit(&sc->sc_lock); 984 1.24 riastrad return error; 985 1.1 bouyer } 986 1.1 bouyer 987 1.1 bouyer void 988 1.1 bouyer ihidev_close(struct ihidev *scd) 989 1.1 bouyer { 990 1.1 bouyer struct ihidev_softc *sc = scd->sc_parent; 991 1.1 bouyer 992 1.28 riastrad DPRINTF(("%s: %s: state=%d refcnt=%d\n", device_xname(sc->sc_dev), 993 1.1 bouyer __func__, scd->sc_state, sc->sc_refcnt)); 994 1.1 bouyer 995 1.24 riastrad mutex_enter(&sc->sc_lock); 996 1.24 riastrad 997 1.26 riastrad KASSERTMSG(scd->sc_state & IHIDEV_OPEN, 998 1.26 riastrad "%s: closing %s when not open", 999 1.26 riastrad device_xname(scd->sc_idev), 1000 1.26 riastrad device_xname(sc->sc_dev)); 1001 1.1 bouyer scd->sc_state &= ~IHIDEV_OPEN; 1002 1.1 bouyer 1003 1.1 bouyer if (--sc->sc_refcnt) 1004 1.24 riastrad goto out; 1005 1.1 bouyer 1006 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 1007 1.1 bouyer &I2C_HID_POWER_OFF, false)) 1008 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power down\n"); 1009 1.24 riastrad 1010 1.24 riastrad out: mutex_exit(&sc->sc_lock); 1011 1.1 bouyer } 1012 1.1 bouyer 1013 1.1 bouyer void 1014 1.1 bouyer ihidev_get_report_desc(struct ihidev_softc *sc, void **desc, int *size) 1015 1.1 bouyer { 1016 1.1 bouyer *desc = sc->sc_report; 1017 1.1 bouyer *size = sc->sc_reportlen; 1018 1.1 bouyer } 1019 1.1 bouyer 1020 1.1 bouyer /* convert hid_* constants used throughout HID code to i2c HID equivalents */ 1021 1.1 bouyer int 1022 1.1 bouyer ihidev_report_type_conv(int hid_type_id) 1023 1.1 bouyer { 1024 1.1 bouyer switch (hid_type_id) { 1025 1.1 bouyer case hid_input: 1026 1.1 bouyer return I2C_HID_REPORT_TYPE_INPUT; 1027 1.1 bouyer case hid_output: 1028 1.1 bouyer return I2C_HID_REPORT_TYPE_OUTPUT; 1029 1.1 bouyer case hid_feature: 1030 1.1 bouyer return I2C_HID_REPORT_TYPE_FEATURE; 1031 1.1 bouyer default: 1032 1.1 bouyer return -1; 1033 1.1 bouyer } 1034 1.1 bouyer } 1035 1.1 bouyer 1036 1.1 bouyer int 1037 1.1 bouyer ihidev_get_report(struct device *dev, int type, int id, void *data, int len) 1038 1.1 bouyer { 1039 1.1 bouyer struct ihidev_softc *sc = (struct ihidev_softc *)dev; 1040 1.1 bouyer struct i2c_hid_report_request rreq; 1041 1.1 bouyer int ctype; 1042 1.1 bouyer 1043 1.1 bouyer if ((ctype = ihidev_report_type_conv(type)) < 0) 1044 1.1 bouyer return (1); 1045 1.1 bouyer 1046 1.1 bouyer rreq.type = ctype; 1047 1.1 bouyer rreq.id = id; 1048 1.1 bouyer rreq.data = data; 1049 1.1 bouyer rreq.len = len; 1050 1.1 bouyer 1051 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_GET_REPORT, &rreq, false)) { 1052 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed fetching report\n"); 1053 1.1 bouyer return (1); 1054 1.1 bouyer } 1055 1.1 bouyer 1056 1.1 bouyer return 0; 1057 1.1 bouyer } 1058 1.1 bouyer 1059 1.1 bouyer int 1060 1.1 bouyer ihidev_set_report(struct device *dev, int type, int id, void *data, 1061 1.1 bouyer int len) 1062 1.1 bouyer { 1063 1.1 bouyer struct ihidev_softc *sc = (struct ihidev_softc *)dev; 1064 1.1 bouyer struct i2c_hid_report_request rreq; 1065 1.1 bouyer int ctype; 1066 1.1 bouyer 1067 1.1 bouyer if ((ctype = ihidev_report_type_conv(type)) < 0) 1068 1.1 bouyer return (1); 1069 1.1 bouyer 1070 1.1 bouyer rreq.type = ctype; 1071 1.1 bouyer rreq.id = id; 1072 1.1 bouyer rreq.data = data; 1073 1.1 bouyer rreq.len = len; 1074 1.1 bouyer 1075 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_REPORT, &rreq, false)) { 1076 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed setting report\n"); 1077 1.1 bouyer return (1); 1078 1.1 bouyer } 1079 1.1 bouyer 1080 1.1 bouyer return 0; 1081 1.1 bouyer } 1082 1.17 thorpej 1083 1.17 thorpej static bool 1084 1.17 thorpej ihidev_acpi_get_info(struct ihidev_softc *sc) 1085 1.21 riastrad { 1086 1.30 andvar #if NACPICA > 0 1087 1.34 thorpej ACPI_HANDLE hdl = devhandle_to_acpi(device_handle(sc->sc_dev)); 1088 1.17 thorpej ACPI_STATUS status; 1089 1.17 thorpej ACPI_INTEGER val; 1090 1.17 thorpej 1091 1.17 thorpej /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */ 1092 1.17 thorpej uint8_t i2c_hid_guid[] = { 1093 1.17 thorpej 0xF7, 0xF6, 0xDF, 0x3C, 1094 1.17 thorpej 0x67, 0x42, 1095 1.17 thorpej 0x55, 0x45, 1096 1.17 thorpej 0xAD, 0x05, 1097 1.17 thorpej 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, 1098 1.17 thorpej }; 1099 1.17 thorpej 1100 1.17 thorpej status = acpi_dsm_integer(hdl, i2c_hid_guid, 1, 1, NULL, &val); 1101 1.17 thorpej if (ACPI_FAILURE(status)) { 1102 1.17 thorpej aprint_error_dev(sc->sc_dev, 1103 1.17 thorpej "failed to get HidDescriptorAddress: %s\n", 1104 1.27 skrll AcpiFormatException(status)); 1105 1.17 thorpej return false; 1106 1.17 thorpej } 1107 1.17 thorpej 1108 1.17 thorpej sc->sc_hid_desc_addr = (u_int)val; 1109 1.17 thorpej 1110 1.17 thorpej return true; 1111 1.30 andvar #else 1112 1.30 andvar return false; 1113 1.30 andvar #endif 1114 1.17 thorpej } 1115