Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144623949
D13456.1775846517.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
45 KB
Referenced Files
None
Subscribers
None
D13456.1775846517.diff
View Options
Index: etc/defaults/rc.conf
===================================================================
--- etc/defaults/rc.conf
+++ etc/defaults/rc.conf
@@ -430,6 +430,7 @@
bthidd_enable="NO" # Enable bthidd(8) (or NO)
bthidd_config="/etc/bluetooth/bthidd.conf" # bthidd(8) configuration file
bthidd_hids="/var/db/bthidd.hids" # bthidd(8) known HID devices file
+bthidd_evdev_support="AUTO" # AUTO depends on EVDEV_SUPPORT kernel option
rfcomm_pppd_server_enable="NO" # Enable rfcomm_pppd(8) in server mode (or NO)
rfcomm_pppd_server_profile="one two" # Profile to use from /etc/ppp/ppp.conf
Index: etc/rc.d/bthidd
===================================================================
--- etc/rc.d/bthidd
+++ etc/rc.d/bthidd
@@ -17,8 +17,25 @@
pidfile="/var/run/${name}.pid"
start_precmd="bthidd_prestart"
+evdev_enabled()
+{
+ case ${bthidd_evdev_support} in
+ [Aa][Uu][Tt][Oo])
+ check_kern_features evdev_support
+ return $?
+ ;;
+ *)
+ checkyesno bthidd_evdev_support
+ return $?
+ ;;
+ esac
+}
+
bthidd_prestart()
{
+ if evdev_enabled; then
+ load_kld -m uinput uinput
+ fi
load_kld -m kbdmux kbdmux
load_kld -m vkbd vkbd
load_kld -m ng_btsocket ng_btsocket
@@ -29,6 +46,9 @@
config="${bthidd_config:-/etc/bluetooth/${name}.conf}"
hids="${bthidd_hids:-/var/db/${name}.hids}"
command_args="-c ${config} -H ${hids} -p ${pidfile}"
+if evdev_enabled; then
+ command_args="$command_args -u"
+fi
required_files="${config}"
run_rc_command "$1"
Index: lib/libsdp/sdp.h
===================================================================
--- lib/libsdp/sdp.h
+++ lib/libsdp/sdp.h
@@ -530,6 +530,7 @@
void * sdp_open_local (char const *control);
int32_t sdp_close (void *xs);
int32_t sdp_error (void *xs);
+int32_t sdp_get_socket (void *xs);
int32_t sdp_search (void *xs,
uint32_t plen, uint16_t const *pp,
Index: lib/libsdp/sdp.3
===================================================================
--- lib/libsdp/sdp.3
+++ lib/libsdp/sdp.3
@@ -25,7 +25,7 @@
.\" $Id: sdp.3,v 1.1 2003/09/07 20:34:19 max Exp $
.\" $FreeBSD$
.\"
-.Dd May 27, 2005
+.Dd December 19, 2017
.Dt SDP 3
.Os
.Sh NAME
@@ -45,6 +45,7 @@
.Nm sdp_open_local ,
.Nm sdp_close ,
.Nm sdp_error ,
+.Nm sdp_get_socket ,
.Nm sdp_search ,
.Nm sdp_attr2desc ,
.Nm sdp_uuid2desc
@@ -75,6 +76,8 @@
.Ft int32_t
.Fn sdp_error "void *xs"
.Ft int32_t
+.Fn sdp_get_socket "void *xs"
+.Ft int32_t
.Fo sdp_search
.Fa "void *xs" "uint32_t plen" "uint16_t const *pp" "uint32_t alen"
.Fa "uint32_t const *ap" "uint32_t vlen" "sdp_attr_t *vp"
@@ -188,6 +191,16 @@
function.
.Pp
The
+.Fn sdp_get_socket
+function returns SDP session socket handle.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+.Pp
+The
.Fn sdp_search
function is used to perform SDP Service Search Attribute Request.
The
Index: lib/libsdp/session.c
===================================================================
--- lib/libsdp/session.c
+++ lib/libsdp/session.c
@@ -178,3 +178,11 @@
return ((ss != NULL)? ss->error : EINVAL);
}
+
+int32_t
+sdp_get_socket(void *xss)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+
+ return (ss->s);
+}
Index: sys/dev/evdev/uinput.h
===================================================================
--- sys/dev/evdev/uinput.h
+++ sys/dev/evdev/uinput.h
@@ -90,6 +90,13 @@
#define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
#define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
+/*
+ * FreeBSD specific. Set unique identifier of input device.
+ * Name and magic are chosen to reduce chances of clashing
+ * with possible future Linux extensions.
+ */
+#define UI_SET_BSDUNIQ _IO(UINPUT_IOCTL_BASE, 109)
+
#define EV_UINPUT 0x0101
#define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2
Index: sys/dev/evdev/uinput.c
===================================================================
--- sys/dev/evdev/uinput.c
+++ sys/dev/evdev/uinput.c
@@ -604,6 +604,15 @@
evdev_set_phys(state->ucs_evdev, buf);
return (0);
+ case UI_SET_BSDUNIQ:
+ if (state->ucs_state == UINPUT_RUNNING)
+ return (EINVAL);
+ ret = copyinstr(*(void **)data, buf, sizeof(buf), NULL);
+ if (ret != 0)
+ return (ret);
+ evdev_set_serial(state->ucs_evdev, buf);
+ return (0);
+
case UI_SET_SWBIT:
if (state->ucs_state == UINPUT_RUNNING ||
intdata > SW_MAX || intdata < 0)
Index: usr.sbin/bluetooth/bthidcontrol/Makefile
===================================================================
--- usr.sbin/bluetooth/bthidcontrol/Makefile
+++ usr.sbin/bluetooth/bthidcontrol/Makefile
@@ -7,7 +7,7 @@
MAN= bthidcontrol.8
SRCS= bthidcontrol.c hid.c lexer.l parser.y sdp.c
WARNS?= 1
-CFLAGS+= -DBTHIDCONTROL=1 -I${.CURDIR:H}/bthidd
+CFLAGS+= -DBTHIDCONTROL=1 -I${.CURDIR:H}/bthidd -I${SRCTOP}/lib/libsdp
LIBADD+= bluetooth sdp usbhid
Index: usr.sbin/bluetooth/bthidcontrol/sdp.c
===================================================================
--- usr.sbin/bluetooth/bthidcontrol/sdp.c
+++ usr.sbin/bluetooth/bthidcontrol/sdp.c
@@ -29,7 +29,9 @@
* $FreeBSD$
*/
+#include <sys/types.h>
#include <sys/queue.h>
+#include <sys/sysctl.h>
#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <dev/usb/usb.h>
@@ -109,16 +111,78 @@
}
}
+static int
+bt_devany_cb(int s, struct bt_devinfo const *di, void *xdevname)
+{
+ strlcpy((char *) xdevname, di->devname, HCI_DEVNAME_SIZE);
+ return (1);
+}
+
+static char *
+hid_hci_remote_name_query(bdaddr_t *local, bdaddr_t *remote)
+{
+ struct bt_devreq r;
+ ng_hci_remote_name_req_cp cp;
+ ng_hci_remote_name_req_compl_ep ep;
+ int s, to;
+ size_t to_size;
+ char *remote_name = NULL;
+ char devname[HCI_DEVNAME_SIZE];
+
+ to_size = sizeof(to);
+ if (sysctlbyname("net.bluetooth.hci.command_timeout",
+ &to, &to_size, NULL, 0) < 0)
+ goto bail_out;
+ to++;
+
+ memset(devname, 0, sizeof(devname));
+ /* Try to find HCI by local bdaddr */
+ if (local == NULL || local == NG_HCI_BDADDR_ANY ||
+ bt_devname(devname, local) != 0)
+ /* Or scan through all BT devices for first HCI available */
+ if (bt_devenum(bt_devany_cb, devname) <= 0)
+ goto bail_out;
+
+ memset(&r, 0, sizeof(r));
+ memset(&cp, 0, sizeof(cp));
+ memset(&ep, 0, sizeof(ep));
+ cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
+ cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
+ bdaddr_copy(&cp.bdaddr, remote);
+ r.opcode = NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_REMOTE_NAME_REQ);
+ r.event = NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL;
+ r.cparam = &cp;
+ r.clen = sizeof(cp);
+ r.rparam = &ep;
+ r.rlen = sizeof(ep);
+
+ s = bt_devopen(devname);
+ if (s < 0)
+ goto bail_out;
+
+ /* send request and expect status response */
+ if (bt_devreq(s, &r, to) == 0 || ep.status == 0x00)
+ remote_name = strndup((const char *)&ep.name, sizeof(ep.name));
+
+ bt_devclose(s);
+bail_out:
+ return (remote_name);
+}
+
static int32_t
hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error)
{
- void *ss = NULL;
- uint8_t *hid_descriptor = NULL, *v;
- int32_t i, control_psm = -1, interrupt_psm = -1,
- reconnect_initiate = -1,
- normally_connectable = 0, battery_power = 0,
- hid_descriptor_length = -1, type;
- int16_t vendor_id = 0, product_id = 0, version = 0;
+ void *ss = NULL;
+ uint8_t *hid_descriptor = NULL, *v;
+ int32_t i, control_psm = -1, interrupt_psm = -1,
+ reconnect_initiate = -1,
+ normally_connectable = 0, battery_power = 0,
+ hid_descriptor_length = -1, type;
+ int16_t vendor_id = 0, product_id = 0, version = 0;
+ struct sockaddr_l2cap salocal;
+ socklen_t salen;
+ bdaddr_t *sdp_local;
if (local == NULL)
local = NG_HCI_BDADDR_ANY;
@@ -173,6 +237,14 @@
if (sdp_search(ss, 1, &service_devid, 1, &attrs_devid, nvalues, values) != 0)
hid_sdp_query_exit(sdp_error(ss));
+ /* Try extract HCI bdaddr from opened SDP session */
+ salen = sizeof(salocal);
+ if (getsockname(sdp_get_socket(ss),
+ (struct sockaddr *)&salocal, &salen) == 0)
+ sdp_local = &salocal.l2cap_bdaddr;
+ else
+ sdp_local = NG_HCI_BDADDR_ANY;
+
sdp_close(ss);
ss = NULL;
@@ -210,6 +282,7 @@
reconnect_initiate == -1 ||
hid_descriptor == NULL || hid_descriptor_length == -1)
hid_sdp_query_exit(ENOATTR);
+ hd->name = hid_hci_remote_name_query(sdp_local, &hd->bdaddr);
hd->vendor_id = vendor_id;
hd->product_id = product_id;
hd->version = version;
Index: usr.sbin/bluetooth/bthidd/Makefile
===================================================================
--- usr.sbin/bluetooth/bthidd/Makefile
+++ usr.sbin/bluetooth/bthidd/Makefile
@@ -4,8 +4,8 @@
PROG= bthidd
MAN= bthidd.8
# bthidd.conf.5
-SRCS= bthidd.c client.c hid.c kbd.c lexer.l parser.y server.c \
- session.c
+SRCS= bthidd.c btuinput.c client.c hid.c kbd.c lexer.l parser.y \
+ server.c session.c
CFLAGS+= -I${.CURDIR}
Index: usr.sbin/bluetooth/bthidd/bthid_config.h
===================================================================
--- usr.sbin/bluetooth/bthidd/bthid_config.h
+++ usr.sbin/bluetooth/bthidd/bthid_config.h
@@ -40,6 +40,7 @@
struct hid_device
{
bdaddr_t bdaddr; /* HID device BDADDR */
+ char * name; /* HID device name */
uint16_t control_psm; /* control PSM */
uint16_t interrupt_psm; /* interrupt PSM */
uint16_t vendor_id; /* primary vendor id */
@@ -50,7 +51,11 @@
unsigned battery_power : 1;
unsigned normally_connectable : 1;
unsigned keyboard : 1;
- unsigned reserved : 11;
+ unsigned mouse : 1;
+ unsigned has_wheel : 1;
+ unsigned has_hwheel : 1;
+ unsigned has_cons : 1;
+ unsigned reserved : 7;
report_desc_t desc; /* HID report descriptor */
LIST_ENTRY(hid_device) next; /* link to the next */
};
Index: usr.sbin/bluetooth/bthidd/bthidd.h
===================================================================
--- usr.sbin/bluetooth/bthidd/bthidd.h
+++ usr.sbin/bluetooth/bthidd/bthidd.h
@@ -46,6 +46,7 @@
int32_t ctrl; /* control channel (listen) */
int32_t intr; /* intr. channel (listen) */
int32_t maxfd; /* max fd in sets */
+ int32_t uinput; /* enable evdev support */
fd_set rfdset; /* read descriptor set */
fd_set wfdset; /* write descriptor set */
LIST_HEAD(, bthid_session) sessions;
@@ -61,6 +62,10 @@
int32_t intr; /* interrupt channel */
int32_t vkbd; /* virual keyboard */
void *ctx; /* product specific dev state */
+ int32_t ukbd; /* evdev user input */
+ int32_t umouse;/* evdev user input */
+ int32_t obutt; /* previous mouse buttons */
+ int32_t consk; /* last consumer page key */
bdaddr_t bdaddr;/* remote bdaddr */
uint16_t state; /* session state */
#define CLOSED 0
@@ -85,6 +90,7 @@
bthid_session_p session_open (bthid_server_p srv, hid_device_p const d);
bthid_session_p session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr);
bthid_session_p session_by_fd (bthid_server_p srv, int32_t fd);
+int32_t session_run (bthid_session_p s);
void session_close (bthid_session_p s);
void hid_initialise (bthid_session_p s);
Index: usr.sbin/bluetooth/bthidd/bthidd.8
===================================================================
--- usr.sbin/bluetooth/bthidd/bthidd.8
+++ usr.sbin/bluetooth/bthidd/bthidd.8
@@ -25,7 +25,7 @@
.\" $Id: bthidd.8,v 1.1 2006/09/07 21:36:55 max Exp $
.\" $FreeBSD$
.\"
-.Dd September 7, 2006
+.Dd December 19, 2017
.Dt BTHIDD 8
.Os
.Sh NAME
@@ -40,6 +40,7 @@
.Op Fl H Ar file
.Op Fl p Ar file
.Op Fl t Ar val
+.Op Fl u
.Sh DESCRIPTION
The
.Nm
@@ -82,6 +83,9 @@
.Dq passive
Bluetooth HID devices and will attempt to establish an outgoing connection.
The default rescan interval is 10 seconds.
+.It Fl u
+Enable support for input event device protocol.
+Requires evdev and uinput drivers to be kld-loaded or compiled into the kernel.
.El
.Sh KNOWN LIMITATIONS
The
Index: usr.sbin/bluetooth/bthidd/bthidd.c
===================================================================
--- usr.sbin/bluetooth/bthidd/bthidd.c
+++ usr.sbin/bluetooth/bthidd/bthidd.c
@@ -67,14 +67,15 @@
struct sigaction sa;
char const *pid_file = BTHIDD_PIDFILE;
char *ep;
- int32_t opt, detach, tval;
+ int32_t opt, detach, tval, uinput;
memset(&srv, 0, sizeof(srv));
memset(&srv.bdaddr, 0, sizeof(srv.bdaddr));
detach = 1;
tval = 10; /* sec */
+ uinput = 0;
- while ((opt = getopt(argc, argv, "a:c:dH:hp:t:")) != -1) {
+ while ((opt = getopt(argc, argv, "a:c:dH:hp:t:u")) != -1) {
switch (opt) {
case 'a': /* BDADDR */
if (!bt_aton(optarg, &srv.bdaddr)) {
@@ -109,6 +110,10 @@
usage();
break;
+ case 'u': /* enable evdev support */
+ uinput = 1;
+ break;
+
case 'h':
default:
usage();
@@ -156,6 +161,8 @@
server_init(&srv) < 0 || write_pid_file(pid_file) < 0)
exit(1);
+ srv.uinput = uinput;
+
for (done = 0; !done; ) {
if (elapsed(tval))
client_rescan(&srv);
@@ -261,6 +268,7 @@
" -h display this message\n" \
" -p file specify PID file name\n" \
" -t tval specify client rescan interval (sec)\n" \
+" -u enable evdev protocol support\n" \
"", BTHIDD_IDENT);
exit(255);
}
Index: usr.sbin/bluetooth/bthidd/bthidd.conf.sample
===================================================================
--- usr.sbin/bluetooth/bthidd/bthidd.conf.sample
+++ usr.sbin/bluetooth/bthidd/bthidd.conf.sample
@@ -2,6 +2,7 @@
device {
bdaddr 00:50:f2:e5:68:84;
+ name "Bluetooth Mouse";
vendor_id 0x0000;
product_id 0x0000;
version 0x0000;
@@ -27,6 +28,7 @@
device {
bdaddr 00:50:f2:e3:fb:e1;
+ name "Bluetooth Keyboard";
vendor_id 0x0000;
product_id 0x0000;
version 0x0000;
Index: usr.sbin/bluetooth/bthidd/btuinput.h
===================================================================
--- /dev/null
+++ usr.sbin/bluetooth/bthidd/btuinput.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2015-2017 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _UINPUT_H_
+#define _UINPUT_H_
+
+int32_t uinput_open_mouse(hid_device_p const d, bdaddr_p local);
+int32_t uinput_open_keyboard(hid_device_p const d, bdaddr_p local);
+int32_t uinput_rep_mouse(int32_t fd, int32_t x, int32_t y, int32_t z,
+ int32_t t, int32_t buttons, int32_t obuttons);
+int32_t uinput_rep_key(int32_t fd, int32_t key, int32_t make);
+int32_t uinput_rep_cons(int32_t fd, int32_t key, int32_t make);
+int32_t uinput_rep_leds(int32_t fd, int state, int mask);
+int32_t uinput_kbd_status_changed(bthid_session_p s, uint8_t *data,
+ int32_t len);
+
+#endif /* ndef _UINPUT_H_ */
Index: usr.sbin/bluetooth/bthidd/btuinput.c
===================================================================
--- /dev/null
+++ usr.sbin/bluetooth/bthidd/btuinput.c
@@ -0,0 +1,623 @@
+/*-
+ * Copyright (c) 2015-2017 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/kbio.h>
+#include <sys/sysctl.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/uinput.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include <usbhid.h>
+
+#include "bthid_config.h"
+#include "bthidd.h"
+#include "btuinput.h"
+
+static int16_t const mbuttons[8] = {
+ BTN_LEFT,
+ BTN_MIDDLE,
+ BTN_RIGHT,
+ BTN_SIDE,
+ BTN_EXTRA,
+ BTN_FORWARD,
+ BTN_BACK,
+ BTN_TASK
+};
+
+static uint16_t const led_codes[3] = {
+ LED_CAPSL, /* CLKED */
+ LED_NUML, /* NLKED */
+ LED_SCROLLL, /* SLKED */
+};
+
+#define NONE KEY_RESERVED
+
+static uint16_t const keymap[0x100] = {
+ /* 0x00 - 0x27 */
+ NONE, NONE, NONE, NONE, KEY_A, KEY_B, KEY_C, KEY_D,
+ KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
+ KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2,
+ KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
+ /* 0x28 - 0x3f */
+ KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB,
+ KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE,
+ KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON,
+ KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT,
+ KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2,
+ KEY_F3, KEY_F4, KEY_F5, KEY_F6,
+ /* 0x40 - 0x5f */
+ KEY_F7, KEY_F8, KEY_F9, KEY_F10,
+ KEY_F11, KEY_F12, KEY_SYSRQ, KEY_SCROLLLOCK,
+ KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP,
+ KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT,
+ KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK,
+ KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS,
+ KEY_KPENTER, KEY_KP1, KEY_KP2, KEY_KP3,
+ KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7,
+ /* 0x60 - 0x7f */
+ KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT,
+ KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL,
+ KEY_F13, KEY_F14, KEY_F15, KEY_F16,
+ KEY_F17, KEY_F18, KEY_F19, KEY_F20,
+ KEY_F21, KEY_F22, KEY_F23, KEY_F24,
+ KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT,
+ KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT,
+ KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE,
+ /* 0x80 - 0x9f */
+ KEY_VOLUMEUP, KEY_VOLUMEDOWN, NONE, NONE,
+ NONE, KEY_KPCOMMA, NONE, KEY_RO,
+ KEY_KATAKANAHIRAGANA, KEY_YEN,KEY_HENKAN, KEY_MUHENKAN,
+ KEY_KPJPCOMMA, NONE, NONE, NONE,
+ KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA,
+ KEY_ZENKAKUHANKAKU, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ /* 0xa0 - 0xbf */
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ /* 0xc0 - 0xdf */
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE,
+ /* 0xe0 - 0xff */
+ KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA,
+ KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA,
+ KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG,KEY_NEXTSONG,
+ KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
+ KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP,
+ KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT,
+ KEY_SLEEP, KEY_COFFEE, KEY_REFRESH, KEY_CALC,
+ NONE, NONE, NONE, NONE,
+};
+
+/* Consumer page usage mapping */
+static uint16_t const consmap[0x300] = {
+ [0x030] = KEY_POWER,
+ [0x031] = KEY_RESTART,
+ [0x032] = KEY_SLEEP,
+ [0x034] = KEY_SLEEP,
+ [0x035] = KEY_KBDILLUMTOGGLE,
+ [0x036] = BTN_MISC,
+ [0x040] = KEY_MENU,
+ [0x041] = KEY_SELECT,
+ [0x042] = KEY_UP,
+ [0x043] = KEY_DOWN,
+ [0x044] = KEY_LEFT,
+ [0x045] = KEY_RIGHT,
+ [0x046] = KEY_ESC,
+ [0x047] = KEY_KPPLUS,
+ [0x048] = KEY_KPMINUS,
+ [0x060] = KEY_INFO,
+ [0x061] = KEY_SUBTITLE,
+ [0x063] = KEY_VCR,
+ [0x065] = KEY_CAMERA,
+ [0x069] = KEY_RED,
+ [0x06a] = KEY_GREEN,
+ [0x06b] = KEY_BLUE,
+ [0x06c] = KEY_YELLOW,
+ [0x06d] = KEY_ZOOM,
+ [0x06f] = KEY_BRIGHTNESSUP,
+ [0x070] = KEY_BRIGHTNESSDOWN,
+ [0x072] = KEY_BRIGHTNESS_TOGGLE,
+ [0x073] = KEY_BRIGHTNESS_MIN,
+ [0x074] = KEY_BRIGHTNESS_MAX,
+ [0x075] = KEY_BRIGHTNESS_AUTO,
+ [0x082] = KEY_VIDEO_NEXT,
+ [0x083] = KEY_LAST,
+ [0x084] = KEY_ENTER,
+ [0x088] = KEY_PC,
+ [0x089] = KEY_TV,
+ [0x08a] = KEY_WWW,
+ [0x08b] = KEY_DVD,
+ [0x08c] = KEY_PHONE,
+ [0x08d] = KEY_PROGRAM,
+ [0x08e] = KEY_VIDEOPHONE,
+ [0x08f] = KEY_GAMES,
+ [0x090] = KEY_MEMO,
+ [0x091] = KEY_CD,
+ [0x092] = KEY_VCR,
+ [0x093] = KEY_TUNER,
+ [0x094] = KEY_EXIT,
+ [0x095] = KEY_HELP,
+ [0x096] = KEY_TAPE,
+ [0x097] = KEY_TV2,
+ [0x098] = KEY_SAT,
+ [0x09a] = KEY_PVR,
+ [0x09c] = KEY_CHANNELUP,
+ [0x09d] = KEY_CHANNELDOWN,
+ [0x0a0] = KEY_VCR2,
+ [0x0b0] = KEY_PLAY,
+ [0x0b1] = KEY_PAUSE,
+ [0x0b2] = KEY_RECORD,
+ [0x0b3] = KEY_FASTFORWARD,
+ [0x0b4] = KEY_REWIND,
+ [0x0b5] = KEY_NEXTSONG,
+ [0x0b6] = KEY_PREVIOUSSONG,
+ [0x0b7] = KEY_STOPCD,
+ [0x0b8] = KEY_EJECTCD,
+ [0x0bc] = KEY_MEDIA_REPEAT,
+ [0x0b9] = KEY_SHUFFLE,
+ [0x0bf] = KEY_SLOW,
+ [0x0cd] = KEY_PLAYPAUSE,
+ [0x0cf] = KEY_VOICECOMMAND,
+ [0x0e2] = KEY_MUTE,
+ [0x0e5] = KEY_BASSBOOST,
+ [0x0e9] = KEY_VOLUMEUP,
+ [0x0ea] = KEY_VOLUMEDOWN,
+ [0x0f5] = KEY_SLOW,
+ [0x181] = KEY_BUTTONCONFIG,
+ [0x182] = KEY_BOOKMARKS,
+ [0x183] = KEY_CONFIG,
+ [0x184] = KEY_WORDPROCESSOR,
+ [0x185] = KEY_EDITOR,
+ [0x186] = KEY_SPREADSHEET,
+ [0x187] = KEY_GRAPHICSEDITOR,
+ [0x188] = KEY_PRESENTATION,
+ [0x189] = KEY_DATABASE,
+ [0x18a] = KEY_MAIL,
+ [0x18b] = KEY_NEWS,
+ [0x18c] = KEY_VOICEMAIL,
+ [0x18d] = KEY_ADDRESSBOOK,
+ [0x18e] = KEY_CALENDAR,
+ [0x18f] = KEY_TASKMANAGER,
+ [0x190] = KEY_JOURNAL,
+ [0x191] = KEY_FINANCE,
+ [0x192] = KEY_CALC,
+ [0x193] = KEY_PLAYER,
+ [0x194] = KEY_FILE,
+ [0x196] = KEY_WWW,
+ [0x199] = KEY_CHAT,
+ [0x19c] = KEY_LOGOFF,
+ [0x19e] = KEY_COFFEE,
+ [0x19f] = KEY_CONTROLPANEL,
+ [0x1a2] = KEY_APPSELECT,
+ [0x1a3] = KEY_NEXT,
+ [0x1a4] = KEY_PREVIOUS,
+ [0x1a6] = KEY_HELP,
+ [0x1a7] = KEY_DOCUMENTS,
+ [0x1ab] = KEY_SPELLCHECK,
+ [0x1ae] = KEY_KEYBOARD,
+ [0x1b1] = KEY_SCREENSAVER,
+ [0x1b4] = KEY_FILE,
+ [0x1b6] = KEY_IMAGES,
+ [0x1b7] = KEY_AUDIO,
+ [0x1b8] = KEY_VIDEO,
+ [0x1bc] = KEY_MESSENGER,
+ [0x1bd] = KEY_INFO,
+ [0x201] = KEY_NEW,
+ [0x202] = KEY_OPEN,
+ [0x203] = KEY_CLOSE,
+ [0x204] = KEY_EXIT,
+ [0x207] = KEY_SAVE,
+ [0x208] = KEY_PRINT,
+ [0x209] = KEY_PROPS,
+ [0x21a] = KEY_UNDO,
+ [0x21b] = KEY_COPY,
+ [0x21c] = KEY_CUT,
+ [0x21d] = KEY_PASTE,
+ [0x21f] = KEY_FIND,
+ [0x221] = KEY_SEARCH,
+ [0x222] = KEY_GOTO,
+ [0x223] = KEY_HOMEPAGE,
+ [0x224] = KEY_BACK,
+ [0x225] = KEY_FORWARD,
+ [0x226] = KEY_STOP,
+ [0x227] = KEY_REFRESH,
+ [0x22a] = KEY_BOOKMARKS,
+ [0x22d] = KEY_ZOOMIN,
+ [0x22e] = KEY_ZOOMOUT,
+ [0x22f] = KEY_ZOOMRESET,
+ [0x233] = KEY_SCROLLUP,
+ [0x234] = KEY_SCROLLDOWN,
+ [0x23d] = KEY_EDIT,
+ [0x25f] = KEY_CANCEL,
+ [0x269] = KEY_INSERT,
+ [0x26a] = KEY_DELETE,
+ [0x279] = KEY_REDO,
+ [0x289] = KEY_REPLY,
+ [0x28b] = KEY_FORWARDMAIL,
+ [0x28c] = KEY_SEND,
+ [0x2c7] = KEY_KBDINPUTASSIST_PREV,
+ [0x2c8] = KEY_KBDINPUTASSIST_NEXT,
+ [0x2c9] = KEY_KBDINPUTASSIST_PREVGROUP,
+ [0x2ca] = KEY_KBDINPUTASSIST_NEXTGROUP,
+ [0x2cb] = KEY_KBDINPUTASSIST_ACCEPT,
+ [0x2cc] = KEY_KBDINPUTASSIST_CANCEL,
+};
+
+static int32_t
+uinput_open_common(hid_device_p const p, bdaddr_p local, const uint8_t *name)
+{
+ struct uinput_setup uisetup;
+ uint8_t phys[UINPUT_MAX_NAME_SIZE];
+ uint8_t uniq[UINPUT_MAX_NAME_SIZE];
+ struct hostent *hp;
+ int32_t fd;
+
+ /* Take local and remote bdaddr */
+ bt_ntoa(local, phys);
+ bt_ntoa(&p->bdaddr, uniq);
+
+ /*
+ * Take device name from bthidd.conf than fallback to BT hostname
+ * found in /etc/bluetooth/hosts and after all fallback to generic
+ * name provided by caller.
+ */
+ if (p->name != NULL)
+ name = p->name;
+ else if ((hp = bt_gethostbyaddr((const char *)&p->bdaddr,
+ sizeof(p->bdaddr), AF_BLUETOOTH)) != NULL)
+ name = hp->h_name;
+
+ /* Set device name and bus/vendor information */
+ memset(&uisetup, 0, sizeof(uisetup));
+ snprintf(uisetup.name, UINPUT_MAX_NAME_SIZE, "%s", name);
+ uisetup.id.bustype = BUS_BLUETOOTH;
+ uisetup.id.vendor = p->vendor_id;
+ uisetup.id.product = p->product_id;
+ uisetup.id.version = p->version;
+
+ fd = open("/dev/uinput", O_RDWR | O_NONBLOCK);
+
+ if (ioctl(fd, UI_SET_PHYS, phys) < 0 ||
+ ioctl(fd, UI_SET_BSDUNIQ, uniq) < 0 ||
+ ioctl(fd, UI_DEV_SETUP, &uisetup) < 0)
+ return (-1);
+
+ return (fd);
+}
+
+/*
+ * Setup uinput device as 8button mouse with wheel(s)
+ * TODO: bring in more feature detection code from ums
+ */
+int32_t
+uinput_open_mouse(hid_device_p const p, bdaddr_p local)
+{
+ size_t i;
+ int32_t fd;
+
+ assert(p != NULL);
+
+ if ((fd = uinput_open_common(p, local, "Bluetooth Mouse")) < 0)
+ goto bail_out;
+
+ /* Advertise events and axes */
+ if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0 ||
+ ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0 ||
+ ioctl(fd, UI_SET_EVBIT, EV_REL) < 0 ||
+ ioctl(fd, UI_SET_RELBIT, REL_X) < 0 ||
+ ioctl(fd, UI_SET_RELBIT, REL_Y) < 0 ||
+ (p->has_wheel && ioctl(fd, UI_SET_RELBIT, REL_WHEEL) < 0) ||
+ (p->has_hwheel && ioctl(fd, UI_SET_RELBIT, REL_HWHEEL) < 0) ||
+ ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_POINTER) < 0)
+ goto bail_out;
+
+ /* Advertise mouse buttons */
+ for (i = 0; i < nitems(mbuttons); i++)
+ if (ioctl(fd, UI_SET_KEYBIT, mbuttons[i]) < 0)
+ goto bail_out;
+
+ if (ioctl(fd, UI_DEV_CREATE) >= 0)
+ return (fd); /* SUCCESS */
+
+bail_out:
+ if (fd >= 0)
+ close(fd);
+ return (-1);
+}
+
+/*
+ * Setup uinput keyboard
+ */
+int32_t
+uinput_open_keyboard(hid_device_p const p, bdaddr_p local)
+{
+ size_t i;
+ int32_t fd;
+
+ assert(p != NULL);
+
+ if ((fd = uinput_open_common(p, local, "Bluetooth Keyboard")) < 0)
+ goto bail_out;
+
+ /* Advertise key events and LEDs */
+ if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0 ||
+ ioctl(fd, UI_SET_EVBIT, EV_LED) < 0 ||
+ ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0 ||
+ ioctl(fd, UI_SET_EVBIT, EV_REP) < 0 ||
+ ioctl(fd, UI_SET_LEDBIT, LED_CAPSL) < 0 ||
+ ioctl(fd, UI_SET_LEDBIT, LED_NUML) < 0 ||
+ ioctl(fd, UI_SET_LEDBIT, LED_SCROLLL))
+ goto bail_out;
+
+ /* Advertise keycodes */
+ for (i = 0; i < nitems(keymap); i++)
+ if (keymap[i] != NONE &&
+ ioctl(fd, UI_SET_KEYBIT, keymap[i]) < 0)
+ goto bail_out;
+
+ /* Advertise consumer page keys if any */
+ if (p->has_cons) {
+ for (i = 0; i < nitems(consmap); i++) {
+ if (consmap[i] != NONE &&
+ ioctl(fd, UI_SET_KEYBIT, consmap[i]) < 0)
+ goto bail_out;
+ }
+ }
+
+ if (ioctl(fd, UI_DEV_CREATE) >= 0)
+ return (fd); /* SUCCESS */
+
+bail_out:
+ if (fd >= 0)
+ close(fd);
+ return (-1);
+}
+
+/* from sys/dev/evdev/evdev.h */
+#define EVDEV_RCPT_HW_MOUSE (1<<2)
+#define EVDEV_RCPT_HW_KBD (1<<3)
+
+#define MASK_POLL_INTERVAL 5 /* seconds */
+#define MASK_SYSCTL "kern.evdev.rcpt_mask"
+
+static int32_t
+uinput_get_rcpt_mask(void)
+{
+ static struct timespec last = { 0, 0 };
+ struct timespec now;
+ static int32_t mask = 0;
+ size_t len;
+ time_t elapsed;
+
+ if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == -1)
+ return mask;
+
+ elapsed = now.tv_sec - last.tv_sec;
+ if (now.tv_nsec < last.tv_nsec)
+ elapsed--;
+
+ if (elapsed >= MASK_POLL_INTERVAL) {
+ len = sizeof(mask);
+ if (sysctlbyname(MASK_SYSCTL, &mask, &len, NULL, 0) < 0) {
+ if (errno == ENOENT)
+ /* kernel is compiled w/o EVDEV_SUPPORT */
+ mask = EVDEV_RCPT_HW_MOUSE | EVDEV_RCPT_HW_KBD;
+ else
+ mask = 0;
+ }
+ last = now;
+ }
+ return mask;
+}
+
+static int32_t
+uinput_write_event(int32_t fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct input_event ie;
+
+ assert(fd >= 0);
+
+ memset(&ie, 0, sizeof(ie));
+ ie.type = type;
+ ie.code = code;
+ ie.value = value;
+ return (write(fd, &ie, sizeof(ie)));
+}
+
+int32_t
+uinput_rep_mouse(int32_t fd, int32_t x, int32_t y, int32_t z, int32_t t,
+ int32_t buttons, int32_t obuttons)
+{
+ size_t i;
+ int32_t rcpt_mask, mask;
+
+ assert(fd >= 0);
+
+ rcpt_mask = uinput_get_rcpt_mask();
+ if (!(rcpt_mask & EVDEV_RCPT_HW_MOUSE))
+ return (0);
+
+ if ((x != 0 && uinput_write_event(fd, EV_REL, REL_X, x) < 0) ||
+ (y != 0 && uinput_write_event(fd, EV_REL, REL_Y, y) < 0) ||
+ (z != 0 && uinput_write_event(fd, EV_REL, REL_WHEEL, -z) < 0) ||
+ (t != 0 && uinput_write_event(fd, EV_REL, REL_HWHEEL, t) < 0))
+ return (-1);
+
+ for (i = 0; i < nitems(mbuttons); i++) {
+ mask = 1 << i;
+ if ((buttons & mask) == (obuttons & mask))
+ continue;
+ if (uinput_write_event(fd, EV_KEY, mbuttons[i],
+ (buttons & mask) != 0) < 0)
+ return (-1);
+ }
+
+ if (uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) < 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Translate and report keyboard page key events
+ */
+int32_t
+uinput_rep_key(int32_t fd, int32_t key, int32_t make)
+{
+ int32_t rcpt_mask;
+
+ assert(fd >= 0);
+
+ rcpt_mask = uinput_get_rcpt_mask();
+ if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
+ return (0);
+
+ if (key >= 0 && key < (int32_t)nitems(keymap) &&
+ keymap[key] != NONE) {
+ if (uinput_write_event(fd, EV_KEY, keymap[key], make) > 0 &&
+ uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) > 0)
+ return (0);
+ }
+ return (-1);
+}
+
+/*
+ * Translate and report consumer page key events
+ */
+int32_t
+uinput_rep_cons(int32_t fd, int32_t key, int32_t make)
+{
+ int32_t rcpt_mask;
+
+ assert(fd >= 0);
+
+ rcpt_mask = uinput_get_rcpt_mask();
+ if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
+ return (0);
+
+ if (key >= 0 && key < (int32_t)nitems(consmap) &&
+ consmap[key] != NONE) {
+ if (uinput_write_event(fd, EV_KEY, consmap[key], make) > 0 &&
+ uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) > 0)
+ return (0);
+ }
+ return (-1);
+}
+
+/*
+ * Translate and report LED events
+ */
+int32_t
+uinput_rep_leds(int32_t fd, int state, int mask)
+{
+ size_t i;
+ int32_t rcpt_mask;
+
+ assert(fd >= 0);
+
+ rcpt_mask = uinput_get_rcpt_mask();
+ if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
+ return (0);
+
+ for (i = 0; i < nitems(led_codes); i++) {
+ if (mask & (1 << i) &&
+ uinput_write_event(fd, EV_LED, led_codes[i],
+ state & (1 << i) ? 1 : 0) < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Process status change from evdev
+ */
+
+int32_t
+uinput_kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len)
+{
+ struct input_event ie;
+ int32_t leds, oleds;
+ size_t i;
+
+ assert(s != NULL);
+ assert(s->vkbd >= 0);
+ assert(len == sizeof(struct input_event));
+
+ memcpy(&ie, data, sizeof(ie));
+ switch (ie.type) {
+ case EV_LED:
+ ioctl(s->vkbd, KDGETLED, &oleds);
+ leds = oleds;
+ for (i = 0; i < nitems(led_codes); i++) {
+ if (led_codes[i] == ie.code) {
+ if (ie.value)
+ leds |= 1 << i;
+ else
+ leds &= ~(1 << i);
+ if (leds != oleds)
+ ioctl(s->vkbd, KDSETLED, leds);
+ break;
+ }
+ }
+ break;
+ case EV_REP:
+ /* Repeats are handled by evdev/uinput subsystem */
+ break;
+ }
+
+ return (0);
+}
Index: usr.sbin/bluetooth/bthidd/client.c
===================================================================
--- usr.sbin/bluetooth/bthidd/client.c
+++ usr.sbin/bluetooth/bthidd/client.c
@@ -186,14 +186,11 @@
s->state = OPEN;
connect_in_progress = 0;
- /* Register session's vkbd descriptor (if any) for read */
- if (s->state == OPEN && d->keyboard) {
- assert(s->vkbd != -1);
-
- FD_SET(s->vkbd, &srv->rfdset);
- if (s->vkbd > srv->maxfd)
- srv->maxfd = s->vkbd;
- }
+ /* Create kbd/mouse after both channels are established */
+ if (session_run(s) < 0) {
+ session_close(s);
+ return (-1);
+ }
break;
default:
Index: usr.sbin/bluetooth/bthidd/hid.c
===================================================================
--- usr.sbin/bluetooth/bthidd/hid.c
+++ usr.sbin/bluetooth/bthidd/hid.c
@@ -48,6 +48,7 @@
#include <usbhid.h>
#include "bthid_config.h"
#include "bthidd.h"
+#include "btuinput.h"
#include "kbd.h"
/*
@@ -278,6 +279,19 @@
break;
case HUP_CONSUMER:
+ if (hid_device->keyboard && s->srv->uinput) {
+ if (h.flags & HIO_VARIABLE) {
+ uinput_rep_cons(s->ukbd, usage, !!val);
+ } else {
+ if (s->consk > 0)
+ uinput_rep_cons(s->ukbd,
+ s->consk, 0);
+ if (uinput_rep_cons(s->ukbd, val, 1)
+ == 0)
+ s->consk = val;
+ }
+ }
+
if (!val)
break;
@@ -549,6 +563,14 @@
syslog(LOG_ERR, "Could not process mouse events from " \
"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
strerror(errno), errno);
+
+ if (hid_device->mouse && s->srv->uinput &&
+ uinput_rep_mouse(s->umouse, mouse_x, mouse_y, mouse_z,
+ mouse_t, mouse_butt, s->obutt) < 0)
+ syslog(LOG_ERR, "Could not process mouse events from " \
+ "%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
+ strerror(errno), errno);
+ s->obutt = mouse_butt;
}
return (0);
Index: usr.sbin/bluetooth/bthidd/kbd.c
===================================================================
--- usr.sbin/bluetooth/bthidd/kbd.c
+++ usr.sbin/bluetooth/bthidd/kbd.c
@@ -54,10 +54,12 @@
#include <usbhid.h>
#include "bthid_config.h"
#include "bthidd.h"
+#include "btuinput.h"
#include "kbd.h"
static void kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd);
static int32_t kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob);
+static void uinput_kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd);
/*
* HID code to PS/2 set 1 code translation table.
@@ -352,6 +354,7 @@
if (f2 != -1) {
/* release old keys */
kbd_write(s->keys2, f2, 0, s->vkbd);
+ uinput_kbd_write(s->keys2, f2, 0, s->ukbd);
memset(s->keys2, 0, bitstr_size(xsize));
}
@@ -364,6 +367,7 @@
memcpy(s->keys2, s->keys1, bitstr_size(xsize));
kbd_write(s->keys1, f1, 1, s->vkbd);
+ uinput_kbd_write(s->keys1, f1, 1, s->ukbd);
memset(s->keys1, 0, bitstr_size(xsize));
return (0);
@@ -391,18 +395,37 @@
}
bit_ffs(diff, xsize, &f2);
- if (f2 > 0)
+ if (f2 > 0) {
kbd_write(diff, f2, 0, s->vkbd);
+ uinput_kbd_write(diff, f2, 0, s->ukbd);
+ }
bit_ffs(s->keys1, xsize, &f1);
if (f1 > 0) {
kbd_write(s->keys1, f1, 1, s->vkbd);
+ uinput_kbd_write(s->keys1, f1, 1, s->ukbd);
memset(s->keys1, 0, bitstr_size(xsize));
}
return (0);
}
+/*
+ * Translate given keymap and write keyscodes
+ */
+void
+uinput_kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd)
+{
+ int32_t i;
+
+ if (fd >= 0) {
+ for (i = fb; i < xsize; i++) {
+ if (bit_test(m, i))
+ uinput_rep_key(fd, i, make);
+ }
+ }
+}
+
/*
* Translate given keymap and write keyscodes
*/
@@ -518,6 +541,7 @@
hid_device_p hid_device;
hid_data_t d;
hid_item_t h;
+ uint8_t leds_mask = 0;
assert(s != NULL);
assert(len == sizeof(vkbd_status_t));
@@ -551,16 +575,19 @@
case 0x01: /* Num Lock LED */
if (st.leds & LED_NUM)
hid_set_data(&data[1], &h, 1);
+ leds_mask |= LED_NUM;
break;
case 0x02: /* Caps Lock LED */
if (st.leds & LED_CAP)
hid_set_data(&data[1], &h, 1);
+ leds_mask |= LED_CAP;
break;
case 0x03: /* Scroll Lock LED */
if (st.leds & LED_SCR)
hid_set_data(&data[1], &h, 1);
+ leds_mask |= LED_SCR;
break;
/* XXX add other LEDs ? */
@@ -577,6 +604,9 @@
if (found)
write(s->intr, data, (report_id != NO_REPORT_ID) ? 3 : 2);
+ if (found && s->srv->uinput && hid_device->keyboard)
+ uinput_rep_leds(s->ukbd, st.leds, leds_mask);
+
return (0);
}
Index: usr.sbin/bluetooth/bthidd/lexer.l
===================================================================
--- usr.sbin/bluetooth/bthidd/lexer.l
+++ usr.sbin/bluetooth/bthidd/lexer.l
@@ -54,6 +54,7 @@
device_word device
bdaddr_word bdaddr
+name_word name
vendor_id_word vendor_id
product_id_word product_id
version_word version
@@ -69,6 +70,7 @@
bdaddrstring {hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}
hexbytestring 0x{hexbyte}
hexwordstring 0x{hexword}
+string \".+\"
%%
@@ -83,6 +85,7 @@
{device_word} return (T_DEVICE);
{bdaddr_word} return (T_BDADDR);
+{name_word} return (T_NAME);
{vendor_id_word} return (T_VENDOR_ID);
{product_id_word} return (T_PRODUCT_ID);
{version_word} return (T_VERSION);
@@ -116,6 +119,12 @@
return (*ep == '\0'? T_HEXWORD : T_ERROR);
}
+{string} {
+ yytext[strlen(yytext) - 1] = 0;
+ yylval.string = &yytext[1];
+ return (T_STRING);
+ }
+
. return (T_ERROR);
%%
Index: usr.sbin/bluetooth/bthidd/parser.y
===================================================================
--- usr.sbin/bluetooth/bthidd/parser.y
+++ usr.sbin/bluetooth/bthidd/parser.y
@@ -61,6 +61,8 @@
#define EOL "\n"
#endif /* ndef BTHIDCONTROL */
+#define NAMELESS_DEVICE "No Name"
+
#include "bthid_config.h"
int yylex (void);
@@ -83,11 +85,14 @@
%union {
bdaddr_t bdaddr;
int32_t num;
+ char *string;
}
%token <bdaddr> T_BDADDRSTRING
%token <num> T_HEXBYTE
%token <num> T_HEXWORD
+%token <string> T_STRING
+%token T_NAME
%token T_DEVICE T_BDADDR T_VENDOR_ID T_PRODUCT_ID T_VERSION T_CONTROL_PSM
%token T_INTERRUPT_PSM T_RECONNECT_INITIATE T_BATTERY_POWER
%token T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR
@@ -126,6 +131,7 @@
;
option: bdaddr
+ | name
| vendor_id
| product_id
| version
@@ -144,6 +150,24 @@
}
;
+name: T_NAME T_STRING
+ {
+ if (hid_device->name != NULL) {
+ free(hid_device->name);
+ hid_device->name = NULL;
+ }
+
+ if (strcmp($2, NAMELESS_DEVICE)) {
+ hid_device->name = strdup($2);
+ if (hid_device->name == NULL) {
+ SYSLOG(LOGCRIT, "Could not allocate new " \
+ "device name" EOL);
+ YYABORT;
+ }
+ }
+ }
+ ;
+
vendor_id: T_VENDOR_ID T_HEXWORD
{
hid_device->vendor_id = $2;
@@ -330,6 +354,7 @@
fprintf(f,
"device {\n" \
" bdaddr %s;\n" \
+" name \"%s\";\n" \
" vendor_id 0x%04x;\n" \
" product_id 0x%04x;\n" \
" version 0x%04x;\n" \
@@ -340,6 +365,7 @@
" normally_connectable %s;\n" \
" hid_descriptor {",
bt_ntoa(&d->bdaddr, NULL),
+ (d->name != NULL)? d->name : NAMELESS_DEVICE,
d->vendor_id, d->product_id, d->version,
d->control_psm, d->interrupt_psm,
d->reconnect_initiate? "true" : "false",
@@ -365,7 +391,7 @@
{
hid_data_t hd;
hid_item_t hi;
- int32_t page;
+ int32_t page, mdepth;
if (get_hid_device(&d->bdaddr) != NULL) {
SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL,
@@ -388,11 +414,23 @@
return (0);
}
+ mdepth = 0;
+
/* XXX somehow need to make sure descriptor is valid */
for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) {
switch (hi.kind) {
case hid_collection:
+ if (mdepth != 0)
+ mdepth++;
+ else if (hi.collection == 1 &&
+ hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
+ mdepth++;
+ break;
case hid_endcollection:
+ if (mdepth != 0)
+ mdepth--;
+ break;
case hid_output:
case hid_feature:
break;
@@ -402,6 +440,28 @@
page = HID_PAGE(hi.usage);
if (page == HUP_KEYBOARD)
d->keyboard = 1;
+ if (page == HUP_CONSUMER &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == 0)
+ d->has_cons = 1;
+ /* Check if the device may send relative motion events */
+ if (mdepth == 0)
+ break;
+ if (hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ d->mouse = 1;
+ if (hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ d->mouse = 1;
+ if (hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ d->has_wheel = 1;
+ if (hi.usage ==
+ HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ d->has_hwheel = 1;
break;
}
}
@@ -417,6 +477,7 @@
if (d->desc != NULL)
hid_dispose_report_desc(d->desc);
+ free(d->name);
memset(d, 0, sizeof(*d));
free(d);
}
Index: usr.sbin/bluetooth/bthidd/server.c
===================================================================
--- usr.sbin/bluetooth/bthidd/server.c
+++ usr.sbin/bluetooth/bthidd/server.c
@@ -35,6 +35,7 @@
#include <assert.h>
#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
+#include <dev/evdev/input.h>
#include <dev/vkbd/vkbd_var.h>
#include <errno.h>
#include <fcntl.h>
@@ -46,6 +47,7 @@
#include <usbhid.h>
#include "bthid_config.h"
#include "bthidd.h"
+#include "btuinput.h"
#include "kbd.h"
#undef max
@@ -280,19 +282,12 @@
(fd == srv->ctrl)? "control" : "interrupt",
bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
- /* Register session's vkbd descriptor (if needed) for read */
- if (s->state == OPEN && d->keyboard) {
- assert(s->vkbd != -1);
-
- FD_SET(s->vkbd, &srv->rfdset);
- if (s->vkbd > srv->maxfd)
- srv->maxfd = s->vkbd;
+ /* Create virtual kbd/mouse after both channels are established */
+ if (s->state == OPEN && session_run(s) < 0) {
+ session_close(s);
+ return (-1);
}
- /* Pass device for probing after both channels are established */
- if (s->state == OPEN)
- hid_initialise(s);
-
return (0);
}
@@ -307,9 +302,10 @@
int32_t len, to_read;
int32_t (*cb)(bthid_session_p, uint8_t *, int32_t);
union {
- uint8_t b[1024];
- vkbd_status_t s;
- } data;
+ uint8_t b[1024];
+ vkbd_status_t s;
+ struct input_event ie;
+ } data;
if (s == NULL)
return (0); /* can happen on device disconnect */
@@ -321,6 +317,9 @@
} else if (fd == s->intr) {
cb = hid_interrupt;
to_read = sizeof(data.b);
+ } else if (fd == s->ukbd) {
+ cb = uinput_kbd_status_changed;
+ to_read = sizeof(data.ie);
} else {
assert(fd == s->vkbd);
Index: usr.sbin/bluetooth/bthidd/session.c
===================================================================
--- usr.sbin/bluetooth/bthidd/session.c
+++ usr.sbin/bluetooth/bthidd/session.c
@@ -45,6 +45,7 @@
#include <usbhid.h>
#include "bthid_config.h"
#include "bthidd.h"
+#include "btuinput.h"
#include "kbd.h"
/*
@@ -66,22 +67,12 @@
memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr));
s->ctrl = -1;
s->intr = -1;
+ s->vkbd = -1;
s->ctx = NULL;
-
- if (d->keyboard) {
- /* Open /dev/vkbdctl */
- s->vkbd = open("/dev/vkbdctl", O_RDWR);
- if (s->vkbd < 0) {
- syslog(LOG_ERR, "Could not open /dev/vkbdctl " \
- "for %s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
- strerror(errno), errno);
- free(s);
- return (NULL);
- }
- } else
- s->vkbd = -1;
-
s->state = CLOSED;
+ s->ukbd = -1;
+ s->umouse = -1;
+ s->obutt = 0;
s->keys1 = bit_alloc(kbd_maxkey());
if (s->keys1 == NULL) {
@@ -101,6 +92,64 @@
return (s);
}
+/*
+ * Initialize virtual keyboard and mouse after both channels are established
+ */
+
+int32_t
+session_run(bthid_session_p s)
+{
+ hid_device_p d = get_hid_device(&s->bdaddr);
+ struct sockaddr_l2cap local;
+ socklen_t len;
+
+ if (d->keyboard) {
+ /* Open /dev/vkbdctl */
+ s->vkbd = open("/dev/vkbdctl", O_RDWR);
+ if (s->vkbd < 0) {
+ syslog(LOG_ERR, "Could not open /dev/vkbdctl " \
+ "for %s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
+ strerror(errno), errno);
+ return (-1);
+ }
+ /* Register session's vkbd descriptor (if needed) for read */
+ FD_SET(s->vkbd, &s->srv->rfdset);
+ if (s->vkbd > s->srv->maxfd)
+ s->srv->maxfd = s->vkbd;
+ }
+
+ /* Pass device for probing */
+ hid_initialise(s);
+
+ /* Take local bdaddr */
+ len = sizeof(local);
+ getsockname(s->ctrl, (struct sockaddr *) &local, &len);
+
+ if (d->mouse && s->srv->uinput) {
+ s->umouse = uinput_open_mouse(d, &local.l2cap_bdaddr);
+ if (s->umouse < 0) {
+ syslog(LOG_ERR, "Could not open /dev/uinput " \
+ "for %s. %s (%d)", bt_ntoa(&s->bdaddr,
+ NULL), strerror(errno), errno);
+ return (-1);
+ }
+ }
+ if (d->keyboard && s->srv->uinput) {
+ s->ukbd = uinput_open_keyboard(d, &local.l2cap_bdaddr);
+ if (s->ukbd < 0) {
+ syslog(LOG_ERR, "Could not open /dev/uinput " \
+ "for %s. %s (%d)", bt_ntoa(&s->bdaddr,
+ NULL), strerror(errno), errno);
+ return (-1);
+ }
+ /* Register session's ukbd descriptor (if needed) for read */
+ FD_SET(s->ukbd, &s->srv->rfdset);
+ if (s->ukbd > s->srv->maxfd)
+ s->srv->maxfd = s->ukbd;
+ }
+ return (0);
+}
+
/*
* Lookup session by bdaddr
*/
@@ -133,7 +182,8 @@
assert(fd >= 0);
LIST_FOREACH(s, &srv->sessions, next)
- if (s->ctrl == fd || s->intr == fd || s->vkbd == fd)
+ if (s->ctrl == fd || s->intr == fd ||
+ s->vkbd == fd || s->ukbd == fd)
break;
return (s);
@@ -177,6 +227,17 @@
s->srv->maxfd --;
}
+ if (s->umouse != -1)
+ close(s->umouse);
+
+ if (s->ukbd != -1) {
+ FD_CLR(s->ukbd, &s->srv->rfdset);
+ close(s->ukbd);
+
+ if (s->srv->maxfd == s->ukbd)
+ s->srv->maxfd --;
+ }
+
free(s->ctx);
free(s->keys1);
free(s->keys2);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 10, 6:41 PM (9 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28318527
Default Alt Text
D13456.1775846517.diff (45 KB)
Attached To
Mode
D13456: bthidd: Add evdev protocol support
Attached
Detach File
Event Timeline
Log In to Comment