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