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