Deleted Added
full compact
kbd.c (155858) kbd.c (162128)
1/*
2 * kbd.c
1/*
2 * kbd.c
3 *
4 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
3 */
4
5/*-
6 * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright

--- 7 unchanged lines hidden (view full) ---

20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright

--- 7 unchanged lines hidden (view full) ---

22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
28 * $Id: kbd.c,v 1.2 2004/11/17 21:59:42 max Exp $
29 * $FreeBSD: head/usr.sbin/bluetooth/bthidd/kbd.c 155858 2006-02-20 10:07:40Z markus $
30 * $Id: kbd.c,v 1.4 2006/09/07 21:06:53 max Exp $
31 * $FreeBSD: head/usr.sbin/bluetooth/bthidd/kbd.c 162128 2006-09-07 21:47:49Z emax $
30 */
31
32#include <sys/consio.h>
33#include <sys/ioctl.h>
34#include <sys/kbio.h>
35#include <sys/queue.h>
36#include <sys/wait.h>
37#include <assert.h>
38#include <bluetooth.h>
32 */
33
34#include <sys/consio.h>
35#include <sys/ioctl.h>
36#include <sys/kbio.h>
37#include <sys/queue.h>
38#include <sys/wait.h>
39#include <assert.h>
40#include <bluetooth.h>
41#include <dev/usb/usb.h>
42#include <dev/usb/usbhid.h>
43#include <dev/vkbd/vkbd_var.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <limits.h>
42#include <stdarg.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <syslog.h>
47#include <unistd.h>
44#include <errno.h>
45#include <fcntl.h>
46#include <limits.h>
47#include <stdarg.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <syslog.h>
52#include <unistd.h>
53#include <usbhid.h>
54#include "bthid_config.h"
48#include "bthidd.h"
49#include "kbd.h"
50
55#include "bthidd.h"
56#include "kbd.h"
57
51static void kbd_write(bitstr_t *m, int fb, int make, int fd);
52static int kbd_xlate(int code, int make, int *b, int const *eob);
58static void kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd);
59static int32_t kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob);
53
54/*
55 * HID code to PS/2 set 1 code translation table.
56 *
57 * http://www.microsoft.com/whdc/device/input/Scancode.mspx
58 *
59 * The table only contains "make" (key pressed) codes.
60 * The "break" (key released) code is generated as "make" | 0x80
61 */
62
63#define E0PREFIX (1 << 31)
64#define NOBREAK (1 << 30)
65#define CODEMASK (~(E0PREFIX|NOBREAK))
66
60
61/*
62 * HID code to PS/2 set 1 code translation table.
63 *
64 * http://www.microsoft.com/whdc/device/input/Scancode.mspx
65 *
66 * The table only contains "make" (key pressed) codes.
67 * The "break" (key released) code is generated as "make" | 0x80
68 */
69
70#define E0PREFIX (1 << 31)
71#define NOBREAK (1 << 30)
72#define CODEMASK (~(E0PREFIX|NOBREAK))
73
67static int const x[] =
74static int32_t const x[] =
68{
69/*==================================================*/
70/* Name HID code Make Break*/
71/*==================================================*/
72/* No Event 00 */ -1, /* None */
73/* Overrun Error 01 */ NOBREAK|0xFF, /* None */
74/* POST Fail 02 */ NOBREAK|0xFC, /* None */
75/* ErrorUndefined 03 */ -1, /* Unassigned */

--- 227 unchanged lines hidden (view full) ---

303/* Left Alt E2 */ 0x38, /* B8 */
304/* Left GUI E3 */ E0PREFIX|0x5B, /* E0 DB */
305/* Right Control E4 */ E0PREFIX|0x1D, /* E0 9D */
306/* Right Shift E5 */ 0x36, /* B6 */
307/* Right Alt E6 */ E0PREFIX|0x38, /* E0 B8 */
308/* Right GUI E7 */ E0PREFIX|0x5C /* E0 DC */
309};
310
75{
76/*==================================================*/
77/* Name HID code Make Break*/
78/*==================================================*/
79/* No Event 00 */ -1, /* None */
80/* Overrun Error 01 */ NOBREAK|0xFF, /* None */
81/* POST Fail 02 */ NOBREAK|0xFC, /* None */
82/* ErrorUndefined 03 */ -1, /* Unassigned */

--- 227 unchanged lines hidden (view full) ---

310/* Left Alt E2 */ 0x38, /* B8 */
311/* Left GUI E3 */ E0PREFIX|0x5B, /* E0 DB */
312/* Right Control E4 */ E0PREFIX|0x1D, /* E0 9D */
313/* Right Shift E5 */ 0x36, /* B6 */
314/* Right Alt E6 */ E0PREFIX|0x38, /* E0 B8 */
315/* Right GUI E7 */ E0PREFIX|0x5C /* E0 DC */
316};
317
311#define xsize (sizeof(x)/sizeof(x[0]))
318#define xsize ((int32_t)(sizeof(x)/sizeof(x[0])))
312
313/*
314 * Get a max HID keycode (aligned)
315 */
316
319
320/*
321 * Get a max HID keycode (aligned)
322 */
323
317int
324int32_t
318kbd_maxkey(void)
319{
320 return (xsize);
321}
322
323/*
324 * Process keys
325 */
326
325kbd_maxkey(void)
326{
327 return (xsize);
328}
329
330/*
331 * Process keys
332 */
333
327int
334int32_t
328kbd_process_keys(bthid_session_p s)
329{
335kbd_process_keys(bthid_session_p s)
336{
330 bitstr_t r[bitstr_size(xsize)];
331 int f0, f1, i;
337 bitstr_t diff[bitstr_size(xsize)];
338 int32_t f1, f2, i;
332
333 assert(s != NULL);
334 assert(s->srv != NULL);
335
339
340 assert(s != NULL);
341 assert(s->srv != NULL);
342
336 bit_ffs(s->srv->keys, xsize, &f0);
337 bit_ffs(s->keys, xsize, &f1);
343 /* Check if the new keys have been pressed */
344 bit_ffs(s->keys1, xsize, &f1);
338
345
339 if (f0 == -1) {
340 /* all keys are released, no keys pressed */
341 if (f1 != -1) {
342 kbd_write(s->keys, f1, 0, s->srv->vkbd);
343 memset(s->keys, 0, bitstr_size(xsize));
346 /* Check if old keys still pressed */
347 bit_ffs(s->keys2, xsize, &f2);
348
349 if (f1 == -1) {
350 /* no new key pressed */
351 if (f2 != -1) {
352 /* release old keys */
353 kbd_write(s->keys2, f2, 0, s->vkbd);
354 memset(s->keys2, 0, bitstr_size(xsize));
344 }
345
346 return (0);
347 }
348
355 }
356
357 return (0);
358 }
359
349 if (f1 == -1) {
350 /* some keys got pressed, no keys released */
351 if (f0 != -1) {
352 memcpy(s->keys, s->srv->keys, bitstr_size(xsize));
353 kbd_write(s->keys, f0, 1, s->srv->vkbd);
354 memset(s->srv->keys, 0, bitstr_size(xsize));
355 }
360 if (f2 == -1) {
361 /* no old keys, but new keys pressed */
362 assert(f1 != -1);
363
364 memcpy(s->keys2, s->keys1, bitstr_size(xsize));
365 kbd_write(s->keys1, f1, 1, s->vkbd);
366 memset(s->keys1, 0, bitstr_size(xsize));
356
357 return (0);
358 }
359
367
368 return (0);
369 }
370
360 /* some keys got pressed, some keys got released */
361 memset(r, 0, bitstr_size(xsize));
371 /* new keys got pressed, old keys got released */
372 memset(diff, 0, bitstr_size(xsize));
362
373
363 for (i = f1; i < xsize; i++) {
364 if (bit_test(s->keys, i)) {
365 if (!bit_test(s->srv->keys, i)) {
366 bit_clear(s->keys, i);
367 bit_set(r, i);
368 } else
369 bit_clear(s->srv->keys, i);
374 for (i = f2; i < xsize; i ++) {
375 if (bit_test(s->keys2, i)) {
376 if (!bit_test(s->keys1, i)) {
377 bit_clear(s->keys2, i);
378 bit_set(diff, i);
379 }
370 }
371 }
372
380 }
381 }
382
373 for (i = f0; i < xsize; i++) {
374 if (bit_test(s->srv->keys, i)) {
375 if (!bit_test(s->keys, i))
376 bit_set(s->keys, i);
383 for (i = f1; i < xsize; i++) {
384 if (bit_test(s->keys1, i)) {
385 if (!bit_test(s->keys2, i))
386 bit_set(s->keys2, i);
377 else
387 else
378 bit_clear(s->srv->keys, i);
388 bit_clear(s->keys1, i);
379 }
380 }
381
389 }
390 }
391
382 bit_ffs(r, xsize, &f0);
383 bit_ffs(s->srv->keys, xsize, &f1);
392 bit_ffs(diff, xsize, &f2);
393 if (f2 > 0)
394 kbd_write(diff, f2, 0, s->vkbd);
384
395
385 if (f0 > 0)
386 kbd_write(r, f0, 0, s->srv->vkbd);
387
396 bit_ffs(s->keys1, xsize, &f1);
388 if (f1 > 0) {
397 if (f1 > 0) {
389 kbd_write(s->srv->keys, f1, 1, s->srv->vkbd);
390 memset(s->srv->keys, 0, bitstr_size(xsize));
398 kbd_write(s->keys1, f1, 1, s->vkbd);
399 memset(s->keys1, 0, bitstr_size(xsize));
391 }
392
393 return (0);
394}
395
396/*
400 }
401
402 return (0);
403}
404
405/*
397 * Get current keyboard index (fd version)
398 */
399
400int
401kbd_get_index_fd(int fd)
402{
403 keyboard_info_t info;
404
405 return ((ioctl(fd, KDGKBINFO, &info) < 0)? -1 : info.kb_index);
406}
407
408/*
409 * Get current keyboard index (device node version)
410 */
411
412int
413kbd_get_index(char const *device)
414{
415 int fd, index;
416
417 fd = open(device, O_RDONLY);
418 if (fd < 0)
419 return (-1);
420
421 index = kbd_get_index_fd(fd);
422
423 close(fd);
424
425 return (index);
426}
427
428/*
429 * Switch keyboards. Execute external script to switch keyboards. The keyboard
430 * index will be passed to the script in the first argument (argv[1]). We use
431 * external script here to allow user to customize his/her wireless keyboard,
432 * i.e. set mapping etc. In theory, all parameters could be picked up from the
433 * rc.conf.
434 */
435
436int
437kbd_switch(char const *script, int index)
438{
439 pid_t pid;
440 int status;
441
442 if (script == NULL) {
443 syslog(LOG_NOTICE, "Could not switch keyboards. " \
444 "Switch script is not defined");
445 return (-1);
446 }
447
448 if (access(script, X_OK) < 0) {
449 syslog(LOG_ERR, "The %s is not executable. %s (%d)",
450 script, strerror(errno), errno);
451 return (-1);
452 }
453
454 pid = fork();
455
456 if (pid == (pid_t) -1) {
457 syslog(LOG_ERR, "Could not create process for %s. %s (%d)",
458 script, strerror(errno), errno);
459 return (-1);
460 }
461
462 if (pid == 0) {
463 char arg[16];
464 char *argv[3] = { (char *) script, arg, NULL };
465
466 snprintf(arg, sizeof(arg), "%d", index);
467 execv(script, argv);
468
469 syslog(LOG_ERR, "Could not execute '%s %d'. %s (%d)",
470 script, index, strerror(errno), errno);
471
472 exit(1);
473 }
474
475 if (waitpid(pid, &status, 0) < 0) {
476 syslog(LOG_ERR, "Could not waitpid for %s. %s (%d)",
477 script, strerror(errno), errno);
478 return (-1);
479 }
480
481 if (WIFEXITED(status) && WEXITSTATUS(status)) {
482 syslog(LOG_ERR, "External command '%s %d' failed, exit code %d",
483 script, index, WEXITSTATUS(status));
484 return (-1);
485 }
486
487 return (0);
488}
489
490/*
491 * Translate given keymap and write keyscodes
492 */
493
494static void
406 * Translate given keymap and write keyscodes
407 */
408
409static void
495kbd_write(bitstr_t *m, int fb, int make, int fd)
410kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd)
496{
411{
497 int i, *b, *eob, n, buf[64];
412 int32_t i, *b, *eob, n, buf[64];
498
499 b = buf;
500 eob = b + sizeof(buf)/sizeof(buf[0]);
501 i = fb;
502
503 while (i < xsize) {
504 if (bit_test(m, i)) {
505 n = kbd_xlate(i, make, b, eob);

--- 8 unchanged lines hidden (view full) ---

514
515 i ++;
516 }
517
518 if (b != buf)
519 write(fd, buf, (b - buf) * sizeof(buf[0]));
520}
521
413
414 b = buf;
415 eob = b + sizeof(buf)/sizeof(buf[0]);
416 i = fb;
417
418 while (i < xsize) {
419 if (bit_test(m, i)) {
420 n = kbd_xlate(i, make, b, eob);

--- 8 unchanged lines hidden (view full) ---

429
430 i ++;
431 }
432
433 if (b != buf)
434 write(fd, buf, (b - buf) * sizeof(buf[0]));
435}
436
522
523/*
524 * Translate HID code into PS/2 code and put codes into buffer b.
525 * Returns the number of codes put in b. Return -1 if buffer has not
526 * enough space.
527 */
528
529#undef PUT
530#define PUT(c, n, b, eob) \
531do { \
532 if ((b) >= (eob)) \
533 return (-1); \
534 *(b) = (c); \
535 (b) ++; \
536 (n) ++; \
537} while (0)
538
437/*
438 * Translate HID code into PS/2 code and put codes into buffer b.
439 * Returns the number of codes put in b. Return -1 if buffer has not
440 * enough space.
441 */
442
443#undef PUT
444#define PUT(c, n, b, eob) \
445do { \
446 if ((b) >= (eob)) \
447 return (-1); \
448 *(b) = (c); \
449 (b) ++; \
450 (n) ++; \
451} while (0)
452
539static int
540kbd_xlate(int code, int make, int *b, int const *eob)
453static int32_t
454kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob)
541{
455{
542 int c, n;
456 int32_t c, n;
543
544 n = 0;
545
546 if (code >= xsize)
547 return (0); /* HID code is not in the table */
548
549 /* Handle special case - Pause/Break */
550 if (code == 0x48) {

--- 35 unchanged lines hidden (view full) ---

586 PUT(0xe0, n, b, eob);
587
588 PUT((0x80|(c & CODEMASK)), n, b, eob);
589 }
590
591 return (n);
592}
593
457
458 n = 0;
459
460 if (code >= xsize)
461 return (0); /* HID code is not in the table */
462
463 /* Handle special case - Pause/Break */
464 if (code == 0x48) {

--- 35 unchanged lines hidden (view full) ---

500 PUT(0xe0, n, b, eob);
501
502 PUT((0x80|(c & CODEMASK)), n, b, eob);
503 }
504
505 return (n);
506}
507
508/*
509 * Process status change from vkbd(4)
510 */
511
512int32_t
513kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len)
514{
515 int32_t leds;
516 uint8_t hleds, report_id;
517 hid_device_p hid_device;
518 hid_data_t d;
519 hid_item_t h;
520
521 assert(s != NULL);
522 assert(len == sizeof(vkbd_status_t));
523
524 leds = ((vkbd_status_p) data)->leds;
525 hleds = 0;
526 report_id = NO_REPORT_ID;
527
528 hid_device = get_hid_device(&s->bdaddr);
529 assert(hid_device != NULL);
530
531 for (d = hid_start_parse(hid_device->desc, 1 << hid_output, -1);
532 hid_get_item(d, &h) > 0; ) {
533 if (HID_PAGE(h.usage) == HUP_LEDS) {
534 if (report_id == NO_REPORT_ID)
535 report_id = h.report_ID;
536 else if (h.report_ID != report_id)
537 syslog(LOG_WARNING, "Output HID report IDs " \
538 "for %s do not match: %d vs. %d. " \
539 "Please report",
540 bt_ntoa(&s->bdaddr, NULL),
541 h.report_ID, report_id);
542
543 switch(HID_USAGE(h.usage)) {
544 case 0x01: /* Num Lock LED */
545 if (leds & LED_NUM)
546 hid_set_data(&hleds, &h, 1);
547 break;
548
549 case 0x02: /* Caps Lock LED */
550 if (leds & LED_CAP)
551 hid_set_data(&hleds, &h, 1);
552 break;
553
554 case 0x03: /* Scroll Lock LED */
555 if (leds & LED_SCR)
556 hid_set_data(&hleds, &h, 1);
557 break;
558
559 /* XXX add other LEDs ? */
560 }
561 }
562 }
563 hid_end_parse(d);
564
565 data[0] = 0xa2; /* DATA output (HID output report) */
566
567 if (report_id != NO_REPORT_ID) {
568 data[1] = report_id;
569 data[2] = hleds;
570 len = 3;
571 } else {
572 data[1] = hleds;
573 len = 2;
574 }
575
576 write(s->intr, data, len);
577
578 return (0);
579}
580