x68kKbd.c revision 4ff7d041
1/* $NetBSD: x68kKbd.c,v 1.16 2025/06/22 22:30:33 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 x68kKbdEvents(int, int, void *);
91static void x68kInitModMap(KeySymsRec *, CARD8 *);
92static void x68kInitKbdNames(XkbRMLVOSet *, X68kKbdPrivPtr);
93static Firm_event *x68kKbdGetEvents(int, int *, Bool *);
94static void x68kKbdEnqueueEvent(DeviceIntPtr, Firm_event *);
95static void x68kKbdRingBell(DeviceIntPtr, int, int);
96static void x68kKbdBell(int, DeviceIntPtr, void *, int);
97static void x68kKbdCtrl(DeviceIntPtr, KeybdCtrl *);
98static void x68kSetLeds(X68kKbdPrivPtr, uint8_t);
99
100/*------------------------------------------------------------------------
101 * x68kKbdEvents --
102 *	When registered polled keyboard input event handler is invoked,
103 *	read device events and enqueue them using the mi event queue.
104 * Results:
105 *	None.
106 *
107 *----------------------------------------------------------------------*/
108static void
109x68kKbdEvents(int fd, int ready, void *data)
110{
111    int i, numEvents = 0;
112    Bool again = FALSE;
113    Firm_event *events;
114    DeviceIntPtr device = (DeviceIntPtr)data;
115
116    input_lock();
117
118    do {
119	events = x68kKbdGetEvents(fd, &numEvents, &again);
120	for (i = 0; i < numEvents; i++) {
121	    x68kKbdEnqueueEvent(device, &events[i]);
122	}
123    } while (again);
124
125    input_unlock();
126}
127
128/*------------------------------------------------------------------------
129 * x68kKbdProc --
130 *	Handle the initialization, etc. of a keyboard.
131 *
132 * Results:
133 *	None.
134 *
135 *----------------------------------------------------------------------*/
136int
137x68kKbdProc(DeviceIntPtr device,	/* Keyboard to manipulate */
138            int what)			/* What to do to it */
139{
140    DevicePtr pKeyboard = &device->public;
141    X68kKbdPrivPtr pPriv;
142    CARD8 x68kModMap[MAP_LENGTH];
143    int mode;
144    XkbRMLVOSet rmlvo;
145
146    switch (what) {
147        case DEVICE_INIT:
148            pPriv = &x68kKbdPriv;
149            if ((pPriv->fd = open("/dev/kbd", O_RDONLY | O_NONBLOCK)) == -1) {
150                ErrorF("Can't open keyboard device\n");
151                return !Success;
152            }
153            pKeyboard->devicePrivate = pPriv;
154            pKeyboard->on = FALSE;
155            x68kInitModMap(x68kKeySyms, x68kModMap);
156
157            x68kInitKbdNames(&rmlvo, pPriv);
158#if 0 /* XXX How should we setup XKB maps for non PS/2 keyboard!? */
159            InitKeyboardDeviceStruct(device, &rmlvo,
160                                     x68kKbdBell, x68kKbdCtrl);
161#else
162            InitKeyboardDeviceStruct(device, NULL,
163                                     x68kKbdBell, x68kKbdCtrl);
164	    XkbApplyMappingChange(device, x68kKeySyms,
165		x68kKeySyms->minKeyCode,
166		x68kKeySyms->maxKeyCode - x68kKeySyms->minKeyCode + 1,
167		x68kModMap, serverClient);
168#endif
169            break;
170
171        case DEVICE_ON:
172            pPriv = (X68kKbdPrivPtr)pKeyboard->devicePrivate;
173            mode = 1;
174            if (ioctl(pPriv->fd, KIOCSDIRECT, &mode) == -1) {
175                LogMessage(X_ERROR, "Failed to set keyboard direct mode\n");
176                return !Success;
177            }
178	    x68kSetLeds(pPriv, (uint8_t)pPriv->leds);
179            SetNotifyFd(pPriv->fd, x68kKbdEvents, X_NOTIFY_READ, device);
180            pKeyboard->on = TRUE;
181            break;
182
183        case DEVICE_CLOSE:
184        case DEVICE_OFF:
185            pPriv = (X68kKbdPrivPtr)pKeyboard->devicePrivate;
186            RemoveNotifyFd(pPriv->fd);
187            pKeyboard->on = FALSE;
188            break;
189
190        case DEVICE_ABORT:
191            break;
192    }
193    return Success;
194}
195
196/*-------------------------------------------------------------------------
197 * function "x68kInitModMap"
198 *
199 *  purpose:  initialize modmap with keysym table
200 *  argument: (KeySymsRec *)x68kKeySyms : keysym table
201 *            (CARD8 *)x68kModMap       : result
202 *  returns:  nothing
203 *-----------------------------------------------------------------------*/
204static void
205x68kInitModMap(KeySymsRec *KeySyms, CARD8 *x68kModMap)
206{
207    int i;
208
209    for (i = 0; i < MAP_LENGTH; i++)
210        x68kModMap[i] = NoSymbol;
211    if (KeySyms->minKeyCode < MIN_KEYCODE) {
212        KeySyms->minKeyCode += MIN_KEYCODE;
213        KeySyms->maxKeyCode += MIN_KEYCODE;
214    }
215    if (KeySyms->maxKeyCode > MAX_KEYCODE)
216        KeySyms->maxKeyCode = MAX_KEYCODE;
217    for (i = KeySyms->minKeyCode;
218         i < KeySyms->maxKeyCode; i++) {
219        switch (KeySyms->map[(i-KeySyms->minKeyCode)*4]) {
220            case XK_Shift_L:
221            case XK_Shift_R:
222                x68kModMap[i] = ShiftMask;
223                break;
224            case XK_Control_L:
225            case XK_Control_R:
226                x68kModMap[i] = ControlMask;
227                break;
228            case XK_Alt_L:
229            case XK_Alt_R:
230                x68kModMap[i] = Mod1Mask;
231                break;
232            case XK_Meta_L:
233            case XK_Meta_R:
234                x68kModMap[i] = Mod2Mask;
235                break;
236            case XK_Caps_Lock:
237                x68kModMap[i] = LockMask;
238                break;
239        }
240    }
241}
242
243/*-------------------------------------------------------------------------
244 * function "x68kInitKbdNames"
245 *
246 *  purpose:  store xkb database names
247 *  argument: (XkbRMLVOSet *)rmlvo
248 *            (X68kKbdPrivPtr)pKbd
249 *  returns:  nothing
250 *-----------------------------------------------------------------------*/
251static void
252x68kInitKbdNames(XkbRMLVOSet *rmlvo, X68kKbdPrivPtr pKbd)
253{
254#if 0 /* XXX How should we setup XKB maps for non PS/2 keyboard!? */
255    rmlvo->rules = "base";
256    rmlvo->model = "x68k";
257    switch (pKbd->type) {
258    case X68K_KB_STANDARD:
259        rmlvo->layout = "jp(standard)";
260        break;
261    case X68K_KB_ASCII:
262        rmlvo->layout = "jp(ascii)";
263        break;
264    }
265    rmlvo->variant = "basic";
266    rmlvo->options = "";
267#else
268    rmlvo->rules = "base";
269    rmlvo->model = NULL;
270    rmlvo->layout = NULL;
271    rmlvo->variant = NULL;
272    rmlvo->options = NULL;
273#endif
274}
275
276/*-
277 *-----------------------------------------------------------------------
278 * x68kKbdGetEvents --
279 *	Return the events waiting in the wings for the given keyboard.
280 *
281 * Results:
282 *	A pointer to an array of Firm_events or (Firm_event *)0 if no events
283 *	The number of events contained in the array.
284 *	A boolean as to whether more events might be available.
285 *
286 * Side Effects:
287 *	None.
288 *-----------------------------------------------------------------------
289 */
290static Firm_event *
291x68kKbdGetEvents(int fd, int *pNumEvents, Bool *pAgain)
292{
293    int nBytes;		/* number of bytes of events available. */
294    static Firm_event evBuf[X68K_MAXEVENTS];	/* Buffer for Firm_events */
295
296    if ((nBytes = read (fd, evBuf, sizeof(evBuf))) == -1) {
297	if (errno == EWOULDBLOCK) {
298	    *pNumEvents = 0;
299	    *pAgain = FALSE;
300	} else {
301	    ErrorF("Reading keyboard\n");
302	    FatalError ("Could not read the keyboard");
303	}
304    } else {
305	*pNumEvents = nBytes / sizeof (Firm_event);
306	*pAgain = (nBytes == sizeof (evBuf));
307    }
308    return evBuf;
309}
310
311/*-
312 *-----------------------------------------------------------------------
313 * x68kKbdEnqueueEvent --
314 *
315 *-----------------------------------------------------------------------
316 */
317static void
318x68kKbdEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
319{
320    BYTE		keycode;
321    int			type;
322
323    type = ((fe->value == VKEY_UP) ? KeyRelease : KeyPress);
324    keycode = (fe->id & 0x7f) + MIN_KEYCODE;
325    QueueKeyboardEvents(device, type, keycode);
326}
327
328/*-
329 *-----------------------------------------------------------------------
330 * x68kKbdBell --
331 *	Ring the terminal/keyboard bell
332 *
333 * Results:
334 *	Ring the keyboard bell for an amount of time proportional to
335 *	"loudness."
336 *
337 * Side Effects:
338 *	None, really...
339 *
340 *-----------------------------------------------------------------------
341 */
342
343static void
344x68kKbdRingBell(DeviceIntPtr device, int volume, int duration)
345{
346    int		    kbdCmd;	/* Command to give keyboard */
347    X68kKbdPrivPtr  pPriv = (X68kKbdPrivPtr)device->public.devicePrivate;
348
349    if (volume == 0)
350	return;
351
352    kbdCmd = KBD_CMD_BELL;
353    if (ioctl (pPriv->fd, KIOCCMD, &kbdCmd) == -1) {
354	ErrorF("Failed to activate bell\n");
355	return;
356    }
357    usleep (duration * 1000);
358    kbdCmd = KBD_CMD_NOBELL;
359    if (ioctl (pPriv->fd, KIOCCMD, &kbdCmd) == -1)
360	ErrorF("Failed to deactivate bell\n");
361}
362
363static void
364x68kKbdBell(int volume, DeviceIntPtr device, void *ctrl, int unused)
365{
366    KeybdCtrl*      kctrl = (KeybdCtrl*) ctrl;
367
368    if (kctrl->bell == 0)
369	return;
370
371    x68kKbdRingBell(device, volume, kctrl->bell_duration);
372}
373
374void
375DDXRingBell(int volume, int pitch, int duration)
376{
377    DeviceIntPtr	pKeyboard;
378
379    pKeyboard = x68kKeyboardDevice;
380    if (pKeyboard != NULL)
381	x68kKbdRingBell(pKeyboard, volume, duration);
382}
383
384/*-
385 *-----------------------------------------------------------------------
386 * x68kKbdCtrl --
387 *	Alter some of the keyboard control parameters
388 *
389 * Results:
390 *	None.
391 *
392 * Side Effects:
393 *	Some...
394 *
395 *-----------------------------------------------------------------------
396 */
397#define	XKB_LED_ZENKAKU		0x40
398#define	XKB_LED_HIRAGANA	0x20
399#define	XKB_LED_INSERT		0x10
400#define	XKB_LED_CAPS_LOCK	0x08
401#define	XKB_LED_CODE_INPUT	0x04
402#define	XKB_LED_ROMAJI		0x02
403#define	XKB_LED_KANA_LOCK	0x01
404
405static void
406x68kKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
407{
408    X68kKbdPrivPtr pPriv = (X68kKbdPrivPtr)device->public.devicePrivate;
409
410    if (pPriv->leds != ctrl->leds) {
411        x68kSetLeds(pPriv, (uint8_t)ctrl->leds);
412	pPriv->leds = ctrl->leds;
413    }
414}
415
416/*-------------------------------------------------------------------------
417 * function "x68kSetLeds"
418 *
419 *  purpose:  set keyboard leds to specified state
420 *  argument: (X68kKbdPrivPtr)pPriv
421 *            (uint8_t)data;
422 *  returns:  nothing
423 *-----------------------------------------------------------------------*/
424static void
425x68kSetLeds(X68kKbdPrivPtr pPriv, uint8_t data)
426{
427    /* bit sequence of led indicator in xkb and hardware are same */
428    if (ioctl(pPriv->fd, KIOCSLED, &data) == -1)
429        ErrorF("Failed to set keyboard lights\n");
430}
431
432/* EOF x68kKbd.c */
433