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