bsd_kbd.c revision 836253ff
1
2/*
3 * Copyright (c) 2002 by The XFree86 Project, Inc.
4 * Author: Ivan Pascal.
5 *
6 * Based on the code from bsd_io.c which is
7 * Copyright 1992 by Rich Murphey <Rich@Rice.edu>
8 * Copyright 1993 by David Dawes <dawes@xfree86.org>
9 */
10
11#ifdef HAVE_CONFIG_H
12#include "config.h"
13#endif
14
15#include <xorg-server.h>
16#include <X11/X.h>
17#include <termios.h>
18
19#include "compiler.h"
20
21#include "xf86.h"
22#include "xf86Priv.h"
23#include "xf86_OSlib.h"
24
25#include "xf86Xinput.h"
26#include "xf86OSKbd.h"
27#include "atKeynames.h"
28#include "bsd_kbd.h"
29
30static KbdProtocolRec protocols[] = {
31   {"standard", PROT_STD },
32#ifdef WSCONS_SUPPORT
33   {"wskbd", PROT_WSCONS },
34#endif
35   { NULL, PROT_UNKNOWN_KBD }
36};
37
38typedef struct {
39   struct termios kbdtty;
40} BsdKbdPrivRec, *BsdKbdPrivPtr;
41
42static
43int KbdInit(InputInfoPtr pInfo, int what)
44{
45    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
46    BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private;
47
48    if (pKbd->isConsole) {
49        switch (pKbd->consType) {
50#if defined(PCCONS_SUPPORT) || defined(SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)  || defined (WSCONS_SUPPORT)
51	    case PCCONS:
52	    case SYSCONS:
53	    case PCVT:
54#if defined WSCONS_SUPPORT
55            case WSCONS:
56#endif
57 	         tcgetattr(pInfo->fd, &(priv->kbdtty));
58#endif
59	         break;
60        }
61    }
62
63    return Success;
64}
65
66static void
67SetKbdLeds(InputInfoPtr pInfo, int leds)
68{
69    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
70    int real_leds = 0;
71
72#ifdef LED_CAP
73    if (leds & XLED1)  real_leds |= LED_CAP;
74#endif
75#ifdef LED_NUM
76    if (leds & XLED2)  real_leds |= LED_NUM;
77#endif
78#ifdef LED_SCR
79    if (leds & XLED3)  real_leds |= LED_SCR;
80    if (leds & XLED4)  real_leds |= LED_SCR;
81#endif
82
83    switch (pKbd->consType) {
84
85#ifdef PCCONS_SUPPORT
86	case PCCONS:
87		break;
88#endif
89#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
90	case SYSCONS:
91	case PCVT:
92	     ioctl(pInfo->fd, KDSETLED, real_leds);
93	     break;
94#endif
95#if defined(WSCONS_SUPPORT)
96        case WSCONS:
97             ioctl(pInfo->fd, WSKBDIO_SETLEDS, &real_leds);
98             break;
99#endif
100    }
101}
102
103static int
104GetKbdLeds(InputInfoPtr pInfo)
105{
106    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
107    int leds = 0, real_leds = 0;
108
109    switch (pKbd->consType) {
110
111#ifdef PCCONS_SUPPORT
112	case PCCONS:
113	     break;
114#endif
115#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
116	case SYSCONS:
117	case PCVT:
118	     ioctl(pInfo->fd, KDGETLED, &real_leds);
119	     break;
120#endif
121#if defined(WSCONS_SUPPORT)
122        case WSCONS:
123             ioctl(pInfo->fd, WSKBDIO_GETLEDS, &real_leds);
124             break;
125#endif
126    }
127
128#ifdef LED_CAP
129    if (real_leds & LED_CAP) leds |= XLED1;
130#endif
131#ifdef LED_NUM
132    if (real_leds & LED_NUM) leds |= XLED2;
133#endif
134#ifdef LED_SCR
135    if (real_leds & LED_SCR) leds |= XLED3;
136#endif
137
138    return(leds);
139}
140
141static int
142KbdOn(InputInfoPtr pInfo, int what)
143{
144    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
145#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT)
146    BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private;
147    struct termios nTty;
148#endif
149#ifdef WSCONS_SUPPORT
150    int option;
151#endif
152
153    if (pKbd->isConsole) {
154        switch (pKbd->consType) {
155
156#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT)
157	    case SYSCONS:
158	    case PCCONS:
159	    case PCVT:
160#ifdef WSCONS_SUPPORT
161            case WSCONS:
162#endif
163		 nTty = priv->kbdtty;
164		 nTty.c_iflag = IGNPAR | IGNBRK;
165		 nTty.c_oflag = 0;
166		 nTty.c_cflag = CREAD | CS8;
167		 nTty.c_lflag = 0;
168		 nTty.c_cc[VTIME] = 0;
169		 nTty.c_cc[VMIN] = 1;
170		 cfsetispeed(&nTty, 9600);
171		 cfsetospeed(&nTty, 9600);
172		 if (tcsetattr(pInfo->fd, TCSANOW, &nTty) < 0) {
173			 xf86Msg(X_ERROR, "KbdOn: tcsetattr: %s\n",
174			     strerror(errno));
175		 }
176                 break;
177#endif
178        }
179#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT)
180        switch (pKbd->consType) {
181	    case SYSCONS:
182	    case PCVT:
183#ifdef K_CODE
184                 if (pKbd->CustomKeycodes)
185		     ioctl(pInfo->fd, KDSKBMODE, K_CODE);
186	         else
187	             ioctl(pInfo->fd, KDSKBMODE, K_RAW);
188#else
189		 ioctl(pInfo->fd, KDSKBMODE, K_RAW);
190#endif
191	         break;
192#ifdef WSCONS_SUPPORT
193            case WSCONS:
194                 option = WSKBD_RAW;
195                 if (ioctl(pInfo->fd, WSKBDIO_SETMODE, &option) == -1) {
196			 FatalError("can't switch keyboard to raw mode. "
197				    "Enable support for it in the kernel\n"
198				    "or use for example:\n\n"
199				    "Option \"Protocol\" \"wskbd\"\n"
200				    "Option \"Device\" \"/dev/wskbd0\"\n"
201				    "\nin your xorg.conf(5) file\n");
202		 }
203		 break;
204#endif
205        }
206#endif
207    }
208    return Success;
209}
210
211static int
212KbdOff(InputInfoPtr pInfo, int what)
213{
214    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
215    BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private;
216#ifdef WSCONS_SUPPORT
217    int option;
218#endif
219
220    if (pKbd->isConsole) {
221        switch (pKbd->consType) {
222#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
223	    case SYSCONS:
224	    case PCVT:
225	         ioctl(pInfo->fd, KDSKBMODE, K_XLATE);
226	         /* FALL THROUGH */
227#endif
228#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT)
229	    case PCCONS:
230	         tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty));
231	         break;
232#endif
233#ifdef WSCONS_SUPPORT
234            case WSCONS:
235                 option = WSKBD_TRANSLATED;
236                 ioctl(xf86Info.consoleFd, WSKBDIO_SETMODE, &option);
237                 tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty));
238	         break;
239#endif
240        }
241    }
242    return Success;
243}
244
245static void
246SoundBell(InputInfoPtr pInfo, int loudness, int pitch, int duration)
247{
248    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
249#ifdef WSCONS_SUPPORT
250    struct wskbd_bell_data wsb;
251#endif
252
253    if (loudness && pitch) {
254    	switch (pKbd->consType) {
255#ifdef PCCONS_SUPPORT
256	    case PCCONS:
257	         { int data[2];
258		   data[0] = pitch;
259		   data[1] = (duration * loudness) / 50;
260		   ioctl(pInfo->fd, CONSOLE_X_BELL, data);
261		   break;
262		 }
263#endif
264#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
265	    case SYSCONS:
266	    case PCVT:
267		 ioctl(pInfo->fd, KDMKTONE,
268		 ((1193190 / pitch) & 0xffff) |
269		 (((unsigned long)duration*loudness/50)<<16));
270		 break;
271#endif
272#if defined (WSCONS_SUPPORT)
273            case WSCONS:
274                 wsb.which = WSKBD_BELL_DOALL;
275                 wsb.pitch = pitch;
276                 wsb.period = duration;
277                 wsb.volume = loudness;
278                 ioctl(pInfo->fd, WSKBDIO_COMPLEXBELL, &wsb);
279                 break;
280#endif
281	}
282    }
283}
284
285static void
286stdReadInput(InputInfoPtr pInfo)
287{
288    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
289    unsigned char rBuf[64];
290    int nBytes, i;
291    if ((nBytes = read( pInfo->fd, (char *)rBuf, sizeof(rBuf))) > 0) {
292       for (i = 0; i < nBytes; i++)
293	   pKbd->PostEvent(pInfo, rBuf[i] & 0x7f,
294                           rBuf[i] & 0x80 ? FALSE : TRUE);
295       }
296}
297
298#ifdef WSCONS_SUPPORT
299
300static void
301WSReadInput(InputInfoPtr pInfo)
302{
303    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
304    struct wscons_event events[64];
305    int type;
306    int blocked, n, i;
307
308    if ((n = read( pInfo->fd, events, sizeof(events))) > 0) {
309        n /=  sizeof(struct wscons_event);
310        for (i = 0; i < n; i++) {
311	    type = events[i].type;
312	    if (type == WSCONS_EVENT_KEY_UP || type == WSCONS_EVENT_KEY_DOWN) {
313		/* It seems better to block SIGIO there */
314		blocked = xf86BlockSIGIO();
315		pKbd->PostEvent(pInfo, (unsigned int)(events[i].value),
316				type == WSCONS_EVENT_KEY_DOWN ? TRUE : FALSE);
317		xf86UnblockSIGIO(blocked);
318	    }
319	} /* for */
320    }
321}
322
323static void
324printWsType(const char *type, char *name)
325{
326    xf86Msg(X_PROBED, "%s: Keyboard type: %s\n", name, type);
327}
328#endif
329
330static Bool
331OpenKeyboard(InputInfoPtr pInfo)
332{
333    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
334    int i;
335    KbdProtocolId prot = PROT_UNKNOWN_KBD;
336    char *s;
337
338    s = xf86SetStrOption(pInfo->options, "Protocol", NULL);
339    for (i = 0; protocols[i].name; i++) {
340        if (xf86NameCmp(s, protocols[i].name) == 0) {
341           prot = protocols[i].id;
342           break;
343        }
344    }
345
346    switch (prot) {
347    	case PROT_STD:
348           pInfo->read_input = stdReadInput;
349           break;
350#ifdef WSCONS_SUPPORT
351        case PROT_WSCONS:
352           pInfo->read_input = WSReadInput;
353           break;
354#endif
355        default:
356           xf86Msg(X_ERROR,"\"%s\" is not a valid keyboard protocol name\n", s);
357           free(s);
358           return FALSE;
359    }
360    free(s);
361
362    if (prot == PROT_WSCONS) {
363	s = xf86SetStrOption(pInfo->options, "Device", "/dev/wskbd");
364    } else
365	s = xf86SetStrOption(pInfo->options, "Device", NULL);
366
367    if (s == NULL) {
368	pInfo->fd = xf86Info.consoleFd;
369	pKbd->isConsole = TRUE;
370	pKbd->consType = xf86Info.consType;
371    } else {
372	pInfo->fd = open(s, O_RDONLY | O_NONBLOCK | O_EXCL);
373	if (pInfo->fd == -1) {
374           xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, s);
375           free(s);
376           return FALSE;
377       }
378       pKbd->isConsole = FALSE;
379       pKbd->consType = xf86Info.consType;
380       free(s);
381    }
382
383#ifdef WSCONS_SUPPORT
384    if( prot == PROT_WSCONS) {
385       pKbd->consType = WSCONS;
386#ifdef WSKBDIO_SETVERSION
387       int version = WSKBDIO_EVENT_VERSION;
388       if (ioctl(pInfo->fd, WSKBDIO_SETVERSION, &version) == -1) {
389           xf86Msg(X_WARNING, "%s: cannot set version\n", pInfo->name);
390           return FALSE;
391       }
392#endif
393       /* Find out keyboard type */
394       if (ioctl(pInfo->fd, WSKBDIO_GTYPE, &(pKbd->wsKbdType)) == -1) {
395           xf86Msg(X_ERROR, "%s: cannot get keyboard type", pInfo->name);
396           close(pInfo->fd);
397           return FALSE;
398       }
399       switch (pKbd->wsKbdType) {
400           case WSKBD_TYPE_PC_XT:
401               printWsType("XT", pInfo->name);
402               break;
403           case WSKBD_TYPE_PC_AT:
404               printWsType("AT", pInfo->name);
405               break;
406           case WSKBD_TYPE_USB:
407               printWsType("USB", pInfo->name);
408               break;
409#ifdef WSKBD_TYPE_ADB
410           case WSKBD_TYPE_ADB:
411               printWsType("ADB", pInfo->name);
412               break;
413#endif
414#ifdef WSKBD_TYPE_LK201
415           case WSKBD_TYPE_LK201:
416               printWsType("LK201", pInfo->name);
417               break;
418#endif
419#ifdef WSKBD_TYPE_MAPLE
420           case WSKBD_TYPE_MAPLE:
421               printWsType("Maple", pInfo->name);
422               break;
423#endif
424#ifdef WSKBD_TYPE_SUN
425           case WSKBD_TYPE_SUN:
426               printWsType("Sun", pInfo->name);
427               break;
428#endif
429#ifdef WSKBD_TYPE_SUN5
430           case WSKBD_TYPE_SUN5:
431               printWsType("Sun5", pInfo->name);
432               break;
433#endif
434           default:
435               xf86Msg(X_ERROR, "%s: Unsupported wskbd type \"%d\"",
436                                pInfo->name, pKbd->wsKbdType);
437               close(pInfo->fd);
438               return FALSE;
439       }
440    }
441#endif
442
443#if 0	/* no more vtSwitchSupported in xf86-input-keyboard-1.6.0 */
444#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT)
445    if ((pKbd->isConsole &&
446         ((pKbd->consType == SYSCONS) || (pKbd->consType == PCVT))) ||
447	(pKbd->consType == WSCONS))
448        pKbd->vtSwitchSupported = TRUE;
449#endif
450#endif
451
452    return TRUE;
453}
454
455_X_EXPORT Bool
456xf86OSKbdPreInit(InputInfoPtr pInfo)
457{
458    KbdDevPtr pKbd = pInfo->private;
459
460    pKbd->KbdInit	= KbdInit;
461    pKbd->KbdOn		= KbdOn;
462    pKbd->KbdOff	= KbdOff;
463    pKbd->Bell		= SoundBell;
464    pKbd->SetLeds	= SetKbdLeds;
465    pKbd->GetLeds	= GetKbdLeds;
466    pKbd->KbdGetMapping	= KbdGetMapping;
467
468    pKbd->RemapScanCode = NULL;
469
470    pKbd->OpenKeyboard = OpenKeyboard;
471
472    pKbd->private = calloc(sizeof(BsdKbdPrivRec), 1);
473    if (pKbd->private == NULL) {
474       xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n");
475       return FALSE;
476    }
477    return TRUE;
478}
479