2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2015-2017 Vladimir Kondratyev <wulf@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
32 #include <sys/ioctl.h>
34 #include <sys/sysctl.h>
36 #include <dev/evdev/input.h>
37 #include <dev/evdev/uinput.h>
38 #include <dev/usb/usb.h>
39 #include <dev/usb/usbhid.h>
42 #define L2CAP_SOCKET_CHECKED
43 #include <bluetooth.h>
53 #include "bthid_config.h"
57 static int16_t const mbuttons[8] = {
68 static uint16_t const led_codes[3] = {
69 LED_CAPSL, /* CLKED */
71 LED_SCROLLL, /* SLKED */
74 #define NONE KEY_RESERVED
76 static uint16_t const keymap[0x100] = {
78 NONE, NONE, NONE, NONE, KEY_A, KEY_B, KEY_C, KEY_D,
79 KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
80 KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
81 KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2,
82 KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
84 KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB,
85 KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE,
86 KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON,
87 KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT,
88 KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2,
89 KEY_F3, KEY_F4, KEY_F5, KEY_F6,
91 KEY_F7, KEY_F8, KEY_F9, KEY_F10,
92 KEY_F11, KEY_F12, KEY_SYSRQ, KEY_SCROLLLOCK,
93 KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP,
94 KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT,
95 KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK,
96 KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS,
97 KEY_KPENTER, KEY_KP1, KEY_KP2, KEY_KP3,
98 KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7,
100 KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT,
101 KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL,
102 KEY_F13, KEY_F14, KEY_F15, KEY_F16,
103 KEY_F17, KEY_F18, KEY_F19, KEY_F20,
104 KEY_F21, KEY_F22, KEY_F23, KEY_F24,
105 KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT,
106 KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT,
107 KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE,
109 KEY_VOLUMEUP, KEY_VOLUMEDOWN, NONE, NONE,
110 NONE, KEY_KPCOMMA, NONE, KEY_RO,
111 KEY_KATAKANAHIRAGANA, KEY_YEN,KEY_HENKAN, KEY_MUHENKAN,
112 KEY_KPJPCOMMA, NONE, NONE, NONE,
113 KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA,
114 KEY_ZENKAKUHANKAKU, NONE, NONE, NONE,
115 NONE, NONE, NONE, NONE,
116 NONE, NONE, NONE, NONE,
118 NONE, NONE, NONE, NONE,
119 NONE, NONE, NONE, NONE,
120 NONE, NONE, NONE, NONE,
121 NONE, NONE, NONE, NONE,
122 NONE, NONE, NONE, NONE,
123 NONE, NONE, NONE, NONE,
124 NONE, NONE, NONE, NONE,
125 NONE, NONE, NONE, NONE,
127 NONE, NONE, NONE, NONE,
128 NONE, NONE, NONE, NONE,
129 NONE, NONE, NONE, NONE,
130 NONE, NONE, NONE, NONE,
131 NONE, NONE, NONE, NONE,
132 NONE, NONE, NONE, NONE,
133 NONE, NONE, NONE, NONE,
134 NONE, NONE, NONE, NONE,
136 KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA,
137 KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA,
138 KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG,KEY_NEXTSONG,
139 KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
140 KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP,
141 KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT,
142 KEY_SLEEP, KEY_COFFEE, KEY_REFRESH, KEY_CALC,
143 NONE, NONE, NONE, NONE,
146 /* Consumer page usage mapping */
147 static uint16_t const consmap[0x300] = {
149 [0x031] = KEY_RESTART,
152 [0x035] = KEY_KBDILLUMTOGGLE,
155 [0x041] = KEY_SELECT,
161 [0x047] = KEY_KPPLUS,
162 [0x048] = KEY_KPMINUS,
164 [0x061] = KEY_SUBTITLE,
166 [0x065] = KEY_CAMERA,
170 [0x06c] = KEY_YELLOW,
172 [0x06f] = KEY_BRIGHTNESSUP,
173 [0x070] = KEY_BRIGHTNESSDOWN,
174 [0x072] = KEY_BRIGHTNESS_TOGGLE,
175 [0x073] = KEY_BRIGHTNESS_MIN,
176 [0x074] = KEY_BRIGHTNESS_MAX,
177 [0x075] = KEY_BRIGHTNESS_AUTO,
178 [0x082] = KEY_VIDEO_NEXT,
186 [0x08d] = KEY_PROGRAM,
187 [0x08e] = KEY_VIDEOPHONE,
199 [0x09c] = KEY_CHANNELUP,
200 [0x09d] = KEY_CHANNELDOWN,
204 [0x0b2] = KEY_RECORD,
205 [0x0b3] = KEY_FASTFORWARD,
206 [0x0b4] = KEY_REWIND,
207 [0x0b5] = KEY_NEXTSONG,
208 [0x0b6] = KEY_PREVIOUSSONG,
209 [0x0b7] = KEY_STOPCD,
210 [0x0b8] = KEY_EJECTCD,
211 [0x0bc] = KEY_MEDIA_REPEAT,
212 [0x0b9] = KEY_SHUFFLE,
214 [0x0cd] = KEY_PLAYPAUSE,
215 [0x0cf] = KEY_VOICECOMMAND,
217 [0x0e5] = KEY_BASSBOOST,
218 [0x0e9] = KEY_VOLUMEUP,
219 [0x0ea] = KEY_VOLUMEDOWN,
221 [0x181] = KEY_BUTTONCONFIG,
222 [0x182] = KEY_BOOKMARKS,
223 [0x183] = KEY_CONFIG,
224 [0x184] = KEY_WORDPROCESSOR,
225 [0x185] = KEY_EDITOR,
226 [0x186] = KEY_SPREADSHEET,
227 [0x187] = KEY_GRAPHICSEDITOR,
228 [0x188] = KEY_PRESENTATION,
229 [0x189] = KEY_DATABASE,
232 [0x18c] = KEY_VOICEMAIL,
233 [0x18d] = KEY_ADDRESSBOOK,
234 [0x18e] = KEY_CALENDAR,
235 [0x18f] = KEY_TASKMANAGER,
236 [0x190] = KEY_JOURNAL,
237 [0x191] = KEY_FINANCE,
239 [0x193] = KEY_PLAYER,
243 [0x19c] = KEY_LOGOFF,
244 [0x19e] = KEY_COFFEE,
245 [0x19f] = KEY_CONTROLPANEL,
246 [0x1a2] = KEY_APPSELECT,
248 [0x1a4] = KEY_PREVIOUS,
250 [0x1a7] = KEY_DOCUMENTS,
251 [0x1ab] = KEY_SPELLCHECK,
252 [0x1ae] = KEY_KEYBOARD,
253 [0x1b1] = KEY_SCREENSAVER,
255 [0x1b6] = KEY_IMAGES,
258 [0x1bc] = KEY_MESSENGER,
272 [0x221] = KEY_SEARCH,
274 [0x223] = KEY_HOMEPAGE,
276 [0x225] = KEY_FORWARD,
278 [0x227] = KEY_REFRESH,
279 [0x22a] = KEY_BOOKMARKS,
280 [0x22d] = KEY_ZOOMIN,
281 [0x22e] = KEY_ZOOMOUT,
282 [0x22f] = KEY_ZOOMRESET,
283 [0x233] = KEY_SCROLLUP,
284 [0x234] = KEY_SCROLLDOWN,
286 [0x25f] = KEY_CANCEL,
287 [0x269] = KEY_INSERT,
288 [0x26a] = KEY_DELETE,
291 [0x28b] = KEY_FORWARDMAIL,
293 [0x2c7] = KEY_KBDINPUTASSIST_PREV,
294 [0x2c8] = KEY_KBDINPUTASSIST_NEXT,
295 [0x2c9] = KEY_KBDINPUTASSIST_PREVGROUP,
296 [0x2ca] = KEY_KBDINPUTASSIST_NEXTGROUP,
297 [0x2cb] = KEY_KBDINPUTASSIST_ACCEPT,
298 [0x2cc] = KEY_KBDINPUTASSIST_CANCEL,
302 uinput_open_common(hid_device_p const p, bdaddr_p local, const uint8_t *name)
304 struct uinput_setup uisetup;
305 uint8_t phys[UINPUT_MAX_NAME_SIZE];
306 uint8_t uniq[UINPUT_MAX_NAME_SIZE];
309 /* Take local and remote bdaddr */
310 bt_ntoa(local, phys);
311 bt_ntoa(&p->bdaddr, uniq);
313 /* Take device name from bthidd.conf. Fallback to generic name. */
317 /* Set device name and bus/vendor information */
318 memset(&uisetup, 0, sizeof(uisetup));
319 snprintf(uisetup.name, UINPUT_MAX_NAME_SIZE,
320 "%s, bdaddr %s", name, uniq);
321 uisetup.id.bustype = BUS_BLUETOOTH;
322 uisetup.id.vendor = p->vendor_id;
323 uisetup.id.product = p->product_id;
324 uisetup.id.version = p->version;
326 fd = open("/dev/uinput", O_RDWR | O_NONBLOCK);
328 if (ioctl(fd, UI_SET_PHYS, phys) < 0 ||
329 ioctl(fd, UI_SET_BSDUNIQ, uniq) < 0 ||
330 ioctl(fd, UI_DEV_SETUP, &uisetup) < 0)
337 * Setup uinput device as 8button mouse with wheel(s)
338 * TODO: bring in more feature detection code from ums
341 uinput_open_mouse(hid_device_p const p, bdaddr_p local)
348 if ((fd = uinput_open_common(p, local, "Bluetooth Mouse")) < 0)
351 /* Advertise events and axes */
352 if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0 ||
353 ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0 ||
354 ioctl(fd, UI_SET_EVBIT, EV_REL) < 0 ||
355 ioctl(fd, UI_SET_RELBIT, REL_X) < 0 ||
356 ioctl(fd, UI_SET_RELBIT, REL_Y) < 0 ||
357 (p->has_wheel && ioctl(fd, UI_SET_RELBIT, REL_WHEEL) < 0) ||
358 (p->has_hwheel && ioctl(fd, UI_SET_RELBIT, REL_HWHEEL) < 0) ||
359 ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_POINTER) < 0)
362 /* Advertise mouse buttons */
363 for (i = 0; i < nitems(mbuttons); i++)
364 if (ioctl(fd, UI_SET_KEYBIT, mbuttons[i]) < 0)
367 if (ioctl(fd, UI_DEV_CREATE) >= 0)
368 return (fd); /* SUCCESS */
377 * Setup uinput keyboard
380 uinput_open_keyboard(hid_device_p const p, bdaddr_p local)
387 if ((fd = uinput_open_common(p, local, "Bluetooth Keyboard")) < 0)
390 /* Advertise key events and LEDs */
391 if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0 ||
392 ioctl(fd, UI_SET_EVBIT, EV_LED) < 0 ||
393 ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0 ||
394 ioctl(fd, UI_SET_EVBIT, EV_REP) < 0 ||
395 ioctl(fd, UI_SET_LEDBIT, LED_CAPSL) < 0 ||
396 ioctl(fd, UI_SET_LEDBIT, LED_NUML) < 0 ||
397 ioctl(fd, UI_SET_LEDBIT, LED_SCROLLL))
400 /* Advertise keycodes */
401 for (i = 0; i < nitems(keymap); i++)
402 if (keymap[i] != NONE &&
403 ioctl(fd, UI_SET_KEYBIT, keymap[i]) < 0)
406 /* Advertise consumer page keys if any */
408 for (i = 0; i < nitems(consmap); i++) {
409 if (consmap[i] != NONE &&
410 ioctl(fd, UI_SET_KEYBIT, consmap[i]) < 0)
415 if (ioctl(fd, UI_DEV_CREATE) >= 0)
416 return (fd); /* SUCCESS */
424 /* from sys/dev/evdev/evdev.h */
425 #define EVDEV_RCPT_HW_MOUSE (1<<2)
426 #define EVDEV_RCPT_HW_KBD (1<<3)
428 #define MASK_POLL_INTERVAL 5 /* seconds */
429 #define MASK_SYSCTL "kern.evdev.rcpt_mask"
432 uinput_get_rcpt_mask(void)
434 static struct timespec last = { 0, 0 };
436 static int32_t mask = 0;
440 if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == -1)
443 elapsed = now.tv_sec - last.tv_sec;
444 if (now.tv_nsec < last.tv_nsec)
447 if (elapsed >= MASK_POLL_INTERVAL) {
449 if (sysctlbyname(MASK_SYSCTL, &mask, &len, NULL, 0) < 0) {
451 /* kernel is compiled w/o EVDEV_SUPPORT */
452 mask = EVDEV_RCPT_HW_MOUSE | EVDEV_RCPT_HW_KBD;
462 uinput_write_event(int32_t fd, uint16_t type, uint16_t code, int32_t value)
464 struct input_event ie;
468 memset(&ie, 0, sizeof(ie));
472 return (write(fd, &ie, sizeof(ie)));
476 uinput_rep_mouse(int32_t fd, int32_t x, int32_t y, int32_t z, int32_t t,
477 int32_t buttons, int32_t obuttons)
480 int32_t rcpt_mask, mask;
484 rcpt_mask = uinput_get_rcpt_mask();
485 if (!(rcpt_mask & EVDEV_RCPT_HW_MOUSE))
488 if ((x != 0 && uinput_write_event(fd, EV_REL, REL_X, x) < 0) ||
489 (y != 0 && uinput_write_event(fd, EV_REL, REL_Y, y) < 0) ||
490 (z != 0 && uinput_write_event(fd, EV_REL, REL_WHEEL, -z) < 0) ||
491 (t != 0 && uinput_write_event(fd, EV_REL, REL_HWHEEL, t) < 0))
494 for (i = 0; i < nitems(mbuttons); i++) {
496 if ((buttons & mask) == (obuttons & mask))
498 if (uinput_write_event(fd, EV_KEY, mbuttons[i],
499 (buttons & mask) != 0) < 0)
503 if (uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) < 0)
510 * Translate and report keyboard page key events
513 uinput_rep_key(int32_t fd, int32_t key, int32_t make)
519 rcpt_mask = uinput_get_rcpt_mask();
520 if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
523 if (key >= 0 && key < (int32_t)nitems(keymap) &&
524 keymap[key] != NONE) {
525 if (uinput_write_event(fd, EV_KEY, keymap[key], make) > 0 &&
526 uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) > 0)
533 * Translate and report consumer page key events
536 uinput_rep_cons(int32_t fd, int32_t key, int32_t make)
542 rcpt_mask = uinput_get_rcpt_mask();
543 if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
546 if (key >= 0 && key < (int32_t)nitems(consmap) &&
547 consmap[key] != NONE) {
548 if (uinput_write_event(fd, EV_KEY, consmap[key], make) > 0 &&
549 uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) > 0)
556 * Translate and report LED events
559 uinput_rep_leds(int32_t fd, int state, int mask)
566 rcpt_mask = uinput_get_rcpt_mask();
567 if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
570 for (i = 0; i < nitems(led_codes); i++) {
571 if (mask & (1 << i) &&
572 uinput_write_event(fd, EV_LED, led_codes[i],
573 state & (1 << i) ? 1 : 0) < 0)
581 * Process status change from evdev
584 uinput_kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len)
586 struct input_event ie;
591 assert(s->vkbd >= 0);
592 assert(len == sizeof(struct input_event));
594 memcpy(&ie, data, sizeof(ie));
597 ioctl(s->vkbd, KDGETLED, &oleds);
599 for (i = 0; i < nitems(led_codes); i++) {
600 if (led_codes[i] == ie.code) {
606 ioctl(s->vkbd, KDSETLED, leds);
612 /* FALLTHROUGH. Repeats are handled by evdev subsystem */