1 /* $NetBSD: kbd.c,v 1.43 2022/06/25 00:58:36 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.43 2022/06/25 00:58:36 tsutsui Exp $"); 34 35 #include "ite.h" 36 #include "bell.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/ioctl.h> 42 #include <sys/tty.h> 43 #include <sys/proc.h> 44 #include <sys/conf.h> 45 #include <sys/file.h> 46 #include <sys/uio.h> 47 #include <sys/kernel.h> 48 #include <sys/syslog.h> 49 #include <sys/signalvar.h> 50 #include <sys/cpu.h> 51 #include <sys/bus.h> 52 #include <sys/intr.h> 53 #include <sys/mutex.h> 54 #include <sys/rndsource.h> 55 56 #include <arch/x68k/dev/intiovar.h> 57 #include <arch/x68k/dev/mfp.h> 58 #include <arch/x68k/dev/itevar.h> 59 60 /* for sun-like event mode, if you go thru /dev/kbd. */ 61 #include <arch/x68k/dev/event_var.h> 62 63 #include <machine/kbio.h> 64 #include <machine/kbd.h> 65 #include <machine/vuid_event.h> 66 67 #include "ioconf.h" 68 69 struct kbd_softc { 70 device_t sc_dev; 71 int sc_event_mode; /* if true, collect events, else pass to ite */ 72 struct evvar sc_events; /* event queue state */ 73 void *sc_softintr_cookie; 74 kmutex_t sc_lock; 75 krndsource_t sc_rndsource; 76 }; 77 78 void kbdenable(int); 79 void kbd_setLED(void); 80 #if NITE > 0 81 int kbdcngetc(void); 82 #endif 83 84 static int kbdintr(void *); 85 static void kbdsoftint(void *); 86 static void kbd_bell(int); 87 static int kbd_send_command(int); 88 89 static int kbdmatch(device_t, cfdata_t, void *); 90 static void kbdattach(device_t, device_t, void *); 91 92 CFATTACH_DECL_NEW(kbd, sizeof(struct kbd_softc), 93 kbdmatch, kbdattach, NULL, NULL); 94 95 static int kbd_attached; 96 97 static dev_type_open(kbdopen); 98 static dev_type_close(kbdclose); 99 static dev_type_read(kbdread); 100 static dev_type_ioctl(kbdioctl); 101 static dev_type_poll(kbdpoll); 102 static dev_type_kqfilter(kbdkqfilter); 103 104 const struct cdevsw kbd_cdevsw = { 105 .d_open = kbdopen, 106 .d_close = kbdclose, 107 .d_read = kbdread, 108 .d_write = nowrite, 109 .d_ioctl = kbdioctl, 110 .d_stop = nostop, 111 .d_tty = notty, 112 .d_poll = kbdpoll, 113 .d_mmap = nommap, 114 .d_kqfilter = kbdkqfilter, 115 .d_discard = nodiscard, 116 .d_flag = 0 117 }; 118 119 static int 120 kbdmatch(device_t parent, cfdata_t cf, void *aux) 121 { 122 123 if (strcmp(aux, "kbd") != 0) 124 return (0); 125 if (kbd_attached) 126 return (0); 127 128 return (1); 129 } 130 131 static void 132 kbdattach(device_t parent, device_t self, void *aux) 133 { 134 struct kbd_softc *sc = device_private(self); 135 struct mfp_softc *mfp = device_private(parent); 136 137 kbd_attached = 1; 138 sc->sc_dev = self; 139 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH); 140 141 /* MFP interrupt #12 is for USART receive buffer full */ 142 intio_intr_establish(mfp->sc_intr + 12, "kbd", kbdintr, sc); 143 sc->sc_softintr_cookie = softint_establish(SOFTINT_SERIAL, 144 kbdsoftint, sc); 145 146 rnd_attach_source(&sc->sc_rndsource, device_xname(self), 147 RND_TYPE_TTY, RND_FLAG_DEFAULT); 148 149 kbdenable(1); 150 sc->sc_event_mode = 0; 151 sc->sc_events.ev_io = 0; 152 153 aprint_normal("\n"); 154 } 155 156 157 /* definitions for x68k keyboard encoding. */ 158 #define KEY_CODE(c) ((c) & 0x7f) 159 #define KEY_UP(c) ((c) & 0x80) 160 161 void 162 kbdenable(int mode) /* 1: interrupt, 0: poll */ 163 { 164 165 intio_set_sysport_keyctrl(8); 166 mfp_bit_clear_iera(MFP_INTR_RCV_FULL | MFP_INTR_TIMER_B); 167 mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP); 168 mfp_set_tbdr(13); /* Timer B interrupt interval */ 169 mfp_set_tbcr(1); /* 1/4 delay mode */ 170 mfp_set_ucr(MFP_UCR_CLKX16 | MFP_UCR_RW_8 | MFP_UCR_ONESB); 171 mfp_set_rsr(MFP_RSR_RE); /* USART receive enable */ 172 mfp_set_tsr(MFP_TSR_TE); /* USART transmit enable */ 173 174 if (mode) { 175 mfp_bit_set_iera(MFP_INTR_RCV_FULL); 176 /* 177 * Perform null read in case that an input byte is in the 178 * receiver buffer, which prevents further interrupts. 179 * We could save the input, but probably not so valuable. 180 */ 181 (void) mfp_get_udr(); 182 } 183 184 kbdled = 0; /* all keyboard LED turn off. */ 185 kbd_setLED(); 186 187 if (!(intio_get_sysport_keyctrl() & 8)) 188 aprint_normal(" (no connected keyboard)"); 189 } 190 191 static int 192 kbdopen(dev_t dev, int flags, int mode, struct lwp *l) 193 { 194 struct kbd_softc *k; 195 196 k = device_lookup_private(&kbd_cd, minor(dev)); 197 if (k == NULL) 198 return (ENXIO); 199 200 if (k->sc_events.ev_io) 201 return (EBUSY); 202 k->sc_events.ev_io = l->l_proc; 203 ev_init(&k->sc_events, device_xname(k->sc_dev), &k->sc_lock); 204 205 return (0); 206 } 207 208 static int 209 kbdclose(dev_t dev, int flags, int mode, struct lwp *l) 210 { 211 struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev)); 212 213 /* Turn off event mode, dump the queue */ 214 k->sc_event_mode = 0; 215 ev_fini(&k->sc_events); 216 k->sc_events.ev_io = NULL; 217 218 return (0); 219 } 220 221 222 static int 223 kbdread(dev_t dev, struct uio *uio, int flags) 224 { 225 struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev)); 226 227 return ev_read(&k->sc_events, uio, flags); 228 } 229 230 #if NBELL > 0 231 struct bell_info; 232 int opm_bell_setup(struct bell_info *); 233 void opm_bell_on(void); 234 void opm_bell_off(void); 235 #endif 236 237 static int 238 kbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 239 { 240 struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev)); 241 int cmd_data; 242 243 switch (cmd) { 244 case KIOCTRANS: 245 if (*(int *)data == TR_UNTRANS_EVENT) 246 return (0); 247 break; 248 249 case KIOCGTRANS: 250 /* 251 * Get translation mode 252 */ 253 *(int *)data = TR_UNTRANS_EVENT; 254 return (0); 255 256 case KIOCSDIRECT: 257 k->sc_event_mode = *(int *)data; 258 return (0); 259 260 case KIOCCMD: 261 cmd_data = *(int *)data; 262 return kbd_send_command(cmd_data); 263 264 case KIOCSLED: 265 kbdled = *(char *)data; 266 kbd_setLED(); 267 return (0); 268 269 case KIOCGLED: 270 *(char *)data = kbdled; 271 return (0); 272 273 case KIOCSBELL: 274 #if NBELL > 0 275 return opm_bell_setup((struct bell_info *)data); 276 #else 277 return (0); /* always success */ 278 #endif 279 280 case FIONBIO: /* we will remove this someday (soon???) */ 281 return (0); 282 283 case FIOASYNC: 284 k->sc_events.ev_async = *(int *)data != 0; 285 return (0); 286 287 case FIOSETOWN: 288 if (-*(int *)data != k->sc_events.ev_io->p_pgid 289 && *(int *)data != k->sc_events.ev_io->p_pid) 290 return (EPERM); 291 return 0; 292 293 case TIOCSPGRP: 294 if (*(int *)data != k->sc_events.ev_io->p_pgid) 295 return (EPERM); 296 return (0); 297 298 default: 299 return (ENOTTY); 300 } 301 302 /* 303 * We identified the ioctl, but we do not handle it. 304 */ 305 return (EOPNOTSUPP); /* misuse, but what the heck */ 306 } 307 308 309 static int 310 kbdpoll(dev_t dev, int events, struct lwp *l) 311 { 312 struct kbd_softc *k; 313 314 k = device_lookup_private(&kbd_cd, minor(dev)); 315 return (ev_poll(&k->sc_events, events, l)); 316 } 317 318 static int 319 kbdkqfilter(dev_t dev, struct knote *kn) 320 { 321 struct kbd_softc *k; 322 323 k = device_lookup_private(&kbd_cd, minor(dev)); 324 return (ev_kqfilter(&k->sc_events, kn)); 325 } 326 327 #define KBDBUFMASK 63 328 #define KBDBUFSIZ 64 329 static u_char kbdbuf[KBDBUFSIZ]; 330 static int kbdputoff = 0; 331 static int kbdgetoff = 0; 332 333 static int 334 kbdintr(void *arg) 335 { 336 uint8_t c, st; 337 struct kbd_softc *sc = arg; 338 struct firm_event *fe; 339 int put; 340 341 /* clear receiver error if any */ 342 st = mfp_get_rsr(); 343 344 c = mfp_get_udr(); 345 346 rnd_add_uint32(&sc->sc_rndsource, (st << 8) | c); 347 348 if ((st & MFP_RSR_BF) == 0) 349 return 0; /* intr caused by an err -- no char received */ 350 351 /* if not in event mode, deliver straight to ite to process key stroke */ 352 if (!sc->sc_event_mode) { 353 kbdbuf[kbdputoff++ & KBDBUFMASK] = c; 354 softint_schedule(sc->sc_softintr_cookie); 355 return 0; 356 } 357 358 /* Keyboard is generating events. Turn this keystroke into an 359 event and put it in the queue. If the queue is full, the 360 keystroke is lost (sorry!). */ 361 362 put = sc->sc_events.ev_put; 363 fe = &sc->sc_events.ev_q[put]; 364 put = (put + 1) % EV_QSIZE; 365 if (put == sc->sc_events.ev_get) { 366 log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */ 367 return 0; 368 } 369 fe->id = KEY_CODE(c); 370 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN; 371 firm_gettime(fe); 372 sc->sc_events.ev_put = put; 373 softint_schedule(sc->sc_softintr_cookie); 374 375 return 0; 376 } 377 378 static void 379 kbdsoftint(void *arg) /* what if ite is not configured? */ 380 { 381 struct kbd_softc *sc = arg; 382 383 if (sc->sc_event_mode) 384 ev_wakeup(&sc->sc_events); 385 386 mutex_enter(&sc->sc_lock); 387 while (kbdgetoff < kbdputoff) { 388 mutex_exit(&sc->sc_lock); 389 ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]); 390 mutex_enter(&sc->sc_lock); 391 } 392 kbdgetoff = kbdputoff = 0; 393 394 mutex_exit(&sc->sc_lock); 395 } 396 397 static void 398 kbd_bell(int mode) 399 { 400 #if NBELL > 0 401 if (mode) 402 opm_bell_on(); 403 else 404 opm_bell_off(); 405 #endif 406 } 407 408 unsigned char kbdled; 409 410 void 411 kbd_setLED(void) 412 { 413 mfp_send_usart(~kbdled | 0x80); 414 } 415 416 static int 417 kbd_send_command(int cmd) 418 { 419 switch (cmd) { 420 case KBD_CMD_RESET: 421 /* XXX */ 422 return 0; 423 424 case KBD_CMD_BELL: 425 kbd_bell(1); 426 return 0; 427 428 case KBD_CMD_NOBELL: 429 kbd_bell(0); 430 return 0; 431 432 default: 433 return ENOTTY; 434 } 435 } 436 437 /* 438 * for console 439 */ 440 #if NITE > 0 441 int 442 kbdcngetc(void) 443 { 444 int s; 445 u_char ints, c; 446 447 s = splhigh(); 448 ints = mfp_get_iera(); 449 450 mfp_bit_clear_iera(MFP_INTR_RCV_FULL); 451 mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE); 452 c = mfp_receive_usart(); 453 454 mfp_set_iera(ints); 455 splx(s); 456 457 return c; 458 } 459 #endif 460