diff options
author | emax <emax@FreeBSD.org> | 2006-09-07 21:47:49 +0000 |
---|---|---|
committer | emax <emax@FreeBSD.org> | 2006-09-07 21:47:49 +0000 |
commit | 0a0c0e69a8b3191ef395c191f4667746e8f79f90 (patch) | |
tree | 2d993bc06bdf62dbb75a647125df678ab96cd3be /usr.sbin | |
parent | d04edc5790dab1504a82e507350c255aac246f8b (diff) | |
download | FreeBSD-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/Makefile | 2 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/bthid_config.h | 21 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/bthidd.8 | 128 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/bthidd.c | 90 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/bthidd.h | 46 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/client.c | 53 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/hid.c | 85 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/kbd.c | 279 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/kbd.h | 16 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/lexer.l | 12 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/parser.y | 132 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/server.c | 146 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/session.c | 86 |
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); |