bsd_kbd.c revision 836253ff
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#ifdef HAVE_CONFIG_H 12#include "config.h" 13#endif 14 15#include <xorg-server.h> 16#include <X11/X.h> 17#include <termios.h> 18 19#include "compiler.h" 20 21#include "xf86.h" 22#include "xf86Priv.h" 23#include "xf86_OSlib.h" 24 25#include "xf86Xinput.h" 26#include "xf86OSKbd.h" 27#include "atKeynames.h" 28#include "bsd_kbd.h" 29 30static KbdProtocolRec protocols[] = { 31 {"standard", PROT_STD }, 32#ifdef WSCONS_SUPPORT 33 {"wskbd", PROT_WSCONS }, 34#endif 35 { NULL, PROT_UNKNOWN_KBD } 36}; 37 38typedef struct { 39 struct termios kbdtty; 40} BsdKbdPrivRec, *BsdKbdPrivPtr; 41 42static 43int KbdInit(InputInfoPtr pInfo, int what) 44{ 45 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 46 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 47 48 if (pKbd->isConsole) { 49 switch (pKbd->consType) { 50#if defined(PCCONS_SUPPORT) || defined(SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 51 case PCCONS: 52 case SYSCONS: 53 case PCVT: 54#if defined WSCONS_SUPPORT 55 case WSCONS: 56#endif 57 tcgetattr(pInfo->fd, &(priv->kbdtty)); 58#endif 59 break; 60 } 61 } 62 63 return Success; 64} 65 66static void 67SetKbdLeds(InputInfoPtr pInfo, int leds) 68{ 69 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 70 int real_leds = 0; 71 72#ifdef LED_CAP 73 if (leds & XLED1) real_leds |= LED_CAP; 74#endif 75#ifdef LED_NUM 76 if (leds & XLED2) real_leds |= LED_NUM; 77#endif 78#ifdef LED_SCR 79 if (leds & XLED3) real_leds |= LED_SCR; 80 if (leds & XLED4) real_leds |= LED_SCR; 81#endif 82 83 switch (pKbd->consType) { 84 85#ifdef PCCONS_SUPPORT 86 case PCCONS: 87 break; 88#endif 89#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 90 case SYSCONS: 91 case PCVT: 92 ioctl(pInfo->fd, KDSETLED, real_leds); 93 break; 94#endif 95#if defined(WSCONS_SUPPORT) 96 case WSCONS: 97 ioctl(pInfo->fd, WSKBDIO_SETLEDS, &real_leds); 98 break; 99#endif 100 } 101} 102 103static int 104GetKbdLeds(InputInfoPtr pInfo) 105{ 106 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 107 int leds = 0, real_leds = 0; 108 109 switch (pKbd->consType) { 110 111#ifdef PCCONS_SUPPORT 112 case PCCONS: 113 break; 114#endif 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 int 142KbdOn(InputInfoPtr pInfo, int what) 143{ 144 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 145#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT) 146 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 147 struct termios nTty; 148#endif 149#ifdef WSCONS_SUPPORT 150 int option; 151#endif 152 153 if (pKbd->isConsole) { 154 switch (pKbd->consType) { 155 156#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT) 157 case SYSCONS: 158 case PCCONS: 159 case PCVT: 160#ifdef WSCONS_SUPPORT 161 case WSCONS: 162#endif 163 nTty = priv->kbdtty; 164 nTty.c_iflag = IGNPAR | IGNBRK; 165 nTty.c_oflag = 0; 166 nTty.c_cflag = CREAD | CS8; 167 nTty.c_lflag = 0; 168 nTty.c_cc[VTIME] = 0; 169 nTty.c_cc[VMIN] = 1; 170 cfsetispeed(&nTty, 9600); 171 cfsetospeed(&nTty, 9600); 172 if (tcsetattr(pInfo->fd, TCSANOW, &nTty) < 0) { 173 xf86Msg(X_ERROR, "KbdOn: tcsetattr: %s\n", 174 strerror(errno)); 175 } 176 break; 177#endif 178 } 179#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 180 switch (pKbd->consType) { 181 case SYSCONS: 182 case PCVT: 183#ifdef K_CODE 184 if (pKbd->CustomKeycodes) 185 ioctl(pInfo->fd, KDSKBMODE, K_CODE); 186 else 187 ioctl(pInfo->fd, KDSKBMODE, K_RAW); 188#else 189 ioctl(pInfo->fd, KDSKBMODE, K_RAW); 190#endif 191 break; 192#ifdef WSCONS_SUPPORT 193 case WSCONS: 194 option = WSKBD_RAW; 195 if (ioctl(pInfo->fd, WSKBDIO_SETMODE, &option) == -1) { 196 FatalError("can't switch keyboard to raw mode. " 197 "Enable support for it in the kernel\n" 198 "or use for example:\n\n" 199 "Option \"Protocol\" \"wskbd\"\n" 200 "Option \"Device\" \"/dev/wskbd0\"\n" 201 "\nin your xorg.conf(5) file\n"); 202 } 203 break; 204#endif 205 } 206#endif 207 } 208 return Success; 209} 210 211static int 212KbdOff(InputInfoPtr pInfo, int what) 213{ 214 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 215 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 216#ifdef WSCONS_SUPPORT 217 int option; 218#endif 219 220 if (pKbd->isConsole) { 221 switch (pKbd->consType) { 222#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 223 case SYSCONS: 224 case PCVT: 225 ioctl(pInfo->fd, KDSKBMODE, K_XLATE); 226 /* FALL THROUGH */ 227#endif 228#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) 229 case PCCONS: 230 tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty)); 231 break; 232#endif 233#ifdef WSCONS_SUPPORT 234 case WSCONS: 235 option = WSKBD_TRANSLATED; 236 ioctl(xf86Info.consoleFd, WSKBDIO_SETMODE, &option); 237 tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty)); 238 break; 239#endif 240 } 241 } 242 return Success; 243} 244 245static void 246SoundBell(InputInfoPtr pInfo, int loudness, int pitch, int duration) 247{ 248 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 249#ifdef WSCONS_SUPPORT 250 struct wskbd_bell_data wsb; 251#endif 252 253 if (loudness && pitch) { 254 switch (pKbd->consType) { 255#ifdef PCCONS_SUPPORT 256 case PCCONS: 257 { int data[2]; 258 data[0] = pitch; 259 data[1] = (duration * loudness) / 50; 260 ioctl(pInfo->fd, CONSOLE_X_BELL, data); 261 break; 262 } 263#endif 264#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 265 case SYSCONS: 266 case PCVT: 267 ioctl(pInfo->fd, KDMKTONE, 268 ((1193190 / pitch) & 0xffff) | 269 (((unsigned long)duration*loudness/50)<<16)); 270 break; 271#endif 272#if defined (WSCONS_SUPPORT) 273 case WSCONS: 274 wsb.which = WSKBD_BELL_DOALL; 275 wsb.pitch = pitch; 276 wsb.period = duration; 277 wsb.volume = loudness; 278 ioctl(pInfo->fd, WSKBDIO_COMPLEXBELL, &wsb); 279 break; 280#endif 281 } 282 } 283} 284 285static void 286stdReadInput(InputInfoPtr pInfo) 287{ 288 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 289 unsigned char rBuf[64]; 290 int nBytes, i; 291 if ((nBytes = read( pInfo->fd, (char *)rBuf, sizeof(rBuf))) > 0) { 292 for (i = 0; i < nBytes; i++) 293 pKbd->PostEvent(pInfo, rBuf[i] & 0x7f, 294 rBuf[i] & 0x80 ? FALSE : TRUE); 295 } 296} 297 298#ifdef WSCONS_SUPPORT 299 300static void 301WSReadInput(InputInfoPtr pInfo) 302{ 303 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 304 struct wscons_event events[64]; 305 int type; 306 int blocked, n, i; 307 308 if ((n = read( pInfo->fd, events, sizeof(events))) > 0) { 309 n /= sizeof(struct wscons_event); 310 for (i = 0; i < n; i++) { 311 type = events[i].type; 312 if (type == WSCONS_EVENT_KEY_UP || type == WSCONS_EVENT_KEY_DOWN) { 313 /* It seems better to block SIGIO there */ 314 blocked = xf86BlockSIGIO(); 315 pKbd->PostEvent(pInfo, (unsigned int)(events[i].value), 316 type == WSCONS_EVENT_KEY_DOWN ? TRUE : FALSE); 317 xf86UnblockSIGIO(blocked); 318 } 319 } /* for */ 320 } 321} 322 323static void 324printWsType(const char *type, char *name) 325{ 326 xf86Msg(X_PROBED, "%s: Keyboard type: %s\n", name, type); 327} 328#endif 329 330static Bool 331OpenKeyboard(InputInfoPtr pInfo) 332{ 333 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 334 int i; 335 KbdProtocolId prot = PROT_UNKNOWN_KBD; 336 char *s; 337 338 s = xf86SetStrOption(pInfo->options, "Protocol", NULL); 339 for (i = 0; protocols[i].name; i++) { 340 if (xf86NameCmp(s, protocols[i].name) == 0) { 341 prot = protocols[i].id; 342 break; 343 } 344 } 345 346 switch (prot) { 347 case PROT_STD: 348 pInfo->read_input = stdReadInput; 349 break; 350#ifdef WSCONS_SUPPORT 351 case PROT_WSCONS: 352 pInfo->read_input = WSReadInput; 353 break; 354#endif 355 default: 356 xf86Msg(X_ERROR,"\"%s\" is not a valid keyboard protocol name\n", s); 357 free(s); 358 return FALSE; 359 } 360 free(s); 361 362 if (prot == PROT_WSCONS) { 363 s = xf86SetStrOption(pInfo->options, "Device", "/dev/wskbd"); 364 } else 365 s = xf86SetStrOption(pInfo->options, "Device", NULL); 366 367 if (s == NULL) { 368 pInfo->fd = xf86Info.consoleFd; 369 pKbd->isConsole = TRUE; 370 pKbd->consType = xf86Info.consType; 371 } else { 372 pInfo->fd = open(s, O_RDONLY | O_NONBLOCK | O_EXCL); 373 if (pInfo->fd == -1) { 374 xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, s); 375 free(s); 376 return FALSE; 377 } 378 pKbd->isConsole = FALSE; 379 pKbd->consType = xf86Info.consType; 380 free(s); 381 } 382 383#ifdef WSCONS_SUPPORT 384 if( prot == PROT_WSCONS) { 385 pKbd->consType = WSCONS; 386#ifdef WSKBDIO_SETVERSION 387 int version = WSKBDIO_EVENT_VERSION; 388 if (ioctl(pInfo->fd, WSKBDIO_SETVERSION, &version) == -1) { 389 xf86Msg(X_WARNING, "%s: cannot set version\n", pInfo->name); 390 return FALSE; 391 } 392#endif 393 /* Find out keyboard type */ 394 if (ioctl(pInfo->fd, WSKBDIO_GTYPE, &(pKbd->wsKbdType)) == -1) { 395 xf86Msg(X_ERROR, "%s: cannot get keyboard type", pInfo->name); 396 close(pInfo->fd); 397 return FALSE; 398 } 399 switch (pKbd->wsKbdType) { 400 case WSKBD_TYPE_PC_XT: 401 printWsType("XT", pInfo->name); 402 break; 403 case WSKBD_TYPE_PC_AT: 404 printWsType("AT", pInfo->name); 405 break; 406 case WSKBD_TYPE_USB: 407 printWsType("USB", pInfo->name); 408 break; 409#ifdef WSKBD_TYPE_ADB 410 case WSKBD_TYPE_ADB: 411 printWsType("ADB", pInfo->name); 412 break; 413#endif 414#ifdef WSKBD_TYPE_LK201 415 case WSKBD_TYPE_LK201: 416 printWsType("LK201", pInfo->name); 417 break; 418#endif 419#ifdef WSKBD_TYPE_MAPLE 420 case WSKBD_TYPE_MAPLE: 421 printWsType("Maple", pInfo->name); 422 break; 423#endif 424#ifdef WSKBD_TYPE_SUN 425 case WSKBD_TYPE_SUN: 426 printWsType("Sun", pInfo->name); 427 break; 428#endif 429#ifdef WSKBD_TYPE_SUN5 430 case WSKBD_TYPE_SUN5: 431 printWsType("Sun5", pInfo->name); 432 break; 433#endif 434 default: 435 xf86Msg(X_ERROR, "%s: Unsupported wskbd type \"%d\"", 436 pInfo->name, pKbd->wsKbdType); 437 close(pInfo->fd); 438 return FALSE; 439 } 440 } 441#endif 442 443#if 0 /* no more vtSwitchSupported in xf86-input-keyboard-1.6.0 */ 444#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 445 if ((pKbd->isConsole && 446 ((pKbd->consType == SYSCONS) || (pKbd->consType == PCVT))) || 447 (pKbd->consType == WSCONS)) 448 pKbd->vtSwitchSupported = TRUE; 449#endif 450#endif 451 452 return TRUE; 453} 454 455_X_EXPORT Bool 456xf86OSKbdPreInit(InputInfoPtr pInfo) 457{ 458 KbdDevPtr pKbd = pInfo->private; 459 460 pKbd->KbdInit = KbdInit; 461 pKbd->KbdOn = KbdOn; 462 pKbd->KbdOff = KbdOff; 463 pKbd->Bell = SoundBell; 464 pKbd->SetLeds = SetKbdLeds; 465 pKbd->GetLeds = GetKbdLeds; 466 pKbd->KbdGetMapping = KbdGetMapping; 467 468 pKbd->RemapScanCode = NULL; 469 470 pKbd->OpenKeyboard = OpenKeyboard; 471 472 pKbd->private = calloc(sizeof(BsdKbdPrivRec), 1); 473 if (pKbd->private == NULL) { 474 xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n"); 475 return FALSE; 476 } 477 return TRUE; 478} 479