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