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