sun_kbd.c revision ee3138f1
1/*
2 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany
3 * Copyright 1993 by David Dawes <dawes@XFree86.org>
4 * Copyright 1999 by David Holland <davidh@iquest.net)
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting documentation, and
10 * that the names of Thomas Roell, David Dawes, and David Holland not be used
11 * in advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission.  Thomas Roell, David Dawes, and
13 * David Holland make no representations about the suitability of this software
14 * for any purpose.  It is provided "as is" without express or implied
15 * warranty.
16 *
17 * THOMAS ROELL, DAVID DAWES, AND DAVID HOLLAND DISCLAIM ALL WARRANTIES WITH
18 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19 * AND FITNESS.  IN NO EVENT SHALL THOMAS ROELL, DAVID DAWES, OR DAVID HOLLAND
20 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
22 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 */
25/* Copyright 2004-2007 Sun Microsystems, Inc.  All rights reserved.
26 *
27 * Permission is hereby granted, free of charge, to any person obtaining a
28 * copy of this software and associated documentation files (the
29 * "Software"), to deal in the Software without restriction, including
30 * without limitation the rights to use, copy, modify, merge, publish,
31 * distribute, and/or sell copies of the Software, and to permit persons
32 * to whom the Software is furnished to do so, provided that the above
33 * copyright notice(s) and this permission notice appear in all copies of
34 * the Software and that both the above copyright notice(s) and this
35 * permission notice appear in supporting documentation.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
40 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
41 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
42 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
43 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
44 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
45 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 *
47 * Except as contained in this notice, the name of a copyright holder
48 * shall not be used in advertising or otherwise to promote the sale, use
49 * or other dealings in this Software without prior written authorization
50 * of the copyright holder.
51 */
52
53#ifdef HAVE_CONFIG_H
54#include "config.h"
55#endif
56
57#include "xf86.h"
58#include "xf86Priv.h"
59#include "xf86_OSlib.h"
60#include "xf86OSKbd.h"
61#include "sun_kbd.h"
62
63#include <sys/stropts.h>
64#include <sys/vuid_event.h>
65#include <sys/kbd.h>
66
67static void
68sunKbdSetLeds(InputInfoPtr pInfo, int leds)
69{
70    int i;
71
72    SYSCALL(i = ioctl(pInfo->fd, KIOCSLED, &leds));
73    if (i < 0) {
74	xf86Msg(X_ERROR, "%s: Failed to set keyboard LED's: %s\n",
75                pInfo->name, strerror(errno));
76    }
77}
78
79
80static int
81sunKbdGetLeds(InputInfoPtr pInfo)
82{
83    int i, leds = 0;
84
85    SYSCALL(i = ioctl(pInfo->fd, KIOCGLED, &leds));
86    if (i < 0) {
87        xf86Msg(X_ERROR, "%s: Failed to get keyboard LED's: %s\n",
88                pInfo->name, strerror(errno));
89    }
90    return leds;
91}
92
93
94/*
95 * Save initial keyboard state.  This is called at the start of each server
96 * generation.
97 */
98static int
99KbdInit(InputInfoPtr pInfo, int what)
100{
101    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
102    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
103    pointer options = pInfo->options;
104
105    int	ktype, klayout, i;
106    const char *ktype_name;
107
108    priv->otranslation 	= -1;
109    priv->odirect 	= -1;
110
111    if (options != NULL) {
112	priv->strmod = xf86SetStrOption(options, "StreamsModule", NULL);
113    } else {
114	priv->strmod 		= NULL;
115    }
116
117    if (priv->strmod) {
118	SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod));
119	if (i < 0) {
120	    xf86Msg(X_ERROR,
121		    "%s: cannot push module '%s' onto keyboard device: %s\n",
122		    pInfo->name, priv->strmod, strerror(errno));
123	}
124    }
125
126    SYSCALL(i = ioctl(pInfo->fd, KIOCTYPE, &ktype));
127    if (i < 0) {
128	xf86Msg(X_ERROR, "%s: Unable to determine keyboard type: %s\n",
129		pInfo->name, strerror(errno));
130	return BadImplementation;
131    }
132
133    SYSCALL(i = ioctl(pInfo->fd, KIOCLAYOUT, &klayout));
134    if (i < 0) {
135	xf86Msg(X_ERROR, "%s: Unable to determine keyboard layout: %s\n",
136		pInfo->name, strerror(errno));
137	return BadImplementation;
138    }
139
140    switch (ktype) {
141    case KB_SUN3:
142	ktype_name = "Sun Type 3"; break;
143    case KB_SUN4:
144	ktype_name = "Sun Type 4/5/6"; break;
145    case KB_USB:
146	ktype_name = "USB"; break;
147    case KB_PC:
148	ktype_name = "PC"; break;
149    default:
150	ktype_name = "Unknown"; break;
151    }
152
153    xf86Msg(X_PROBED, "%s: Keyboard type: %s (%d)\n",
154	    pInfo->name, ktype_name, ktype);
155    xf86Msg(X_PROBED, "%s: Keyboard layout: %d\n", pInfo->name, klayout);
156
157    priv->ktype 	= ktype;
158    priv->oleds 	= sunKbdGetLeds(pInfo);
159
160    return Success;
161}
162
163
164static int
165KbdOn(InputInfoPtr pInfo, int what)
166{
167    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
168    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
169
170    int	ktrans, kdirect, i;
171
172    SYSCALL(i = ioctl(pInfo->fd, KIOCGDIRECT, &kdirect));
173    if (i < 0) {
174	xf86Msg(X_ERROR,
175		"%s: Unable to determine keyboard direct setting: %s\n",
176		pInfo->name, strerror(errno));
177	return BadImplementation;
178    }
179
180    priv->odirect = kdirect;
181    kdirect = 1;
182
183    SYSCALL(i = ioctl(pInfo->fd, KIOCSDIRECT, &kdirect));
184    if (i < 0) {
185	xf86Msg(X_ERROR, "%s: Failed turning keyboard direct mode on: %s\n",
186			pInfo->name, strerror(errno));
187	return BadImplementation;
188    }
189
190    /* Setup translation */
191
192    SYSCALL(i = ioctl(pInfo->fd, KIOCGTRANS, &ktrans));
193    if (i < 0) {
194	xf86Msg(X_ERROR,
195		"%s: Unable to determine keyboard translation mode: %s\n",
196		pInfo->name, strerror(errno));
197	return BadImplementation;
198    }
199
200    priv->otranslation = ktrans;
201    ktrans = TR_UNTRANS_EVENT;
202
203    SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &ktrans));
204    if (i < 0) {
205	xf86Msg(X_ERROR, "%s: Failed setting keyboard translation mode: %s\n",
206			pInfo->name, strerror(errno));
207	return BadImplementation;
208    }
209
210    return Success;
211}
212
213static int
214KbdOff(InputInfoPtr pInfo, int what)
215{
216    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
217    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
218
219    int i;
220
221    /* restore original state */
222
223    sunKbdSetLeds(pInfo, priv->oleds);
224
225    if (priv->otranslation != -1) {
226        SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &priv->otranslation));
227	if (i < 0) {
228	    xf86Msg(X_ERROR,
229		    "%s: Unable to restore keyboard translation mode: %s\n",
230		    pInfo->name, strerror(errno));
231	    return BadImplementation;
232	}
233	priv->otranslation = -1;
234    }
235
236    if (priv->odirect != -1) {
237        SYSCALL(i = ioctl(pInfo->fd, KIOCSDIRECT, &priv->odirect));
238	if (i < 0) {
239	    xf86Msg(X_ERROR,
240		    "%s: Unable to restore keyboard direct setting: %s\n",
241		    pInfo->name, strerror(errno));
242	    return BadImplementation;
243	}
244	priv->odirect = -1;
245    }
246
247    if (priv->strmod) {
248	SYSCALL(i = ioctl(pInfo->fd, I_POP, priv->strmod));
249	if (i < 0) {
250            xf86Msg(X_WARNING,
251		    "%s: cannot pop module '%s' off keyboard device: %s\n",
252		    pInfo->name, priv->strmod, strerror(errno));
253	}
254    }
255
256    return Success;
257}
258
259
260static void
261SoundKbdBell(InputInfoPtr pInfo, int loudness, int pitch, int duration)
262{
263    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
264    sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
265
266    int	kbdCmd, i;
267#ifdef KIOCMKTONE
268    int cycles;
269    int mktonevalue;
270#endif
271
272    if (loudness && pitch)
273    {
274#ifdef KIOCMKTONE
275	if (pitch == 0)
276	    cycles = UINT16_MAX;
277	else if (pitch >= UINT16_MAX)
278	    cycles = 0;
279	else {
280	    cycles = (PIT_HZ + pitch / 2) / pitch;
281	    if (cycles > UINT16_MAX)
282		cycles = UINT16_MAX;
283	}
284
285	mktonevalue = cycles | (((duration * loudness * 20) / 1000) << 16);
286
287	errno = 0;
288	SYSCALL(i = ioctl (pInfo->fd, KIOCMKTONE, mktonevalue));
289	if (i == 0)
290	    return;
291
292	if (errno != EINVAL) {
293	    if (errno != EAGAIN)
294		xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n",
295			pInfo->name, strerror(errno));
296	    return;
297	}
298#endif
299
300 	kbdCmd = KBD_CMD_BELL;
301
302	SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd));
303	if (i < 0) {
304	    xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n",
305                pInfo->name, strerror(errno));
306	}
307
308	usleep(duration * loudness * 20);
309
310	kbdCmd = KBD_CMD_NOBELL;
311	SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd));
312	if (i < 0) {
313	     xf86Msg(X_ERROR, "%s: Failed to deactivate bell: %s\n",
314                pInfo->name, strerror(errno));
315	}
316    }
317}
318
319static void
320SetKbdLeds(InputInfoPtr pInfo, int leds)
321{
322    int real_leds = sunKbdGetLeds(pInfo);
323
324    real_leds &= ~(LED_CAPS_LOCK | LED_NUM_LOCK | LED_SCROLL_LOCK | LED_COMPOSE);
325
326    if (leds & XLED1)  real_leds |= LED_CAPS_LOCK;
327    if (leds & XLED2)  real_leds |= LED_NUM_LOCK;
328    if (leds & XLED3)  real_leds |= LED_SCROLL_LOCK;
329    if (leds & XLED4)  real_leds |= LED_COMPOSE;
330
331    sunKbdSetLeds(pInfo, real_leds);
332}
333
334static int
335GetKbdLeds(InputInfoPtr pInfo)
336{
337    int leds = 0;
338    int real_leds = sunKbdGetLeds(pInfo);
339
340    if (real_leds & LED_CAPS_LOCK)	leds |= XLED1;
341    if (real_leds & LED_NUM_LOCK)	leds |= XLED2;
342    if (real_leds & LED_SCROLL_LOCK)	leds |= XLED3;
343    if (real_leds & LED_COMPOSE)	leds |= XLED4;
344
345    return leds;
346}
347
348/* ARGSUSED0 */
349static void
350SetKbdRepeat(InputInfoPtr pInfo, char rad)
351{
352    /* Nothing to do */
353}
354
355static void
356ReadInput(InputInfoPtr pInfo)
357{
358    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
359    Firm_event event[64];
360    int        nBytes, i;
361
362    /* I certainly hope its not possible to read partial events */
363
364    if ((nBytes = read(pInfo->fd, (char *)event, sizeof(event))) > 0)
365    {
366        for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) {
367	    pKbd->PostEvent(pInfo, event[i].id & 0xFF,
368			    event[i].value == VKEY_DOWN ? TRUE : FALSE);
369	}
370    }
371}
372
373static Bool
374OpenKeyboard(InputInfoPtr pInfo)
375{
376    const char *kbdPath = NULL;
377    const char *defaultKbd = "/dev/kbd";
378
379    if (pInfo->options != NULL) {
380	kbdPath = xf86SetStrOption(pInfo->options, "Device", NULL);
381    }
382    if (kbdPath == NULL) {
383        kbdPath = defaultKbd;
384    }
385
386    pInfo->fd = open(kbdPath, O_RDONLY | O_NONBLOCK);
387
388    if (pInfo->fd == -1) {
389        xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, kbdPath);
390    } else {
391	xf86MsgVerb(X_INFO, 3, "%s: Opened device \"%s\"\n", pInfo->name,
392		    kbdPath);
393    }
394
395    if ((kbdPath != NULL) && (kbdPath != defaultKbd)) {
396	xfree(kbdPath);
397    }
398
399    if (pInfo->fd == -1) {
400	return FALSE;
401    } else {
402	pInfo->read_input = ReadInput;
403	return TRUE;
404    }
405}
406
407_X_EXPORT Bool
408xf86OSKbdPreInit(InputInfoPtr pInfo)
409{
410    KbdDevPtr pKbd = pInfo->private;
411
412    pKbd->KbdInit       = KbdInit;
413    pKbd->KbdOn         = KbdOn;
414    pKbd->KbdOff        = KbdOff;
415    pKbd->Bell          = SoundKbdBell;
416    pKbd->SetLeds       = SetKbdLeds;
417    pKbd->GetLeds       = GetKbdLeds;
418    pKbd->SetKbdRepeat  = SetKbdRepeat;
419    pKbd->KbdGetMapping = KbdGetMapping;
420
421    pKbd->RemapScanCode = NULL;
422    pKbd->GetSpecialKey = NULL;
423    pKbd->SpecialKey    = NULL;
424
425    pKbd->OpenKeyboard = OpenKeyboard;
426
427    pKbd->vtSwitchSupported = FALSE;
428    pKbd->CustomKeycodes = FALSE;
429
430    pKbd->private = xcalloc(sizeof(sunKbdPrivRec), 1);
431    if (pKbd->private == NULL) {
432       xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n");
433       return FALSE;
434    } else {
435	sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private;
436	priv->otranslation = -1;
437	priv->odirect = -1;
438    }
439
440    return TRUE;
441}
442