FreeBSD/Linux Kernel Cross Reference
sys/dev/hid/hidmap.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 /*
32 * Abstract 1 to 1 HID input usage to evdev event mapper driver.
33 */
34
35 #include "opt_hid.h"
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/module.h>
43 #include <sys/sysctl.h>
44 #include <sys/systm.h>
45
46 #include <dev/evdev/input.h>
47 #include <dev/evdev/evdev.h>
48
49 #include <dev/hid/hid.h>
50 #include <dev/hid/hidbus.h>
51 #include <dev/hid/hidmap.h>
52
53 #ifdef HID_DEBUG
54 #define DPRINTFN(hm, n, fmt, ...) do { \
55 if ((hm)->debug_var != NULL && *(hm)->debug_var >= (n)) { \
56 device_printf((hm)->dev, "%s: " fmt, \
57 __FUNCTION__ ,##__VA_ARGS__); \
58 } \
59 } while (0)
60 #define DPRINTF(hm, ...) DPRINTFN(hm, 1, __VA_ARGS__)
61 #else
62 #define DPRINTF(...) do { } while (0)
63 #define DPRINTFN(...) do { } while (0)
64 #endif
65
66 static evdev_open_t hidmap_ev_open;
67 static evdev_close_t hidmap_ev_close;
68
69 #define HIDMAP_WANT_MERGE_KEYS(hm) ((hm)->key_rel != NULL)
70
71 #define HIDMAP_FOREACH_ITEM(hm, mi, uoff) \
72 for (u_int _map = 0, _item = 0, _uoff_priv = -1; \
73 ((mi) = hidmap_get_next_map_item( \
74 (hm), &_map, &_item, &_uoff_priv, &(uoff))) != NULL;)
75
76 static inline bool
77 hidmap_get_next_map_index(const struct hidmap_item *map, int nmap_items,
78 uint32_t *index, uint16_t *usage_offset)
79 {
80
81 ++*usage_offset;
82 if ((*index != 0 || *usage_offset != 0) &&
83 *usage_offset >= map[*index].nusages) {
84 ++*index;
85 *usage_offset = 0;
86 }
87
88 return (*index < nmap_items);
89 }
90
91 static inline const struct hidmap_item *
92 hidmap_get_next_map_item(struct hidmap *hm, u_int *map, u_int *item,
93 u_int *uoff_priv, uint16_t *uoff)
94 {
95
96 *uoff = *uoff_priv;
97 while (!hidmap_get_next_map_index(
98 hm->map[*map], hm->nmap_items[*map], item, uoff)) {
99 ++*map;
100 *item = 0;
101 *uoff = -1;
102 if (*map >= hm->nmaps)
103 return (NULL);
104 }
105 *uoff_priv = *uoff;
106
107 return (hm->map[*map] + *item);
108 }
109
110 void
111 _hidmap_set_debug_var(struct hidmap *hm, int *debug_var)
112 {
113 #ifdef HID_DEBUG
114 hm->debug_var = debug_var;
115 #endif
116 }
117
118 static int
119 hidmap_ev_close(struct evdev_dev *evdev)
120 {
121 return (hidbus_intr_stop(evdev_get_softc(evdev)));
122 }
123
124 static int
125 hidmap_ev_open(struct evdev_dev *evdev)
126 {
127 return (hidbus_intr_start(evdev_get_softc(evdev)));
128 }
129
130 void
131 hidmap_support_key(struct hidmap *hm, uint16_t key)
132 {
133 if (hm->key_press == NULL) {
134 hm->key_press = malloc(howmany(KEY_CNT, 8), M_DEVBUF,
135 M_ZERO | M_WAITOK);
136 evdev_support_event(hm->evdev, EV_KEY);
137 hm->key_min = key;
138 hm->key_max = key;
139 }
140 hm->key_min = MIN(hm->key_min, key);
141 hm->key_max = MAX(hm->key_max, key);
142 if (isset(hm->key_press, key)) {
143 if (hm->key_rel == NULL)
144 hm->key_rel = malloc(howmany(KEY_CNT, 8), M_DEVBUF,
145 M_ZERO | M_WAITOK);
146 } else {
147 setbit(hm->key_press, key);
148 evdev_support_key(hm->evdev, key);
149 }
150 }
151
152 void
153 hidmap_push_key(struct hidmap *hm, uint16_t key, int32_t value)
154 {
155 if (HIDMAP_WANT_MERGE_KEYS(hm))
156 setbit(value != 0 ? hm->key_press : hm->key_rel, key);
157 else
158 evdev_push_key(hm->evdev, key, value);
159 }
160
161 static void
162 hidmap_sync_keys(struct hidmap *hm)
163 {
164 int i, j;
165 bool press, rel;
166
167 for (j = hm->key_min / 8; j <= hm->key_max / 8; j++) {
168 if (hm->key_press[j] != hm->key_rel[j]) {
169 for (i = j * 8; i < j * 8 + 8; i++) {
170 press = isset(hm->key_press, i);
171 rel = isset(hm->key_rel, i);
172 if (press != rel)
173 evdev_push_key(hm->evdev, i, press);
174 }
175 }
176 }
177 bzero(hm->key_press, howmany(KEY_CNT, 8));
178 bzero(hm->key_rel, howmany(KEY_CNT, 8));
179 }
180
181 void
182 hidmap_intr(void *context, void *buf, hid_size_t len)
183 {
184 struct hidmap *hm = context;
185 struct hidmap_hid_item *hi;
186 const struct hidmap_item *mi;
187 int32_t usage;
188 int32_t data;
189 uint16_t key, uoff;
190 uint8_t id = 0;
191 bool found, do_sync = false;
192
193 DPRINTFN(hm, 6, "hm=%p len=%d\n", hm, len);
194 DPRINTFN(hm, 6, "data = %*D\n", len, buf, " ");
195
196 /* Strip leading "report ID" byte */
197 if (hm->hid_items[0].id) {
198 id = *(uint8_t *)buf;
199 len--;
200 buf = (uint8_t *)buf + 1;
201 }
202
203 hm->intr_buf = buf;
204 hm->intr_len = len;
205
206 for (hi = hm->hid_items; hi < hm->hid_items + hm->nhid_items; hi++) {
207 /* At first run callbacks that not tied to HID items */
208 if (hi->type == HIDMAP_TYPE_FINALCB) {
209 DPRINTFN(hm, 6, "type=%d item=%*D\n", hi->type,
210 (int)sizeof(hi->cb), &hi->cb, " ");
211 if (hi->cb(hm, hi, (union hidmap_cb_ctx){.rid = id})
212 == 0)
213 do_sync = true;
214 continue;
215 }
216
217 /* Ignore irrelevant reports */
218 if (id != hi->id)
219 continue;
220
221 /*
222 * 5.8. If Logical Minimum and Logical Maximum are both
223 * positive values then the contents of a field can be assumed
224 * to be an unsigned value. Otherwise, all integer values are
225 * signed values represented in 2’s complement format.
226 */
227 data = hi->lmin < 0 || hi->lmax < 0
228 ? hid_get_data(buf, len, &hi->loc)
229 : hid_get_udata(buf, len, &hi->loc);
230
231 DPRINTFN(hm, 6, "type=%d data=%d item=%*D\n", hi->type, data,
232 (int)sizeof(hi->cb), &hi->cb, " ");
233
234 if (hi->invert_value && hi->type < HIDMAP_TYPE_ARR_LIST)
235 data = hi->evtype == EV_REL
236 ? -data
237 : hi->lmin + hi->lmax - data;
238
239 switch (hi->type) {
240 case HIDMAP_TYPE_CALLBACK:
241 if (hi->cb(hm, hi, (union hidmap_cb_ctx){.data = data})
242 != 0)
243 continue;
244 break;
245
246 case HIDMAP_TYPE_VAR_NULLST:
247 /*
248 * 5.10. If the host or the device receives an
249 * out-of-range value then the current value for the
250 * respective control will not be modified.
251 */
252 if (data < hi->lmin || data > hi->lmax)
253 continue;
254 /* FALLTHROUGH */
255 case HIDMAP_TYPE_VARIABLE:
256 /*
257 * Ignore reports for absolute data if the data did not
258 * change and for relative data if data is 0.
259 * Evdev layer filters out them anyway.
260 */
261 if (data == (hi->evtype == EV_REL ? 0 : hi->last_val))
262 continue;
263 if (hi->evtype == EV_KEY)
264 hidmap_push_key(hm, hi->code, data);
265 else
266 evdev_push_event(hm->evdev, hi->evtype,
267 hi->code, data);
268 hi->last_val = data;
269 break;
270
271 case HIDMAP_TYPE_ARR_LIST:
272 key = KEY_RESERVED;
273 /*
274 * 6.2.2.5. An out-of range value in an array field
275 * is considered no controls asserted.
276 */
277 if (data < hi->lmin || data > hi->lmax)
278 goto report_key;
279 /*
280 * 6.2.2.5. Rather than returning a single bit for each
281 * button in the group, an array returns an index in
282 * each field that corresponds to the pressed button.
283 */
284 key = hi->codes[data - hi->lmin];
285 if (key == KEY_RESERVED)
286 DPRINTF(hm, "Can not map unknown HID "
287 "array index: %08x\n", data);
288 goto report_key;
289
290 case HIDMAP_TYPE_ARR_RANGE:
291 key = KEY_RESERVED;
292 /*
293 * 6.2.2.5. An out-of range value in an array field
294 * is considered no controls asserted.
295 */
296 if (data < hi->lmin || data > hi->lmax)
297 goto report_key;
298 /*
299 * When the input field is an array and the usage is
300 * specified with a range instead of an ID, we have to
301 * derive the actual usage by using the item value as
302 * an index in the usage range list.
303 */
304 usage = data - hi->lmin + hi->umin;
305 found = false;
306 HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
307 if (usage == mi->usage + uoff &&
308 mi->type == EV_KEY && !mi->has_cb) {
309 key = mi->code;
310 found = true;
311 break;
312 }
313 }
314 if (!found)
315 DPRINTF(hm, "Can not map unknown HID "
316 "usage: %08x\n", usage);
317 report_key:
318 if (key == HIDMAP_KEY_NULL || key == hi->last_key)
319 continue;
320 if (hi->last_key != KEY_RESERVED)
321 hidmap_push_key(hm, hi->last_key, 0);
322 if (key != KEY_RESERVED)
323 hidmap_push_key(hm, key, 1);
324 hi->last_key = key;
325 break;
326
327 default:
328 KASSERT(0, ("Unknown map type (%d)", hi->type));
329 }
330 do_sync = true;
331 }
332
333 if (do_sync) {
334 if (HIDMAP_WANT_MERGE_KEYS(hm))
335 hidmap_sync_keys(hm);
336 evdev_sync(hm->evdev);
337 }
338 }
339
340 static inline bool
341 can_map_callback(struct hid_item *hi, const struct hidmap_item *mi,
342 uint16_t usage_offset)
343 {
344
345 return (mi->has_cb && !mi->final_cb &&
346 hi->usage == mi->usage + usage_offset &&
347 (mi->relabs == HIDMAP_RELABS_ANY ||
348 !(hi->flags & HIO_RELATIVE) == !(mi->relabs == HIDMAP_RELATIVE)));
349 }
350
351 static inline bool
352 can_map_variable(struct hid_item *hi, const struct hidmap_item *mi,
353 uint16_t usage_offset)
354 {
355
356 return ((hi->flags & HIO_VARIABLE) != 0 && !mi->has_cb &&
357 hi->usage == mi->usage + usage_offset &&
358 (mi->relabs == HIDMAP_RELABS_ANY ||
359 !(hi->flags & HIO_RELATIVE) == !(mi->relabs == HIDMAP_RELATIVE)));
360 }
361
362 static inline bool
363 can_map_arr_range(struct hid_item *hi, const struct hidmap_item *mi,
364 uint16_t usage_offset)
365 {
366
367 return ((hi->flags & HIO_VARIABLE) == 0 && !mi->has_cb &&
368 hi->usage_minimum <= mi->usage + usage_offset &&
369 hi->usage_maximum >= mi->usage + usage_offset &&
370 mi->type == EV_KEY &&
371 (mi->code != KEY_RESERVED && mi->code != HIDMAP_KEY_NULL));
372 }
373
374 static inline bool
375 can_map_arr_list(struct hid_item *hi, const struct hidmap_item *mi,
376 uint32_t usage, uint16_t usage_offset)
377 {
378
379 return ((hi->flags & HIO_VARIABLE) == 0 && !mi->has_cb &&
380 usage == mi->usage + usage_offset &&
381 mi->type == EV_KEY &&
382 (mi->code != KEY_RESERVED && mi->code != HIDMAP_KEY_NULL));
383 }
384
385 static bool
386 hidmap_probe_hid_item(struct hid_item *hi, const struct hidmap_item *map,
387 int nitems_map, hidmap_caps_t caps)
388 {
389 u_int i, j;
390 uint16_t uoff;
391 bool found = false;
392
393 #define HIDMAP_FOREACH_INDEX(map, nitems, idx, uoff) \
394 for ((idx) = 0, (uoff) = -1; \
395 hidmap_get_next_map_index((map), (nitems), &(idx), &(uoff));)
396
397 HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
398 if (can_map_callback(hi, map + i, uoff)) {
399 if (map[i].cb(NULL, NULL,
400 (union hidmap_cb_ctx){.hi = hi}) != 0)
401 break;
402 setbit(caps, i);
403 return (true);
404 }
405 }
406
407 if (hi->flags & HIO_VARIABLE) {
408 HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
409 if (can_map_variable(hi, map + i, uoff)) {
410 KASSERT(map[i].type == EV_KEY ||
411 map[i].type == EV_REL ||
412 map[i].type == EV_ABS ||
413 map[i].type == EV_SW,
414 ("Unsupported event type"));
415 setbit(caps, i);
416 return (true);
417 }
418 }
419 return (false);
420 }
421
422 if (hi->usage_minimum != 0 || hi->usage_maximum != 0) {
423 HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
424 if (can_map_arr_range(hi, map + i, uoff)) {
425 setbit(caps, i);
426 found = true;
427 }
428 }
429 return (found);
430 }
431
432 for (j = 0; j < hi->nusages; j++) {
433 HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
434 if (can_map_arr_list(hi, map+i, hi->usages[j], uoff)) {
435 setbit(caps, i);
436 found = true;
437 }
438 }
439 }
440
441 return (found);
442 }
443
444 static uint32_t
445 hidmap_probe_hid_descr(void *d_ptr, hid_size_t d_len, uint8_t tlc_index,
446 const struct hidmap_item *map, int nitems_map, hidmap_caps_t caps)
447 {
448 struct hid_data *hd;
449 struct hid_item hi;
450 uint32_t i, items = 0;
451 bool do_free = false;
452
453 if (caps == NULL) {
454 caps = malloc(HIDMAP_CAPS_SZ(nitems_map), M_DEVBUF,
455 M_WAITOK | M_ZERO);
456 do_free = true;
457 } else
458 bzero (caps, HIDMAP_CAPS_SZ(nitems_map));
459
460 /* Parse inputs */
461 hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
462 HIDBUS_FOREACH_ITEM(hd, &hi, tlc_index) {
463 if (hi.kind != hid_input)
464 continue;
465 if (hi.flags & HIO_CONST)
466 continue;
467 for (i = 0; i < hi.loc.count; i++, hi.loc.pos += hi.loc.size)
468 if (hidmap_probe_hid_item(&hi, map, nitems_map, caps))
469 items++;
470 }
471 hid_end_parse(hd);
472
473 /* Take finalizing callbacks in to account */
474 for (i = 0; i < nitems_map; i++) {
475 if (map[i].has_cb && map[i].final_cb &&
476 map[i].cb(NULL, NULL, (union hidmap_cb_ctx){}) == 0) {
477 setbit(caps, i);
478 items++;
479 }
480 }
481
482 /* Check that all mandatory usages are present in report descriptor */
483 if (items != 0) {
484 for (i = 0; i < nitems_map; i++) {
485 KASSERT(!(map[i].required && map[i].forbidden),
486 ("both required & forbidden item flags are set"));
487 if ((map[i].required && isclr(caps, i)) ||
488 (map[i].forbidden && isset(caps, i))) {
489 items = 0;
490 break;
491 }
492 }
493 }
494
495 if (do_free)
496 free(caps, M_DEVBUF);
497
498 return (items);
499 }
500
501 uint32_t
502 hidmap_add_map(struct hidmap *hm, const struct hidmap_item *map,
503 int nitems_map, hidmap_caps_t caps)
504 {
505 void *d_ptr;
506 uint32_t items;
507 int i, error;
508 hid_size_t d_len;
509 uint8_t tlc_index = hidbus_get_index(hm->dev);
510
511 /* Avoid double-adding of map in probe() handler */
512 for (i = 0; i < hm->nmaps; i++)
513 if (hm->map[i] == map)
514 return (0);
515
516 error = hid_get_report_descr(hm->dev, &d_ptr, &d_len);
517 if (error != 0) {
518 device_printf(hm->dev, "could not retrieve report descriptor "
519 "from device: %d\n", error);
520 return (error);
521 }
522
523 hm->cb_state = HIDMAP_CB_IS_PROBING;
524 items = hidmap_probe_hid_descr(d_ptr, d_len, tlc_index, map,
525 nitems_map, caps);
526 if (items == 0)
527 return (ENXIO);
528
529 KASSERT(hm->nmaps < HIDMAP_MAX_MAPS,
530 ("Not more than %d maps is supported", HIDMAP_MAX_MAPS));
531 hm->nhid_items += items;
532 hm->map[hm->nmaps] = map;
533 hm->nmap_items[hm->nmaps] = nitems_map;
534 hm->nmaps++;
535
536 return (0);
537 }
538
539 static bool
540 hidmap_parse_hid_item(struct hidmap *hm, struct hid_item *hi,
541 struct hidmap_hid_item *item)
542 {
543 const struct hidmap_item *mi;
544 struct hidmap_hid_item hi_temp;
545 uint32_t i;
546 uint16_t uoff;
547 bool found = false;
548
549 HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
550 if (can_map_callback(hi, mi, uoff)) {
551 bzero(&hi_temp, sizeof(hi_temp));
552 hi_temp.cb = mi->cb;
553 hi_temp.type = HIDMAP_TYPE_CALLBACK;
554 /*
555 * Values returned by probe- and attach-stage
556 * callbacks MUST be identical.
557 */
558 if (mi->cb(hm, &hi_temp,
559 (union hidmap_cb_ctx){.hi = hi}) != 0)
560 break;
561 bcopy(&hi_temp, item, sizeof(hi_temp));
562 goto mapped;
563 }
564 }
565
566 if (hi->flags & HIO_VARIABLE) {
567 HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
568 if (can_map_variable(hi, mi, uoff)) {
569 item->evtype = mi->type;
570 item->code = mi->code + uoff;
571 item->type = hi->flags & HIO_NULLSTATE
572 ? HIDMAP_TYPE_VAR_NULLST
573 : HIDMAP_TYPE_VARIABLE;
574 item->last_val = 0;
575 item->invert_value = mi->invert_value;
576 switch (mi->type) {
577 case EV_KEY:
578 hidmap_support_key(hm, item->code);
579 break;
580 case EV_REL:
581 evdev_support_event(hm->evdev, EV_REL);
582 evdev_support_rel(hm->evdev,
583 item->code);
584 break;
585 case EV_ABS:
586 evdev_support_event(hm->evdev, EV_ABS);
587 evdev_support_abs(hm->evdev,
588 item->code,
589 hi->logical_minimum,
590 hi->logical_maximum,
591 mi->fuzz,
592 mi->flat,
593 hid_item_resolution(hi));
594 break;
595 case EV_SW:
596 evdev_support_event(hm->evdev, EV_SW);
597 evdev_support_sw(hm->evdev,
598 item->code);
599 break;
600 default:
601 KASSERT(0, ("Unsupported event type"));
602 }
603 goto mapped;
604 }
605 }
606 return (false);
607 }
608
609 if (hi->usage_minimum != 0 || hi->usage_maximum != 0) {
610 HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
611 if (can_map_arr_range(hi, mi, uoff)) {
612 hidmap_support_key(hm, mi->code + uoff);
613 found = true;
614 }
615 }
616 if (!found)
617 return (false);
618 item->umin = hi->usage_minimum;
619 item->type = HIDMAP_TYPE_ARR_RANGE;
620 item->last_key = KEY_RESERVED;
621 goto mapped;
622 }
623
624 for (i = 0; i < hi->nusages; i++) {
625 HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
626 if (can_map_arr_list(hi, mi, hi->usages[i], uoff)) {
627 hidmap_support_key(hm, mi->code + uoff);
628 if (item->codes == NULL)
629 item->codes = malloc(
630 hi->nusages * sizeof(uint16_t),
631 M_DEVBUF, M_WAITOK | M_ZERO);
632 item->codes[i] = mi->code + uoff;
633 found = true;
634 break;
635 }
636 }
637 }
638 if (!found)
639 return (false);
640 item->type = HIDMAP_TYPE_ARR_LIST;
641 item->last_key = KEY_RESERVED;
642
643 mapped:
644 item->id = hi->report_ID;
645 item->loc = hi->loc;
646 item->loc.count = 1;
647 item->lmin = hi->logical_minimum;
648 item->lmax = hi->logical_maximum;
649
650 DPRINTFN(hm, 6, "usage=%04x id=%d loc=%u/%u type=%d item=%*D\n",
651 hi->usage, hi->report_ID, hi->loc.pos, hi->loc.size, item->type,
652 (int)sizeof(item->cb), &item->cb, " ");
653
654 return (true);
655 }
656
657 static int
658 hidmap_parse_hid_descr(struct hidmap *hm, uint8_t tlc_index)
659 {
660 const struct hidmap_item *map;
661 struct hidmap_hid_item *item = hm->hid_items;
662 void *d_ptr;
663 struct hid_data *hd;
664 struct hid_item hi;
665 int i, error;
666 hid_size_t d_len;
667
668 error = hid_get_report_descr(hm->dev, &d_ptr, &d_len);
669 if (error != 0) {
670 DPRINTF(hm, "could not retrieve report descriptor from "
671 "device: %d\n", error);
672 return (error);
673 }
674
675 /* Parse inputs */
676 hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
677 HIDBUS_FOREACH_ITEM(hd, &hi, tlc_index) {
678 if (hi.kind != hid_input)
679 continue;
680 if (hi.flags & HIO_CONST)
681 continue;
682 for (i = 0; i < hi.loc.count; i++, hi.loc.pos += hi.loc.size)
683 if (hidmap_parse_hid_item(hm, &hi, item))
684 item++;
685 KASSERT(item <= hm->hid_items + hm->nhid_items,
686 ("Parsed HID item array overflow"));
687 }
688 hid_end_parse(hd);
689
690 /* Add finalizing callbacks to the end of list */
691 for (i = 0; i < hm->nmaps; i++) {
692 for (map = hm->map[i];
693 map < hm->map[i] + hm->nmap_items[i];
694 map++) {
695 if (map->has_cb && map->final_cb &&
696 map->cb(hm, item, (union hidmap_cb_ctx){}) == 0) {
697 item->cb = map->cb;
698 item->type = HIDMAP_TYPE_FINALCB;
699 item++;
700 }
701 }
702 }
703
704 /*
705 * Resulting number of parsed HID items can be less than expected as
706 * map items might be duplicated in different maps. Save real number.
707 */
708 if (hm->nhid_items != item - hm->hid_items)
709 DPRINTF(hm, "Parsed HID item number mismatch: expected=%u "
710 "result=%td\n", hm->nhid_items, item - hm->hid_items);
711 hm->nhid_items = item - hm->hid_items;
712
713 if (HIDMAP_WANT_MERGE_KEYS(hm))
714 bzero(hm->key_press, howmany(KEY_CNT, 8));
715
716 return (0);
717 }
718
719 int
720 hidmap_probe(struct hidmap* hm, device_t dev,
721 const struct hid_device_id *id, int nitems_id,
722 const struct hidmap_item *map, int nitems_map,
723 const char *suffix, hidmap_caps_t caps)
724 {
725 int error;
726
727 error = hidbus_lookup_driver_info(dev, id, nitems_id);
728 if (error != 0)
729 return (error);
730
731 hidmap_set_dev(hm, dev);
732
733 error = hidmap_add_map(hm, map, nitems_map, caps);
734 if (error != 0)
735 return (error);
736
737 hidbus_set_desc(dev, suffix);
738
739 return (BUS_PROBE_DEFAULT);
740 }
741
742 int
743 hidmap_attach(struct hidmap* hm)
744 {
745 const struct hid_device_info *hw = hid_get_device_info(hm->dev);
746 #ifdef HID_DEBUG
747 char tunable[40];
748 #endif
749 int error;
750
751 #ifdef HID_DEBUG
752 if (hm->debug_var == NULL) {
753 hm->debug_var = &hm->debug_level;
754 snprintf(tunable, sizeof(tunable), "hw.hid.%s.debug",
755 device_get_name(hm->dev));
756 TUNABLE_INT_FETCH(tunable, &hm->debug_level);
757 SYSCTL_ADD_INT(device_get_sysctl_ctx(hm->dev),
758 SYSCTL_CHILDREN(device_get_sysctl_tree(hm->dev)),
759 OID_AUTO, "debug", CTLFLAG_RWTUN,
760 &hm->debug_level, 0, "Verbosity level");
761 }
762 #endif
763
764 DPRINTFN(hm, 11, "hm=%p\n", hm);
765
766 hm->cb_state = HIDMAP_CB_IS_ATTACHING;
767
768 hm->hid_items = malloc(hm->nhid_items * sizeof(struct hid_item),
769 M_DEVBUF, M_WAITOK | M_ZERO);
770
771 hidbus_set_intr(hm->dev, hidmap_intr, hm);
772 hm->evdev_methods = (struct evdev_methods) {
773 .ev_open = &hidmap_ev_open,
774 .ev_close = &hidmap_ev_close,
775 };
776
777 hm->evdev = evdev_alloc();
778 evdev_set_name(hm->evdev, device_get_desc(hm->dev));
779 evdev_set_phys(hm->evdev, device_get_nameunit(hm->dev));
780 evdev_set_id(hm->evdev, hw->idBus, hw->idVendor, hw->idProduct,
781 hw->idVersion);
782 evdev_set_serial(hm->evdev, hw->serial);
783 evdev_set_flag(hm->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
784 evdev_support_event(hm->evdev, EV_SYN);
785 error = hidmap_parse_hid_descr(hm, hidbus_get_index(hm->dev));
786 if (error) {
787 DPRINTF(hm, "error=%d\n", error);
788 hidmap_detach(hm);
789 return (ENXIO);
790 }
791
792 evdev_set_methods(hm->evdev, hm->dev, &hm->evdev_methods);
793 hm->cb_state = HIDMAP_CB_IS_RUNNING;
794
795 error = evdev_register(hm->evdev);
796 if (error) {
797 DPRINTF(hm, "error=%d\n", error);
798 hidmap_detach(hm);
799 return (ENXIO);
800 }
801
802 return (0);
803 }
804
805 int
806 hidmap_detach(struct hidmap* hm)
807 {
808 struct hidmap_hid_item *hi;
809
810 DPRINTFN(hm, 11, "\n");
811
812 hm->cb_state = HIDMAP_CB_IS_DETACHING;
813
814 evdev_free(hm->evdev);
815 if (hm->hid_items != NULL) {
816 for (hi = hm->hid_items;
817 hi < hm->hid_items + hm->nhid_items;
818 hi++)
819 if (hi->type == HIDMAP_TYPE_FINALCB ||
820 hi->type == HIDMAP_TYPE_CALLBACK)
821 hi->cb(hm, hi, (union hidmap_cb_ctx){});
822 else if (hi->type == HIDMAP_TYPE_ARR_LIST)
823 free(hi->codes, M_DEVBUF);
824 free(hm->hid_items, M_DEVBUF);
825 }
826
827 free(hm->key_press, M_DEVBUF);
828 free(hm->key_rel, M_DEVBUF);
829
830 return (0);
831 }
832
833 MODULE_DEPEND(hidmap, hid, 1, 1, 1);
834 MODULE_DEPEND(hidmap, hidbus, 1, 1, 1);
835 MODULE_DEPEND(hidmap, evdev, 1, 1, 1);
836 MODULE_VERSION(hidmap, 1);
Cache object: 33a068968896ca779a5f8a0aba5a9770
|