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