sun_kbd.c revision a1ed278c
1ee3138f1Smrg/*
2ee3138f1Smrg * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany
3ee3138f1Smrg * Copyright 1993 by David Dawes <dawes@XFree86.org>
4ee3138f1Smrg * Copyright 1999 by David Holland <davidh@iquest.net)
5ee3138f1Smrg *
6ee3138f1Smrg * Permission to use, copy, modify, distribute, and sell this software and its
7ee3138f1Smrg * documentation for any purpose is hereby granted without fee, provided that
8ee3138f1Smrg * the above copyright notice appear in all copies and that both that copyright
9ee3138f1Smrg * notice and this permission notice appear in supporting documentation, and
10ee3138f1Smrg * that the names of Thomas Roell, David Dawes, and David Holland not be used
11ee3138f1Smrg * in advertising or publicity pertaining to distribution of the software
12ee3138f1Smrg * without specific, written prior permission.  Thomas Roell, David Dawes, and
13ee3138f1Smrg * David Holland make no representations about the suitability of this software
14ee3138f1Smrg * for any purpose.  It is provided "as is" without express or implied
15ee3138f1Smrg * warranty.
16ee3138f1Smrg *
17ee3138f1Smrg * THOMAS ROELL, DAVID DAWES, AND DAVID HOLLAND DISCLAIM ALL WARRANTIES WITH
18ee3138f1Smrg * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19ee3138f1Smrg * AND FITNESS.  IN NO EVENT SHALL THOMAS ROELL, DAVID DAWES, OR DAVID HOLLAND
20ee3138f1Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21ee3138f1Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
22ee3138f1Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23ee3138f1Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24ee3138f1Smrg */
25b425557eSmrg/*
26b425557eSmrg * Copyright (c) 2004-2009, Oracle and/or its affiliates. All rights reserved.
27ee3138f1Smrg *
28ee3138f1Smrg * Permission is hereby granted, free of charge, to any person obtaining a
29b425557eSmrg * copy of this software and associated documentation files (the "Software"),
30b425557eSmrg * to deal in the Software without restriction, including without limitation
31b425557eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
32b425557eSmrg * and/or sell copies of the Software, and to permit persons to whom the
33b425557eSmrg * Software is furnished to do so, subject to the following conditions:
34b425557eSmrg *
35b425557eSmrg * The above copyright notice and this permission notice (including the next
36b425557eSmrg * paragraph) shall be included in all copies or substantial portions of the
37b425557eSmrg * Software.
38b425557eSmrg *
39b425557eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40b425557eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41b425557eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
42b425557eSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43b425557eSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
44b425557eSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
45b425557eSmrg * DEALINGS IN THE SOFTWARE.
46ee3138f1Smrg */
47ee3138f1Smrg
48ee3138f1Smrg#ifdef HAVE_CONFIG_H
49ee3138f1Smrg#include "config.h"
50ee3138f1Smrg#endif
51ee3138f1Smrg
52b425557eSmrg#include <xorg-server.h>
53ee3138f1Smrg#include "xf86.h"
54ee3138f1Smrg#include "xf86Priv.h"
55ee3138f1Smrg#include "xf86_OSlib.h"
56ee3138f1Smrg#include "xf86OSKbd.h"
57ee3138f1Smrg#include "sun_kbd.h"
58ee3138f1Smrg
59ee3138f1Smrg#include <sys/stropts.h>
60ee3138f1Smrg#include <sys/vuid_event.h>
61ee3138f1Smrg#include <sys/kbd.h>
6234977a2fSmrg#include <sys/note.h>	/* needed before including older versions of hid.h */
6334977a2fSmrg#include <sys/usb/clients/hid/hid.h>
6434977a2fSmrg
6534977a2fSmrgstatic int KbdOn(InputInfoPtr pInfo, int what);
6634977a2fSmrgstatic Bool OpenKeyboard(InputInfoPtr pInfo);
6734977a2fSmrgstatic void CloseKeyboard(InputInfoPtr pInfo);
68ee3138f1Smrg
69ee3138f1Smrgstatic void
70ee3138f1SmrgsunKbdSetLeds(InputInfoPtr pInfo, int leds)
71ee3138f1Smrg{
72ee3138f1Smrg    int i;
73ee3138f1Smrg
74ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCSLED, &leds));
75ee3138f1Smrg    if (i < 0) {
76ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Failed to set keyboard LED's: %s\n",
77ee3138f1Smrg                pInfo->name, strerror(errno));
78ee3138f1Smrg    }
79ee3138f1Smrg}
80ee3138f1Smrg
81ee3138f1Smrg
82ee3138f1Smrgstatic int
83ee3138f1SmrgsunKbdGetLeds(InputInfoPtr pInfo)
84ee3138f1Smrg{
85ee3138f1Smrg    int i, leds = 0;
86ee3138f1Smrg
87ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCGLED, &leds));
88ee3138f1Smrg    if (i < 0) {
89ee3138f1Smrg        xf86Msg(X_ERROR, "%s: Failed to get keyboard LED's: %s\n",
90ee3138f1Smrg                pInfo->name, strerror(errno));
91ee3138f1Smrg    }
92ee3138f1Smrg    return leds;
93ee3138f1Smrg}
94ee3138f1Smrg
95ee3138f1Smrg
96ee3138f1Smrg/*
97ee3138f1Smrg * Save initial keyboard state.  This is called at the start of each server
98ee3138f1Smrg * generation.
99ee3138f1Smrg */
100ee3138f1Smrgstatic int
101ee3138f1SmrgKbdInit(InputInfoPtr pInfo, int what)
102ee3138f1Smrg{
103ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
104ee3138f1Smrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
105ee3138f1Smrg    pointer options = pInfo->options;
106ee3138f1Smrg
107ee3138f1Smrg    int	ktype, klayout, i;
108ee3138f1Smrg    const char *ktype_name;
109ee3138f1Smrg
11034977a2fSmrg    priv->kbdActive	= FALSE;
111ee3138f1Smrg    priv->otranslation 	= -1;
112ee3138f1Smrg    priv->odirect 	= -1;
113ee3138f1Smrg
114ee3138f1Smrg    if (options != NULL) {
115ee3138f1Smrg	priv->strmod = xf86SetStrOption(options, "StreamsModule", NULL);
116ee3138f1Smrg    } else {
117ee3138f1Smrg	priv->strmod 		= NULL;
118ee3138f1Smrg    }
119ee3138f1Smrg
12034977a2fSmrg    i = KbdOn(pInfo, DEVICE_INIT);
12134977a2fSmrg    if (i != Success) {
12234977a2fSmrg	return i;
123ee3138f1Smrg    }
12434977a2fSmrg
125ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCTYPE, &ktype));
126ee3138f1Smrg    if (i < 0) {
127ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Unable to determine keyboard type: %s\n",
128ee3138f1Smrg		pInfo->name, strerror(errno));
129ee3138f1Smrg	return BadImplementation;
130ee3138f1Smrg    }
131ee3138f1Smrg
132ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCLAYOUT, &klayout));
133ee3138f1Smrg    if (i < 0) {
134ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Unable to determine keyboard layout: %s\n",
135ee3138f1Smrg		pInfo->name, strerror(errno));
136ee3138f1Smrg	return BadImplementation;
137ee3138f1Smrg    }
138ee3138f1Smrg
139ee3138f1Smrg    switch (ktype) {
140ee3138f1Smrg    case KB_SUN3:
141ee3138f1Smrg	ktype_name = "Sun Type 3"; break;
142ee3138f1Smrg    case KB_SUN4:
143ee3138f1Smrg	ktype_name = "Sun Type 4/5/6"; break;
144ee3138f1Smrg    case KB_USB:
145ee3138f1Smrg	ktype_name = "USB"; break;
146ee3138f1Smrg    case KB_PC:
147ee3138f1Smrg	ktype_name = "PC"; break;
148ee3138f1Smrg    default:
149ee3138f1Smrg	ktype_name = "Unknown"; break;
150ee3138f1Smrg    }
151ee3138f1Smrg
152ee3138f1Smrg    xf86Msg(X_PROBED, "%s: Keyboard type: %s (%d)\n",
153ee3138f1Smrg	    pInfo->name, ktype_name, ktype);
154ee3138f1Smrg    xf86Msg(X_PROBED, "%s: Keyboard layout: %d\n", pInfo->name, klayout);
155ee3138f1Smrg
156ee3138f1Smrg    priv->ktype 	= ktype;
157ee3138f1Smrg
158ee3138f1Smrg    return Success;
159ee3138f1Smrg}
160ee3138f1Smrg
161ee3138f1Smrg
162ee3138f1Smrgstatic int
163ee3138f1SmrgKbdOn(InputInfoPtr pInfo, int what)
164ee3138f1Smrg{
165ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
166ee3138f1Smrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
167ee3138f1Smrg
168ee3138f1Smrg    int	ktrans, kdirect, i;
16934977a2fSmrg    int io_get_direct = KIOCGDIRECT;
17034977a2fSmrg    int io_set_direct = KIOCSDIRECT;
17134977a2fSmrg
17234977a2fSmrg    if (priv->kbdActive) {
17334977a2fSmrg	return Success;
17434977a2fSmrg    }
175ee3138f1Smrg
17634977a2fSmrg    if (pInfo->fd == -1) {
17734977a2fSmrg	if (!OpenKeyboard(pInfo)) {
17834977a2fSmrg	    return BadImplementation;
17934977a2fSmrg	}
18034977a2fSmrg    }
18134977a2fSmrg
18234977a2fSmrg    if (priv->strmod) {
18334977a2fSmrg	/* Check to see if module is already pushed */
18434977a2fSmrg	SYSCALL(i = ioctl(pInfo->fd, I_FIND, priv->strmod));
18534977a2fSmrg
18634977a2fSmrg	if (i == 0) { /* Not already pushed */
18734977a2fSmrg	    SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod));
18834977a2fSmrg	    if (i < 0) {
18934977a2fSmrg		xf86Msg(X_ERROR, "%s: cannot push module '%s' onto "
19034977a2fSmrg			"keyboard device: %s\n",
19134977a2fSmrg			pInfo->name, priv->strmod, strerror(errno));
19234977a2fSmrg	    }
19334977a2fSmrg	}
19434977a2fSmrg
19534977a2fSmrg#ifdef HIDIOCKMSDIRECT
19634977a2fSmrg	if (strcmp(priv->strmod, "usbkbm") == 0) {
19734977a2fSmrg	    io_get_direct = HIDIOCKMGDIRECT;
19834977a2fSmrg	    io_set_direct = HIDIOCKMSDIRECT;
19934977a2fSmrg	}
20034977a2fSmrg#endif
20134977a2fSmrg    }
20234977a2fSmrg
20334977a2fSmrg    SYSCALL(i = ioctl(pInfo->fd, io_get_direct, &kdirect));
204ee3138f1Smrg    if (i < 0) {
205ee3138f1Smrg	xf86Msg(X_ERROR,
206ee3138f1Smrg		"%s: Unable to determine keyboard direct setting: %s\n",
207ee3138f1Smrg		pInfo->name, strerror(errno));
208ee3138f1Smrg	return BadImplementation;
209ee3138f1Smrg    }
210ee3138f1Smrg
211ee3138f1Smrg    priv->odirect = kdirect;
212ee3138f1Smrg    kdirect = 1;
213ee3138f1Smrg
21434977a2fSmrg    SYSCALL(i = ioctl(pInfo->fd, io_set_direct, &kdirect));
215ee3138f1Smrg    if (i < 0) {
216ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Failed turning keyboard direct mode on: %s\n",
217ee3138f1Smrg			pInfo->name, strerror(errno));
218ee3138f1Smrg	return BadImplementation;
219ee3138f1Smrg    }
220ee3138f1Smrg
221ee3138f1Smrg    /* Setup translation */
222ee3138f1Smrg
223ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCGTRANS, &ktrans));
224ee3138f1Smrg    if (i < 0) {
225ee3138f1Smrg	xf86Msg(X_ERROR,
226ee3138f1Smrg		"%s: Unable to determine keyboard translation mode: %s\n",
227ee3138f1Smrg		pInfo->name, strerror(errno));
228ee3138f1Smrg	return BadImplementation;
229ee3138f1Smrg    }
230ee3138f1Smrg
231ee3138f1Smrg    priv->otranslation = ktrans;
232ee3138f1Smrg    ktrans = TR_UNTRANS_EVENT;
233ee3138f1Smrg
234ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &ktrans));
235ee3138f1Smrg    if (i < 0) {
236ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Failed setting keyboard translation mode: %s\n",
237ee3138f1Smrg			pInfo->name, strerror(errno));
238ee3138f1Smrg	return BadImplementation;
239ee3138f1Smrg    }
240ee3138f1Smrg
24134977a2fSmrg    priv->oleds	= sunKbdGetLeds(pInfo);
24234977a2fSmrg
24334977a2fSmrg    /* Allocate here so we don't alloc in ReadInput which may be called
24434977a2fSmrg       from SIGIO handler. */
24534977a2fSmrg    priv->remove_timer = TimerSet(priv->remove_timer, 0, 0, NULL, NULL);
24634977a2fSmrg
24734977a2fSmrg    priv->kbdActive = TRUE;
248ee3138f1Smrg    return Success;
249ee3138f1Smrg}
250ee3138f1Smrg
251ee3138f1Smrgstatic int
252ee3138f1SmrgKbdOff(InputInfoPtr pInfo, int what)
253ee3138f1Smrg{
254ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
255ee3138f1Smrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
256ee3138f1Smrg
257ee3138f1Smrg    int i;
25834977a2fSmrg    int io_set_direct, kdirect;
25934977a2fSmrg
26034977a2fSmrg    if (priv->remove_timer) {
26134977a2fSmrg	TimerFree(priv->remove_timer);
26234977a2fSmrg	priv->remove_timer = NULL;
26334977a2fSmrg    }
26434977a2fSmrg
26534977a2fSmrg    if (!priv->kbdActive) {
26634977a2fSmrg	return Success;
26734977a2fSmrg    }
26834977a2fSmrg
26934977a2fSmrg    if (pInfo->fd == -1) {
27034977a2fSmrg	priv->kbdActive = FALSE;
27134977a2fSmrg	return Success;
27234977a2fSmrg    }
273ee3138f1Smrg
274ee3138f1Smrg    /* restore original state */
27579a8a9c6Smrg
27679a8a9c6Smrg    if (priv->oleds != -1) {
27779a8a9c6Smrg	sunKbdSetLeds(pInfo, priv->oleds);
27879a8a9c6Smrg	priv->oleds = -1;
27979a8a9c6Smrg    }
280ee3138f1Smrg
281ee3138f1Smrg    if (priv->otranslation != -1) {
282ee3138f1Smrg        SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &priv->otranslation));
283ee3138f1Smrg	if (i < 0) {
284ee3138f1Smrg	    xf86Msg(X_ERROR,
285ee3138f1Smrg		    "%s: Unable to restore keyboard translation mode: %s\n",
286ee3138f1Smrg		    pInfo->name, strerror(errno));
287ee3138f1Smrg	    return BadImplementation;
288ee3138f1Smrg	}
289ee3138f1Smrg	priv->otranslation = -1;
290ee3138f1Smrg    }
291ee3138f1Smrg
29234977a2fSmrg    io_set_direct = KIOCSDIRECT;
29334977a2fSmrg    kdirect = priv->odirect;
29434977a2fSmrg
29534977a2fSmrg#ifdef HIDIOCKMSDIRECT
29634977a2fSmrg    if ((priv->strmod != NULL) && (strcmp(priv->strmod, "usbkbm") == 0)) {
29734977a2fSmrg	io_set_direct = HIDIOCKMSDIRECT;
29834977a2fSmrg	kdirect = 0;
29934977a2fSmrg    }
30034977a2fSmrg#endif
30134977a2fSmrg
30234977a2fSmrg    if (kdirect != -1) {
30334977a2fSmrg	SYSCALL(i = ioctl(pInfo->fd, io_set_direct, &kdirect));
304ee3138f1Smrg	if (i < 0) {
305ee3138f1Smrg	    xf86Msg(X_ERROR,
306ee3138f1Smrg		    "%s: Unable to restore keyboard direct setting: %s\n",
307ee3138f1Smrg		    pInfo->name, strerror(errno));
308ee3138f1Smrg	    return BadImplementation;
309ee3138f1Smrg	}
310ee3138f1Smrg	priv->odirect = -1;
311ee3138f1Smrg    }
312ee3138f1Smrg
313ee3138f1Smrg    if (priv->strmod) {
314ee3138f1Smrg	SYSCALL(i = ioctl(pInfo->fd, I_POP, priv->strmod));
315ee3138f1Smrg	if (i < 0) {
316ee3138f1Smrg            xf86Msg(X_WARNING,
317ee3138f1Smrg		    "%s: cannot pop module '%s' off keyboard device: %s\n",
318ee3138f1Smrg		    pInfo->name, priv->strmod, strerror(errno));
319ee3138f1Smrg	}
320ee3138f1Smrg    }
321ee3138f1Smrg
32234977a2fSmrg    CloseKeyboard(pInfo);
323ee3138f1Smrg    return Success;
324ee3138f1Smrg}
325ee3138f1Smrg
326ee3138f1Smrg
327ee3138f1Smrgstatic void
328ee3138f1SmrgSoundKbdBell(InputInfoPtr pInfo, int loudness, int pitch, int duration)
329ee3138f1Smrg{
330ee3138f1Smrg    int	kbdCmd, i;
331ee3138f1Smrg#ifdef KIOCMKTONE
332ee3138f1Smrg    int cycles;
333ee3138f1Smrg    int mktonevalue;
334ee3138f1Smrg#endif
335ee3138f1Smrg
336ee3138f1Smrg    if (loudness && pitch)
337ee3138f1Smrg    {
338ee3138f1Smrg#ifdef KIOCMKTONE
339ee3138f1Smrg	if (pitch == 0)
340ee3138f1Smrg	    cycles = UINT16_MAX;
341ee3138f1Smrg	else if (pitch >= UINT16_MAX)
342ee3138f1Smrg	    cycles = 0;
343ee3138f1Smrg	else {
344ee3138f1Smrg	    cycles = (PIT_HZ + pitch / 2) / pitch;
345ee3138f1Smrg	    if (cycles > UINT16_MAX)
346ee3138f1Smrg		cycles = UINT16_MAX;
347ee3138f1Smrg	}
348ee3138f1Smrg
349ee3138f1Smrg	mktonevalue = cycles | (((duration * loudness * 20) / 1000) << 16);
350ee3138f1Smrg
351ee3138f1Smrg	errno = 0;
352ee3138f1Smrg	SYSCALL(i = ioctl (pInfo->fd, KIOCMKTONE, mktonevalue));
353ee3138f1Smrg	if (i == 0)
354ee3138f1Smrg	    return;
355ee3138f1Smrg
356ee3138f1Smrg	if (errno != EINVAL) {
357ee3138f1Smrg	    if (errno != EAGAIN)
358ee3138f1Smrg		xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n",
359ee3138f1Smrg			pInfo->name, strerror(errno));
360ee3138f1Smrg	    return;
361ee3138f1Smrg	}
362ee3138f1Smrg#endif
363ee3138f1Smrg
364ee3138f1Smrg 	kbdCmd = KBD_CMD_BELL;
365ee3138f1Smrg
366ee3138f1Smrg	SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd));
367ee3138f1Smrg	if (i < 0) {
368ee3138f1Smrg	    xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n",
369ee3138f1Smrg                pInfo->name, strerror(errno));
370ee3138f1Smrg	}
371ee3138f1Smrg
372ee3138f1Smrg	usleep(duration * loudness * 20);
373ee3138f1Smrg
374ee3138f1Smrg	kbdCmd = KBD_CMD_NOBELL;
375ee3138f1Smrg	SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd));
376ee3138f1Smrg	if (i < 0) {
377ee3138f1Smrg	     xf86Msg(X_ERROR, "%s: Failed to deactivate bell: %s\n",
378ee3138f1Smrg                pInfo->name, strerror(errno));
379ee3138f1Smrg	}
380ee3138f1Smrg    }
381ee3138f1Smrg}
382ee3138f1Smrg
383ee3138f1Smrgstatic void
384ee3138f1SmrgSetKbdLeds(InputInfoPtr pInfo, int leds)
385ee3138f1Smrg{
386ee3138f1Smrg    int real_leds = sunKbdGetLeds(pInfo);
387ee3138f1Smrg
388ee3138f1Smrg    real_leds &= ~(LED_CAPS_LOCK | LED_NUM_LOCK | LED_SCROLL_LOCK | LED_COMPOSE);
389ee3138f1Smrg
390ee3138f1Smrg    if (leds & XLED1)  real_leds |= LED_CAPS_LOCK;
391ee3138f1Smrg    if (leds & XLED2)  real_leds |= LED_NUM_LOCK;
392ee3138f1Smrg    if (leds & XLED3)  real_leds |= LED_SCROLL_LOCK;
393ee3138f1Smrg    if (leds & XLED4)  real_leds |= LED_COMPOSE;
394ee3138f1Smrg
395ee3138f1Smrg    sunKbdSetLeds(pInfo, real_leds);
396ee3138f1Smrg}
397ee3138f1Smrg
398ee3138f1Smrgstatic int
399ee3138f1SmrgGetKbdLeds(InputInfoPtr pInfo)
400ee3138f1Smrg{
401ee3138f1Smrg    int leds = 0;
402ee3138f1Smrg    int real_leds = sunKbdGetLeds(pInfo);
403ee3138f1Smrg
404ee3138f1Smrg    if (real_leds & LED_CAPS_LOCK)	leds |= XLED1;
405ee3138f1Smrg    if (real_leds & LED_NUM_LOCK)	leds |= XLED2;
406ee3138f1Smrg    if (real_leds & LED_SCROLL_LOCK)	leds |= XLED3;
407ee3138f1Smrg    if (real_leds & LED_COMPOSE)	leds |= XLED4;
408ee3138f1Smrg
409ee3138f1Smrg    return leds;
410ee3138f1Smrg}
411ee3138f1Smrg
41234977a2fSmrgstatic void
41334977a2fSmrgCloseKeyboard(InputInfoPtr pInfo)
41434977a2fSmrg{
41534977a2fSmrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
41634977a2fSmrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
41734977a2fSmrg
41834977a2fSmrg    close(pInfo->fd);
41934977a2fSmrg    pInfo->fd = -1;
42034977a2fSmrg    priv->kbdActive = FALSE;
42134977a2fSmrg}
42234977a2fSmrg
42334977a2fSmrg/* Called from OsTimer callback, since removing a device from the device
42434977a2fSmrg   list or changing pInfo->fd while xf86Wakeup is looping through the list
42534977a2fSmrg   causes server crashes */
42634977a2fSmrgstatic CARD32
42734977a2fSmrgRemoveKeyboard(OsTimerPtr timer, CARD32 time, pointer arg)
42834977a2fSmrg{
42934977a2fSmrg    InputInfoPtr pInfo = (InputInfoPtr) arg;
43034977a2fSmrg
43134977a2fSmrg    CloseKeyboard(pInfo);
43234977a2fSmrg    xf86DisableDevice(pInfo->dev, TRUE);
43334977a2fSmrg
43434977a2fSmrg    return 0;  /* All done, don't set to run again */
43534977a2fSmrg}
43634977a2fSmrg
437ee3138f1Smrgstatic void
438ee3138f1SmrgReadInput(InputInfoPtr pInfo)
439ee3138f1Smrg{
440ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
44134977a2fSmrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
442ee3138f1Smrg    Firm_event event[64];
443ee3138f1Smrg    int        nBytes, i;
444ee3138f1Smrg
44534977a2fSmrg    while (TRUE) {
44634977a2fSmrg	/* I certainly hope it's not possible to read partial events */
44734977a2fSmrg	nBytes = read(pInfo->fd, (char *)event, sizeof(event));
44834977a2fSmrg	if (nBytes > 0) {
44934977a2fSmrg	    for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) {
45034977a2fSmrg		pKbd->PostEvent(pInfo, event[i].id & 0xFF,
45134977a2fSmrg				event[i].value == VKEY_DOWN ? TRUE : FALSE);
45234977a2fSmrg	    }
45334977a2fSmrg	} else if (nBytes == -1) {
45434977a2fSmrg	    switch (errno) {
45534977a2fSmrg		case EAGAIN: /* Nothing to read now */
45634977a2fSmrg		    return;
45734977a2fSmrg		case EINTR:  /* Interrupted, try again */
45834977a2fSmrg		    break;
45934977a2fSmrg		case ENODEV: /* May happen when USB kbd is unplugged */
46034977a2fSmrg		    /* We use X_NONE here because it doesn't alloc since we
46134977a2fSmrg		       may be called from SIGIO handler */
46234977a2fSmrg		    xf86MsgVerb(X_NONE, 0,
46334977a2fSmrg				"%s: Device no longer present - removing.\n",
46434977a2fSmrg				pInfo->name);
46534977a2fSmrg		    xf86RemoveEnabledDevice(pInfo);
46634977a2fSmrg		    priv->remove_timer = TimerSet(priv->remove_timer, 0, 1,
46734977a2fSmrg						  RemoveKeyboard, pInfo);
46834977a2fSmrg		    return;
46934977a2fSmrg		default:     /* All other errors */
47034977a2fSmrg		    /* We use X_NONE here because it doesn't alloc since we
47134977a2fSmrg		       may be called from SIGIO handler */
47234977a2fSmrg		    xf86MsgVerb(X_NONE, 0, "%s: Read error: %s\n", pInfo->name,
47334977a2fSmrg				strerror(errno));
47434977a2fSmrg		    return;
47534977a2fSmrg	    }
47634977a2fSmrg	} else { /* nBytes == 0, so nothing more to read */
47734977a2fSmrg	    return;
478ee3138f1Smrg	}
479ee3138f1Smrg    }
480ee3138f1Smrg}
481ee3138f1Smrg
482ee3138f1Smrgstatic Bool
483ee3138f1SmrgOpenKeyboard(InputInfoPtr pInfo)
484ee3138f1Smrg{
485a1ed278cSmrg    char *kbdPath = xf86SetStrOption(pInfo->options, "Device", "/dev/kbd");
486a1ed278cSmrg    Bool ret;
487ee3138f1Smrg
488ee3138f1Smrg    pInfo->fd = open(kbdPath, O_RDONLY | O_NONBLOCK);
489ee3138f1Smrg
490ee3138f1Smrg    if (pInfo->fd == -1) {
491a1ed278cSmrg	xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, kbdPath);
492a1ed278cSmrg	ret = FALSE;
493ee3138f1Smrg    } else {
494ee3138f1Smrg	xf86MsgVerb(X_INFO, 3, "%s: Opened device \"%s\"\n", pInfo->name,
495ee3138f1Smrg		    kbdPath);
496ee3138f1Smrg	pInfo->read_input = ReadInput;
497a1ed278cSmrg	ret = TRUE;
498ee3138f1Smrg    }
499a1ed278cSmrg
500a1ed278cSmrg    free(kbdPath);
501a1ed278cSmrg    return ret;
502ee3138f1Smrg}
503ee3138f1Smrg
504ee3138f1Smrg_X_EXPORT Bool
505ee3138f1Smrgxf86OSKbdPreInit(InputInfoPtr pInfo)
506ee3138f1Smrg{
507ee3138f1Smrg    KbdDevPtr pKbd = pInfo->private;
508ee3138f1Smrg
509ee3138f1Smrg    pKbd->KbdInit       = KbdInit;
510ee3138f1Smrg    pKbd->KbdOn         = KbdOn;
511ee3138f1Smrg    pKbd->KbdOff        = KbdOff;
512ee3138f1Smrg    pKbd->Bell          = SoundKbdBell;
513ee3138f1Smrg    pKbd->SetLeds       = SetKbdLeds;
514ee3138f1Smrg    pKbd->GetLeds       = GetKbdLeds;
515ee3138f1Smrg    pKbd->KbdGetMapping = KbdGetMapping;
516ee3138f1Smrg
517ee3138f1Smrg    pKbd->RemapScanCode = NULL;
518ee3138f1Smrg
519ee3138f1Smrg    pKbd->OpenKeyboard = OpenKeyboard;
520ee3138f1Smrg
521a1ed278cSmrg    pKbd->private = calloc(sizeof(sunKbdPrivRec), 1);
522ee3138f1Smrg    if (pKbd->private == NULL) {
523ee3138f1Smrg       xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n");
524ee3138f1Smrg       return FALSE;
525ee3138f1Smrg    } else {
526ee3138f1Smrg	sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
527ee3138f1Smrg	priv->otranslation = -1;
528ee3138f1Smrg	priv->odirect = -1;
529ee3138f1Smrg    }
530ee3138f1Smrg
531ee3138f1Smrg    return TRUE;
532ee3138f1Smrg}
533