bsd_kbd.c revision 37d4bb4a
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 302static void 303stdReadInput(InputInfoPtr pInfo) 304{ 305 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 306 unsigned char rBuf[64]; 307 int nBytes, i; 308 if ((nBytes = read( pInfo->fd, (char *)rBuf, sizeof(rBuf))) > 0) { 309 for (i = 0; i < nBytes; i++) 310 pKbd->PostEvent(pInfo, rBuf[i] & 0x7f, 311 rBuf[i] & 0x80 ? FALSE : TRUE); 312 } 313} 314 315#ifdef WSCONS_SUPPORT 316 317static void 318WSReadInput(InputInfoPtr pInfo) 319{ 320 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 321 struct wscons_event events[64]; 322 int type; 323 int blocked, n, i; 324 325 if ((n = read( pInfo->fd, events, sizeof(events))) > 0) { 326 n /= sizeof(struct wscons_event); 327 for (i = 0; i < n; i++) { 328 type = events[i].type; 329 if (type == WSCONS_EVENT_KEY_UP || type == WSCONS_EVENT_KEY_DOWN) { 330 /* It seems better to block SIGIO there */ 331 blocked = xf86BlockSIGIO(); 332 pKbd->PostEvent(pInfo, (unsigned int)(events[i].value), 333 type == WSCONS_EVENT_KEY_DOWN ? TRUE : FALSE); 334 xf86UnblockSIGIO(blocked); 335 } 336 } /* for */ 337 } 338} 339 340static void 341printWsType(const char *type, char *name) 342{ 343 xf86Msg(X_PROBED, "%s: Keyboard type: %s\n", name, type); 344} 345#endif 346 347static Bool 348OpenKeyboard(InputInfoPtr pInfo) 349{ 350 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 351 int i; 352 KbdProtocolId prot = PROT_UNKNOWN_KBD; 353 char *s; 354 355 s = xf86SetStrOption(pInfo->options, "Protocol", NULL); 356 for (i = 0; protocols[i].name; i++) { 357 if (xf86NameCmp(s, protocols[i].name) == 0) { 358 prot = protocols[i].id; 359 break; 360 } 361 } 362 363 switch (prot) { 364 case PROT_STD: 365 pInfo->read_input = stdReadInput; 366 break; 367#ifdef WSCONS_SUPPORT 368 case PROT_WSCONS: 369 pInfo->read_input = WSReadInput; 370 break; 371#endif 372 default: 373 xf86Msg(X_ERROR,"\"%s\" is not a valid keyboard protocol name\n", s); 374 xfree(s); 375 return FALSE; 376 } 377 xf86Msg(X_CONFIG, "%s: Protocol: %s\n", pInfo->name, s); 378 xfree(s); 379 380 s = xf86SetStrOption(pInfo->options, "Device", NULL); 381 if (s == NULL) { 382 if (prot == PROT_WSCONS) { 383 xf86Msg(X_ERROR,"A \"device\" option is required with" 384 " the \"wskbd\" keyboard protocol\n"); 385 return FALSE; 386 } else { 387 pInfo->fd = xf86Info.consoleFd; 388 pKbd->isConsole = TRUE; 389 pKbd->consType = xf86Info.consType; 390 } 391 } else { 392 pInfo->fd = open(s, O_RDONLY | O_NONBLOCK | O_EXCL); 393 if (pInfo->fd == -1) { 394 xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, s); 395 xfree(s); 396 return FALSE; 397 } 398 pKbd->isConsole = FALSE; 399 pKbd->consType = xf86Info.consType; 400 xfree(s); 401 } 402 403#ifdef WSCONS_SUPPORT 404 if( prot == PROT_WSCONS) { 405 pKbd->consType = WSCONS; 406#ifdef WSKBDIO_SETVERSION 407 int version = WSKBDIO_EVENT_VERSION; 408 if (ioctl(pInfo->fd, WSKBDIO_SETVERSION, &version) == -1) { 409 xf86Msg(X_WARNING, "%s: cannot set version\n", pInfo->name); 410 return FALSE; 411 } 412#endif 413 /* Find out keyboard type */ 414 if (ioctl(pInfo->fd, WSKBDIO_GTYPE, &(pKbd->wsKbdType)) == -1) { 415 xf86Msg(X_ERROR, "%s: cannot get keyboard type", pInfo->name); 416 close(pInfo->fd); 417 return FALSE; 418 } 419 switch (pKbd->wsKbdType) { 420 case WSKBD_TYPE_PC_XT: 421 printWsType("XT", pInfo->name); 422 break; 423 case WSKBD_TYPE_PC_AT: 424 printWsType("AT", pInfo->name); 425 break; 426 case WSKBD_TYPE_USB: 427 printWsType("USB", pInfo->name); 428 break; 429#ifdef WSKBD_TYPE_ADB 430 case WSKBD_TYPE_ADB: 431 printWsType("ADB", pInfo->name); 432 break; 433#endif 434#ifdef WSKBD_TYPE_SUN 435 case WSKBD_TYPE_SUN: 436 printWsType("Sun", pInfo->name); 437 break; 438#endif 439#ifdef WSKBD_TYPE_SUN5 440 case WSKBD_TYPE_SUN5: 441 printWsType("Sun5", pInfo->name); 442 break; 443#endif 444 default: 445 xf86Msg(X_ERROR, "%s: Unsupported wskbd type \"%d\"", 446 pInfo->name, pKbd->wsKbdType); 447 close(pInfo->fd); 448 return FALSE; 449 } 450 } 451#endif 452 453#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 454 if (pKbd->isConsole && 455 ((pKbd->consType == SYSCONS) || (pKbd->consType == PCVT) || 456 (pKbd->consType == WSCONS))) 457 pKbd->vtSwitchSupported = TRUE; 458#endif 459 460 return TRUE; 461} 462 463_X_EXPORT Bool 464xf86OSKbdPreInit(InputInfoPtr pInfo) 465{ 466 KbdDevPtr pKbd = pInfo->private; 467 468 pKbd->KbdInit = KbdInit; 469 pKbd->KbdOn = KbdOn; 470 pKbd->KbdOff = KbdOff; 471 pKbd->Bell = SoundBell; 472 pKbd->SetLeds = SetKbdLeds; 473 pKbd->GetLeds = GetKbdLeds; 474 pKbd->SetKbdRepeat = SetKbdRepeat; 475 pKbd->KbdGetMapping = KbdGetMapping; 476 477 pKbd->RemapScanCode = NULL; 478 479 pKbd->OpenKeyboard = OpenKeyboard; 480 pKbd->vtSwitchSupported = FALSE; 481 pKbd->CustomKeycodes = FALSE; 482 483 pKbd->private = xcalloc(sizeof(BsdKbdPrivRec), 1); 484 if (pKbd->private == NULL) { 485 xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n"); 486 return FALSE; 487 } 488 return TRUE; 489} 490