1/* Portions of this file were derived from the following files: 2 * 3 ********************************************************************** 4 * 5 * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c} 6 * 7 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 8 * 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. 18 * 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. 26 * 27 ********************************************************************** 28 * 29 * xfree86/common/xf86KbdLnx.c 30 * 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. 36 * 37 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 38 * 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. 48 * 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. 56 * 57 ********************************************************************** 58 * 59 * xfree86/os-support/linux/lnx_io.c 60 * 61 * Copyright 1992 by Orest Zborowski <obz@Kodak.com> 62 * Copyright 1993 by David Dawes <dawes@xfree86.org> 63 * 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. 74 * 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. 82 * 83 */ 84 85/* 86 * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. 87 * 88 * All Rights Reserved. 89 * 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: 97 * 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. 101 * 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. 110 */ 111 112/* 113 * Authors: 114 * Rickard E. (Rik) Faith <faith@redhat.com> 115 * 116 */ 117 118/** \file 119 * 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). */ 124 125#ifdef HAVE_DMX_CONFIG_H 126#include <dmx-config.h> 127#endif 128 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" 135 136#define GETPRIV myPrivate *priv \ 137 = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private 138 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." 153 154/* End of interface definitions. */ 155/*****************************************************************************/ 156 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> 170#include <xkbsrv.h> 171 172#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0])) 173#define NUM_STATE_ENTRIES (256/32) 174 175 176/* Private area for Linux-style keyboards. */ 177typedef struct _myPrivate { 178 int fd; 179 int vtno; 180 int vtcurrent; 181 int kbdtrans; 182 struct termios kbdtty; 183 int kbdType; 184 CARD32 kbdState[NUM_STATE_ENTRIES]; 185 DeviceIntPtr pKeyboard; 186 unsigned char prefix; 187 188 int switched; 189 SWITCHRETPROC switch_return; 190 void *switch_return_data; 191 192 /* For bell */ 193 int pitch; 194 unsigned long duration; 195} myPrivate; 196 197static myPrivate *PRIV = NULL; 198 199#undef SYSCALL 200#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) 201 202static int kbdLinuxKeyDown(myPrivate *priv, int keyCode) 203{ 204 CARD8 byte = keyCode >> 5; 205 CARD32 bit = 1 << (keyCode & 0x1f); 206 207 if (byte > NUM_STATE_ENTRIES) return 0; 208 return priv->kbdState[byte] & bit; 209} 210 211static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode) 212{ 213 CARD8 byte = keyCode >> 5; 214 CARD32 bit = 1 << (keyCode & 0x1f); 215 216 if (byte > NUM_STATE_ENTRIES) return; 217 if (type == KeyPress) priv->kbdState[byte] |= bit; 218 else priv->kbdState[byte] &= ~bit; 219} 220 221static KeySym linux_to_x[256] = { 222 NoSymbol, NoSymbol, NoSymbol, NoSymbol, 223 NoSymbol, NoSymbol, NoSymbol, NoSymbol, 224 XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, 225 NoSymbol, NoSymbol, NoSymbol, NoSymbol, 226 NoSymbol, NoSymbol, NoSymbol, NoSymbol, 227 NoSymbol, NoSymbol, NoSymbol, NoSymbol, 228 NoSymbol, NoSymbol, NoSymbol, XK_Escape, 229 NoSymbol, NoSymbol, NoSymbol, NoSymbol, 230 XK_space, XK_exclam, XK_quotedbl, XK_numbersign, 231 XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, 232 XK_parenleft, XK_parenright, XK_asterisk, XK_plus, 233 XK_comma, XK_minus, XK_period, XK_slash, 234 XK_0, XK_1, XK_2, XK_3, 235 XK_4, XK_5, XK_6, XK_7, 236 XK_8, XK_9, XK_colon, XK_semicolon, 237 XK_less, XK_equal, XK_greater, XK_question, 238 XK_at, XK_A, XK_B, XK_C, 239 XK_D, XK_E, XK_F, XK_G, 240 XK_H, XK_I, XK_J, XK_K, 241 XK_L, XK_M, XK_N, XK_O, 242 XK_P, XK_Q, XK_R, XK_S, 243 XK_T, XK_U, XK_V, XK_W, 244 XK_X, XK_Y, XK_Z, XK_bracketleft, 245 XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, 246 XK_grave, XK_a, XK_b, XK_c, 247 XK_d, XK_e, XK_f, XK_g, 248 XK_h, XK_i, XK_j, XK_k, 249 XK_l, XK_m, XK_n, XK_o, 250 XK_p, XK_q, XK_r, XK_s, 251 XK_t, XK_u, XK_v, XK_w, 252 XK_x, XK_y, XK_z, XK_braceleft, 253 XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, 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 NoSymbol, NoSymbol, NoSymbol, NoSymbol, 262 XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, 263 XK_currency, XK_yen, XK_brokenbar, XK_section, 264 XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, 265 XK_notsign, XK_hyphen, XK_registered, XK_macron, 266 XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, 267 XK_acute, XK_mu, XK_paragraph, XK_periodcentered, 268 XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, 269 XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, 270 XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, 271 XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, 272 XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, 273 XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, 274 XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, 275 XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, 276 XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, 277 XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, 278 XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, 279 XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, 280 XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, 281 XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, 282 XK_eth, XK_ntilde, XK_ograve, XK_oacute, 283 XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, 284 XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, 285 XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis 286}; 287 288/* 289 * Maps the AT keycodes to Linux keycodes 290 */ 291static unsigned char at2lnx[NUM_KEYCODES] = 292{ 293 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ 294 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ 295 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ 296 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ 297 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ 298 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ 299 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ 300 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ 301 0x11, /* KEY_W */ 0x12, /* KEY_E */ 302 0x13, /* KEY_R */ 0x14, /* KEY_T */ 303 0x15, /* KEY_Y */ 0x16, /* KEY_U */ 304 0x17, /* KEY_I */ 0x18, /* KEY_O */ 305 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ 306 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ 307 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ 308 0x1f, /* KEY_S */ 0x20, /* KEY_D */ 309 0x21, /* KEY_F */ 0x22, /* KEY_G */ 310 0x23, /* KEY_H */ 0x24, /* KEY_J */ 311 0x25, /* KEY_K */ 0x26, /* KEY_L */ 312 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ 313 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ 314 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ 315 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ 316 0x2f, /* KEY_V */ 0x30, /* KEY_B */ 317 0x31, /* KEY_N */ 0x32, /* KEY_M */ 318 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ 319 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ 320 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ 321 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ 322 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ 323 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ 324 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ 325 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ 326 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ 327 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ 328 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ 329 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ 330 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ 331 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ 332 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ 333 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ 334 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ 335 0x00, /* 0x55 */ 0x56, /* KEY_Less */ 336 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ 337 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ 338 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ 339 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ 340 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ 341 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ 342 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ 343 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ 344 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ 345 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ 346 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ 347 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ 348 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ 349 0x00, /* 0x71 */ 0x00, /* 0x72 */ 350 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ 351 0x00, /* 0x75 */ 0x00, /* 0x76 */ 352 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ 353 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ 354 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ 355 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ 356 0x00, /* 0x7f */ 357}; 358 359/** Create a private structure for use within this file. */ 360pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) 361{ 362 myPrivate *priv = calloc(1, sizeof(*priv)); 363 priv->fd = -1; 364 priv->pKeyboard = pKeyboard; 365 return priv; 366} 367 368/** Destroy a private structure. */ 369void kbdLinuxDestroyPrivate(pointer priv) 370{ 371 free(priv); 372} 373 374/** Ring the bell. 375 * 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. 380 * 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"). */ 390void kbdLinuxBell(DevicePtr pDev, int percent, 391 int volume, int pitch, int duration) 392{ 393 GETPRIV; 394 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 */ 400 } 401} 402 403/** Set the LEDs. */ 404void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl) 405{ 406 GETPRIV; 407 408 ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07); 409} 410 411static int kbdLinuxGetFreeVTNumber(void) 412{ 413 int fd = -1; 414 int vtno; 415 int i; 416 const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; 417 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; 426} 427 428static int kbdLinuxOpenVT(int vtno) 429{ 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 */ 434 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; 438 } 439 if (fd < 0) 440 FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n", 441 vtno, strerror(errno)); 442 return fd; 443} 444 445static int kbdLinuxGetCurrentVTNumber(int fd) 446{ 447 struct vt_stat vts; 448 449 if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active; 450 return -1; 451} 452 453static int kbdLinuxActivate(int fd, int vtno, int setSig); 454 455/** Currently unused hook called prior to an VT switch. */ 456void kbdLinuxVTPreSwitch(pointer p) 457{ 458} 459 460/** Currently unused hook called after returning from a VT switch. */ 461void kbdLinuxVTPostSwitch(pointer p) 462{ 463} 464 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). */ 469int kbdLinuxVTSwitch(pointer p, int vt, 470 void (*switch_return)(pointer), 471 pointer switch_return_data) 472{ 473 myPrivate *priv = p; 474 475 if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n"); 476 if (priv->vtno == vt) return 0; 477 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; 484} 485 486/* RATS: This function is only ever used to handle SIGUSR1. */ 487static void kbdLinuxVTSignalHandler(int sig) 488{ 489 myPrivate *priv = PRIV; 490 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); 499 } 500} 501 502static int kbdLinuxActivate(int fd, int vtno, int setSig) 503{ 504 int result; 505 struct vt_mode VT; 506 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); 520 } 521 return Success; 522} 523 524static void kbdLinuxOpenConsole(DevicePtr pDev) 525{ 526 GETPRIV; 527 const char *msg = MESSAGE; 528 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)); 538} 539 540static void kbdLinuxCloseConsole(DevicePtr pDev) 541{ 542 GETPRIV; 543 struct vt_mode VT; 544 const char *msg = FINALMESSAGE; 545 546 if (priv->fd < 0) return; 547 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); 553 } 554 555 LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent); 556 if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0); 557 558 close(priv->fd); 559 priv->fd = -1; 560} 561 562/** Initialize the \a pDev as a Linux keyboard. */ 563void kbdLinuxInit(DevicePtr pDev) 564{ 565 GETPRIV; 566 567 if (priv->fd <= 0) kbdLinuxOpenConsole(pDev); 568 569 ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans); 570 if (tcgetattr(priv->fd, &priv->kbdtty) < 0) 571 FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); 572} 573 574static int kbdLinuxPrefix0Mapping(unsigned char *scanCode) 575{ 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; 604 /* 605 * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) 606 */ 607 case 0x2A: 608 case 0x36: 609 return 1; 610 default: 611 /* 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. 615 */ 616 scanCode += 0x78; 617 } 618 return 0; 619} 620 621static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode) 622{ 623 int pressed = *scanCode & 0x80; 624 unsigned char code = *scanCode & 0x7f; 625 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; 633 } 634 return 0; /* No change */ 635 } 636 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; 651 } 652 653 *scanCode = code | (pressed ? 0x80 : 0x00); 654 return 0; /* Use old scanCode */ 655} 656 657static void kbdLinuxConvert(DevicePtr pDev, 658 unsigned char scanCode, 659 ENQUEUEPROC enqueue, 660 CHECKPROC checkspecial, 661 BLOCK block) 662{ 663 GETPRIV; 664 XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; 665 int type; 666 KeySym keySym = NoSymbol; 667 int keyCode; 668 int switching; 669 670 /* Do special PC/AT prefix mapping -- may change scanCode! */ 671 if (kbdLinuxPrefixMapping(priv, &scanCode)) return; 672 673 type = (scanCode & 0x80) ? KeyRelease : KeyPress; 674 keyCode = (scanCode & 0x7f) + MIN_KEYCODE; 675 676 /* Handle repeats */ 677 678 if (keyCode >= xkbi->desc->min_key_code && 679 keyCode <= xkbi->desc->max_key_code) { 680 681 int effectiveGroup = XkbGetEffectiveGroup(xkbi, 682 &xkbi->state, 683 scanCode); 684 keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); 685#if 0 686 switch (keySym) { 687 case XK_Num_Lock: 688 case XK_Scroll_Lock: 689 case XK_Shift_Lock: 690 case XK_Caps_Lock: 691 /* Ignore releases and all but first press */ 692 if (kbdLinuxModIgnore(priv, &xE, keySym)) return; 693 if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; 694 else xE.u.u.type = KeyPress; 695 break; 696 } 697#endif 698 699 /* If key is already down, ignore or autorepeat */ 700 if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) { 701 KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed; 702 703 /* No auto-repeat? */ 704 if ((feed && !feed->ctrl.autoRepeat) 705 || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode] 706 || (feed 707 && !(feed->ctrl.autoRepeats[keyCode >> 3] 708 & (1 << (keyCode & 7))))) return; /* Ignore */ 709 710 /* Do auto-repeat */ 711 enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); 712 type = KeyPress; 713 } 714 715 /* If key is already up, ignore */ 716 if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return; 717 } 718 719 switching = 0; 720 if (checkspecial && type == KeyPress) 721 switching = checkspecial(pDev, keySym); 722 if (!switching) { 723 if (enqueue) 724 enqueue(pDev, type, keyCode, keySym, NULL, block); 725 kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */ 726 } 727} 728 729/** Read an event from the \a pDev device. If the event is a motion 730 * event, enqueue it with the \a motion function. Otherwise, check for 731 * special keys with the \a checkspecial function and enqueue the event 732 * with the \a enqueue function. The \a block type is passed to the 733 * functions so that they may block SIGIO handling as appropriate to the 734 * caller of this function. */ 735void kbdLinuxRead(DevicePtr pDev, 736 MOTIONPROC motion, 737 ENQUEUEPROC enqueue, 738 CHECKPROC checkspecial, 739 BLOCK block) 740{ 741 GETPRIV; 742 unsigned char buf[256]; /* RATS: Only used in length-limited call */ 743 unsigned char *pt; 744 int n; 745 746 while ((n = read(priv->fd, buf, sizeof(buf))) > 0) 747 for (pt = buf; n; --n, ++pt) 748 kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block); 749} 750 751/** Turn \a pDev on (i.e., take input from \a pDev). */ 752int kbdLinuxOn(DevicePtr pDev) 753{ 754 GETPRIV; 755 struct termios nTty; 756 757 ioctl(priv->fd, KDSKBMODE, K_RAW); 758 759 nTty = priv->kbdtty; 760 nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); 761 nTty.c_oflag = 0; 762 nTty.c_cflag = CREAD | CS8; 763 nTty.c_lflag = 0; 764 nTty.c_cc[VTIME] = 0; 765 nTty.c_cc[VMIN] = 1; 766 cfsetispeed(&nTty, B9600); 767 cfsetospeed(&nTty, B9600); 768 if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) 769 FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno)); 770 return priv->fd; 771} 772 773/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ 774void kbdLinuxOff(DevicePtr pDev) 775{ 776 GETPRIV; 777 778 ioctl(priv->fd, KDSKBMODE, priv->kbdtrans); 779 tcsetattr(priv->fd, TCSANOW, &priv->kbdtty); 780 kbdLinuxCloseConsole(pDev); 781} 782 783 784static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms) 785{ 786 KeySym *k; 787 int i; 788 int maxkey; 789 static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */ 790 0, /* unshifted */ 791 1, /* shifted */ 792 0, /* modeswitch unshifted */ 793 0 /* modeswitch shifted */ 794 }; 795 796 /* 797 * Read the mapping from the kernel. 798 * Since we're still using the XFree86 scancode->AT keycode mapping 799 * routines, we need to convert the AT keycodes to Linux keycodes, 800 * then translate the Linux keysyms into X keysyms. 801 * 802 * First, figure out which tables to use for the modeswitch columns 803 * above, from the XF86Config fields. 804 */ 805 tbl[2] = 8; /* alt */ 806 tbl[3] = tbl[2] | 1; 807 808#if 00/*BP*/ 809 k = map+GLYPHS_PER_KEY; 810#else 811 ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n"); 812 return; 813#endif 814 maxkey = NUM_AT2LNX; 815 816 for (i = 0; i < maxkey; ++i) { 817 struct kbentry kbe; 818 int j; 819 820 kbe.kb_index = at2lnx[i]; 821 822 for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { 823 unsigned short kval; 824 825 *k = NoSymbol; 826 827 kbe.kb_table = tbl[j]; 828 if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue; 829 830 kval = KVAL(kbe.kb_value); 831 switch (KTYP(kbe.kb_value)) { 832 case KT_LATIN: 833 case KT_LETTER: *k = linux_to_x[kval]; break; 834 case KT_FN: 835 if (kval <= 19) *k = XK_F1 + kval; 836 else switch (kbe.kb_value) { 837 case K_FIND: *k = XK_Home; /* or XK_Find */ break; 838 case K_INSERT: *k = XK_Insert; break; 839 case K_REMOVE: *k = XK_Delete; break; 840 case K_SELECT: *k = XK_End; /* or XK_Select */ break; 841 case K_PGUP: *k = XK_Prior; break; 842 case K_PGDN: *k = XK_Next; break; 843 case K_HELP: *k = XK_Help; break; 844 case K_DO: *k = XK_Execute; break; 845 case K_PAUSE: *k = XK_Pause; break; 846 case K_MACRO: *k = XK_Menu; break; 847 default: break; 848 } 849 break; 850 case KT_SPEC: 851 switch (kbe.kb_value) { 852 case K_ENTER: *k = XK_Return; break; 853 case K_BREAK: *k = XK_Break; break; 854 case K_CAPS: *k = XK_Caps_Lock; break; 855 case K_NUM: *k = XK_Num_Lock; break; 856 case K_HOLD: *k = XK_Scroll_Lock; break; 857 case K_COMPOSE: *k = XK_Multi_key; break; 858 default: break; 859 } 860 break; 861 case KT_PAD: 862 switch (kbe.kb_value) { 863 case K_PPLUS: *k = XK_KP_Add; break; 864 case K_PMINUS: *k = XK_KP_Subtract; break; 865 case K_PSTAR: *k = XK_KP_Multiply; break; 866 case K_PSLASH: *k = XK_KP_Divide; break; 867 case K_PENTER: *k = XK_KP_Enter; break; 868 case K_PCOMMA: *k = XK_KP_Separator; break; 869 case K_PDOT: *k = XK_KP_Decimal; break; 870 case K_PPLUSMINUS: *k = XK_KP_Subtract; break; 871 default: if (kval <= 9) *k = XK_KP_0 + kval; break; 872 } 873 break; 874 case KT_DEAD: 875 /* KT_DEAD keys are for accelerated diacritical creation. */ 876 switch (kbe.kb_value) { 877 case K_DGRAVE: *k = XK_dead_grave; break; 878 case K_DACUTE: *k = XK_dead_acute; break; 879 case K_DCIRCM: *k = XK_dead_circumflex; break; 880 case K_DTILDE: *k = XK_dead_tilde; break; 881 case K_DDIERE: *k = XK_dead_diaeresis; break; 882 } 883 break; 884 case KT_CUR: 885 switch (kbe.kb_value) { 886 case K_DOWN: *k = XK_Down; break; 887 case K_LEFT: *k = XK_Left; break; 888 case K_RIGHT: *k = XK_Right; break; 889 case K_UP: *k = XK_Up; break; 890 } 891 break; 892 case KT_SHIFT: 893 switch (kbe.kb_value) { 894 case K_ALTGR: *k = XK_Alt_R; break; 895 case K_ALT: 896 *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); 897 break; 898 case K_CTRL: 899 *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); 900 break; 901 case K_CTRLL: *k = XK_Control_L; break; 902 case K_CTRLR: *k = XK_Control_R; break; 903 case K_SHIFT: 904 *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); 905 break; 906 case K_SHIFTL: *k = XK_Shift_L; break; 907 case K_SHIFTR: *k = XK_Shift_R; break; 908 default: break; 909 } 910 break; 911 case KT_ASCII: 912 /* KT_ASCII keys accumulate a 3 digit decimal number that 913 * gets emitted when the shift state changes. We can't 914 * emulate that. 915 */ 916 break; 917 case KT_LOCK: 918 if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock; 919 break; 920 default: break; 921 } 922 } 923 924 if (k[-1] == k[-2]) k[-1] = NoSymbol; 925 if (k[-2] == k[-3]) k[-2] = NoSymbol; 926 if (k[-3] == k[-4]) k[-3] = NoSymbol; 927 if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol; 928 if (k[-1] == k[-4] && k[-2] == k[-3] 929 && k[-2] == NoSymbol) k[-1] = NoSymbol; 930 } 931} 932 933static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) 934{ 935 GETPRIV; 936 KeySym *k, *mapCopy; 937 char type; 938 int i; 939 940#if 00/*BP*/ 941 mapCopy = malloc(sizeof(map)); 942 memcpy(mapCopy, map, sizeof(map)); 943#else 944 ErrorF("kbdLinuxGetMap() is broken/no-op'd\n"); 945 return; 946#endif 947 948 kbdLinuxReadKernelMapping(priv->fd, pKeySyms); 949 950 /* compute the modifier map */ 951 for (i = 0; i < MAP_LENGTH; i++) 952 pModMap[i] = NoSymbol; /* make sure it is restored */ 953 954 for (k = mapCopy, i = MIN_KEYCODE; 955 i < NUM_KEYCODES + MIN_KEYCODE; 956 i++, k += 4) { 957 switch(*k) { 958 case XK_Shift_L: 959 case XK_Shift_R: pModMap[i] = ShiftMask; break; 960 case XK_Control_L: 961 case XK_Control_R: pModMap[i] = ControlMask; break; 962 case XK_Caps_Lock: pModMap[i] = LockMask; break; 963 case XK_Alt_L: 964 case XK_Alt_R: pModMap[i] = AltMask; break; 965 case XK_Num_Lock: pModMap[i] = NumLockMask; break; 966 case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; 967 case XK_Kana_Lock: 968 case XK_Kana_Shift: pModMap[i] = KanaMask; break; 969 case XK_Mode_switch: pModMap[i] = AltLangMask; break; 970 } 971 } 972 973 priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type; 974 975 pKeySyms->map = mapCopy; /* Must be XFree'able */ 976 pKeySyms->mapWidth = GLYPHS_PER_KEY; 977 pKeySyms->minKeyCode = MIN_KEYCODE; 978 pKeySyms->maxKeyCode = MAX_KEYCODE; 979} 980 981/** Fill the \a info structure with information needed to initialize \a 982 * pDev. */ 983void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) 984{ 985 info->keyboard = 1; 986 info->keyClass = 1; 987 kbdLinuxGetMap(pDev, &info->keySyms, info->modMap); 988 info->focusClass = 1; 989 info->kbdFeedbackClass = 1; 990} 991