diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2008-08-04 20:58:34 +0200 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2008-08-04 20:58:34 +0200 | 
| commit | 40372f9dc3ab115870a10343124216a041e55d17 (patch) | |
| tree | ef5bfa80e3f560cf6856fd7a0d5c27c75c2cefe0 /compat/fakehid.c | |
| parent | 295eb0c879802eacff46cf3c962646363d81f6d3 (diff) | |
Move hidd pand and dund into compat directory
Diffstat (limited to 'compat/fakehid.c')
| -rw-r--r-- | compat/fakehid.c | 669 | 
1 files changed, 669 insertions, 0 deletions
| diff --git a/compat/fakehid.c b/compat/fakehid.c new file mode 100644 index 00000000..feefe2a6 --- /dev/null +++ b/compat/fakehid.c @@ -0,0 +1,669 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2003-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/poll.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> +#include <bluetooth/hidp.h> + +#include "hidd.h" +#include "uinput.h" + +#include <math.h> + +#ifdef NEED_PPOLL +#include "ppoll.h" +#endif + +static volatile sig_atomic_t __io_canceled = 0; + +static void sig_hup(int sig) +{ +} + +static void sig_term(int sig) +{ +	__io_canceled = 1; +} + +static void send_event(int fd, uint16_t type, uint16_t code, int32_t value) +{ +	struct uinput_event event; +	int len; + +	if (fd <= fileno(stderr)) +		return; + +	memset(&event, 0, sizeof(event)); +	event.type = type; +	event.code = code; +	event.value = value; + +	len = write(fd, &event, sizeof(event)); +} + +static int uinput_create(char *name, int keyboard, int mouse) +{ +	struct uinput_dev dev; +	int fd, aux; + +	fd = open("/dev/uinput", O_RDWR); +	if (fd < 0) { +		fd = open("/dev/input/uinput", O_RDWR); +		if (fd < 0) { +			fd = open("/dev/misc/uinput", O_RDWR); +			if (fd < 0) { +				fprintf(stderr, "Can't open input device: %s (%d)\n", +							strerror(errno), errno); +				return -1; +			} +		} +	} + +	memset(&dev, 0, sizeof(dev)); + +	if (name) +		strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE); + +	dev.id.bustype = BUS_BLUETOOTH; +	dev.id.vendor  = 0x0000; +	dev.id.product = 0x0000; +	dev.id.version = 0x0000; + +	if (write(fd, &dev, sizeof(dev)) < 0) { +		fprintf(stderr, "Can't write device information: %s (%d)\n", +							strerror(errno), errno); +		close(fd); +		return -1; +	} + +	if (mouse) { +		ioctl(fd, UI_SET_EVBIT, EV_REL); + +		for (aux = REL_X; aux <= REL_MISC; aux++) +			ioctl(fd, UI_SET_RELBIT, aux); +	} + +	if (keyboard) { +		ioctl(fd, UI_SET_EVBIT, EV_KEY); +		ioctl(fd, UI_SET_EVBIT, EV_LED); +		ioctl(fd, UI_SET_EVBIT, EV_REP); + +		for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++) +			ioctl(fd, UI_SET_KEYBIT, aux); + +		//for (aux = LED_NUML; aux <= LED_MISC; aux++) +		//	ioctl(fd, UI_SET_LEDBIT, aux); +	} + +	if (mouse) { +		ioctl(fd, UI_SET_EVBIT, EV_KEY); + +		for (aux = BTN_LEFT; aux <= BTN_BACK; aux++) +			ioctl(fd, UI_SET_KEYBIT, aux); +	} + +	ioctl(fd, UI_DEV_CREATE); + +	return fd; +} + +static int rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) +{ +	struct sockaddr_rc addr; +	int sk; + +	sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); +	if (sk < 0) { +		fprintf(stderr, "Can't create socket: %s (%d)\n", +							strerror(errno), errno); +		return -1; +	} + +	memset(&addr, 0, sizeof(addr)); +	addr.rc_family = AF_BLUETOOTH; +	bacpy(&addr.rc_bdaddr, src); + +	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		fprintf(stderr, "Can't bind socket: %s (%d)\n", +							strerror(errno), errno); +		close(sk); +		return -1; +	} + +	memset(&addr, 0, sizeof(addr)); +	addr.rc_family = AF_BLUETOOTH; +	bacpy(&addr.rc_bdaddr, dst); +	addr.rc_channel = channel; + +	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		fprintf(stderr, "Can't connect: %s (%d)\n", +							strerror(errno), errno); +		close(sk); +		return -1; +	} + +	return sk; +} + +static void func(int fd) +{ +} + +static void back(int fd) +{ +} + +static void next(int fd) +{ +} + +static void button(int fd, unsigned int button, int is_press) +{ +	switch (button) { +	case 1: +		send_event(fd, EV_KEY, BTN_LEFT, is_press); +		break; +	case 3: +		send_event(fd, EV_KEY, BTN_RIGHT, is_press); +		break; +	} + +	send_event(fd, EV_SYN, SYN_REPORT, 0); +} + +static void move(int fd, unsigned int direction) +{ +	double angle; +	int32_t x, y; + +	angle = (direction * 22.5) * 3.1415926 / 180; +	x = (int) (sin(angle) * 8); +	y = (int) (cos(angle) * -8); + +	send_event(fd, EV_REL, REL_X, x); +	send_event(fd, EV_REL, REL_Y, y); + +	send_event(fd, EV_SYN, SYN_REPORT, 0); +} + +static inline void epox_decode(int fd, unsigned char event) +{ +	switch (event) { +	case 48: +		func(fd); break; +	case 55: +		back(fd); break; +	case 56: +		next(fd); break; +	case 53: +		button(fd, 1, 1); break; +	case 121: +		button(fd, 1, 0); break; +	case 113: +		break; +	case 54: +		button(fd, 3, 1); break; +	case 120: +		button(fd, 3, 0); break; +	case 112: +		break; +	case 51: +		move(fd, 0); break; +	case 97: +		move(fd, 1); break; +	case 65: +		move(fd, 2); break; +	case 98: +		move(fd, 3); break; +	case 50: +		move(fd, 4); break; +	case 99: +		move(fd, 5); break; +	case 67: +		move(fd, 6); break; +	case 101: +		move(fd, 7); break; +	case 52: +		move(fd, 8); break; +	case 100: +		move(fd, 9); break; +	case 66: +		move(fd, 10); break; +	case 102: +		move(fd, 11); break; +	case 49: +		move(fd, 12); break; +	case 103: +		move(fd, 13); break; +	case 57: +		move(fd, 14); break; +	case 104: +		move(fd, 15); break; +	case 69: +		break; +	default: +		printf("Unknown event code %d\n", event); +		break; +	} +} + +int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) +{ +	unsigned char buf[16]; +	struct sigaction sa; +	struct pollfd p; +	sigset_t sigs; +	char addr[18]; +	int i, fd, sk, len; + +	sk = rfcomm_connect(src, dst, channel); +	if (sk < 0) +		return -1; + +	fd = uinput_create("Bluetooth Presenter", 0, 1); +	if (fd < 0) { +		close(sk); +		return -1; +	} + +	ba2str(dst, addr); + +	printf("Connected to %s on channel %d\n", addr, channel); +	printf("Press CTRL-C for hangup\n"); + +	memset(&sa, 0, sizeof(sa)); +	sa.sa_flags   = SA_NOCLDSTOP; +	sa.sa_handler = SIG_IGN; +	sigaction(SIGCHLD, &sa, NULL); +	sigaction(SIGPIPE, &sa, NULL); + +	sa.sa_handler = sig_term; +	sigaction(SIGTERM, &sa, NULL); +	sigaction(SIGINT,  &sa, NULL); + +	sa.sa_handler = sig_hup; +	sigaction(SIGHUP, &sa, NULL); + +	sigfillset(&sigs); +	sigdelset(&sigs, SIGCHLD); +	sigdelset(&sigs, SIGPIPE); +	sigdelset(&sigs, SIGTERM); +	sigdelset(&sigs, SIGINT); +	sigdelset(&sigs, SIGHUP); + +	p.fd = sk; +	p.events = POLLIN | POLLERR | POLLHUP; + +	while (!__io_canceled) { +		p.revents = 0; +		if (ppoll(&p, 1, NULL, &sigs) < 1) +			continue; + +		len = read(sk, buf, sizeof(buf)); +		if (len < 0) +			break; + +		for (i = 0; i < len; i++) +			epox_decode(fd, buf[i]); +	} + +	printf("Disconnected\n"); + +	ioctl(fd, UI_DEV_DESTROY); + +	close(fd); +	close(sk); + +	return 0; +} + +int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) +{ +	printf("Not implemented\n"); +	return -1; +} + +/* The strange meta key close to Ctrl has been assigned to Esc, +   Fn key to CtrlR and the left space to Alt*/ + +static unsigned char jthree_keycodes[63] = { +	KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, +	KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, +	KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, +	KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, +	KEY_LEFTALT, KEY_TAB, KEY_CAPSLOCK, KEY_ESC, +	KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, +	KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, +	KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, +	KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_UP, +	KEY_SPACE, KEY_COMPOSE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, +	KEY_LEFTCTRL, KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_DELETE, KEY_RIGHTCTRL, KEY_RIGHTALT, +}; + +static inline void jthree_decode(int fd, unsigned char event) +{ +	if (event > 63) +		send_event(fd, EV_KEY, jthree_keycodes[event & 0x3f], 0); +	else +		send_event(fd, EV_KEY, jthree_keycodes[event - 1], 1); +} + +int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) +{ +	unsigned char buf[16]; +	struct sigaction sa; +	struct pollfd p; +	sigset_t sigs; +	char addr[18]; +	int i, fd, sk, len; + +	sk = rfcomm_connect(src, dst, channel); +	if (sk < 0) +		return -1; + +	fd = uinput_create("J-Three Keyboard", 1, 0); +	if (fd < 0) { +		close(sk); +		return -1; +	} + +	ba2str(dst, addr); + +	printf("Connected to %s on channel %d\n", addr, channel); +	printf("Press CTRL-C for hangup\n"); + +	memset(&sa, 0, sizeof(sa)); +	sa.sa_flags   = SA_NOCLDSTOP; +	sa.sa_handler = SIG_IGN; +	sigaction(SIGCHLD, &sa, NULL); +	sigaction(SIGPIPE, &sa, NULL); + +	sa.sa_handler = sig_term; +	sigaction(SIGTERM, &sa, NULL); +	sigaction(SIGINT,  &sa, NULL); + +	sa.sa_handler = sig_hup; +	sigaction(SIGHUP, &sa, NULL); + +	sigfillset(&sigs); +	sigdelset(&sigs, SIGCHLD); +	sigdelset(&sigs, SIGPIPE); +	sigdelset(&sigs, SIGTERM); +	sigdelset(&sigs, SIGINT); +	sigdelset(&sigs, SIGHUP); + +	p.fd = sk; +	p.events = POLLIN | POLLERR | POLLHUP; + +	while (!__io_canceled) { +		p.revents = 0; +		if (ppoll(&p, 1, NULL, &sigs) < 1) +			continue; + +		len = read(sk, buf, sizeof(buf)); +		if (len < 0) +			break; + +		for (i = 0; i < len; i++) +			jthree_decode(fd, buf[i]); +	} + +	printf("Disconnected\n"); + +	ioctl(fd, UI_DEV_DESTROY); + +	close(fd); +	close(sk); + +	return 0; +} + +static const int celluon_xlate_num[10] = { +	KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 +}; + +static const int celluon_xlate_char[26] = { +	KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, +	KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, +	KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z +}; + +static int celluon_xlate(int c) +{ +	if (c >= '0' && c <= '9') +		return celluon_xlate_num[c - '0']; + +	if (c >= 'A' && c <= 'Z') +		return celluon_xlate_char[c - 'A']; + +	switch (c) { +	case 0x08: +		return KEY_BACKSPACE; +	case 0x09: +		return KEY_TAB; +	case 0x0d: +		return KEY_ENTER; +	case 0x11: +		return KEY_LEFTCTRL; +	case 0x14: +		return KEY_CAPSLOCK; +	case 0x20: +		return KEY_SPACE; +	case 0x25: +		return KEY_LEFT; +	case 0x26: +		return KEY_UP; +	case 0x27: +		return KEY_RIGHT; +	case 0x28: +		return KEY_DOWN; +	case 0x2e: +		return KEY_DELETE; +	case 0x5b: +		return KEY_MENU; +	case 0xa1: +		return KEY_RIGHTSHIFT; +	case 0xa0: +		return KEY_LEFTSHIFT; +	case 0xba: +		return KEY_SEMICOLON; +	case 0xbd: +		return KEY_MINUS; +	case 0xbc: +		return KEY_COMMA; +	case 0xbb: +		return KEY_EQUAL; +	case 0xbe: +		return KEY_DOT; +	case 0xbf: +		return KEY_SLASH; +	case 0xc0: +		return KEY_GRAVE; +	case 0xdb: +		return KEY_LEFTBRACE; +	case 0xdc: +		return KEY_BACKSLASH; +	case 0xdd: +		return KEY_RIGHTBRACE; +	case 0xde: +		return KEY_APOSTROPHE; +	case 0xff03: +		return KEY_HOMEPAGE; +	case 0xff04: +		return KEY_TIME; +	case 0xff06: +		return KEY_OPEN; +	case 0xff07: +		return KEY_LIST; +	case 0xff08: +		return KEY_MAIL; +	case 0xff30: +		return KEY_CALC; +	case 0xff1a: /* Map FN to ALT */ +		return KEY_LEFTALT; +	case 0xff2f: +		return KEY_INFO; +	default: +		printf("Unknown key %x\n", c); +		return c; +	} +} + +struct celluon_state { +	int len;	/* Expected length of current packet */ +	int count;	/* Number of bytes received */ +	int action; +	int key; +}; + +static void celluon_decode(int fd, struct celluon_state *s, uint8_t c) +{ +	if (s->count < 2 && c != 0xa5) { +		/* Lost Sync */ +		s->count = 0; +		return; +	} + +	switch (s->count) { +	case 0: +		/* New packet - Reset state */ +		s->len = 30; +		s->key = 0; +		break; +	case 1: +		break; +	case 6: +		s->action = c; +		break; +	case 28: +		s->key = c; +		if (c == 0xff) +			s->len = 31; +		break; +	case 29: +	case 30: +		if (s->count == s->len - 1) { +			/* TODO: Verify checksum */ +			if (s->action < 2) { +				send_event(fd, EV_KEY, celluon_xlate(s->key), +								s->action); +			} +			s->count = -1; +		} else { +			s->key = (s->key << 8) | c; +		} +		break; +	} + +	s->count++; + +	return; +} + +int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) +{ +	unsigned char buf[16]; +	struct sigaction sa; +	struct pollfd p; +	sigset_t sigs; +	char addr[18]; +	int i, fd, sk, len; +	struct celluon_state s; + +	sk = rfcomm_connect(src, dst, channel); +	if (sk < 0) +		return -1; + +	fd = uinput_create("Celluon Keyboard", 1, 0); +	if (fd < 0) { +		close(sk); +		return -1; +	} + +	ba2str(dst, addr); + +	printf("Connected to %s on channel %d\n", addr, channel); +	printf("Press CTRL-C for hangup\n"); + +	memset(&sa, 0, sizeof(sa)); +	sa.sa_flags   = SA_NOCLDSTOP; +	sa.sa_handler = SIG_IGN; +	sigaction(SIGCHLD, &sa, NULL); +	sigaction(SIGPIPE, &sa, NULL); + +	sa.sa_handler = sig_term; +	sigaction(SIGTERM, &sa, NULL); +	sigaction(SIGINT,  &sa, NULL); + +	sa.sa_handler = sig_hup; +	sigaction(SIGHUP, &sa, NULL); + +	sigfillset(&sigs); +	sigdelset(&sigs, SIGCHLD); +	sigdelset(&sigs, SIGPIPE); +	sigdelset(&sigs, SIGTERM); +	sigdelset(&sigs, SIGINT); +	sigdelset(&sigs, SIGHUP); + +	p.fd = sk; +	p.events = POLLIN | POLLERR | POLLHUP; + +	memset(&s, 0, sizeof(s)); + +	while (!__io_canceled) { +		p.revents = 0; +		if (ppoll(&p, 1, NULL, &sigs) < 1) +			continue; + +		len = read(sk, buf, sizeof(buf)); +		if (len < 0) +			break; + +		for (i = 0; i < len; i++) +			celluon_decode(fd, &s, buf[i]); +	} + +	printf("Disconnected\n"); + +	ioctl(fd, UI_DEV_DESTROY); + +	close(fd); +	close(sk); + +	return 0; +} | 
