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 #ifndef _HIDMAP_H_
29 #define _HIDMAP_H_
30
31 #include <sys/param.h>
32
33 #include <dev/hid/hid.h>
34
35 #define HIDMAP_MAX_MAPS 4
36
37 struct hid_device_id;
38 struct hidmap_hid_item;
39 struct hidmap_item;
40 struct hidmap;
41
42 enum hidmap_cb_state {
43 HIDMAP_CB_IS_PROBING,
44 HIDMAP_CB_IS_ATTACHING,
45 HIDMAP_CB_IS_RUNNING,
46 HIDMAP_CB_IS_DETACHING,
47 };
48
49 #define HIDMAP_KEY_NULL 0xFF /* Special event code to discard input */
50
51 /* Third parameter of hidmap callback has different type depending on state */
52 union hidmap_cb_ctx {
53 struct hid_item *hi; /* Probe- and attach-stage callbacks */
54 int32_t data; /* Run-stage callbacks */
55 uint8_t rid; /* Run-stage finalizing callbacks */
56 };
57
58 #define HIDMAP_CB_ARGS \
59 struct hidmap *hm, struct hidmap_hid_item *hi, union hidmap_cb_ctx ctx
60 typedef int hidmap_cb_t(HIDMAP_CB_ARGS);
61
62 /* These helpers can be used at any stage of any callbacks */
63 #define HIDMAP_CB_GET_STATE(...) \
64 ((hm == NULL) ? HIDMAP_CB_IS_PROBING : hm->cb_state)
65 #define HIDMAP_CB_GET_DEV(...) \
66 (hm == NULL ? NULL : hm->dev)
67 #define HIDMAP_CB_GET_SOFTC(...) \
68 (hm == NULL ? NULL : device_get_softc(hm->dev))
69 #define HIDMAP_CB_GET_EVDEV(...) \
70 (hm == NULL ? NULL : hm->evdev)
71 #define HIDMAP_CB_UDATA (hi->udata)
72 #define HIDMAP_CB_UDATA64 (hi->udata64)
73 /* Special helpers for run-stage of finalizing callbacks */
74 #define HIDMAP_CB_GET_RID(...) (ctx.rid)
75 #define HIDMAP_CB_GET_DATA(loc) \
76 hid_get_data(hm->intr_buf, hm->intr_len, (loc))
77 #define HIDMAP_CB_GET_UDATA(loc) \
78 hid_get_udata(hm->intr_buf, hm->intr_len, (loc))
79
80 enum hidmap_relabs {
81 HIDMAP_RELABS_ANY = 0,
82 HIDMAP_RELATIVE,
83 HIDMAP_ABSOLUTE,
84 };
85
86 struct hidmap_item {
87 union {
88 struct {
89 uint16_t type; /* Evdev event type */
90 uint16_t code; /* Evdev event code */
91 uint16_t fuzz; /* Evdev event fuzz */
92 uint16_t flat; /* Evdev event flat */
93 };
94 hidmap_cb_t *cb; /* Reporting callback */
95 };
96 int32_t usage; /* HID usage (base) */
97 uint16_t nusages; /* number of usages */
98 bool required:1; /* Required by driver */
99 enum hidmap_relabs relabs:2;
100 bool has_cb:1;
101 bool final_cb:1;
102 bool invert_value:1;
103 bool forbidden:1; /* Forbidden by driver */
104 u_int reserved:9;
105 };
106
107 #define HIDMAP_ANY(_page, _usage, _type, _code) \
108 .usage = HID_USAGE2((_page), (_usage)), \
109 .nusages = 1, \
110 .type = (_type), \
111 .code = (_code)
112 #define HIDMAP_ANY_RANGE(_page, _usage_from, _usage_to, _type, _code) \
113 .usage = HID_USAGE2((_page), (_usage_from)), \
114 .nusages = (_usage_to) - (_usage_from) + 1, \
115 .type = (_type), \
116 .code = (_code)
117 #define HIDMAP_ANY_CB(_page, _usage, _callback) \
118 .usage = HID_USAGE2((_page), (_usage)), \
119 .nusages = 1, \
120 .cb = (_callback), \
121 .has_cb = true
122 #define HIDMAP_ANY_CB_RANGE(_page, _usage_from, _usage_to, _callback) \
123 .usage = HID_USAGE2((_page), (_usage_from)), \
124 .nusages = (_usage_to) - (_usage_from) + 1, \
125 .cb = (_callback), \
126 .has_cb = true
127 #define HIDMAP_KEY(_page, _usage, _code) \
128 HIDMAP_ANY((_page), (_usage), EV_KEY, (_code)), \
129 .relabs = HIDMAP_RELABS_ANY
130 #define HIDMAP_KEY_RANGE(_page, _ufrom, _uto, _code) \
131 HIDMAP_ANY_RANGE((_page), (_ufrom), (_uto), EV_KEY, (_code)), \
132 .relabs = HIDMAP_RELABS_ANY
133 #define HIDMAP_REL(_page, _usage, _code) \
134 HIDMAP_ANY((_page), (_usage), EV_REL, (_code)), \
135 .relabs = HIDMAP_RELATIVE
136 #define HIDMAP_ABS(_page, _usage, _code) \
137 HIDMAP_ANY((_page), (_usage), EV_ABS, (_code)), \
138 .relabs = HIDMAP_ABSOLUTE
139 #define HIDMAP_SW(_page, _usage, _code) \
140 HIDMAP_ANY((_page), (_usage), EV_SW, (_code)), \
141 .relabs = HIDMAP_RELABS_ANY
142 #define HIDMAP_REL_CB(_page, _usage, _callback) \
143 HIDMAP_ANY_CB((_page), (_usage), (_callback)), \
144 .relabs = HIDMAP_RELATIVE
145 #define HIDMAP_ABS_CB(_page, _usage, _callback) \
146 HIDMAP_ANY_CB((_page), (_usage), (_callback)), \
147 .relabs = HIDMAP_ABSOLUTE
148 /*
149 * Special callback function which is not tied to particular HID input usage
150 * but called at the end evdev properties setting or interrupt handler
151 * just before evdev_register() or evdev_sync() calls.
152 */
153 #define HIDMAP_FINAL_CB(_callback) \
154 HIDMAP_ANY_CB(0, 0, (_callback)), .final_cb = true
155
156 enum hidmap_type {
157 HIDMAP_TYPE_FINALCB = 0,/* No HID item associated. Runs unconditionally
158 * at the end of other items processing */
159 HIDMAP_TYPE_CALLBACK, /* HID item is reported with user callback */
160 HIDMAP_TYPE_VARIABLE, /* HID item is variable (single usage) */
161 HIDMAP_TYPE_VAR_NULLST, /* HID item is null state variable */
162 HIDMAP_TYPE_ARR_LIST, /* HID item is array with list of usages */
163 HIDMAP_TYPE_ARR_RANGE, /* Array with range (min;max) of usages */
164 };
165
166 struct hidmap_hid_item {
167 union {
168 hidmap_cb_t *cb; /* Callback */
169 struct { /* Variable */
170 uint16_t evtype; /* Evdev event type */
171 uint16_t code; /* Evdev event code */
172 };
173 uint16_t *codes; /* Array list map type */
174 int32_t umin; /* Array range map type */
175 };
176 union {
177 void *udata; /* Callback private context */
178 uint64_t udata64;
179 int32_t last_val; /* Last reported value (var) */
180 uint16_t last_key; /* Last reported key (array) */
181 };
182 struct hid_location loc; /* HID item location */
183 int32_t lmin; /* HID item logical minimum */
184 int32_t lmax; /* HID item logical maximum */
185 enum hidmap_type type:8;
186 uint8_t id; /* Report ID */
187 bool invert_value;
188 };
189
190 struct hidmap {
191 device_t dev;
192
193 struct evdev_dev *evdev;
194 struct evdev_methods evdev_methods;
195
196 /* Scatter-gather list of maps */
197 int nmaps;
198 uint32_t nmap_items[HIDMAP_MAX_MAPS];
199 const struct hidmap_item *map[HIDMAP_MAX_MAPS];
200
201 /* List of preparsed HID items */
202 uint32_t nhid_items;
203 struct hidmap_hid_item *hid_items;
204
205 /* Key event merging buffers */
206 uint8_t *key_press;
207 uint8_t *key_rel;
208 uint16_t key_min;
209 uint16_t key_max;
210
211 int *debug_var;
212 int debug_level;
213 enum hidmap_cb_state cb_state;
214 void * intr_buf;
215 hid_size_t intr_len;
216 };
217
218 typedef uint8_t * hidmap_caps_t;
219 #define HIDMAP_CAPS_SZ(nitems) howmany((nitems), 8)
220 #define HIDMAP_CAPS(name, map) uint8_t (name)[HIDMAP_CAPS_SZ(nitems(map))]
221 static inline bool
hidmap_test_cap(hidmap_caps_t caps,int cap)222 hidmap_test_cap(hidmap_caps_t caps, int cap)
223 {
224 return (isset(caps, cap) != 0);
225 }
226
227 /*
228 * It is safe to call any of following procedures in device_probe context
229 * that makes possible to write probe-only drivers with attach/detach handlers
230 * inherited from hidmap. See hcons and hsctrl drivers for example.
231 */
232 static inline void
hidmap_set_dev(struct hidmap * hm,device_t dev)233 hidmap_set_dev(struct hidmap *hm, device_t dev)
234 {
235 hm->dev = dev;
236 }
237
238 /* Hack to avoid #ifdef-ing of hidmap_set_debug_var in hidmap based drivers */
239 #ifdef HID_DEBUG
240 #define hidmap_set_debug_var(h, d) _hidmap_set_debug_var((h), (d))
241 #else
242 #define hidmap_set_debug_var(...)
243 #endif
244 void _hidmap_set_debug_var(struct hidmap *hm, int *debug_var);
245 #define HIDMAP_ADD_MAP(hm, map, caps) \
246 hidmap_add_map((hm), (map), nitems(map), (caps))
247 uint32_t hidmap_add_map(struct hidmap *hm, const struct hidmap_item *map,
248 int nitems_map, hidmap_caps_t caps);
249
250 /* Versions of evdev_* functions capable to merge key events with same codes */
251 void hidmap_support_key(struct hidmap *hm, uint16_t key);
252 void hidmap_push_key(struct hidmap *hm, uint16_t key, int32_t value);
253
254 void hidmap_intr(void *context, void *buf, hid_size_t len);
255 #define HIDMAP_PROBE(hm, dev, id, map, suffix) \
256 hidmap_probe((hm), (dev), (id), nitems(id), (map), nitems(map), \
257 (suffix), NULL)
258 int hidmap_probe(struct hidmap* hm, device_t dev,
259 const struct hid_device_id *id, int nitems_id,
260 const struct hidmap_item *map, int nitems_map,
261 const char *suffix, hidmap_caps_t caps);
262 int hidmap_attach(struct hidmap *hm);
263 int hidmap_detach(struct hidmap *hm);
264
265 #endif /* _HIDMAP_H_ */
266