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