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