Bug Summary

File:dev/i2c/ihidev.c
Warning:line 645, column 2
Value stored to 'res' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ihidev.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/i2c/ihidev.c
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 */
45enum {
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
60static int I2C_HID_POWER_ON = 0x0;
61static int I2C_HID_POWER_OFF = 0x1;
62
63int ihidev_match(struct device *, void *, void *);
64void ihidev_attach(struct device *, struct device *, void *);
65int ihidev_detach(struct device *, int);
66int ihidev_activate(struct device *, int);
67
68int ihidev_hid_command(struct ihidev_softc *, int, void *);
69int ihidev_intr(void *);
70int ihidev_reset(struct ihidev_softc *);
71int ihidev_hid_desc_parse(struct ihidev_softc *);
72
73int ihidev_maxrepid(void *buf, int len);
74int ihidev_print(void *aux, const char *pnp);
75int ihidev_submatch(struct device *parent, void *cf, void *aux);
76
77struct cfattach ihidev_ca = {
78 sizeof(struct ihidev_softc),
79 ihidev_match,
80 ihidev_attach,
81 ihidev_detach,
82 ihidev_activate,
83};
84
85struct cfdriver ihidev_cd = {
86 NULL((void *)0), "ihidev", DV_DULL
87};
88
89int
90ihidev_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
100void
101ihidev_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
208int
209ihidev_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
229int
230ihidev_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
262void
263ihidev_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
271int
272ihidev_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
525int
526ihidev_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 */
557int
558ihidev_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
610void
611ihidev_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
620int
621ihidev_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
717more_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
726int
727ihidev_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
743int
744ihidev_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
757int
758ihidev_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
770int
771ihidev_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
799void
800ihidev_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
824int
825ihidev_ioctl(struct ihidev *sc, u_long cmd, caddr_t addr, int flag,
826 struct proc *p)
827{
828 return -1;
829}
830
831void
832ihidev_get_report_desc(struct ihidev_softc *sc, void **desc, int *size)
833{
834 *desc = sc->sc_report;
835 *size = sc->sc_reportlen;
836}
837
838int
839ihidev_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
853int
854ihidev_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
872int
873ihidev_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}