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