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