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