First import
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / input / lnx-keyboard.c
blob42a807b1132daa89b05bbb448216be953c6d5a15
1 /* Portions of this file were derived from the following files:
3 **********************************************************************
5 * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c}
7 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
9 * Permission to use, copy, modify, distribute, and sell this software and its
10 * documentation for any purpose is hereby granted without fee, provided that
11 * the above copyright notice appear in all copies and that both that
12 * copyright notice and this permission notice appear in supporting
13 * documentation, and that the name of Thomas Roell not be used in
14 * advertising or publicity pertaining to distribution of the software without
15 * specific, written prior permission. Thomas Roell makes no representations
16 * about the suitability of this software for any purpose. It is provided
17 * "as is" without express or implied warranty.
19 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
21 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
23 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
24 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25 * PERFORMANCE OF THIS SOFTWARE.
27 **********************************************************************
29 * xfree86/common/xf86KbdLnx.c
31 * Linux version of keymapping setup. The kernel (since 0.99.14) has support
32 * for fully remapping the keyboard, but there are some differences between
33 * the Linux map and the SVR4 map (esp. in the extended keycodes). We also
34 * remove the restriction on what keycodes can be remapped.
35 * Orest Zborowski.
37 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
39 * Permission to use, copy, modify, distribute, and sell this software and its
40 * documentation for any purpose is hereby granted without fee, provided that
41 * the above copyright notice appear in all copies and that both that
42 * copyright notice and this permission notice appear in supporting
43 * documentation, and that the name of Thomas Roell not be used in
44 * advertising or publicity pertaining to distribution of the software without
45 * specific, written prior permission. Thomas Roell makes no representations
46 * about the suitability of this software for any purpose. It is provided
47 * "as is" without express or implied warranty.
49 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
50 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
51 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
52 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
53 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
54 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
55 * PERFORMANCE OF THIS SOFTWARE.
57 **********************************************************************
59 * xfree86/os-support/linux/lnx_io.c
61 * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
62 * Copyright 1993 by David Dawes <dawes@xfree86.org>
64 * Permission to use, copy, modify, distribute, and sell this software and its
65 * documentation for any purpose is hereby granted without fee, provided that
66 * the above copyright notice appear in all copies and that both that
67 * copyright notice and this permission notice appear in supporting
68 * documentation, and that the names of Orest Zborowski and David Dawes
69 * not be used in advertising or publicity pertaining to distribution of
70 * the software without specific, written prior permission. Orest Zborowski
71 * and David Dawes make no representations about the suitability of this
72 * software for any purpose. It is provided "as is" without express or
73 * implied warranty.
75 * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD
76 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
77 * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES BE LIABLE
78 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
79 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
80 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
81 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
86 * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
88 * All Rights Reserved.
90 * Permission is hereby granted, free of charge, to any person obtaining
91 * a copy of this software and associated documentation files (the
92 * "Software"), to deal in the Software without restriction, including
93 * without limitation on the rights to use, copy, modify, merge,
94 * publish, distribute, sublicense, and/or sell copies of the Software,
95 * and to permit persons to whom the Software is furnished to do so,
96 * subject to the following conditions:
98 * The above copyright notice and this permission notice (including the
99 * next paragraph) shall be included in all copies or substantial
100 * portions of the Software.
102 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
103 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
104 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
105 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
106 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
107 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
108 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
109 * SOFTWARE.
113 * Authors:
114 * Rickard E. (Rik) Faith <faith@redhat.com>
118 /** \file
120 * This code implements a low-level device driver for the Linux
121 * keyboard. The code is derived from code by Thomas Roell, Orest
122 * Zborowski, and David Dawes (see the source code for complete
123 * references). */
125 #ifdef HAVE_DMX_CONFIG_H
126 #include <dmx-config.h>
127 #endif
129 /*****************************************************************************/
130 /* Define some macros to make it easier to move this file to another
131 * part of the Xserver tree. All calls to the dmx* layer are #defined
132 * here for the .c file. The .h file will also have to be edited. */
133 #include "dmxinputinit.h"
134 #include "lnx-keyboard.h"
136 #define GETPRIV myPrivate *priv \
137 = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private
139 #define LOG0(f) dmxLog(dmxDebug,f)
140 #define LOG1(f,a) dmxLog(dmxDebug,f,a)
141 #define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b)
142 #define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
143 #define FATAL0(f) dmxLog(dmxFatal,f)
144 #define FATAL1(f,a) dmxLog(dmxFatal,f,a)
145 #define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b)
146 #define MOTIONPROC dmxMotionProcPtr
147 #define ENQUEUEPROC dmxEnqueueProcPtr
148 #define CHECKPROC dmxCheckSpecialProcPtr
149 #define SWITCHRETPROC dmxVTSwitchReturnProcPtr
150 #define BLOCK DMXBlockType
151 #define MESSAGE "\033c\n\n\nDMX taking input from this console..."
152 #define FINALMESSAGE "\033cDMX terminated."
154 /* End of interface definitions. */
155 /*****************************************************************************/
157 #include "inputstr.h"
158 #include <X11/Xos.h>
159 #include <sys/ioctl.h>
160 #include <errno.h>
161 #include <signal.h>
162 #include <sys/vt.h>
163 #include <sys/kd.h>
164 #include <termios.h>
165 #include "atKeynames.h"
166 #if 00
167 #include "xf86Keymap.h"
168 #endif
169 #include <linux/keyboard.h>
171 #define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0]))
172 #define NUM_STATE_ENTRIES (256/32)
175 /* Private area for Linux-style keyboards. */
176 typedef struct _myPrivate {
177 int fd;
178 int vtno;
179 int vtcurrent;
180 int kbdtrans;
181 struct termios kbdtty;
182 int kbdType;
183 CARD32 kbdState[NUM_STATE_ENTRIES];
184 DeviceIntPtr pKeyboard;
185 unsigned char prefix;
187 int switched;
188 SWITCHRETPROC switch_return;
189 void *switch_return_data;
191 /* For bell */
192 int pitch;
193 unsigned long duration;
194 } myPrivate;
196 static myPrivate *PRIV = NULL;
198 #undef SYSCALL
199 #define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
201 static int kbdLinuxKeyDown(myPrivate *priv, int keyCode)
203 CARD8 byte = keyCode >> 5;
204 CARD32 bit = 1 << (keyCode & 0x1f);
206 if (byte > NUM_STATE_ENTRIES) return 0;
207 return priv->kbdState[byte] & bit;
210 static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode)
212 CARD8 byte = keyCode >> 5;
213 CARD32 bit = 1 << (keyCode & 0x1f);
215 if (byte > NUM_STATE_ENTRIES) return;
216 if (type == KeyPress) priv->kbdState[byte] |= bit;
217 else priv->kbdState[byte] &= ~bit;
220 static KeySym linux_to_x[256] = {
221 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
222 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
223 XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol,
224 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
225 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
226 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
227 NoSymbol, NoSymbol, NoSymbol, XK_Escape,
228 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
229 XK_space, XK_exclam, XK_quotedbl, XK_numbersign,
230 XK_dollar, XK_percent, XK_ampersand, XK_apostrophe,
231 XK_parenleft, XK_parenright, XK_asterisk, XK_plus,
232 XK_comma, XK_minus, XK_period, XK_slash,
233 XK_0, XK_1, XK_2, XK_3,
234 XK_4, XK_5, XK_6, XK_7,
235 XK_8, XK_9, XK_colon, XK_semicolon,
236 XK_less, XK_equal, XK_greater, XK_question,
237 XK_at, XK_A, XK_B, XK_C,
238 XK_D, XK_E, XK_F, XK_G,
239 XK_H, XK_I, XK_J, XK_K,
240 XK_L, XK_M, XK_N, XK_O,
241 XK_P, XK_Q, XK_R, XK_S,
242 XK_T, XK_U, XK_V, XK_W,
243 XK_X, XK_Y, XK_Z, XK_bracketleft,
244 XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore,
245 XK_grave, XK_a, XK_b, XK_c,
246 XK_d, XK_e, XK_f, XK_g,
247 XK_h, XK_i, XK_j, XK_k,
248 XK_l, XK_m, XK_n, XK_o,
249 XK_p, XK_q, XK_r, XK_s,
250 XK_t, XK_u, XK_v, XK_w,
251 XK_x, XK_y, XK_z, XK_braceleft,
252 XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace,
253 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
254 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
255 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
256 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
257 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
258 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
259 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
260 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
261 XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling,
262 XK_currency, XK_yen, XK_brokenbar, XK_section,
263 XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft,
264 XK_notsign, XK_hyphen, XK_registered, XK_macron,
265 XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior,
266 XK_acute, XK_mu, XK_paragraph, XK_periodcentered,
267 XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright,
268 XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown,
269 XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde,
270 XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla,
271 XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis,
272 XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis,
273 XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute,
274 XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply,
275 XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex,
276 XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp,
277 XK_agrave, XK_aacute, XK_acircumflex, XK_atilde,
278 XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla,
279 XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis,
280 XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis,
281 XK_eth, XK_ntilde, XK_ograve, XK_oacute,
282 XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division,
283 XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex,
284 XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis
288 * Maps the AT keycodes to Linux keycodes
290 static unsigned char at2lnx[NUM_KEYCODES] =
292 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */
293 0x03, /* KEY_2 */ 0x04, /* KEY_3 */
294 0x05, /* KEY_4 */ 0x06, /* KEY_5 */
295 0x07, /* KEY_6 */ 0x08, /* KEY_7 */
296 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */
297 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */
298 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */
299 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */
300 0x11, /* KEY_W */ 0x12, /* KEY_E */
301 0x13, /* KEY_R */ 0x14, /* KEY_T */
302 0x15, /* KEY_Y */ 0x16, /* KEY_U */
303 0x17, /* KEY_I */ 0x18, /* KEY_O */
304 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */
305 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */
306 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */
307 0x1f, /* KEY_S */ 0x20, /* KEY_D */
308 0x21, /* KEY_F */ 0x22, /* KEY_G */
309 0x23, /* KEY_H */ 0x24, /* KEY_J */
310 0x25, /* KEY_K */ 0x26, /* KEY_L */
311 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */
312 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */
313 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */
314 0x2d, /* KEY_X */ 0x2e, /* KEY_C */
315 0x2f, /* KEY_V */ 0x30, /* KEY_B */
316 0x31, /* KEY_N */ 0x32, /* KEY_M */
317 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */
318 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */
319 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */
320 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */
321 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */
322 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */
323 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */
324 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */
325 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */
326 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */
327 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */
328 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */
329 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */
330 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */
331 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */
332 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */
333 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */
334 0x00, /* 0x55 */ 0x56, /* KEY_Less */
335 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */
336 0x66, /* KEY_Home */ 0x67, /* KEY_Up */
337 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */
338 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */
339 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */
340 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */
341 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */
342 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */
343 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */
344 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */
345 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */
346 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */
347 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */
348 0x00, /* 0x71 */ 0x00, /* 0x72 */
349 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */
350 0x00, /* 0x75 */ 0x00, /* 0x76 */
351 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */
352 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */
353 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */
354 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */
355 0x00, /* 0x7f */
358 /** Create a private structure for use within this file. */
359 pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard)
361 myPrivate *priv = xalloc(sizeof(*priv));
362 memset(priv, 0, sizeof(*priv));
363 priv->fd = -1;
364 priv->pKeyboard = pKeyboard;
365 return priv;
368 /** Destroy a private structure. */
369 void kbdLinuxDestroyPrivate(pointer priv)
371 if (priv) xfree(priv);
374 /** Ring the bell.
376 * Note: we completely ignore the \a volume, since Linux's ioctl()
377 * interface does not provide a way to control it. If it did, the XBell
378 * manpage tells how the actual volume is a function of the percent and
379 * the (base) volume.
381 * Note that most of the other PC-based bell drivers compute the
382 * duration for KDMKTONE as a function of the volume and the duration.
383 * For some drivers, the duration is only measured in mS if the volume
384 * is 50, and is scaled by the volume for other values. This seems
385 * confusing and possibly incorrect (the xset man page says that the
386 * bell will be "as closely as it can to the user's specifications" --
387 * if we ignore the volume and set the duration correctly, then we'll
388 * get one parameter "wrong" -- but if we use the volume to scale the
389 * duration, then we'll get both parameters "wrong"). */
390 void kbdLinuxBell(DevicePtr pDev, int percent,
391 int volume, int pitch, int duration)
393 GETPRIV;
395 if (duration && pitch) {
396 ioctl(priv->fd,
397 KDMKTONE,
398 ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */
399 | (duration << 16)); /* High bits are duration in msec */
403 /** Set the LEDs. */
404 void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl)
406 GETPRIV;
408 ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07);
411 static int kbdLinuxGetFreeVTNumber(void)
413 int fd = -1;
414 int vtno;
415 int i;
416 const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL };
418 for (i = 0; tty0[i]; i++)
419 if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break;
420 if (fd < 0)
421 FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n",
422 strerror(errno));
423 if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0)
424 FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n");
425 return vtno;
428 static int kbdLinuxOpenVT(int vtno)
430 int fd = -1;
431 int i;
432 const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL };
433 char name[64]; /* RATS: Only used in XmuSnprintf */
435 for (i = 0; vcs[i]; i++) {
436 XmuSnprintf(name, sizeof(name), vcs[i], vtno);
437 if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break;
439 if (fd < 0)
440 FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n",
441 vtno, strerror(errno));
442 return fd;
445 static int kbdLinuxGetCurrentVTNumber(int fd)
447 struct vt_stat vts;
449 if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active;
450 return -1;
453 static int kbdLinuxActivate(int fd, int vtno, int setSig);
455 /** Currently unused hook called prior to an VT switch. */
456 void kbdLinuxVTPreSwitch(pointer p)
460 /** Currently unused hook called after returning from a VT switch. */
461 void kbdLinuxVTPostSwitch(pointer p)
465 /** Tell the operating system to switch to \a vt. The \a switch_return
466 * function is called with the \a switch_return_data when the VT is
467 * switched back to the pre-switch VT (i.e., the user returns to the DMX
468 * session). */
469 int kbdLinuxVTSwitch(pointer p, int vt,
470 void (*switch_return)(pointer),
471 pointer switch_return_data)
473 myPrivate *priv = p;
475 if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n");
476 if (priv->vtno == vt) return 0;
478 PRIV = priv;
479 priv->switched = 0; /* Will switch to 1 in handler */
480 priv->switch_return = switch_return;
481 priv->switch_return_data = switch_return_data;
482 kbdLinuxActivate(priv->fd, vt, 0);
483 return 1;
486 /* RATS: This function is only ever used to handle SIGUSR1. */
487 static void kbdLinuxVTSignalHandler(int sig)
489 myPrivate *priv = PRIV;
491 signal(sig, kbdLinuxVTSignalHandler);
492 if (priv) {
493 ioctl(priv->fd, VT_RELDISP, VT_ACKACQ);
494 priv->switched = !priv->switched;
495 LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n",
496 sig, priv->switched);
497 if (!priv->switched && priv->switch_return)
498 priv->switch_return(priv->switch_return_data);
502 static int kbdLinuxActivate(int fd, int vtno, int setSig)
504 int result;
505 struct vt_mode VT;
507 SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno));
508 if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n");
509 SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno));
510 if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n");
511 if (setSig) {
512 SYSCALL(result = ioctl(fd, VT_GETMODE, &VT));
513 if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n");
514 VT.mode = VT_PROCESS;
515 VT.relsig = SIGUSR1;
516 VT.acqsig = SIGUSR1;
517 if (ioctl(fd, VT_SETMODE, &VT))
518 FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n");
519 signal(SIGUSR1, kbdLinuxVTSignalHandler);
521 return Success;
524 static void kbdLinuxOpenConsole(DevicePtr pDev)
526 GETPRIV;
527 const char *msg = MESSAGE;
529 if (priv->fd >= 0) return;
530 priv->vtno = kbdLinuxGetFreeVTNumber();
531 priv->fd = kbdLinuxOpenVT(priv->vtno);
532 priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd);
533 LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n",
534 priv->vtcurrent, priv->vtno);
535 kbdLinuxActivate(priv->fd, priv->vtno, 1);
536 ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */
537 if (msg) write(priv->fd, msg, strlen(msg));
540 static void kbdLinuxCloseConsole(DevicePtr pDev)
542 GETPRIV;
543 struct vt_mode VT;
544 const char *msg = FINALMESSAGE;
546 if (priv->fd < 0) return;
548 ioctl(priv->fd, KDSETMODE, KD_TEXT);
549 if (msg) write(priv->fd, msg, strlen(msg));
550 if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) {
551 VT.mode = VT_AUTO;
552 ioctl(priv->fd, VT_SETMODE, &VT);
555 LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent);
556 if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0);
558 close(priv->fd);
559 priv->fd = -1;
562 /** Initialize the \a pDev as a Linux keyboard. */
563 void kbdLinuxInit(DevicePtr pDev)
565 GETPRIV;
567 if (priv->fd <= 0) kbdLinuxOpenConsole(pDev);
569 ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans);
570 if (tcgetattr(priv->fd, &priv->kbdtty) < 0)
571 FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno));
574 static int kbdLinuxPrefix0Mapping(unsigned char *scanCode)
576 /* Table from xfree86/common/xf86Events.c */
577 switch (*scanCode) {
578 case KEY_KP_7: *scanCode = KEY_Home; break; /* curs home */
579 case KEY_KP_8: *scanCode = KEY_Up; break; /* curs up */
580 case KEY_KP_9: *scanCode = KEY_PgUp; break; /* curs pgup */
581 case KEY_KP_4: *scanCode = KEY_Left; break; /* curs left */
582 case KEY_KP_5: *scanCode = KEY_Begin; break; /* curs begin */
583 case KEY_KP_6: *scanCode = KEY_Right; break; /* curs right */
584 case KEY_KP_1: *scanCode = KEY_End; break; /* curs end */
585 case KEY_KP_2: *scanCode = KEY_Down; break; /* curs down */
586 case KEY_KP_3: *scanCode = KEY_PgDown; break; /* curs pgdown */
587 case KEY_KP_0: *scanCode = KEY_Insert; break; /* curs insert */
588 case KEY_KP_Decimal: *scanCode = KEY_Delete; break; /* curs delete */
589 case KEY_Enter: *scanCode = KEY_KP_Enter; break; /* keypad enter */
590 case KEY_LCtrl: *scanCode = KEY_RCtrl; break; /* right ctrl */
591 case KEY_KP_Multiply: *scanCode = KEY_Print; break; /* print */
592 case KEY_Slash: *scanCode = KEY_KP_Divide; break; /* keyp divide */
593 case KEY_Alt: *scanCode = KEY_AltLang; break; /* right alt */
594 case KEY_ScrollLock: *scanCode = KEY_Break; break; /* curs break */
595 case 0x5b: *scanCode = KEY_LMeta; break;
596 case 0x5c: *scanCode = KEY_RMeta; break;
597 case 0x5d: *scanCode = KEY_Menu; break;
598 case KEY_F3: *scanCode = KEY_F13; break;
599 case KEY_F4: *scanCode = KEY_F14; break;
600 case KEY_F5: *scanCode = KEY_F15; break;
601 case KEY_F6: *scanCode = KEY_F16; break;
602 case KEY_F7: *scanCode = KEY_F17; break;
603 case KEY_KP_Plus: *scanCode = KEY_KP_DEC; break;
605 * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6)
607 case 0x2A:
608 case 0x36:
609 return 1;
610 default:
612 * "Internet" keyboards are generating lots of new codes.
613 * Let them pass. There is little consistency between them,
614 * so don't bother with symbolic names at this level.
616 scanCode += 0x78;
618 return 0;
621 static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode)
623 int pressed = *scanCode & 0x80;
624 unsigned char code = *scanCode & 0x7f;
626 /* If we don't have a prefix, check for one */
627 if (!priv->prefix) {
628 switch (code) {
629 case KEY_Prefix0:
630 case KEY_Prefix1:
631 priv->prefix = code;
632 return 1;
634 return 0; /* No change */
637 /* We have a prefix from the last scanCode */
638 switch (priv->prefix) {
639 case KEY_Prefix0:
640 priv->prefix = 0;
641 if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */
642 break;
643 case KEY_Prefix1:
644 priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0;
645 return 1; /* Use new prefix */
646 case KEY_LCtrl:
647 priv->prefix = 0;
648 if (code != KEY_NumLock) return 1; /* Skip sequence*/
649 code = KEY_Pause;
650 break;
653 *scanCode = code | (pressed ? 0x80 : 0x00);
654 return 0; /* Use old scanCode */
657 static void kbdLinuxConvert(DevicePtr pDev,
658 unsigned char scanCode,
659 ENQUEUEPROC enqueue,
660 CHECKPROC checkspecial,
661 BLOCK block)
663 GETPRIV;
664 KeySymsPtr pKeySyms = &priv->pKeyboard->key->curKeySyms;
665 int type;
666 KeySym keySym = NoSymbol;
667 int keyCode;
668 int switching;
670 /* Do special PC/AT prefix mapping -- may change scanCode! */
671 if (kbdLinuxPrefixMapping(priv, &scanCode)) return;
673 type = (scanCode & 0x80) ? KeyRelease : KeyPress;
674 keyCode = (scanCode & 0x7f) + MIN_KEYCODE;
676 /* Handle repeats */
678 if (keyCode >= pKeySyms->minKeyCode && keyCode <= pKeySyms->maxKeyCode) {
679 keySym = pKeySyms->map[(keyCode - pKeySyms->minKeyCode)
680 * pKeySyms->mapWidth];
681 #if 0
682 switch (keySym) {
683 case XK_Num_Lock:
684 case XK_Scroll_Lock:
685 case XK_Shift_Lock:
686 case XK_Caps_Lock:
687 /* Ignore releases and all but first press */
688 if (kbdLinuxModIgnore(priv, &xE, keySym)) return;
689 if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease;
690 else xE.u.u.type = KeyPress;
691 break;
693 #endif
695 /* If key is already down, ignore or autorepeat */
696 if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) {
697 KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed;
699 /* No auto-repeat? */
700 if ((feed && !feed->ctrl.autoRepeat)
701 || priv->pKeyboard->key->modifierMap[keyCode]
702 || (feed
703 && !(feed->ctrl.autoRepeats[keyCode >> 3]
704 & (1 << (keyCode & 7))))) return; /* Ignore */
706 /* Do auto-repeat */
707 enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block);
708 type = KeyPress;
711 /* If key is already up, ignore */
712 if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return;
715 switching = 0;
716 if (checkspecial && type == KeyPress)
717 switching = checkspecial(pDev, keySym);
718 if (!switching) {
719 if (enqueue)
720 enqueue(pDev, type, keyCode, keySym, NULL, block);
721 kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */
725 /** Read an event from the \a pDev device. If the event is a motion
726 * event, enqueue it with the \a motion function. Otherwise, check for
727 * special keys with the \a checkspecial function and enqueue the event
728 * with the \a enqueue function. The \a block type is passed to the
729 * functions so that they may block SIGIO handling as appropriate to the
730 * caller of this function. */
731 void kbdLinuxRead(DevicePtr pDev,
732 MOTIONPROC motion,
733 ENQUEUEPROC enqueue,
734 CHECKPROC checkspecial,
735 BLOCK block)
737 GETPRIV;
738 unsigned char buf[256]; /* RATS: Only used in length-limited call */
739 unsigned char *pt;
740 int n;
742 while ((n = read(priv->fd, buf, sizeof(buf))) > 0)
743 for (pt = buf; n; --n, ++pt)
744 kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block);
747 /** Turn \a pDev on (i.e., take input from \a pDev). */
748 int kbdLinuxOn(DevicePtr pDev)
750 GETPRIV;
751 struct termios nTty;
753 ioctl(priv->fd, KDSKBMODE, K_RAW);
755 nTty = priv->kbdtty;
756 nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
757 nTty.c_oflag = 0;
758 nTty.c_cflag = CREAD | CS8;
759 nTty.c_lflag = 0;
760 nTty.c_cc[VTIME] = 0;
761 nTty.c_cc[VMIN] = 1;
762 cfsetispeed(&nTty, B9600);
763 cfsetospeed(&nTty, B9600);
764 if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0)
765 FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno));
766 return priv->fd;
769 /** Turn \a pDev off (i.e., stop taking input from \a pDev). */
770 void kbdLinuxOff(DevicePtr pDev)
772 GETPRIV;
774 ioctl(priv->fd, KDSKBMODE, priv->kbdtrans);
775 tcsetattr(priv->fd, TCSANOW, &priv->kbdtty);
776 kbdLinuxCloseConsole(pDev);
780 static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms)
782 KeySym *k;
783 int i;
784 int maxkey;
785 static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */
786 0, /* unshifted */
787 1, /* shifted */
788 0, /* modeswitch unshifted */
789 0 /* modeswitch shifted */
793 * Read the mapping from the kernel.
794 * Since we're still using the XFree86 scancode->AT keycode mapping
795 * routines, we need to convert the AT keycodes to Linux keycodes,
796 * then translate the Linux keysyms into X keysyms.
798 * First, figure out which tables to use for the modeswitch columns
799 * above, from the XF86Config fields.
801 tbl[2] = 8; /* alt */
802 tbl[3] = tbl[2] | 1;
804 #if 00/*BP*/
805 k = map+GLYPHS_PER_KEY;
806 #else
807 ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n");
808 return;
809 #endif
810 maxkey = NUM_AT2LNX;
812 for (i = 0; i < maxkey; ++i) {
813 struct kbentry kbe;
814 int j;
816 kbe.kb_index = at2lnx[i];
818 for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) {
819 unsigned short kval;
821 *k = NoSymbol;
823 kbe.kb_table = tbl[j];
824 if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue;
826 kval = KVAL(kbe.kb_value);
827 switch (KTYP(kbe.kb_value)) {
828 case KT_LATIN:
829 case KT_LETTER: *k = linux_to_x[kval]; break;
830 case KT_FN:
831 if (kval <= 19) *k = XK_F1 + kval;
832 else switch (kbe.kb_value) {
833 case K_FIND: *k = XK_Home; /* or XK_Find */ break;
834 case K_INSERT: *k = XK_Insert; break;
835 case K_REMOVE: *k = XK_Delete; break;
836 case K_SELECT: *k = XK_End; /* or XK_Select */ break;
837 case K_PGUP: *k = XK_Prior; break;
838 case K_PGDN: *k = XK_Next; break;
839 case K_HELP: *k = XK_Help; break;
840 case K_DO: *k = XK_Execute; break;
841 case K_PAUSE: *k = XK_Pause; break;
842 case K_MACRO: *k = XK_Menu; break;
843 default: break;
845 break;
846 case KT_SPEC:
847 switch (kbe.kb_value) {
848 case K_ENTER: *k = XK_Return; break;
849 case K_BREAK: *k = XK_Break; break;
850 case K_CAPS: *k = XK_Caps_Lock; break;
851 case K_NUM: *k = XK_Num_Lock; break;
852 case K_HOLD: *k = XK_Scroll_Lock; break;
853 case K_COMPOSE: *k = XK_Multi_key; break;
854 default: break;
856 break;
857 case KT_PAD:
858 switch (kbe.kb_value) {
859 case K_PPLUS: *k = XK_KP_Add; break;
860 case K_PMINUS: *k = XK_KP_Subtract; break;
861 case K_PSTAR: *k = XK_KP_Multiply; break;
862 case K_PSLASH: *k = XK_KP_Divide; break;
863 case K_PENTER: *k = XK_KP_Enter; break;
864 case K_PCOMMA: *k = XK_KP_Separator; break;
865 case K_PDOT: *k = XK_KP_Decimal; break;
866 case K_PPLUSMINUS: *k = XK_KP_Subtract; break;
867 default: if (kval <= 9) *k = XK_KP_0 + kval; break;
869 break;
870 case KT_DEAD:
871 /* KT_DEAD keys are for accelerated diacritical creation. */
872 switch (kbe.kb_value) {
873 case K_DGRAVE: *k = XK_dead_grave; break;
874 case K_DACUTE: *k = XK_dead_acute; break;
875 case K_DCIRCM: *k = XK_dead_circumflex; break;
876 case K_DTILDE: *k = XK_dead_tilde; break;
877 case K_DDIERE: *k = XK_dead_diaeresis; break;
879 break;
880 case KT_CUR:
881 switch (kbe.kb_value) {
882 case K_DOWN: *k = XK_Down; break;
883 case K_LEFT: *k = XK_Left; break;
884 case K_RIGHT: *k = XK_Right; break;
885 case K_UP: *k = XK_Up; break;
887 break;
888 case KT_SHIFT:
889 switch (kbe.kb_value) {
890 case K_ALTGR: *k = XK_Alt_R; break;
891 case K_ALT:
892 *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L);
893 break;
894 case K_CTRL:
895 *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L);
896 break;
897 case K_CTRLL: *k = XK_Control_L; break;
898 case K_CTRLR: *k = XK_Control_R; break;
899 case K_SHIFT:
900 *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L);
901 break;
902 case K_SHIFTL: *k = XK_Shift_L; break;
903 case K_SHIFTR: *k = XK_Shift_R; break;
904 default: break;
906 break;
907 case KT_ASCII:
908 /* KT_ASCII keys accumulate a 3 digit decimal number that
909 * gets emitted when the shift state changes. We can't
910 * emulate that.
912 break;
913 case KT_LOCK:
914 if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock;
915 break;
916 default: break;
920 if (k[-1] == k[-2]) k[-1] = NoSymbol;
921 if (k[-2] == k[-3]) k[-2] = NoSymbol;
922 if (k[-3] == k[-4]) k[-3] = NoSymbol;
923 if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol;
924 if (k[-1] == k[-4] && k[-2] == k[-3]
925 && k[-2] == NoSymbol) k[-1] = NoSymbol;
929 static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
931 GETPRIV;
932 KeySym *k, *mapCopy;
933 char type;
934 int i;
936 #if 00/*BP*/
937 mapCopy = xalloc(sizeof(map));
938 memcpy(mapCopy, map, sizeof(map));
939 #else
940 ErrorF("kbdLinuxGetMap() is broken/no-op'd\n");
941 return;
942 #endif
944 kbdLinuxReadKernelMapping(priv->fd, pKeySyms);
946 /* compute the modifier map */
947 for (i = 0; i < MAP_LENGTH; i++)
948 pModMap[i] = NoSymbol; /* make sure it is restored */
950 for (k = mapCopy, i = MIN_KEYCODE;
951 i < NUM_KEYCODES + MIN_KEYCODE;
952 i++, k += 4) {
953 switch(*k) {
954 case XK_Shift_L:
955 case XK_Shift_R: pModMap[i] = ShiftMask; break;
956 case XK_Control_L:
957 case XK_Control_R: pModMap[i] = ControlMask; break;
958 case XK_Caps_Lock: pModMap[i] = LockMask; break;
959 case XK_Alt_L:
960 case XK_Alt_R: pModMap[i] = AltMask; break;
961 case XK_Num_Lock: pModMap[i] = NumLockMask; break;
962 case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break;
963 case XK_Kana_Lock:
964 case XK_Kana_Shift: pModMap[i] = KanaMask; break;
965 case XK_Mode_switch: pModMap[i] = AltLangMask; break;
969 priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type;
971 pKeySyms->map = mapCopy; /* Must be XFree'able */
972 pKeySyms->mapWidth = GLYPHS_PER_KEY;
973 pKeySyms->minKeyCode = MIN_KEYCODE;
974 pKeySyms->maxKeyCode = MAX_KEYCODE;
977 /** Fill the \a info structure with information needed to initialize \a
978 * pDev. */
979 void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
981 info->keyboard = 1;
982 info->keyClass = 1;
983 kbdLinuxGetMap(pDev, &info->keySyms, info->modMap);
984 info->focusClass = 1;
985 info->kbdFeedbackClass = 1;