1 1.59 rillig /* $NetBSD: kbd.c,v 1.59 2024/09/08 09:36:48 rillig Exp $ */ 2 1.1 leo 3 1.1 leo /* 4 1.28 leo * Copyright (c) 1995 Leo Weppelman 5 1.1 leo * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 6 1.1 leo * All rights reserved. 7 1.1 leo * 8 1.1 leo * Redistribution and use in source and binary forms, with or without 9 1.1 leo * modification, are permitted provided that the following conditions 10 1.1 leo * are met: 11 1.1 leo * 1. Redistributions of source code must retain the above copyright 12 1.1 leo * notice, this list of conditions and the following disclaimer. 13 1.1 leo * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 leo * notice, this list of conditions and the following disclaimer in the 15 1.1 leo * documentation and/or other materials provided with the distribution. 16 1.26 agc * 3. Neither the name of the University nor the names of its contributors 17 1.26 agc * may be used to endorse or promote products derived from this software 18 1.26 agc * without specific prior written permission. 19 1.26 agc * 20 1.26 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 1.26 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.26 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.26 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 1.26 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.26 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.26 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.26 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.26 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.26 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.26 agc * SUCH DAMAGE. 31 1.26 agc */ 32 1.26 agc 33 1.25 lukem #include <sys/cdefs.h> 34 1.59 rillig __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.59 2024/09/08 09:36:48 rillig Exp $"); 35 1.1 leo 36 1.23 thomas #include "mouse.h" 37 1.23 thomas #include "ite.h" 38 1.23 thomas #include "wskbd.h" 39 1.23 thomas 40 1.1 leo #include <sys/param.h> 41 1.1 leo #include <sys/systm.h> 42 1.1 leo #include <sys/device.h> 43 1.1 leo #include <sys/ioctl.h> 44 1.1 leo #include <sys/tty.h> 45 1.1 leo #include <sys/proc.h> 46 1.1 leo #include <sys/conf.h> 47 1.1 leo #include <sys/file.h> 48 1.1 leo #include <sys/kernel.h> 49 1.9 leo #include <sys/signalvar.h> 50 1.1 leo #include <sys/syslog.h> 51 1.54 tsutsui #include <sys/rndsource.h> 52 1.54 tsutsui 53 1.1 leo #include <dev/cons.h> 54 1.1 leo #include <machine/cpu.h> 55 1.1 leo #include <machine/iomap.h> 56 1.1 leo #include <machine/mfp.h> 57 1.1 leo #include <machine/acia.h> 58 1.1 leo #include <atari/dev/itevar.h> 59 1.1 leo #include <atari/dev/event_var.h> 60 1.1 leo #include <atari/dev/vuid_event.h> 61 1.9 leo #include <atari/dev/ym2149reg.h> 62 1.9 leo #include <atari/dev/kbdreg.h> 63 1.9 leo #include <atari/dev/kbdvar.h> 64 1.15 leo #include <atari/dev/kbdmap.h> 65 1.9 leo #include <atari/dev/msvar.h> 66 1.1 leo 67 1.23 thomas #if NWSKBD>0 68 1.23 thomas #include <dev/wscons/wsconsio.h> 69 1.23 thomas #include <dev/wscons/wskbdvar.h> 70 1.23 thomas #include <dev/wscons/wsksymdef.h> 71 1.23 thomas #include <dev/wscons/wsksymvar.h> 72 1.23 thomas #include <atari/dev/wskbdmap_atari.h> 73 1.23 thomas #endif 74 1.23 thomas 75 1.51 tsutsui /* 76 1.51 tsutsui * The ringbuffer is the interface between the hard and soft interrupt handler. 77 1.51 tsutsui * The hard interrupt runs straight from the MFP interrupt. 78 1.51 tsutsui */ 79 1.51 tsutsui #define KBD_RING_SIZE 256 /* Sz of input ring buffer, must be power of 2 */ 80 1.51 tsutsui #define KBD_RING_MASK 255 /* Modulo mask for above */ 81 1.51 tsutsui 82 1.51 tsutsui struct kbd_softc { 83 1.52 tsutsui int sc_event_mode; /* if 1, collect events, */ 84 1.51 tsutsui /* else pass to ite */ 85 1.52 tsutsui struct evvar sc_events; /* event queue state */ 86 1.52 tsutsui uint8_t sc_soft_cs; /* control-reg. copy */ 87 1.52 tsutsui uint8_t sc_package[20]; /* XXX package being build */ 88 1.52 tsutsui uint8_t sc_pkg_size; /* Size of the package */ 89 1.52 tsutsui uint8_t sc_pkg_idx; /* Running pkg assembly index */ 90 1.52 tsutsui uint8_t sc_pkg_type; /* Type of package */ 91 1.52 tsutsui const uint8_t *sc_sendp; /* Output pointer */ 92 1.52 tsutsui int sc_send_cnt; /* Chars left for output */ 93 1.51 tsutsui #if NWSKBD > 0 94 1.52 tsutsui device_t sc_wskbddev; /* pointer to wskbd for sending strokes */ 95 1.52 tsutsui int sc_pollingmode; /* polling mode on? whatever it is... */ 96 1.51 tsutsui #endif 97 1.52 tsutsui void *sc_sicookie; /* softint(9) cookie */ 98 1.57 tsutsui krndsource_t sc_rndsource; /* rnd(9) entropy */ 99 1.51 tsutsui }; 100 1.51 tsutsui 101 1.23 thomas /* WSKBD */ 102 1.23 thomas /* 103 1.59 rillig * If NWSKBD>0 we try to attach a wskbd device to us. What follows 104 1.23 thomas * is definitions of callback functions and structures that are passed 105 1.23 thomas * to wscons when initializing. 106 1.23 thomas */ 107 1.23 thomas 108 1.23 thomas /* 109 1.23 thomas * Now with wscons this driver exhibits some weird behaviour. 110 1.23 thomas * It may act both as a driver of its own and the md part of the 111 1.23 thomas * wskbd driver. Therefore it can be accessed through /dev/kbd 112 1.23 thomas * and /dev/wskbd0 both. 113 1.23 thomas * 114 1.23 thomas * The data from they keyboard may end up in at least four different 115 1.23 thomas * places: 116 1.23 thomas * - If this driver has been opened (/dev/kbd) and the 117 1.23 thomas * direct mode (TIOCDIRECT) has been set, data goes to 118 1.23 thomas * the process who opened the device. Data will transmit itself 119 1.23 thomas * as described by the firm_event structure. 120 1.23 thomas * - If wskbd support is compiled in and a wskbd driver has been 121 1.23 thomas * attached then the data is sent to it. Wskbd in turn may 122 1.23 thomas * - Send the data in the wscons_event form to a process that 123 1.23 thomas * has opened /dev/wskbd0 124 1.23 thomas * - Feed the data to a virtual terminal. 125 1.23 thomas * - If an ite is present the data may be fed to it. 126 1.23 thomas */ 127 1.5 leo 128 1.37 tsutsui uint8_t kbd_modifier; /* Modifier mask */ 129 1.15 leo 130 1.37 tsutsui static uint8_t kbd_ring[KBD_RING_SIZE]; 131 1.1 leo static volatile u_int kbd_rbput = 0; /* 'put' index */ 132 1.1 leo static u_int kbd_rbget = 0; /* 'get' index */ 133 1.1 leo 134 1.52 tsutsui static struct kbd_softc kbd_softc; /* XXX */ 135 1.1 leo 136 1.6 leo /* {b,c}devsw[] function prototypes */ 137 1.50 tsutsui static dev_type_open(kbdopen); 138 1.50 tsutsui static dev_type_close(kbdclose); 139 1.50 tsutsui static dev_type_read(kbdread); 140 1.50 tsutsui static dev_type_ioctl(kbdioctl); 141 1.50 tsutsui static dev_type_poll(kbdpoll); 142 1.50 tsutsui static dev_type_kqfilter(kbdkqfilter); 143 1.6 leo 144 1.39 tsutsui static void kbdsoft(void *); 145 1.42 tsutsui static void kbdattach(device_t, device_t, void *); 146 1.42 tsutsui static int kbdmatch(device_t, cfdata_t, void *); 147 1.50 tsutsui #if NITE > 0 148 1.37 tsutsui static int kbd_do_modifier(uint8_t); 149 1.23 thomas #endif 150 1.38 tsutsui static int kbd_write_poll(const uint8_t *, int); 151 1.37 tsutsui static void kbd_pkg_start(struct kbd_softc *, uint8_t); 152 1.1 leo 153 1.42 tsutsui CFATTACH_DECL_NEW(kbd, 0, 154 1.21 thorpej kbdmatch, kbdattach, NULL, NULL); 155 1.19 gehenna 156 1.19 gehenna const struct cdevsw kbd_cdevsw = { 157 1.43 dholland .d_open = kbdopen, 158 1.43 dholland .d_close = kbdclose, 159 1.43 dholland .d_read = kbdread, 160 1.43 dholland .d_write = nowrite, 161 1.43 dholland .d_ioctl = kbdioctl, 162 1.43 dholland .d_stop = nostop, 163 1.43 dholland .d_tty = notty, 164 1.43 dholland .d_poll = kbdpoll, 165 1.43 dholland .d_mmap = nommap, 166 1.43 dholland .d_kqfilter = kbdkqfilter, 167 1.45 dholland .d_discard = nodiscard, 168 1.43 dholland .d_flag = 0 169 1.7 thorpej }; 170 1.9 leo 171 1.23 thomas #if NWSKBD>0 172 1.23 thomas /* accessops */ 173 1.23 thomas static int kbd_enable(void *, int); 174 1.23 thomas static void kbd_set_leds(void *, int); 175 1.30 christos static int kbd_ioctl(void *, u_long, void *, int, struct lwp *); 176 1.23 thomas 177 1.23 thomas /* console ops */ 178 1.23 thomas static void kbd_getc(void *, u_int *, int *); 179 1.23 thomas static void kbd_pollc(void *, int); 180 1.23 thomas static void kbd_bell(void *, u_int, u_int, u_int); 181 1.23 thomas 182 1.23 thomas static struct wskbd_accessops kbd_accessops = { 183 1.23 thomas kbd_enable, 184 1.23 thomas kbd_set_leds, 185 1.23 thomas kbd_ioctl 186 1.23 thomas }; 187 1.23 thomas 188 1.23 thomas static struct wskbd_consops kbd_consops = { 189 1.50 tsutsui kbd_getc, 190 1.23 thomas kbd_pollc, 191 1.23 thomas kbd_bell 192 1.23 thomas }; 193 1.23 thomas 194 1.23 thomas /* Pointer to keymaps. */ 195 1.23 thomas static struct wskbd_mapdata kbd_mapdata = { 196 1.50 tsutsui atarikbd_keydesctab, 197 1.23 thomas KB_US 198 1.23 thomas }; 199 1.23 thomas #endif /* WSKBD */ 200 1.23 thomas 201 1.1 leo /*ARGSUSED*/ 202 1.50 tsutsui static int 203 1.42 tsutsui kbdmatch(device_t parent, cfdata_t cf, void *aux) 204 1.1 leo { 205 1.37 tsutsui 206 1.42 tsutsui if (!strcmp((char *)aux, "kbd")) 207 1.37 tsutsui return 1; 208 1.37 tsutsui return 0; 209 1.1 leo } 210 1.1 leo 211 1.1 leo /*ARGSUSED*/ 212 1.1 leo static void 213 1.42 tsutsui kbdattach(device_t parent, device_t self, void *aux) 214 1.1 leo { 215 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 216 1.37 tsutsui int timeout; 217 1.38 tsutsui const uint8_t kbd_rst[] = { 0x80, 0x01 }; 218 1.38 tsutsui const uint8_t kbd_icmd[] = { 0x12, 0x15 }; 219 1.3 leo 220 1.3 leo /* 221 1.3 leo * Disable keyboard interrupts from MFP 222 1.3 leo */ 223 1.3 leo MFP->mf_ierb &= ~IB_AINT; 224 1.3 leo 225 1.3 leo /* 226 1.47 dholland * Reset ACIA and initialize to: 227 1.3 leo * divide by 16, 8 data, 1 stop, no parity, enable RX interrupts 228 1.3 leo */ 229 1.3 leo KBD->ac_cs = A_RESET; 230 1.3 leo delay(100); /* XXX: enough? */ 231 1.52 tsutsui KBD->ac_cs = sc->sc_soft_cs = KBD_INIT | A_RXINT; 232 1.3 leo 233 1.3 leo /* 234 1.3 leo * Clear error conditions 235 1.3 leo */ 236 1.50 tsutsui while ((KBD->ac_cs & (A_IRQ | A_RXRDY)) != 0) 237 1.3 leo timeout = KBD->ac_da; 238 1.3 leo 239 1.3 leo /* 240 1.46 snj * Now send the reset string, and read+ignore its response 241 1.3 leo */ 242 1.53 tsutsui aprint_normal("\n"); 243 1.50 tsutsui if (kbd_write_poll(kbd_rst, 2) == 0) 244 1.53 tsutsui aprint_error_dev(self, "error cannot reset keyboard\n"); 245 1.3 leo for (timeout = 1000; timeout > 0; timeout--) { 246 1.50 tsutsui if ((KBD->ac_cs & (A_IRQ | A_RXRDY)) != 0) { 247 1.3 leo timeout = KBD->ac_da; 248 1.3 leo timeout = 100; 249 1.3 leo } 250 1.3 leo delay(100); 251 1.3 leo } 252 1.4 leo /* 253 1.4 leo * Send init command: disable mice & joysticks 254 1.4 leo */ 255 1.4 leo kbd_write_poll(kbd_icmd, sizeof(kbd_icmd)); 256 1.3 leo 257 1.52 tsutsui sc->sc_sicookie = softint_establish(SOFTINT_SERIAL, kbdsoft, NULL); 258 1.54 tsutsui rnd_attach_source(&sc->sc_rndsource, device_xname(self), 259 1.54 tsutsui RND_TYPE_TTY, RND_FLAG_DEFAULT); 260 1.39 tsutsui 261 1.50 tsutsui #if NWSKBD > 0 262 1.42 tsutsui if (self != NULL) { 263 1.23 thomas /* 264 1.23 thomas * Try to attach the wskbd. 265 1.23 thomas */ 266 1.23 thomas struct wskbddev_attach_args waa; 267 1.23 thomas 268 1.23 thomas /* Maybe should be done before this?... */ 269 1.23 thomas wskbd_cnattach(&kbd_consops, NULL, &kbd_mapdata); 270 1.23 thomas 271 1.23 thomas waa.console = 1; 272 1.23 thomas waa.keymap = &kbd_mapdata; 273 1.23 thomas waa.accessops = &kbd_accessops; 274 1.23 thomas waa.accesscookie = NULL; 275 1.52 tsutsui sc->sc_wskbddev = config_found(self, &waa, wskbddevprint, 276 1.49 thorpej CFARGS_NONE); 277 1.23 thomas 278 1.52 tsutsui sc->sc_pollingmode = 0; 279 1.23 thomas 280 1.23 thomas kbdenable(); 281 1.23 thomas } 282 1.23 thomas #endif /* WSKBD */ 283 1.1 leo } 284 1.1 leo 285 1.1 leo void 286 1.36 cegger kbdenable(void) 287 1.1 leo { 288 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 289 1.50 tsutsui int s; 290 1.1 leo 291 1.1 leo s = spltty(); 292 1.3 leo 293 1.1 leo /* 294 1.3 leo * Clear error conditions... 295 1.1 leo */ 296 1.50 tsutsui while ((KBD->ac_cs & (A_IRQ | A_RXRDY)) != 0) 297 1.50 tsutsui (void)KBD->ac_da; 298 1.1 leo /* 299 1.1 leo * Enable interrupts from MFP 300 1.1 leo */ 301 1.50 tsutsui MFP->mf_iprb = (uint8_t)~IB_AINT; 302 1.1 leo MFP->mf_ierb |= IB_AINT; 303 1.1 leo MFP->mf_imrb |= IB_AINT; 304 1.1 leo 305 1.52 tsutsui sc->sc_event_mode = 0; 306 1.52 tsutsui sc->sc_events.ev_io = 0; 307 1.52 tsutsui sc->sc_pkg_size = 0; 308 1.1 leo splx(s); 309 1.1 leo } 310 1.1 leo 311 1.50 tsutsui static int 312 1.50 tsutsui kbdopen(dev_t dev, int flags, int mode, struct lwp *l) 313 1.1 leo { 314 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 315 1.37 tsutsui 316 1.52 tsutsui if (sc->sc_events.ev_io) 317 1.1 leo return EBUSY; 318 1.1 leo 319 1.52 tsutsui sc->sc_events.ev_io = l->l_proc; 320 1.52 tsutsui ev_init(&sc->sc_events); 321 1.37 tsutsui return 0; 322 1.1 leo } 323 1.1 leo 324 1.50 tsutsui static int 325 1.29 christos kbdclose(dev_t dev, int flags, int mode, struct lwp *l) 326 1.1 leo { 327 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 328 1.37 tsutsui 329 1.1 leo /* Turn off event mode, dump the queue */ 330 1.52 tsutsui sc->sc_event_mode = 0; 331 1.52 tsutsui ev_fini(&sc->sc_events); 332 1.52 tsutsui sc->sc_events.ev_io = NULL; 333 1.37 tsutsui return 0; 334 1.1 leo } 335 1.1 leo 336 1.50 tsutsui static int 337 1.1 leo kbdread(dev_t dev, struct uio *uio, int flags) 338 1.1 leo { 339 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 340 1.37 tsutsui 341 1.52 tsutsui return ev_read(&sc->sc_events, uio, flags); 342 1.1 leo } 343 1.1 leo 344 1.50 tsutsui static int 345 1.52 tsutsui kbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 346 1.1 leo { 347 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 348 1.52 tsutsui struct kbdbell *kb; 349 1.1 leo 350 1.1 leo switch (cmd) { 351 1.50 tsutsui case KIOCTRANS: 352 1.50 tsutsui if (*(int *)data == TR_UNTRANS_EVENT) 353 1.50 tsutsui return 0; 354 1.50 tsutsui break; 355 1.50 tsutsui 356 1.50 tsutsui case KIOCGTRANS: 357 1.50 tsutsui /* 358 1.50 tsutsui * Get translation mode 359 1.50 tsutsui */ 360 1.50 tsutsui *(int *)data = TR_UNTRANS_EVENT; 361 1.50 tsutsui return 0; 362 1.50 tsutsui 363 1.50 tsutsui case KIOCSDIRECT: 364 1.52 tsutsui sc->sc_event_mode = *(int *)data; 365 1.50 tsutsui return 0; 366 1.1 leo 367 1.50 tsutsui case KIOCRINGBELL: 368 1.50 tsutsui kb = (struct kbdbell *)data; 369 1.50 tsutsui if (kb) 370 1.50 tsutsui kbd_bell_sparms(kb->volume, kb->pitch, 371 1.50 tsutsui kb->duration); 372 1.50 tsutsui kbdbell(); 373 1.50 tsutsui return 0; 374 1.1 leo 375 1.50 tsutsui case FIONBIO: /* we will remove this someday (soon???) */ 376 1.50 tsutsui return 0; 377 1.1 leo 378 1.50 tsutsui case FIOASYNC: 379 1.52 tsutsui sc->sc_events.ev_async = *(int *)data != 0; 380 1.50 tsutsui return 0; 381 1.1 leo 382 1.50 tsutsui case FIOSETOWN: 383 1.52 tsutsui if (-*(int *)data != sc->sc_events.ev_io->p_pgid && 384 1.52 tsutsui *(int *)data != sc->sc_events.ev_io->p_pid) 385 1.50 tsutsui return EPERM; 386 1.50 tsutsui return 0; 387 1.1 leo 388 1.50 tsutsui case TIOCSPGRP: 389 1.52 tsutsui if (*(int *)data != sc->sc_events.ev_io->p_pgid) 390 1.50 tsutsui return EPERM; 391 1.50 tsutsui return 0; 392 1.1 leo 393 1.50 tsutsui default: 394 1.50 tsutsui return ENOTTY; 395 1.1 leo } 396 1.1 leo 397 1.1 leo /* 398 1.1 leo * We identified the ioctl, but we do not handle it. 399 1.1 leo */ 400 1.1 leo return EOPNOTSUPP; /* misuse, but what the heck */ 401 1.1 leo } 402 1.1 leo 403 1.50 tsutsui static int 404 1.50 tsutsui kbdpoll(dev_t dev, int events, struct lwp *l) 405 1.1 leo { 406 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 407 1.37 tsutsui 408 1.52 tsutsui return ev_poll(&sc->sc_events, events, l); 409 1.22 jdolecek } 410 1.22 jdolecek 411 1.50 tsutsui static int 412 1.22 jdolecek kbdkqfilter(dev_t dev, struct knote *kn) 413 1.22 jdolecek { 414 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 415 1.22 jdolecek 416 1.52 tsutsui return ev_kqfilter(&sc->sc_events, kn); 417 1.1 leo } 418 1.1 leo 419 1.1 leo /* 420 1.3 leo * Keyboard interrupt handler called straight from MFP at spl6. 421 1.1 leo */ 422 1.6 leo void 423 1.35 dsl kbdintr(int sr) 424 1.50 tsutsui /* sr: sr at time of interrupt */ 425 1.1 leo { 426 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 427 1.56 martin uint8_t stat, code = 0 /* XXX gcc */; 428 1.54 tsutsui uint32_t rndstat; 429 1.50 tsutsui bool got_char = false; 430 1.1 leo 431 1.1 leo /* 432 1.1 leo * There may be multiple keys available. Read them all. 433 1.1 leo */ 434 1.54 tsutsui stat = KBD->ac_cs; 435 1.54 tsutsui rndstat = stat; 436 1.54 tsutsui while ((stat & (A_RXRDY | A_OE | A_PE)) != 0) { 437 1.50 tsutsui got_char = true; 438 1.55 tsutsui if ((KBD->ac_cs & (A_OE | A_PE)) == 0) { 439 1.55 tsutsui code = KBD->ac_da; 440 1.54 tsutsui kbd_ring[kbd_rbput++ & KBD_RING_MASK] = code; 441 1.54 tsutsui } else { 442 1.50 tsutsui /* Silently ignore errors */ 443 1.55 tsutsui code = KBD->ac_da; 444 1.1 leo } 445 1.54 tsutsui stat = KBD->ac_cs; 446 1.1 leo } 447 1.3 leo 448 1.3 leo /* 449 1.3 leo * If characters are waiting for transmit, send them. 450 1.3 leo */ 451 1.52 tsutsui if ((sc->sc_soft_cs & A_TXINT) != 0 && 452 1.50 tsutsui (KBD->ac_cs & A_TXRDY) != 0) { 453 1.52 tsutsui if (sc->sc_sendp != NULL) 454 1.52 tsutsui KBD->ac_da = *sc->sc_sendp++; 455 1.52 tsutsui if (--sc->sc_send_cnt <= 0) { 456 1.3 leo /* 457 1.3 leo * The total package has been transmitted, 458 1.3 leo * wakeup anyone waiting for it. 459 1.3 leo */ 460 1.52 tsutsui KBD->ac_cs = (sc->sc_soft_cs &= ~A_TXINT); 461 1.52 tsutsui sc->sc_sendp = NULL; 462 1.52 tsutsui sc->sc_send_cnt = 0; 463 1.52 tsutsui wakeup((void *)&sc->sc_send_cnt); 464 1.3 leo } 465 1.3 leo } 466 1.3 leo 467 1.3 leo /* 468 1.3 leo * Activate software-level to handle possible input. 469 1.54 tsutsui * Also add status and data to the rnd(9) pool. 470 1.3 leo */ 471 1.54 tsutsui if (got_char) { 472 1.52 tsutsui softint_schedule(sc->sc_sicookie); 473 1.54 tsutsui rnd_add_uint32(&sc->sc_rndsource, (rndstat << 8) | code); 474 1.54 tsutsui } 475 1.1 leo } 476 1.1 leo 477 1.1 leo /* 478 1.1 leo * Keyboard soft interrupt handler 479 1.1 leo */ 480 1.39 tsutsui static void 481 1.39 tsutsui kbdsoft(void *junk1) 482 1.1 leo { 483 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 484 1.37 tsutsui int s; 485 1.37 tsutsui uint8_t code; 486 1.37 tsutsui struct firm_event *fe; 487 1.37 tsutsui int put, get, n; 488 1.1 leo 489 1.50 tsutsui get = kbd_rbget; 490 1.1 leo 491 1.3 leo for (;;) { 492 1.1 leo n = kbd_rbput; 493 1.3 leo if (get == n) /* We're done */ 494 1.1 leo break; 495 1.1 leo n -= get; 496 1.3 leo if (n > KBD_RING_SIZE) { /* Ring buffer overflow */ 497 1.1 leo get += n - KBD_RING_SIZE; 498 1.1 leo n = KBD_RING_SIZE; 499 1.1 leo } 500 1.3 leo while (--n >= 0) { 501 1.1 leo code = kbd_ring[get++ & KBD_RING_MASK]; 502 1.1 leo 503 1.1 leo /* 504 1.3 leo * If collecting a package, stuff it in and 505 1.3 leo * continue. 506 1.3 leo */ 507 1.52 tsutsui if (sc->sc_pkg_size && 508 1.52 tsutsui (sc->sc_pkg_idx < sc->sc_pkg_size)) { 509 1.52 tsutsui sc->sc_package[sc->sc_pkg_idx++] = code; 510 1.52 tsutsui if (sc->sc_pkg_idx == sc->sc_pkg_size) { 511 1.50 tsutsui /* 512 1.50 tsutsui * Package is complete. 513 1.50 tsutsui */ 514 1.52 tsutsui switch (sc->sc_pkg_type) { 515 1.5 leo #if NMOUSE > 0 516 1.50 tsutsui case KBD_AMS_PKG: 517 1.50 tsutsui case KBD_RMS_PKG: 518 1.50 tsutsui case KBD_JOY1_PKG: 519 1.50 tsutsui mouse_soft( 520 1.52 tsutsui (REL_MOUSE *)sc->sc_package, 521 1.52 tsutsui sc->sc_pkg_size, 522 1.52 tsutsui sc->sc_pkg_type); 523 1.5 leo #endif /* NMOUSE */ 524 1.50 tsutsui } 525 1.52 tsutsui sc->sc_pkg_size = 0; 526 1.3 leo } 527 1.50 tsutsui continue; 528 1.3 leo } 529 1.3 leo /* 530 1.3 leo * If this is a package header, init pkg. handling. 531 1.3 leo */ 532 1.15 leo if (!KBD_IS_KEY(code)) { 533 1.52 tsutsui kbd_pkg_start(sc, code); 534 1.3 leo continue; 535 1.3 leo } 536 1.50 tsutsui #if NWSKBD > 0 537 1.23 thomas /* 538 1.37 tsutsui * If we have attached a wskbd and not in polling mode 539 1.37 tsutsui * and nobody has opened us directly, then send the 540 1.37 tsutsui * keystroke to the wskbd. 541 1.23 thomas */ 542 1.23 thomas 543 1.52 tsutsui if (sc->sc_pollingmode == 0 && 544 1.52 tsutsui sc->sc_wskbddev != NULL && 545 1.52 tsutsui sc->sc_event_mode == 0) { 546 1.52 tsutsui wskbd_input(sc->sc_wskbddev, 547 1.50 tsutsui KBD_RELEASED(code) ? 548 1.50 tsutsui WSCONS_EVENT_KEY_UP : 549 1.50 tsutsui WSCONS_EVENT_KEY_DOWN, 550 1.50 tsutsui KBD_SCANCODE(code)); 551 1.23 thomas continue; 552 1.23 thomas } 553 1.23 thomas #endif /* NWSKBD */ 554 1.50 tsutsui #if NITE > 0 555 1.52 tsutsui if (kbd_do_modifier(code) && !sc->sc_event_mode) 556 1.15 leo continue; 557 1.23 thomas #endif 558 1.50 tsutsui 559 1.3 leo /* 560 1.1 leo * if not in event mode, deliver straight to ite to 561 1.1 leo * process key stroke 562 1.1 leo */ 563 1.52 tsutsui if (!sc->sc_event_mode) { 564 1.1 leo /* Gets to spltty() by itself */ 565 1.50 tsutsui #if NITE > 0 566 1.1 leo ite_filter(code, ITEFILT_TTY); 567 1.23 thomas #endif 568 1.1 leo continue; 569 1.1 leo } 570 1.1 leo 571 1.1 leo /* 572 1.1 leo * Keyboard is generating events. Turn this keystroke 573 1.1 leo * into an event and put it in the queue. If the queue 574 1.1 leo * is full, the keystroke is lost (sorry!). 575 1.1 leo */ 576 1.1 leo s = spltty(); 577 1.52 tsutsui put = sc->sc_events.ev_put; 578 1.52 tsutsui fe = &sc->sc_events.ev_q[put]; 579 1.1 leo put = (put + 1) % EV_QSIZE; 580 1.52 tsutsui if (put == sc->sc_events.ev_get) { 581 1.1 leo log(LOG_WARNING, 582 1.37 tsutsui "keyboard event queue overflow\n"); 583 1.1 leo splx(s); 584 1.1 leo continue; 585 1.1 leo } 586 1.15 leo fe->id = KBD_SCANCODE(code); 587 1.15 leo fe->value = KBD_RELEASED(code) ? VKEY_UP : VKEY_DOWN; 588 1.32 tsutsui firm_gettime(fe); 589 1.52 tsutsui sc->sc_events.ev_put = put; 590 1.52 tsutsui EV_WAKEUP(&sc->sc_events); 591 1.1 leo splx(s); 592 1.1 leo } 593 1.1 leo kbd_rbget = get; 594 1.1 leo } 595 1.1 leo } 596 1.1 leo 597 1.52 tsutsui static uint8_t sound[] = { 598 1.37 tsutsui 0xA8, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0x00, 599 1.37 tsutsui 0xF8, 0x10, 0x10, 0x10, 0x00, 0x20, 0x03 600 1.1 leo }; 601 1.1 leo 602 1.6 leo void 603 1.36 cegger kbdbell(void) 604 1.1 leo { 605 1.52 tsutsui int i, s; 606 1.1 leo 607 1.52 tsutsui s = splhigh(); 608 1.3 leo for (i = 0; i < sizeof(sound); i++) { 609 1.8 leo YM2149->sd_selr = i; 610 1.8 leo YM2149->sd_wdat = sound[i]; 611 1.3 leo } 612 1.52 tsutsui splx(s); 613 1.16 leo } 614 1.16 leo 615 1.16 leo 616 1.16 leo /* 617 1.16 leo * Set the parameters of the 'default' beep. 618 1.16 leo */ 619 1.16 leo 620 1.16 leo #define KBDBELLCLOCK 125000 /* 2MHz / 16 */ 621 1.16 leo #define KBDBELLDURATION 128 /* 256 / 2MHz */ 622 1.16 leo 623 1.16 leo void 624 1.35 dsl kbd_bell_gparms(u_int *volume, u_int *pitch, u_int *duration) 625 1.16 leo { 626 1.52 tsutsui u_int tmp; 627 1.16 leo 628 1.16 leo tmp = sound[11] | (sound[12] << 8); 629 1.16 leo *duration = (tmp * KBDBELLDURATION) / 1000; 630 1.16 leo 631 1.16 leo tmp = sound[0] | (sound[1] << 8); 632 1.16 leo *pitch = KBDBELLCLOCK / tmp; 633 1.50 tsutsui 634 1.16 leo *volume = 0; 635 1.16 leo } 636 1.16 leo 637 1.16 leo void 638 1.35 dsl kbd_bell_sparms(u_int volume, u_int pitch, u_int duration) 639 1.16 leo { 640 1.52 tsutsui u_int f, t; 641 1.16 leo 642 1.16 leo f = pitch > 10 ? pitch : 10; /* minimum pitch */ 643 1.16 leo if (f > 20000) 644 1.16 leo f = 20000; /* maximum pitch */ 645 1.16 leo 646 1.16 leo f = KBDBELLCLOCK / f; 647 1.16 leo 648 1.16 leo t = (duration * 1000) / KBDBELLDURATION; 649 1.16 leo 650 1.16 leo sound[ 0] = f & 0xff; 651 1.16 leo sound[ 1] = (f >> 8) & 0xf; 652 1.16 leo f -= 1; 653 1.16 leo sound[ 2] = f & 0xff; 654 1.16 leo sound[ 3] = (f >> 8) & 0xf; 655 1.16 leo f += 2; 656 1.16 leo sound[ 4] = f & 0xff; 657 1.16 leo sound[ 5] = (f >> 8) & 0xf; 658 1.50 tsutsui 659 1.16 leo sound[11] = t & 0xff; 660 1.16 leo sound[12] = (t >> 8) & 0xff; 661 1.16 leo 662 1.16 leo sound[13] = 0x03; 663 1.1 leo } 664 1.1 leo 665 1.1 leo int 666 1.36 cegger kbdgetcn(void) 667 1.1 leo { 668 1.37 tsutsui uint8_t code; 669 1.37 tsutsui int s = spltty(); 670 1.37 tsutsui int ints_active; 671 1.1 leo 672 1.4 leo ints_active = 0; 673 1.50 tsutsui if ((MFP->mf_imrb & IB_AINT) != 0) { 674 1.4 leo ints_active = 1; 675 1.4 leo MFP->mf_imrb &= ~IB_AINT; 676 1.4 leo } 677 1.3 leo for (;;) { 678 1.52 tsutsui while (!((KBD->ac_cs & (A_IRQ | A_RXRDY)) == (A_IRQ | A_RXRDY))) 679 1.50 tsutsui continue; /* Wait for key */ 680 1.50 tsutsui if ((KBD->ac_cs & (A_OE | A_PE)) != 0) { 681 1.3 leo code = KBD->ac_da; /* Silently ignore errors */ 682 1.3 leo continue; 683 1.3 leo } 684 1.15 leo code = KBD->ac_da; 685 1.23 thomas #if NITE>0 686 1.15 leo if (!kbd_do_modifier(code)) 687 1.23 thomas #endif 688 1.15 leo break; 689 1.3 leo } 690 1.1 leo 691 1.4 leo if (ints_active) { 692 1.37 tsutsui MFP->mf_iprb = (uint8_t)~IB_AINT; 693 1.4 leo MFP->mf_imrb |= IB_AINT; 694 1.4 leo } 695 1.1 leo 696 1.37 tsutsui splx(s); 697 1.1 leo return code; 698 1.3 leo } 699 1.3 leo 700 1.3 leo /* 701 1.3 leo * Write a command to the keyboard in 'polled' mode. 702 1.3 leo */ 703 1.3 leo static int 704 1.38 tsutsui kbd_write_poll(const uint8_t *cmd, int len) 705 1.3 leo { 706 1.50 tsutsui int timeout; 707 1.3 leo 708 1.3 leo while (len-- > 0) { 709 1.3 leo KBD->ac_da = *cmd++; 710 1.50 tsutsui for (timeout = 100; (KBD->ac_cs & A_TXRDY) == 0; timeout--) 711 1.3 leo delay(10); 712 1.37 tsutsui if ((KBD->ac_cs & A_TXRDY) == 0) 713 1.37 tsutsui return 0; 714 1.3 leo } 715 1.37 tsutsui return 1; 716 1.3 leo } 717 1.3 leo 718 1.3 leo /* 719 1.3 leo * Write a command to the keyboard. Return when command is send. 720 1.3 leo */ 721 1.4 leo void 722 1.38 tsutsui kbd_write(const uint8_t *cmd, int len) 723 1.3 leo { 724 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 725 1.52 tsutsui int s; 726 1.3 leo 727 1.3 leo /* 728 1.3 leo * Get to splhigh, 'real' interrupts arrive at spl6! 729 1.3 leo */ 730 1.50 tsutsui s = splhigh(); 731 1.3 leo 732 1.3 leo /* 733 1.58 andvar * Make sure any previous write has ended... 734 1.3 leo */ 735 1.52 tsutsui while (sc->sc_sendp != NULL) 736 1.52 tsutsui tsleep((void *)&sc->sc_sendp, TTOPRI, "kbd_write1", 0); 737 1.3 leo 738 1.3 leo /* 739 1.3 leo * If the KBD-acia is not currently busy, send the first 740 1.3 leo * character now. 741 1.3 leo */ 742 1.52 tsutsui KBD->ac_cs = (sc->sc_soft_cs |= A_TXINT); 743 1.52 tsutsui if ((KBD->ac_cs & A_TXRDY) != 0) { 744 1.3 leo KBD->ac_da = *cmd++; 745 1.3 leo len--; 746 1.3 leo } 747 1.3 leo 748 1.3 leo /* 749 1.3 leo * If we're not yet done, wait until all characters are send. 750 1.3 leo */ 751 1.3 leo if (len > 0) { 752 1.52 tsutsui sc->sc_sendp = cmd; 753 1.52 tsutsui sc->sc_send_cnt = len; 754 1.52 tsutsui tsleep((void *)&sc->sc_send_cnt, TTOPRI, "kbd_write2", 0); 755 1.3 leo } 756 1.50 tsutsui splx(s); 757 1.3 leo 758 1.3 leo /* 759 1.3 leo * Wakeup all procs waiting for us. 760 1.3 leo */ 761 1.52 tsutsui wakeup((void *)&sc->sc_sendp); 762 1.3 leo } 763 1.3 leo 764 1.3 leo /* 765 1.3 leo * Setup softc-fields to assemble a keyboard package. 766 1.3 leo */ 767 1.3 leo static void 768 1.52 tsutsui kbd_pkg_start(struct kbd_softc *sc, uint8_t msg_start) 769 1.3 leo { 770 1.37 tsutsui 771 1.52 tsutsui sc->sc_pkg_idx = 1; 772 1.52 tsutsui sc->sc_package[0] = msg_start; 773 1.3 leo switch (msg_start) { 774 1.50 tsutsui case 0xf6: 775 1.52 tsutsui sc->sc_pkg_type = KBD_MEM_PKG; 776 1.52 tsutsui sc->sc_pkg_size = 8; 777 1.50 tsutsui break; 778 1.50 tsutsui case 0xf7: 779 1.52 tsutsui sc->sc_pkg_type = KBD_AMS_PKG; 780 1.52 tsutsui sc->sc_pkg_size = 6; 781 1.50 tsutsui break; 782 1.50 tsutsui case 0xf8: 783 1.50 tsutsui case 0xf9: 784 1.50 tsutsui case 0xfa: 785 1.50 tsutsui case 0xfb: 786 1.52 tsutsui sc->sc_pkg_type = KBD_RMS_PKG; 787 1.52 tsutsui sc->sc_pkg_size = 3; 788 1.50 tsutsui break; 789 1.50 tsutsui case 0xfc: 790 1.52 tsutsui sc->sc_pkg_type = KBD_CLK_PKG; 791 1.52 tsutsui sc->sc_pkg_size = 7; 792 1.50 tsutsui break; 793 1.50 tsutsui case 0xfe: 794 1.52 tsutsui sc->sc_pkg_type = KBD_JOY0_PKG; 795 1.52 tsutsui sc->sc_pkg_size = 2; 796 1.50 tsutsui break; 797 1.50 tsutsui case 0xff: 798 1.52 tsutsui sc->sc_pkg_type = KBD_JOY1_PKG; 799 1.52 tsutsui sc->sc_pkg_size = 2; 800 1.50 tsutsui break; 801 1.50 tsutsui default: 802 1.50 tsutsui printf("kbd: Unknown packet 0x%x\n", msg_start); 803 1.50 tsutsui break; 804 1.3 leo } 805 1.1 leo } 806 1.15 leo 807 1.37 tsutsui #if NITE > 0 808 1.15 leo /* 809 1.15 leo * Modifier processing 810 1.15 leo */ 811 1.15 leo static int 812 1.37 tsutsui kbd_do_modifier(uint8_t code) 813 1.15 leo { 814 1.37 tsutsui uint8_t up, mask; 815 1.15 leo 816 1.15 leo up = KBD_RELEASED(code); 817 1.15 leo mask = 0; 818 1.15 leo 819 1.37 tsutsui switch (KBD_SCANCODE(code)) { 820 1.50 tsutsui case KBD_LEFT_SHIFT: 821 1.50 tsutsui mask = KBD_MOD_LSHIFT; 822 1.50 tsutsui break; 823 1.50 tsutsui case KBD_RIGHT_SHIFT: 824 1.50 tsutsui mask = KBD_MOD_RSHIFT; 825 1.50 tsutsui break; 826 1.50 tsutsui case KBD_CTRL: 827 1.50 tsutsui mask = KBD_MOD_CTRL; 828 1.50 tsutsui break; 829 1.50 tsutsui case KBD_ALT: 830 1.50 tsutsui mask = KBD_MOD_ALT; 831 1.50 tsutsui break; 832 1.50 tsutsui case KBD_CAPS_LOCK: 833 1.50 tsutsui /* CAPSLOCK is a toggle */ 834 1.50 tsutsui if (!up) 835 1.50 tsutsui kbd_modifier ^= KBD_MOD_CAPS; 836 1.50 tsutsui return 1; 837 1.15 leo } 838 1.37 tsutsui if (mask) { 839 1.41 tsutsui if (up) 840 1.15 leo kbd_modifier &= ~mask; 841 1.15 leo else 842 1.15 leo kbd_modifier |= mask; 843 1.15 leo return 1; 844 1.15 leo } 845 1.15 leo return 0; 846 1.50 tsutsui } 847 1.23 thomas #endif 848 1.23 thomas 849 1.50 tsutsui #if NWSKBD > 0 850 1.23 thomas /* 851 1.23 thomas * These are the callback functions that are passed to wscons. 852 1.23 thomas * They really don't do anything worth noting, just call the 853 1.23 thomas * other functions above. 854 1.23 thomas */ 855 1.23 thomas 856 1.23 thomas static int 857 1.23 thomas kbd_enable(void *c, int on) 858 1.23 thomas { 859 1.37 tsutsui 860 1.50 tsutsui /* Wonder what this is supposed to do... */ 861 1.23 thomas return 0; 862 1.23 thomas } 863 1.23 thomas 864 1.23 thomas static void 865 1.23 thomas kbd_set_leds(void *c, int leds) 866 1.23 thomas { 867 1.37 tsutsui 868 1.50 tsutsui /* we can not set the leds */ 869 1.23 thomas } 870 1.23 thomas 871 1.23 thomas static int 872 1.40 abs kbd_ioctl(void *c, u_long cmd, void *data, int flag, struct lwp *p) 873 1.23 thomas { 874 1.23 thomas struct wskbd_bell_data *kd; 875 1.23 thomas 876 1.37 tsutsui switch (cmd) { 877 1.23 thomas case WSKBDIO_COMPLEXBELL: 878 1.23 thomas kd = (struct wskbd_bell_data *)data; 879 1.23 thomas kbd_bell(0, kd->pitch, kd->period, kd->volume); 880 1.23 thomas return 0; 881 1.23 thomas case WSKBDIO_SETLEDS: 882 1.23 thomas return 0; 883 1.23 thomas case WSKBDIO_GETLEDS: 884 1.37 tsutsui *(int *)data = 0; 885 1.23 thomas return 0; 886 1.23 thomas case WSKBDIO_GTYPE: 887 1.37 tsutsui *(u_int *)data = WSKBD_TYPE_ATARI; 888 1.23 thomas return 0; 889 1.23 thomas } 890 1.23 thomas 891 1.23 thomas /* 892 1.23 thomas * We are supposed to return EPASSTHROUGH to wscons if we didn't 893 1.23 thomas * understand. 894 1.23 thomas */ 895 1.37 tsutsui return EPASSTHROUGH; 896 1.23 thomas } 897 1.23 thomas 898 1.23 thomas static void 899 1.23 thomas kbd_getc(void *c, u_int *type, int *data) 900 1.23 thomas { 901 1.23 thomas int key; 902 1.52 tsutsui 903 1.23 thomas key = kbdgetcn(); 904 1.23 thomas 905 1.23 thomas *data = KBD_SCANCODE(key); 906 1.23 thomas *type = KBD_RELEASED(key) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 907 1.23 thomas } 908 1.23 thomas 909 1.23 thomas static void 910 1.23 thomas kbd_pollc(void *c, int on) 911 1.23 thomas { 912 1.52 tsutsui struct kbd_softc *sc = &kbd_softc; 913 1.37 tsutsui 914 1.52 tsutsui sc->sc_pollingmode = on; 915 1.23 thomas } 916 1.23 thomas 917 1.23 thomas static void 918 1.23 thomas kbd_bell(void *v, u_int pitch, u_int duration, u_int volume) 919 1.23 thomas { 920 1.37 tsutsui 921 1.50 tsutsui kbd_bell_sparms(volume, pitch, duration); 922 1.23 thomas kbdbell(); 923 1.23 thomas } 924 1.23 thomas #endif /* NWSKBD */ 925