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