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