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