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