bsd_kbd.c revision 7a5a6f8e
1 2/* 3 * Copyright (c) 2002 by The XFree86 Project, Inc. 4 * Author: Ivan Pascal. 5 * 6 * Based on the code from bsd_io.c which is 7 * Copyright 1992 by Rich Murphey <Rich@Rice.edu> 8 * Copyright 1993 by David Dawes <dawes@xfree86.org> 9 */ 10 11#define NEED_EVENTS 12 13#ifdef HAVE_CONFIG_H 14#include "config.h" 15#endif 16 17#include <X11/X.h> 18#include <termios.h> 19 20#include "compiler.h" 21 22#include "xf86.h" 23#include "xf86Priv.h" 24#include "xf86_OSlib.h" 25 26#include "xf86Xinput.h" 27#include "xf86OSKbd.h" 28#include "atKeynames.h" 29 30extern void KbdGetMapping(InputInfoPtr pInfo, KeySymsPtr pKeySyms, 31 CARD8 *pModMap); 32 33extern Bool VTSwitchEnabled; 34 35static KbdProtocolRec protocols[] = { 36 {"standard", PROT_STD }, 37#ifdef WSCONS_SUPPORT 38 {"wskbd", PROT_WSCONS }, 39#endif 40 { NULL, PROT_UNKNOWN_KBD } 41}; 42 43typedef struct { 44 struct termios kbdtty; 45} BsdKbdPrivRec, *BsdKbdPrivPtr; 46 47static 48int KbdInit(InputInfoPtr pInfo, int what) 49{ 50 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 51 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 52 53 if (pKbd->isConsole) { 54 switch (pKbd->consType) { 55#if defined(PCCONS_SUPPORT) || defined(SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 56 case PCCONS: 57 case SYSCONS: 58 case PCVT: 59#if defined WSCONS_SUPPORT 60 case WSCONS: 61#endif 62 tcgetattr(pInfo->fd, &(priv->kbdtty)); 63#endif 64 break; 65 } 66 } 67 68 return Success; 69} 70 71static void 72SetKbdLeds(InputInfoPtr pInfo, int leds) 73{ 74 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 75 int real_leds = 0; 76 77#ifdef LED_CAP 78 if (leds & XLED1) real_leds |= LED_CAP; 79#endif 80#ifdef LED_NUM 81 if (leds & XLED2) real_leds |= LED_NUM; 82#endif 83#ifdef LED_SCR 84 if (leds & XLED3) real_leds |= LED_SCR; 85 if (leds & XLED4) real_leds |= LED_SCR; 86#endif 87 88 switch (pKbd->consType) { 89 90 case PCCONS: 91 break; 92#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 93 case SYSCONS: 94 case PCVT: 95 ioctl(pInfo->fd, KDSETLED, real_leds); 96 break; 97#endif 98#if defined(WSCONS_SUPPORT) 99 case WSCONS: 100 ioctl(pInfo->fd, WSKBDIO_SETLEDS, &real_leds); 101 break; 102#endif 103 } 104} 105 106static int 107GetKbdLeds(InputInfoPtr pInfo) 108{ 109 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 110 int leds = 0, real_leds = 0; 111 112 switch (pKbd->consType) { 113 case PCCONS: 114 break; 115#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 116 case SYSCONS: 117 case PCVT: 118 ioctl(pInfo->fd, KDGETLED, &real_leds); 119 break; 120#endif 121#if defined(WSCONS_SUPPORT) 122 case WSCONS: 123 ioctl(pInfo->fd, WSKBDIO_GETLEDS, &real_leds); 124 break; 125#endif 126 } 127 128#ifdef LED_CAP 129 if (real_leds & LED_CAP) leds |= XLED1; 130#endif 131#ifdef LED_NUM 132 if (real_leds & LED_NUM) leds |= XLED2; 133#endif 134#ifdef LED_SCR 135 if (real_leds & LED_SCR) leds |= XLED3; 136#endif 137 138 return(leds); 139} 140 141static void 142SetKbdRepeat(InputInfoPtr pInfo, char rad) 143{ 144 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 145 switch (pKbd->consType) { 146 147 case PCCONS: 148 break; 149#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 150 case SYSCONS: 151 case PCVT: 152 ioctl(pInfo->fd, KDSETRAD, rad); 153 break; 154#endif 155 } 156} 157 158static int 159KbdOn(InputInfoPtr pInfo, int what) 160{ 161 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 162#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT) 163 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 164 struct termios nTty; 165#endif 166#ifdef WSCONS_SUPPORT 167 int option; 168#endif 169 170 if (pKbd->isConsole) { 171 switch (pKbd->consType) { 172 173#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT) 174 case SYSCONS: 175 case PCCONS: 176 case PCVT: 177#ifdef WSCONS_SUPPORT 178 case WSCONS: 179#endif 180 nTty = priv->kbdtty; 181 nTty.c_iflag = IGNPAR | IGNBRK; 182 nTty.c_oflag = 0; 183 nTty.c_cflag = CREAD | CS8; 184 nTty.c_lflag = 0; 185 nTty.c_cc[VTIME] = 0; 186 nTty.c_cc[VMIN] = 1; 187 cfsetispeed(&nTty, 9600); 188 cfsetospeed(&nTty, 9600); 189 if (tcsetattr(pInfo->fd, TCSANOW, &nTty) < 0) { 190 xf86Msg(X_ERROR, "KbdOn: tcsetattr: %s\n", 191 strerror(errno)); 192 } 193 break; 194#endif 195 } 196#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 197 switch (pKbd->consType) { 198 case SYSCONS: 199 case PCVT: 200#ifdef K_CODE 201 if (pKbd->CustomKeycodes) 202 ioctl(pInfo->fd, KDSKBMODE, K_CODE); 203 else 204 ioctl(pInfo->fd, KDSKBMODE, K_RAW); 205#else 206 ioctl(pInfo->fd, KDSKBMODE, K_RAW); 207#endif 208 break; 209#ifdef WSCONS_SUPPORT 210 case WSCONS: 211 option = WSKBD_RAW; 212 if (ioctl(pInfo->fd, WSKBDIO_SETMODE, &option) == -1) { 213 FatalError("can't switch keyboard to raw mode. " 214 "Enable support for it in the kernel\n" 215 "or use for example:\n\n" 216 "Option \"Protocol\" \"wskbd\"\n" 217 "Option \"Device\" \"/dev/wskbd0\"\n" 218 "\nin your xorg.conf(5) file\n"); 219 } 220 break; 221#endif 222 } 223#endif 224 } 225 return Success; 226} 227 228static int 229KbdOff(InputInfoPtr pInfo, int what) 230{ 231 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 232 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 233#ifdef WSCONS_SUPPORT 234 int option; 235#endif 236 237 if (pKbd->isConsole) { 238 switch (pKbd->consType) { 239#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 240 case SYSCONS: 241 case PCVT: 242 ioctl(pInfo->fd, KDSKBMODE, K_XLATE); 243 /* FALL THROUGH */ 244#endif 245#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) 246 case PCCONS: 247 tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty)); 248 break; 249#endif 250#ifdef WSCONS_SUPPORT 251 case WSCONS: 252 option = WSKBD_TRANSLATED; 253 ioctl(xf86Info.consoleFd, WSKBDIO_SETMODE, &option); 254 tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty)); 255 break; 256#endif 257 } 258 } 259 return Success; 260} 261 262static void 263SoundBell(InputInfoPtr pInfo, int loudness, int pitch, int duration) 264{ 265 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 266#ifdef WSCONS_SUPPORT 267 struct wskbd_bell_data wsb; 268#endif 269 270 if (loudness && pitch) { 271 switch (pKbd->consType) { 272#ifdef PCCONS_SUPPORT 273 case PCCONS: 274 { int data[2]; 275 data[0] = pitch; 276 data[1] = (duration * loudness) / 50; 277 ioctl(pInfo->fd, CONSOLE_X_BELL, data); 278 break; 279 } 280#endif 281#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 282 case SYSCONS: 283 case PCVT: 284 ioctl(pInfo->fd, KDMKTONE, 285 ((1193190 / pitch) & 0xffff) | 286 (((unsigned long)duration*loudness/50)<<16)); 287 break; 288#endif 289#if defined (WSCONS_SUPPORT) 290 case WSCONS: 291 wsb.which = WSKBD_BELL_DOALL; 292 wsb.pitch = pitch; 293 wsb.period = duration; 294 wsb.volume = loudness; 295 ioctl(pInfo->fd, WSKBDIO_COMPLEXBELL, &wsb); 296 break; 297#endif 298 } 299 } 300} 301 302#define ModifierSet(k) ((modifiers & (k)) == (k)) 303 304static 305Bool SpecialKey(InputInfoPtr pInfo, int key, Bool down, int modifiers) 306{ 307 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 308 309 if(!pKbd->vtSwitchSupported) 310 return FALSE; 311 312 if ((ModifierSet(ControlMask | AltMask)) || 313 (ModifierSet(ControlMask | AltLangMask))) { 314 if (VTSwitchEnabled && !xf86Info.vtSysreq && !xf86Info.dontVTSwitch) { 315 switch (key) { 316 case KEY_F1: 317 case KEY_F2: 318 case KEY_F3: 319 case KEY_F4: 320 case KEY_F5: 321 case KEY_F6: 322 case KEY_F7: 323 case KEY_F8: 324 case KEY_F9: 325 case KEY_F10: 326#ifdef VT_ACTIVATE 327 if (down) { 328 ioctl(xf86Info.consoleFd, VT_ACTIVATE, key - KEY_F1 + 1); 329 return TRUE; 330 } 331#endif 332 case KEY_F11: 333 case KEY_F12: 334#ifdef VT_ACTIVATE 335 if (down) { 336 ioctl(xf86Info.consoleFd, VT_ACTIVATE, key - KEY_F11 + 11); 337 return TRUE; 338 } 339#else 340 ; 341#endif 342 } 343 } 344 } 345 346 return FALSE; 347} 348 349static void 350stdReadInput(InputInfoPtr pInfo) 351{ 352 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 353 unsigned char rBuf[64]; 354 int nBytes, i; 355 if ((nBytes = read( pInfo->fd, (char *)rBuf, sizeof(rBuf))) > 0) { 356 for (i = 0; i < nBytes; i++) 357 pKbd->PostEvent(pInfo, rBuf[i] & 0x7f, 358 rBuf[i] & 0x80 ? FALSE : TRUE); 359 } 360} 361 362#ifdef WSCONS_SUPPORT 363 364static void 365WSReadInput(InputInfoPtr pInfo) 366{ 367 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 368 struct wscons_event events[64]; 369 int type; 370 int blocked, n, i; 371 372 if ((n = read( pInfo->fd, events, sizeof(events))) > 0) { 373 n /= sizeof(struct wscons_event); 374 for (i = 0; i < n; i++) { 375 type = events[i].type; 376 if (type == WSCONS_EVENT_KEY_UP || type == WSCONS_EVENT_KEY_DOWN) { 377 /* It seems better to block SIGIO there */ 378 blocked = xf86BlockSIGIO(); 379 pKbd->PostEvent(pInfo, (unsigned int)(events[i].value), 380 type == WSCONS_EVENT_KEY_DOWN ? TRUE : FALSE); 381 xf86UnblockSIGIO(blocked); 382 } 383 } /* for */ 384 } 385} 386 387static void 388printWsType(char *type, char *devname) 389{ 390 xf86Msg(X_PROBED, "%s: Keyboard type: %s\n", devname, type); 391} 392#endif 393 394static Bool 395OpenKeyboard(InputInfoPtr pInfo) 396{ 397 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 398 int i; 399 KbdProtocolId prot = PROT_UNKNOWN_KBD; 400 char *s; 401 402 s = xf86SetStrOption(pInfo->options, "Protocol", NULL); 403 for (i = 0; protocols[i].name; i++) { 404 if (xf86NameCmp(s, protocols[i].name) == 0) { 405 prot = protocols[i].id; 406 break; 407 } 408 } 409 410 switch (prot) { 411 case PROT_STD: 412 pInfo->read_input = stdReadInput; 413 break; 414#ifdef WSCONS_SUPPORT 415 case PROT_WSCONS: 416 pInfo->read_input = WSReadInput; 417 break; 418#endif 419 default: 420 xf86Msg(X_ERROR,"\"%s\" is not a valid keyboard protocol name\n", s); 421 xfree(s); 422 return FALSE; 423 } 424 xf86Msg(X_CONFIG, "%s: Protocol: %s\n", pInfo->name, s); 425 xfree(s); 426 427 s = xf86SetStrOption(pInfo->options, "Device", NULL); 428 if (s == NULL) { 429 if (prot == PROT_WSCONS) { 430 xf86Msg(X_ERROR,"A \"device\" option is required with" 431 " the \"wskbd\" keyboard protocol\n"); 432 return FALSE; 433 } else { 434 pInfo->fd = xf86Info.consoleFd; 435 pKbd->isConsole = TRUE; 436 pKbd->consType = xf86Info.consType; 437 } 438 } else { 439 pInfo->fd = open(s, O_RDONLY | O_NONBLOCK | O_EXCL); 440 if (pInfo->fd == -1) { 441 xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, s); 442 xfree(s); 443 return FALSE; 444 } 445 pKbd->isConsole = FALSE; 446 pKbd->consType = xf86Info.consType; 447 xfree(s); 448 } 449 450#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 451 if (pKbd->isConsole && 452 ((pKbd->consType == SYSCONS) || (pKbd->consType == PCVT))) 453 pKbd->vtSwitchSupported = TRUE; 454#endif 455 456#ifdef WSCONS_SUPPORT 457 if( prot == PROT_WSCONS) { 458 pKbd->consType = WSCONS; 459 /* Find out keyboard type */ 460 if (ioctl(pInfo->fd, WSKBDIO_GTYPE, &(pKbd->wsKbdType)) == -1) { 461 xf86Msg(X_ERROR, "%s: cannot get keyboard type", pInfo->name); 462 close(pInfo->fd); 463 return FALSE; 464 } 465 switch (pKbd->wsKbdType) { 466 case WSKBD_TYPE_PC_XT: 467 printWsType("XT", pInfo->name); 468 break; 469 case WSKBD_TYPE_PC_AT: 470 printWsType("AT", pInfo->name); 471 break; 472 case WSKBD_TYPE_USB: 473 printWsType("USB", pInfo->name); 474 break; 475#ifdef WSKBD_TYPE_ADB 476 case WSKBD_TYPE_ADB: 477 printWsType("ADB", pInfo->name); 478 break; 479#endif 480#ifdef WSKBD_TYPE_SUN 481 case WSKBD_TYPE_SUN: 482 printWsType("Sun", pInfo->name); 483 break; 484#endif 485#ifdef WSKBD_TYPE_SUN5 486 case WSKBD_TYPE_SUN5: 487 xf86Msg(X_PROBED, "Keyboard type: Sun5\n"); 488 break; 489#endif 490 default: 491 xf86Msg(X_ERROR, "%s: Unsupported wskbd type \"%d\"", 492 pInfo->name, pKbd->wsKbdType); 493 close(pInfo->fd); 494 return FALSE; 495 } 496 } 497#endif 498 return TRUE; 499} 500 501_X_EXPORT Bool 502xf86OSKbdPreInit(InputInfoPtr pInfo) 503{ 504 KbdDevPtr pKbd = pInfo->private; 505 506 pKbd->KbdInit = KbdInit; 507 pKbd->KbdOn = KbdOn; 508 pKbd->KbdOff = KbdOff; 509 pKbd->Bell = SoundBell; 510 pKbd->SetLeds = SetKbdLeds; 511 pKbd->GetLeds = GetKbdLeds; 512 pKbd->SetKbdRepeat = SetKbdRepeat; 513 pKbd->KbdGetMapping = KbdGetMapping; 514 pKbd->SpecialKey = SpecialKey; 515 516 pKbd->RemapScanCode = NULL; 517 pKbd->GetSpecialKey = NULL; 518 519 pKbd->OpenKeyboard = OpenKeyboard; 520 pKbd->vtSwitchSupported = FALSE; 521 pKbd->CustomKeycodes = FALSE; 522 523 pKbd->private = xcalloc(sizeof(BsdKbdPrivRec), 1); 524 if (pKbd->private == NULL) { 525 xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n"); 526 return FALSE; 527 } 528 return TRUE; 529} 530