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