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