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 |
|