sunKbd.c revision e83940e6
1/* $Xorg: sunKbd.c,v 1.3 2000/08/17 19:48:30 cpqbld Exp $ */ 2/*- 3 * Copyright 1987 by the Regents of the University of California 4 * 5 * Permission to use, copy, modify, and distribute this 6 * software and its documentation for any purpose and without 7 * fee is hereby granted, provided that the above copyright 8 * notice appear in all copies. The University of California 9 * makes no representations about the suitability of this 10 * software for any purpose. It is provided "as is" without 11 * express or implied warranty. 12 */ 13 14/************************************************************ 15Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA. 16 17 All Rights Reserved 18 19Permission to use, copy, modify, and distribute this 20software and its documentation for any purpose and without 21fee is hereby granted, provided that the above copyright no- 22tice appear in all copies and that both that copyright no- 23tice and this permission notice appear in supporting docu- 24mentation, and that the names of Sun or The Open Group 25not be used in advertising or publicity pertaining to 26distribution of the software without specific prior 27written permission. Sun and The Open Group make no 28representations about the suitability of this software for 29any purpose. It is provided "as is" without any express or 30implied warranty. 31 32SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 33INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- 34NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- 35ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 36ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 37PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 38OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 39THE USE OR PERFORMANCE OF THIS SOFTWARE. 40 41********************************************************/ 42/* $XFree86: xc/programs/Xserver/hw/sun/sunKbd.c,v 1.9 2003/11/17 22:20:36 dawes Exp $ */ 43 44#define NEED_EVENTS 45#include "sun.h" 46#include <X11/keysym.h> 47#include <X11/Sunkeysym.h> 48#include "mi.h" 49 50#include <X11/extensions/XKB.h> 51#include "xkbsrv.h" 52#include "xkbstr.h" 53 54#ifdef __sun 55#define SUN_LED_MASK 0x0f 56#else 57#define SUN_LED_MASK 0x07 58#endif 59#define MIN_KEYCODE 7 /* necessary to avoid the mouse buttons */ 60#define MAX_KEYCODE 255 /* limited by the protocol */ 61#define NUM_KEYCODES (MAX_KEYCODE - MIN_KEYCODE + 1) 62#ifndef KB_SUN4 63#define KB_SUN4 4 64#endif 65 66#define Meta_Mask Mod1Mask 67#define Mode_switch_Mask Mod2Mask 68#define Alt_Mask Mod3Mask 69#define Num_Lock_Mask Mod4Mask 70#define ScrollLockMask Mod5Mask 71 72#define tvminus(tv, tv1, tv2) /* tv = tv1 - tv2 */ \ 73 if ((tv1).tv_usec < (tv2).tv_usec) { \ 74 (tv1).tv_usec += 1000000; \ 75 (tv1).tv_sec -= 1; \ 76 } \ 77 (tv).tv_usec = (tv1).tv_usec - (tv2).tv_usec; \ 78 (tv).tv_sec = (tv1).tv_sec - (tv2).tv_sec; 79 80#define tvplus(tv, tv1, tv2) /* tv = tv1 + tv2 */ \ 81 (tv).tv_sec = (tv1).tv_sec + (tv2).tv_sec; \ 82 (tv).tv_usec = (tv1).tv_usec + (tv2).tv_usec; \ 83 if ((tv).tv_usec > 1000000) { \ 84 (tv).tv_usec -= 1000000; \ 85 (tv).tv_sec += 1; \ 86 } 87 88/* 89 * Data private to any sun keyboard. 90 */ 91typedef struct { 92 int fd; 93 int type; /* Type of keyboard */ 94 int layout; /* The layout of the keyboard */ 95 int click; /* kbd click save state */ 96 Leds leds; /* last known LED state */ 97 KeySymsRec keysym; /* working keysym */ 98 Firm_event evbuf[SUN_MAXEVENTS]; /* Buffer for Firm_events */ 99} sunKbdPrivRec, *sunKbdPrivPtr; 100 101static void sunKbdEvents(int, int, void *); 102static void sunKbdWait(void); 103static void sunInitModMap(const KeySymsRec *, CARD8 *); 104static int sunKbdGetEvents(DeviceIntPtr); 105static void sunKbdEnqueueEvent(DeviceIntPtr, Firm_event *); 106static void SwapLKeys(KeySymsRec *); 107static void SetLights(KeybdCtrl *, int); 108static KeyCode LookupKeyCode(KeySym, XkbDescPtr, KeySymsPtr); 109static void pseudoKey(DeviceIntPtr, Bool, KeyCode); 110static void DoLEDs(DeviceIntPtr, KeybdCtrl *, sunKbdPrivPtr); 111static int getKbdType(int); 112static int sunChangeKbdTranslation(int, Bool); 113 114DeviceIntPtr sunKeyboardDevice = NULL; 115 116static void 117sunKbdEvents(int fd, int ready, void *data) 118{ 119 int i, numEvents; 120 DeviceIntPtr device = (DeviceIntPtr)data; 121 DevicePtr pKeyboard = &device->public; 122 sunKbdPrivPtr pPriv = pKeyboard->devicePrivate; 123 124 input_lock(); 125 126 do { 127 numEvents = sunKbdGetEvents(device); 128 for (i = 0; i < numEvents; i++) { 129 sunKbdEnqueueEvent(device, &pPriv->evbuf[i]); 130 } 131 } while (numEvents == SUN_MAXEVENTS); 132 133 input_unlock(); 134} 135 136static void 137sunKbdWait(void) 138{ 139 static struct timeval lastChngKbdTransTv; 140 struct timeval tv; 141 struct timeval lastChngKbdDeltaTv; 142 unsigned int lastChngKbdDelta; 143 144 X_GETTIMEOFDAY(&tv); 145 if (!lastChngKbdTransTv.tv_sec) 146 lastChngKbdTransTv = tv; 147 tvminus(lastChngKbdDeltaTv, tv, lastChngKbdTransTv); 148 lastChngKbdDelta = TVTOMILLI(lastChngKbdDeltaTv); 149 if (lastChngKbdDelta < 750) { 150 unsigned wait; 151 /* 152 * We need to guarantee at least 750 milliseconds between 153 * calls to KIOCTRANS. YUCK! 154 */ 155 wait = (750L - lastChngKbdDelta) * 1000L; 156 usleep (wait); 157 X_GETTIMEOFDAY(&tv); 158 } 159 lastChngKbdTransTv = tv; 160} 161 162static 163void SwapLKeys(KeySymsRec* keysyms) 164{ 165 unsigned int i; 166 KeySym k; 167 168 for (i = 2; i < keysyms->maxKeyCode * keysyms->mapWidth; i++) 169 if (keysyms->map[i] == XK_L1 || 170 keysyms->map[i] == XK_L2 || 171 keysyms->map[i] == XK_L3 || 172 keysyms->map[i] == XK_L4 || 173 keysyms->map[i] == XK_L5 || 174 keysyms->map[i] == XK_L6 || 175 keysyms->map[i] == XK_L7 || 176 keysyms->map[i] == XK_L8 || 177 keysyms->map[i] == XK_L9 || 178 keysyms->map[i] == XK_L10) { 179 /* yes, I could have done a clever two line swap! */ 180 k = keysyms->map[i - 2]; 181 keysyms->map[i - 2] = keysyms->map[i]; 182 keysyms->map[i] = k; 183 } 184} 185 186static void 187SetLights(KeybdCtrl* ctrl, int fd) 188{ 189#ifdef KIOCSLED 190 static unsigned char led_tab[16] = { 191 0, 192#ifdef __sun 193 LED_NUM_LOCK, 194 LED_SCROLL_LOCK, 195 LED_SCROLL_LOCK | LED_NUM_LOCK, 196 LED_COMPOSE, 197 LED_COMPOSE | LED_NUM_LOCK, 198 LED_COMPOSE | LED_SCROLL_LOCK, 199 LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK, 200 LED_CAPS_LOCK, 201 LED_CAPS_LOCK | LED_NUM_LOCK, 202 LED_CAPS_LOCK | LED_SCROLL_LOCK, 203 LED_CAPS_LOCK | LED_SCROLL_LOCK | LED_NUM_LOCK, 204 LED_CAPS_LOCK | LED_COMPOSE, 205 LED_CAPS_LOCK | LED_COMPOSE | LED_NUM_LOCK, 206 LED_CAPS_LOCK | LED_COMPOSE | LED_SCROLL_LOCK, 207 LED_CAPS_LOCK | LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK 208#else 209 LED_CAPS_LOCK, 210 LED_NUM_LOCK, 211 LED_NUM_LOCK | LED_CAPS_LOCK, 212 LED_SCROLL_LOCK, 213 LED_SCROLL_LOCK | LED_CAPS_LOCK, 214 LED_SCROLL_LOCK | LED_NUM_LOCK, 215 LED_SCROLL_LOCK | LED_NUM_LOCK | LED_CAPS_LOCK, 216 LED_COMPOSE, 217 LED_COMPOSE | LED_CAPS_LOCK, 218 LED_COMPOSE | LED_NUM_LOCK, 219 LED_COMPOSE | LED_NUM_LOCK | LED_CAPS_LOCK, 220 LED_COMPOSE | LED_SCROLL_LOCK, 221 LED_COMPOSE | LED_SCROLL_LOCK | LED_CAPS_LOCK, 222 LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK, 223 LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK | LED_CAPS_LOCK, 224#endif 225 }; 226 if (ioctl (fd, KIOCSLED, (caddr_t)&led_tab[ctrl->leds & SUN_LED_MASK]) == -1) 227 LogMessage(X_ERROR, "Failed to set keyboard lights\n"); 228#endif 229} 230 231 232/*- 233 *----------------------------------------------------------------------- 234 * sunBell -- 235 * Ring the terminal/keyboard bell 236 * 237 * Results: 238 * Ring the keyboard bell for an amount of time proportional to 239 * "loudness." 240 * 241 * Side Effects: 242 * None, really... 243 * 244 *----------------------------------------------------------------------- 245 */ 246 247static void 248bell(int fd, int duration) 249{ 250 int kbdCmd; /* Command to give keyboard */ 251 252 kbdCmd = KBD_CMD_BELL; 253 if (ioctl (fd, KIOCCMD, &kbdCmd) == -1) { 254 LogMessage(X_ERROR, "Failed to activate bell\n"); 255 return; 256 } 257 if (duration) usleep (duration); 258 kbdCmd = KBD_CMD_NOBELL; 259 if (ioctl (fd, KIOCCMD, &kbdCmd) == -1) 260 LogMessage(X_ERROR, "Failed to deactivate bell\n"); 261} 262 263static void 264sunBell(int percent, DeviceIntPtr device, void *ctrl, int unused) 265{ 266 KeybdCtrl* kctrl = (KeybdCtrl*) ctrl; 267 sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate; 268 269 if (percent == 0 || kctrl->bell == 0) 270 return; 271 272 bell (pPriv->fd, kctrl->bell_duration * 1000); 273} 274 275void 276DDXRingBell(int volume, int pitch, int duration) 277{ 278 DeviceIntPtr pKeyboard; 279 sunKbdPrivPtr pPriv; 280 281 pKeyboard = sunKeyboardDevice; 282 if (pKeyboard != NULL) { 283 pPriv = (sunKbdPrivPtr)pKeyboard->public.devicePrivate; 284 bell(pPriv->fd, duration * 1000); 285 } 286} 287 288 289#ifdef __sun 290#define XLED_NUM_LOCK 0x1 291#define XLED_COMPOSE 0x4 292#define XLED_SCROLL_LOCK 0x2 293#define XLED_CAPS_LOCK 0x8 294#else 295#define XLED_NUM_LOCK 0x2 296#define XLED_COMPOSE 0x8 297#define XLED_SCROLL_LOCK 0x4 298#define XLED_CAPS_LOCK 0x1 299#endif 300 301static KeyCode 302LookupKeyCode(KeySym keysym, XkbDescPtr xkb, KeySymsPtr syms) 303{ 304 KeyCode i; 305 int ii, index = 0; 306 307 for (i = xkb->min_key_code; i < xkb->max_key_code; i++) 308 for (ii = 0; ii < syms->mapWidth; ii++) 309 if (syms->map[index++] == keysym) 310 return i; 311 return 0; 312} 313 314static void 315pseudoKey(DeviceIntPtr device, Bool down, KeyCode keycode) 316{ 317 int bit; 318 CARD8 modifiers; 319 CARD16 mask; 320 BYTE* kptr; 321 322 kptr = &device->key->down[keycode >> 3]; 323 bit = 1 << (keycode & 7); 324 modifiers = device->key->xkbInfo->desc->map->modmap[keycode]; 325 if (down) { 326 /* fool dix into thinking this key is now "down" */ 327 int i; 328 *kptr |= bit; 329 for (i = 0, mask = 1; modifiers; i++, mask <<= 1) 330 if (mask & modifiers) { 331 device->key->modifierKeyCount[i]++; 332 modifiers &= ~mask; 333 } 334 } else { 335 /* fool dix into thinking this key is now "up" */ 336 if (*kptr & bit) { 337 int i; 338 *kptr &= ~bit; 339 for (i = 0, mask = 1; modifiers; i++, mask <<= 1) 340 if (mask & modifiers) { 341 if (--device->key->modifierKeyCount[i] <= 0) { 342 device->key->modifierKeyCount[i] = 0; 343 } 344 modifiers &= ~mask; 345 } 346 } 347 } 348} 349 350static void 351DoLEDs( 352 DeviceIntPtr device, /* Keyboard to alter */ 353 KeybdCtrl* ctrl, 354 sunKbdPrivPtr pPriv 355) 356{ 357 XkbDescPtr xkb; 358 KeySymsPtr syms; 359 360 xkb = device->key->xkbInfo->desc; 361 syms = XkbGetCoreMap(device); 362 if (!syms) 363 return; /* XXX */ 364 365 if ((ctrl->leds & XLED_CAPS_LOCK) && !(pPriv->leds & XLED_CAPS_LOCK)) 366 pseudoKey(device, TRUE, 367 LookupKeyCode(XK_Caps_Lock, xkb, syms)); 368 369 if (!(ctrl->leds & XLED_CAPS_LOCK) && (pPriv->leds & XLED_CAPS_LOCK)) 370 pseudoKey(device, FALSE, 371 LookupKeyCode(XK_Caps_Lock, xkb, syms)); 372 373 if ((ctrl->leds & XLED_NUM_LOCK) && !(pPriv->leds & XLED_NUM_LOCK)) 374 pseudoKey(device, TRUE, 375 LookupKeyCode(XK_Num_Lock, xkb, syms)); 376 377 if (!(ctrl->leds & XLED_NUM_LOCK) && (pPriv->leds & XLED_NUM_LOCK)) 378 pseudoKey(device, FALSE, 379 LookupKeyCode(XK_Num_Lock, xkb, syms)); 380 381 if ((ctrl->leds & XLED_SCROLL_LOCK) && !(pPriv->leds & XLED_SCROLL_LOCK)) 382 pseudoKey(device, TRUE, 383 LookupKeyCode(XK_Scroll_Lock, xkb, syms)); 384 385 if (!(ctrl->leds & XLED_SCROLL_LOCK) && (pPriv->leds & XLED_SCROLL_LOCK)) 386 pseudoKey(device, FALSE, 387 LookupKeyCode(XK_Scroll_Lock, xkb, syms)); 388 389 if ((ctrl->leds & XLED_COMPOSE) && !(pPriv->leds & XLED_COMPOSE)) 390 pseudoKey(device, TRUE, 391 LookupKeyCode(SunXK_Compose, xkb, syms)); 392 393 if (!(ctrl->leds & XLED_COMPOSE) && (pPriv->leds & XLED_COMPOSE)) 394 pseudoKey(device, FALSE, 395 LookupKeyCode(SunXK_Compose, xkb, syms)); 396 397 pPriv->leds = ctrl->leds & SUN_LED_MASK; 398 SetLights (ctrl, pPriv->fd); 399 free(syms->map); 400 free(syms); 401} 402 403/*- 404 *----------------------------------------------------------------------- 405 * sunKbdCtrl -- 406 * Alter some of the keyboard control parameters 407 * 408 * Results: 409 * None. 410 * 411 * Side Effects: 412 * Some... 413 * 414 *----------------------------------------------------------------------- 415 */ 416 417static void 418sunKbdCtrl(DeviceIntPtr device, KeybdCtrl* ctrl) 419{ 420 sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate; 421 422 if (pPriv->fd < 0) return; 423 424 if (ctrl->click != pPriv->click) { 425 int kbdClickCmd; 426 427 pPriv->click = ctrl->click; 428 kbdClickCmd = pPriv->click ? KBD_CMD_CLICK : KBD_CMD_NOCLICK; 429 if (ioctl (pPriv->fd, KIOCCMD, &kbdClickCmd) == -1) 430 LogMessage(X_ERROR, "Failed to set keyclick\n"); 431 } 432 if ((pPriv->type == KB_SUN4) && (pPriv->leds != (ctrl->leds & SUN_LED_MASK))) 433 DoLEDs(device, ctrl, pPriv); 434} 435 436/*- 437 *----------------------------------------------------------------------- 438 * sunInitKbdNames -- 439 * Handle the XKB initialization 440 * 441 * Results: 442 * None. 443 * 444 * Comments: 445 * This function needs considerable work, in conjunctions with 446 * the need to add geometry descriptions of Sun Keyboards. 447 * It would also be nice to have #defines for all the keyboard 448 * layouts so that we don't have to have these hard-coded 449 * numbers. 450 * 451 *----------------------------------------------------------------------- 452 */ 453static void 454sunInitKbdNames(XkbRMLVOSet *rmlvo, sunKbdPrivPtr pKbd) 455{ 456#if 0 /* XXX to be revisited later */ 457#ifndef XKBBUFSIZE 458#define XKBBUFSIZE 64 459#endif 460 static char keycodesbuf[XKBBUFSIZE]; 461 static char geometrybuf[XKBBUFSIZE]; 462 static char symbolsbuf[XKBBUFSIZE]; 463 464 names->keymap = NULL; 465 names->compat = "compat/complete"; 466 names->types = "types/complete"; 467 names->keycodes = keycodesbuf; 468 names->geometry = geometrybuf; 469 names->symbols = symbolsbuf; 470 (void) strcpy (keycodesbuf, "keycodes/"); 471 (void) strcpy (geometrybuf, "geometry/"); 472 (void) strcpy (symbolsbuf, "symbols/"); 473 474 /* keycodes & geometry */ 475 switch (pKbd->type) { 476 case KB_SUN2: 477 (void) strcat (names->keycodes, "sun(type2)"); 478 (void) strcat (names->geometry, "sun(type2)"); 479 (void) strcat (names->symbols, "us(sun2)"); 480 break; 481 case KB_SUN3: 482 (void) strcat (names->keycodes, "sun(type3)"); 483 (void) strcat (names->geometry, "sun(type3)"); 484 (void) strcat (names->symbols, "us(sun3)"); 485 break; 486 case KB_SUN4: 487 /* First, catch "fully known" models */ 488 switch (pKbd->layout) { 489 case 11: /* type4, Sweden */ 490 (void) strcat (names->geometry, "sun(type4_se)"); 491 (void) strcat (names->keycodes, 492 "sun(type4_se_swapctl)"); 493 (void) strcat (names->symbols, 494 "sun/se(sun4)+se(fixdollar)"); 495 return; 496 break; 497 case 43: /* type5/5c, Sweden */ 498 (void) strcat (names->geometry, "sun(type5c_se)"); 499 (void) strcat (names->keycodes, "sun(type5_se)"); 500 (void) strcat (names->symbols, 501 "sun/se(sun5)+se(fixdollar)"); 502 return; 503 break; 504 case 90: /* "Compact 1", Sweden (???) */ 505 break; /* No specific mapping, yet */ 506 default: 507 break; 508 } 509 510 if (pKbd->layout == 19) { 511 (void) strcat (names->keycodes, "sun(US101A)"); 512 (void) strcat (names->geometry, "pc101-NG"); /* XXX */ 513 (void) strcat (names->symbols, "us(pc101)"); 514 } else if (pKbd->layout < 33) { 515 (void) strcat (names->keycodes, "sun(type4)"); 516 (void) strcat (names->geometry, "sun(type4)"); 517 if (sunSwapLkeys) 518 (void) strcat (names->symbols, "sun/us(sun4ol)"); 519 else 520 (void) strcat (names->symbols, "sun/us(sun4)"); 521 } else { 522 switch (pKbd->layout) { 523 case 33: case 80: /* U.S. */ 524 case 47: case 94: /* Korea */ 525 case 48: case 95: /* Taiwan */ 526 case 49: case 96: /* Japan */ 527 (void) strcat (names->keycodes, "sun(type5)"); 528 (void) strcat (names->geometry, "sun(type5)"); 529 break; 530 case 34: case 81: /* U.S. Unix */ 531 (void) strcat (names->keycodes, "sun(type5)"); 532 (void) strcat (names->geometry, "sun(type5unix)"); 533 break; 534 default: 535 (void) strcat (names->keycodes, "sun(type5_euro)"); 536 (void) strcat (names->geometry, "sun(type5euro)"); 537 } 538 539 if (sunSwapLkeys) 540 (void) strcat (names->symbols, "sun/us(sun5ol)"); 541 else 542 (void) strcat (names->symbols, "sun/us(sun5)"); 543 } 544 break; 545 default: 546 names->keycodes = names->geometry = NULL; 547 break; 548 } 549 550 /* extra symbols */ 551 552 if (pKbd->type == KB_SUN4) { 553 switch (pKbd->layout) { 554 case 4: case 36: case 83: 555 case 5: case 37: case 84: 556 case 6: case 38: case 85: 557 case 8: case 40: case 87: 558 case 9: case 41: case 88: 559 case 10: case 42: case 89: 560/* case 11: case 43: case 90: */ /* handled earlier */ 561 case 12: case 44: case 91: 562 case 13: case 45: case 92: 563 case 14: case 46: case 93: 564 (void) strcat (names->symbols, "+iso9995-3(basic)"); break; 565 } 566 } 567 568 if (pKbd->type == KB_SUN4) { 569 switch (pKbd->layout) { 570 case 0: case 1: case 33: case 34: case 80: case 81: 571 break; 572 case 3: 573 (void) strcat (names->symbols, "+ca"); break; 574 case 4: case 36: case 83: 575 (void) strcat (names->symbols, "+dk"); break; 576 case 5: case 37: case 84: 577 (void) strcat (names->symbols, "+de"); break; 578 case 6: case 38: case 85: 579 (void) strcat (names->symbols, "+it"); break; 580 case 8: case 40: case 87: 581 (void) strcat (names->symbols, "+no"); break; 582 case 9: case 41: case 88: 583 (void) strcat (names->symbols, "+pt"); break; 584 case 10: case 42: case 89: 585 (void) strcat (names->symbols, "+es"); break; 586 /* case 11: case 43: */ /* handled earlier */ 587 case 90: 588 (void) strcat (names->symbols, "+se"); break; 589 case 12: case 44: case 91: 590 (void) strcat (names->symbols, "+fr_CH"); break; 591 case 13: case 45: case 92: 592 (void) strcat (names->symbols, "+de_CH"); break; 593 case 14: case 46: case 93: 594 (void) strcat (names->symbols, "+gb"); break; /* s/b en_UK */ 595 case 52: 596 (void) strcat (names->symbols, "+pl"); break; 597 case 53: 598 (void) strcat (names->symbols, "+cs"); break; 599 case 54: 600 (void) strcat (names->symbols, "+ru"); break; 601#if 0 602 /* don't have symbols defined for these yet, let them default */ 603 case 2: 604 (void) strcat (names->symbols, "+fr_BE"); break; 605 case 7: case 39: case 86: 606 (void) strcat (names->symbols, "+nl"); break; 607 case 50: case 97: 608 (void) strcat (names->symbols, "+fr_CA"); break; 609 case 16: case 47: case 94: 610 (void) strcat (names->symbols, "+ko"); break; 611 case 17: case 48: case 95: 612 (void) strcat (names->symbols, "+tw"); break; 613 case 32: case 49: case 96: 614 (void) strcat (names->symbols, "+jp"); break; 615 case 51: 616 (void) strcat (names->symbols, "+hu"); break; 617#endif 618 /* 619 * by setting the symbols to NULL XKB will use the symbols in 620 * the "default" keymap. 621 */ 622 default: 623 names->symbols = NULL; return; break; 624 } 625 } 626#else 627 rmlvo->rules = "base"; 628 rmlvo->model = "empty"; 629 rmlvo->layout = "empty"; 630 rmlvo->variant = NULL; 631 rmlvo->options = NULL; 632#endif 633} 634 635static int 636getKbdType(int fd) 637{ 638/* 639 * The Sun 386i has system include files that preclude this pre SunOS 4.1 640 * test for the presence of a type 4 keyboard however it really doesn't 641 * matter since no 386i has ever been shipped with a type 3 keyboard. 642 * SunOS 4.1 no longer needs this kludge. 643 */ 644#if !defined(i386) && !defined(KIOCGKEY) 645#define TYPE4KEYBOARDOVERRIDE 646#endif 647 648 int ii, type; 649 650 for (ii = 0; ii < 3; ii++) { 651 sunKbdWait(); 652 (void)ioctl(fd, KIOCTYPE, &type); 653#ifdef TYPE4KEYBOARDOVERRIDE 654 /* 655 * Magic. Look for a key which is non-existent on a real type 656 * 3 keyboard but does exist on a type 4 keyboard. 657 */ 658 if (type == KB_SUN3) { 659 struct kiockeymap key; 660 661 key.kio_tablemask = 0; 662 key.kio_station = 118; 663 if (ioctl(fd, KIOCGKEY, &key) == -1) { 664 LogMessage(X_ERROR, "ioctl KIOCGKEY\n" ); 665 FatalError("Can't KIOCGKEY on fd %d\n", fd); 666 } 667 if (key.kio_entry != HOLE) 668 type = KB_SUN4; 669 } 670#endif 671 switch (type) { 672 case KB_SUN2: 673 case KB_SUN3: 674 case KB_SUN4: 675 return type; 676 default: 677 sunChangeKbdTranslation(fd, FALSE); 678 continue; 679 } 680 } 681 return -1; 682} 683 684/*- 685 *----------------------------------------------------------------------- 686 * sunKbdProc -- 687 * Handle the initialization, etc. of a keyboard. 688 * 689 * Results: 690 * None. 691 * 692 *----------------------------------------------------------------------- 693 */ 694 695int 696sunKbdProc(DeviceIntPtr device, int what) 697{ 698 DevicePtr pKeyboard = &device->public; 699 sunKbdPrivPtr pPriv; 700 KeybdCtrl* ctrl = &device->kbdfeed->ctrl; 701 XkbRMLVOSet rmlvo; 702 CARD8 workingModMap[MAP_LENGTH]; 703 int type = -1, layout = -1, mapsize; 704 KeySymsPtr keysym; 705 KeySym *map; 706 707 switch (what) { 708 case DEVICE_INIT: 709 pPriv = malloc(sizeof(*pPriv)); 710 if (pPriv == NULL) { 711 LogMessage(X_ERROR, "Cannot allocate private data for keyboard\n"); 712 return !Success; 713 } 714 pPriv->fd = open("/dev/kbd", O_RDWR | O_NONBLOCK, 0); 715 if (pPriv->fd < 0) { 716 LogMessage(X_ERROR, "Cannot open /dev/kbd, error %d\n", errno); 717 free(pPriv); 718 return !Success; 719 } 720 721 type = getKbdType(pPriv->fd); 722 if (type < 0) 723 FatalError("Unsupported keyboard type %d\n", type); 724 725 switch (type) { 726 case KB_SUN2: 727 case KB_SUN3: 728 /* No layout variation */ 729 LogMessage(X_INFO, "Sun type %d Keyboard\n", type); 730 break; 731 case KB_SUN4: 732#define LAYOUT_US5 33 733 (void)ioctl(pPriv->fd, KIOCLAYOUT, &layout); 734 if (layout < 0 || 735 layout > sunMaxLayout || 736 sunType4KeyMaps[layout] == NULL) 737 FatalError("Unsupported keyboard type 4 layout %d\n", layout); 738 /* Type 5 keyboard also treated as Type 4 layout variants */ 739 LogMessage(X_INFO, "Sun type %d Keyboard, layout %d\n", 740 layout >= LAYOUT_US5 ? 5 : 4, layout); 741 break; 742 default: 743 LogMessage(X_INFO, "Unknown keyboard type\n"); 744 break; 745 } 746 747 keysym = &sunKeySyms[type]; 748 mapsize = ((int)keysym->maxKeyCode - (int)keysym->minKeyCode + 1) 749 * keysym->mapWidth * sizeof(keysym->map[0]); 750 map = malloc(mapsize); 751 if (map == NULL) { 752 LogMessage(X_ERROR, "Failed to allocate KeySym map\n"); 753 close(pPriv->fd); 754 free(pPriv); 755 return !Success; 756 } 757 if (type == KB_SUN4) { 758 memcpy(map, sunType4KeyMaps[layout], mapsize); 759 } else { 760 memcpy(map, sunKeySyms[type].map, mapsize); 761 } 762 763 pPriv->type = type; 764 pPriv->layout = layout; 765 pPriv->click = 0; 766 pPriv->leds = (Leds)0; 767 pPriv->keysym.map = map; 768 pPriv->keysym.minKeyCode = keysym->minKeyCode; 769 pPriv->keysym.maxKeyCode = keysym->maxKeyCode; 770 pPriv->keysym.mapWidth = keysym->mapWidth; 771 772 /* sunKbdCtrl() callback refers pKeyboard->devicePrivate */ 773 pKeyboard->devicePrivate = pPriv; 774 pKeyboard->on = FALSE; 775 776 if (type == KB_SUN4 && sunSwapLkeys) { 777 /* This could update pPriv->keysym.map */ 778 SwapLKeys(&pPriv->keysym); 779 } 780 781 if (pPriv->keysym.minKeyCode < MIN_KEYCODE) { 782 pPriv->keysym.minKeyCode += MIN_KEYCODE; 783 pPriv->keysym.maxKeyCode += MIN_KEYCODE; 784 } 785 if (pPriv->keysym.maxKeyCode > MAX_KEYCODE) 786 pPriv->keysym.maxKeyCode = MAX_KEYCODE; 787 788 sunInitModMap(&pPriv->keysym, workingModMap); 789 790 sunInitKbdNames(&rmlvo, pPriv); 791#if 0 /* XXX needs more work for Xorg xkb */ 792 InitKeyboardDeviceStruct(device, &rmlvo, 793 sunBell, sunKbdCtrl); 794#else 795 XkbSetRulesDflts(&rmlvo); 796 InitKeyboardDeviceStruct(device, NULL, 797 sunBell, sunKbdCtrl); 798 XkbApplyMappingChange(device, &pPriv->keysym, 799 pPriv->keysym.minKeyCode, 800 pPriv->keysym.maxKeyCode - 801 pPriv->keysym.minKeyCode + 1, 802 workingModMap, serverClient); 803#endif 804 break; 805 806 case DEVICE_ON: 807 pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate; 808 /* 809 * Set the keyboard into "direct" mode and turn on 810 * event translation. 811 */ 812 if (sunChangeKbdTranslation(pPriv->fd, TRUE) == -1) 813 FatalError("Can't set keyboard translation\n"); 814 815 SetNotifyFd(pPriv->fd, sunKbdEvents, X_NOTIFY_READ, device); 816 817 pKeyboard->on = TRUE; 818 break; 819 820 case DEVICE_OFF: 821 pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate; 822 if (pPriv->type == KB_SUN4) { 823 /* dumb bug in Sun's keyboard! Turn off LEDS before resetting */ 824 pPriv->leds = 0; 825 ctrl->leds = 0; 826 SetLights(ctrl, pPriv->fd); 827 } 828 /* 829 * Restore original keyboard directness and translation. 830 */ 831 if (sunChangeKbdTranslation(pPriv->fd, FALSE) == -1) 832 FatalError("Can't reset keyboard translation\n"); 833 RemoveNotifyFd(pPriv->fd); 834 pKeyboard->on = FALSE; 835 break; 836 837 case DEVICE_CLOSE: 838 pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate; 839 free(pPriv->keysym.map); 840 close(pPriv->fd); 841 free(pPriv); 842 pKeyboard->devicePrivate = NULL; 843 break; 844 845 case DEVICE_ABORT: 846 /* 847 * Restore original keyboard directness and translation. 848 */ 849 pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate; 850 (void)sunChangeKbdTranslation(pPriv->fd, FALSE); 851 break; 852 } 853 return Success; 854} 855 856/*------------------------------------------------------------------------- 857 * sunInitModMap -- 858 * Initialize ModMap per specified KeyMap table. 859 * 860 * Results: 861 * None. 862 * 863 * Side Effects: 864 * None. 865 *-----------------------------------------------------------------------*/ 866static void 867sunInitModMap( 868 const KeySymsRec *KeySyms, /* KeyMap data to set ModMap */ 869 CARD8 *ModMap /* ModMap to be initialized */ 870) 871{ 872 KeySym *k; 873 int i, min, max, width; 874 875 for (i = 0; i < MAP_LENGTH; i++) 876 ModMap[i] = NoSymbol; 877 878 min = KeySyms->minKeyCode; 879 max = KeySyms->maxKeyCode; 880 width = KeySyms->mapWidth; 881 for (i = min, k = KeySyms->map; i < max; i++, k += width) { 882 switch (*k) { 883 884 case XK_Shift_L: 885 case XK_Shift_R: 886 ModMap[i] = ShiftMask; 887 break; 888 889 case XK_Control_L: 890 case XK_Control_R: 891 ModMap[i] = ControlMask; 892 break; 893 894 case XK_Caps_Lock: 895 ModMap[i] = LockMask; 896 break; 897 898 case XK_Alt_L: 899 case XK_Alt_R: 900 ModMap[i] = Alt_Mask; 901 break; 902 903 case XK_Num_Lock: 904 ModMap[i] = Num_Lock_Mask; 905 break; 906 907 case XK_Scroll_Lock: 908 ModMap[i] = ScrollLockMask; 909 break; 910 911 case XK_Meta_L: 912 case XK_Meta_R: 913 ModMap[i] = Meta_Mask; 914 break; 915 916 case SunXK_AltGraph: 917 ModMap[i] = Mode_switch_Mask; 918 break; 919 } 920 } 921} 922 923/*- 924 *----------------------------------------------------------------------- 925 * sunKbdGetEvents -- 926 * Return the events waiting in the wings for the given keyboard. 927 * 928 * Results: 929 * Update Firm_event buffer in DeviceIntPtr if events are received. 930 * Return the number of received Firm_events in the buffer. 931 * 932 * Side Effects: 933 * None. 934 *----------------------------------------------------------------------- 935 */ 936 937static int 938sunKbdGetEvents(DeviceIntPtr device) 939{ 940 DevicePtr pKeyboard = &device->public; 941 sunKbdPrivPtr pPriv = pKeyboard->devicePrivate; 942 int nBytes; /* number of bytes of events available. */ 943 int NumEvents = 0; 944 945 nBytes = read(pPriv->fd, pPriv->evbuf, sizeof(pPriv->evbuf)); 946 if (nBytes == -1) { 947 if (errno != EWOULDBLOCK) { 948 LogMessage(X_ERROR, "Unexpected error on reading keyboard\n"); 949 FatalError("Could not read the keyboard"); 950 } 951 } else { 952 if (pKeyboard->on) { 953 NumEvents = nBytes / sizeof(pPriv->evbuf[0]); 954 } 955 } 956 return NumEvents; 957} 958 959/*- 960 *----------------------------------------------------------------------- 961 * sunKbdEnqueueEvent -- 962 * 963 *----------------------------------------------------------------------- 964 */ 965 966static void 967sunKbdEnqueueEvent(DeviceIntPtr device, Firm_event *fe) 968{ 969 BYTE keycode; 970 int type; 971 972 keycode = (fe->id & 0x7f) + MIN_KEYCODE; 973 type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress); 974 QueueKeyboardEvents(device, type, keycode); 975} 976 977 978/*- 979 *----------------------------------------------------------------------- 980 * sunChangeKbdTranslation 981 * Makes operating system calls to set keyboard translation 982 * and direction on or off. 983 * 984 * Results: 985 * -1 if failure, else 0. 986 * 987 * Side Effects: 988 * Changes kernel management of keyboard. 989 * 990 *----------------------------------------------------------------------- 991 */ 992static int 993sunChangeKbdTranslation(int fd, Bool makeTranslated) 994{ 995 int tmp; 996#ifndef i386 /* { */ 997 sigset_t hold_mask, old_mask; 998#else /* }{ */ 999 int old_mask; 1000#endif /* } */ 1001 int toread; 1002 char junk[8192]; 1003 1004#ifndef i386 /* { */ 1005 (void) sigfillset(&hold_mask); 1006 (void) sigprocmask(SIG_BLOCK, &hold_mask, &old_mask); 1007#else /* }{ */ 1008 old_mask = sigblock (~0); 1009#endif /* } */ 1010 sunKbdWait(); 1011 if (makeTranslated) { 1012 /* 1013 * Next set the keyboard into "direct" mode and turn on 1014 * event translation. If either of these fails, we can't go 1015 * on. 1016 */ 1017 tmp = 1; 1018 if (ioctl (fd, KIOCSDIRECT, &tmp) == -1) { 1019 ErrorF("Setting keyboard direct mode\n"); 1020 return -1; 1021 } 1022 tmp = TR_UNTRANS_EVENT; 1023 if (ioctl (fd, KIOCTRANS, &tmp) == -1) { 1024 ErrorF("Setting keyboard translation\n"); 1025 ErrorF ("sunChangeKbdTranslation: kbdFd=%d\n", fd); 1026 return -1; 1027 } 1028 } else { 1029 /* 1030 * Next set the keyboard into "indirect" mode and turn off 1031 * event translation. 1032 */ 1033 tmp = 0; 1034 (void)ioctl (fd, KIOCSDIRECT, &tmp); 1035 tmp = TR_ASCII; 1036 (void)ioctl (fd, KIOCTRANS, &tmp); 1037 } 1038 if (ioctl (fd, FIONREAD, &toread) != -1 && toread > 0) { 1039 while (toread) { 1040 tmp = toread; 1041 if (toread > sizeof (junk)) 1042 tmp = sizeof (junk); 1043 (void) read (fd, junk, tmp); 1044 toread -= tmp; 1045 } 1046 } 1047#ifndef i386 /* { */ 1048 (void) sigprocmask(SIG_SETMASK, &old_mask, NULL); 1049#else /* }{ */ 1050 sigsetmask (old_mask); 1051#endif /* } */ 1052 return 0; 1053} 1054