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