1 /* 2 * kbd.c 3 */ 4 5 /*- 6 * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com> 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 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 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 * 30 * $Id: kbd.c,v 1.4 2006/09/07 21:06:53 max Exp $ 31 * $FreeBSD$ 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 #define L2CAP_SOCKET_CHECKED 41 #include <bluetooth.h> 42 #include <dev/usb/usb.h> 43 #include <dev/usb/usbhid.h> 44 #include <dev/vkbd/vkbd_var.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <limits.h> 48 #include <stdarg.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <syslog.h> 53 #include <unistd.h> 54 #include <usbhid.h> 55 #include "bthid_config.h" 56 #include "bthidd.h" 57 #include "kbd.h" 58 59 static void kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd); 60 static int32_t kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob); 61 62 /* 63 * HID code to PS/2 set 1 code translation table. 64 * 65 * http://www.microsoft.com/whdc/device/input/Scancode.mspx 66 * 67 * The table only contains "make" (key pressed) codes. 68 * The "break" (key released) code is generated as "make" | 0x80 69 */ 70 71 #define E0PREFIX (1U << 31) 72 #define NOBREAK (1 << 30) 73 #define CODEMASK (~(E0PREFIX|NOBREAK)) 74 75 static int32_t const x[] = 76 { 77 /*==================================================*/ 78 /* Name HID code Make Break*/ 79 /*==================================================*/ 80 /* No Event 00 */ -1, /* None */ 81 /* Overrun Error 01 */ NOBREAK|0xFF, /* None */ 82 /* POST Fail 02 */ NOBREAK|0xFC, /* None */ 83 /* ErrorUndefined 03 */ -1, /* Unassigned */ 84 /* a A 04 */ 0x1E, /* 9E */ 85 /* b B 05 */ 0x30, /* B0 */ 86 /* c C 06 */ 0x2E, /* AE */ 87 /* d D 07 */ 0x20, /* A0 */ 88 /* e E 08 */ 0x12, /* 92 */ 89 /* f F 09 */ 0x21, /* A1 */ 90 /* g G 0A */ 0x22, /* A2 */ 91 /* h H 0B */ 0x23, /* A3 */ 92 /* i I 0C */ 0x17, /* 97 */ 93 /* j J 0D */ 0x24, /* A4 */ 94 /* k K 0E */ 0x25, /* A5 */ 95 /* l L 0F */ 0x26, /* A6 */ 96 /* m M 10 */ 0x32, /* B2 */ 97 /* n N 11 */ 0x31, /* B1 */ 98 /* o O 12 */ 0x18, /* 98 */ 99 /* p P 13 */ 0x19, /* 99 */ 100 /* q Q 14 */ 0x10, /* 90 */ 101 /* r R 15 */ 0x13, /* 93 */ 102 /* s S 16 */ 0x1F, /* 9F */ 103 /* t T 17 */ 0x14, /* 94 */ 104 /* u U 18 */ 0x16, /* 96 */ 105 /* v V 19 */ 0x2F, /* AF */ 106 /* w W 1A */ 0x11, /* 91 */ 107 /* x X 1B */ 0x2D, /* AD */ 108 /* y Y 1C */ 0x15, /* 95 */ 109 /* z Z 1D */ 0x2C, /* AC */ 110 /* 1 ! 1E */ 0x02, /* 82 */ 111 /* 2 @ 1F */ 0x03, /* 83 */ 112 /* 3 # 20 */ 0x04, /* 84 */ 113 /* 4 $ 21 */ 0x05, /* 85 */ 114 /* 5 % 22 */ 0x06, /* 86 */ 115 /* 6 ^ 23 */ 0x07, /* 87 */ 116 /* 7 & 24 */ 0x08, /* 88 */ 117 /* 8 * 25 */ 0x09, /* 89 */ 118 /* 9 ( 26 */ 0x0A, /* 8A */ 119 /* 0 ) 27 */ 0x0B, /* 8B */ 120 /* Return 28 */ 0x1C, /* 9C */ 121 /* Escape 29 */ 0x01, /* 81 */ 122 /* Backspace 2A */ 0x0E, /* 8E */ 123 /* Tab 2B */ 0x0F, /* 8F */ 124 /* Space 2C */ 0x39, /* B9 */ 125 /* - _ 2D */ 0x0C, /* 8C */ 126 /* = + 2E */ 0x0D, /* 8D */ 127 /* [ { 2F */ 0x1A, /* 9A */ 128 /* ] } 30 */ 0x1B, /* 9B */ 129 /* \ | 31 */ 0x2B, /* AB */ 130 /* Europe 1 32 */ 0x2B, /* AB */ 131 /* ; : 33 */ 0x27, /* A7 */ 132 /* " ' 34 */ 0x28, /* A8 */ 133 /* ` ~ 35 */ 0x29, /* A9 */ 134 /* comma < 36 */ 0x33, /* B3 */ 135 /* . > 37 */ 0x34, /* B4 */ 136 /* / ? 38 */ 0x35, /* B5 */ 137 /* Caps Lock 39 */ 0x3A, /* BA */ 138 /* F1 3A */ 0x3B, /* BB */ 139 /* F2 3B */ 0x3C, /* BC */ 140 /* F3 3C */ 0x3D, /* BD */ 141 /* F4 3D */ 0x3E, /* BE */ 142 /* F5 3E */ 0x3F, /* BF */ 143 /* F6 3F */ 0x40, /* C0 */ 144 /* F7 40 */ 0x41, /* C1 */ 145 /* F8 41 */ 0x42, /* C2 */ 146 /* F9 42 */ 0x43, /* C3 */ 147 /* F10 43 */ 0x44, /* C4 */ 148 /* F11 44 */ 0x57, /* D7 */ 149 /* F12 45 */ 0x58, /* D8 */ 150 /* Print Screen 46 */ E0PREFIX|0x37, /* E0 B7 */ 151 /* Scroll Lock 47 */ 0x46, /* C6 */ 152 #if 0 153 /* Break (Ctrl-Pause) 48 */ E0 46 E0 C6, /* None */ 154 /* Pause 48 */ E1 1D 45 E1 9D C5, /* None */ 155 #else 156 /* Break (Ctrl-Pause)/Pause 48 */ NOBREAK /* Special case */, /* None */ 157 #endif 158 /* Insert 49 */ E0PREFIX|0x52, /* E0 D2 */ 159 /* Home 4A */ E0PREFIX|0x47, /* E0 C7 */ 160 /* Page Up 4B */ E0PREFIX|0x49, /* E0 C9 */ 161 /* Delete 4C */ E0PREFIX|0x53, /* E0 D3 */ 162 /* End 4D */ E0PREFIX|0x4F, /* E0 CF */ 163 /* Page Down 4E */ E0PREFIX|0x51, /* E0 D1 */ 164 /* Right Arrow 4F */ E0PREFIX|0x4D, /* E0 CD */ 165 /* Left Arrow 50 */ E0PREFIX|0x4B, /* E0 CB */ 166 /* Down Arrow 51 */ E0PREFIX|0x50, /* E0 D0 */ 167 /* Up Arrow 52 */ E0PREFIX|0x48, /* E0 C8 */ 168 /* Num Lock 53 */ 0x45, /* C5 */ 169 /* Keypad / 54 */ E0PREFIX|0x35, /* E0 B5 */ 170 /* Keypad * 55 */ 0x37, /* B7 */ 171 /* Keypad - 56 */ 0x4A, /* CA */ 172 /* Keypad + 57 */ 0x4E, /* CE */ 173 /* Keypad Enter 58 */ E0PREFIX|0x1C, /* E0 9C */ 174 /* Keypad 1 End 59 */ 0x4F, /* CF */ 175 /* Keypad 2 Down 5A */ 0x50, /* D0 */ 176 /* Keypad 3 PageDn 5B */ 0x51, /* D1 */ 177 /* Keypad 4 Left 5C */ 0x4B, /* CB */ 178 /* Keypad 5 5D */ 0x4C, /* CC */ 179 /* Keypad 6 Right 5E */ 0x4D, /* CD */ 180 /* Keypad 7 Home 5F */ 0x47, /* C7 */ 181 /* Keypad 8 Up 60 */ 0x48, /* C8 */ 182 /* Keypad 9 PageUp 61 */ 0x49, /* C9 */ 183 /* Keypad 0 Insert 62 */ 0x52, /* D2 */ 184 /* Keypad . Delete 63 */ 0x53, /* D3 */ 185 /* Europe 2 64 */ 0x56, /* D6 */ 186 /* App 65 */ E0PREFIX|0x5D, /* E0 DD */ 187 /* Keyboard Power 66 */ E0PREFIX|0x5E, /* E0 DE */ 188 /* Keypad = 67 */ 0x59, /* D9 */ 189 /* F13 68 */ 0x64, /* E4 */ 190 /* F14 69 */ 0x65, /* E5 */ 191 /* F15 6A */ 0x66, /* E6 */ 192 /* F16 6B */ 0x67, /* E7 */ 193 /* F17 6C */ 0x68, /* E8 */ 194 /* F18 6D */ 0x69, /* E9 */ 195 /* F19 6E */ 0x6A, /* EA */ 196 /* F20 6F */ 0x6B, /* EB */ 197 /* F21 70 */ 0x6C, /* EC */ 198 /* F22 71 */ 0x6D, /* ED */ 199 /* F23 72 */ 0x6E, /* EE */ 200 /* F24 73 */ 0x76, /* F6 */ 201 /* Keyboard Execute 74 */ -1, /* Unassigned */ 202 /* Keyboard Help 75 */ -1, /* Unassigned */ 203 /* Keyboard Menu 76 */ -1, /* Unassigned */ 204 /* Keyboard Select 77 */ -1, /* Unassigned */ 205 /* Keyboard Stop 78 */ -1, /* Unassigned */ 206 /* Keyboard Again 79 */ -1, /* Unassigned */ 207 /* Keyboard Undo 7A */ -1, /* Unassigned */ 208 /* Keyboard Cut 7B */ -1, /* Unassigned */ 209 /* Keyboard Copy 7C */ -1, /* Unassigned */ 210 /* Keyboard Paste 7D */ -1, /* Unassigned */ 211 /* Keyboard Find 7E */ -1, /* Unassigned */ 212 /* Keyboard Mute 7F */ -1, /* Unassigned */ 213 /* Keyboard Volume Up 80 */ -1, /* Unassigned */ 214 /* Keyboard Volume Dn 81 */ -1, /* Unassigned */ 215 /* Keyboard Locking Caps Lock 82 */ -1, /* Unassigned */ 216 /* Keyboard Locking Num Lock 83 */ -1, /* Unassigned */ 217 /* Keyboard Locking Scroll Lock 84 */ -1, /* Unassigned */ 218 /* Keypad comma 85 */ 0x7E, /* FE */ 219 /* Keyboard Equal Sign 86 */ -1, /* Unassigned */ 220 /* Keyboard Int'l 1 87 */ 0x73, /* F3 */ 221 /* Keyboard Int'l 2 88 */ 0x70, /* F0 */ 222 /* Keyboard Int'l 2 89 */ 0x7D, /* FD */ 223 /* Keyboard Int'l 4 8A */ 0x79, /* F9 */ 224 /* Keyboard Int'l 5 8B */ 0x7B, /* FB */ 225 /* Keyboard Int'l 6 8C */ 0x5C, /* DC */ 226 /* Keyboard Int'l 7 8D */ -1, /* Unassigned */ 227 /* Keyboard Int'l 8 8E */ -1, /* Unassigned */ 228 /* Keyboard Int'l 9 8F */ -1, /* Unassigned */ 229 /* Keyboard Lang 1 90 */ 0x71, /* eisu */ 230 /* Keyboard Lang 2 91 */ 0x72, /* kana */ 231 /* Keyboard Lang 3 92 */ 0x78, /* F8 */ 232 /* Keyboard Lang 4 93 */ 0x77, /* F7 */ 233 /* Keyboard Lang 5 94 */ 0x76, /* F6 */ 234 /* Keyboard Lang 6 95 */ -1, /* Unassigned */ 235 /* Keyboard Lang 7 96 */ -1, /* Unassigned */ 236 /* Keyboard Lang 8 97 */ -1, /* Unassigned */ 237 /* Keyboard Lang 9 98 */ -1, /* Unassigned */ 238 /* Keyboard Alternate Erase 99 */ -1, /* Unassigned */ 239 /* Keyboard SysReq/Attention 9A */ -1, /* Unassigned */ 240 /* Keyboard Cancel 9B */ -1, /* Unassigned */ 241 /* Keyboard Clear 9C */ -1, /* Unassigned */ 242 /* Keyboard Prior 9D */ -1, /* Unassigned */ 243 /* Keyboard Return 9E */ -1, /* Unassigned */ 244 /* Keyboard Separator 9F */ -1, /* Unassigned */ 245 /* Keyboard Out A0 */ -1, /* Unassigned */ 246 /* Keyboard Oper A1 */ -1, /* Unassigned */ 247 /* Keyboard Clear/Again A2 */ -1, /* Unassigned */ 248 /* Keyboard CrSel/Props A3 */ -1, /* Unassigned */ 249 /* Keyboard ExSel A4 */ -1, /* Unassigned */ 250 /* Reserved A5 */ -1, /* Reserved */ 251 /* Reserved A6 */ -1, /* Reserved */ 252 /* Reserved A7 */ -1, /* Reserved */ 253 /* Reserved A8 */ -1, /* Reserved */ 254 /* Reserved A9 */ -1, /* Reserved */ 255 /* Reserved AA */ -1, /* Reserved */ 256 /* Reserved AB */ -1, /* Reserved */ 257 /* Reserved AC */ -1, /* Reserved */ 258 /* Reserved AD */ -1, /* Reserved */ 259 /* Reserved AE */ -1, /* Reserved */ 260 /* Reserved AF */ -1, /* Reserved */ 261 /* Reserved B0 */ -1, /* Reserved */ 262 /* Reserved B1 */ -1, /* Reserved */ 263 /* Reserved B2 */ -1, /* Reserved */ 264 /* Reserved B3 */ -1, /* Reserved */ 265 /* Reserved B4 */ -1, /* Reserved */ 266 /* Reserved B5 */ -1, /* Reserved */ 267 /* Reserved B6 */ -1, /* Reserved */ 268 /* Reserved B7 */ -1, /* Reserved */ 269 /* Reserved B8 */ -1, /* Reserved */ 270 /* Reserved B9 */ -1, /* Reserved */ 271 /* Reserved BA */ -1, /* Reserved */ 272 /* Reserved BB */ -1, /* Reserved */ 273 /* Reserved BC */ -1, /* Reserved */ 274 /* Reserved BD */ -1, /* Reserved */ 275 /* Reserved BE */ -1, /* Reserved */ 276 /* Reserved BF */ -1, /* Reserved */ 277 /* Reserved C0 */ -1, /* Reserved */ 278 /* Reserved C1 */ -1, /* Reserved */ 279 /* Reserved C2 */ -1, /* Reserved */ 280 /* Reserved C3 */ -1, /* Reserved */ 281 /* Reserved C4 */ -1, /* Reserved */ 282 /* Reserved C5 */ -1, /* Reserved */ 283 /* Reserved C6 */ -1, /* Reserved */ 284 /* Reserved C7 */ -1, /* Reserved */ 285 /* Reserved C8 */ -1, /* Reserved */ 286 /* Reserved C9 */ -1, /* Reserved */ 287 /* Reserved CA */ -1, /* Reserved */ 288 /* Reserved CB */ -1, /* Reserved */ 289 /* Reserved CC */ -1, /* Reserved */ 290 /* Reserved CD */ -1, /* Reserved */ 291 /* Reserved CE */ -1, /* Reserved */ 292 /* Reserved CF */ -1, /* Reserved */ 293 /* Reserved D0 */ -1, /* Reserved */ 294 /* Reserved D1 */ -1, /* Reserved */ 295 /* Reserved D2 */ -1, /* Reserved */ 296 /* Reserved D3 */ -1, /* Reserved */ 297 /* Reserved D4 */ -1, /* Reserved */ 298 /* Reserved D5 */ -1, /* Reserved */ 299 /* Reserved D6 */ -1, /* Reserved */ 300 /* Reserved D7 */ -1, /* Reserved */ 301 /* Reserved D8 */ -1, /* Reserved */ 302 /* Reserved D9 */ -1, /* Reserved */ 303 /* Reserved DA */ -1, /* Reserved */ 304 /* Reserved DB */ -1, /* Reserved */ 305 /* Reserved DC */ -1, /* Reserved */ 306 /* Reserved DD */ -1, /* Reserved */ 307 /* Reserved DE */ -1, /* Reserved */ 308 /* Reserved DF */ -1, /* Reserved */ 309 /* Left Control E0 */ 0x1D, /* 9D */ 310 /* Left Shift E1 */ 0x2A, /* AA */ 311 /* Left Alt E2 */ 0x38, /* B8 */ 312 /* Left GUI E3 */ E0PREFIX|0x5B, /* E0 DB */ 313 /* Right Control E4 */ E0PREFIX|0x1D, /* E0 9D */ 314 /* Right Shift E5 */ 0x36, /* B6 */ 315 /* Right Alt E6 */ E0PREFIX|0x38, /* E0 B8 */ 316 /* Right GUI E7 */ E0PREFIX|0x5C /* E0 DC */ 317 }; 318 319 #define xsize ((int32_t)(sizeof(x)/sizeof(x[0]))) 320 321 /* 322 * Get a max HID keycode (aligned) 323 */ 324 325 int32_t 326 kbd_maxkey(void) 327 { 328 return (xsize); 329 } 330 331 /* 332 * Process keys 333 */ 334 335 int32_t 336 kbd_process_keys(bthid_session_p s) 337 { 338 bitstr_t diff[bitstr_size(xsize)]; 339 int32_t f1, f2, i; 340 341 assert(s != NULL); 342 assert(s->srv != NULL); 343 344 /* Check if the new keys have been pressed */ 345 bit_ffs(s->keys1, xsize, &f1); 346 347 /* Check if old keys still pressed */ 348 bit_ffs(s->keys2, xsize, &f2); 349 350 if (f1 == -1) { 351 /* no new key pressed */ 352 if (f2 != -1) { 353 /* release old keys */ 354 kbd_write(s->keys2, f2, 0, s->vkbd); 355 memset(s->keys2, 0, bitstr_size(xsize)); 356 } 357 358 return (0); 359 } 360 361 if (f2 == -1) { 362 /* no old keys, but new keys pressed */ 363 assert(f1 != -1); 364 365 memcpy(s->keys2, s->keys1, bitstr_size(xsize)); 366 kbd_write(s->keys1, f1, 1, s->vkbd); 367 memset(s->keys1, 0, bitstr_size(xsize)); 368 369 return (0); 370 } 371 372 /* new keys got pressed, old keys got released */ 373 memset(diff, 0, bitstr_size(xsize)); 374 375 for (i = f2; i < xsize; i ++) { 376 if (bit_test(s->keys2, i)) { 377 if (!bit_test(s->keys1, i)) { 378 bit_clear(s->keys2, i); 379 bit_set(diff, i); 380 } 381 } 382 } 383 384 for (i = f1; i < xsize; i++) { 385 if (bit_test(s->keys1, i)) { 386 if (!bit_test(s->keys2, i)) 387 bit_set(s->keys2, i); 388 else 389 bit_clear(s->keys1, i); 390 } 391 } 392 393 bit_ffs(diff, xsize, &f2); 394 if (f2 > 0) 395 kbd_write(diff, f2, 0, s->vkbd); 396 397 bit_ffs(s->keys1, xsize, &f1); 398 if (f1 > 0) { 399 kbd_write(s->keys1, f1, 1, s->vkbd); 400 memset(s->keys1, 0, bitstr_size(xsize)); 401 } 402 403 return (0); 404 } 405 406 /* 407 * Translate given keymap and write keyscodes 408 */ 409 410 static void 411 kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd) 412 { 413 int32_t i, *b, *eob, n, buf[64]; 414 415 b = buf; 416 eob = b + sizeof(buf)/sizeof(buf[0]); 417 i = fb; 418 419 while (i < xsize) { 420 if (bit_test(m, i)) { 421 n = kbd_xlate(i, make, b, eob); 422 if (n == -1) { 423 write(fd, buf, (b - buf) * sizeof(buf[0])); 424 b = buf; 425 continue; 426 } 427 428 b += n; 429 } 430 431 i ++; 432 } 433 434 if (b != buf) 435 write(fd, buf, (b - buf) * sizeof(buf[0])); 436 } 437 438 /* 439 * Translate HID code into PS/2 code and put codes into buffer b. 440 * Returns the number of codes put in b. Return -1 if buffer has not 441 * enough space. 442 */ 443 444 #undef PUT 445 #define PUT(c, n, b, eob) \ 446 do { \ 447 if ((b) >= (eob)) \ 448 return (-1); \ 449 *(b) = (c); \ 450 (b) ++; \ 451 (n) ++; \ 452 } while (0) 453 454 static int32_t 455 kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob) 456 { 457 int32_t c, n; 458 459 n = 0; 460 461 if (code >= xsize) 462 return (0); /* HID code is not in the table */ 463 464 /* Handle special case - Pause/Break */ 465 if (code == 0x48) { 466 if (!make) 467 return (0); /* No break code */ 468 469 #if 0 470 XXX FIXME 471 if (ctrl_is_pressed) { 472 /* Break (Ctrl-Pause) */ 473 PUT(0xe0, n, b, eob); 474 PUT(0x46, n, b, eob); 475 PUT(0xe0, n, b, eob); 476 PUT(0xc6, n, b, eob); 477 } else { 478 /* Pause */ 479 PUT(0xe1, n, b, eob); 480 PUT(0x1d, n, b, eob); 481 PUT(0x45, n, b, eob); 482 PUT(0xe1, n, b, eob); 483 PUT(0x9d, n, b, eob); 484 PUT(0xc5, n, b, eob); 485 } 486 #endif 487 488 return (n); 489 } 490 491 if ((c = x[code]) == -1) 492 return (0); /* HID code translation is not defined */ 493 494 if (make) { 495 if (c & E0PREFIX) 496 PUT(0xe0, n, b, eob); 497 498 PUT((c & CODEMASK), n, b, eob); 499 } else if (!(c & NOBREAK)) { 500 if (c & E0PREFIX) 501 PUT(0xe0, n, b, eob); 502 503 PUT((0x80|(c & CODEMASK)), n, b, eob); 504 } 505 506 return (n); 507 } 508 509 /* 510 * Process status change from vkbd(4) 511 */ 512 513 int32_t 514 kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len) 515 { 516 vkbd_status_t st; 517 uint8_t leds, report_id; 518 hid_device_p hid_device; 519 hid_data_t d; 520 hid_item_t h; 521 522 assert(s != NULL); 523 assert(len == sizeof(vkbd_status_t)); 524 525 memcpy(&st, data, sizeof(st)); 526 leds = 0; 527 report_id = NO_REPORT_ID; 528 529 hid_device = get_hid_device(&s->bdaddr); 530 assert(hid_device != NULL); 531 532 for (d = hid_start_parse(hid_device->desc, 1 << hid_output, -1); 533 hid_get_item(d, &h) > 0; ) { 534 if (HID_PAGE(h.usage) == HUP_LEDS) { 535 if (report_id == NO_REPORT_ID) 536 report_id = h.report_ID; 537 else if (h.report_ID != report_id) 538 syslog(LOG_WARNING, "Output HID report IDs " \ 539 "for %s do not match: %d vs. %d. " \ 540 "Please report", 541 bt_ntoa(&s->bdaddr, NULL), 542 h.report_ID, report_id); 543 544 switch(HID_USAGE(h.usage)) { 545 case 0x01: /* Num Lock LED */ 546 if (st.leds & LED_NUM) 547 hid_set_data(&leds, &h, 1); 548 break; 549 550 case 0x02: /* Caps Lock LED */ 551 if (st.leds & LED_CAP) 552 hid_set_data(&leds, &h, 1); 553 break; 554 555 case 0x03: /* Scroll Lock LED */ 556 if (st.leds & LED_SCR) 557 hid_set_data(&leds, &h, 1); 558 break; 559 560 /* XXX add other LEDs ? */ 561 } 562 } 563 } 564 hid_end_parse(d); 565 566 data[0] = 0xa2; /* DATA output (HID output report) */ 567 568 if (report_id != NO_REPORT_ID) { 569 data[1] = report_id; 570 data[2] = leds; 571 len = 3; 572 } else { 573 data[1] = leds; 574 len = 2; 575 } 576 577 write(s->intr, data, len); 578 579 return (0); 580 } 581 582