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