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;
733e72ca8cSmrg    uchar_t setleds = (uchar_t) (leds & 0xFF);
74ee3138f1Smrg
753e72ca8cSmrg    SYSCALL(i = ioctl(pInfo->fd, KIOCSLED, &setleds));
76ee3138f1Smrg    if (i < 0) {
77ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Failed to set keyboard LED's: %s\n",
78ee3138f1Smrg                pInfo->name, strerror(errno));
79ee3138f1Smrg    }
80ee3138f1Smrg}
81ee3138f1Smrg
82ee3138f1Smrg
83ee3138f1Smrgstatic int
84ee3138f1SmrgsunKbdGetLeds(InputInfoPtr pInfo)
85ee3138f1Smrg{
863e72ca8cSmrg    int i;
873e72ca8cSmrg    uchar_t leds = 0;
88ee3138f1Smrg
89ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCGLED, &leds));
90ee3138f1Smrg    if (i < 0) {
91ee3138f1Smrg        xf86Msg(X_ERROR, "%s: Failed to get keyboard LED's: %s\n",
92ee3138f1Smrg                pInfo->name, strerror(errno));
93ee3138f1Smrg    }
943e72ca8cSmrg    return (int) leds;
95ee3138f1Smrg}
96ee3138f1Smrg
97ee3138f1Smrg
98ee3138f1Smrg/*
99ee3138f1Smrg * Save initial keyboard state.  This is called at the start of each server
100ee3138f1Smrg * generation.
101ee3138f1Smrg */
102ee3138f1Smrgstatic int
103ee3138f1SmrgKbdInit(InputInfoPtr pInfo, int what)
104ee3138f1Smrg{
105ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
106ee3138f1Smrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
107ee3138f1Smrg    pointer options = pInfo->options;
108ee3138f1Smrg
109ee3138f1Smrg    int	ktype, klayout, i;
110ee3138f1Smrg    const char *ktype_name;
111ee3138f1Smrg
11234977a2fSmrg    priv->kbdActive	= FALSE;
113ee3138f1Smrg    priv->otranslation 	= -1;
114ee3138f1Smrg    priv->odirect 	= -1;
115ee3138f1Smrg
116ee3138f1Smrg    if (options != NULL) {
117ee3138f1Smrg	priv->strmod = xf86SetStrOption(options, "StreamsModule", NULL);
118ee3138f1Smrg    } else {
119ee3138f1Smrg	priv->strmod 		= NULL;
120ee3138f1Smrg    }
121ee3138f1Smrg
12234977a2fSmrg    i = KbdOn(pInfo, DEVICE_INIT);
12334977a2fSmrg    if (i != Success) {
12434977a2fSmrg	return i;
125ee3138f1Smrg    }
12634977a2fSmrg
127ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCTYPE, &ktype));
128ee3138f1Smrg    if (i < 0) {
129ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Unable to determine keyboard type: %s\n",
130ee3138f1Smrg		pInfo->name, strerror(errno));
131ee3138f1Smrg	return BadImplementation;
132ee3138f1Smrg    }
133ee3138f1Smrg
134ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCLAYOUT, &klayout));
135ee3138f1Smrg    if (i < 0) {
136ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Unable to determine keyboard layout: %s\n",
137ee3138f1Smrg		pInfo->name, strerror(errno));
138ee3138f1Smrg	return BadImplementation;
139ee3138f1Smrg    }
140ee3138f1Smrg
141ee3138f1Smrg    switch (ktype) {
142ee3138f1Smrg    case KB_SUN3:
143ee3138f1Smrg	ktype_name = "Sun Type 3"; break;
144ee3138f1Smrg    case KB_SUN4:
145ee3138f1Smrg	ktype_name = "Sun Type 4/5/6"; break;
146ee3138f1Smrg    case KB_USB:
147ee3138f1Smrg	ktype_name = "USB"; break;
148ee3138f1Smrg    case KB_PC:
149ee3138f1Smrg	ktype_name = "PC"; break;
150ee3138f1Smrg    default:
151ee3138f1Smrg	ktype_name = "Unknown"; break;
152ee3138f1Smrg    }
153ee3138f1Smrg
154ee3138f1Smrg    xf86Msg(X_PROBED, "%s: Keyboard type: %s (%d)\n",
155ee3138f1Smrg	    pInfo->name, ktype_name, ktype);
156ee3138f1Smrg    xf86Msg(X_PROBED, "%s: Keyboard layout: %d\n", pInfo->name, klayout);
157ee3138f1Smrg
158ee3138f1Smrg    priv->ktype 	= ktype;
159ee3138f1Smrg
160ee3138f1Smrg    return Success;
161ee3138f1Smrg}
162ee3138f1Smrg
163ee3138f1Smrg
164ee3138f1Smrgstatic int
165ee3138f1SmrgKbdOn(InputInfoPtr pInfo, int what)
166ee3138f1Smrg{
167ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
168ee3138f1Smrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
169ee3138f1Smrg
170ee3138f1Smrg    int	ktrans, kdirect, i;
17134977a2fSmrg    int io_get_direct = KIOCGDIRECT;
17234977a2fSmrg    int io_set_direct = KIOCSDIRECT;
17334977a2fSmrg
17434977a2fSmrg    if (priv->kbdActive) {
17534977a2fSmrg	return Success;
17634977a2fSmrg    }
177ee3138f1Smrg
17834977a2fSmrg    if (pInfo->fd == -1) {
17934977a2fSmrg	if (!OpenKeyboard(pInfo)) {
18034977a2fSmrg	    return BadImplementation;
18134977a2fSmrg	}
18234977a2fSmrg    }
18334977a2fSmrg
18434977a2fSmrg    if (priv->strmod) {
18534977a2fSmrg	/* Check to see if module is already pushed */
18634977a2fSmrg	SYSCALL(i = ioctl(pInfo->fd, I_FIND, priv->strmod));
18734977a2fSmrg
18834977a2fSmrg	if (i == 0) { /* Not already pushed */
18934977a2fSmrg	    SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod));
19034977a2fSmrg	    if (i < 0) {
19134977a2fSmrg		xf86Msg(X_ERROR, "%s: cannot push module '%s' onto "
19234977a2fSmrg			"keyboard device: %s\n",
19334977a2fSmrg			pInfo->name, priv->strmod, strerror(errno));
19434977a2fSmrg	    }
19534977a2fSmrg	}
19634977a2fSmrg
19734977a2fSmrg#ifdef HIDIOCKMSDIRECT
19834977a2fSmrg	if (strcmp(priv->strmod, "usbkbm") == 0) {
19934977a2fSmrg	    io_get_direct = HIDIOCKMGDIRECT;
20034977a2fSmrg	    io_set_direct = HIDIOCKMSDIRECT;
20134977a2fSmrg	}
20234977a2fSmrg#endif
20334977a2fSmrg    }
20434977a2fSmrg
20534977a2fSmrg    SYSCALL(i = ioctl(pInfo->fd, io_get_direct, &kdirect));
206ee3138f1Smrg    if (i < 0) {
207ee3138f1Smrg	xf86Msg(X_ERROR,
208ee3138f1Smrg		"%s: Unable to determine keyboard direct setting: %s\n",
209ee3138f1Smrg		pInfo->name, strerror(errno));
210ee3138f1Smrg	return BadImplementation;
211ee3138f1Smrg    }
212ee3138f1Smrg
213ee3138f1Smrg    priv->odirect = kdirect;
214ee3138f1Smrg    kdirect = 1;
215ee3138f1Smrg
21634977a2fSmrg    SYSCALL(i = ioctl(pInfo->fd, io_set_direct, &kdirect));
217ee3138f1Smrg    if (i < 0) {
218ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Failed turning keyboard direct mode on: %s\n",
219ee3138f1Smrg			pInfo->name, strerror(errno));
220ee3138f1Smrg	return BadImplementation;
221ee3138f1Smrg    }
222ee3138f1Smrg
223ee3138f1Smrg    /* Setup translation */
224ee3138f1Smrg
225ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCGTRANS, &ktrans));
226ee3138f1Smrg    if (i < 0) {
227ee3138f1Smrg	xf86Msg(X_ERROR,
228ee3138f1Smrg		"%s: Unable to determine keyboard translation mode: %s\n",
229ee3138f1Smrg		pInfo->name, strerror(errno));
230ee3138f1Smrg	return BadImplementation;
231ee3138f1Smrg    }
232ee3138f1Smrg
233ee3138f1Smrg    priv->otranslation = ktrans;
234ee3138f1Smrg    ktrans = TR_UNTRANS_EVENT;
235ee3138f1Smrg
236ee3138f1Smrg    SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &ktrans));
237ee3138f1Smrg    if (i < 0) {
238ee3138f1Smrg	xf86Msg(X_ERROR, "%s: Failed setting keyboard translation mode: %s\n",
239ee3138f1Smrg			pInfo->name, strerror(errno));
240ee3138f1Smrg	return BadImplementation;
241ee3138f1Smrg    }
242ee3138f1Smrg
24334977a2fSmrg    priv->oleds	= sunKbdGetLeds(pInfo);
24434977a2fSmrg
24534977a2fSmrg    /* Allocate here so we don't alloc in ReadInput which may be called
24634977a2fSmrg       from SIGIO handler. */
24734977a2fSmrg    priv->remove_timer = TimerSet(priv->remove_timer, 0, 0, NULL, NULL);
24834977a2fSmrg
24934977a2fSmrg    priv->kbdActive = TRUE;
250ee3138f1Smrg    return Success;
251ee3138f1Smrg}
252ee3138f1Smrg
253ee3138f1Smrgstatic int
254ee3138f1SmrgKbdOff(InputInfoPtr pInfo, int what)
255ee3138f1Smrg{
256ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
257ee3138f1Smrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
258ee3138f1Smrg
259ee3138f1Smrg    int i;
26034977a2fSmrg    int io_set_direct, kdirect;
26134977a2fSmrg
26234977a2fSmrg    if (priv->remove_timer) {
26334977a2fSmrg	TimerFree(priv->remove_timer);
26434977a2fSmrg	priv->remove_timer = NULL;
26534977a2fSmrg    }
26634977a2fSmrg
26734977a2fSmrg    if (!priv->kbdActive) {
26834977a2fSmrg	return Success;
26934977a2fSmrg    }
27034977a2fSmrg
27134977a2fSmrg    if (pInfo->fd == -1) {
27234977a2fSmrg	priv->kbdActive = FALSE;
27334977a2fSmrg	return Success;
27434977a2fSmrg    }
275ee3138f1Smrg
276ee3138f1Smrg    /* restore original state */
27779a8a9c6Smrg
27879a8a9c6Smrg    if (priv->oleds != -1) {
27979a8a9c6Smrg	sunKbdSetLeds(pInfo, priv->oleds);
28079a8a9c6Smrg	priv->oleds = -1;
28179a8a9c6Smrg    }
282ee3138f1Smrg
283ee3138f1Smrg    if (priv->otranslation != -1) {
284ee3138f1Smrg        SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &priv->otranslation));
285ee3138f1Smrg	if (i < 0) {
286ee3138f1Smrg	    xf86Msg(X_ERROR,
287ee3138f1Smrg		    "%s: Unable to restore keyboard translation mode: %s\n",
288ee3138f1Smrg		    pInfo->name, strerror(errno));
289ee3138f1Smrg	    return BadImplementation;
290ee3138f1Smrg	}
291ee3138f1Smrg	priv->otranslation = -1;
292ee3138f1Smrg    }
293ee3138f1Smrg
29434977a2fSmrg    io_set_direct = KIOCSDIRECT;
29534977a2fSmrg    kdirect = priv->odirect;
29634977a2fSmrg
29734977a2fSmrg#ifdef HIDIOCKMSDIRECT
29834977a2fSmrg    if ((priv->strmod != NULL) && (strcmp(priv->strmod, "usbkbm") == 0)) {
29934977a2fSmrg	io_set_direct = HIDIOCKMSDIRECT;
30034977a2fSmrg	kdirect = 0;
30134977a2fSmrg    }
30234977a2fSmrg#endif
30334977a2fSmrg
30434977a2fSmrg    if (kdirect != -1) {
30534977a2fSmrg	SYSCALL(i = ioctl(pInfo->fd, io_set_direct, &kdirect));
306ee3138f1Smrg	if (i < 0) {
307ee3138f1Smrg	    xf86Msg(X_ERROR,
308ee3138f1Smrg		    "%s: Unable to restore keyboard direct setting: %s\n",
309ee3138f1Smrg		    pInfo->name, strerror(errno));
310ee3138f1Smrg	    return BadImplementation;
311ee3138f1Smrg	}
312ee3138f1Smrg	priv->odirect = -1;
313ee3138f1Smrg    }
314ee3138f1Smrg
315ee3138f1Smrg    if (priv->strmod) {
316ee3138f1Smrg	SYSCALL(i = ioctl(pInfo->fd, I_POP, priv->strmod));
317ee3138f1Smrg	if (i < 0) {
318ee3138f1Smrg            xf86Msg(X_WARNING,
319ee3138f1Smrg		    "%s: cannot pop module '%s' off keyboard device: %s\n",
320ee3138f1Smrg		    pInfo->name, priv->strmod, strerror(errno));
321ee3138f1Smrg	}
322ee3138f1Smrg    }
323ee3138f1Smrg
32434977a2fSmrg    CloseKeyboard(pInfo);
325ee3138f1Smrg    return Success;
326ee3138f1Smrg}
327ee3138f1Smrg
328ee3138f1Smrg
329ee3138f1Smrgstatic void
330ee3138f1SmrgSoundKbdBell(InputInfoPtr pInfo, int loudness, int pitch, int duration)
331ee3138f1Smrg{
332ee3138f1Smrg    int	kbdCmd, i;
333ee3138f1Smrg#ifdef KIOCMKTONE
334ee3138f1Smrg    int cycles;
335ee3138f1Smrg    int mktonevalue;
336ee3138f1Smrg#endif
337ee3138f1Smrg
338ee3138f1Smrg    if (loudness && pitch)
339ee3138f1Smrg    {
340ee3138f1Smrg#ifdef KIOCMKTONE
341ee3138f1Smrg	if (pitch == 0)
342ee3138f1Smrg	    cycles = UINT16_MAX;
343ee3138f1Smrg	else if (pitch >= UINT16_MAX)
344ee3138f1Smrg	    cycles = 0;
345ee3138f1Smrg	else {
346ee3138f1Smrg	    cycles = (PIT_HZ + pitch / 2) / pitch;
347ee3138f1Smrg	    if (cycles > UINT16_MAX)
348ee3138f1Smrg		cycles = UINT16_MAX;
349ee3138f1Smrg	}
350ee3138f1Smrg
351ee3138f1Smrg	mktonevalue = cycles | (((duration * loudness * 20) / 1000) << 16);
352ee3138f1Smrg
353ee3138f1Smrg	errno = 0;
354ee3138f1Smrg	SYSCALL(i = ioctl (pInfo->fd, KIOCMKTONE, mktonevalue));
355ee3138f1Smrg	if (i == 0)
356ee3138f1Smrg	    return;
357ee3138f1Smrg
358ee3138f1Smrg	if (errno != EINVAL) {
359ee3138f1Smrg	    if (errno != EAGAIN)
360ee3138f1Smrg		xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n",
361ee3138f1Smrg			pInfo->name, strerror(errno));
362ee3138f1Smrg	    return;
363ee3138f1Smrg	}
364ee3138f1Smrg#endif
365ee3138f1Smrg
366ee3138f1Smrg 	kbdCmd = KBD_CMD_BELL;
367ee3138f1Smrg
368ee3138f1Smrg	SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd));
369ee3138f1Smrg	if (i < 0) {
370ee3138f1Smrg	    xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n",
371ee3138f1Smrg                pInfo->name, strerror(errno));
372ee3138f1Smrg	}
373ee3138f1Smrg
374ee3138f1Smrg	usleep(duration * loudness * 20);
375ee3138f1Smrg
376ee3138f1Smrg	kbdCmd = KBD_CMD_NOBELL;
377ee3138f1Smrg	SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd));
378ee3138f1Smrg	if (i < 0) {
379ee3138f1Smrg	     xf86Msg(X_ERROR, "%s: Failed to deactivate bell: %s\n",
380ee3138f1Smrg                pInfo->name, strerror(errno));
381ee3138f1Smrg	}
382ee3138f1Smrg    }
383ee3138f1Smrg}
384ee3138f1Smrg
385ee3138f1Smrgstatic void
386ee3138f1SmrgSetKbdLeds(InputInfoPtr pInfo, int leds)
387ee3138f1Smrg{
388ee3138f1Smrg    int real_leds = sunKbdGetLeds(pInfo);
389ee3138f1Smrg
390ee3138f1Smrg    real_leds &= ~(LED_CAPS_LOCK | LED_NUM_LOCK | LED_SCROLL_LOCK | LED_COMPOSE);
391ee3138f1Smrg
392ee3138f1Smrg    if (leds & XLED1)  real_leds |= LED_CAPS_LOCK;
393ee3138f1Smrg    if (leds & XLED2)  real_leds |= LED_NUM_LOCK;
394ee3138f1Smrg    if (leds & XLED3)  real_leds |= LED_SCROLL_LOCK;
395ee3138f1Smrg    if (leds & XLED4)  real_leds |= LED_COMPOSE;
396ee3138f1Smrg
397ee3138f1Smrg    sunKbdSetLeds(pInfo, real_leds);
398ee3138f1Smrg}
399ee3138f1Smrg
400ee3138f1Smrgstatic int
401ee3138f1SmrgGetKbdLeds(InputInfoPtr pInfo)
402ee3138f1Smrg{
403ee3138f1Smrg    int leds = 0;
404ee3138f1Smrg    int real_leds = sunKbdGetLeds(pInfo);
405ee3138f1Smrg
406ee3138f1Smrg    if (real_leds & LED_CAPS_LOCK)	leds |= XLED1;
407ee3138f1Smrg    if (real_leds & LED_NUM_LOCK)	leds |= XLED2;
408ee3138f1Smrg    if (real_leds & LED_SCROLL_LOCK)	leds |= XLED3;
409ee3138f1Smrg    if (real_leds & LED_COMPOSE)	leds |= XLED4;
410ee3138f1Smrg
411ee3138f1Smrg    return leds;
412ee3138f1Smrg}
413ee3138f1Smrg
41434977a2fSmrgstatic void
41534977a2fSmrgCloseKeyboard(InputInfoPtr pInfo)
41634977a2fSmrg{
41734977a2fSmrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
41834977a2fSmrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
41934977a2fSmrg
42034977a2fSmrg    close(pInfo->fd);
42134977a2fSmrg    pInfo->fd = -1;
42234977a2fSmrg    priv->kbdActive = FALSE;
42334977a2fSmrg}
42434977a2fSmrg
42534977a2fSmrg/* Called from OsTimer callback, since removing a device from the device
42634977a2fSmrg   list or changing pInfo->fd while xf86Wakeup is looping through the list
42734977a2fSmrg   causes server crashes */
42834977a2fSmrgstatic CARD32
42934977a2fSmrgRemoveKeyboard(OsTimerPtr timer, CARD32 time, pointer arg)
43034977a2fSmrg{
43134977a2fSmrg    InputInfoPtr pInfo = (InputInfoPtr) arg;
43234977a2fSmrg
43334977a2fSmrg    CloseKeyboard(pInfo);
43434977a2fSmrg    xf86DisableDevice(pInfo->dev, TRUE);
43534977a2fSmrg
43634977a2fSmrg    return 0;  /* All done, don't set to run again */
43734977a2fSmrg}
43834977a2fSmrg
439ee3138f1Smrgstatic void
440ee3138f1SmrgReadInput(InputInfoPtr pInfo)
441ee3138f1Smrg{
442ee3138f1Smrg    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
44334977a2fSmrg    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
444ee3138f1Smrg    Firm_event event[64];
445ee3138f1Smrg    int        nBytes, i;
446ee3138f1Smrg
44734977a2fSmrg    while (TRUE) {
44834977a2fSmrg	/* I certainly hope it's not possible to read partial events */
44934977a2fSmrg	nBytes = read(pInfo->fd, (char *)event, sizeof(event));
45034977a2fSmrg	if (nBytes > 0) {
45134977a2fSmrg	    for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) {
45234977a2fSmrg		pKbd->PostEvent(pInfo, event[i].id & 0xFF,
45334977a2fSmrg				event[i].value == VKEY_DOWN ? TRUE : FALSE);
45434977a2fSmrg	    }
45534977a2fSmrg	} else if (nBytes == -1) {
45634977a2fSmrg	    switch (errno) {
45734977a2fSmrg		case EAGAIN: /* Nothing to read now */
45834977a2fSmrg		    return;
45934977a2fSmrg		case EINTR:  /* Interrupted, try again */
46034977a2fSmrg		    break;
46134977a2fSmrg		case ENODEV: /* May happen when USB kbd is unplugged */
4623e72ca8cSmrg		    /* We use X_NONE here because it didn't alloc since we
4633e72ca8cSmrg		       may be called from SIGIO handler. No longer true for
4643e72ca8cSmrg		       sigsafe logging, but matters for older servers  */
4653e72ca8cSmrg		    LogMessageVerbSigSafe(X_NONE, 0,
4663e72ca8cSmrg					  "%s: Device no longer present - removing.\n",
4673e72ca8cSmrg					  pInfo->name);
46834977a2fSmrg		    xf86RemoveEnabledDevice(pInfo);
46934977a2fSmrg		    priv->remove_timer = TimerSet(priv->remove_timer, 0, 1,
47034977a2fSmrg						  RemoveKeyboard, pInfo);
47134977a2fSmrg		    return;
47234977a2fSmrg		default:     /* All other errors */
4733e72ca8cSmrg		    /* We use X_NONE here because it didn't alloc since we
4743e72ca8cSmrg		       may be called from SIGIO handler. No longer true for
4753e72ca8cSmrg		       sigsafe logging, but matters for older servers  */
4763e72ca8cSmrg		    LogMessageVerbSigSafe(X_NONE, 0, "%s: Read error: %s\n", pInfo->name,
4773e72ca8cSmrg					  strerror(errno));
47834977a2fSmrg		    return;
47934977a2fSmrg	    }
48034977a2fSmrg	} else { /* nBytes == 0, so nothing more to read */
48134977a2fSmrg	    return;
482ee3138f1Smrg	}
483ee3138f1Smrg    }
484ee3138f1Smrg}
485ee3138f1Smrg
486ee3138f1Smrgstatic Bool
487ee3138f1SmrgOpenKeyboard(InputInfoPtr pInfo)
488ee3138f1Smrg{
489a1ed278cSmrg    char *kbdPath = xf86SetStrOption(pInfo->options, "Device", "/dev/kbd");
490a1ed278cSmrg    Bool ret;
491ee3138f1Smrg
492ee3138f1Smrg    pInfo->fd = open(kbdPath, O_RDONLY | O_NONBLOCK);
493ee3138f1Smrg
494ee3138f1Smrg    if (pInfo->fd == -1) {
495a1ed278cSmrg	xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, kbdPath);
496a1ed278cSmrg	ret = FALSE;
497ee3138f1Smrg    } else {
498ee3138f1Smrg	xf86MsgVerb(X_INFO, 3, "%s: Opened device \"%s\"\n", pInfo->name,
499ee3138f1Smrg		    kbdPath);
500ee3138f1Smrg	pInfo->read_input = ReadInput;
501a1ed278cSmrg	ret = TRUE;
5023e72ca8cSmrg	/* in case it wasn't set and we fell back to default */
5033e72ca8cSmrg	xf86ReplaceStrOption(pInfo->options, "Device", kbdPath);
504ee3138f1Smrg    }
505a1ed278cSmrg
506a1ed278cSmrg    free(kbdPath);
507a1ed278cSmrg    return ret;
508ee3138f1Smrg}
509ee3138f1Smrg
510ee3138f1Smrg_X_EXPORT Bool
511ee3138f1Smrgxf86OSKbdPreInit(InputInfoPtr pInfo)
512ee3138f1Smrg{
513ee3138f1Smrg    KbdDevPtr pKbd = pInfo->private;
514ee3138f1Smrg
515ee3138f1Smrg    pKbd->KbdInit       = KbdInit;
516ee3138f1Smrg    pKbd->KbdOn         = KbdOn;
517ee3138f1Smrg    pKbd->KbdOff        = KbdOff;
518ee3138f1Smrg    pKbd->Bell          = SoundKbdBell;
519ee3138f1Smrg    pKbd->SetLeds       = SetKbdLeds;
520ee3138f1Smrg    pKbd->GetLeds       = GetKbdLeds;
521ee3138f1Smrg    pKbd->KbdGetMapping = KbdGetMapping;
522ee3138f1Smrg
523ee3138f1Smrg    pKbd->RemapScanCode = NULL;
524ee3138f1Smrg
525ee3138f1Smrg    pKbd->OpenKeyboard = OpenKeyboard;
526ee3138f1Smrg
527a1ed278cSmrg    pKbd->private = calloc(sizeof(sunKbdPrivRec), 1);
528ee3138f1Smrg    if (pKbd->private == NULL) {
529ee3138f1Smrg       xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n");
530ee3138f1Smrg       return FALSE;
531ee3138f1Smrg    } else {
532ee3138f1Smrg	sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
533ee3138f1Smrg	priv->otranslation = -1;
534ee3138f1Smrg	priv->odirect = -1;
535ee3138f1Smrg    }
536ee3138f1Smrg
537ee3138f1Smrg    return TRUE;
538ee3138f1Smrg}
539