sunKbd.c revision f8338865
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	XkbSetRulesDflts(&rmlvo);
803	InitKeyboardDeviceStruct(device, NULL,
804				 sunBell, sunKbdCtrl);
805	XkbApplyMappingChange(device, &pPriv->keysym,
806			      pPriv->keysym.minKeyCode,
807			      pPriv->keysym.maxKeyCode -
808			      pPriv->keysym.minKeyCode + 1,
809			      workingModMap, serverClient);
810#endif
811	break;
812
813    case DEVICE_ON:
814	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
815	/*
816	 * Set the keyboard into "direct" mode and turn on
817	 * event translation.
818	 */
819	if (sunChangeKbdTranslation(pPriv->fd, TRUE) == -1)
820	    FatalError("Can't set keyboard translation\n");
821
822	SetNotifyFd(pPriv->fd, sunKbdEvents, X_NOTIFY_READ, device);
823
824	pKeyboard->on = TRUE;
825	break;
826
827    case DEVICE_OFF:
828	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
829	if (pPriv->type == KB_SUN4) {
830	    /* dumb bug in Sun's keyboard! Turn off LEDS before resetting */
831	    pPriv->leds = 0;
832	    ctrl->leds = 0;
833	    SetLights(ctrl, pPriv->fd);
834	}
835	/*
836	 * Restore original keyboard directness and translation.
837	 */
838	if (sunChangeKbdTranslation(pPriv->fd, FALSE) == -1)
839	    FatalError("Can't reset keyboard translation\n");
840	RemoveNotifyFd(pPriv->fd);
841	pKeyboard->on = FALSE;
842	break;
843
844    case DEVICE_CLOSE:
845	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
846	free(pPriv->keysym.map);
847	close(pPriv->fd);
848	free(pPriv);
849	pKeyboard->devicePrivate = NULL;
850	break;
851
852    case DEVICE_ABORT:
853	/*
854	 * Restore original keyboard directness and translation.
855	 */
856	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
857	(void)sunChangeKbdTranslation(pPriv->fd, FALSE);
858	break;
859    }
860    return Success;
861}
862
863/*-------------------------------------------------------------------------
864 * sunInitModMap --
865 *	Initialize ModMap per specified KeyMap table.
866 *
867 * Results:
868 * 	None.
869 *
870 * Side Effects:
871 *	None.
872 *-----------------------------------------------------------------------*/
873static void
874sunInitModMap(
875    const KeySymsRec *KeySyms,	/* KeyMap data to set ModMap */
876    CARD8 *ModMap		/* ModMap to be initialized */
877)
878{
879    KeySym *k;
880    int i, min, max, width;
881
882    for (i = 0; i < MAP_LENGTH; i++)
883        ModMap[i] = NoSymbol;
884
885    min   = KeySyms->minKeyCode;
886    max   = KeySyms->maxKeyCode;
887    width = KeySyms->mapWidth;
888    for (i = min, k = KeySyms->map; i < max; i++, k += width) {
889	switch (*k) {
890
891	case XK_Shift_L:
892	case XK_Shift_R:
893	    ModMap[i] = ShiftMask;
894	    break;
895
896	case XK_Control_L:
897	case XK_Control_R:
898	    ModMap[i] = ControlMask;
899	    break;
900
901	case XK_Caps_Lock:
902	    ModMap[i] = LockMask;
903	    break;
904
905	case XK_Alt_L:
906	case XK_Alt_R:
907	    ModMap[i] = Alt_Mask;
908	    break;
909
910	case XK_Num_Lock:
911	    ModMap[i] = Num_Lock_Mask;
912	    break;
913
914	case XK_Scroll_Lock:
915	    ModMap[i] = ScrollLockMask;
916	    break;
917
918	case XK_Meta_L:
919	case XK_Meta_R:
920	    ModMap[i] = Meta_Mask;
921	    break;
922
923	case SunXK_AltGraph:
924	    ModMap[i] = Mode_switch_Mask;
925	    break;
926        }
927    }
928}
929
930/*-
931 *-----------------------------------------------------------------------
932 * sunKbdGetEvents --
933 *	Return the events waiting in the wings for the given keyboard.
934 *
935 * Results:
936 *	Update Firm_event buffer in DeviceIntPtr if events are received.
937 *	Return the number of received Firm_events in the buffer.
938 *
939 * Side Effects:
940 *	None.
941 *-----------------------------------------------------------------------
942 */
943
944static int
945sunKbdGetEvents(DeviceIntPtr device)
946{
947    DevicePtr pKeyboard = &device->public;
948    sunKbdPrivPtr pPriv = pKeyboard->devicePrivate;
949    int	nBytes;	 	   /* number of bytes of events available. */
950    int NumEvents = 0;
951
952    nBytes = read(pPriv->fd, pPriv->evbuf, sizeof(pPriv->evbuf));
953    if (nBytes == -1) {
954	if (errno != EWOULDBLOCK) {
955	    LogMessage(X_ERROR, "Unexpected error on reading keyboard\n");
956	    FatalError("Could not read the keyboard");
957	}
958    } else {
959	NumEvents = nBytes / sizeof(pPriv->evbuf[0]);
960    }
961    return NumEvents;
962}
963
964/*-
965 *-----------------------------------------------------------------------
966 * sunKbdEnqueueEvent --
967 *
968 *-----------------------------------------------------------------------
969 */
970
971static void
972sunKbdEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
973{
974    BYTE		keycode;
975    int			type;
976
977    keycode = (fe->id & 0x7f) + MIN_KEYCODE;
978    type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress);
979    QueueKeyboardEvents(device, type, keycode);
980}
981
982
983/*-
984 *-----------------------------------------------------------------------
985 * sunChangeKbdTranslation
986 *	Makes operating system calls to set keyboard translation
987 *	and direction on or off.
988 *
989 * Results:
990 *	-1 if failure, else 0.
991 *
992 * Side Effects:
993 * 	Changes kernel management of keyboard.
994 *
995 *-----------------------------------------------------------------------
996 */
997static int
998sunChangeKbdTranslation(int fd, Bool makeTranslated)
999{
1000    int 	tmp;
1001#ifndef i386 /* { */
1002    sigset_t	hold_mask, old_mask;
1003#else /* }{ */
1004    int		old_mask;
1005#endif /* } */
1006    int		toread;
1007    char	junk[8192];
1008
1009#ifndef i386 /* { */
1010    (void) sigfillset(&hold_mask);
1011    (void) sigprocmask(SIG_BLOCK, &hold_mask, &old_mask);
1012#else /* }{ */
1013    old_mask = sigblock (~0);
1014#endif /* } */
1015    sunKbdWait();
1016    if (makeTranslated) {
1017        /*
1018         * Next set the keyboard into "direct" mode and turn on
1019         * event translation. If either of these fails, we can't go
1020         * on.
1021         */
1022	tmp = 1;
1023	if (ioctl (fd, KIOCSDIRECT, &tmp) == -1) {
1024	    ErrorF("Setting keyboard direct mode\n");
1025	    return -1;
1026	}
1027	tmp = TR_UNTRANS_EVENT;
1028	if (ioctl (fd, KIOCTRANS, &tmp) == -1) {
1029	    ErrorF("Setting keyboard translation\n");
1030	    ErrorF ("sunChangeKbdTranslation: kbdFd=%d\n", fd);
1031	    return -1;
1032	}
1033    } else {
1034        /*
1035         * Next set the keyboard into "indirect" mode and turn off
1036         * event translation.
1037         */
1038	tmp = 0;
1039	(void)ioctl (fd, KIOCSDIRECT, &tmp);
1040	tmp = TR_ASCII;
1041	(void)ioctl (fd, KIOCTRANS, &tmp);
1042    }
1043    if (ioctl (fd, FIONREAD, &toread) != -1 && toread > 0) {
1044	while (toread) {
1045	    tmp = toread;
1046	    if (toread > sizeof (junk))
1047		tmp = sizeof (junk);
1048	    (void) read (fd, junk, tmp);
1049	    toread -= tmp;
1050	}
1051    }
1052#ifndef i386 /* { */
1053    (void) sigprocmask(SIG_SETMASK, &old_mask, NULL);
1054#else /* }{ */
1055    sigsetmask (old_mask);
1056#endif /* } */
1057    return 0;
1058}
1059