xref: /freebsd/sys/dev/hid/hidmap.h (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1afd590d9SVladimir Kondratyev /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3afd590d9SVladimir Kondratyev  *
4afd590d9SVladimir Kondratyev  * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
5afd590d9SVladimir Kondratyev  *
6afd590d9SVladimir Kondratyev  * Redistribution and use in source and binary forms, with or without
7afd590d9SVladimir Kondratyev  * modification, are permitted provided that the following conditions
8afd590d9SVladimir Kondratyev  * are met:
9afd590d9SVladimir Kondratyev  * 1. Redistributions of source code must retain the above copyright
10afd590d9SVladimir Kondratyev  *    notice, this list of conditions and the following disclaimer.
11afd590d9SVladimir Kondratyev  * 2. Redistributions in binary form must reproduce the above copyright
12afd590d9SVladimir Kondratyev  *    notice, this list of conditions and the following disclaimer in the
13afd590d9SVladimir Kondratyev  *    documentation and/or other materials provided with the distribution.
14afd590d9SVladimir Kondratyev  *
15afd590d9SVladimir Kondratyev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16afd590d9SVladimir Kondratyev  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17afd590d9SVladimir Kondratyev  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18afd590d9SVladimir Kondratyev  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19afd590d9SVladimir Kondratyev  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20afd590d9SVladimir Kondratyev  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21afd590d9SVladimir Kondratyev  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22afd590d9SVladimir Kondratyev  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23afd590d9SVladimir Kondratyev  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24afd590d9SVladimir Kondratyev  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25afd590d9SVladimir Kondratyev  * SUCH DAMAGE.
26afd590d9SVladimir Kondratyev  */
27afd590d9SVladimir Kondratyev 
28afd590d9SVladimir Kondratyev #ifndef _HIDMAP_H_
29afd590d9SVladimir Kondratyev #define _HIDMAP_H_
30afd590d9SVladimir Kondratyev 
31afd590d9SVladimir Kondratyev #include <sys/param.h>
32afd590d9SVladimir Kondratyev 
33afd590d9SVladimir Kondratyev #include <dev/hid/hid.h>
34afd590d9SVladimir Kondratyev 
35afd590d9SVladimir Kondratyev #define	HIDMAP_MAX_MAPS	4
36afd590d9SVladimir Kondratyev 
37afd590d9SVladimir Kondratyev struct hid_device_id;
38afd590d9SVladimir Kondratyev struct hidmap_hid_item;
39afd590d9SVladimir Kondratyev struct hidmap_item;
40afd590d9SVladimir Kondratyev struct hidmap;
41afd590d9SVladimir Kondratyev 
42afd590d9SVladimir Kondratyev enum hidmap_cb_state {
43afd590d9SVladimir Kondratyev 	HIDMAP_CB_IS_PROBING,
44afd590d9SVladimir Kondratyev 	HIDMAP_CB_IS_ATTACHING,
45afd590d9SVladimir Kondratyev 	HIDMAP_CB_IS_RUNNING,
46afd590d9SVladimir Kondratyev 	HIDMAP_CB_IS_DETACHING,
47afd590d9SVladimir Kondratyev };
48afd590d9SVladimir Kondratyev 
49afd590d9SVladimir Kondratyev #define	HIDMAP_KEY_NULL	0xFF	/* Special event code to discard input */
50afd590d9SVladimir Kondratyev 
51afd590d9SVladimir Kondratyev /* Third parameter of hidmap callback has different type depending on state */
52afd590d9SVladimir Kondratyev union hidmap_cb_ctx {
53afd590d9SVladimir Kondratyev 	struct hid_item	*hi;	/* Probe- and attach-stage callbacks */
54afd590d9SVladimir Kondratyev 	int32_t		data;	/* Run-stage callbacks */
55afd590d9SVladimir Kondratyev 	uint8_t		rid;	/* Run-stage finalizing callbacks */
56afd590d9SVladimir Kondratyev };
57afd590d9SVladimir Kondratyev 
58afd590d9SVladimir Kondratyev #define	HIDMAP_CB_ARGS							\
59afd590d9SVladimir Kondratyev 	struct hidmap *hm, struct hidmap_hid_item *hi, union hidmap_cb_ctx ctx
60afd590d9SVladimir Kondratyev typedef int hidmap_cb_t(HIDMAP_CB_ARGS);
61afd590d9SVladimir Kondratyev 
62afd590d9SVladimir Kondratyev /* These helpers can be used at any stage of any callbacks */
63afd590d9SVladimir Kondratyev #define	HIDMAP_CB_GET_STATE(...)					\
64afd590d9SVladimir Kondratyev 	((hm == NULL) ? HIDMAP_CB_IS_PROBING : hm->cb_state)
65a36bdfc2SVladimir Kondratyev #define	HIDMAP_CB_GET_DEV(...)						\
66a36bdfc2SVladimir Kondratyev 	(hm == NULL ? NULL : hm->dev)
67afd590d9SVladimir Kondratyev #define	HIDMAP_CB_GET_SOFTC(...)					\
68afd590d9SVladimir Kondratyev 	(hm == NULL ? NULL : device_get_softc(hm->dev))
69afd590d9SVladimir Kondratyev #define	HIDMAP_CB_GET_EVDEV(...)					\
70afd590d9SVladimir Kondratyev 	(hm == NULL ? NULL : hm->evdev)
71afd590d9SVladimir Kondratyev #define	HIDMAP_CB_UDATA		(hi->udata)
72afd590d9SVladimir Kondratyev #define	HIDMAP_CB_UDATA64	(hi->udata64)
73afd590d9SVladimir Kondratyev /* Special helpers for run-stage of finalizing callbacks */
74afd590d9SVladimir Kondratyev #define	HIDMAP_CB_GET_RID(...)	(ctx.rid)
75afd590d9SVladimir Kondratyev #define	HIDMAP_CB_GET_DATA(loc)						\
76afd590d9SVladimir Kondratyev 	hid_get_data(hm->intr_buf, hm->intr_len, (loc))
77afd590d9SVladimir Kondratyev #define	HIDMAP_CB_GET_UDATA(loc)					\
78afd590d9SVladimir Kondratyev 	hid_get_udata(hm->intr_buf, hm->intr_len, (loc))
79afd590d9SVladimir Kondratyev 
80afd590d9SVladimir Kondratyev enum hidmap_relabs {
81afd590d9SVladimir Kondratyev 	HIDMAP_RELABS_ANY = 0,
82afd590d9SVladimir Kondratyev 	HIDMAP_RELATIVE,
83afd590d9SVladimir Kondratyev 	HIDMAP_ABSOLUTE,
84afd590d9SVladimir Kondratyev };
85afd590d9SVladimir Kondratyev 
86afd590d9SVladimir Kondratyev struct hidmap_item {
87afd590d9SVladimir Kondratyev 	union {
88afd590d9SVladimir Kondratyev 		struct {
89afd590d9SVladimir Kondratyev 			uint16_t	type;	/* Evdev event type */
90afd590d9SVladimir Kondratyev 			uint16_t	code;	/* Evdev event code */
91afd590d9SVladimir Kondratyev 			uint16_t	fuzz;	/* Evdev event fuzz */
92afd590d9SVladimir Kondratyev 			uint16_t	flat;	/* Evdev event flat */
93afd590d9SVladimir Kondratyev 		};
94afd590d9SVladimir Kondratyev 		hidmap_cb_t		*cb;	/* Reporting callback */
95afd590d9SVladimir Kondratyev 	};
96afd590d9SVladimir Kondratyev 	int32_t 		usage;		/* HID usage (base) */
97afd590d9SVladimir Kondratyev 	uint16_t		nusages;	/* number of usages */
98afd590d9SVladimir Kondratyev 	bool			required:1;	/* Required by driver */
99afd590d9SVladimir Kondratyev 	enum hidmap_relabs	relabs:2;
100afd590d9SVladimir Kondratyev 	bool			has_cb:1;
101afd590d9SVladimir Kondratyev 	bool			final_cb:1;
102afd590d9SVladimir Kondratyev 	bool			invert_value:1;
103cded1fdbSVladimir Kondratyev 	bool			forbidden:1;	/* Forbidden by driver */
104cded1fdbSVladimir Kondratyev 	u_int			reserved:9;
105afd590d9SVladimir Kondratyev };
106afd590d9SVladimir Kondratyev 
107afd590d9SVladimir Kondratyev #define	HIDMAP_ANY(_page, _usage, _type, _code)				\
108afd590d9SVladimir Kondratyev 	.usage = HID_USAGE2((_page), (_usage)),				\
109afd590d9SVladimir Kondratyev 	.nusages = 1,							\
110afd590d9SVladimir Kondratyev 	.type = (_type),						\
111afd590d9SVladimir Kondratyev 	.code = (_code)
112afd590d9SVladimir Kondratyev #define	HIDMAP_ANY_RANGE(_page, _usage_from, _usage_to, _type, _code)	\
113afd590d9SVladimir Kondratyev 	.usage = HID_USAGE2((_page), (_usage_from)),			\
114afd590d9SVladimir Kondratyev 	.nusages = (_usage_to) - (_usage_from) + 1,			\
115afd590d9SVladimir Kondratyev 	.type = (_type),						\
116afd590d9SVladimir Kondratyev 	.code = (_code)
117afd590d9SVladimir Kondratyev #define	HIDMAP_ANY_CB(_page, _usage, _callback)				\
118afd590d9SVladimir Kondratyev 	.usage = HID_USAGE2((_page), (_usage)),				\
119afd590d9SVladimir Kondratyev 	.nusages = 1,							\
120afd590d9SVladimir Kondratyev 	.cb = (_callback),						\
121afd590d9SVladimir Kondratyev 	.has_cb = true
122afd590d9SVladimir Kondratyev #define	HIDMAP_ANY_CB_RANGE(_page, _usage_from, _usage_to, _callback)	\
123afd590d9SVladimir Kondratyev 	.usage = HID_USAGE2((_page), (_usage_from)),			\
124afd590d9SVladimir Kondratyev 	.nusages = (_usage_to) - (_usage_from) + 1,			\
125afd590d9SVladimir Kondratyev 	.cb = (_callback),						\
126afd590d9SVladimir Kondratyev 	.has_cb = true
127afd590d9SVladimir Kondratyev #define	HIDMAP_KEY(_page, _usage, _code)				\
128afd590d9SVladimir Kondratyev 	HIDMAP_ANY((_page), (_usage), EV_KEY, (_code)),			\
129afd590d9SVladimir Kondratyev 		.relabs = HIDMAP_RELABS_ANY
130afd590d9SVladimir Kondratyev #define	HIDMAP_KEY_RANGE(_page, _ufrom, _uto, _code)			\
131afd590d9SVladimir Kondratyev 	HIDMAP_ANY_RANGE((_page), (_ufrom), (_uto), EV_KEY, (_code)),	\
132afd590d9SVladimir Kondratyev 		.relabs = HIDMAP_RELABS_ANY
133afd590d9SVladimir Kondratyev #define	HIDMAP_REL(_page, _usage, _code)				\
134afd590d9SVladimir Kondratyev 	HIDMAP_ANY((_page), (_usage), EV_REL, (_code)),			\
135afd590d9SVladimir Kondratyev 		.relabs = HIDMAP_RELATIVE
136afd590d9SVladimir Kondratyev #define	HIDMAP_ABS(_page, _usage, _code)				\
137afd590d9SVladimir Kondratyev 	HIDMAP_ANY((_page), (_usage), EV_ABS, (_code)),			\
138afd590d9SVladimir Kondratyev 		.relabs = HIDMAP_ABSOLUTE
139afd590d9SVladimir Kondratyev #define	HIDMAP_SW(_page, _usage, _code)					\
140afd590d9SVladimir Kondratyev 	HIDMAP_ANY((_page), (_usage), EV_SW, (_code)),			\
141afd590d9SVladimir Kondratyev 		.relabs = HIDMAP_RELABS_ANY
142afd590d9SVladimir Kondratyev #define	HIDMAP_REL_CB(_page, _usage, _callback)				\
143afd590d9SVladimir Kondratyev 	HIDMAP_ANY_CB((_page), (_usage), (_callback)),			\
144afd590d9SVladimir Kondratyev 		.relabs = HIDMAP_RELATIVE
145afd590d9SVladimir Kondratyev #define	HIDMAP_ABS_CB(_page, _usage, _callback)				\
146afd590d9SVladimir Kondratyev 	HIDMAP_ANY_CB((_page), (_usage), (_callback)),			\
147afd590d9SVladimir Kondratyev 		.relabs = HIDMAP_ABSOLUTE
148afd590d9SVladimir Kondratyev /*
149afd590d9SVladimir Kondratyev  * Special callback function which is not tied to particular HID input usage
150afd590d9SVladimir Kondratyev  * but called at the end evdev properties setting or interrupt handler
151afd590d9SVladimir Kondratyev  * just before evdev_register() or evdev_sync() calls.
152afd590d9SVladimir Kondratyev  */
153afd590d9SVladimir Kondratyev #define	HIDMAP_FINAL_CB(_callback)					\
154afd590d9SVladimir Kondratyev 	HIDMAP_ANY_CB(0, 0, (_callback)), .final_cb = true
155afd590d9SVladimir Kondratyev 
156afd590d9SVladimir Kondratyev enum hidmap_type {
157afd590d9SVladimir Kondratyev 	HIDMAP_TYPE_FINALCB = 0,/* No HID item associated. Runs unconditionally
158afd590d9SVladimir Kondratyev 				 * at the end of other items processing */
159afd590d9SVladimir Kondratyev 	HIDMAP_TYPE_CALLBACK,	/* HID item is reported with user callback */
160afd590d9SVladimir Kondratyev 	HIDMAP_TYPE_VARIABLE,	/* HID item is variable (single usage) */
161afd590d9SVladimir Kondratyev 	HIDMAP_TYPE_VAR_NULLST,	/* HID item is null state variable */
162afd590d9SVladimir Kondratyev 	HIDMAP_TYPE_ARR_LIST,	/* HID item is array with list of usages */
163afd590d9SVladimir Kondratyev 	HIDMAP_TYPE_ARR_RANGE,	/* Array with range (min;max) of usages */
164afd590d9SVladimir Kondratyev };
165afd590d9SVladimir Kondratyev 
166afd590d9SVladimir Kondratyev struct hidmap_hid_item {
167afd590d9SVladimir Kondratyev 	union {
168afd590d9SVladimir Kondratyev 		hidmap_cb_t	*cb;		/* Callback */
169afd590d9SVladimir Kondratyev 		struct {			/* Variable */
170afd590d9SVladimir Kondratyev 			uint16_t	evtype;	/* Evdev event type */
171afd590d9SVladimir Kondratyev 			uint16_t	code;	/* Evdev event code */
172afd590d9SVladimir Kondratyev 		};
173afd590d9SVladimir Kondratyev 		uint16_t	*codes;		/* Array list map type */
174afd590d9SVladimir Kondratyev 		int32_t		umin;		/* Array range map type */
175afd590d9SVladimir Kondratyev 	};
176afd590d9SVladimir Kondratyev 	union {
177afd590d9SVladimir Kondratyev 		void		*udata;		/* Callback private context */
178afd590d9SVladimir Kondratyev 		uint64_t	udata64;
179afd590d9SVladimir Kondratyev 		int32_t		last_val;	/* Last reported value (var) */
180afd590d9SVladimir Kondratyev 		uint16_t	last_key;	/* Last reported key (array) */
181afd590d9SVladimir Kondratyev 	};
182afd590d9SVladimir Kondratyev 	struct hid_location	loc;		/* HID item location */
183afd590d9SVladimir Kondratyev 	int32_t			lmin;		/* HID item logical minimum */
184afd590d9SVladimir Kondratyev 	int32_t			lmax;		/* HID item logical maximum */
185afd590d9SVladimir Kondratyev 	enum hidmap_type	type:8;
186afd590d9SVladimir Kondratyev 	uint8_t			id;		/* Report ID */
187afd590d9SVladimir Kondratyev 	bool			invert_value;
188afd590d9SVladimir Kondratyev };
189afd590d9SVladimir Kondratyev 
190afd590d9SVladimir Kondratyev struct hidmap {
191afd590d9SVladimir Kondratyev 	device_t		dev;
192afd590d9SVladimir Kondratyev 
193afd590d9SVladimir Kondratyev 	struct evdev_dev	*evdev;
194afd590d9SVladimir Kondratyev 	struct evdev_methods	evdev_methods;
195afd590d9SVladimir Kondratyev 
196afd590d9SVladimir Kondratyev 	/* Scatter-gather list of maps */
197afd590d9SVladimir Kondratyev 	int			nmaps;
198afd590d9SVladimir Kondratyev 	uint32_t		nmap_items[HIDMAP_MAX_MAPS];
199afd590d9SVladimir Kondratyev 	const struct hidmap_item	*map[HIDMAP_MAX_MAPS];
200afd590d9SVladimir Kondratyev 
201afd590d9SVladimir Kondratyev 	/* List of preparsed HID items */
202afd590d9SVladimir Kondratyev 	uint32_t		nhid_items;
203afd590d9SVladimir Kondratyev 	struct hidmap_hid_item	*hid_items;
204afd590d9SVladimir Kondratyev 
205afd590d9SVladimir Kondratyev 	/* Key event merging buffers */
206afd590d9SVladimir Kondratyev 	uint8_t			*key_press;
207afd590d9SVladimir Kondratyev 	uint8_t			*key_rel;
208afd590d9SVladimir Kondratyev 	uint16_t		key_min;
209afd590d9SVladimir Kondratyev 	uint16_t		key_max;
210afd590d9SVladimir Kondratyev 
211afd590d9SVladimir Kondratyev 	int			*debug_var;
212afd590d9SVladimir Kondratyev 	int			debug_level;
213afd590d9SVladimir Kondratyev 	enum hidmap_cb_state	cb_state;
214afd590d9SVladimir Kondratyev 	void *			intr_buf;
215afd590d9SVladimir Kondratyev 	hid_size_t		intr_len;
216afd590d9SVladimir Kondratyev };
217afd590d9SVladimir Kondratyev 
218afd590d9SVladimir Kondratyev typedef	uint8_t *		hidmap_caps_t;
219afd590d9SVladimir Kondratyev #define	HIDMAP_CAPS_SZ(nitems)	howmany((nitems), 8)
220afd590d9SVladimir Kondratyev #define	HIDMAP_CAPS(name, map)	uint8_t	(name)[HIDMAP_CAPS_SZ(nitems(map))]
221afd590d9SVladimir Kondratyev static inline bool
hidmap_test_cap(hidmap_caps_t caps,int cap)222afd590d9SVladimir Kondratyev hidmap_test_cap(hidmap_caps_t caps, int cap)
223afd590d9SVladimir Kondratyev {
224afd590d9SVladimir Kondratyev 	return (isset(caps, cap) != 0);
225afd590d9SVladimir Kondratyev }
226afd590d9SVladimir Kondratyev 
227afd590d9SVladimir Kondratyev /*
228afd590d9SVladimir Kondratyev  * It is safe to call any of following procedures in device_probe context
229afd590d9SVladimir Kondratyev  * that makes possible to write probe-only drivers with attach/detach handlers
230afd590d9SVladimir Kondratyev  * inherited from hidmap. See hcons and hsctrl drivers for example.
231afd590d9SVladimir Kondratyev  */
232afd590d9SVladimir Kondratyev static inline void
hidmap_set_dev(struct hidmap * hm,device_t dev)233afd590d9SVladimir Kondratyev hidmap_set_dev(struct hidmap *hm, device_t dev)
234afd590d9SVladimir Kondratyev {
235afd590d9SVladimir Kondratyev 	hm->dev = dev;
236afd590d9SVladimir Kondratyev }
237afd590d9SVladimir Kondratyev 
238afd590d9SVladimir Kondratyev /* Hack to avoid #ifdef-ing of hidmap_set_debug_var in hidmap based drivers */
239afd590d9SVladimir Kondratyev #ifdef HID_DEBUG
240afd590d9SVladimir Kondratyev #define	hidmap_set_debug_var(h, d)	_hidmap_set_debug_var((h), (d))
241afd590d9SVladimir Kondratyev #else
242afd590d9SVladimir Kondratyev #define	hidmap_set_debug_var(...)
243afd590d9SVladimir Kondratyev #endif
244afd590d9SVladimir Kondratyev void	_hidmap_set_debug_var(struct hidmap *hm, int *debug_var);
245afd590d9SVladimir Kondratyev #define	HIDMAP_ADD_MAP(hm, map, caps)					\
246afd590d9SVladimir Kondratyev 	hidmap_add_map((hm), (map), nitems(map), (caps))
247afd590d9SVladimir Kondratyev uint32_t hidmap_add_map(struct hidmap *hm, const struct hidmap_item *map,
248afd590d9SVladimir Kondratyev 	    int nitems_map, hidmap_caps_t caps);
249afd590d9SVladimir Kondratyev 
250afd590d9SVladimir Kondratyev /* Versions of evdev_* functions capable to merge key events with same codes */
251afd590d9SVladimir Kondratyev void	hidmap_support_key(struct hidmap *hm, uint16_t key);
252afd590d9SVladimir Kondratyev void	hidmap_push_key(struct hidmap *hm, uint16_t key, int32_t value);
253afd590d9SVladimir Kondratyev 
254afd590d9SVladimir Kondratyev void	hidmap_intr(void *context, void *buf, hid_size_t len);
255afd590d9SVladimir Kondratyev #define	HIDMAP_PROBE(hm, dev, id, map, suffix)				\
256afd590d9SVladimir Kondratyev 	hidmap_probe((hm), (dev), (id), nitems(id), (map), nitems(map),	\
257afd590d9SVladimir Kondratyev 	    (suffix), NULL)
258afd590d9SVladimir Kondratyev int	hidmap_probe(struct hidmap* hm, device_t dev,
259afd590d9SVladimir Kondratyev 	    const struct hid_device_id *id, int nitems_id,
260afd590d9SVladimir Kondratyev 	    const struct hidmap_item *map, int nitems_map,
261afd590d9SVladimir Kondratyev 	    const char *suffix, hidmap_caps_t caps);
262afd590d9SVladimir Kondratyev int	hidmap_attach(struct hidmap *hm);
263afd590d9SVladimir Kondratyev int	hidmap_detach(struct hidmap *hm);
264afd590d9SVladimir Kondratyev 
265afd590d9SVladimir Kondratyev #endif	/* _HIDMAP_H_ */
266