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