sunKbd.c revision 9679a91b
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 = "empty";
596    rmlvo->layout = "empty";
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 = &device->public;
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 != &sunKeyboardDevice->public) {
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	XkbSetRulesDflts(&rmlvo);
656	InitKeyboardDeviceStruct(device, NULL,
657				 sunBell, sunKbdCtrl);
658	XkbApplyMappingChange(device, workingKeySyms,
659			      workingKeySyms->minKeyCode,
660			      workingKeySyms->maxKeyCode -
661			      workingKeySyms->minKeyCode + 1,
662			      workingModMap, serverClient);
663#endif
664	break;
665
666    case DEVICE_ON:
667	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
668	/*
669	 * Set the keyboard into "direct" mode and turn on
670	 * event translation.
671	 */
672	if (sunChangeKbdTranslation(pPriv->fd,TRUE) == -1)
673	    FatalError("Can't set keyboard translation\n");
674	SetNotifyFd(pPriv->fd, sunKbdHandlerNotify, X_NOTIFY_READ, NULL);
675	pKeyboard->on = TRUE;
676	break;
677
678    case DEVICE_CLOSE:
679    case DEVICE_OFF:
680	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
681	if (pPriv->type == KB_SUN4) {
682	    /* dumb bug in Sun's keyboard! Turn off LEDS before resetting */
683	    pPriv->leds = 0;
684	    ctrl->leds = 0;
685	    SetLights(ctrl, pPriv->fd);
686	}
687	/*
688	 * Restore original keyboard directness and translation.
689	 */
690	if (sunChangeKbdTranslation(pPriv->fd,FALSE) == -1)
691	    FatalError("Can't reset keyboard translation\n");
692	RemoveNotifyFd(pPriv->fd);
693	pKeyboard->on = FALSE;
694	break;
695    default:
696	FatalError("Unknown keyboard operation\n");
697    }
698    return Success;
699}
700
701/*-------------------------------------------------------------------------
702 * sunInitModMap --
703 *	Initialize ModMap per specified KeyMap table.
704 *
705 * Results:
706 * 	None.
707 *
708 * Side Effects:
709 *	None.
710 *-----------------------------------------------------------------------*/
711static void
712sunInitModMap(
713    const KeySymsRec *KeySyms,	/* KeyMap data to set ModMap */
714    CARD8 *ModMap		/* ModMap to be initialized */
715)
716{
717    KeySym *k;
718    int i, min, max, width;
719
720    for (i = 0; i < MAP_LENGTH; i++)
721        ModMap[i] = NoSymbol;
722
723    min   = KeySyms->minKeyCode;
724    max   = KeySyms->maxKeyCode;
725    width = KeySyms->mapWidth;
726    for (i = min, k = KeySyms->map; i < max; i++, k += width) {
727	switch (*k) {
728
729	case XK_Shift_L:
730	case XK_Shift_R:
731	    ModMap[i] = ShiftMask;
732	    break;
733
734	case XK_Control_L:
735	case XK_Control_R:
736	    ModMap[i] = ControlMask;
737	    break;
738
739	case XK_Caps_Lock:
740	    ModMap[i] = LockMask;
741	    break;
742
743	case XK_Alt_L:
744	case XK_Alt_R:
745	    ModMap[i] = Alt_Mask;
746	    break;
747
748	case XK_Num_Lock:
749	    ModMap[i] = Num_Lock_Mask;
750	    break;
751
752	case XK_Scroll_Lock:
753	    ModMap[i] = ScrollLockMask;
754	    break;
755
756	case XK_Meta_L:
757	case XK_Meta_R:
758	    ModMap[i] = Meta_Mask;
759	    break;
760
761	case SunXK_AltGraph:
762	    ModMap[i] = Mode_switch_Mask;
763	    break;
764        }
765    }
766}
767
768/*-
769 *-----------------------------------------------------------------------
770 * sunKbdGetEvents --
771 *	Return the events waiting in the wings for the given keyboard.
772 *
773 * Results:
774 *	A pointer to an array of Firm_events or (Firm_event *)0 if no events
775 *	The number of events contained in the array.
776 *	A boolean as to whether more events might be available.
777 *
778 * Side Effects:
779 *	None.
780 *-----------------------------------------------------------------------
781 */
782
783Firm_event *
784sunKbdGetEvents(int fd, Bool on, int *pNumEvents, Bool *pAgain)
785{
786    int	    	  nBytes;	    /* number of bytes of events available. */
787    static Firm_event	evBuf[SUN_MAXEVENTS];   /* Buffer for Firm_events */
788
789    if ((nBytes = read (fd, evBuf, sizeof(evBuf))) == -1) {
790	if (errno == EWOULDBLOCK) {
791	    *pNumEvents = 0;
792	    *pAgain = FALSE;
793	} else {
794	    ErrorF("Reading keyboard");
795	    FatalError ("Could not read the keyboard");
796	}
797    } else {
798	if (on) {
799	    *pNumEvents = nBytes / sizeof (Firm_event);
800	    *pAgain = (nBytes == sizeof (evBuf));
801	} else {
802	    *pNumEvents = 0;
803	    *pAgain = FALSE;
804	}
805    }
806    return evBuf;
807}
808
809/*-
810 *-----------------------------------------------------------------------
811 * sunKbdEnqueueEvent --
812 *
813 *-----------------------------------------------------------------------
814 */
815
816void
817sunKbdEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
818{
819    BYTE		keycode;
820    int			type;
821
822    keycode = (fe->id & 0x7f) + MIN_KEYCODE;
823    type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress);
824    QueueKeyboardEvents(device, type, keycode);
825}
826
827
828/*-
829 *-----------------------------------------------------------------------
830 * sunChangeKbdTranslation
831 *	Makes operating system calls to set keyboard translation
832 *	and direction on or off.
833 *
834 * Results:
835 *	-1 if failure, else 0.
836 *
837 * Side Effects:
838 * 	Changes kernel management of keyboard.
839 *
840 *-----------------------------------------------------------------------
841 */
842int
843sunChangeKbdTranslation(int fd, Bool makeTranslated)
844{
845    int 	tmp;
846#ifndef i386 /* { */
847    sigset_t	hold_mask, old_mask;
848#else /* }{ */
849    int		old_mask;
850#endif /* } */
851    int		toread;
852    char	junk[8192];
853
854#ifndef i386 /* { */
855    (void) sigfillset(&hold_mask);
856    (void) sigprocmask(SIG_BLOCK, &hold_mask, &old_mask);
857#else /* }{ */
858    old_mask = sigblock (~0);
859#endif /* } */
860    sunKbdWait();
861    if (makeTranslated) {
862        /*
863         * Next set the keyboard into "direct" mode and turn on
864         * event translation. If either of these fails, we can't go
865         * on.
866         */
867	tmp = 1;
868	if (ioctl (fd, KIOCSDIRECT, &tmp) == -1) {
869	    ErrorF("Setting keyboard direct mode");
870	    return -1;
871	}
872	tmp = TR_UNTRANS_EVENT;
873	if (ioctl (fd, KIOCTRANS, &tmp) == -1) {
874	    ErrorF("Setting keyboard translation");
875	    ErrorF ("sunChangeKbdTranslation: kbdFd=%d\n", fd);
876	    return -1;
877	}
878    } else {
879        /*
880         * Next set the keyboard into "indirect" mode and turn off
881         * event translation.
882         */
883	tmp = 0;
884	(void)ioctl (fd, KIOCSDIRECT, &tmp);
885	tmp = TR_ASCII;
886	(void)ioctl (fd, KIOCTRANS, &tmp);
887    }
888    if (ioctl (fd, FIONREAD, &toread) != -1 && toread > 0) {
889	while (toread) {
890	    tmp = toread;
891	    if (toread > sizeof (junk))
892		tmp = sizeof (junk);
893	    (void) read (fd, junk, tmp);
894	    toread -= tmp;
895	}
896    }
897#ifndef i386 /* { */
898    (void) sigprocmask(SIG_SETMASK, &old_mask, NULL);
899#else /* }{ */
900    sigsetmask (old_mask);
901#endif /* } */
902    return 0;
903}
904
905/*ARGSUSED*/
906Bool
907LegalModifier(unsigned int key, DeviceIntPtr pDev)
908{
909    return TRUE;
910}
911