diff options
Diffstat (limited to 'usr.sbin/bluetooth/bthidd/kbd.c')
-rw-r--r-- | usr.sbin/bluetooth/bthidd/kbd.c | 279 |
1 files changed, 133 insertions, 146 deletions
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); +} + |