kbd.c revision 155858
1/*
2 * kbd.c
3 *
4 * Copyright (c) 2004 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
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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 *
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 */
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>
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>
48#include "bthidd.h"
49#include "kbd.h"
50
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);
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
67static int 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 */
76/* a A                          04 */ 0x1E, /* 9E */
77/* b B                          05 */ 0x30, /* B0 */
78/* c C                          06 */ 0x2E, /* AE */
79/* d D                          07 */ 0x20, /* A0 */
80/* e E                          08 */ 0x12, /* 92 */
81/* f F                          09 */ 0x21, /* A1 */
82/* g G                          0A */ 0x22, /* A2 */
83/* h H                          0B */ 0x23, /* A3 */
84/* i I                          0C */ 0x17, /* 97 */
85/* j J                          0D */ 0x24, /* A4 */
86/* k K                          0E */ 0x25, /* A5 */
87/* l L                          0F */ 0x26, /* A6 */
88/* m M                          10 */ 0x32, /* B2 */
89/* n N                          11 */ 0x31, /* B1 */
90/* o O                          12 */ 0x18, /* 98 */
91/* p P                          13 */ 0x19, /* 99 */
92/* q Q                          14 */ 0x10, /* 90 */
93/* r R                          15 */ 0x13, /* 93 */
94/* s S                          16 */ 0x1F, /* 9F */
95/* t T                          17 */ 0x14, /* 94 */
96/* u U                          18 */ 0x16, /* 96 */
97/* v V                          19 */ 0x2F, /* AF */
98/* w W                          1A */ 0x11, /* 91 */
99/* x X                          1B */ 0x2D, /* AD */
100/* y Y                          1C */ 0x15, /* 95 */
101/* z Z                          1D */ 0x2C, /* AC */
102/* 1 !                          1E */ 0x02, /* 82 */
103/* 2 @                          1F */ 0x03, /* 83 */
104/* 3 #                          20 */ 0x04, /* 84 */
105/* 4 $                          21 */ 0x05, /* 85 */
106/* 5 %                          22 */ 0x06, /* 86 */
107/* 6 ^                          23 */ 0x07, /* 87 */
108/* 7 &                          24 */ 0x08, /* 88 */
109/* 8 *                          25 */ 0x09, /* 89 */
110/* 9 (                          26 */ 0x0A, /* 8A */
111/* 0 )                          27 */ 0x0B, /* 8B */
112/* Return                       28 */ 0x1C, /* 9C */
113/* Escape                       29 */ 0x01, /* 81 */
114/* Backspace                    2A */ 0x0E, /* 8E */
115/* Tab                          2B */ 0x0F, /* 8F */
116/* Space                        2C */ 0x39, /* B9 */
117/* - _                          2D */ 0x0C, /* 8C */
118/* = +                          2E */ 0x0D, /* 8D */
119/* [ {                          2F */ 0x1A, /* 9A */
120/* ] }                          30 */ 0x1B, /* 9B */
121/* \ |                          31 */ 0x2B, /* AB */
122/* Europe 1                     32 */ 0x2B, /* AB */
123/* ; :                          33 */ 0x27, /* A7 */
124/* " '                          34 */ 0x28, /* A8 */
125/* ` ~                          35 */ 0x29, /* A9 */
126/* comma <                      36 */ 0x33, /* B3 */
127/* . >                          37 */ 0x34, /* B4 */
128/* / ?                          38 */ 0x35, /* B5 */
129/* Caps Lock                    39 */ 0x3A, /* BA */
130/* F1                           3A */ 0x3B, /* BB */
131/* F2                           3B */ 0x3C, /* BC */
132/* F3                           3C */ 0x3D, /* BD */
133/* F4                           3D */ 0x3E, /* BE */
134/* F5                           3E */ 0x3F, /* BF */
135/* F6                           3F */ 0x40, /* C0 */
136/* F7                           40 */ 0x41, /* C1 */
137/* F8                           41 */ 0x42, /* C2 */
138/* F9                           42 */ 0x43, /* C3 */
139/* F10                          43 */ 0x44, /* C4 */
140/* F11                          44 */ 0x57, /* D7 */
141/* F12                          45 */ 0x58, /* D8 */
142/* Print Screen                 46 */ E0PREFIX|0x37, /* E0 B7 */
143/* Scroll Lock                  47 */ 0x46, /* C6 */
144#if 0
145/* Break (Ctrl-Pause)           48 */ E0 46 E0 C6, /* None */
146/* Pause                        48 */ E1 1D 45 E1 9D C5, /* None */
147#else
148/* Break (Ctrl-Pause)/Pause     48 */ NOBREAK /* Special case */, /* None */
149#endif
150/* Insert                       49 */ E0PREFIX|0x52, /* E0 D2 */
151/* Home                         4A */ E0PREFIX|0x47, /* E0 C7 */
152/* Page Up                      4B */ E0PREFIX|0x49, /* E0 C9 */
153/* Delete                       4C */ E0PREFIX|0x53, /* E0 D3 */
154/* End                          4D */ E0PREFIX|0x4F, /* E0 CF */
155/* Page Down                    4E */ E0PREFIX|0x51, /* E0 D1 */
156/* Right Arrow                  4F */ E0PREFIX|0x4D, /* E0 CD */
157/* Left Arrow                   50 */ E0PREFIX|0x4B, /* E0 CB */
158/* Down Arrow                   51 */ E0PREFIX|0x50, /* E0 D0 */
159/* Up Arrow                     52 */ E0PREFIX|0x48, /* E0 C8 */
160/* Num Lock                     53 */ 0x45, /* C5 */
161/* Keypad /                     54 */ E0PREFIX|0x35, /* E0 B5 */
162/* Keypad *                     55 */ 0x37, /* B7 */
163/* Keypad -                     56 */ 0x4A, /* CA */
164/* Keypad +                     57 */ 0x4E, /* CE */
165/* Keypad Enter                 58 */ E0PREFIX|0x1C, /* E0 9C */
166/* Keypad 1 End                 59 */ 0x4F, /* CF */
167/* Keypad 2 Down                5A */ 0x50, /* D0 */
168/* Keypad 3 PageDn              5B */ 0x51, /* D1 */
169/* Keypad 4 Left                5C */ 0x4B, /* CB */
170/* Keypad 5                     5D */ 0x4C, /* CC */
171/* Keypad 6 Right               5E */ 0x4D, /* CD */
172/* Keypad 7 Home                5F */ 0x47, /* C7 */
173/* Keypad 8 Up                  60 */ 0x48, /* C8 */
174/* Keypad 9 PageUp              61 */ 0x49, /* C9 */
175/* Keypad 0 Insert              62 */ 0x52, /* D2 */
176/* Keypad . Delete              63 */ 0x53, /* D3 */
177/* Europe 2                     64 */ 0x56, /* D6 */
178/* App                          65 */ E0PREFIX|0x5D, /* E0 DD */
179/* Keyboard Power               66 */ E0PREFIX|0x5E, /* E0 DE */
180/* Keypad =                     67 */ 0x59, /* D9 */
181/* F13                          68 */ 0x64, /* E4 */
182/* F14                          69 */ 0x65, /* E5 */
183/* F15                          6A */ 0x66, /* E6 */
184/* F16                          6B */ 0x67, /* E7 */
185/* F17                          6C */ 0x68, /* E8 */
186/* F18                          6D */ 0x69, /* E9 */
187/* F19                          6E */ 0x6A, /* EA */
188/* F20                          6F */ 0x6B, /* EB */
189/* F21                          70 */ 0x6C, /* EC */
190/* F22                          71 */ 0x6D, /* ED */
191/* F23                          72 */ 0x6E, /* EE */
192/* F24                          73 */ 0x76, /* F6 */
193/* Keyboard Execute             74 */ -1,   /* Unassigned */
194/* Keyboard Help                75 */ -1,   /* Unassigned */
195/* Keyboard Menu                76 */ -1,   /* Unassigned */
196/* Keyboard Select              77 */ -1,   /* Unassigned */
197/* Keyboard Stop                78 */ -1,   /* Unassigned */
198/* Keyboard Again               79 */ -1,   /* Unassigned */
199/* Keyboard Undo                7A */ -1,   /* Unassigned */
200/* Keyboard Cut                 7B */ -1,   /* Unassigned */
201/* Keyboard Copy                7C */ -1,   /* Unassigned */
202/* Keyboard Paste               7D */ -1,   /* Unassigned */
203/* Keyboard Find                7E */ -1,   /* Unassigned */
204/* Keyboard Mute                7F */ -1,   /* Unassigned */
205/* Keyboard Volume Up           80 */ -1,   /* Unassigned */
206/* Keyboard Volume Dn           81 */ -1,   /* Unassigned */
207/* Keyboard Locking Caps Lock   82 */ -1,   /* Unassigned */
208/* Keyboard Locking Num Lock    83 */ -1,   /* Unassigned */
209/* Keyboard Locking Scroll Lock 84 */ -1,   /* Unassigned */
210/* Keypad comma                 85 */ 0x7E, /* FE */
211/* Keyboard Equal Sign          86 */ -1,   /* Unassigned */
212/* Keyboard Int'l 1             87 */ 0x73, /* F3 */
213/* Keyboard Int'l 2             88 */ 0x70, /* F0 */
214/* Keyboard Int'l 2             89 */ 0x7D, /* FD */
215/* Keyboard Int'l 4             8A */ 0x79, /* F9 */
216/* Keyboard Int'l 5             8B */ 0x7B, /* FB */
217/* Keyboard Int'l 6             8C */ 0x5C, /* DC */
218/* Keyboard Int'l 7             8D */ -1,   /* Unassigned */
219/* Keyboard Int'l 8             8E */ -1,   /* Unassigned */
220/* Keyboard Int'l 9             8F */ -1,   /* Unassigned */
221/* Keyboard Lang 1              90 */ NOBREAK|0xF2, /* None */
222/* Keyboard Lang 2              91 */ NOBREAK|0xF1, /* None */
223/* Keyboard Lang 3              92 */ 0x78, /* F8 */
224/* Keyboard Lang 4              93 */ 0x77, /* F7 */
225/* Keyboard Lang 5              94 */ 0x76, /* F6 */
226/* Keyboard Lang 6              95 */ -1,   /* Unassigned */
227/* Keyboard Lang 7              96 */ -1,   /* Unassigned */
228/* Keyboard Lang 8              97 */ -1,   /* Unassigned */
229/* Keyboard Lang 9              98 */ -1,   /* Unassigned */
230/* Keyboard Alternate Erase     99 */ -1,   /* Unassigned */
231/* Keyboard SysReq/Attention    9A */ -1,   /* Unassigned */
232/* Keyboard Cancel              9B */ -1,   /* Unassigned */
233/* Keyboard Clear               9C */ -1,   /* Unassigned */
234/* Keyboard Prior               9D */ -1,   /* Unassigned */
235/* Keyboard Return              9E */ -1,   /* Unassigned */
236/* Keyboard Separator           9F */ -1,   /* Unassigned */
237/* Keyboard Out                 A0 */ -1,   /* Unassigned */
238/* Keyboard Oper                A1 */ -1,   /* Unassigned */
239/* Keyboard Clear/Again         A2 */ -1,   /* Unassigned */
240/* Keyboard CrSel/Props         A3 */ -1,   /* Unassigned */
241/* Keyboard ExSel               A4 */ -1,   /* Unassigned */
242/* Reserved                     A5 */ -1,   /* Reserved */
243/* Reserved                     A6 */ -1,   /* Reserved */
244/* Reserved                     A7 */ -1,   /* Reserved */
245/* Reserved                     A8 */ -1,   /* Reserved */
246/* Reserved                     A9 */ -1,   /* Reserved */
247/* Reserved                     AA */ -1,   /* Reserved */
248/* Reserved                     AB */ -1,   /* Reserved */
249/* Reserved                     AC */ -1,   /* Reserved */
250/* Reserved                     AD */ -1,   /* Reserved */
251/* Reserved                     AE */ -1,   /* Reserved */
252/* Reserved                     AF */ -1,   /* Reserved */
253/* Reserved                     B0 */ -1,   /* Reserved */
254/* Reserved                     B1 */ -1,   /* Reserved */
255/* Reserved                     B2 */ -1,   /* Reserved */
256/* Reserved                     B3 */ -1,   /* Reserved */
257/* Reserved                     B4 */ -1,   /* Reserved */
258/* Reserved                     B5 */ -1,   /* Reserved */
259/* Reserved                     B6 */ -1,   /* Reserved */
260/* Reserved                     B7 */ -1,   /* Reserved */
261/* Reserved                     B8 */ -1,   /* Reserved */
262/* Reserved                     B9 */ -1,   /* Reserved */
263/* Reserved                     BA */ -1,   /* Reserved */
264/* Reserved                     BB */ -1,   /* Reserved */
265/* Reserved                     BC */ -1,   /* Reserved */
266/* Reserved                     BD */ -1,   /* Reserved */
267/* Reserved                     BE */ -1,   /* Reserved */
268/* Reserved                     BF */ -1,   /* Reserved */
269/* Reserved                     C0 */ -1,   /* Reserved */
270/* Reserved                     C1 */ -1,   /* Reserved */
271/* Reserved                     C2 */ -1,   /* Reserved */
272/* Reserved                     C3 */ -1,   /* Reserved */
273/* Reserved                     C4 */ -1,   /* Reserved */
274/* Reserved                     C5 */ -1,   /* Reserved */
275/* Reserved                     C6 */ -1,   /* Reserved */
276/* Reserved                     C7 */ -1,   /* Reserved */
277/* Reserved                     C8 */ -1,   /* Reserved */
278/* Reserved                     C9 */ -1,   /* Reserved */
279/* Reserved                     CA */ -1,   /* Reserved */
280/* Reserved                     CB */ -1,   /* Reserved */
281/* Reserved                     CC */ -1,   /* Reserved */
282/* Reserved                     CD */ -1,   /* Reserved */
283/* Reserved                     CE */ -1,   /* Reserved */
284/* Reserved                     CF */ -1,   /* Reserved */
285/* Reserved                     D0 */ -1,   /* Reserved */
286/* Reserved                     D1 */ -1,   /* Reserved */
287/* Reserved                     D2 */ -1,   /* Reserved */
288/* Reserved                     D3 */ -1,   /* Reserved */
289/* Reserved                     D4 */ -1,   /* Reserved */
290/* Reserved                     D5 */ -1,   /* Reserved */
291/* Reserved                     D6 */ -1,   /* Reserved */
292/* Reserved                     D7 */ -1,   /* Reserved */
293/* Reserved                     D8 */ -1,   /* Reserved */
294/* Reserved                     D9 */ -1,   /* Reserved */
295/* Reserved                     DA */ -1,   /* Reserved */
296/* Reserved                     DB */ -1,   /* Reserved */
297/* Reserved                     DC */ -1,   /* Reserved */
298/* Reserved                     DD */ -1,   /* Reserved */
299/* Reserved                     DE */ -1,   /* Reserved */
300/* Reserved                     DF */ -1,   /* Reserved */
301/* Left Control                 E0 */ 0x1D, /* 9D */
302/* Left Shift                   E1 */ 0x2A, /* AA */
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
311#define xsize	(sizeof(x)/sizeof(x[0]))
312
313/*
314 * Get a max HID keycode (aligned)
315 */
316
317int
318kbd_maxkey(void)
319{
320	return (xsize);
321}
322
323/*
324 * Process keys
325 */
326
327int
328kbd_process_keys(bthid_session_p s)
329{
330	bitstr_t	r[bitstr_size(xsize)];
331	int		f0, f1, i;
332
333	assert(s != NULL);
334	assert(s->srv != NULL);
335
336	bit_ffs(s->srv->keys, xsize, &f0);
337	bit_ffs(s->keys, xsize, &f1);
338
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));
344		}
345
346		return (0);
347	}
348
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		}
356
357		return (0);
358	}
359
360	/* some keys got pressed, some keys got released */
361	memset(r, 0, bitstr_size(xsize));
362
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);
370		}
371	}
372
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);
377			else
378				bit_clear(s->srv->keys, i);
379		}
380	}
381
382	bit_ffs(r, xsize, &f0);
383	bit_ffs(s->srv->keys, xsize, &f1);
384
385	if (f0 > 0)
386		kbd_write(r, f0, 0, s->srv->vkbd);
387
388	if (f1 > 0) {
389		kbd_write(s->srv->keys, f1, 1, s->srv->vkbd);
390		memset(s->srv->keys, 0, bitstr_size(xsize));
391	}
392
393	return (0);
394}
395
396/*
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
495kbd_write(bitstr_t *m, int fb, int make, int fd)
496{
497	int	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);
506			if (n == -1) {
507				write(fd, buf, (b - buf) * sizeof(buf[0]));
508				b = buf;
509				continue;
510			}
511
512			b += n;
513		}
514
515		i ++;
516	}
517
518	if (b != buf)
519		write(fd, buf, (b - buf) * sizeof(buf[0]));
520}
521
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
539static int
540kbd_xlate(int code, int make, int *b, int const *eob)
541{
542	int	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) {
551		if (!make)
552			return (0); /* No break code */
553
554#if 0
555XXX FIXME
556		if (ctrl_is_pressed) {
557			/* Break (Ctrl-Pause) */
558			PUT(0xe0, n, b, eob);
559			PUT(0x46, n, b, eob);
560			PUT(0xe0, n, b, eob);
561			PUT(0xc6, n, b, eob);
562		} else {
563			/* Pause */
564			PUT(0xe1, n, b, eob);
565			PUT(0x1d, n, b, eob);
566			PUT(0x45, n, b, eob);
567			PUT(0xe1, n, b, eob);
568			PUT(0x9d, n, b, eob);
569			PUT(0xc5, n, b, eob);
570		}
571#endif
572
573		return (n);
574	}
575
576	if ((c = x[code]) == -1)
577		return (0); /* HID code translation is not defined */
578
579	if (make) {
580		if (c & E0PREFIX)
581			PUT(0xe0, n, b, eob);
582
583		PUT((c & CODEMASK), n, b, eob);
584	} else if (!(c & NOBREAK)) {
585		if (c & E0PREFIX)
586			PUT(0xe0, n, b, eob);
587
588		PUT((0x80|(c & CODEMASK)), n, b, eob);
589	}
590
591	return (n);
592}
593
594