summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authoremax <emax@FreeBSD.org>2006-09-07 21:47:49 +0000
committeremax <emax@FreeBSD.org>2006-09-07 21:47:49 +0000
commit0a0c0e69a8b3191ef395c191f4667746e8f79f90 (patch)
tree2d993bc06bdf62dbb75a647125df678ab96cd3be /usr.sbin
parentd04edc5790dab1504a82e507350c255aac246f8b (diff)
downloadFreeBSD-src-0a0c0e69a8b3191ef395c191f4667746e8f79f90.zip
FreeBSD-src-0a0c0e69a8b3191ef395c191f4667746e8f79f90.tar.gz
Update bthidd(8) code and hook it up to the build.
bthidd(8) now was integrated with vkbd(4) and supports multiple keyboards via vkbd(4)/kbdmux(4). The code was tested with Apple Bluetooth keyboard and SE k700i cell phone (remote control feature). MFC after: 1 month
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bluetooth/Makefile2
-rw-r--r--usr.sbin/bluetooth/bthidd/Makefile8
-rw-r--r--usr.sbin/bluetooth/bthidd/bthid_config.h21
-rw-r--r--usr.sbin/bluetooth/bthidd/bthidd.8128
-rw-r--r--usr.sbin/bluetooth/bthidd/bthidd.c90
-rw-r--r--usr.sbin/bluetooth/bthidd/bthidd.h46
-rw-r--r--usr.sbin/bluetooth/bthidd/client.c53
-rw-r--r--usr.sbin/bluetooth/bthidd/hid.c85
-rw-r--r--usr.sbin/bluetooth/bthidd/kbd.c279
-rw-r--r--usr.sbin/bluetooth/bthidd/kbd.h16
-rw-r--r--usr.sbin/bluetooth/bthidd/lexer.l12
-rw-r--r--usr.sbin/bluetooth/bthidd/parser.y132
-rw-r--r--usr.sbin/bluetooth/bthidd/server.c146
-rw-r--r--usr.sbin/bluetooth/bthidd/session.c86
14 files changed, 642 insertions, 462 deletions
diff --git a/usr.sbin/bluetooth/Makefile b/usr.sbin/bluetooth/Makefile
index 23c03f7..ed6f83a 100644
--- a/usr.sbin/bluetooth/Makefile
+++ b/usr.sbin/bluetooth/Makefile
@@ -4,6 +4,8 @@
SUBDIR= \
bcmfw \
bt3cfw \
+ bthidcontrol \
+ bthidd \
hccontrol \
hcsecd \
hcseriald \
diff --git a/usr.sbin/bluetooth/bthidd/Makefile b/usr.sbin/bluetooth/bthidd/Makefile
index a65bd6e..7ceba10 100644
--- a/usr.sbin/bluetooth/bthidd/Makefile
+++ b/usr.sbin/bluetooth/bthidd/Makefile
@@ -1,14 +1,14 @@
-# $Id: Makefile,v 1.3 2004/08/17 21:49:46 max Exp $
+# $Id: Makefile,v 1.6 2006/09/07 21:36:55 max Exp $
# $FreeBSD$
PROG= bthidd
-#MAN= bthidd.8 bthidd.conf.5
-NO_MAN=
+MAN= bthidd.8
+# bthidd.conf.5
SRCS= bthidd.c client.c hid.c kbd.c lexer.l parser.y server.c \
session.c
CFLAGS+= -I${.CURDIR}
-WARNS?= 2
+WARNS?= 6
DEBUG_FLAGS= -g
DPADD= ${LIBBLUETOOTH} ${LIBSDP}
diff --git a/usr.sbin/bluetooth/bthidd/bthid_config.h b/usr.sbin/bluetooth/bthidd/bthid_config.h
index 6be7c7e..71cb425 100644
--- a/usr.sbin/bluetooth/bthidd/bthid_config.h
+++ b/usr.sbin/bluetooth/bthidd/bthid_config.h
@@ -1,7 +1,9 @@
/*
* bthid_config.h
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: bthid_config.h,v 1.3 2004/02/17 22:05:02 max Exp $
+ * $Id: bthid_config.h,v 1.4 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
@@ -44,24 +46,25 @@ struct hid_device
unsigned reconnect_initiate : 1;
unsigned battery_power : 1;
unsigned normally_connectable : 1;
- unsigned reserved : 12;
+ unsigned keyboard : 1;
+ unsigned reserved : 11;
report_desc_t desc; /* HID report descriptor */
LIST_ENTRY(hid_device) next; /* link to the next */
};
typedef struct hid_device hid_device_t;
typedef struct hid_device * hid_device_p;
-extern char *config_file;
-extern char *hids_file;
+extern char const *config_file;
+extern char const *hids_file;
-int read_config_file (void);
+int32_t read_config_file (void);
void clean_config (void);
hid_device_p get_hid_device (bdaddr_p bdaddr);
hid_device_p get_next_hid_device (hid_device_p d);
void print_hid_device (hid_device_p hid_device, FILE *f);
-int read_hids_file (void);
-int write_hids_file (void);
+int32_t read_hids_file (void);
+int32_t write_hids_file (void);
#endif /* ndef _BTHID_CONFIG_H_ */
diff --git a/usr.sbin/bluetooth/bthidd/bthidd.8 b/usr.sbin/bluetooth/bthidd/bthidd.8
new file mode 100644
index 0000000..d89f03d
--- /dev/null
+++ b/usr.sbin/bluetooth/bthidd/bthidd.8
@@ -0,0 +1,128 @@
+.\" Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bthidd.8,v 1.1 2006/09/07 21:36:55 max Exp $
+.\" $FreeBSD$
+.\"
+.Dd September 7, 2006
+.Dt BTHIDD 8
+.Os
+.Sh NAME
+.Nm bthidd
+.Nd Bluetooth HID daemon
+.Sh SYNOPSIS
+.Nm
+.Fl h
+.Nm
+.Op Fl a Ar BD_ADDR
+.Op Fl c Ar file
+.Op Fl H Ar file
+.Op Fl p Ar file
+.Op Fl t Ar val
+.Sh DESCRIPTION
+The
+.Nm
+daemon handles remote Bluetooth HID devices.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar BD_ADDR
+Specify the local address to listen on.
+By default, server will listen on
+.Dv ANY
+address.
+The address can be specified as BD_ADDR or name.
+If name was specified then the
+.Nm
+daemon will attempt to resolve the name via
+.Xr bt_gethostbyname 3 .
+.It Fl c Ar file
+Specify path to the configuration file.
+The default path is
+.Pa /etc/bluetooth/bthidd.conf .
+.It Fl d
+Do not detach from the controlling terminal, i.e., run in foreground.
+.It Fl H Ar file
+Specify path to the known HIDs file.
+The default path is
+.Pa /var/db/bthidd.hids .
+.It Fl h
+Display usage message and exit.
+.It Fl p Ar file
+Specify path to the PID file.
+The default path is
+.Pa /var/run/bthidd.pid .
+.It Fl t Ar val
+Specify client rescan interval in seconds.
+The
+.Nm
+daemon will periodically scan for newly configured Bluetooth HID devices or
+disconnected
+.Dq passive
+Bluetooth HID devices and will attempt to establish outgoing connection.
+Default rescan interval is 10 seconds.
+.El
+.Sh CAVEAT
+Any Bluetooth HID device that has
+.Dv HUP_KEYBOARD
+or
+.Dv HUP_CONSUMER
+entries in its descriptor is considered as
+.Dq keyboard .
+For each
+.Dq keyboard
+Bluetooth HID device,
+the
+.Nm
+daemon will use separate instance of
+.Xr vkbd 4
+virtual keyboard.
+Therefore
+.Xr kbdmux 4
+driver must be used to properly multiplex input from multiple keyboards.
+.Sh KNOWN LIMITATIONS
+The
+.Nm
+daemon currently does not handle key auto repeat and double click mouse events.
+Those events work under
+.Xr X 7
+just fine,
+but not in text console.
+.Pp
+This man page needs more work.
+Also need a man page documenting format of the
+.Pa /etc/bluetooth/bthidd.conf
+configuraion file.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/bthidd.conf" -compact
+.It Pa /etc/bluetooth/bthidd.conf
+.It Pa /var/db/bthidd.hids
+.It Pa /var/run/bthidd.pid
+.El
+.Sh SEE ALSO
+.Xr kbdmux 4 ,
+.Xr vkbd 4 ,
+.Xr bthidcontrol 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/bthidd/bthidd.c b/usr.sbin/bluetooth/bthidd/bthidd.c
index a0f1463..b93fd3d 100644
--- a/usr.sbin/bluetooth/bthidd/bthidd.c
+++ b/usr.sbin/bluetooth/bthidd/bthidd.c
@@ -1,7 +1,9 @@
/*
* bthidd.c
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: bthidd.c,v 1.7 2004/11/17 21:59:42 max Exp $
+ * $Id: bthidd.c,v 1.8 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
@@ -42,42 +44,40 @@
#include <syslog.h>
#include <unistd.h>
#include <usbhid.h>
-#include "bthidd.h"
#include "bthid_config.h"
+#include "bthidd.h"
-static int write_pid_file (char const *file);
-static int remove_pid_file (char const *file);
-static int elapsed (int tval);
-static void sighandler (int s);
-static void sighup (int s);
+static int32_t write_pid_file (char const *file);
+static int32_t remove_pid_file (char const *file);
+static int32_t elapsed (int32_t tval);
+static void sighandler (int32_t s);
static void usage (void);
/*
* bthidd
*/
-static int done = 0; /* are we done? */
-static int reload = 0; /* reload config file */
+static int32_t done = 0; /* are we done? */
-int
-main(int argc, char *argv[])
+int32_t
+main(int32_t argc, char *argv[])
{
struct bthid_server srv;
struct sigaction sa;
- char const *pid_file = BTHIDD_PIDFILE, *ep = NULL;
- int opt, detach, tval;
+ char const *pid_file = BTHIDD_PIDFILE;
+ char *ep;
+ int32_t opt, detach, tval;
memset(&srv, 0, sizeof(srv));
- memcpy(&srv.bdaddr, NG_HCI_BDADDR_ANY, sizeof(srv.bdaddr));
- srv.windex = -1;
+ memset(&srv.bdaddr, 0, sizeof(srv.bdaddr));
detach = 1;
tval = 10; /* sec */
- while ((opt = getopt(argc, argv, "a:c:dH:hp:s:t:")) != -1) {
+ while ((opt = getopt(argc, argv, "a:c:dH:hp:t:")) != -1) {
switch (opt) {
case 'a': /* BDADDR */
if (!bt_aton(optarg, &srv.bdaddr)) {
- struct hostent *he = NULL;
+ struct hostent *he;
if ((he = bt_gethostbyname(optarg)) == NULL)
errx(1, "%s: %s", optarg, hstrerror(h_errno));
@@ -102,22 +102,12 @@ main(int argc, char *argv[])
pid_file = optarg;
break;
- case 's': /* switch script */
- srv.script = optarg;
- break;
-
case 't': /* rescan interval */
tval = strtol(optarg, (char **) &ep, 10);
if (*ep != '\0' || tval <= 0)
usage();
break;
- case 'u': /* wired keyboard index */
- srv.windex = strtol(optarg, (char **) &ep, 10);
- if (*ep != '\0' || srv.windex < 0)
- usage();
- break;
-
case 'h':
default:
usage();
@@ -139,19 +129,13 @@ main(int argc, char *argv[])
sa.sa_handler = sighandler;
if (sigaction(SIGTERM, &sa, NULL) < 0 ||
+ sigaction(SIGHUP, &sa, NULL) < 0 ||
sigaction(SIGINT, &sa, NULL) < 0) {
syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
strerror(errno), errno);
exit(1);
}
- sa.sa_handler = sighup;
- if (sigaction(SIGHUP, &sa, NULL) < 0) {
- syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
- strerror(errno), errno);
- exit(1);
- }
-
sa.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &sa, NULL) < 0) {
syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
@@ -177,15 +161,6 @@ main(int argc, char *argv[])
if (server_do(&srv) < 0)
break;
-
- if (reload) {
- if (write_hids_file() < 0 ||
- read_config_file() < 0 ||
- read_hids_file() < 0)
- break;
-
- reload = 0;
- }
}
server_shutdown(&srv);
@@ -200,10 +175,10 @@ main(int argc, char *argv[])
* Write pid file
*/
-static int
+static int32_t
write_pid_file(char const *file)
{
- FILE *pid = NULL;
+ FILE *pid;
assert(file != NULL);
@@ -223,7 +198,7 @@ write_pid_file(char const *file)
* Remote pid file
*/
-static int
+static int32_t
remove_pid_file(char const *file)
{
assert(file != NULL);
@@ -241,10 +216,10 @@ remove_pid_file(char const *file)
* Returns true if desired time interval has elapsed
*/
-static int
-elapsed(int tval)
+static int32_t
+elapsed(int32_t tval)
{
- static struct timeval last = { 0, };
+ static struct timeval last = { 0, 0 };
struct timeval now;
gettimeofday(&now, NULL);
@@ -258,23 +233,16 @@ elapsed(int tval)
}
/*
- * Signal handlers
+ * Signal handler
*/
static void
-sighandler(int s)
+sighandler(int32_t s)
{
syslog(LOG_NOTICE, "Got signal %d, total number of signals %d",
s, ++ done);
}
-static void
-sighup(int s)
-{
- syslog(LOG_NOTICE, "Got SIGHUP: reload config");
- reload = 1;
-}
-
/*
* Display usage and exit
*/
@@ -291,9 +259,7 @@ usage(void)
" -H file specify known HIDs file name\n" \
" -h display this message\n" \
" -p file specify PID file name\n" \
-" -s script specify keyboard switching script\n" \
" -t tval specify client rescan interval (sec)\n" \
-" -u unit specify wired keyboard unit\n" \
"", BTHIDD_IDENT);
exit(255);
}
diff --git a/usr.sbin/bluetooth/bthidd/bthidd.h b/usr.sbin/bluetooth/bthidd/bthidd.h
index d4ebbc6..3485fc3 100644
--- a/usr.sbin/bluetooth/bthidd/bthidd.h
+++ b/usr.sbin/bluetooth/bthidd/bthidd.h
@@ -1,7 +1,9 @@
/*
* bthidd.h
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: bthidd.h,v 1.6 2004/11/17 21:59:42 max Exp $
+ * $Id: bthidd.h,v 1.7 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
@@ -40,14 +42,10 @@ struct bthid_session;
struct bthid_server
{
bdaddr_t bdaddr; /* local bdaddr */
- int cons; /* /dev/consolectl */
- int vkbd; /* /dev/vkbdctl */
- char const *script; /* keyboard switching script */
- int windex; /* wired keyboard index */
- bitstr_t *keys; /* pressed keys map */
- int ctrl; /* control channel (listen) */
- int intr; /* intr. channel (listen) */
- int maxfd; /* max fd in sets */
+ int32_t cons; /* /dev/consolectl */
+ int32_t ctrl; /* control channel (listen) */
+ int32_t intr; /* intr. channel (listen) */
+ int32_t maxfd; /* max fd in sets */
fd_set rfdset; /* read descriptor set */
fd_set wfdset; /* write descriptor set */
LIST_HEAD(, bthid_session) sessions;
@@ -59,35 +57,37 @@ typedef struct bthid_server * bthid_server_p;
struct bthid_session
{
bthid_server_p srv; /* pointer back to server */
- int ctrl; /* control channel */
- int intr; /* interrupt channel */
+ int32_t ctrl; /* control channel */
+ int32_t intr; /* interrupt channel */
+ int32_t vkbd; /* virual keyboard */
bdaddr_t bdaddr;/* remote bdaddr */
- short state; /* session state */
+ uint16_t state; /* session state */
#define CLOSED 0
#define W4CTRL 1
#define W4INTR 2
#define OPEN 3
- bitstr_t *keys; /* pressed keys map */
+ bitstr_t *keys1; /* keys map (new) */
+ bitstr_t *keys2; /* keys map (old) */
LIST_ENTRY(bthid_session) next; /* link to next */
};
typedef struct bthid_session bthid_session_t;
typedef struct bthid_session * bthid_session_p;
-int server_init (bthid_server_p srv);
+int32_t server_init (bthid_server_p srv);
void server_shutdown (bthid_server_p srv);
-int server_do (bthid_server_p srv);
+int32_t server_do (bthid_server_p srv);
-int client_rescan (bthid_server_p srv);
-int client_connect (bthid_server_p srv, int fd);
+int32_t client_rescan (bthid_server_p srv);
+int32_t client_connect (bthid_server_p srv, int fd);
-bthid_session_p session_open (bthid_server_p srv, bdaddr_p bdaddr);
+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, int fd);
+bthid_session_p session_by_fd (bthid_server_p srv, int32_t fd);
void session_close (bthid_session_p s);
-int hid_control (bthid_session_p s, char *data, int len);
-int hid_interrupt (bthid_session_p s, char *data, int len);
+int32_t hid_control (bthid_session_p s, uint8_t *data, int32_t len);
+int32_t hid_interrupt (bthid_session_p s, uint8_t *data, int32_t len);
#endif /* ndef _BTHIDD_H_ */
diff --git a/usr.sbin/bluetooth/bthidd/client.c b/usr.sbin/bluetooth/bthidd/client.c
index 252248d..27508ce 100644
--- a/usr.sbin/bluetooth/bthidd/client.c
+++ b/usr.sbin/bluetooth/bthidd/client.c
@@ -1,7 +1,9 @@
/*
* client.c
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: client.c,v 1.6 2004/02/26 21:57:55 max Exp $
+ * $Id: client.c,v 1.7 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
@@ -40,10 +42,10 @@
#include <syslog.h>
#include <unistd.h>
#include <usbhid.h>
-#include "bthidd.h"
#include "bthid_config.h"
+#include "bthidd.h"
-static int client_socket(bdaddr_p bdaddr, int psm);
+static int32_t client_socket(bdaddr_p bdaddr, int32_t psm);
/*
* Get next config entry and create outbound connection (if required)
@@ -53,13 +55,13 @@ static int client_socket(bdaddr_p bdaddr, int psm);
* Create_Connection command is still pending. Weird...
*/
-static int connect_in_progress = 0;
+static int32_t connect_in_progress = 0;
-int
+int32_t
client_rescan(bthid_server_p srv)
{
- static hid_device_p d = NULL;
- bthid_session_p s = NULL;
+ static hid_device_p d;
+ bthid_session_p s;
assert(srv != NULL);
@@ -82,9 +84,9 @@ client_rescan(bthid_server_p srv)
"(new_device=%d, reconnect_initiate=%d)",
bt_ntoa(&d->bdaddr, NULL), d->new_device, d->reconnect_initiate);
- if ((s = session_open(srv, &d->bdaddr)) == NULL) {
- syslog(LOG_CRIT, "Could not open outbound session for %s. " \
- "Not enough memory", bt_ntoa(&d->bdaddr, NULL));
+ if ((s = session_open(srv, d)) == NULL) {
+ syslog(LOG_CRIT, "Could not create outbound session for %s",
+ bt_ntoa(&d->bdaddr, NULL));
return (-1);
}
@@ -112,12 +114,12 @@ client_rescan(bthid_server_p srv)
* Process connect on the socket
*/
-int
-client_connect(bthid_server_p srv, int fd)
+int32_t
+client_connect(bthid_server_p srv, int32_t fd)
{
- bthid_session_p s = NULL;
- hid_device_p d = NULL;
- int error, len;
+ bthid_session_p s;
+ hid_device_p d;
+ int32_t error, len;
assert(srv != NULL);
assert(fd >= 0);
@@ -181,6 +183,15 @@ client_connect(bthid_server_p srv, int fd)
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;
+ }
break;
default:
@@ -200,10 +211,10 @@ client_connect(bthid_server_p srv, int fd)
*/
static int
-client_socket(bdaddr_p bdaddr, int psm)
+client_socket(bdaddr_p bdaddr, int32_t psm)
{
struct sockaddr_l2cap l2addr;
- int s, m;
+ int32_t s, m;
s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
if (s < 0)
@@ -222,7 +233,7 @@ client_socket(bdaddr_p bdaddr, int psm)
l2addr.l2cap_len = sizeof(l2addr);
l2addr.l2cap_family = AF_BLUETOOTH;
- memcpy(&l2addr.l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2addr.l2cap_bdaddr));
+ memset(&l2addr.l2cap_bdaddr, 0, sizeof(l2addr.l2cap_bdaddr));
l2addr.l2cap_psm = 0;
if (bind(s, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
@@ -231,7 +242,7 @@ client_socket(bdaddr_p bdaddr, int psm)
}
memcpy(&l2addr.l2cap_bdaddr, bdaddr, sizeof(l2addr.l2cap_bdaddr));
- l2addr.l2cap_psm = htole16(psm);
+ l2addr.l2cap_psm = psm;
if (connect(s, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0 &&
errno != EINPROGRESS) {
diff --git a/usr.sbin/bluetooth/bthidd/hid.c b/usr.sbin/bluetooth/bthidd/hid.c
index c350110..b9f9839 100644
--- a/usr.sbin/bluetooth/bthidd/hid.c
+++ b/usr.sbin/bluetooth/bthidd/hid.c
@@ -1,7 +1,9 @@
/*
* hid.c
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: hid.c,v 1.4 2004/11/17 21:59:42 max Exp $
+ * $Id: hid.c,v 1.5 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
@@ -34,16 +36,16 @@
#include <sys/queue.h>
#include <assert.h>
#include <bluetooth.h>
-#include <errno.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
+#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <usbhid.h>
-#include "bthidd.h"
#include "bthid_config.h"
+#include "bthidd.h"
#include "kbd.h"
#undef min
@@ -52,15 +54,12 @@
#undef ASIZE
#define ASIZE(a) (sizeof(a)/sizeof(a[0]))
-#undef HID_BUT
-#define HID_BUT(i) ((i) < 3 ? (((i) ^ 3) % 3) : (i))
-
/*
* Process data from control channel
*/
-int
-hid_control(bthid_session_p s, char *data, int len)
+int32_t
+hid_control(bthid_session_p s, uint8_t *data, int32_t len)
{
assert(s != NULL);
assert(data != NULL);
@@ -123,13 +122,13 @@ hid_control(bthid_session_p s, char *data, int len)
* Process data from the interrupt channel
*/
-int
-hid_interrupt(bthid_session_p s, char *data, int len)
+int32_t
+hid_interrupt(bthid_session_p s, uint8_t *data, int32_t len)
{
- hid_device_p hid_device = NULL;
+ hid_device_p hid_device;
hid_data_t d;
hid_item_t h;
- int report_id, usage, page, val,
+ int32_t report_id, usage, page, val,
mouse_x, mouse_y, mouse_z, mouse_butt,
mevents, kevents;
@@ -143,7 +142,7 @@ hid_interrupt(bthid_session_p s, char *data, int len)
return (-1);
}
- if ((unsigned char) data[0] != 0xa1) {
+ if (data[0] != 0xa1) {
syslog(LOG_ERR, "Got unexpected message 0x%x on " \
"Interrupt channel from %s",
data[0], bt_ntoa(&s->bdaddr, NULL));
@@ -198,10 +197,10 @@ hid_interrupt(bthid_session_p s, char *data, int len)
if (h.flags & HIO_VARIABLE) {
if (val && usage < kbd_maxkey())
- bit_set(s->srv->keys, usage);
+ bit_set(s->keys1, usage);
} else {
if (val && val < kbd_maxkey())
- bit_set(s->srv->keys, val);
+ bit_set(s->keys1, val);
data ++;
len --;
@@ -210,7 +209,7 @@ hid_interrupt(bthid_session_p s, char *data, int len)
while (len > 0) {
val = hid_get_data(data, &h);
if (val && val < kbd_maxkey())
- bit_set(s->srv->keys, val);
+ bit_set(s->keys1, val);
data ++;
len --;
@@ -219,8 +218,15 @@ hid_interrupt(bthid_session_p s, char *data, int len)
break;
case HUP_BUTTON:
- mouse_butt |= (val << HID_BUT(usage - 1));
- mevents ++;
+ if (usage != 0) {
+ if (usage == 2)
+ usage = 3;
+ else if (usage == 3)
+ usage = 2;
+
+ mouse_butt |= (val << (usage - 1));
+ mevents ++;
+ }
break;
case HUP_CONSUMER:
@@ -292,7 +298,7 @@ hid_interrupt(bthid_session_p s, char *data, int len)
val = 0x68;
break;
- case 0x227: /* WWW Refresh */
+ case 0227: /* WWW Refresh */
val = 0x67;
break;
@@ -307,9 +313,17 @@ hid_interrupt(bthid_session_p s, char *data, int len)
/* XXX FIXME - UGLY HACK */
if (val != 0) {
- int buf[4] = { 0xe0, val, 0xe0, val|0x80 };
-
- write(s->srv->vkbd, buf, sizeof(buf));
+ if (hid_device->keyboard) {
+ int32_t buf[4] = { 0xe0, val,
+ 0xe0, val|0x80 };
+
+ assert(s->vkbd != -1);
+ write(s->vkbd, buf, sizeof(buf));
+ } else
+ syslog(LOG_ERR, "Keyboard events " \
+ "received from non-keyboard " \
+ "device %s. Please report",
+ bt_ntoa(&s->bdaddr, NULL));
}
break;
@@ -343,14 +357,30 @@ hid_interrupt(bthid_session_p s, char *data, int len)
}
hid_end_parse(d);
- /* Feed keyboard events into kernel */
- if (kevents > 0)
- kbd_process_keys(s);
+ /*
+ * XXX FIXME Feed keyboard events into kernel.
+ * The code below works, bit host also needs to track
+ * and handle repeat.
+ *
+ * Key repeat currently works in X, but not in console.
+ */
+
+ if (kevents > 0) {
+ if (hid_device->keyboard) {
+ assert(s->vkbd != -1);
+ kbd_process_keys(s);
+ } else
+ syslog(LOG_ERR, "Keyboard events received from " \
+ "non-keyboard device %s. Please report",
+ bt_ntoa(&s->bdaddr, NULL));
+ }
/*
* XXX FIXME Feed mouse events into kernel.
* The code block below works, but it is not good enough.
* Need to track double-clicks etc.
+ *
+ * Double click currently works in X, but not in console.
*/
if (mevents > 0) {
@@ -370,4 +400,3 @@ hid_interrupt(bthid_session_p s, char *data, int len)
return (0);
}
-
diff --git a/usr.sbin/bluetooth/bthidd/kbd.c b/usr.sbin/bluetooth/bthidd/kbd.c
index 4db8288..cd400c1 100644
--- a/usr.sbin/bluetooth/bthidd/kbd.c
+++ b/usr.sbin/bluetooth/bthidd/kbd.c
@@ -1,7 +1,9 @@
/*
* kbd.c
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: kbd.c,v 1.2 2004/11/17 21:59:42 max Exp $
+ * $Id: kbd.c,v 1.4 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
@@ -36,6 +38,9 @@
#include <sys/wait.h>
#include <assert.h>
#include <bluetooth.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+#include <dev/vkbd/vkbd_var.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -45,11 +50,13 @@
#include <string.h>
#include <syslog.h>
#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
#include "bthidd.h"
#include "kbd.h"
-static void kbd_write(bitstr_t *m, int fb, int make, int fd);
-static int kbd_xlate(int code, int make, int *b, int const *eob);
+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);
/*
* HID code to PS/2 set 1 code translation table.
@@ -64,7 +71,7 @@ static int kbd_xlate(int code, int make, int *b, int const *eob);
#define NOBREAK (1 << 30)
#define CODEMASK (~(E0PREFIX|NOBREAK))
-static int const x[] =
+static int32_t const x[] =
{
/*==================================================*/
/* Name HID code Make Break*/
@@ -308,13 +315,13 @@ static int const x[] =
/* Right GUI E7 */ E0PREFIX|0x5C /* E0 DC */
};
-#define xsize (sizeof(x)/sizeof(x[0]))
+#define xsize ((int32_t)(sizeof(x)/sizeof(x[0])))
/*
* Get a max HID keycode (aligned)
*/
-int
+int32_t
kbd_maxkey(void)
{
return (xsize);
@@ -324,164 +331,72 @@ kbd_maxkey(void)
* Process keys
*/
-int
+int32_t
kbd_process_keys(bthid_session_p s)
{
- bitstr_t r[bitstr_size(xsize)];
- int f0, f1, i;
+ bitstr_t diff[bitstr_size(xsize)];
+ int32_t f1, f2, i;
assert(s != NULL);
assert(s->srv != NULL);
- bit_ffs(s->srv->keys, xsize, &f0);
- bit_ffs(s->keys, xsize, &f1);
+ /* Check if the new keys have been pressed */
+ bit_ffs(s->keys1, xsize, &f1);
- if (f0 == -1) {
- /* all keys are released, no keys pressed */
- if (f1 != -1) {
- kbd_write(s->keys, f1, 0, s->srv->vkbd);
- memset(s->keys, 0, bitstr_size(xsize));
+ /* Check if old keys still pressed */
+ bit_ffs(s->keys2, xsize, &f2);
+
+ if (f1 == -1) {
+ /* no new key pressed */
+ if (f2 != -1) {
+ /* release old keys */
+ kbd_write(s->keys2, f2, 0, s->vkbd);
+ memset(s->keys2, 0, bitstr_size(xsize));
}
return (0);
}
- if (f1 == -1) {
- /* some keys got pressed, no keys released */
- if (f0 != -1) {
- memcpy(s->keys, s->srv->keys, bitstr_size(xsize));
- kbd_write(s->keys, f0, 1, s->srv->vkbd);
- memset(s->srv->keys, 0, bitstr_size(xsize));
- }
+ if (f2 == -1) {
+ /* no old keys, but new keys pressed */
+ assert(f1 != -1);
+
+ memcpy(s->keys2, s->keys1, bitstr_size(xsize));
+ kbd_write(s->keys1, f1, 1, s->vkbd);
+ memset(s->keys1, 0, bitstr_size(xsize));
return (0);
}
- /* some keys got pressed, some keys got released */
- memset(r, 0, bitstr_size(xsize));
+ /* new keys got pressed, old keys got released */
+ memset(diff, 0, bitstr_size(xsize));
- for (i = f1; i < xsize; i++) {
- if (bit_test(s->keys, i)) {
- if (!bit_test(s->srv->keys, i)) {
- bit_clear(s->keys, i);
- bit_set(r, i);
- } else
- bit_clear(s->srv->keys, i);
+ for (i = f2; i < xsize; i ++) {
+ if (bit_test(s->keys2, i)) {
+ if (!bit_test(s->keys1, i)) {
+ bit_clear(s->keys2, i);
+ bit_set(diff, i);
+ }
}
}
- for (i = f0; i < xsize; i++) {
- if (bit_test(s->srv->keys, i)) {
- if (!bit_test(s->keys, i))
- bit_set(s->keys, i);
+ for (i = f1; i < xsize; i++) {
+ if (bit_test(s->keys1, i)) {
+ if (!bit_test(s->keys2, i))
+ bit_set(s->keys2, i);
else
- bit_clear(s->srv->keys, i);
+ bit_clear(s->keys1, i);
}
}
- bit_ffs(r, xsize, &f0);
- bit_ffs(s->srv->keys, xsize, &f1);
-
- if (f0 > 0)
- kbd_write(r, f0, 0, s->srv->vkbd);
+ bit_ffs(diff, xsize, &f2);
+ if (f2 > 0)
+ kbd_write(diff, f2, 0, s->vkbd);
+ bit_ffs(s->keys1, xsize, &f1);
if (f1 > 0) {
- kbd_write(s->srv->keys, f1, 1, s->srv->vkbd);
- memset(s->srv->keys, 0, bitstr_size(xsize));
- }
-
- return (0);
-}
-
-/*
- * Get current keyboard index (fd version)
- */
-
-int
-kbd_get_index_fd(int fd)
-{
- keyboard_info_t info;
-
- return ((ioctl(fd, KDGKBINFO, &info) < 0)? -1 : info.kb_index);
-}
-
-/*
- * Get current keyboard index (device node version)
- */
-
-int
-kbd_get_index(char const *device)
-{
- int fd, index;
-
- fd = open(device, O_RDONLY);
- if (fd < 0)
- return (-1);
-
- index = kbd_get_index_fd(fd);
-
- close(fd);
-
- return (index);
-}
-
-/*
- * Switch keyboards. Execute external script to switch keyboards. The keyboard
- * index will be passed to the script in the first argument (argv[1]). We use
- * external script here to allow user to customize his/her wireless keyboard,
- * i.e. set mapping etc. In theory, all parameters could be picked up from the
- * rc.conf.
- */
-
-int
-kbd_switch(char const *script, int index)
-{
- pid_t pid;
- int status;
-
- if (script == NULL) {
- syslog(LOG_NOTICE, "Could not switch keyboards. " \
- "Switch script is not defined");
- return (-1);
- }
-
- if (access(script, X_OK) < 0) {
- syslog(LOG_ERR, "The %s is not executable. %s (%d)",
- script, strerror(errno), errno);
- return (-1);
- }
-
- pid = fork();
-
- if (pid == (pid_t) -1) {
- syslog(LOG_ERR, "Could not create process for %s. %s (%d)",
- script, strerror(errno), errno);
- return (-1);
- }
-
- if (pid == 0) {
- char arg[16];
- char *argv[3] = { (char *) script, arg, NULL };
-
- snprintf(arg, sizeof(arg), "%d", index);
- execv(script, argv);
-
- syslog(LOG_ERR, "Could not execute '%s %d'. %s (%d)",
- script, index, strerror(errno), errno);
-
- exit(1);
- }
-
- if (waitpid(pid, &status, 0) < 0) {
- syslog(LOG_ERR, "Could not waitpid for %s. %s (%d)",
- script, strerror(errno), errno);
- return (-1);
- }
-
- if (WIFEXITED(status) && WEXITSTATUS(status)) {
- syslog(LOG_ERR, "External command '%s %d' failed, exit code %d",
- script, index, WEXITSTATUS(status));
- return (-1);
+ kbd_write(s->keys1, f1, 1, s->vkbd);
+ memset(s->keys1, 0, bitstr_size(xsize));
}
return (0);
@@ -492,9 +407,9 @@ kbd_switch(char const *script, int index)
*/
static void
-kbd_write(bitstr_t *m, int fb, int make, int fd)
+kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd)
{
- int i, *b, *eob, n, buf[64];
+ int32_t i, *b, *eob, n, buf[64];
b = buf;
eob = b + sizeof(buf)/sizeof(buf[0]);
@@ -519,7 +434,6 @@ kbd_write(bitstr_t *m, int fb, int make, int fd)
write(fd, buf, (b - buf) * sizeof(buf[0]));
}
-
/*
* Translate HID code into PS/2 code and put codes into buffer b.
* Returns the number of codes put in b. Return -1 if buffer has not
@@ -536,10 +450,10 @@ do { \
(n) ++; \
} while (0)
-static int
-kbd_xlate(int code, int make, int *b, int const *eob)
+static int32_t
+kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob)
{
- int c, n;
+ int32_t c, n;
n = 0;
@@ -591,3 +505,76 @@ XXX FIXME
return (n);
}
+/*
+ * Process status change from vkbd(4)
+ */
+
+int32_t
+kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len)
+{
+ int32_t leds;
+ uint8_t hleds, report_id;
+ hid_device_p hid_device;
+ hid_data_t d;
+ hid_item_t h;
+
+ assert(s != NULL);
+ assert(len == sizeof(vkbd_status_t));
+
+ leds = ((vkbd_status_p) data)->leds;
+ hleds = 0;
+ report_id = NO_REPORT_ID;
+
+ hid_device = get_hid_device(&s->bdaddr);
+ assert(hid_device != NULL);
+
+ for (d = hid_start_parse(hid_device->desc, 1 << hid_output, -1);
+ hid_get_item(d, &h) > 0; ) {
+ if (HID_PAGE(h.usage) == HUP_LEDS) {
+ if (report_id == NO_REPORT_ID)
+ report_id = h.report_ID;
+ else if (h.report_ID != report_id)
+ syslog(LOG_WARNING, "Output HID report IDs " \
+ "for %s do not match: %d vs. %d. " \
+ "Please report",
+ bt_ntoa(&s->bdaddr, NULL),
+ h.report_ID, report_id);
+
+ switch(HID_USAGE(h.usage)) {
+ case 0x01: /* Num Lock LED */
+ if (leds & LED_NUM)
+ hid_set_data(&hleds, &h, 1);
+ break;
+
+ case 0x02: /* Caps Lock LED */
+ if (leds & LED_CAP)
+ hid_set_data(&hleds, &h, 1);
+ break;
+
+ case 0x03: /* Scroll Lock LED */
+ if (leds & LED_SCR)
+ hid_set_data(&hleds, &h, 1);
+ break;
+
+ /* XXX add other LEDs ? */
+ }
+ }
+ }
+ hid_end_parse(d);
+
+ data[0] = 0xa2; /* DATA output (HID output report) */
+
+ if (report_id != NO_REPORT_ID) {
+ data[1] = report_id;
+ data[2] = hleds;
+ len = 3;
+ } else {
+ data[1] = hleds;
+ len = 2;
+ }
+
+ write(s->intr, data, len);
+
+ return (0);
+}
+
diff --git a/usr.sbin/bluetooth/bthidd/kbd.h b/usr.sbin/bluetooth/bthidd/kbd.h
index 06e2caf..552f310 100644
--- a/usr.sbin/bluetooth/bthidd/kbd.h
+++ b/usr.sbin/bluetooth/bthidd/kbd.h
@@ -1,7 +1,9 @@
/*
* kbd.h
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,17 +27,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: kbd.h,v 1.2 2004/11/17 21:59:42 max Exp $
+ * $Id: kbd.h,v 1.3 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
#ifndef _KBD_H_
#define _KBD_H_
-int kbd_maxkey (void);
-int kbd_process_keys(bthid_session_p s);
-int kbd_get_index_fd(int fd);
-int kbd_get_index (char const *device);
-int kbd_switch (char const *script, int index);
+int32_t kbd_maxkey (void);
+int32_t kbd_process_keys (bthid_session_p s);
+int32_t kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len);
#endif /* ndef _KBD_H_ */
diff --git a/usr.sbin/bluetooth/bthidd/lexer.l b/usr.sbin/bluetooth/bthidd/lexer.l
index 93ad394..a25ae92 100644
--- a/usr.sbin/bluetooth/bthidd/lexer.l
+++ b/usr.sbin/bluetooth/bthidd/lexer.l
@@ -1,8 +1,10 @@
%{
/*
* lexer.l
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,13 +28,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: lexer.l,v 1.2 2004/02/13 21:46:20 max Exp $
+ * $Id: lexer.l,v 1.3 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
#include <bluetooth.h>
#include <stdlib.h>
#include "parser.h"
+
+ int yylex (void);
%}
%option yylineno noyywrap nounput
@@ -87,7 +91,7 @@ hexbytestring 0x{hexbyte}
}
{hexbytestring} {
- char *ep = NULL;
+ char *ep;
yylval.num = strtoul(yytext, &ep, 16);
diff --git a/usr.sbin/bluetooth/bthidd/parser.y b/usr.sbin/bluetooth/bthidd/parser.y
index eda82f6..8d95f4e 100644
--- a/usr.sbin/bluetooth/bthidd/parser.y
+++ b/usr.sbin/bluetooth/bthidd/parser.y
@@ -1,8 +1,10 @@
%{
/*
* parser.y
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,12 +28,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: parser.y,v 1.4 2004/11/17 21:59:42 max Exp $
+ * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
@@ -59,15 +63,17 @@
int yyparse (void);
int yylex (void);
-static int check_hid_device(hid_device_p hid_device);
+ void yyerror (char const *);
+static int32_t check_hid_device(hid_device_p hid_device);
static void free_hid_device (hid_device_p hid_device);
+extern FILE *yyin;
extern int yylineno;
- char *config_file = BTHIDD_CONFFILE;
- char *hids_file = BTHIDD_HIDSFILE;
+ char const *config_file = BTHIDD_CONFFILE;
+ char const *hids_file = BTHIDD_HIDSFILE;
static char buffer[1024];
-static int hid_descriptor_size;
+static int32_t hid_descriptor_size;
static hid_device_t *hid_device = NULL;
static LIST_HEAD(, hid_device) hid_devices;
@@ -75,7 +81,7 @@ static LIST_HEAD(, hid_device) hid_devices;
%union {
bdaddr_t bdaddr;
- int num;
+ int32_t num;
}
%token <bdaddr> T_BDADDRSTRING
@@ -197,7 +203,7 @@ hid_descriptor_bytes: hid_descriptor_byte
hid_descriptor_byte: T_HEXBYTE
{
- if (hid_descriptor_size >= sizeof(buffer)) {
+ if (hid_descriptor_size >= (int32_t) sizeof(buffer)) {
SYSLOG(LOGCRIT, "HID descriptor is too big" EOL);
YYABORT;
}
@@ -221,11 +227,10 @@ yyerror(char const *message)
}
/* Re-read config file */
-int
+int32_t
read_config_file(void)
{
- extern FILE *yyin;
- int e;
+ int32_t e;
if (config_file == NULL) {
SYSLOG(LOGERR, "Unknown config file name!" EOL);
@@ -257,10 +262,10 @@ void
clean_config(void)
{
while (!LIST_EMPTY(&hid_devices)) {
- hid_device_p hid_device = LIST_FIRST(&hid_devices);
+ hid_device_p d = LIST_FIRST(&hid_devices);
- LIST_REMOVE(hid_device, next);
- free_hid_device(hid_device);
+ LIST_REMOVE(d, next);
+ free_hid_device(d);
}
}
@@ -268,13 +273,13 @@ clean_config(void)
hid_device_p
get_hid_device(bdaddr_p bdaddr)
{
- hid_device_p hid_device;
+ hid_device_p d;
- LIST_FOREACH(hid_device, &hid_devices, next)
- if (memcmp(&hid_device->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
+ LIST_FOREACH(d, &hid_devices, next)
+ if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
break;
- return (hid_device);
+ return (d);
}
/* Get next config entry */
@@ -286,7 +291,7 @@ get_next_hid_device(hid_device_p d)
/* Print config entry */
void
-print_hid_device(hid_device_p hid_device, FILE *f)
+print_hid_device(hid_device_p d, FILE *f)
{
/* XXX FIXME hack! */
struct report_desc {
@@ -295,8 +300,8 @@ print_hid_device(hid_device_p hid_device, FILE *f)
};
/* XXX FIXME hack! */
- struct report_desc *desc = (struct report_desc *) hid_device->desc;
- int i;
+ struct report_desc *desc = (struct report_desc *) d->desc;
+ uint32_t i;
fprintf(f,
"device {\n" \
@@ -307,11 +312,11 @@ print_hid_device(hid_device_p hid_device, FILE *f)
" battery_power %s;\n" \
" normally_connectable %s;\n" \
" hid_descriptor {",
- bt_ntoa(&hid_device->bdaddr, NULL),
- hid_device->control_psm, hid_device->interrupt_psm,
- hid_device->reconnect_initiate? "true" : "false",
- hid_device->battery_power? "true" : "false",
- hid_device->normally_connectable? "true" : "false");
+ bt_ntoa(&d->bdaddr, NULL),
+ d->control_psm, d->interrupt_psm,
+ d->reconnect_initiate? "true" : "false",
+ d->battery_power? "true" : "false",
+ d->normally_connectable? "true" : "false");
for (i = 0; i < desc->size; i ++) {
if ((i % 8) == 0)
@@ -327,53 +332,76 @@ print_hid_device(hid_device_p hid_device, FILE *f)
}
/* Check config entry */
-static int
-check_hid_device(hid_device_p hid_device)
+static int32_t
+check_hid_device(hid_device_p d)
{
- if (get_hid_device(&hid_device->bdaddr) != NULL) {
+ hid_data_t hd;
+ hid_item_t hi;
+ int32_t page;
+
+ if (get_hid_device(&d->bdaddr) != NULL) {
SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL,
- bt_ntoa(&hid_device->bdaddr, NULL));
+ bt_ntoa(&d->bdaddr, NULL));
return (0);
}
- if (hid_device->control_psm == 0) {
+ if (d->control_psm == 0) {
SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL);
return (0);
}
- if (hid_device->interrupt_psm == 0) {
+ if (d->interrupt_psm == 0) {
SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL);
return (0);
}
- if (hid_device->desc == NULL) {
+ if (d->desc == NULL) {
SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL);
return (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:
+ case hid_endcollection:
+ case hid_output:
+ case hid_feature:
+ break;
+
+ case hid_input:
+ /* Check if the device may send keystrokes */
+ page = HID_PAGE(hi.usage);
+ if (page == HUP_KEYBOARD || page == HUP_CONSUMER)
+ d->keyboard = 1;
+ break;
+ }
+ }
+ hid_end_parse(hd);
+
return (1);
}
/* Free config entry */
static void
-free_hid_device(hid_device_p hid_device)
+free_hid_device(hid_device_p d)
{
- if (hid_device->desc != NULL)
- hid_dispose_report_desc(hid_device->desc);
+ if (d->desc != NULL)
+ hid_dispose_report_desc(d->desc);
- memset(hid_device, 0, sizeof(*hid_device));
- free(hid_device);
+ memset(d, 0, sizeof(*d));
+ free(d);
}
/* Re-read hids file */
-int
+int32_t
read_hids_file(void)
{
- FILE *f = NULL;
- hid_device_t *hid_device = NULL;
- char *line = NULL;
+ FILE *f;
+ hid_device_t *d;
+ char *line;
bdaddr_t bdaddr;
- int lineno;
+ int32_t lineno;
if (hids_file == NULL) {
SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
@@ -399,8 +427,8 @@ read_hids_file(void)
continue;
}
- if ((hid_device = get_hid_device(&bdaddr)) != NULL)
- hid_device->new_device = 0;
+ if ((d = get_hid_device(&bdaddr)) != NULL)
+ d->new_device = 0;
}
fclose(f);
@@ -409,12 +437,12 @@ read_hids_file(void)
}
/* Write hids file */
-int
+int32_t
write_hids_file(void)
{
char path[PATH_MAX];
- FILE *f = NULL;
- hid_device_t *hid_device = NULL;
+ FILE *f;
+ hid_device_t *d;
if (hids_file == NULL) {
SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
@@ -429,9 +457,9 @@ write_hids_file(void)
return (-1);
}
- LIST_FOREACH(hid_device, &hid_devices, next)
- if (!hid_device->new_device)
- fprintf(f, "%s\n", bt_ntoa(&hid_device->bdaddr, NULL));
+ LIST_FOREACH(d, &hid_devices, next)
+ if (!d->new_device)
+ fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL));
fclose(f);
diff --git a/usr.sbin/bluetooth/bthidd/server.c b/usr.sbin/bluetooth/bthidd/server.c
index 2f20715..2ed2fe4 100644
--- a/usr.sbin/bluetooth/bthidd/server.c
+++ b/usr.sbin/bluetooth/bthidd/server.c
@@ -1,7 +1,9 @@
/*
* server.c
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,13 +27,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: server.c,v 1.7 2004/11/17 21:59:42 max Exp $
+ * $Id: server.c,v 1.9 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <assert.h>
#include <bluetooth.h>
+#include <dev/vkbd/vkbd_var.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -40,21 +43,21 @@
#include <syslog.h>
#include <unistd.h>
#include <usbhid.h>
-#include "bthidd.h"
#include "bthid_config.h"
+#include "bthidd.h"
#include "kbd.h"
#undef max
#define max(x, y) (((x) > (y))? (x) : (y))
-static int server_accept (bthid_server_p srv, int fd);
-static int server_process(bthid_server_p srv, int fd);
+static int32_t server_accept (bthid_server_p srv, int32_t fd);
+static int32_t server_process(bthid_server_p srv, int32_t fd);
/*
* Initialize server
*/
-int
+int32_t
server_init(bthid_server_p srv)
{
struct sockaddr_l2cap l2addr;
@@ -66,25 +69,6 @@ server_init(bthid_server_p srv)
FD_ZERO(&srv->wfdset);
LIST_INIT(&srv->sessions);
- /* Allocate HID keycodes buffer */
- srv->keys = bit_alloc(kbd_maxkey());
- if (srv->keys == NULL) {
- syslog(LOG_ERR, "Could not allocate HID keys buffer");
- return (-1);
- }
- memset(srv->keys, 0, bitstr_size(kbd_maxkey()));
-
- /* Get wired keyboard index (if was not specified) */
- if (srv->windex == -1) {
- srv->windex = kbd_get_index("/dev/console");
- if (srv->windex < 0) {
- syslog(LOG_ERR, "Could not open get wired keyboard " \
- "index. %s (%d)", strerror(errno), errno);
- free(srv->keys);
- return (-1);
- }
- }
-
/* Open /dev/consolectl */
srv->cons = open("/dev/consolectl", O_RDWR);
if (srv->cons < 0) {
@@ -93,24 +77,12 @@ server_init(bthid_server_p srv)
return (-1);
}
- /* Open /dev/vkbdctl */
- srv->vkbd = open("/dev/vkbdctl", O_RDWR);
- if (srv->vkbd < 0) {
- syslog(LOG_ERR, "Could not open /dev/vkbdctl. %s (%d)",
- strerror(errno), errno);
- close(srv->cons);
- free(srv->keys);
- return (-1);
- }
-
/* Create control socket */
srv->ctrl = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
if (srv->ctrl < 0) {
syslog(LOG_ERR, "Could not create control L2CAP socket. " \
"%s (%d)", strerror(errno), errno);
- close(srv->vkbd);
close(srv->cons);
- free(srv->keys);
return (-1);
}
@@ -123,9 +95,7 @@ server_init(bthid_server_p srv)
syslog(LOG_ERR, "Could not bind control L2CAP socket. " \
"%s (%d)", strerror(errno), errno);
close(srv->ctrl);
- close(srv->vkbd);
close(srv->cons);
- free(srv->keys);
return (-1);
}
@@ -133,9 +103,7 @@ server_init(bthid_server_p srv)
syslog(LOG_ERR, "Could not listen on control L2CAP socket. " \
"%s (%d)", strerror(errno), errno);
close(srv->ctrl);
- close(srv->vkbd);
close(srv->cons);
- free(srv->keys);
return (-1);
}
@@ -145,9 +113,7 @@ server_init(bthid_server_p srv)
syslog(LOG_ERR, "Could not create interrupt L2CAP socket. " \
"%s (%d)", strerror(errno), errno);
close(srv->ctrl);
- close(srv->vkbd);
close(srv->cons);
- free(srv->keys);
return (-1);
}
@@ -158,9 +124,7 @@ server_init(bthid_server_p srv)
"%s (%d)", strerror(errno), errno);
close(srv->intr);
close(srv->ctrl);
- close(srv->vkbd);
close(srv->cons);
- free(srv->keys);
return (-1);
}
@@ -169,9 +133,7 @@ server_init(bthid_server_p srv)
"%s (%d)", strerror(errno), errno);
close(srv->intr);
close(srv->ctrl);
- close(srv->vkbd);
close(srv->cons);
- free(srv->keys);
return (-1);
}
@@ -192,15 +154,12 @@ server_shutdown(bthid_server_p srv)
assert(srv != NULL);
close(srv->cons);
- close(srv->vkbd);
close(srv->ctrl);
close(srv->intr);
while (!LIST_EMPTY(&srv->sessions))
session_close(LIST_FIRST(&srv->sessions));
- free(srv->keys);
-
memset(srv, 0, sizeof(*srv));
}
@@ -208,12 +167,12 @@ server_shutdown(bthid_server_p srv)
* Do one server iteration
*/
-int
+int32_t
server_do(bthid_server_p srv)
{
struct timeval tv;
fd_set rfdset, wfdset;
- int n, fd;
+ int32_t n, fd;
assert(srv != NULL);
@@ -258,13 +217,13 @@ server_do(bthid_server_p srv)
* Accept new connection
*/
-static int
-server_accept(bthid_server_p srv, int fd)
+static int32_t
+server_accept(bthid_server_p srv, int32_t fd)
{
- bthid_session_p s = NULL;
- hid_device_p d = NULL;
+ bthid_session_p s;
+ hid_device_p d;
struct sockaddr_l2cap l2addr;
- int len, new_fd;
+ int32_t len, new_fd;
len = sizeof(l2addr);
if ((new_fd = accept(fd, (struct sockaddr *) &l2addr, &len)) < 0) {
@@ -274,26 +233,25 @@ server_accept(bthid_server_p srv, int fd)
return (-1);
}
+ /* Is device configured? */
+ if ((d = get_hid_device(&l2addr.l2cap_bdaddr)) == NULL) {
+ syslog(LOG_ERR, "Rejecting %s connection from %s. " \
+ "Device not configured",
+ (fd == srv->ctrl)? "control" : "interrupt",
+ bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
+ close(new_fd);
+ return (-1);
+ }
+
/* Check if we have session for the device */
if ((s = session_by_bdaddr(srv, &l2addr.l2cap_bdaddr)) == NULL) {
- /* Is device configured? */
- if ((d = get_hid_device(&l2addr.l2cap_bdaddr)) == NULL) {
- syslog(LOG_ERR, "Rejecting %s connection from %s. " \
- "Device not configured",
- (fd == srv->ctrl)? "control" : "interrupt",
- bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
- close(new_fd);
- return (-1);
- }
-
d->new_device = 0; /* reset new device flag */
write_hids_file();
/* Create new inbound session */
- if ((s = session_open(srv, &l2addr.l2cap_bdaddr)) == NULL) {
- syslog(LOG_CRIT, "Could not open inbound session " \
- "for %s. Not enough memory",
- bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
+ if ((s = session_open(srv, d)) == NULL) {
+ syslog(LOG_CRIT, "Could not open inbound session "
+ "for %s", bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
close(new_fd);
return (-1);
}
@@ -318,6 +276,15 @@ server_accept(bthid_server_p srv, int fd)
(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;
+ }
+
return (0);
}
@@ -325,18 +292,36 @@ server_accept(bthid_server_p srv, int fd)
* Process data on the connection
*/
-static int
-server_process(bthid_server_p srv, int fd)
+static int32_t
+server_process(bthid_server_p srv, int32_t fd)
{
- bthid_session_p s = session_by_fd(srv, fd);
- char data[1024];
- int len;
+ bthid_session_p s = session_by_fd(srv, fd);
+ 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;
if (s == NULL)
return (0); /* can happen on device disconnect */
+
+ if (fd == s->ctrl) {
+ cb = hid_control;
+ to_read = sizeof(data.b);
+ } else if (fd == s->intr) {
+ cb = hid_interrupt;
+ to_read = sizeof(data.b);
+ } else {
+ assert(fd == s->vkbd);
+
+ cb = kbd_status_changed;
+ to_read = sizeof(data.s);
+ }
+
do {
- len = read(fd, data, sizeof(data));
+ len = read(fd, &data, to_read);
} while (len < 0 && errno == EINTR);
if (len < 0) {
@@ -356,10 +341,7 @@ server_process(bthid_server_p srv, int fd)
return (0);
}
- if (fd == s->ctrl)
- hid_control(s, data, len);
- else
- hid_interrupt(s, data, len);
+ (*cb)(s, (uint8_t *) &data, len);
return (0);
}
diff --git a/usr.sbin/bluetooth/bthidd/session.c b/usr.sbin/bluetooth/bthidd/session.c
index eefd98a..b9f331b 100644
--- a/usr.sbin/bluetooth/bthidd/session.c
+++ b/usr.sbin/bluetooth/bthidd/session.c
@@ -1,7 +1,9 @@
/*
* session.c
- *
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,17 +27,22 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: session.c,v 1.2 2004/11/17 21:59:42 max Exp $
+ * $Id: session.c,v 1.3 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <assert.h>
#include <bluetooth.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
#include "bthidd.h"
#include "kbd.h"
@@ -44,27 +51,51 @@
*/
bthid_session_p
-session_open(bthid_server_p srv, bdaddr_p bdaddr)
+session_open(bthid_server_p srv, hid_device_p const d)
{
- bthid_session_p s = NULL;
+ bthid_session_p s;
assert(srv != NULL);
- assert(bdaddr != NULL);
-
- if ((s = (bthid_session_p) malloc(sizeof(*s))) != NULL) {
- s->srv = srv;
- memcpy(&s->bdaddr, bdaddr, sizeof(s->bdaddr));
- s->ctrl = -1;
- s->intr = -1;
- s->state = CLOSED;
- s->keys = bit_alloc(kbd_maxkey());
- if (s->keys == NULL) {
+ assert(d != NULL);
+
+ if ((s = (bthid_session_p) malloc(sizeof(*s))) == NULL)
+ return (NULL);
+
+ s->srv = srv;
+ memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr));
+ s->ctrl = -1;
+ s->intr = -1;
+
+ 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);
- s = NULL;
- } else
- LIST_INSERT_HEAD(&srv->sessions, s, next);
+ return (NULL);
+ }
+ } else
+ s->vkbd = -1;
+
+ s->state = CLOSED;
+
+ s->keys1 = bit_alloc(kbd_maxkey());
+ if (s->keys1 == NULL) {
+ free(s);
+ return (NULL);
}
+ s->keys2 = bit_alloc(kbd_maxkey());
+ if (s->keys2 == NULL) {
+ free(s->keys1);
+ free(s);
+ return (NULL);
+ }
+
+ LIST_INSERT_HEAD(&srv->sessions, s, next);
+
return (s);
}
@@ -75,7 +106,7 @@ session_open(bthid_server_p srv, bdaddr_p bdaddr)
bthid_session_p
session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr)
{
- bthid_session_p s = NULL;
+ bthid_session_p s;
assert(srv != NULL);
assert(bdaddr != NULL);
@@ -92,15 +123,15 @@ session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr)
*/
bthid_session_p
-session_by_fd(bthid_server_p srv, int fd)
+session_by_fd(bthid_server_p srv, int32_t fd)
{
- bthid_session_p s = NULL;
+ bthid_session_p s;
assert(srv != NULL);
assert(fd >= 0);
LIST_FOREACH(s, &srv->sessions, next)
- if (s->ctrl == fd || s->intr == fd)
+ if (s->ctrl == fd || s->intr == fd || s->vkbd == fd)
break;
return (s);
@@ -136,7 +167,16 @@ session_close(bthid_session_p s)
s->srv->maxfd --;
}
- free(s->keys);
+ if (s->vkbd != -1) {
+ FD_CLR(s->vkbd, &s->srv->rfdset);
+ close(s->vkbd);
+
+ if (s->srv->maxfd == s->vkbd)
+ s->srv->maxfd --;
+ }
+
+ free(s->keys1);
+ free(s->keys2);
memset(s, 0, sizeof(*s));
free(s);
OpenPOWER on IntegriCloud