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