ihidev.c revision 1.31 1 1.31 jmcneill /* $NetBSD: ihidev.c,v 1.31 2024/12/08 20:49:56 jmcneill Exp $ */
2 1.1 bouyer /* $OpenBSD ihidev.c,v 1.13 2017/04/08 02:57:23 deraadt Exp $ */
3 1.1 bouyer
4 1.1 bouyer /*-
5 1.1 bouyer * Copyright (c) 2017 The NetBSD Foundation, Inc.
6 1.1 bouyer * All rights reserved.
7 1.1 bouyer *
8 1.1 bouyer * This code is derived from software contributed to The NetBSD Foundation
9 1.1 bouyer * by Manuel Bouyer.
10 1.1 bouyer *
11 1.1 bouyer * Redistribution and use in source and binary forms, with or without
12 1.1 bouyer * modification, are permitted provided that the following conditions
13 1.1 bouyer * are met:
14 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
15 1.1 bouyer * notice, this list of conditions and the following disclaimer.
16 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
18 1.1 bouyer * documentation and/or other materials provided with the distribution.
19 1.1 bouyer *
20 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.1 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.1 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.1 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.1 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.1 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.1 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.1 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.1 bouyer * POSSIBILITY OF SUCH DAMAGE.
31 1.1 bouyer */
32 1.1 bouyer
33 1.1 bouyer /*
34 1.1 bouyer * Copyright (c) 2015, 2016 joshua stein <jcs (at) openbsd.org>
35 1.1 bouyer *
36 1.1 bouyer * Permission to use, copy, modify, and distribute this software for any
37 1.1 bouyer * purpose with or without fee is hereby granted, provided that the above
38 1.1 bouyer * copyright notice and this permission notice appear in all copies.
39 1.1 bouyer *
40 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
41 1.1 bouyer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
42 1.1 bouyer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
43 1.1 bouyer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44 1.1 bouyer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
45 1.1 bouyer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
46 1.1 bouyer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47 1.1 bouyer */
48 1.1 bouyer
49 1.1 bouyer /*
50 1.1 bouyer * HID-over-i2c driver
51 1.1 bouyer *
52 1.1 bouyer * https://msdn.microsoft.com/en-us/library/windows/hardware/dn642101%28v=vs.85%29.aspx
53 1.1 bouyer *
54 1.1 bouyer */
55 1.1 bouyer
56 1.31 jmcneill #include "gpio.h"
57 1.31 jmcneill #include "acpica.h"
58 1.31 jmcneill
59 1.1 bouyer #include <sys/cdefs.h>
60 1.31 jmcneill __KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1.31 2024/12/08 20:49:56 jmcneill Exp $");
61 1.1 bouyer
62 1.1 bouyer #include <sys/param.h>
63 1.1 bouyer #include <sys/systm.h>
64 1.1 bouyer #include <sys/device.h>
65 1.1 bouyer #include <sys/kmem.h>
66 1.21 riastrad #include <sys/workqueue.h>
67 1.1 bouyer
68 1.1 bouyer #include <dev/i2c/i2cvar.h>
69 1.1 bouyer #include <dev/i2c/ihidev.h>
70 1.1 bouyer
71 1.1 bouyer #include <dev/hid/hid.h>
72 1.1 bouyer
73 1.1 bouyer #if NACPICA > 0
74 1.12 thorpej #include <dev/acpi/acpivar.h>
75 1.1 bouyer #include <dev/acpi/acpi_intr.h>
76 1.31 jmcneill #include <dev/acpi/acpi_gpio.h>
77 1.31 jmcneill #endif
78 1.31 jmcneill #if NGPIO > 0
79 1.31 jmcneill #include <dev/gpio/gpiovar.h>
80 1.1 bouyer #endif
81 1.1 bouyer
82 1.1 bouyer #include "locators.h"
83 1.1 bouyer
84 1.1 bouyer /* #define IHIDEV_DEBUG */
85 1.1 bouyer
86 1.1 bouyer #ifdef IHIDEV_DEBUG
87 1.1 bouyer #define DPRINTF(x) printf x
88 1.1 bouyer #else
89 1.1 bouyer #define DPRINTF(x)
90 1.1 bouyer #endif
91 1.1 bouyer
92 1.1 bouyer /* 7.2 */
93 1.1 bouyer enum {
94 1.1 bouyer I2C_HID_CMD_DESCR = 0x0,
95 1.1 bouyer I2C_HID_CMD_RESET = 0x1,
96 1.1 bouyer I2C_HID_CMD_GET_REPORT = 0x2,
97 1.1 bouyer I2C_HID_CMD_SET_REPORT = 0x3,
98 1.1 bouyer I2C_HID_CMD_GET_IDLE = 0x4,
99 1.1 bouyer I2C_HID_CMD_SET_IDLE = 0x5,
100 1.1 bouyer I2C_HID_CMD_GET_PROTO = 0x6,
101 1.1 bouyer I2C_HID_CMD_SET_PROTO = 0x7,
102 1.1 bouyer I2C_HID_CMD_SET_POWER = 0x8,
103 1.1 bouyer
104 1.1 bouyer /* pseudo commands */
105 1.1 bouyer I2C_HID_REPORT_DESCR = 0x100,
106 1.1 bouyer };
107 1.1 bouyer
108 1.1 bouyer static int I2C_HID_POWER_ON = 0x0;
109 1.1 bouyer static int I2C_HID_POWER_OFF = 0x1;
110 1.1 bouyer
111 1.1 bouyer static int ihidev_match(device_t, cfdata_t, void *);
112 1.1 bouyer static void ihidev_attach(device_t, device_t, void *);
113 1.1 bouyer static int ihidev_detach(device_t, int);
114 1.1 bouyer CFATTACH_DECL_NEW(ihidev, sizeof(struct ihidev_softc),
115 1.1 bouyer ihidev_match, ihidev_attach, ihidev_detach, NULL);
116 1.1 bouyer
117 1.21 riastrad static bool ihidev_intr_init(struct ihidev_softc *);
118 1.21 riastrad static void ihidev_intr_fini(struct ihidev_softc *);
119 1.12 thorpej
120 1.1 bouyer static bool ihidev_suspend(device_t, const pmf_qual_t *);
121 1.1 bouyer static bool ihidev_resume(device_t, const pmf_qual_t *);
122 1.1 bouyer static int ihidev_hid_command(struct ihidev_softc *, int, void *, bool);
123 1.30 andvar #if NACPICA > 0
124 1.7 jmcneill static int ihidev_intr(void *);
125 1.21 riastrad static void ihidev_work(struct work *, void *);
126 1.30 andvar #endif
127 1.1 bouyer static int ihidev_reset(struct ihidev_softc *, bool);
128 1.1 bouyer static int ihidev_hid_desc_parse(struct ihidev_softc *);
129 1.1 bouyer
130 1.1 bouyer static int ihidev_maxrepid(void *, int);
131 1.1 bouyer static int ihidev_print(void *, const char *);
132 1.1 bouyer static int ihidev_submatch(device_t, cfdata_t, const int *, void *);
133 1.1 bouyer
134 1.17 thorpej static bool ihidev_acpi_get_info(struct ihidev_softc *);
135 1.17 thorpej
136 1.5 thorpej static const struct device_compatible_entry compat_data[] = {
137 1.16 thorpej { .compat = "PNP0C50" },
138 1.16 thorpej { .compat = "ACPI0C50" },
139 1.13 thorpej { .compat = "hid-over-i2c" },
140 1.18 thorpej DEVICE_COMPAT_EOL
141 1.4 thorpej };
142 1.4 thorpej
143 1.1 bouyer static int
144 1.1 bouyer ihidev_match(device_t parent, cfdata_t match, void *aux)
145 1.1 bouyer {
146 1.1 bouyer struct i2c_attach_args * const ia = aux;
147 1.3 thorpej int match_result;
148 1.3 thorpej
149 1.5 thorpej if (iic_use_direct_match(ia, match, compat_data, &match_result))
150 1.29 riastrad return match_result;
151 1.1 bouyer
152 1.1 bouyer return 0;
153 1.1 bouyer }
154 1.1 bouyer
155 1.1 bouyer static void
156 1.1 bouyer ihidev_attach(device_t parent, device_t self, void *aux)
157 1.1 bouyer {
158 1.1 bouyer struct ihidev_softc *sc = device_private(self);
159 1.1 bouyer struct i2c_attach_args *ia = aux;
160 1.1 bouyer struct ihidev_attach_arg iha;
161 1.1 bouyer device_t dev;
162 1.1 bouyer int repid, repsz;
163 1.1 bouyer int isize;
164 1.1 bouyer int locs[IHIDBUSCF_NLOCS];
165 1.1 bouyer
166 1.1 bouyer sc->sc_dev = self;
167 1.1 bouyer sc->sc_tag = ia->ia_tag;
168 1.1 bouyer sc->sc_addr = ia->ia_addr;
169 1.21 riastrad mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
170 1.1 bouyer
171 1.17 thorpej sc->sc_phandle = ia->ia_cookie;
172 1.17 thorpej if (ia->ia_cookietype != I2C_COOKIE_ACPI) {
173 1.17 thorpej aprint_error(": unsupported device tree type\n");
174 1.17 thorpej return;
175 1.17 thorpej }
176 1.21 riastrad if (!ihidev_acpi_get_info(sc)) {
177 1.1 bouyer return;
178 1.1 bouyer }
179 1.1 bouyer
180 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_DESCR, NULL, false) ||
181 1.1 bouyer ihidev_hid_desc_parse(sc)) {
182 1.1 bouyer aprint_error(": failed fetching initial HID descriptor\n");
183 1.1 bouyer return;
184 1.1 bouyer }
185 1.1 bouyer
186 1.1 bouyer aprint_naive("\n");
187 1.1 bouyer aprint_normal(": vendor 0x%x product 0x%x, %s\n",
188 1.1 bouyer le16toh(sc->hid_desc.wVendorID), le16toh(sc->hid_desc.wProductID),
189 1.1 bouyer ia->ia_name);
190 1.1 bouyer
191 1.1 bouyer sc->sc_nrepid = ihidev_maxrepid(sc->sc_report, sc->sc_reportlen);
192 1.1 bouyer if (sc->sc_nrepid < 0)
193 1.1 bouyer return;
194 1.1 bouyer
195 1.1 bouyer aprint_normal_dev(self, "%d report id%s\n", sc->sc_nrepid,
196 1.1 bouyer sc->sc_nrepid > 1 ? "s" : "");
197 1.1 bouyer
198 1.1 bouyer sc->sc_nrepid++;
199 1.1 bouyer sc->sc_subdevs = kmem_zalloc(sc->sc_nrepid * sizeof(struct ihidev *),
200 1.9 chs KM_SLEEP);
201 1.1 bouyer
202 1.1 bouyer /* find largest report size and allocate memory for input buffer */
203 1.1 bouyer sc->sc_isize = le16toh(sc->hid_desc.wMaxInputLength);
204 1.1 bouyer for (repid = 0; repid < sc->sc_nrepid; repid++) {
205 1.1 bouyer repsz = hid_report_size(sc->sc_report, sc->sc_reportlen,
206 1.1 bouyer hid_input, repid);
207 1.1 bouyer
208 1.1 bouyer isize = repsz + 2; /* two bytes for the length */
209 1.1 bouyer isize += (sc->sc_nrepid != 1); /* one byte for the report ID */
210 1.1 bouyer if (isize > sc->sc_isize)
211 1.1 bouyer sc->sc_isize = isize;
212 1.1 bouyer
213 1.28 riastrad DPRINTF(("%s: repid %d size %d\n",
214 1.28 riastrad device_xname(sc->sc_dev), repid, repsz));
215 1.1 bouyer }
216 1.9 chs sc->sc_ibuf = kmem_zalloc(sc->sc_isize, KM_SLEEP);
217 1.21 riastrad if (!ihidev_intr_init(sc)) {
218 1.12 thorpej return;
219 1.1 bouyer }
220 1.1 bouyer
221 1.1 bouyer iha.iaa = ia;
222 1.1 bouyer iha.parent = sc;
223 1.1 bouyer
224 1.1 bouyer /* Look for a driver claiming all report IDs first. */
225 1.1 bouyer iha.reportid = IHIDEV_CLAIM_ALLREPORTID;
226 1.1 bouyer locs[IHIDBUSCF_REPORTID] = IHIDEV_CLAIM_ALLREPORTID;
227 1.19 thorpej dev = config_found(self, &iha, ihidev_print,
228 1.20 thorpej CFARGS(.submatch = ihidev_submatch,
229 1.31 jmcneill .locators = locs,
230 1.31 jmcneill .iattr = "ihidbus"));
231 1.1 bouyer if (dev != NULL) {
232 1.1 bouyer for (repid = 0; repid < sc->sc_nrepid; repid++)
233 1.1 bouyer sc->sc_subdevs[repid] = device_private(dev);
234 1.1 bouyer return;
235 1.1 bouyer }
236 1.1 bouyer
237 1.1 bouyer for (repid = 0; repid < sc->sc_nrepid; repid++) {
238 1.1 bouyer if (hid_report_size(sc->sc_report, sc->sc_reportlen, hid_input,
239 1.1 bouyer repid) == 0 &&
240 1.1 bouyer hid_report_size(sc->sc_report, sc->sc_reportlen,
241 1.1 bouyer hid_output, repid) == 0 &&
242 1.1 bouyer hid_report_size(sc->sc_report, sc->sc_reportlen,
243 1.1 bouyer hid_feature, repid) == 0)
244 1.1 bouyer continue;
245 1.1 bouyer
246 1.1 bouyer iha.reportid = repid;
247 1.1 bouyer locs[IHIDBUSCF_REPORTID] = repid;
248 1.19 thorpej dev = config_found(self, &iha, ihidev_print,
249 1.20 thorpej CFARGS(.submatch = ihidev_submatch,
250 1.31 jmcneill .locators = locs,
251 1.31 jmcneill .iattr = "ihidbus"));
252 1.1 bouyer sc->sc_subdevs[repid] = device_private(dev);
253 1.1 bouyer }
254 1.1 bouyer
255 1.1 bouyer /* power down until we're opened */
256 1.21 riastrad if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF,
257 1.21 riastrad false)) {
258 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power down\n");
259 1.1 bouyer return;
260 1.1 bouyer }
261 1.1 bouyer if (!pmf_device_register(self, ihidev_suspend, ihidev_resume))
262 1.1 bouyer aprint_error_dev(self, "couldn't establish power handler\n");
263 1.1 bouyer }
264 1.1 bouyer
265 1.1 bouyer static int
266 1.1 bouyer ihidev_detach(device_t self, int flags)
267 1.1 bouyer {
268 1.1 bouyer struct ihidev_softc *sc = device_private(self);
269 1.21 riastrad int error;
270 1.21 riastrad
271 1.21 riastrad error = config_detach_children(self, flags);
272 1.21 riastrad if (error)
273 1.21 riastrad return error;
274 1.21 riastrad
275 1.21 riastrad pmf_device_deregister(self);
276 1.21 riastrad ihidev_intr_fini(sc);
277 1.21 riastrad
278 1.21 riastrad if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF,
279 1.21 riastrad true))
280 1.21 riastrad aprint_error_dev(sc->sc_dev, "failed to power down\n");
281 1.1 bouyer
282 1.1 bouyer if (sc->sc_ibuf != NULL) {
283 1.1 bouyer kmem_free(sc->sc_ibuf, sc->sc_isize);
284 1.1 bouyer sc->sc_ibuf = NULL;
285 1.1 bouyer }
286 1.1 bouyer
287 1.1 bouyer if (sc->sc_report != NULL)
288 1.1 bouyer kmem_free(sc->sc_report, sc->sc_reportlen);
289 1.1 bouyer
290 1.21 riastrad mutex_destroy(&sc->sc_lock);
291 1.21 riastrad
292 1.21 riastrad return 0;
293 1.1 bouyer }
294 1.1 bouyer
295 1.1 bouyer static bool
296 1.1 bouyer ihidev_suspend(device_t self, const pmf_qual_t *q)
297 1.1 bouyer {
298 1.1 bouyer struct ihidev_softc *sc = device_private(self);
299 1.1 bouyer
300 1.21 riastrad mutex_enter(&sc->sc_lock);
301 1.1 bouyer if (sc->sc_refcnt > 0) {
302 1.1 bouyer printf("ihidev power off\n");
303 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
304 1.1 bouyer &I2C_HID_POWER_OFF, true))
305 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power down\n");
306 1.1 bouyer }
307 1.21 riastrad mutex_exit(&sc->sc_lock);
308 1.1 bouyer return true;
309 1.1 bouyer }
310 1.1 bouyer
311 1.1 bouyer static bool
312 1.1 bouyer ihidev_resume(device_t self, const pmf_qual_t *q)
313 1.1 bouyer {
314 1.1 bouyer struct ihidev_softc *sc = device_private(self);
315 1.1 bouyer
316 1.21 riastrad mutex_enter(&sc->sc_lock);
317 1.1 bouyer if (sc->sc_refcnt > 0) {
318 1.1 bouyer printf("ihidev power reset\n");
319 1.1 bouyer ihidev_reset(sc, true);
320 1.1 bouyer }
321 1.21 riastrad mutex_exit(&sc->sc_lock);
322 1.1 bouyer return true;
323 1.1 bouyer }
324 1.1 bouyer
325 1.1 bouyer static int
326 1.1 bouyer ihidev_hid_command(struct ihidev_softc *sc, int hidcmd, void *arg, bool poll)
327 1.1 bouyer {
328 1.1 bouyer int i, res = 1;
329 1.1 bouyer int flags = poll ? I2C_F_POLL : 0;
330 1.1 bouyer
331 1.1 bouyer iic_acquire_bus(sc->sc_tag, flags);
332 1.1 bouyer
333 1.1 bouyer switch (hidcmd) {
334 1.1 bouyer case I2C_HID_CMD_DESCR: {
335 1.1 bouyer /*
336 1.1 bouyer * 5.2.2 - HID Descriptor Retrieval
337 1.1 bouyer * register is passed from the controller
338 1.1 bouyer */
339 1.1 bouyer uint8_t cmd[] = {
340 1.1 bouyer htole16(sc->sc_hid_desc_addr) & 0xff,
341 1.1 bouyer htole16(sc->sc_hid_desc_addr) >> 8,
342 1.1 bouyer };
343 1.1 bouyer
344 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_DESCR at 0x%x\n",
345 1.28 riastrad device_xname(sc->sc_dev), htole16(sc->sc_hid_desc_addr)));
346 1.1 bouyer
347 1.1 bouyer /* 20 00 */
348 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
349 1.1 bouyer &cmd, sizeof(cmd), &sc->hid_desc_buf,
350 1.1 bouyer sizeof(struct i2c_hid_desc), flags);
351 1.1 bouyer
352 1.28 riastrad DPRINTF(("%s: HID descriptor:", device_xname(sc->sc_dev)));
353 1.1 bouyer for (i = 0; i < sizeof(struct i2c_hid_desc); i++)
354 1.1 bouyer DPRINTF((" %.2x", sc->hid_desc_buf[i]));
355 1.1 bouyer DPRINTF(("\n"));
356 1.1 bouyer
357 1.1 bouyer break;
358 1.1 bouyer }
359 1.1 bouyer case I2C_HID_CMD_RESET: {
360 1.1 bouyer uint8_t cmd[] = {
361 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff,
362 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8,
363 1.1 bouyer 0,
364 1.1 bouyer I2C_HID_CMD_RESET,
365 1.1 bouyer };
366 1.1 bouyer
367 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_RESET\n",
368 1.28 riastrad device_xname(sc->sc_dev)));
369 1.1 bouyer
370 1.1 bouyer /* 22 00 00 01 */
371 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
372 1.1 bouyer &cmd, sizeof(cmd), NULL, 0, flags);
373 1.1 bouyer
374 1.1 bouyer break;
375 1.1 bouyer }
376 1.1 bouyer case I2C_HID_CMD_GET_REPORT: {
377 1.1 bouyer struct i2c_hid_report_request *rreq =
378 1.1 bouyer (struct i2c_hid_report_request *)arg;
379 1.1 bouyer
380 1.1 bouyer uint8_t cmd[] = {
381 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff,
382 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8,
383 1.1 bouyer 0,
384 1.1 bouyer I2C_HID_CMD_GET_REPORT,
385 1.1 bouyer 0, 0, 0,
386 1.1 bouyer };
387 1.1 bouyer int cmdlen = 7;
388 1.1 bouyer int dataoff = 4;
389 1.1 bouyer int report_id = rreq->id;
390 1.1 bouyer int report_id_len = 1;
391 1.1 bouyer int report_len = rreq->len + 2;
392 1.1 bouyer int d;
393 1.1 bouyer uint8_t *tmprep;
394 1.1 bouyer
395 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_GET_REPORT %d "
396 1.28 riastrad "(type %d, len %d)\n", device_xname(sc->sc_dev), report_id,
397 1.1 bouyer rreq->type, rreq->len));
398 1.1 bouyer
399 1.1 bouyer /*
400 1.1 bouyer * 7.2.2.4 - "The protocol is optimized for Report < 15. If a
401 1.1 bouyer * report ID >= 15 is necessary, then the Report ID in the Low
402 1.1 bouyer * Byte must be set to 1111 and a Third Byte is appended to the
403 1.1 bouyer * protocol. This Third Byte contains the entire/actual report
404 1.1 bouyer * ID."
405 1.1 bouyer */
406 1.1 bouyer if (report_id >= 15) {
407 1.1 bouyer cmd[dataoff++] = report_id;
408 1.1 bouyer report_id = 15;
409 1.1 bouyer report_id_len = 2;
410 1.1 bouyer } else
411 1.1 bouyer cmdlen--;
412 1.1 bouyer
413 1.1 bouyer cmd[2] = report_id | rreq->type << 4;
414 1.1 bouyer
415 1.1 bouyer cmd[dataoff++] = sc->hid_desc.wDataRegister & 0xff;
416 1.1 bouyer cmd[dataoff] = sc->hid_desc.wDataRegister >> 8;
417 1.1 bouyer
418 1.1 bouyer /*
419 1.1 bouyer * 7.2.2.2 - Response will be a 2-byte length value, the report
420 1.1 bouyer * id with length determined above, and then the report.
421 1.1 bouyer * Allocate rreq->len + 2 + 2 bytes, read into that temporary
422 1.1 bouyer * buffer, and then copy only the report back out to
423 1.1 bouyer * rreq->data.
424 1.1 bouyer */
425 1.1 bouyer report_len += report_id_len;
426 1.1 bouyer tmprep = kmem_zalloc(report_len, KM_NOSLEEP);
427 1.23 riastrad if (tmprep == NULL) {
428 1.23 riastrad /* XXX pool or preallocate? */
429 1.23 riastrad DPRINTF(("%s: out of memory\n",
430 1.23 riastrad device_xname(sc->sc_dev)));
431 1.23 riastrad res = ENOMEM;
432 1.23 riastrad break;
433 1.23 riastrad }
434 1.1 bouyer
435 1.1 bouyer /* type 3 id 8: 22 00 38 02 23 00 */
436 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
437 1.1 bouyer &cmd, cmdlen, tmprep, report_len, flags);
438 1.1 bouyer
439 1.1 bouyer d = tmprep[0] | tmprep[1] << 8;
440 1.1 bouyer if (d != report_len) {
441 1.1 bouyer DPRINTF(("%s: response size %d != expected length %d\n",
442 1.28 riastrad device_xname(sc->sc_dev), d, report_len));
443 1.1 bouyer }
444 1.1 bouyer
445 1.1 bouyer if (report_id_len == 2)
446 1.1 bouyer d = tmprep[2] | tmprep[3] << 8;
447 1.1 bouyer else
448 1.1 bouyer d = tmprep[2];
449 1.1 bouyer
450 1.1 bouyer if (d != rreq->id) {
451 1.1 bouyer DPRINTF(("%s: response report id %d != %d\n",
452 1.28 riastrad device_xname(sc->sc_dev), d, rreq->id));
453 1.1 bouyer iic_release_bus(sc->sc_tag, 0);
454 1.1 bouyer kmem_free(tmprep, report_len);
455 1.1 bouyer return (1);
456 1.1 bouyer }
457 1.1 bouyer
458 1.28 riastrad DPRINTF(("%s: response:", device_xname(sc->sc_dev)));
459 1.1 bouyer for (i = 0; i < report_len; i++)
460 1.1 bouyer DPRINTF((" %.2x", tmprep[i]));
461 1.1 bouyer DPRINTF(("\n"));
462 1.1 bouyer
463 1.1 bouyer memcpy(rreq->data, tmprep + 2 + report_id_len, rreq->len);
464 1.1 bouyer kmem_free(tmprep, report_len);
465 1.1 bouyer
466 1.1 bouyer break;
467 1.1 bouyer }
468 1.1 bouyer case I2C_HID_CMD_SET_REPORT: {
469 1.1 bouyer struct i2c_hid_report_request *rreq =
470 1.1 bouyer (struct i2c_hid_report_request *)arg;
471 1.1 bouyer
472 1.1 bouyer uint8_t cmd[] = {
473 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff,
474 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8,
475 1.1 bouyer 0,
476 1.1 bouyer I2C_HID_CMD_SET_REPORT,
477 1.1 bouyer 0, 0, 0, 0, 0, 0,
478 1.1 bouyer };
479 1.1 bouyer int cmdlen = 10;
480 1.1 bouyer int report_id = rreq->id;
481 1.1 bouyer int report_len = 2 + (report_id ? 1 : 0) + rreq->len;
482 1.1 bouyer int dataoff;
483 1.1 bouyer uint8_t *finalcmd;
484 1.1 bouyer
485 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_SET_REPORT %d "
486 1.28 riastrad "(type %d, len %d):", device_xname(sc->sc_dev), report_id,
487 1.1 bouyer rreq->type, rreq->len));
488 1.1 bouyer for (i = 0; i < rreq->len; i++)
489 1.1 bouyer DPRINTF((" %.2x", ((uint8_t *)rreq->data)[i]));
490 1.1 bouyer DPRINTF(("\n"));
491 1.1 bouyer
492 1.1 bouyer /*
493 1.1 bouyer * 7.2.2.4 - "The protocol is optimized for Report < 15. If a
494 1.1 bouyer * report ID >= 15 is necessary, then the Report ID in the Low
495 1.1 bouyer * Byte must be set to 1111 and a Third Byte is appended to the
496 1.1 bouyer * protocol. This Third Byte contains the entire/actual report
497 1.1 bouyer * ID."
498 1.1 bouyer */
499 1.1 bouyer dataoff = 4;
500 1.1 bouyer if (report_id >= 15) {
501 1.1 bouyer cmd[dataoff++] = report_id;
502 1.1 bouyer report_id = 15;
503 1.1 bouyer } else
504 1.1 bouyer cmdlen--;
505 1.1 bouyer
506 1.1 bouyer cmd[2] = report_id | rreq->type << 4;
507 1.1 bouyer
508 1.1 bouyer if (rreq->type == I2C_HID_REPORT_TYPE_FEATURE) {
509 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister)
510 1.1 bouyer & 0xff;
511 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister)
512 1.1 bouyer >> 8;
513 1.1 bouyer } else {
514 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister)
515 1.1 bouyer & 0xff;
516 1.1 bouyer cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister)
517 1.1 bouyer >> 8;
518 1.1 bouyer }
519 1.1 bouyer
520 1.1 bouyer cmd[dataoff++] = report_len & 0xff;
521 1.1 bouyer cmd[dataoff++] = report_len >> 8;
522 1.1 bouyer cmd[dataoff] = rreq->id;
523 1.1 bouyer
524 1.1 bouyer finalcmd = kmem_zalloc(cmdlen + rreq->len, KM_NOSLEEP);
525 1.23 riastrad if (finalcmd == NULL) {
526 1.23 riastrad res = ENOMEM;
527 1.23 riastrad break;
528 1.23 riastrad }
529 1.1 bouyer
530 1.1 bouyer memcpy(finalcmd, cmd, cmdlen);
531 1.1 bouyer memcpy(finalcmd + cmdlen, rreq->data, rreq->len);
532 1.1 bouyer
533 1.1 bouyer /* type 3 id 4: 22 00 34 03 23 00 04 00 04 03 */
534 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
535 1.1 bouyer finalcmd, cmdlen + rreq->len, NULL, 0, flags);
536 1.1 bouyer kmem_free(finalcmd, cmdlen + rreq->len);
537 1.1 bouyer
538 1.1 bouyer break;
539 1.1 bouyer }
540 1.1 bouyer
541 1.1 bouyer case I2C_HID_CMD_SET_POWER: {
542 1.1 bouyer int power = *(int *)arg;
543 1.1 bouyer uint8_t cmd[] = {
544 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) & 0xff,
545 1.1 bouyer htole16(sc->hid_desc.wCommandRegister) >> 8,
546 1.1 bouyer power,
547 1.1 bouyer I2C_HID_CMD_SET_POWER,
548 1.1 bouyer };
549 1.1 bouyer
550 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_CMD_SET_POWER(%d)\n",
551 1.28 riastrad device_xname(sc->sc_dev), power));
552 1.1 bouyer
553 1.1 bouyer /* 22 00 00 08 */
554 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
555 1.1 bouyer &cmd, sizeof(cmd), NULL, 0, flags);
556 1.1 bouyer
557 1.1 bouyer break;
558 1.1 bouyer }
559 1.1 bouyer case I2C_HID_REPORT_DESCR: {
560 1.1 bouyer uint8_t cmd[] = {
561 1.1 bouyer htole16(sc->hid_desc.wReportDescRegister) & 0xff,
562 1.1 bouyer htole16(sc->hid_desc.wReportDescRegister) >> 8,
563 1.1 bouyer };
564 1.1 bouyer
565 1.1 bouyer DPRINTF(("%s: HID command I2C_HID_REPORT_DESCR at 0x%x with "
566 1.28 riastrad "size %d\n", device_xname(sc->sc_dev), cmd[0],
567 1.1 bouyer sc->sc_reportlen));
568 1.1 bouyer
569 1.1 bouyer /* 20 00 */
570 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
571 1.1 bouyer &cmd, sizeof(cmd), sc->sc_report, sc->sc_reportlen, flags);
572 1.1 bouyer
573 1.28 riastrad DPRINTF(("%s: HID report descriptor:",
574 1.28 riastrad device_xname(sc->sc_dev)));
575 1.1 bouyer for (i = 0; i < sc->sc_reportlen; i++)
576 1.1 bouyer DPRINTF((" %.2x", sc->sc_report[i]));
577 1.1 bouyer DPRINTF(("\n"));
578 1.1 bouyer
579 1.1 bouyer break;
580 1.1 bouyer }
581 1.1 bouyer default:
582 1.1 bouyer aprint_error_dev(sc->sc_dev, "unknown command %d\n",
583 1.1 bouyer hidcmd);
584 1.1 bouyer }
585 1.1 bouyer
586 1.1 bouyer iic_release_bus(sc->sc_tag, flags);
587 1.1 bouyer
588 1.1 bouyer return (res);
589 1.1 bouyer }
590 1.1 bouyer
591 1.1 bouyer static int
592 1.1 bouyer ihidev_reset(struct ihidev_softc *sc, bool poll)
593 1.1 bouyer {
594 1.28 riastrad DPRINTF(("%s: resetting\n", device_xname(sc->sc_dev)));
595 1.1 bouyer
596 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
597 1.1 bouyer &I2C_HID_POWER_ON, poll)) {
598 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power on\n");
599 1.1 bouyer return (1);
600 1.1 bouyer }
601 1.1 bouyer
602 1.1 bouyer DELAY(1000);
603 1.1 bouyer
604 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_RESET, 0, poll)) {
605 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to reset hardware\n");
606 1.1 bouyer
607 1.1 bouyer ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
608 1.1 bouyer &I2C_HID_POWER_OFF, poll);
609 1.1 bouyer
610 1.1 bouyer return (1);
611 1.1 bouyer }
612 1.1 bouyer
613 1.1 bouyer DELAY(1000);
614 1.1 bouyer
615 1.1 bouyer return (0);
616 1.1 bouyer }
617 1.1 bouyer
618 1.1 bouyer /*
619 1.1 bouyer * 5.2.2 - HID Descriptor Retrieval
620 1.1 bouyer *
621 1.1 bouyer * parse HID Descriptor that has already been read into hid_desc with
622 1.1 bouyer * I2C_HID_CMD_DESCR
623 1.1 bouyer */
624 1.1 bouyer static int
625 1.1 bouyer ihidev_hid_desc_parse(struct ihidev_softc *sc)
626 1.1 bouyer {
627 1.1 bouyer int retries = 3;
628 1.1 bouyer
629 1.1 bouyer /* must be v01.00 */
630 1.1 bouyer if (le16toh(sc->hid_desc.bcdVersion) != 0x0100) {
631 1.1 bouyer aprint_error_dev(sc->sc_dev,
632 1.1 bouyer "bad HID descriptor bcdVersion (0x%x)\n",
633 1.1 bouyer le16toh(sc->hid_desc.bcdVersion));
634 1.1 bouyer return (1);
635 1.1 bouyer }
636 1.1 bouyer
637 1.1 bouyer /* must be 30 bytes for v1.00 */
638 1.1 bouyer if (le16toh(sc->hid_desc.wHIDDescLength !=
639 1.1 bouyer sizeof(struct i2c_hid_desc))) {
640 1.1 bouyer aprint_error_dev(sc->sc_dev,
641 1.1 bouyer "bad HID descriptor size (%d != %zu)\n",
642 1.1 bouyer le16toh(sc->hid_desc.wHIDDescLength),
643 1.1 bouyer sizeof(struct i2c_hid_desc));
644 1.1 bouyer return (1);
645 1.1 bouyer }
646 1.1 bouyer
647 1.1 bouyer if (le16toh(sc->hid_desc.wReportDescLength) <= 0) {
648 1.1 bouyer aprint_error_dev(sc->sc_dev,
649 1.1 bouyer "bad HID report descriptor size (%d)\n",
650 1.1 bouyer le16toh(sc->hid_desc.wReportDescLength));
651 1.1 bouyer return (1);
652 1.1 bouyer }
653 1.1 bouyer
654 1.1 bouyer while (retries-- > 0) {
655 1.1 bouyer if (ihidev_reset(sc, false)) {
656 1.1 bouyer if (retries == 0)
657 1.1 bouyer return(1);
658 1.1 bouyer
659 1.1 bouyer DELAY(1000);
660 1.1 bouyer }
661 1.1 bouyer else
662 1.1 bouyer break;
663 1.1 bouyer }
664 1.1 bouyer
665 1.1 bouyer sc->sc_reportlen = le16toh(sc->hid_desc.wReportDescLength);
666 1.22 riastrad sc->sc_report = kmem_zalloc(sc->sc_reportlen, KM_SLEEP);
667 1.1 bouyer
668 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_REPORT_DESCR, 0, false)) {
669 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed fetching HID report\n");
670 1.1 bouyer return (1);
671 1.1 bouyer }
672 1.1 bouyer
673 1.1 bouyer return (0);
674 1.1 bouyer }
675 1.1 bouyer
676 1.12 thorpej static bool
677 1.21 riastrad ihidev_intr_init(struct ihidev_softc *sc)
678 1.12 thorpej {
679 1.12 thorpej #if NACPICA > 0
680 1.12 thorpej ACPI_HANDLE hdl = (void *)(uintptr_t)sc->sc_phandle;
681 1.12 thorpej struct acpi_resources res;
682 1.12 thorpej ACPI_STATUS rv;
683 1.12 thorpej char buf[100];
684 1.12 thorpej
685 1.12 thorpej rv = acpi_resource_parse(sc->sc_dev, hdl, "_CRS", &res,
686 1.12 thorpej &acpi_resource_parse_ops_quiet);
687 1.12 thorpej if (ACPI_FAILURE(rv)) {
688 1.12 thorpej aprint_error_dev(sc->sc_dev, "can't parse '_CRS'\n");
689 1.12 thorpej return false;
690 1.12 thorpej }
691 1.12 thorpej
692 1.12 thorpej const struct acpi_irq * const irq = acpi_res_irq(&res, 0);
693 1.12 thorpej if (irq == NULL) {
694 1.31 jmcneill aprint_debug_dev(sc->sc_dev, "no IRQ resource\n");
695 1.12 thorpej acpi_resource_cleanup(&res);
696 1.31 jmcneill #if NGPIO > 0
697 1.31 jmcneill goto try_gpioint;
698 1.31 jmcneill #else
699 1.12 thorpej return false;
700 1.31 jmcneill #endif
701 1.12 thorpej }
702 1.12 thorpej
703 1.12 thorpej sc->sc_intr_type =
704 1.12 thorpej irq->ar_type == ACPI_EDGE_SENSITIVE ? IST_EDGE : IST_LEVEL;
705 1.12 thorpej
706 1.12 thorpej acpi_resource_cleanup(&res);
707 1.12 thorpej
708 1.12 thorpej sc->sc_ih = acpi_intr_establish(sc->sc_dev, sc->sc_phandle, IPL_TTY,
709 1.12 thorpej false, ihidev_intr, sc, device_xname(sc->sc_dev));
710 1.12 thorpej if (sc->sc_ih == NULL) {
711 1.12 thorpej aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
712 1.12 thorpej return false;
713 1.12 thorpej }
714 1.12 thorpej aprint_normal_dev(sc->sc_dev, "interrupting at %s\n",
715 1.12 thorpej acpi_intr_string(sc->sc_ih, buf, sizeof(buf)));
716 1.12 thorpej
717 1.31 jmcneill #if NGPIO > 0
718 1.31 jmcneill try_gpioint:
719 1.31 jmcneill if (sc->sc_ih == NULL) {
720 1.31 jmcneill int pin, irqmode, error;
721 1.31 jmcneill
722 1.31 jmcneill rv = acpi_gpio_get_int(hdl, 0, &sc->sc_ih_gpio, &pin, &irqmode);
723 1.31 jmcneill if (ACPI_FAILURE(rv)) {
724 1.31 jmcneill aprint_error_dev(sc->sc_dev,
725 1.31 jmcneill "can't find gpioint resource\n");
726 1.31 jmcneill return false;
727 1.31 jmcneill }
728 1.31 jmcneill device_printf(sc->sc_dev, "[GPIO] got controller %p\n", sc->sc_ih_gpio);
729 1.31 jmcneill
730 1.31 jmcneill sc->sc_ih_gpiomap.pm_map = sc->sc_ih_gpiopins;
731 1.31 jmcneill error = gpio_pin_map(sc->sc_ih_gpio, pin, 1,
732 1.31 jmcneill &sc->sc_ih_gpiomap);
733 1.31 jmcneill if (error) {
734 1.31 jmcneill aprint_error_dev(sc->sc_dev, "can't map pin %d\n", pin);
735 1.31 jmcneill return false;
736 1.31 jmcneill }
737 1.31 jmcneill
738 1.31 jmcneill sc->sc_ih = gpio_intr_establish(sc->sc_ih_gpio,
739 1.31 jmcneill &sc->sc_ih_gpiomap, 0, IPL_VM, irqmode, ihidev_intr, sc);
740 1.31 jmcneill if (sc->sc_ih == NULL) {
741 1.31 jmcneill aprint_error_dev(sc->sc_dev,
742 1.31 jmcneill "can't establish gpio interrupt\n");
743 1.31 jmcneill return false;
744 1.31 jmcneill }
745 1.31 jmcneill
746 1.31 jmcneill sc->sc_intr_type = (irqmode & GPIO_INTR_LEVEL_MASK) ?
747 1.31 jmcneill IST_LEVEL : IST_EDGE;
748 1.31 jmcneill
749 1.31 jmcneill gpio_intr_str(sc->sc_ih_gpio, &sc->sc_ih_gpiomap, 0,
750 1.31 jmcneill irqmode, buf, sizeof(buf));
751 1.31 jmcneill aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", buf);
752 1.31 jmcneill }
753 1.31 jmcneill #endif
754 1.31 jmcneill
755 1.21 riastrad if (workqueue_create(&sc->sc_wq, device_xname(sc->sc_dev), ihidev_work,
756 1.21 riastrad sc, PRI_NONE, IPL_TTY, WQ_MPSAFE)) {
757 1.12 thorpej aprint_error_dev(sc->sc_dev,
758 1.21 riastrad "can't establish workqueue\n");
759 1.12 thorpej return false;
760 1.12 thorpej }
761 1.21 riastrad sc->sc_work_pending = 0;
762 1.12 thorpej
763 1.12 thorpej return true;
764 1.12 thorpej #else
765 1.12 thorpej aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
766 1.12 thorpej return false;
767 1.12 thorpej #endif
768 1.12 thorpej }
769 1.12 thorpej
770 1.12 thorpej static void
771 1.21 riastrad ihidev_intr_fini(struct ihidev_softc *sc)
772 1.12 thorpej {
773 1.12 thorpej #if NACPICA > 0
774 1.12 thorpej if (sc->sc_ih != NULL) {
775 1.31 jmcneill if (sc->sc_ih_gpio != NULL) {
776 1.31 jmcneill #if NGPIO > 0
777 1.31 jmcneill gpio_intr_disestablish(sc->sc_ih_gpio, sc->sc_ih);
778 1.31 jmcneill #endif
779 1.31 jmcneill } else {
780 1.31 jmcneill acpi_intr_disestablish(sc->sc_ih);
781 1.31 jmcneill }
782 1.12 thorpej }
783 1.21 riastrad if (sc->sc_wq != NULL) {
784 1.21 riastrad workqueue_destroy(sc->sc_wq);
785 1.12 thorpej }
786 1.12 thorpej #endif
787 1.12 thorpej }
788 1.12 thorpej
789 1.30 andvar #if NACPICA > 0
790 1.12 thorpej static void
791 1.12 thorpej ihidev_intr_mask(struct ihidev_softc * const sc)
792 1.12 thorpej {
793 1.12 thorpej
794 1.12 thorpej if (sc->sc_intr_type == IST_LEVEL) {
795 1.31 jmcneill if (sc->sc_ih_gpio != NULL) {
796 1.31 jmcneill #if NGPIO > 0
797 1.31 jmcneill gpio_intr_mask(sc->sc_ih_gpio, sc->sc_ih);
798 1.31 jmcneill #endif
799 1.31 jmcneill } else {
800 1.31 jmcneill acpi_intr_mask(sc->sc_ih);
801 1.31 jmcneill }
802 1.12 thorpej }
803 1.12 thorpej }
804 1.12 thorpej
805 1.12 thorpej static void
806 1.12 thorpej ihidev_intr_unmask(struct ihidev_softc * const sc)
807 1.12 thorpej {
808 1.12 thorpej
809 1.12 thorpej if (sc->sc_intr_type == IST_LEVEL) {
810 1.31 jmcneill if (sc->sc_ih_gpio != NULL) {
811 1.31 jmcneill #if NGPIO > 0
812 1.31 jmcneill gpio_intr_unmask(sc->sc_ih_gpio, sc->sc_ih);
813 1.31 jmcneill #endif
814 1.31 jmcneill } else {
815 1.31 jmcneill acpi_intr_unmask(sc->sc_ih);
816 1.31 jmcneill }
817 1.12 thorpej }
818 1.12 thorpej }
819 1.12 thorpej
820 1.7 jmcneill static int
821 1.1 bouyer ihidev_intr(void *arg)
822 1.1 bouyer {
823 1.12 thorpej struct ihidev_softc * const sc = arg;
824 1.12 thorpej
825 1.12 thorpej /*
826 1.21 riastrad * Schedule our work. If we're using a level-triggered
827 1.21 riastrad * interrupt, we have to mask it off while we wait for service.
828 1.12 thorpej */
829 1.21 riastrad if (atomic_swap_uint(&sc->sc_work_pending, 1) == 0)
830 1.21 riastrad workqueue_enqueue(sc->sc_wq, &sc->sc_work, NULL);
831 1.12 thorpej ihidev_intr_mask(sc);
832 1.12 thorpej
833 1.12 thorpej return 1;
834 1.12 thorpej }
835 1.12 thorpej
836 1.12 thorpej static void
837 1.21 riastrad ihidev_work(struct work *wk, void *arg)
838 1.12 thorpej {
839 1.12 thorpej struct ihidev_softc * const sc = arg;
840 1.1 bouyer struct ihidev *scd;
841 1.1 bouyer u_int psize;
842 1.1 bouyer int res, i;
843 1.1 bouyer u_char *p;
844 1.1 bouyer u_int rep = 0;
845 1.1 bouyer
846 1.21 riastrad atomic_store_relaxed(&sc->sc_work_pending, 0);
847 1.21 riastrad
848 1.21 riastrad mutex_enter(&sc->sc_lock);
849 1.21 riastrad
850 1.12 thorpej iic_acquire_bus(sc->sc_tag, 0);
851 1.1 bouyer res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0,
852 1.12 thorpej sc->sc_ibuf, sc->sc_isize, 0);
853 1.12 thorpej iic_release_bus(sc->sc_tag, 0);
854 1.1 bouyer if (res != 0)
855 1.12 thorpej goto out;
856 1.1 bouyer
857 1.1 bouyer /*
858 1.1 bouyer * 6.1.1 - First two bytes are the packet length, which must be less
859 1.1 bouyer * than or equal to wMaxInputLength
860 1.1 bouyer */
861 1.1 bouyer psize = sc->sc_ibuf[0] | sc->sc_ibuf[1] << 8;
862 1.1 bouyer if (!psize || psize > sc->sc_isize) {
863 1.1 bouyer DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n",
864 1.28 riastrad device_xname(sc->sc_dev), __func__, psize, sc->sc_isize));
865 1.12 thorpej goto out;
866 1.1 bouyer }
867 1.1 bouyer
868 1.1 bouyer /* 3rd byte is the report id */
869 1.1 bouyer p = sc->sc_ibuf + 2;
870 1.1 bouyer psize -= 2;
871 1.1 bouyer if (sc->sc_nrepid != 1)
872 1.1 bouyer rep = *p++, psize--;
873 1.1 bouyer
874 1.1 bouyer if (rep >= sc->sc_nrepid) {
875 1.1 bouyer aprint_error_dev(sc->sc_dev, "%s: bad report id %d\n",
876 1.1 bouyer __func__, rep);
877 1.12 thorpej goto out;
878 1.1 bouyer }
879 1.1 bouyer
880 1.28 riastrad DPRINTF(("%s: %s: hid input (rep %d):", device_xname(sc->sc_dev),
881 1.12 thorpej __func__, rep));
882 1.1 bouyer for (i = 0; i < sc->sc_isize; i++)
883 1.1 bouyer DPRINTF((" %.2x", sc->sc_ibuf[i]));
884 1.1 bouyer DPRINTF(("\n"));
885 1.1 bouyer
886 1.1 bouyer scd = sc->sc_subdevs[rep];
887 1.1 bouyer if (scd == NULL || !(scd->sc_state & IHIDEV_OPEN))
888 1.12 thorpej goto out;
889 1.1 bouyer
890 1.1 bouyer scd->sc_intr(scd, p, psize);
891 1.1 bouyer
892 1.12 thorpej out:
893 1.21 riastrad mutex_exit(&sc->sc_lock);
894 1.21 riastrad
895 1.12 thorpej /*
896 1.12 thorpej * If our interrupt is level-triggered, re-enable it now.
897 1.12 thorpej */
898 1.12 thorpej ihidev_intr_unmask(sc);
899 1.1 bouyer }
900 1.30 andvar #endif
901 1.1 bouyer
902 1.1 bouyer static int
903 1.1 bouyer ihidev_maxrepid(void *buf, int len)
904 1.1 bouyer {
905 1.1 bouyer struct hid_data *d;
906 1.1 bouyer struct hid_item h;
907 1.1 bouyer int maxid;
908 1.1 bouyer
909 1.1 bouyer maxid = -1;
910 1.1 bouyer h.report_ID = 0;
911 1.1 bouyer for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
912 1.6 jakllsch if ((int)h.report_ID > maxid)
913 1.1 bouyer maxid = h.report_ID;
914 1.1 bouyer hid_end_parse(d);
915 1.1 bouyer
916 1.1 bouyer return (maxid);
917 1.1 bouyer }
918 1.1 bouyer
919 1.1 bouyer static int
920 1.1 bouyer ihidev_print(void *aux, const char *pnp)
921 1.1 bouyer {
922 1.1 bouyer struct ihidev_attach_arg *iha = aux;
923 1.1 bouyer
924 1.1 bouyer if (iha->reportid == IHIDEV_CLAIM_ALLREPORTID)
925 1.1 bouyer return (QUIET);
926 1.21 riastrad
927 1.1 bouyer if (pnp)
928 1.1 bouyer aprint_normal("hid at %s", pnp);
929 1.1 bouyer
930 1.1 bouyer if (iha->reportid != 0)
931 1.1 bouyer aprint_normal(" reportid %d", iha->reportid);
932 1.1 bouyer
933 1.1 bouyer return (UNCONF);
934 1.1 bouyer }
935 1.1 bouyer
936 1.1 bouyer static int
937 1.1 bouyer ihidev_submatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
938 1.1 bouyer {
939 1.1 bouyer struct ihidev_attach_arg *iha = aux;
940 1.1 bouyer
941 1.1 bouyer if (cf->ihidevcf_reportid != IHIDEV_UNK_REPORTID &&
942 1.1 bouyer cf->ihidevcf_reportid != iha->reportid)
943 1.1 bouyer return (0);
944 1.1 bouyer
945 1.1 bouyer return config_match(parent, cf, aux);
946 1.1 bouyer }
947 1.1 bouyer
948 1.1 bouyer int
949 1.1 bouyer ihidev_open(struct ihidev *scd)
950 1.1 bouyer {
951 1.1 bouyer struct ihidev_softc *sc = scd->sc_parent;
952 1.24 riastrad int error;
953 1.1 bouyer
954 1.28 riastrad DPRINTF(("%s: %s: state=%d refcnt=%d\n", device_xname(sc->sc_dev),
955 1.1 bouyer __func__, scd->sc_state, sc->sc_refcnt));
956 1.1 bouyer
957 1.24 riastrad mutex_enter(&sc->sc_lock);
958 1.24 riastrad
959 1.25 riastrad if (scd->sc_state & IHIDEV_OPEN || sc->sc_refcnt == INT_MAX) {
960 1.24 riastrad error = EBUSY;
961 1.24 riastrad goto out;
962 1.24 riastrad }
963 1.1 bouyer
964 1.1 bouyer scd->sc_state |= IHIDEV_OPEN;
965 1.1 bouyer
966 1.24 riastrad if (sc->sc_refcnt++ || sc->sc_isize == 0) {
967 1.24 riastrad error = 0;
968 1.24 riastrad goto out;
969 1.24 riastrad }
970 1.1 bouyer
971 1.1 bouyer /* power on */
972 1.1 bouyer ihidev_reset(sc, false);
973 1.24 riastrad error = 0;
974 1.1 bouyer
975 1.24 riastrad out: mutex_exit(&sc->sc_lock);
976 1.24 riastrad return error;
977 1.1 bouyer }
978 1.1 bouyer
979 1.1 bouyer void
980 1.1 bouyer ihidev_close(struct ihidev *scd)
981 1.1 bouyer {
982 1.1 bouyer struct ihidev_softc *sc = scd->sc_parent;
983 1.1 bouyer
984 1.28 riastrad DPRINTF(("%s: %s: state=%d refcnt=%d\n", device_xname(sc->sc_dev),
985 1.1 bouyer __func__, scd->sc_state, sc->sc_refcnt));
986 1.1 bouyer
987 1.24 riastrad mutex_enter(&sc->sc_lock);
988 1.24 riastrad
989 1.26 riastrad KASSERTMSG(scd->sc_state & IHIDEV_OPEN,
990 1.26 riastrad "%s: closing %s when not open",
991 1.26 riastrad device_xname(scd->sc_idev),
992 1.26 riastrad device_xname(sc->sc_dev));
993 1.1 bouyer scd->sc_state &= ~IHIDEV_OPEN;
994 1.1 bouyer
995 1.1 bouyer if (--sc->sc_refcnt)
996 1.24 riastrad goto out;
997 1.1 bouyer
998 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
999 1.1 bouyer &I2C_HID_POWER_OFF, false))
1000 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power down\n");
1001 1.24 riastrad
1002 1.24 riastrad out: mutex_exit(&sc->sc_lock);
1003 1.1 bouyer }
1004 1.1 bouyer
1005 1.1 bouyer void
1006 1.1 bouyer ihidev_get_report_desc(struct ihidev_softc *sc, void **desc, int *size)
1007 1.1 bouyer {
1008 1.1 bouyer *desc = sc->sc_report;
1009 1.1 bouyer *size = sc->sc_reportlen;
1010 1.1 bouyer }
1011 1.1 bouyer
1012 1.1 bouyer /* convert hid_* constants used throughout HID code to i2c HID equivalents */
1013 1.1 bouyer int
1014 1.1 bouyer ihidev_report_type_conv(int hid_type_id)
1015 1.1 bouyer {
1016 1.1 bouyer switch (hid_type_id) {
1017 1.1 bouyer case hid_input:
1018 1.1 bouyer return I2C_HID_REPORT_TYPE_INPUT;
1019 1.1 bouyer case hid_output:
1020 1.1 bouyer return I2C_HID_REPORT_TYPE_OUTPUT;
1021 1.1 bouyer case hid_feature:
1022 1.1 bouyer return I2C_HID_REPORT_TYPE_FEATURE;
1023 1.1 bouyer default:
1024 1.1 bouyer return -1;
1025 1.1 bouyer }
1026 1.1 bouyer }
1027 1.1 bouyer
1028 1.1 bouyer int
1029 1.1 bouyer ihidev_get_report(struct device *dev, int type, int id, void *data, int len)
1030 1.1 bouyer {
1031 1.1 bouyer struct ihidev_softc *sc = (struct ihidev_softc *)dev;
1032 1.1 bouyer struct i2c_hid_report_request rreq;
1033 1.1 bouyer int ctype;
1034 1.1 bouyer
1035 1.1 bouyer if ((ctype = ihidev_report_type_conv(type)) < 0)
1036 1.1 bouyer return (1);
1037 1.1 bouyer
1038 1.1 bouyer rreq.type = ctype;
1039 1.1 bouyer rreq.id = id;
1040 1.1 bouyer rreq.data = data;
1041 1.1 bouyer rreq.len = len;
1042 1.1 bouyer
1043 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_GET_REPORT, &rreq, false)) {
1044 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed fetching report\n");
1045 1.1 bouyer return (1);
1046 1.1 bouyer }
1047 1.1 bouyer
1048 1.1 bouyer return 0;
1049 1.1 bouyer }
1050 1.1 bouyer
1051 1.1 bouyer int
1052 1.1 bouyer ihidev_set_report(struct device *dev, int type, int id, void *data,
1053 1.1 bouyer int len)
1054 1.1 bouyer {
1055 1.1 bouyer struct ihidev_softc *sc = (struct ihidev_softc *)dev;
1056 1.1 bouyer struct i2c_hid_report_request rreq;
1057 1.1 bouyer int ctype;
1058 1.1 bouyer
1059 1.1 bouyer if ((ctype = ihidev_report_type_conv(type)) < 0)
1060 1.1 bouyer return (1);
1061 1.1 bouyer
1062 1.1 bouyer rreq.type = ctype;
1063 1.1 bouyer rreq.id = id;
1064 1.1 bouyer rreq.data = data;
1065 1.1 bouyer rreq.len = len;
1066 1.1 bouyer
1067 1.1 bouyer if (ihidev_hid_command(sc, I2C_HID_CMD_SET_REPORT, &rreq, false)) {
1068 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed setting report\n");
1069 1.1 bouyer return (1);
1070 1.1 bouyer }
1071 1.1 bouyer
1072 1.1 bouyer return 0;
1073 1.1 bouyer }
1074 1.17 thorpej
1075 1.17 thorpej static bool
1076 1.17 thorpej ihidev_acpi_get_info(struct ihidev_softc *sc)
1077 1.21 riastrad {
1078 1.30 andvar #if NACPICA > 0
1079 1.17 thorpej ACPI_HANDLE hdl = (void *)(uintptr_t)sc->sc_phandle;
1080 1.17 thorpej ACPI_STATUS status;
1081 1.17 thorpej ACPI_INTEGER val;
1082 1.17 thorpej
1083 1.17 thorpej /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
1084 1.17 thorpej uint8_t i2c_hid_guid[] = {
1085 1.17 thorpej 0xF7, 0xF6, 0xDF, 0x3C,
1086 1.17 thorpej 0x67, 0x42,
1087 1.17 thorpej 0x55, 0x45,
1088 1.17 thorpej 0xAD, 0x05,
1089 1.17 thorpej 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
1090 1.17 thorpej };
1091 1.17 thorpej
1092 1.17 thorpej status = acpi_dsm_integer(hdl, i2c_hid_guid, 1, 1, NULL, &val);
1093 1.17 thorpej if (ACPI_FAILURE(status)) {
1094 1.17 thorpej aprint_error_dev(sc->sc_dev,
1095 1.17 thorpej "failed to get HidDescriptorAddress: %s\n",
1096 1.27 skrll AcpiFormatException(status));
1097 1.17 thorpej return false;
1098 1.17 thorpej }
1099 1.17 thorpej
1100 1.17 thorpej sc->sc_hid_desc_addr = (u_int)val;
1101 1.17 thorpej
1102 1.17 thorpej return true;
1103 1.30 andvar #else
1104 1.30 andvar return false;
1105 1.30 andvar #endif
1106 1.17 thorpej }
1107