1 /* $OpenBSD: ihidev.c,v 1.9 2016/01/29 17:11:58 jcs Exp $ */ 2 /* 3 * HID-over-i2c driver 4 * 5 * https://msdn.microsoft.com/en-us/library/windows/hardware/dn642101%28v=vs.85%29.aspx 6 * 7 * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/device.h> 25 #include <sys/malloc.h> 26 #include <sys/stdint.h> 27 28 #include <dev/i2c/i2cvar.h> 29 #include <dev/i2c/ihidev.h> 30 31 #include <dev/hid/hid.h> 32 33 /* XXX */ 34 #include <dev/acpi/acpivar.h> 35 36 /* #define IHIDEV_DEBUG */ 37 38 #ifdef IHIDEV_DEBUG 39 #define DPRINTF(x) printf x 40 #else 41 #define DPRINTF(x) 42 #endif 43 44 /* 7.2 */ 45 enum { 46 I2C_HID_CMD_DESCR = 0x0, 47 I2C_HID_CMD_RESET = 0x1, 48 I2C_HID_CMD_GET_REPORT = 0x2, 49 I2C_HID_CMD_SET_REPORT = 0x3, 50 I2C_HID_CMD_GET_IDLE = 0x4, 51 I2C_HID_CMD_SET_IDLE = 0x5, 52 I2C_HID_CMD_GET_PROTO = 0x6, 53 I2C_HID_CMD_SET_PROTO = 0x7, 54 I2C_HID_CMD_SET_POWER = 0x8, 55 56 /* pseudo commands */ 57 I2C_HID_REPORT_DESCR = 0x100, 58 }; 59 60 static int I2C_HID_POWER_ON = 0x0; 61 static int I2C_HID_POWER_OFF = 0x1; 62 63 int ihidev_match(struct device *, void *, void *); 64 void ihidev_attach(struct device *, struct device *, void *); 65 int ihidev_detach(struct device *, int); 66 67 int ihidev_hid_command(struct ihidev_softc *, int, void *); 68 int ihidev_intr(void *); 69 int ihidev_reset(struct ihidev_softc *); 70 int ihidev_hid_desc_parse(struct ihidev_softc *); 71 72 int ihidev_maxrepid(void *buf, int len); 73 int ihidev_print(void *aux, const char *pnp); 74 int ihidev_submatch(struct device *parent, void *cf, void *aux); 75 76 struct cfattach ihidev_ca = { 77 sizeof(struct ihidev_softc), 78 ihidev_match, 79 ihidev_attach, 80 ihidev_detach, 81 NULL 82 }; 83 84 struct cfdriver ihidev_cd = { 85 NULL, "ihidev", DV_DULL 86 }; 87 88 int 89 ihidev_match(struct device *parent, void *match, void *aux) 90 { 91 struct i2c_attach_args *ia = aux; 92 93 if (strcmp(ia->ia_name, "ihidev") == 0) 94 return (1); 95 96 return (0); 97 } 98 99 void 100 ihidev_attach(struct device *parent, struct device *self, void *aux) 101 { 102 struct ihidev_softc *sc = (struct ihidev_softc *)self; 103 struct i2c_attach_args *ia = aux; 104 struct ihidev_attach_arg iha; 105 struct device *dev; 106 int repid, repsz; 107 int repsizes[256]; 108 int isize; 109 110 sc->sc_tag = ia->ia_tag; 111 sc->sc_addr = ia->ia_addr; 112 sc->sc_hid_desc_addr = ia->ia_size; 113 114 printf(": int %d", ia->ia_int); 115 116 if (ihidev_hid_command(sc, I2C_HID_CMD_DESCR, NULL) || 117 ihidev_hid_desc_parse(sc)) { 118 printf(", failed fetching initial HID descriptor\n"); 119 return; 120 } 121 122 printf(", vendor 0x%x product 0x%x, %s\n", 123 letoh16(sc->hid_desc.wVendorID), letoh16(sc->hid_desc.wProductID), 124 (char *)ia->ia_cookie); 125 126 sc->sc_nrepid = ihidev_maxrepid(sc->sc_report, sc->sc_reportlen); 127 if (sc->sc_nrepid < 0) 128 return; 129 130 printf("%s: %d report id%s\n", sc->sc_dev.dv_xname, sc->sc_nrepid, 131 sc->sc_nrepid > 1 ? "s" : ""); 132 133 sc->sc_nrepid++; 134 sc->sc_subdevs = mallocarray(sc->sc_nrepid, sizeof(struct ihidev *), 135 M_DEVBUF, M_NOWAIT | M_ZERO); 136 if (sc->sc_subdevs == NULL) { 137 printf("%s: failed allocating memory\n", sc->sc_dev.dv_xname); 138 return; 139 } 140 141 /* find largest report size and allocate memory for input buffer */ 142 sc->sc_isize = letoh16(sc->hid_desc.wMaxInputLength); 143 for (repid = 0; repid < sc->sc_nrepid; repid++) { 144 repsz = hid_report_size(sc->sc_report, sc->sc_reportlen, 145 hid_input, repid); 146 repsizes[repid] = repsz; 147 148 isize = repsz + 2; /* two bytes for the length */ 149 isize += (sc->sc_nrepid != 1); /* one byte for the report ID */ 150 if (isize > sc->sc_isize) 151 sc->sc_isize = isize; 152 153 DPRINTF(("%s: repid %d size %d\n", sc->sc_dev.dv_xname, repid, 154 repsz)); 155 } 156 sc->sc_ibuf = malloc(sc->sc_isize, M_DEVBUF, M_NOWAIT | M_ZERO); 157 158 /* register interrupt with system */ 159 if (ia->ia_int > 0) { 160 /* XXX: don't assume this uses acpi_intr_establish */ 161 sc->sc_ih = acpi_intr_establish(ia->ia_int, ia->ia_int_flags, 162 IPL_BIO, ihidev_intr, sc, sc->sc_dev.dv_xname); 163 if (sc->sc_ih == NULL) { 164 printf(", failed establishing intr\n"); 165 return; 166 } 167 } 168 169 iha.iaa = ia; 170 iha.parent = sc; 171 172 /* Look for a driver claiming all report IDs first. */ 173 iha.reportid = IHIDEV_CLAIM_ALLREPORTID; 174 dev = config_found_sm((struct device *)sc, &iha, NULL, 175 ihidev_submatch); 176 if (dev != NULL) { 177 for (repid = 0; repid < sc->sc_nrepid; repid++) 178 sc->sc_subdevs[repid] = (struct ihidev *)dev; 179 return; 180 } 181 182 for (repid = 0; repid < sc->sc_nrepid; repid++) { 183 if (hid_report_size(sc->sc_report, sc->sc_reportlen, hid_input, 184 repid) == 0 && 185 hid_report_size(sc->sc_report, sc->sc_reportlen, 186 hid_output, repid) == 0 && 187 hid_report_size(sc->sc_report, sc->sc_reportlen, 188 hid_feature, repid) == 0) 189 continue; 190 191 iha.reportid = repid; 192 dev = config_found_sm(self, &iha, ihidev_print, 193 ihidev_submatch); 194 sc->sc_subdevs[repid] = (struct ihidev *)dev; 195 } 196 197 /* power down until we're opened */ 198 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF)) { 199 printf("%s: failed to power down\n", sc->sc_dev.dv_xname); 200 return; 201 } 202 } 203 204 int 205 ihidev_detach(struct device *self, int flags) 206 { 207 struct ihidev_softc *sc = (struct ihidev_softc *)self; 208 209 if (sc->sc_ih != NULL) { 210 intr_disestablish(sc->sc_ih); 211 sc->sc_ih = NULL; 212 } 213 214 if (sc->sc_ibuf != NULL) { 215 free(sc->sc_ibuf, M_DEVBUF, 0); 216 sc->sc_ibuf = NULL; 217 } 218 219 if (sc->sc_report != NULL) 220 free(sc->sc_report, M_DEVBUF, sc->sc_reportlen); 221 222 return (0); 223 } 224 225 int 226 ihidev_hid_command(struct ihidev_softc *sc, int hidcmd, void *arg) 227 { 228 int i, res = 1; 229 230 iic_acquire_bus(sc->sc_tag, 0); 231 232 switch (hidcmd) { 233 case I2C_HID_CMD_DESCR: { 234 /* 235 * 5.2.2 - HID Descriptor Retrieval 236 * register is passed from the controller 237 */ 238 uint8_t cmd[] = { 239 htole16(sc->sc_hid_desc_addr) & 0xff, 240 htole16(sc->sc_hid_desc_addr) >> 8, 241 }; 242 243 DPRINTF(("%s: HID command I2C_HID_CMD_DESCR at 0x%x\n", 244 sc->sc_dev.dv_xname, htole16(sc->sc_hid_desc_addr))); 245 246 /* 20 00 */ 247 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 248 &cmd, sizeof(cmd), &sc->hid_desc_buf, 249 sizeof(struct i2c_hid_desc), 0); 250 251 DPRINTF(("%s: HID descriptor:", sc->sc_dev.dv_xname)); 252 for (i = 0; i < sizeof(struct i2c_hid_desc); i++) 253 DPRINTF((" %.2x", sc->hid_desc_buf[i])); 254 DPRINTF(("\n")); 255 256 break; 257 } 258 case I2C_HID_CMD_RESET: { 259 uint8_t cmd[] = { 260 htole16(sc->hid_desc.wCommandRegister) & 0xff, 261 htole16(sc->hid_desc.wCommandRegister) >> 8, 262 0, 263 I2C_HID_CMD_RESET, 264 }; 265 266 DPRINTF(("%s: HID command I2C_HID_CMD_RESET\n", 267 sc->sc_dev.dv_xname)); 268 269 /* 22 00 00 01 */ 270 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 271 &cmd, sizeof(cmd), NULL, 0, 0); 272 273 break; 274 } 275 case I2C_HID_CMD_GET_REPORT: { 276 struct i2c_hid_report_request *rreq = 277 (struct i2c_hid_report_request *)arg; 278 279 uint8_t cmd[] = { 280 htole16(sc->hid_desc.wCommandRegister) & 0xff, 281 htole16(sc->hid_desc.wCommandRegister) >> 8, 282 0, 283 I2C_HID_CMD_GET_REPORT, 284 0, 0, 0, 285 }; 286 int cmdlen = 7; 287 int dataoff = 4; 288 int report_id = rreq->id; 289 int report_id_len = 1; 290 int report_len = rreq->len + 2; 291 int d; 292 uint8_t *tmprep; 293 294 DPRINTF(("%s: HID command I2C_HID_CMD_GET_REPORT %d " 295 "(type %d, len %d)\n", sc->sc_dev.dv_xname, report_id, 296 rreq->type, rreq->len)); 297 298 /* 299 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a 300 * report ID >= 15 is necessary, then the Report ID in the Low 301 * Byte must be set to 1111 and a Third Byte is appended to the 302 * protocol. This Third Byte contains the entire/actual report 303 * ID." 304 */ 305 if (report_id >= 15) { 306 cmd[dataoff++] = report_id; 307 report_id = 15; 308 report_id_len = 2; 309 } else 310 cmdlen--; 311 312 cmd[2] = report_id | rreq->type << 4; 313 314 cmd[dataoff++] = sc->hid_desc.wDataRegister & 0xff; 315 cmd[dataoff] = sc->hid_desc.wDataRegister >> 8; 316 317 /* 318 * 7.2.2.2 - Response will be a 2-byte length value, the report 319 * id with length determined above, and then the report. 320 * Allocate rreq->len + 2 + 2 bytes, read into that temporary 321 * buffer, and then copy only the report back out to 322 * rreq->data. 323 */ 324 report_len += report_id_len; 325 tmprep = malloc(report_len, M_DEVBUF, M_NOWAIT | M_ZERO); 326 327 /* type 3 id 8: 22 00 38 02 23 00 */ 328 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 329 &cmd, cmdlen, tmprep, report_len, 0); 330 331 d = tmprep[0] | tmprep[1] << 8; 332 if (d != report_len) 333 DPRINTF(("%s: response size %d != expected length %d\n", 334 sc->sc_dev.dv_xname, d, report_len)); 335 336 if (report_id_len == 2) 337 d = tmprep[2] | tmprep[3] << 8; 338 else 339 d = tmprep[2]; 340 341 if (d != rreq->id) { 342 DPRINTF(("%s: response report id %d != %d\n", 343 sc->sc_dev.dv_xname, d, rreq->id)); 344 iic_release_bus(sc->sc_tag, 0); 345 return (1); 346 } 347 348 DPRINTF(("%s: response:", sc->sc_dev.dv_xname)); 349 for (i = 0; i < report_len; i++) 350 DPRINTF((" %.2x", tmprep[i])); 351 DPRINTF(("\n")); 352 353 memcpy(rreq->data, tmprep + 2 + report_id_len, rreq->len); 354 free(tmprep, M_DEVBUF, report_len); 355 356 break; 357 } 358 case I2C_HID_CMD_SET_REPORT: { 359 struct i2c_hid_report_request *rreq = 360 (struct i2c_hid_report_request *)arg; 361 362 uint8_t cmd[] = { 363 htole16(sc->hid_desc.wCommandRegister) & 0xff, 364 htole16(sc->hid_desc.wCommandRegister) >> 8, 365 0, 366 I2C_HID_CMD_SET_REPORT, 367 0, 0, 0, 0, 0, 0, 368 }; 369 int cmdlen = 10; 370 int report_id = rreq->id; 371 int report_len = 2 + (report_id ? 1 : 0) + rreq->len; 372 int dataoff; 373 uint8_t *finalcmd; 374 375 DPRINTF(("%s: HID command I2C_HID_CMD_SET_REPORT %d " 376 "(type %d, len %d):", sc->sc_dev.dv_xname, report_id, 377 rreq->type, rreq->len)); 378 for (i = 0; i < rreq->len; i++) 379 DPRINTF((" %.2x", ((uint8_t *)rreq->data)[i])); 380 DPRINTF(("\n")); 381 382 /* 383 * 7.2.2.4 - "The protocol is optimized for Report < 15. If a 384 * report ID >= 15 is necessary, then the Report ID in the Low 385 * Byte must be set to 1111 and a Third Byte is appended to the 386 * protocol. This Third Byte contains the entire/actual report 387 * ID." 388 */ 389 dataoff = 4; 390 if (report_id >= 15) { 391 cmd[dataoff++] = report_id; 392 report_id = 15; 393 } else 394 cmdlen--; 395 396 cmd[2] = report_id | rreq->type << 4; 397 398 if (rreq->type == I2C_HID_REPORT_TYPE_FEATURE) { 399 cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister) 400 & 0xff; 401 cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister) 402 >> 8; 403 } else { 404 cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister) 405 & 0xff; 406 cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister) 407 >> 8; 408 } 409 410 cmd[dataoff++] = report_len & 0xff; 411 cmd[dataoff++] = report_len >> 8; 412 cmd[dataoff] = rreq->id; 413 414 finalcmd = malloc(cmdlen + rreq->len, M_DEVBUF, 415 M_NOWAIT | M_ZERO); 416 417 memcpy(finalcmd, cmd, cmdlen); 418 memcpy(finalcmd + cmdlen, rreq->data, rreq->len); 419 420 /* type 3 id 4: 22 00 34 03 23 00 04 00 04 03 */ 421 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 422 finalcmd, cmdlen + rreq->len, NULL, 0, 0); 423 424 free(finalcmd, M_DEVBUF, cmdlen + rreq->len); 425 426 break; 427 } 428 429 case I2C_HID_CMD_SET_POWER: { 430 int power = *(int *)arg; 431 uint8_t cmd[] = { 432 htole16(sc->hid_desc.wCommandRegister) & 0xff, 433 htole16(sc->hid_desc.wCommandRegister) >> 8, 434 power, 435 I2C_HID_CMD_SET_POWER, 436 }; 437 438 DPRINTF(("%s: HID command I2C_HID_CMD_SET_POWER(%d)\n", 439 sc->sc_dev.dv_xname, power)); 440 441 /* 22 00 00 08 */ 442 res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 443 &cmd, sizeof(cmd), NULL, 0, 0); 444 445 break; 446 } 447 case I2C_HID_REPORT_DESCR: { 448 uint8_t cmd[] = { 449 htole16(sc->hid_desc.wReportDescRegister) & 0xff, 450 htole16(sc->hid_desc.wReportDescRegister) >> 8, 451 }; 452 453 DPRINTF(("%s: HID command I2C_HID_REPORT_DESCR at 0x%x with " 454 "size %d\n", sc->sc_dev.dv_xname, cmd[0], 455 sc->sc_reportlen)); 456 457 /* 20 00 */ 458 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 459 &cmd, sizeof(cmd), sc->sc_report, sc->sc_reportlen, 0); 460 461 DPRINTF(("%s: HID report descriptor:", sc->sc_dev.dv_xname)); 462 for (i = 0; i < sc->sc_reportlen; i++) 463 DPRINTF((" %.2x", sc->sc_report[i])); 464 DPRINTF(("\n")); 465 466 break; 467 } 468 default: 469 printf("%s: unknown command %d\n", sc->sc_dev.dv_xname, 470 hidcmd); 471 } 472 473 iic_release_bus(sc->sc_tag, 0); 474 475 return (res); 476 } 477 478 int 479 ihidev_reset(struct ihidev_softc *sc) 480 { 481 DPRINTF(("%s: resetting\n", sc->sc_dev.dv_xname)); 482 483 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_ON)) { 484 printf("%s: failed to power on\n", sc->sc_dev.dv_xname); 485 return (1); 486 } 487 488 DELAY(1000); 489 490 if (ihidev_hid_command(sc, I2C_HID_CMD_RESET, 0)) { 491 printf("%s: failed to reset hardware\n", sc->sc_dev.dv_xname); 492 493 ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, 494 &I2C_HID_POWER_OFF); 495 496 return (1); 497 } 498 499 DELAY(1000); 500 501 return (0); 502 } 503 504 /* 505 * 5.2.2 - HID Descriptor Retrieval 506 * 507 * parse HID Descriptor that has already been read into hid_desc with 508 * I2C_HID_CMD_DESCR 509 */ 510 int 511 ihidev_hid_desc_parse(struct ihidev_softc *sc) 512 { 513 int retries = 3; 514 515 /* must be v01.00 */ 516 if (letoh16(sc->hid_desc.bcdVersion) != 0x0100) { 517 printf("%s: bad HID descriptor bcdVersion (0x%x)\n", 518 sc->sc_dev.dv_xname, 519 letoh16(sc->hid_desc.bcdVersion)); 520 return (1); 521 } 522 523 /* must be 30 bytes for v1.00 */ 524 if (letoh16(sc->hid_desc.wHIDDescLength != 525 sizeof(struct i2c_hid_desc))) { 526 printf("%s: bad HID descriptor size (%d != %zu)\n", 527 sc->sc_dev.dv_xname, 528 letoh16(sc->hid_desc.wHIDDescLength), 529 sizeof(struct i2c_hid_desc)); 530 return (1); 531 } 532 533 if (letoh16(sc->hid_desc.wReportDescLength) <= 0) { 534 printf("%s: bad HID report descriptor size (%d)\n", 535 sc->sc_dev.dv_xname, 536 letoh16(sc->hid_desc.wReportDescLength)); 537 return (1); 538 } 539 540 while (retries-- > 0) { 541 if (ihidev_reset(sc)) { 542 if (retries == 0) 543 return(1); 544 545 DELAY(1000); 546 } 547 else 548 break; 549 } 550 551 sc->sc_reportlen = letoh16(sc->hid_desc.wReportDescLength); 552 sc->sc_report = malloc(sc->sc_reportlen, M_DEVBUF, M_NOWAIT | M_ZERO); 553 554 if (ihidev_hid_command(sc, I2C_HID_REPORT_DESCR, 0)) { 555 printf("%s: failed fetching HID report\n", 556 sc->sc_dev.dv_xname); 557 return (1); 558 } 559 560 return (0); 561 } 562 563 int 564 ihidev_intr(void *arg) 565 { 566 struct ihidev_softc *sc = arg; 567 struct ihidev *scd; 568 u_int psize; 569 int res, i; 570 u_char *p; 571 u_int rep = 0; 572 573 /* 574 * XXX: force I2C_F_POLL for now to avoid dwiic interrupting 575 * while we are interrupting 576 */ 577 578 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 579 580 res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0, 581 sc->sc_ibuf, sc->sc_isize, I2C_F_POLL); 582 583 iic_release_bus(sc->sc_tag, I2C_F_POLL); 584 585 /* 586 * 6.1.1 - First two bytes are the packet length, which must be less 587 * than or equal to wMaxInputLength 588 */ 589 psize = sc->sc_ibuf[0] | sc->sc_ibuf[1] << 8; 590 if (!psize || psize > sc->sc_isize) { 591 DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n", 592 sc->sc_dev.dv_xname, __func__, psize, sc->sc_isize)); 593 return (1); 594 } 595 596 /* 3rd byte is the report id */ 597 p = sc->sc_ibuf + 2; 598 psize -= 2; 599 if (sc->sc_nrepid != 1) 600 rep = *p++, psize--; 601 602 if (rep >= sc->sc_nrepid) { 603 printf("%s: %s: bad report id %d\n", sc->sc_dev.dv_xname, 604 __func__, rep); 605 return (1); 606 } 607 608 DPRINTF(("%s: ihidev_intr: hid input (rep %d):", sc->sc_dev.dv_xname, 609 rep)); 610 for (i = 0; i < sc->sc_isize; i++) 611 DPRINTF((" %.2x", sc->sc_ibuf[i])); 612 DPRINTF(("\n")); 613 614 scd = sc->sc_subdevs[rep]; 615 if (scd == NULL || !(scd->sc_state & IHIDEV_OPEN)) 616 return (1); 617 618 scd->sc_intr(scd, p, psize); 619 620 return (1); 621 } 622 623 int 624 ihidev_maxrepid(void *buf, int len) 625 { 626 struct hid_data *d; 627 struct hid_item h; 628 int maxid; 629 630 maxid = -1; 631 h.report_ID = 0; 632 for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); ) 633 if (h.report_ID > maxid) 634 maxid = h.report_ID; 635 hid_end_parse(d); 636 637 return (maxid); 638 } 639 640 int 641 ihidev_print(void *aux, const char *pnp) 642 { 643 struct ihidev_attach_arg *iha = aux; 644 645 if (pnp) 646 printf("hid at %s", pnp); 647 648 if (iha->reportid != 0 && iha->reportid != IHIDEV_CLAIM_ALLREPORTID) 649 printf(" reportid %d", iha->reportid); 650 651 return (UNCONF); 652 } 653 654 int 655 ihidev_submatch(struct device *parent, void *match, void *aux) 656 { 657 struct ihidev_attach_arg *iha = aux; 658 struct cfdata *cf = match; 659 660 if (cf->ihidevcf_reportid != IHIDEV_UNK_REPORTID && 661 cf->ihidevcf_reportid != iha->reportid) 662 return (0); 663 664 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 665 } 666 667 int 668 ihidev_open(struct ihidev *scd) 669 { 670 struct ihidev_softc *sc = scd->sc_parent; 671 672 DPRINTF(("%s: %s: state=%d refcnt=%d\n", sc->sc_dev.dv_xname, 673 __func__, scd->sc_state, sc->sc_refcnt)); 674 675 if (scd->sc_state & IHIDEV_OPEN) 676 return (EBUSY); 677 678 scd->sc_state |= IHIDEV_OPEN; 679 680 if (sc->sc_refcnt++ || sc->sc_isize == 0) 681 return (0); 682 683 /* power on */ 684 ihidev_reset(sc); 685 686 return (0); 687 } 688 689 void 690 ihidev_close(struct ihidev *scd) 691 { 692 struct ihidev_softc *sc = scd->sc_parent; 693 694 DPRINTF(("%s: %s: state=%d refcnt=%d\n", sc->sc_dev.dv_xname, 695 __func__, scd->sc_state, sc->sc_refcnt)); 696 697 if (!(scd->sc_state & IHIDEV_OPEN)) 698 return; 699 700 scd->sc_state &= ~IHIDEV_OPEN; 701 702 if (--sc->sc_refcnt) 703 return; 704 705 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF)) 706 printf("%s: failed to power down\n", sc->sc_dev.dv_xname); 707 } 708 709 int 710 ihidev_ioctl(struct ihidev *sc, u_long cmd, caddr_t addr, int flag, 711 struct proc *p) 712 { 713 return -1; 714 } 715 716 void 717 ihidev_get_report_desc(struct ihidev_softc *sc, void **desc, int *size) 718 { 719 *desc = sc->sc_report; 720 *size = sc->sc_reportlen; 721 } 722 723 /* convert hid_* constants used throughout HID code to i2c HID equivalents */ 724 int 725 ihidev_report_type_conv(int hid_type_id) 726 { 727 switch (hid_type_id) { 728 case hid_input: 729 return I2C_HID_REPORT_TYPE_INPUT; 730 case hid_output: 731 return I2C_HID_REPORT_TYPE_OUTPUT; 732 case hid_feature: 733 return I2C_HID_REPORT_TYPE_FEATURE; 734 default: 735 return -1; 736 } 737 } 738 739 int 740 ihidev_get_report(struct device *dev, int type, int id, void *data, int len) 741 { 742 struct ihidev_softc *sc = (struct ihidev_softc *)dev; 743 struct i2c_hid_report_request rreq; 744 int ctype; 745 746 if ((ctype = ihidev_report_type_conv(type)) < 0) 747 return (1); 748 749 rreq.type = ctype; 750 rreq.id = id; 751 rreq.data = data; 752 rreq.len = len; 753 754 if (ihidev_hid_command(sc, I2C_HID_CMD_GET_REPORT, &rreq)) { 755 printf("%s: failed fetching report\n", sc->sc_dev.dv_xname); 756 return (1); 757 } 758 759 return 0; 760 } 761 762 int 763 ihidev_set_report(struct device *dev, int type, int id, void *data, 764 int len) 765 { 766 struct ihidev_softc *sc = (struct ihidev_softc *)dev; 767 struct i2c_hid_report_request rreq; 768 int ctype; 769 770 if ((ctype = ihidev_report_type_conv(type)) < 0) 771 return (1); 772 773 rreq.type = ctype; 774 rreq.id = id; 775 rreq.data = data; 776 rreq.len = len; 777 778 if (ihidev_hid_command(sc, I2C_HID_CMD_SET_REPORT, &rreq)) { 779 printf("%s: failed setting report\n", sc->sc_dev.dv_xname); 780 return (1); 781 } 782 783 return 0; 784 } 785