sunKbd.c revision a740dc46
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#ifndef KB_SUN4
62#define KB_SUN4		4
63#endif
64
65#define tvminus(tv, tv1, tv2)   /* tv = tv1 - tv2 */ \
66		if ((tv1).tv_usec < (tv2).tv_usec) { \
67		    (tv1).tv_usec += 1000000; \
68		    (tv1).tv_sec -= 1; \
69		} \
70		(tv).tv_usec = (tv1).tv_usec - (tv2).tv_usec; \
71		(tv).tv_sec = (tv1).tv_sec - (tv2).tv_sec;
72
73#define tvplus(tv, tv1, tv2)    /* tv = tv1 + tv2 */ \
74		(tv).tv_sec = (tv1).tv_sec + (tv2).tv_sec; \
75		(tv).tv_usec = (tv1).tv_usec + (tv2).tv_usec; \
76		if ((tv).tv_usec > 1000000) { \
77		    (tv).tv_usec -= 1000000; \
78		    (tv).tv_sec += 1; \
79		}
80
81static void sunKbdHandlerNotify(int, int, void *);
82static void SwapLKeys(KeySymsRec *);
83static void SetLights(KeybdCtrl *, int);
84static KeyCode LookupKeyCode(KeySym, XkbDescPtr, KeySymsPtr);
85static void pseudoKey(DeviceIntPtr, Bool, KeyCode);
86static void DoLEDs(DeviceIntPtr, KeybdCtrl *, sunKbdPrivPtr);
87
88DeviceIntPtr	sunKeyboardDevice = NULL;
89
90static void
91sunKbdHandlerNotify(int fd __unused, int ready __unused, void *data __unused)
92{
93}
94
95void
96sunKbdWait(void)
97{
98    static struct timeval lastChngKbdTransTv;
99    struct timeval tv;
100    struct timeval lastChngKbdDeltaTv;
101    unsigned int lastChngKbdDelta;
102
103    X_GETTIMEOFDAY(&tv);
104    if (!lastChngKbdTransTv.tv_sec)
105	lastChngKbdTransTv = tv;
106    tvminus(lastChngKbdDeltaTv, tv, lastChngKbdTransTv);
107    lastChngKbdDelta = TVTOMILLI(lastChngKbdDeltaTv);
108    if (lastChngKbdDelta < 750) {
109	unsigned wait;
110	/*
111         * We need to guarantee at least 750 milliseconds between
112	 * calls to KIOCTRANS. YUCK!
113	 */
114	wait = (750L - lastChngKbdDelta) * 1000L;
115        usleep (wait);
116        X_GETTIMEOFDAY(&tv);
117    }
118    lastChngKbdTransTv = tv;
119}
120
121static
122void SwapLKeys(KeySymsRec* keysyms)
123{
124    unsigned int i;
125    KeySym k;
126
127    for (i = 2; i < keysyms->maxKeyCode * keysyms->mapWidth; i++)
128	if (keysyms->map[i] == XK_L1 ||
129	    keysyms->map[i] == XK_L2 ||
130	    keysyms->map[i] == XK_L3 ||
131	    keysyms->map[i] == XK_L4 ||
132	    keysyms->map[i] == XK_L5 ||
133	    keysyms->map[i] == XK_L6 ||
134	    keysyms->map[i] == XK_L7 ||
135	    keysyms->map[i] == XK_L8 ||
136	    keysyms->map[i] == XK_L9 ||
137	    keysyms->map[i] == XK_L10) {
138	    /* yes, I could have done a clever two line swap! */
139	    k = keysyms->map[i - 2];
140	    keysyms->map[i - 2] = keysyms->map[i];
141	    keysyms->map[i] = k;
142	}
143}
144
145static void
146SetLights(KeybdCtrl* ctrl, int fd)
147{
148#ifdef KIOCSLED
149    static unsigned char led_tab[16] = {
150	0,
151#ifdef __sun
152	LED_NUM_LOCK,
153	LED_SCROLL_LOCK,
154	LED_SCROLL_LOCK | LED_NUM_LOCK,
155	LED_COMPOSE,
156	LED_COMPOSE | LED_NUM_LOCK,
157	LED_COMPOSE | LED_SCROLL_LOCK,
158	LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK,
159	LED_CAPS_LOCK,
160	LED_CAPS_LOCK | LED_NUM_LOCK,
161	LED_CAPS_LOCK | LED_SCROLL_LOCK,
162	LED_CAPS_LOCK | LED_SCROLL_LOCK | LED_NUM_LOCK,
163	LED_CAPS_LOCK | LED_COMPOSE,
164	LED_CAPS_LOCK | LED_COMPOSE | LED_NUM_LOCK,
165	LED_CAPS_LOCK | LED_COMPOSE | LED_SCROLL_LOCK,
166	LED_CAPS_LOCK | LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK
167#else
168	LED_CAPS_LOCK,
169	LED_NUM_LOCK,
170	LED_NUM_LOCK | LED_CAPS_LOCK,
171	LED_SCROLL_LOCK,
172	LED_SCROLL_LOCK | LED_CAPS_LOCK,
173	LED_SCROLL_LOCK | LED_NUM_LOCK,
174	LED_SCROLL_LOCK | LED_NUM_LOCK | LED_CAPS_LOCK,
175	LED_COMPOSE,
176	LED_COMPOSE | LED_CAPS_LOCK,
177	LED_COMPOSE | LED_NUM_LOCK,
178	LED_COMPOSE | LED_NUM_LOCK | LED_CAPS_LOCK,
179	LED_COMPOSE | LED_SCROLL_LOCK,
180	LED_COMPOSE | LED_SCROLL_LOCK | LED_CAPS_LOCK,
181	LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK,
182	LED_COMPOSE | LED_SCROLL_LOCK | LED_NUM_LOCK | LED_CAPS_LOCK,
183#endif
184    };
185    if (ioctl (fd, KIOCSLED, (caddr_t)&led_tab[ctrl->leds & SUN_LED_MASK]) == -1)
186	ErrorF("Failed to set keyboard lights");
187#endif
188}
189
190
191/*-
192 *-----------------------------------------------------------------------
193 * sunBell --
194 *	Ring the terminal/keyboard bell
195 *
196 * Results:
197 *	Ring the keyboard bell for an amount of time proportional to
198 *	"loudness."
199 *
200 * Side Effects:
201 *	None, really...
202 *
203 *-----------------------------------------------------------------------
204 */
205
206static void
207bell(int fd, int duration)
208{
209    int		    kbdCmd;   	    /* Command to give keyboard */
210
211    kbdCmd = KBD_CMD_BELL;
212    if (ioctl (fd, KIOCCMD, &kbdCmd) == -1) {
213 	ErrorF("Failed to activate bell");
214	return;
215    }
216    if (duration) usleep (duration);
217    kbdCmd = KBD_CMD_NOBELL;
218    if (ioctl (fd, KIOCCMD, &kbdCmd) == -1)
219	ErrorF("Failed to deactivate bell");
220}
221
222static void
223sunBell(int percent, DeviceIntPtr device, void *ctrl, int unused)
224{
225    KeybdCtrl*      kctrl = (KeybdCtrl*) ctrl;
226    sunKbdPrivPtr   pPriv = (sunKbdPrivPtr) device->public.devicePrivate;
227
228    if (percent == 0 || kctrl->bell == 0)
229 	return;
230
231    bell (pPriv->fd, kctrl->bell_duration * 1000);
232}
233
234void
235DDXRingBell(int volume, int pitch, int duration)
236{
237    DeviceIntPtr pKeyboard;
238    sunKbdPrivPtr pPriv;
239
240    pKeyboard = sunKeyboardDevice;
241    if (pKeyboard != NULL) {
242	pPriv = (sunKbdPrivPtr)pKeyboard->public.devicePrivate;
243	bell(pPriv->fd, duration * 1000);
244    }
245}
246
247
248#ifdef __sun
249#define XLED_NUM_LOCK    0x1
250#define XLED_COMPOSE     0x4
251#define XLED_SCROLL_LOCK 0x2
252#define XLED_CAPS_LOCK   0x8
253#else
254#define XLED_NUM_LOCK    0x2
255#define XLED_COMPOSE     0x8
256#define XLED_SCROLL_LOCK 0x4
257#define XLED_CAPS_LOCK   0x1
258#endif
259
260static KeyCode
261LookupKeyCode(KeySym keysym, XkbDescPtr xkb, KeySymsPtr syms)
262{
263    KeyCode i;
264    int ii, index = 0;
265
266    for (i = xkb->min_key_code; i < xkb->max_key_code; i++)
267	for (ii = 0; ii < syms->mapWidth; ii++)
268	    if (syms->map[index++] == keysym)
269		return i;
270    return 0;
271}
272
273static void
274pseudoKey(DeviceIntPtr device, Bool down, KeyCode keycode)
275{
276    int bit;
277    CARD8 modifiers;
278    CARD16 mask;
279    BYTE* kptr;
280
281    kptr = &device->key->down[keycode >> 3];
282    bit = 1 << (keycode & 7);
283    modifiers = device->key->xkbInfo->desc->map->modmap[keycode];
284    if (down) {
285	/* fool dix into thinking this key is now "down" */
286	int i;
287	*kptr |= bit;
288	for (i = 0, mask = 1; modifiers; i++, mask <<= 1)
289	    if (mask & modifiers) {
290		device->key->modifierKeyCount[i]++;
291		modifiers &= ~mask;
292	    }
293    } else {
294	/* fool dix into thinking this key is now "up" */
295	if (*kptr & bit) {
296	    int i;
297	    *kptr &= ~bit;
298	    for (i = 0, mask = 1; modifiers; i++, mask <<= 1)
299		if (mask & modifiers) {
300		    if (--device->key->modifierKeyCount[i] <= 0) {
301			device->key->modifierKeyCount[i] = 0;
302		    }
303		    modifiers &= ~mask;
304		}
305	}
306    }
307}
308
309static void
310DoLEDs(
311    DeviceIntPtr    device,	    /* Keyboard to alter */
312    KeybdCtrl* ctrl,
313    sunKbdPrivPtr pPriv
314)
315{
316    XkbDescPtr xkb;
317    KeySymsPtr syms;
318
319    xkb = device->key->xkbInfo->desc;
320    syms = XkbGetCoreMap(device);
321    if (!syms)
322	return;	/* XXX */
323
324    if ((ctrl->leds & XLED_CAPS_LOCK) && !(pPriv->leds & XLED_CAPS_LOCK))
325	    pseudoKey(device, TRUE,
326		LookupKeyCode(XK_Caps_Lock, xkb, syms));
327
328    if (!(ctrl->leds & XLED_CAPS_LOCK) && (pPriv->leds & XLED_CAPS_LOCK))
329	    pseudoKey(device, FALSE,
330		LookupKeyCode(XK_Caps_Lock, xkb, syms));
331
332    if ((ctrl->leds & XLED_NUM_LOCK) && !(pPriv->leds & XLED_NUM_LOCK))
333	    pseudoKey(device, TRUE,
334		LookupKeyCode(XK_Num_Lock, xkb, syms));
335
336    if (!(ctrl->leds & XLED_NUM_LOCK) && (pPriv->leds & XLED_NUM_LOCK))
337	    pseudoKey(device, FALSE,
338		LookupKeyCode(XK_Num_Lock, xkb, syms));
339
340    if ((ctrl->leds & XLED_SCROLL_LOCK) && !(pPriv->leds & XLED_SCROLL_LOCK))
341	    pseudoKey(device, TRUE,
342		LookupKeyCode(XK_Scroll_Lock, xkb, syms));
343
344    if (!(ctrl->leds & XLED_SCROLL_LOCK) && (pPriv->leds & XLED_SCROLL_LOCK))
345	    pseudoKey(device, FALSE,
346		LookupKeyCode(XK_Scroll_Lock, xkb, syms));
347
348    if ((ctrl->leds & XLED_COMPOSE) && !(pPriv->leds & XLED_COMPOSE))
349	    pseudoKey(device, TRUE,
350		LookupKeyCode(SunXK_Compose, xkb, syms));
351
352    if (!(ctrl->leds & XLED_COMPOSE) && (pPriv->leds & XLED_COMPOSE))
353	    pseudoKey(device, FALSE,
354		LookupKeyCode(SunXK_Compose, xkb, syms));
355
356    pPriv->leds = ctrl->leds & SUN_LED_MASK;
357    SetLights (ctrl, pPriv->fd);
358    free(syms->map);
359    free(syms);
360}
361
362/*-
363 *-----------------------------------------------------------------------
364 * sunKbdCtrl --
365 *	Alter some of the keyboard control parameters
366 *
367 * Results:
368 *	None.
369 *
370 * Side Effects:
371 *	Some...
372 *
373 *-----------------------------------------------------------------------
374 */
375
376static void
377sunKbdCtrl(DeviceIntPtr device, KeybdCtrl* ctrl)
378{
379    sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate;
380
381    if (pPriv->fd < 0) return;
382
383    if (ctrl->click != pPriv->click) {
384    	int kbdClickCmd;
385
386	pPriv->click = ctrl->click;
387	kbdClickCmd = pPriv->click ? KBD_CMD_CLICK : KBD_CMD_NOCLICK;
388    	if (ioctl (pPriv->fd, KIOCCMD, &kbdClickCmd) == -1)
389 	    ErrorF("Failed to set keyclick");
390    }
391    if ((pPriv->type == KB_SUN4) && (pPriv->leds != (ctrl->leds & SUN_LED_MASK)))
392	DoLEDs(device, ctrl, pPriv);
393}
394
395/*-
396 *-----------------------------------------------------------------------
397 * sunInitKbdNames --
398 *	Handle the XKB initialization
399 *
400 * Results:
401 *	None.
402 *
403 * Comments:
404 *     This function needs considerable work, in conjunctions with
405 *     the need to add geometry descriptions of Sun Keyboards.
406 *     It would also be nice to have #defines for all the keyboard
407 *     layouts so that we don't have to have these hard-coded
408 *     numbers.
409 *
410 *-----------------------------------------------------------------------
411 */
412static void
413sunInitKbdNames(XkbRMLVOSet *rmlvo, sunKbdPrivPtr pKbd)
414{
415#if 0 /* XXX to be revisited later */
416#ifndef XKBBUFSIZE
417#define XKBBUFSIZE 64
418#endif
419    static char keycodesbuf[XKBBUFSIZE];
420    static char geometrybuf[XKBBUFSIZE];
421    static char  symbolsbuf[XKBBUFSIZE];
422
423    names->keymap = NULL;
424    names->compat = "compat/complete";
425    names->types  = "types/complete";
426    names->keycodes = keycodesbuf;
427    names->geometry = geometrybuf;
428    names->symbols = symbolsbuf;
429    (void) strcpy (keycodesbuf, "keycodes/");
430    (void) strcpy (geometrybuf, "geometry/");
431    (void) strcpy (symbolsbuf, "symbols/");
432
433    /* keycodes & geometry */
434    switch (pKbd->type) {
435    case KB_SUN2:
436	(void) strcat (names->keycodes, "sun(type2)");
437	(void) strcat (names->geometry, "sun(type2)");
438	(void) strcat (names->symbols, "us(sun2)");
439	break;
440    case KB_SUN3:
441	(void) strcat (names->keycodes, "sun(type3)");
442	(void) strcat (names->geometry, "sun(type3)");
443	(void) strcat (names->symbols, "us(sun3)");
444	break;
445    case KB_SUN4:
446	/* First, catch "fully known" models */
447	switch (pKbd->layout) {
448	case 11:		/* type4, Sweden */
449	    (void) strcat (names->geometry, "sun(type4_se)");
450	    (void) strcat (names->keycodes,
451			   "sun(type4_se_swapctl)");
452	    (void) strcat (names->symbols,
453			   "sun/se(sun4)+se(fixdollar)");
454	    return;
455	    break;
456	case 43:		/* type5/5c, Sweden */
457	    (void) strcat (names->geometry, "sun(type5c_se)");
458	    (void) strcat (names->keycodes, "sun(type5_se)");
459	    (void) strcat (names->symbols,
460			   "sun/se(sun5)+se(fixdollar)");
461	    return;
462	    break;
463	case 90:		/* "Compact 1", Sweden (???) */
464	    break;		/* No specific mapping, yet */
465	default:
466	    break;
467	}
468
469	if (pKbd->layout == 19) {
470	    (void) strcat (names->keycodes, "sun(US101A)");
471	    (void) strcat (names->geometry, "pc101-NG"); /* XXX */
472	    (void) strcat (names->symbols, "us(pc101)");
473	} else if (pKbd->layout < 33) {
474	    (void) strcat (names->keycodes, "sun(type4)");
475	    (void) strcat (names->geometry, "sun(type4)");
476	    if (sunSwapLkeys)
477		(void) strcat (names->symbols, "sun/us(sun4ol)");
478	    else
479		(void) strcat (names->symbols, "sun/us(sun4)");
480	} else {
481	    switch (pKbd->layout) {
482	    case 33: case 80: /* U.S. */
483	    case 47: case 94: /* Korea */
484	    case 48: case 95: /* Taiwan */
485	    case 49: case 96: /* Japan */
486		(void) strcat (names->keycodes, "sun(type5)");
487		(void) strcat (names->geometry, "sun(type5)");
488		break;
489	    case 34: case 81: /* U.S. Unix */
490		(void) strcat (names->keycodes, "sun(type5)");
491		(void) strcat (names->geometry, "sun(type5unix)");
492		break;
493	    default:
494		(void) strcat (names->keycodes, "sun(type5_euro)");
495		(void) strcat (names->geometry, "sun(type5euro)");
496	    }
497
498	    if (sunSwapLkeys)
499		(void) strcat (names->symbols, "sun/us(sun5ol)");
500	    else
501		(void) strcat (names->symbols, "sun/us(sun5)");
502	}
503	break;
504    default:
505	names->keycodes = names->geometry = NULL;
506	break;
507    }
508
509    /* extra symbols */
510
511    if (pKbd->type == KB_SUN4) {
512	switch (pKbd->layout) {
513	case  4: case 36: case 83:
514	case  5: case 37: case 84:
515	case  6: case 38: case 85:
516	case  8: case 40: case 87:
517	case  9: case 41: case 88:
518	case 10: case 42: case 89:
519/*	case 11: case 43: case 90: */ /* handled earlier */
520	case 12: case 44: case 91:
521	case 13: case 45: case 92:
522	case 14: case 46: case 93:
523	    (void) strcat (names->symbols, "+iso9995-3(basic)"); break;
524	}
525    }
526
527    if (pKbd->type == KB_SUN4) {
528	switch (pKbd->layout) {
529	case  0: case  1: case 33: case 34: case 80: case 81:
530	    break;
531	case  3:
532	    (void) strcat (names->symbols, "+ca"); break;
533	case  4: case 36: case 83:
534	    (void) strcat (names->symbols, "+dk"); break;
535	case  5: case 37: case 84:
536	    (void) strcat (names->symbols, "+de"); break;
537	case  6: case 38: case 85:
538	    (void) strcat (names->symbols, "+it"); break;
539	case  8: case 40: case 87:
540	    (void) strcat (names->symbols, "+no"); break;
541	case  9: case 41: case 88:
542	    (void) strcat (names->symbols, "+pt"); break;
543	case 10: case 42: case 89:
544	    (void) strcat (names->symbols, "+es"); break;
545	    /* case 11: case 43: */ /* handled earlier */
546	case 90:
547	    (void) strcat (names->symbols, "+se"); break;
548	case 12: case 44: case 91:
549	    (void) strcat (names->symbols, "+fr_CH"); break;
550	case 13: case 45: case 92:
551	    (void) strcat (names->symbols, "+de_CH"); break;
552	case 14: case 46: case 93:
553	    (void) strcat (names->symbols, "+gb"); break; /* s/b en_UK */
554	case 52:
555	    (void) strcat (names->symbols, "+pl"); break;
556	case 53:
557	    (void) strcat (names->symbols, "+cs"); break;
558	case 54:
559	    (void) strcat (names->symbols, "+ru"); break;
560#if 0
561	/* don't have symbols defined for these yet, let them default */
562	case  2:
563	    (void) strcat (names->symbols, "+fr_BE"); break;
564	case  7: case 39: case 86:
565	    (void) strcat (names->symbols, "+nl"); break;
566	case 50: case 97:
567	    (void) strcat (names->symbols, "+fr_CA"); break;
568	case 16: case 47: case 94:
569	    (void) strcat (names->symbols, "+ko"); break;
570	case 17: case 48: case 95:
571	    (void) strcat (names->symbols, "+tw"); break;
572	case 32: case 49: case 96:
573	    (void) strcat (names->symbols, "+jp"); break;
574	case 51:
575	    (void) strcat (names->symbols, "+hu"); break;
576#endif
577	/*
578	 * by setting the symbols to NULL XKB will use the symbols in
579	 * the "default" keymap.
580	 */
581	default:
582	    names->symbols = NULL; return; break;
583	}
584    }
585#else
586    rmlvo->rules = "base";
587    rmlvo->model = NULL;
588    rmlvo->layout = NULL;
589    rmlvo->variant = NULL;
590    rmlvo->options = NULL;
591#endif
592}
593
594/*-
595 *-----------------------------------------------------------------------
596 * sunKbdProc --
597 *	Handle the initialization, etc. of a keyboard.
598 *
599 * Results:
600 *	None.
601 *
602 *-----------------------------------------------------------------------
603 */
604
605int
606sunKbdProc(DeviceIntPtr device, int what)
607{
608    int i;
609    DevicePtr pKeyboard = (DevicePtr) device;
610    sunKbdPrivPtr pPriv;
611    KeybdCtrl*	ctrl = &device->kbdfeed->ctrl;
612    XkbRMLVOSet rmlvo;
613
614    static CARD8 *workingModMap = NULL;
615    static KeySymsRec *workingKeySyms;
616
617    switch (what) {
618    case DEVICE_INIT:
619	if (pKeyboard != (DevicePtr)sunKeyboardDevice) {
620	    ErrorF ("Cannot open non-system keyboard\n");
621	    return (!Success);
622	}
623
624	if (!workingKeySyms) {
625	    workingKeySyms = &sunKeySyms[sunKbdPriv.type];
626
627	    if (sunKbdPriv.type == KB_SUN4 && sunSwapLkeys)
628		SwapLKeys(workingKeySyms);
629
630	    if (workingKeySyms->minKeyCode < MIN_KEYCODE) {
631		workingKeySyms->minKeyCode += MIN_KEYCODE;
632		workingKeySyms->maxKeyCode += MIN_KEYCODE;
633	    }
634	    if (workingKeySyms->maxKeyCode > MAX_KEYCODE)
635		workingKeySyms->maxKeyCode = MAX_KEYCODE;
636	}
637
638	if (!workingModMap) {
639	    workingModMap = malloc(MAP_LENGTH);
640	    (void) memset(workingModMap, 0, MAP_LENGTH);
641	    for(i=0; sunModMaps[sunKbdPriv.type][i].key != 0; i++)
642		workingModMap[sunModMaps[sunKbdPriv.type][i].key + MIN_KEYCODE] =
643		sunModMaps[sunKbdPriv.type][i].modifiers;
644	}
645
646	pKeyboard->devicePrivate = (void *)&sunKbdPriv;
647	pKeyboard->on = FALSE;
648
649	sunInitKbdNames(&rmlvo, pKeyboard->devicePrivate);
650#if 0 /* XXX needs more work for Xorg xkb */
651	InitKeyboardDeviceStruct(device, rmlvo,
652				 sunBell, sunKbdCtrl);
653#else
654	InitKeyboardDeviceStruct(device, NULL,
655				 sunBell, sunKbdCtrl);
656	XkbApplyMappingChange(device, workingKeySyms,
657			      workingKeySyms->minKeyCode,
658			      workingKeySyms->maxKeyCode -
659			      workingKeySyms->minKeyCode + 1,
660			      workingModMap, serverClient);
661#endif
662	break;
663
664    case DEVICE_ON:
665	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
666	/*
667	 * Set the keyboard into "direct" mode and turn on
668	 * event translation.
669	 */
670	if (sunChangeKbdTranslation(pPriv->fd,TRUE) == -1)
671	    FatalError("Can't set keyboard translation\n");
672	SetNotifyFd(pPriv->fd, sunKbdHandlerNotify, X_NOTIFY_READ, NULL);
673	pKeyboard->on = TRUE;
674	break;
675
676    case DEVICE_CLOSE:
677    case DEVICE_OFF:
678	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
679	if (pPriv->type == KB_SUN4) {
680	    /* dumb bug in Sun's keyboard! Turn off LEDS before resetting */
681	    pPriv->leds = 0;
682	    ctrl->leds = 0;
683	    SetLights(ctrl, pPriv->fd);
684	}
685	/*
686	 * Restore original keyboard directness and translation.
687	 */
688	if (sunChangeKbdTranslation(pPriv->fd,FALSE) == -1)
689	    FatalError("Can't reset keyboard translation\n");
690	RemoveNotifyFd(pPriv->fd);
691	pKeyboard->on = FALSE;
692	break;
693    default:
694	FatalError("Unknown keyboard operation\n");
695    }
696    return Success;
697}
698
699/*-
700 *-----------------------------------------------------------------------
701 * sunKbdGetEvents --
702 *	Return the events waiting in the wings for the given keyboard.
703 *
704 * Results:
705 *	A pointer to an array of Firm_events or (Firm_event *)0 if no events
706 *	The number of events contained in the array.
707 *	A boolean as to whether more events might be available.
708 *
709 * Side Effects:
710 *	None.
711 *-----------------------------------------------------------------------
712 */
713
714Firm_event *
715sunKbdGetEvents(int fd, Bool on, int *pNumEvents, Bool *pAgain)
716{
717    int	    	  nBytes;	    /* number of bytes of events available. */
718    static Firm_event	evBuf[SUN_MAXEVENTS];   /* Buffer for Firm_events */
719
720    if ((nBytes = read (fd, evBuf, sizeof(evBuf))) == -1) {
721	if (errno == EWOULDBLOCK) {
722	    *pNumEvents = 0;
723	    *pAgain = FALSE;
724	} else {
725	    ErrorF("Reading keyboard");
726	    FatalError ("Could not read the keyboard");
727	}
728    } else {
729	if (on) {
730	    *pNumEvents = nBytes / sizeof (Firm_event);
731	    *pAgain = (nBytes == sizeof (evBuf));
732	} else {
733	    *pNumEvents = 0;
734	    *pAgain = FALSE;
735	}
736    }
737    return evBuf;
738}
739
740/*-
741 *-----------------------------------------------------------------------
742 * sunKbdEnqueueEvent --
743 *
744 *-----------------------------------------------------------------------
745 */
746
747void
748sunKbdEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
749{
750    BYTE		keycode;
751    int			type;
752
753    keycode = (fe->id & 0x7f) + MIN_KEYCODE;
754    type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress);
755    QueueKeyboardEvents(device, type, keycode);
756}
757
758
759/*-
760 *-----------------------------------------------------------------------
761 * sunChangeKbdTranslation
762 *	Makes operating system calls to set keyboard translation
763 *	and direction on or off.
764 *
765 * Results:
766 *	-1 if failure, else 0.
767 *
768 * Side Effects:
769 * 	Changes kernel management of keyboard.
770 *
771 *-----------------------------------------------------------------------
772 */
773int
774sunChangeKbdTranslation(int fd, Bool makeTranslated)
775{
776    int 	tmp;
777#ifndef i386 /* { */
778    sigset_t	hold_mask, old_mask;
779#else /* }{ */
780    int		old_mask;
781#endif /* } */
782    int		toread;
783    char	junk[8192];
784
785#ifndef i386 /* { */
786    (void) sigfillset(&hold_mask);
787    (void) sigprocmask(SIG_BLOCK, &hold_mask, &old_mask);
788#else /* }{ */
789    old_mask = sigblock (~0);
790#endif /* } */
791    sunKbdWait();
792    if (makeTranslated) {
793        /*
794         * Next set the keyboard into "direct" mode and turn on
795         * event translation. If either of these fails, we can't go
796         * on.
797         */
798	tmp = 1;
799	if (ioctl (fd, KIOCSDIRECT, &tmp) == -1) {
800	    ErrorF("Setting keyboard direct mode");
801	    return -1;
802	}
803	tmp = TR_UNTRANS_EVENT;
804	if (ioctl (fd, KIOCTRANS, &tmp) == -1) {
805	    ErrorF("Setting keyboard translation");
806	    ErrorF ("sunChangeKbdTranslation: kbdFd=%d\n", fd);
807	    return -1;
808	}
809    } else {
810        /*
811         * Next set the keyboard into "indirect" mode and turn off
812         * event translation.
813         */
814	tmp = 0;
815	(void)ioctl (fd, KIOCSDIRECT, &tmp);
816	tmp = TR_ASCII;
817	(void)ioctl (fd, KIOCTRANS, &tmp);
818    }
819    if (ioctl (fd, FIONREAD, &toread) != -1 && toread > 0) {
820	while (toread) {
821	    tmp = toread;
822	    if (toread > sizeof (junk))
823		tmp = sizeof (junk);
824	    (void) read (fd, junk, tmp);
825	    toread -= tmp;
826	}
827    }
828#ifndef i386 /* { */
829    (void) sigprocmask(SIG_SETMASK, &old_mask, NULL);
830#else /* }{ */
831    sigsetmask (old_mask);
832#endif /* } */
833    return 0;
834}
835
836/*ARGSUSED*/
837Bool
838LegalModifier(unsigned int key, DeviceIntPtr pDev)
839{
840    return TRUE;
841}
842