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