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