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 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 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