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
This commit is contained in:
parent
0f31538c9d
commit
7aebfa93ac
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=162128
@ -4,6 +4,8 @@
|
||||
SUBDIR= \
|
||||
bcmfw \
|
||||
bt3cfw \
|
||||
bthidcontrol \
|
||||
bthidd \
|
||||
hccontrol \
|
||||
hcsecd \
|
||||
hcseriald \
|
||||
|
@ -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}
|
||||
|
@ -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_ */
|
||||
|
||||
|
128
usr.sbin/bluetooth/bthidd/bthidd.8
Normal file
128
usr.sbin/bluetooth/bthidd/bthidd.8
Normal file
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 };
|
||||
if (hid_device->keyboard) {
|
||||
int32_t buf[4] = { 0xe0, val,
|
||||
0xe0, val|0x80 };
|
||||
|
||||
write(s->srv->vkbd, buf, sizeof(buf));
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
/* Check if old keys still pressed */
|
||||
bit_ffs(s->keys2, xsize, &f2);
|
||||
|
||||
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));
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* some keys got pressed, some keys got released */
|
||||
memset(r, 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);
|
||||
}
|
||||
|
||||
/* new keys got pressed, old keys got released */
|
||||
memset(diff, 0, bitstr_size(xsize));
|
||||
|
||||
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 = 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 = f0; i < xsize; i++) {
|
||||
if (bit_test(s->srv->keys, i)) {
|
||||
if (!bit_test(s->keys, i))
|
||||
bit_set(s->keys, 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);
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
assert(d != 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) {
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user