x68kKbd.c revision bd299232
1/* $NetBSD: x68kKbd.c,v 1.9 2020/11/01 11:44:55 tsutsui Exp $ */
2/*-------------------------------------------------------------------------
3 * Copyright (c) 1996 Yasushi Yamasaki
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *-----------------------------------------------------------------------*/
26
27/*-
28 * Copyright (c) 1987 by the Regents of the University of California
29 *
30 * Permission to use, copy, modify, and distribute this
31 * software and its documentation for any purpose and without
32 * fee is hereby granted, provided that the above copyright
33 * notice appear in all copies.  The University of California
34 * makes no representations about the suitability of this
35 * software for any purpose.  It is provided "as is" without
36 * express or implied warranty.
37 */
38
39/************************************************************
40Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.
41
42                    All Rights Reserved
43
44Permission  to  use,  copy,  modify,  and  distribute   this
45software  and  its documentation for any purpose and without
46fee is hereby granted, provided that the above copyright no-
47tice  appear  in all copies and that both that copyright no-
48tice and this permission notice appear in  supporting  docu-
49mentation,  and  that the names of Sun or X Consortium
50not be used in advertising or publicity pertaining to
51distribution  of  the software  without specific prior
52written permission. Sun and X Consortium make no
53representations about the suitability of this software for
54any purpose. It is provided "as is" without any express or
55implied warranty.
56
57SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
58INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
59NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
60ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
61ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
62PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
63OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
64THE USE OR PERFORMANCE OF THIS SOFTWARE.
65
66********************************************************/
67
68#include "x68k.h"
69#include "mi.h"
70
71#include <X11/X.h>
72#include <X11/Xproto.h>
73#include <X11/keysym.h>
74#include "screenint.h"
75#include "inputstr.h"
76#include "eventstr.h"
77#include "misc.h"
78#include "scrnintstr.h"
79#include "servermd.h"
80
81#include <X11/extensions/XKB.h>
82#include "xkbsrv.h"
83
84#define MIN_KEYCODE     7       /* necessary to avoid the mouse buttons */
85#define MAX_KEYCODE     255     /* limited by the protocol */
86
87X68kKbdPriv x68kKbdPriv;
88DeviceIntPtr x68kKeyboardDevice = NULL;
89
90static void x68kKbdHandlerNotify(int, int, void *);
91static void x68kInitModMap(KeySymsRec *, CARD8 *);
92static void x68kInitKbdNames(XkbRMLVOSet *, X68kKbdPrivPtr);
93static void x68kKbdRingBell(DeviceIntPtr, int, int);
94static void x68kKbdBell(int, DeviceIntPtr, void *, int);
95static void x68kKbdCtrl(DeviceIntPtr, KeybdCtrl *);
96static void x68kSetLeds(X68kKbdPrivPtr, u_char);
97
98static void
99x68kKbdHandlerNotify(int fd __unused, int ready __unused, void *data __unused)
100{
101}
102
103/*------------------------------------------------------------------------
104 * x68kKbdProc --
105 *	Handle the initialization, etc. of a keyboard.
106 *
107 * Results:
108 *	None.
109 *
110 *----------------------------------------------------------------------*/
111int
112x68kKbdProc(DeviceIntPtr pDev,	/* Keyboard to manipulate */
113            int what)		/* What to do to it */
114{
115    DevicePtr pKeyboard = &pDev->public;
116    CARD8 x68kModMap[MAP_LENGTH];
117    int mode;
118    XkbRMLVOSet rmlvo;
119
120    switch (what) {
121        case DEVICE_INIT:
122            pKeyboard->devicePrivate = (void *)&x68kKbdPriv;
123            if( (x68kKbdPriv.fd = open("/dev/kbd", O_RDONLY)) == -1 ) {
124                ErrorF("Can't open keyboard device");
125                return !Success;
126            }
127            pKeyboard->on = FALSE;
128            x68kInitModMap(x68kKeySyms, x68kModMap);
129
130            x68kInitKbdNames(&rmlvo, pKeyboard->devicePrivate);
131#if 0 /* XXX How should we setup XKB maps for non PS/2 keyboard!? */
132            InitKeyboardDeviceStruct(pDev, &rmlvo,
133                                     x68kKbdBell, x68kKbdCtrl);
134#else
135            InitKeyboardDeviceStruct(pDev, NULL,
136                                     x68kKbdBell, x68kKbdCtrl);
137	    XkbApplyMappingChange(pDev, x68kKeySyms,
138		x68kKeySyms->minKeyCode,
139		x68kKeySyms->maxKeyCode - x68kKeySyms->minKeyCode + 1,
140		x68kModMap, serverClient);
141#endif
142            break;
143
144        case DEVICE_ON:
145            mode = 1;
146            if ( fcntl(x68kKbdPriv.fd, F_SETOWN, getpid()) == -1 ||
147                 fcntl(x68kKbdPriv.fd, F_SETFL, O_NONBLOCK|O_ASYNC) == -1 ||
148                 ioctl(x68kKbdPriv.fd, KIOCSDIRECT, &mode) == -1 ) {
149                ErrorF("Async keyboard I/O failed");
150                return !Success;
151            }
152	    x68kSetLeds(&x68kKbdPriv, (u_char)x68kKbdPriv.leds);
153            SetNotifyFd(x68kKbdPriv.fd, x68kKbdHandlerNotify,
154		X_NOTIFY_READ, NULL);
155            pKeyboard->on = TRUE;
156            break;
157
158        case DEVICE_CLOSE:
159        case DEVICE_OFF:
160            RemoveNotifyFd(x68kKbdPriv.fd);
161            pKeyboard->on = FALSE;
162            break;
163        default:
164            FatalError("Unknown keyboard operation\n");
165    }
166    return Success;
167}
168
169/*-------------------------------------------------------------------------
170 * function "x68kInitModMap"
171 *
172 *  purpose:  initialize modmap with keysym table
173 *  argument: (KeySymsRec *)x68kKeySyms : keysym table
174 *            (CARD8 *)x68kModMap       : result
175 *  returns:  nothing
176 *-----------------------------------------------------------------------*/
177static void
178x68kInitModMap(KeySymsRec *KeySyms, CARD8 *x68kModMap)
179{
180    int i;
181
182    for (i = 0; i < MAP_LENGTH; i++)
183        x68kModMap[i] = NoSymbol;
184    if (KeySyms->minKeyCode < MIN_KEYCODE) {
185        KeySyms->minKeyCode += MIN_KEYCODE;
186        KeySyms->maxKeyCode += MIN_KEYCODE;
187    }
188    if (KeySyms->maxKeyCode > MAX_KEYCODE)
189        KeySyms->maxKeyCode = MAX_KEYCODE;
190    for (i = KeySyms->minKeyCode;
191         i < KeySyms->maxKeyCode; i++) {
192        switch (KeySyms->map[(i-KeySyms->minKeyCode)*4]) {
193            case XK_Shift_L:
194            case XK_Shift_R:
195                x68kModMap[i] = ShiftMask;
196                break;
197            case XK_Control_L:
198            case XK_Control_R:
199                x68kModMap[i] = ControlMask;
200                break;
201            case XK_Alt_L:
202            case XK_Alt_R:
203                x68kModMap[i] = Mod1Mask;
204                break;
205            case XK_Meta_L:
206            case XK_Meta_R:
207                x68kModMap[i] = Mod2Mask;
208                break;
209            case XK_Caps_Lock:
210                x68kModMap[i] = LockMask;
211                break;
212        }
213    }
214}
215
216/*-------------------------------------------------------------------------
217 * function "x68kInitKbdNames"
218 *
219 *  purpose:  store xkb database names
220 *  argument: (XkbRMLVOSet *)rmlvo
221 *            (X68kKbdPrivPtr)pKbd
222 *  returns:  nothing
223 *-----------------------------------------------------------------------*/
224static void
225x68kInitKbdNames(XkbRMLVOSet *rmlvo, X68kKbdPrivPtr pKbd)
226{
227#if 0 /* XXX How should we setup XKB maps for non PS/2 keyboard!? */
228    rmlvo->rules = "base";
229    rmlvo->model = "x68k";
230    switch (pKbd->type) {
231    case X68K_KB_STANDARD:
232        rmlvo->layout = "jp(standard)";
233        break;
234    case X68K_KB_ASCII:
235        rmlvo->layout = "jp(ascii)";
236        break;
237    }
238    rmlvo->variant = "basic";
239    rmlvo->options = "";
240#else
241    rmlvo->rules = "base";
242    rmlvo->model = NULL;
243    rmlvo->layout = NULL;
244    rmlvo->variant = NULL;
245    rmlvo->options = NULL;
246#endif
247}
248
249/*-
250 *-----------------------------------------------------------------------
251 * x68kKbdGetEvents --
252 *	Return the events waiting in the wings for the given keyboard.
253 *
254 * Results:
255 *	A pointer to an array of Firm_events or (Firm_event *)0 if no events
256 *	The number of events contained in the array.
257 *	A boolean as to whether more events might be available.
258 *
259 * Side Effects:
260 *	None.
261 *-----------------------------------------------------------------------
262 */
263Firm_event *
264x68kKbdGetEvents(int fd, int *pNumEvents, Bool *pAgain)
265{
266    int nBytes;		/* number of bytes of events available. */
267    static Firm_event evBuf[X68K_MAXEVENTS];	/* Buffer for Firm_events */
268
269    if ((nBytes = read (fd, evBuf, sizeof(evBuf))) == -1) {
270	if (errno == EWOULDBLOCK) {
271	    *pNumEvents = 0;
272	    *pAgain = FALSE;
273	} else {
274	    ErrorF("Reading keyboard");
275	    FatalError ("Could not read the keyboard");
276	}
277    } else {
278	*pNumEvents = nBytes / sizeof (Firm_event);
279	*pAgain = (nBytes == sizeof (evBuf));
280    }
281    return evBuf;
282}
283
284/*-
285 *-----------------------------------------------------------------------
286 * x68kKbdEnqueueEvent --
287 *
288 *-----------------------------------------------------------------------
289 */
290void
291x68kKbdEnqueueEvent(DeviceIntPtr pDev, Firm_event *fe)
292{
293    BYTE		keycode;
294    int			type;
295
296    type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress);
297    keycode = (fe->id & 0x7f) + MIN_KEYCODE;
298    QueueKeyboardEvents(pDev, type, keycode);
299}
300
301/*-
302 *-----------------------------------------------------------------------
303 * x68kKbdBell --
304 *	Ring the terminal/keyboard bell
305 *
306 * Results:
307 *	Ring the keyboard bell for an amount of time proportional to
308 *	"loudness."
309 *
310 * Side Effects:
311 *	None, really...
312 *
313 *-----------------------------------------------------------------------
314 */
315
316static void
317x68kKbdRingBell(DeviceIntPtr pDev, int volume, int duration)
318{
319    int		    kbdCmd;	/* Command to give keyboard */
320    X68kKbdPrivPtr  pPriv = (X68kKbdPrivPtr)pDev->public.devicePrivate;
321
322    if (volume == 0)
323	return;
324
325    kbdCmd = KBD_CMD_BELL;
326    if (ioctl (pPriv->fd, KIOCCMD, &kbdCmd) == -1) {
327	ErrorF("Failed to activate bell");
328	return;
329    }
330    usleep (duration * 1000);
331    kbdCmd = KBD_CMD_NOBELL;
332    if (ioctl (pPriv->fd, KIOCCMD, &kbdCmd) == -1)
333	ErrorF("Failed to deactivate bell");
334}
335
336static void
337x68kKbdBell(int volume, DeviceIntPtr pDev, void *ctrl, int unused)
338{
339    KeybdCtrl*      kctrl = (KeybdCtrl*) ctrl;
340
341    if (kctrl->bell == 0)
342	return;
343
344    x68kKbdRingBell(pDev, volume, kctrl->bell_duration);
345}
346
347void
348DDXRingBell(int volume, int pitch, int duration)
349{
350    DeviceIntPtr	pKeyboard;
351
352    pKeyboard = x68kKeyboardDevice;
353    if (pKeyboard != NULL)
354	x68kKbdRingBell(pKeyboard, volume, duration);
355}
356
357/*-
358 *-----------------------------------------------------------------------
359 * x68kKbdCtrl --
360 *	Alter some of the keyboard control parameters
361 *
362 * Results:
363 *	None.
364 *
365 * Side Effects:
366 *	Some...
367 *
368 *-----------------------------------------------------------------------
369 */
370#define	XKB_LED_ZENKAKU		0x40
371#define	XKB_LED_HIRAGANA	0x20
372#define	XKB_LED_INSERT		0x10
373#define	XKB_LED_CAPS_LOCK	0x08
374#define	XKB_LED_CODE_INPUT	0x04
375#define	XKB_LED_ROMAJI		0x02
376#define	XKB_LED_KANA_LOCK	0x01
377
378static void
379x68kKbdCtrl(DeviceIntPtr pDev, KeybdCtrl *ctrl)
380{
381    X68kKbdPrivPtr pPriv = (X68kKbdPrivPtr)pDev->public.devicePrivate;
382
383    if (pPriv->leds != ctrl->leds) {
384        x68kSetLeds(pPriv, (u_char)ctrl->leds);
385	pPriv->leds = ctrl->leds;
386    }
387}
388
389/*-------------------------------------------------------------------------
390 * function "x68kSetLeds"
391 *
392 *  purpose:  set keyboard leds to specified state
393 *  argument: (X68kKbdPrivPtr)pPriv
394 *            (u_char)data;
395 *  returns:  nothing
396 *-----------------------------------------------------------------------*/
397static void
398x68kSetLeds(X68kKbdPrivPtr pPriv, u_char data)
399{
400    /* bit sequence of led indicator in xkb and hardware are same */
401    if (ioctl(pPriv->fd, KIOCSLED, &data) == -1)
402        ErrorF("Failed to set keyboard lights");
403}
404
405Bool
406LegalModifier(unsigned int key, DeviceIntPtr pDev)
407{
408    return TRUE;
409}
410
411/* EOF x68kKbd.c */
412