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