sunKbd.c revision 2eda485b
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 pKeyboard;
282    sunKbdPrivPtr pPriv;
283
284    pKeyboard = sunKeyboardDevice;
285    if (pKeyboard != NULL) {
286	pPriv = (sunKbdPrivPtr)pKeyboard->public.devicePrivate;
287	bell(pPriv->fd, duration * 1000);
288    }
289}
290
291
292#ifdef __sun
293#define XLED_NUM_LOCK    0x1
294#define XLED_COMPOSE     0x4
295#define XLED_SCROLL_LOCK 0x2
296#define XLED_CAPS_LOCK   0x8
297#else
298#define XLED_NUM_LOCK    0x2
299#define XLED_COMPOSE     0x8
300#define XLED_SCROLL_LOCK 0x4
301#define XLED_CAPS_LOCK   0x1
302#endif
303
304static KeyCode
305LookupKeyCode(KeySym keysym, XkbDescPtr xkb, KeySymsPtr syms)
306{
307    KeyCode i;
308    int ii, index = 0;
309
310    for (i = xkb->min_key_code; i < xkb->max_key_code; i++)
311	for (ii = 0; ii < syms->mapWidth; ii++)
312	    if (syms->map[index++] == keysym)
313		return i;
314    return 0;
315}
316
317static void
318pseudoKey(DeviceIntPtr device, Bool down, KeyCode keycode)
319{
320    int bit;
321    CARD8 modifiers;
322    CARD16 mask;
323    BYTE* kptr;
324
325    kptr = &device->key->down[keycode >> 3];
326    bit = 1 << (keycode & 7);
327    modifiers = device->key->xkbInfo->desc->map->modmap[keycode];
328    if (down) {
329	/* fool dix into thinking this key is now "down" */
330	int i;
331	*kptr |= bit;
332	for (i = 0, mask = 1; modifiers; i++, mask <<= 1)
333	    if (mask & modifiers) {
334		device->key->modifierKeyCount[i]++;
335		modifiers &= ~mask;
336	    }
337    } else {
338	/* fool dix into thinking this key is now "up" */
339	if (*kptr & bit) {
340	    int i;
341	    *kptr &= ~bit;
342	    for (i = 0, mask = 1; modifiers; i++, mask <<= 1)
343		if (mask & modifiers) {
344		    if (--device->key->modifierKeyCount[i] <= 0) {
345			device->key->modifierKeyCount[i] = 0;
346		    }
347		    modifiers &= ~mask;
348		}
349	}
350    }
351}
352
353static void
354DoLEDs(
355    DeviceIntPtr    device,	    /* Keyboard to alter */
356    KeybdCtrl* ctrl,
357    sunKbdPrivPtr pPriv
358)
359{
360    XkbDescPtr xkb;
361    KeySymsPtr syms;
362
363    xkb = device->key->xkbInfo->desc;
364    syms = XkbGetCoreMap(device);
365    if (!syms)
366	return;	/* XXX */
367
368    if ((ctrl->leds & XLED_CAPS_LOCK) && !(pPriv->leds & XLED_CAPS_LOCK))
369	    pseudoKey(device, TRUE,
370		LookupKeyCode(XK_Caps_Lock, xkb, syms));
371
372    if (!(ctrl->leds & XLED_CAPS_LOCK) && (pPriv->leds & XLED_CAPS_LOCK))
373	    pseudoKey(device, FALSE,
374		LookupKeyCode(XK_Caps_Lock, xkb, syms));
375
376    if ((ctrl->leds & XLED_NUM_LOCK) && !(pPriv->leds & XLED_NUM_LOCK))
377	    pseudoKey(device, TRUE,
378		LookupKeyCode(XK_Num_Lock, xkb, syms));
379
380    if (!(ctrl->leds & XLED_NUM_LOCK) && (pPriv->leds & XLED_NUM_LOCK))
381	    pseudoKey(device, FALSE,
382		LookupKeyCode(XK_Num_Lock, xkb, syms));
383
384    if ((ctrl->leds & XLED_SCROLL_LOCK) && !(pPriv->leds & XLED_SCROLL_LOCK))
385	    pseudoKey(device, TRUE,
386		LookupKeyCode(XK_Scroll_Lock, xkb, syms));
387
388    if (!(ctrl->leds & XLED_SCROLL_LOCK) && (pPriv->leds & XLED_SCROLL_LOCK))
389	    pseudoKey(device, FALSE,
390		LookupKeyCode(XK_Scroll_Lock, xkb, syms));
391
392    if ((ctrl->leds & XLED_COMPOSE) && !(pPriv->leds & XLED_COMPOSE))
393	    pseudoKey(device, TRUE,
394		LookupKeyCode(SunXK_Compose, xkb, syms));
395
396    if (!(ctrl->leds & XLED_COMPOSE) && (pPriv->leds & XLED_COMPOSE))
397	    pseudoKey(device, FALSE,
398		LookupKeyCode(SunXK_Compose, xkb, syms));
399
400    pPriv->leds = ctrl->leds & SUN_LED_MASK;
401    SetLights (ctrl, pPriv->fd);
402    free(syms->map);
403    free(syms);
404}
405
406/*-
407 *-----------------------------------------------------------------------
408 * sunKbdCtrl --
409 *	Alter some of the keyboard control parameters
410 *
411 * Results:
412 *	None.
413 *
414 * Side Effects:
415 *	Some...
416 *
417 *-----------------------------------------------------------------------
418 */
419
420static void
421sunKbdCtrl(DeviceIntPtr device, KeybdCtrl* ctrl)
422{
423    sunKbdPrivPtr pPriv = (sunKbdPrivPtr) device->public.devicePrivate;
424
425    if (pPriv->fd < 0) return;
426
427    if (ctrl->click != pPriv->click) {
428    	int kbdClickCmd;
429
430	pPriv->click = ctrl->click;
431	kbdClickCmd = pPriv->click ? KBD_CMD_CLICK : KBD_CMD_NOCLICK;
432    	if (ioctl (pPriv->fd, KIOCCMD, &kbdClickCmd) == -1)
433 	    LogMessage(X_ERROR, "Failed to set keyclick\n");
434    }
435    if ((pPriv->type == KB_SUN4) && (pPriv->leds != (ctrl->leds & SUN_LED_MASK)))
436	DoLEDs(device, ctrl, pPriv);
437}
438
439/*-
440 *-----------------------------------------------------------------------
441 * sunInitKbdNames --
442 *	Handle the XKB initialization
443 *
444 * Results:
445 *	None.
446 *
447 * Comments:
448 *     This function needs considerable work, in conjunctions with
449 *     the need to add geometry descriptions of Sun Keyboards.
450 *     It would also be nice to have #defines for all the keyboard
451 *     layouts so that we don't have to have these hard-coded
452 *     numbers.
453 *
454 *-----------------------------------------------------------------------
455 */
456static void
457sunInitKbdNames(XkbRMLVOSet *rmlvo, sunKbdPrivPtr pKbd)
458{
459#if 0 /* XXX to be revisited later */
460#ifndef XKBBUFSIZE
461#define XKBBUFSIZE 64
462#endif
463    static char keycodesbuf[XKBBUFSIZE];
464    static char geometrybuf[XKBBUFSIZE];
465    static char  symbolsbuf[XKBBUFSIZE];
466
467    names->keymap = NULL;
468    names->compat = "compat/complete";
469    names->types  = "types/complete";
470    names->keycodes = keycodesbuf;
471    names->geometry = geometrybuf;
472    names->symbols = symbolsbuf;
473    (void) strcpy (keycodesbuf, "keycodes/");
474    (void) strcpy (geometrybuf, "geometry/");
475    (void) strcpy (symbolsbuf, "symbols/");
476
477    /* keycodes & geometry */
478    switch (pKbd->type) {
479    case KB_SUN2:
480	(void) strcat (names->keycodes, "sun(type2)");
481	(void) strcat (names->geometry, "sun(type2)");
482	(void) strcat (names->symbols, "us(sun2)");
483	break;
484    case KB_SUN3:
485	(void) strcat (names->keycodes, "sun(type3)");
486	(void) strcat (names->geometry, "sun(type3)");
487	(void) strcat (names->symbols, "us(sun3)");
488	break;
489    case KB_SUN4:
490	/* First, catch "fully known" models */
491	switch (pKbd->layout) {
492	case 11:		/* type4, Sweden */
493	    (void) strcat (names->geometry, "sun(type4_se)");
494	    (void) strcat (names->keycodes,
495			   "sun(type4_se_swapctl)");
496	    (void) strcat (names->symbols,
497			   "sun/se(sun4)+se(fixdollar)");
498	    return;
499	    break;
500	case 43:		/* type5/5c, Sweden */
501	    (void) strcat (names->geometry, "sun(type5c_se)");
502	    (void) strcat (names->keycodes, "sun(type5_se)");
503	    (void) strcat (names->symbols,
504			   "sun/se(sun5)+se(fixdollar)");
505	    return;
506	    break;
507	case 90:		/* "Compact 1", Sweden (???) */
508	    break;		/* No specific mapping, yet */
509	default:
510	    break;
511	}
512
513	if (pKbd->layout == 19) {
514	    (void) strcat (names->keycodes, "sun(US101A)");
515	    (void) strcat (names->geometry, "pc101-NG"); /* XXX */
516	    (void) strcat (names->symbols, "us(pc101)");
517	} else if (pKbd->layout < 33) {
518	    (void) strcat (names->keycodes, "sun(type4)");
519	    (void) strcat (names->geometry, "sun(type4)");
520	    if (sunSwapLkeys)
521		(void) strcat (names->symbols, "sun/us(sun4ol)");
522	    else
523		(void) strcat (names->symbols, "sun/us(sun4)");
524	} else {
525	    switch (pKbd->layout) {
526	    case 33: case 80: /* U.S. */
527	    case 47: case 94: /* Korea */
528	    case 48: case 95: /* Taiwan */
529	    case 49: case 96: /* Japan */
530		(void) strcat (names->keycodes, "sun(type5)");
531		(void) strcat (names->geometry, "sun(type5)");
532		break;
533	    case 34: case 81: /* U.S. Unix */
534		(void) strcat (names->keycodes, "sun(type5)");
535		(void) strcat (names->geometry, "sun(type5unix)");
536		break;
537	    default:
538		(void) strcat (names->keycodes, "sun(type5_euro)");
539		(void) strcat (names->geometry, "sun(type5euro)");
540	    }
541
542	    if (sunSwapLkeys)
543		(void) strcat (names->symbols, "sun/us(sun5ol)");
544	    else
545		(void) strcat (names->symbols, "sun/us(sun5)");
546	}
547	break;
548    default:
549	names->keycodes = names->geometry = NULL;
550	break;
551    }
552
553    /* extra symbols */
554
555    if (pKbd->type == KB_SUN4) {
556	switch (pKbd->layout) {
557	case  4: case 36: case 83:
558	case  5: case 37: case 84:
559	case  6: case 38: case 85:
560	case  8: case 40: case 87:
561	case  9: case 41: case 88:
562	case 10: case 42: case 89:
563/*	case 11: case 43: case 90: */ /* handled earlier */
564	case 12: case 44: case 91:
565	case 13: case 45: case 92:
566	case 14: case 46: case 93:
567	    (void) strcat (names->symbols, "+iso9995-3(basic)"); break;
568	}
569    }
570
571    if (pKbd->type == KB_SUN4) {
572	switch (pKbd->layout) {
573	case  0: case  1: case 33: case 34: case 80: case 81:
574	    break;
575	case  3:
576	    (void) strcat (names->symbols, "+ca"); break;
577	case  4: case 36: case 83:
578	    (void) strcat (names->symbols, "+dk"); break;
579	case  5: case 37: case 84:
580	    (void) strcat (names->symbols, "+de"); break;
581	case  6: case 38: case 85:
582	    (void) strcat (names->symbols, "+it"); break;
583	case  8: case 40: case 87:
584	    (void) strcat (names->symbols, "+no"); break;
585	case  9: case 41: case 88:
586	    (void) strcat (names->symbols, "+pt"); break;
587	case 10: case 42: case 89:
588	    (void) strcat (names->symbols, "+es"); break;
589	    /* case 11: case 43: */ /* handled earlier */
590	case 90:
591	    (void) strcat (names->symbols, "+se"); break;
592	case 12: case 44: case 91:
593	    (void) strcat (names->symbols, "+fr_CH"); break;
594	case 13: case 45: case 92:
595	    (void) strcat (names->symbols, "+de_CH"); break;
596	case 14: case 46: case 93:
597	    (void) strcat (names->symbols, "+gb"); break; /* s/b en_UK */
598	case 52:
599	    (void) strcat (names->symbols, "+pl"); break;
600	case 53:
601	    (void) strcat (names->symbols, "+cs"); break;
602	case 54:
603	    (void) strcat (names->symbols, "+ru"); break;
604#if 0
605	/* don't have symbols defined for these yet, let them default */
606	case  2:
607	    (void) strcat (names->symbols, "+fr_BE"); break;
608	case  7: case 39: case 86:
609	    (void) strcat (names->symbols, "+nl"); break;
610	case 50: case 97:
611	    (void) strcat (names->symbols, "+fr_CA"); break;
612	case 16: case 47: case 94:
613	    (void) strcat (names->symbols, "+ko"); break;
614	case 17: case 48: case 95:
615	    (void) strcat (names->symbols, "+tw"); break;
616	case 32: case 49: case 96:
617	    (void) strcat (names->symbols, "+jp"); break;
618	case 51:
619	    (void) strcat (names->symbols, "+hu"); break;
620#endif
621	/*
622	 * by setting the symbols to NULL XKB will use the symbols in
623	 * the "default" keymap.
624	 */
625	default:
626	    names->symbols = NULL; return; break;
627	}
628    }
629#else
630    rmlvo->rules = "base";
631    rmlvo->model = "empty";
632    rmlvo->layout = "empty";
633    rmlvo->variant = NULL;
634    rmlvo->options = NULL;
635#endif
636}
637
638static int
639getKbdType(int fd)
640{
641/*
642 * The Sun 386i has system include files that preclude this pre SunOS 4.1
643 * test for the presence of a type 4 keyboard however it really doesn't
644 * matter since no 386i has ever been shipped with a type 3 keyboard.
645 * SunOS 4.1 no longer needs this kludge.
646 */
647#if !defined(i386) && !defined(KIOCGKEY)
648#define TYPE4KEYBOARDOVERRIDE
649#endif
650
651    int ii, type;
652
653    for (ii = 0; ii < 3; ii++) {
654	sunKbdWait();
655	(void)ioctl(fd, KIOCTYPE, &type);
656#ifdef TYPE4KEYBOARDOVERRIDE
657	/*
658	 * Magic. Look for a key which is non-existent on a real type
659	 * 3 keyboard but does exist on a type 4 keyboard.
660	 */
661	if (type == KB_SUN3) {
662	    struct kiockeymap key;
663
664	    key.kio_tablemask = 0;
665	    key.kio_station = 118;
666	    if (ioctl(fd, KIOCGKEY, &key) == -1) {
667		LogMessage(X_ERROR, "ioctl KIOCGKEY\n" );
668		FatalError("Can't KIOCGKEY on fd %d\n", fd);
669	    }
670	    if (key.kio_entry != HOLE)
671		type = KB_SUN4;
672	}
673#endif
674	switch (type) {
675	case KB_SUN2:
676	case KB_SUN3:
677	case KB_SUN4:
678	    return type;
679	default:
680	    sunChangeKbdTranslation(fd, FALSE);
681	    continue;
682	}
683    }
684    return -1;
685}
686
687/*-
688 *-----------------------------------------------------------------------
689 * sunKbdProc --
690 *	Handle the initialization, etc. of a keyboard.
691 *
692 * Results:
693 *	None.
694 *
695 *-----------------------------------------------------------------------
696 */
697
698int
699sunKbdProc(DeviceIntPtr device, int what)
700{
701    DevicePtr pKeyboard = &device->public;
702    sunKbdPrivPtr pPriv;
703    KeybdCtrl*	ctrl = &device->kbdfeed->ctrl;
704    XkbRMLVOSet rmlvo;
705    CARD8 workingModMap[MAP_LENGTH];
706    int type = -1, layout = -1, mapsize;
707    KeySymsPtr keysym;
708    KeySym *map;
709
710    switch (what) {
711    case DEVICE_INIT:
712	pPriv = malloc(sizeof(*pPriv));
713	if (pPriv == NULL) {
714	    LogMessage(X_ERROR, "Cannot allocate private data for keyboard\n");
715	    return !Success;
716	}
717	pPriv->fd = open("/dev/kbd", O_RDWR | O_NONBLOCK, 0);
718	if (pPriv->fd < 0) {
719	    LogMessage(X_ERROR, "Cannot open /dev/kbd, error %d\n", errno);
720	    free(pPriv);
721	    return !Success;
722	}
723
724	type = getKbdType(pPriv->fd);
725	if (type < 0)
726	    FatalError("Unsupported keyboard type %d\n", type);
727
728	switch (type) {
729	case KB_SUN2:
730	case KB_SUN3:
731	    /* No layout variation */
732	    LogMessage(X_INFO, "Sun type %d Keyboard\n", type);
733	    break;
734	case KB_SUN4:
735#define LAYOUT_US5	33
736	    (void)ioctl(pPriv->fd, KIOCLAYOUT, &layout);
737	    if (layout < 0 ||
738		layout > sunMaxLayout ||
739		sunType4KeyMaps[layout] == NULL)
740		FatalError("Unsupported keyboard type 4 layout %d\n", layout);
741	    /* Type 5 keyboard also treated as Type 4 layout variants */
742	    LogMessage(X_INFO, "Sun type %d Keyboard, layout %d\n",
743		layout >= LAYOUT_US5 ? 5 : 4, layout);
744	    break;
745	default:
746	    LogMessage(X_INFO, "Unknown keyboard type\n");
747	    break;
748        }
749
750	keysym = &sunKeySyms[type];
751	mapsize = ((int)keysym->maxKeyCode - (int)keysym->minKeyCode + 1)
752	    * keysym->mapWidth * sizeof(keysym->map[0]);
753	map = malloc(mapsize);
754	if (map == NULL) {
755	    LogMessage(X_ERROR, "Failed to allocate KeySym map\n");
756	    close(pPriv->fd);
757	    free(pPriv);
758	    return !Success;
759        }
760	if (type == KB_SUN4) {
761	    memcpy(map, sunType4KeyMaps[layout], mapsize);
762	} else {
763	    memcpy(map, sunKeySyms[type].map, mapsize);
764	}
765
766	pPriv->type = type;
767	pPriv->layout = layout;
768	pPriv->click = 0;
769	pPriv->leds = (Leds)0;
770	pPriv->keysym.map = map;
771	pPriv->keysym.minKeyCode = keysym->minKeyCode;
772	pPriv->keysym.maxKeyCode = keysym->maxKeyCode;
773	pPriv->keysym.mapWidth = keysym->mapWidth;
774
775	/* sunKbdCtrl() callback refers pKeyboard->devicePrivate */
776	pKeyboard->devicePrivate = pPriv;
777	pKeyboard->on = FALSE;
778
779	if (type == KB_SUN4 && sunSwapLkeys) {
780	    /* This could update pPriv->keysym.map */
781	    SwapLKeys(&pPriv->keysym);
782	}
783
784	if (pPriv->keysym.minKeyCode < MIN_KEYCODE) {
785	    pPriv->keysym.minKeyCode += MIN_KEYCODE;
786	    pPriv->keysym.maxKeyCode += MIN_KEYCODE;
787	}
788	if (pPriv->keysym.maxKeyCode > MAX_KEYCODE)
789	    pPriv->keysym.maxKeyCode = MAX_KEYCODE;
790
791	sunInitModMap(&pPriv->keysym, workingModMap);
792
793	sunInitKbdNames(&rmlvo, pPriv);
794#if 0 /* XXX needs more work for Xorg xkb */
795	InitKeyboardDeviceStruct(device, &rmlvo,
796				 sunBell, sunKbdCtrl);
797#else
798	XkbSetRulesDflts(&rmlvo);
799	InitKeyboardDeviceStruct(device, NULL,
800				 sunBell, sunKbdCtrl);
801	XkbApplyMappingChange(device, &pPriv->keysym,
802			      pPriv->keysym.minKeyCode,
803			      pPriv->keysym.maxKeyCode -
804			      pPriv->keysym.minKeyCode + 1,
805			      workingModMap, serverClient);
806#endif
807	break;
808
809    case DEVICE_ON:
810	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
811	/*
812	 * Set the keyboard into "direct" mode and turn on
813	 * event translation.
814	 */
815	if (sunChangeKbdTranslation(pPriv->fd, TRUE) == -1)
816	    FatalError("Can't set keyboard translation\n");
817
818	SetNotifyFd(pPriv->fd, sunKbdEvents, X_NOTIFY_READ, device);
819
820	pKeyboard->on = TRUE;
821	break;
822
823    case DEVICE_OFF:
824	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
825	if (pPriv->type == KB_SUN4) {
826	    /* dumb bug in Sun's keyboard! Turn off LEDS before resetting */
827	    pPriv->leds = 0;
828	    ctrl->leds = 0;
829	    SetLights(ctrl, pPriv->fd);
830	}
831	/*
832	 * Restore original keyboard directness and translation.
833	 */
834	if (sunChangeKbdTranslation(pPriv->fd, FALSE) == -1)
835	    FatalError("Can't reset keyboard translation\n");
836	RemoveNotifyFd(pPriv->fd);
837	pKeyboard->on = FALSE;
838	break;
839
840    case DEVICE_CLOSE:
841	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
842	free(pPriv->keysym.map);
843	close(pPriv->fd);
844	free(pPriv);
845	pKeyboard->devicePrivate = NULL;
846	break;
847
848    case DEVICE_ABORT:
849	/*
850	 * Restore original keyboard directness and translation.
851	 */
852	pPriv = (sunKbdPrivPtr)pKeyboard->devicePrivate;
853	(void)sunChangeKbdTranslation(pPriv->fd, FALSE);
854	break;
855    }
856    return Success;
857}
858
859/*-------------------------------------------------------------------------
860 * sunInitModMap --
861 *	Initialize ModMap per specified KeyMap table.
862 *
863 * Results:
864 * 	None.
865 *
866 * Side Effects:
867 *	None.
868 *-----------------------------------------------------------------------*/
869static void
870sunInitModMap(
871    const KeySymsRec *KeySyms,	/* KeyMap data to set ModMap */
872    CARD8 *ModMap		/* ModMap to be initialized */
873)
874{
875    KeySym *k;
876    int i, min, max, width;
877
878    for (i = 0; i < MAP_LENGTH; i++)
879        ModMap[i] = NoSymbol;
880
881    min   = KeySyms->minKeyCode;
882    max   = KeySyms->maxKeyCode;
883    width = KeySyms->mapWidth;
884    for (i = min, k = KeySyms->map; i < max; i++, k += width) {
885	switch (*k) {
886
887	case XK_Shift_L:
888	case XK_Shift_R:
889	    ModMap[i] = ShiftMask;
890	    break;
891
892	case XK_Control_L:
893	case XK_Control_R:
894	    ModMap[i] = ControlMask;
895	    break;
896
897	case XK_Caps_Lock:
898	    ModMap[i] = LockMask;
899	    break;
900
901	case XK_Alt_L:
902	case XK_Alt_R:
903	    ModMap[i] = Alt_Mask;
904	    break;
905
906	case XK_Num_Lock:
907	    ModMap[i] = Num_Lock_Mask;
908	    break;
909
910	case XK_Scroll_Lock:
911	    ModMap[i] = ScrollLockMask;
912	    break;
913
914	case XK_Meta_L:
915	case XK_Meta_R:
916	    ModMap[i] = Meta_Mask;
917	    break;
918
919	case SunXK_AltGraph:
920	    ModMap[i] = Mode_switch_Mask;
921	    break;
922        }
923    }
924}
925
926/*-
927 *-----------------------------------------------------------------------
928 * sunKbdGetEvents --
929 *	Return the events waiting in the wings for the given keyboard.
930 *
931 * Results:
932 *	Update Firm_event buffer in DeviceIntPtr if events are received.
933 *	Return the number of received Firm_events in the buffer.
934 *
935 * Side Effects:
936 *	None.
937 *-----------------------------------------------------------------------
938 */
939
940static int
941sunKbdGetEvents(DeviceIntPtr device)
942{
943    DevicePtr pKeyboard = &device->public;
944    sunKbdPrivPtr pPriv = pKeyboard->devicePrivate;
945    int	nBytes;	 	   /* number of bytes of events available. */
946    int NumEvents = 0;
947
948    nBytes = read(pPriv->fd, pPriv->evbuf, sizeof(pPriv->evbuf));
949    if (nBytes == -1) {
950	if (errno != EWOULDBLOCK) {
951	    LogMessage(X_ERROR, "Unexpected error on reading keyboard\n");
952	    FatalError("Could not read the keyboard");
953	}
954    } else {
955	NumEvents = nBytes / sizeof(pPriv->evbuf[0]);
956    }
957    return NumEvents;
958}
959
960/*-
961 *-----------------------------------------------------------------------
962 * sunKbdEnqueueEvent --
963 *
964 *-----------------------------------------------------------------------
965 */
966
967static void
968sunKbdEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
969{
970    BYTE		keycode;
971    int			type;
972
973    keycode = (fe->id & 0x7f) + MIN_KEYCODE;
974    type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress);
975    QueueKeyboardEvents(device, type, keycode);
976}
977
978
979/*-
980 *-----------------------------------------------------------------------
981 * sunChangeKbdTranslation
982 *	Makes operating system calls to set keyboard translation
983 *	and direction on or off.
984 *
985 * Results:
986 *	-1 if failure, else 0.
987 *
988 * Side Effects:
989 * 	Changes kernel management of keyboard.
990 *
991 *-----------------------------------------------------------------------
992 */
993static int
994sunChangeKbdTranslation(int fd, Bool makeTranslated)
995{
996    int 	tmp;
997#ifndef i386 /* { */
998    sigset_t	hold_mask, old_mask;
999#else /* }{ */
1000    int		old_mask;
1001#endif /* } */
1002    int		toread;
1003    char	junk[8192];
1004
1005#ifndef i386 /* { */
1006    (void) sigfillset(&hold_mask);
1007    (void) sigprocmask(SIG_BLOCK, &hold_mask, &old_mask);
1008#else /* }{ */
1009    old_mask = sigblock (~0);
1010#endif /* } */
1011    sunKbdWait();
1012    if (makeTranslated) {
1013        /*
1014         * Next set the keyboard into "direct" mode and turn on
1015         * event translation. If either of these fails, we can't go
1016         * on.
1017         */
1018	tmp = 1;
1019	if (ioctl (fd, KIOCSDIRECT, &tmp) == -1) {
1020	    ErrorF("Setting keyboard direct mode\n");
1021	    return -1;
1022	}
1023	tmp = TR_UNTRANS_EVENT;
1024	if (ioctl (fd, KIOCTRANS, &tmp) == -1) {
1025	    ErrorF("Setting keyboard translation\n");
1026	    ErrorF ("sunChangeKbdTranslation: kbdFd=%d\n", fd);
1027	    return -1;
1028	}
1029    } else {
1030        /*
1031         * Next set the keyboard into "indirect" mode and turn off
1032         * event translation.
1033         */
1034	tmp = 0;
1035	(void)ioctl (fd, KIOCSDIRECT, &tmp);
1036	tmp = TR_ASCII;
1037	(void)ioctl (fd, KIOCTRANS, &tmp);
1038    }
1039    if (ioctl (fd, FIONREAD, &toread) != -1 && toread > 0) {
1040	while (toread) {
1041	    tmp = toread;
1042	    if (toread > sizeof (junk))
1043		tmp = sizeof (junk);
1044	    (void) read (fd, junk, tmp);
1045	    toread -= tmp;
1046	}
1047    }
1048#ifndef i386 /* { */
1049    (void) sigprocmask(SIG_SETMASK, &old_mask, NULL);
1050#else /* }{ */
1051    sigsetmask (old_mask);
1052#endif /* } */
1053    return 0;
1054}
1055