1 /* $NetBSD: kbd.c,v 1.40 2014/07/25 08:10:35 dholland 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.40 2014/07/25 08:10:35 dholland 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 55 #include <arch/x68k/dev/intiovar.h> 56 #include <arch/x68k/dev/mfp.h> 57 #include <arch/x68k/dev/itevar.h> 58 59 /* for sun-like event mode, if you go thru /dev/kbd. */ 60 #include <arch/x68k/dev/event_var.h> 61 62 #include <machine/kbio.h> 63 #include <machine/kbd.h> 64 #include <machine/vuid_event.h> 65 66 struct kbd_softc { 67 device_t sc_dev; 68 int sc_event_mode; /* if true, collect events, else pass to ite */ 69 struct evvar sc_events; /* event queue state */ 70 void *sc_softintr_cookie; 71 kmutex_t sc_lock; 72 }; 73 74 void kbdenable(int); 75 int kbdintr(void *); 76 void kbdsoftint(void *); 77 void kbd_bell(int); 78 int kbdcngetc(void); 79 void kbd_setLED(void); 80 int kbd_send_command(int); 81 82 83 static int kbdmatch(device_t, cfdata_t, void *); 84 static void kbdattach(device_t, device_t, void *); 85 86 CFATTACH_DECL_NEW(kbd, sizeof(struct kbd_softc), 87 kbdmatch, kbdattach, NULL, NULL); 88 89 static int kbd_attached; 90 91 dev_type_open(kbdopen); 92 dev_type_close(kbdclose); 93 dev_type_read(kbdread); 94 dev_type_ioctl(kbdioctl); 95 dev_type_poll(kbdpoll); 96 dev_type_kqfilter(kbdkqfilter); 97 98 const struct cdevsw kbd_cdevsw = { 99 .d_open = kbdopen, 100 .d_close = kbdclose, 101 .d_read = kbdread, 102 .d_write = nowrite, 103 .d_ioctl = kbdioctl, 104 .d_stop = nostop, 105 .d_tty = notty, 106 .d_poll = kbdpoll, 107 .d_mmap = nommap, 108 .d_kqfilter = kbdkqfilter, 109 .d_discard = nodiscard, 110 .d_flag = 0 111 }; 112 113 static int 114 kbdmatch(device_t parent, cfdata_t cf, void *aux) 115 { 116 117 if (strcmp(aux, "kbd") != 0) 118 return (0); 119 if (kbd_attached) 120 return (0); 121 122 return (1); 123 } 124 125 static void 126 kbdattach(device_t parent, device_t self, void *aux) 127 { 128 struct kbd_softc *sc = device_private(self); 129 struct mfp_softc *mfp = device_private(parent); 130 131 kbd_attached = 1; 132 sc->sc_dev = self; 133 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH); 134 135 /* MFP interrupt #12 is for USART receive buffer full */ 136 intio_intr_establish(mfp->sc_intr + 12, "kbd", kbdintr, sc); 137 sc->sc_softintr_cookie = softint_establish(SOFTINT_SERIAL, 138 kbdsoftint, sc); 139 140 kbdenable(1); 141 sc->sc_event_mode = 0; 142 sc->sc_events.ev_io = 0; 143 144 aprint_normal("\n"); 145 } 146 147 148 /* definitions for x68k keyboard encoding. */ 149 #define KEY_CODE(c) ((c) & 0x7f) 150 #define KEY_UP(c) ((c) & 0x80) 151 152 void 153 kbdenable(int mode) /* 1: interrupt, 0: poll */ 154 { 155 156 intio_set_sysport_keyctrl(8); 157 mfp_bit_clear_iera(MFP_INTR_RCV_FULL | MFP_INTR_TIMER_B); 158 mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP); 159 mfp_set_tbdr(13); /* Timer B interrupt interval */ 160 mfp_set_tbcr(1); /* 1/4 delay mode */ 161 mfp_set_ucr(MFP_UCR_CLKX16 | MFP_UCR_RW_8 | MFP_UCR_ONESB); 162 mfp_set_rsr(MFP_RSR_RE); /* USART receive enable */ 163 mfp_set_tsr(MFP_TSR_TE); /* USART transmit enable */ 164 165 if (mode) { 166 mfp_bit_set_iera(MFP_INTR_RCV_FULL); 167 /* 168 * Perform null read in case that an input byte is in the 169 * receiver buffer, which prevents further interrupts. 170 * We could save the input, but probably not so valuable. 171 */ 172 (void) mfp_get_udr(); 173 } 174 175 kbdled = 0; /* all keyboard LED turn off. */ 176 kbd_setLED(); 177 178 if (!(intio_get_sysport_keyctrl() & 8)) 179 aprint_normal(" (no connected keyboard)"); 180 } 181 182 extern struct cfdriver kbd_cd; 183 184 int 185 kbdopen(dev_t dev, int flags, int mode, struct lwp *l) 186 { 187 struct kbd_softc *k; 188 189 k = device_lookup_private(&kbd_cd, minor(dev)); 190 if (k == NULL) 191 return (ENXIO); 192 193 if (k->sc_events.ev_io) 194 return (EBUSY); 195 k->sc_events.ev_io = l->l_proc; 196 ev_init(&k->sc_events, device_xname(k->sc_dev), &k->sc_lock); 197 198 return (0); 199 } 200 201 int 202 kbdclose(dev_t dev, int flags, int mode, struct lwp *l) 203 { 204 struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev)); 205 206 /* Turn off event mode, dump the queue */ 207 k->sc_event_mode = 0; 208 ev_fini(&k->sc_events); 209 k->sc_events.ev_io = NULL; 210 211 return (0); 212 } 213 214 215 int 216 kbdread(dev_t dev, struct uio *uio, int flags) 217 { 218 struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev)); 219 220 return ev_read(&k->sc_events, uio, flags); 221 } 222 223 #if NBELL > 0 224 struct bell_info; 225 int opm_bell_setup(struct bell_info *); 226 void opm_bell_on(void); 227 void opm_bell_off(void); 228 #endif 229 230 int 231 kbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 232 { 233 struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev)); 234 int cmd_data; 235 236 switch (cmd) { 237 case KIOCTRANS: 238 if (*(int *)data == TR_UNTRANS_EVENT) 239 return (0); 240 break; 241 242 case KIOCGTRANS: 243 /* 244 * Get translation mode 245 */ 246 *(int *)data = TR_UNTRANS_EVENT; 247 return (0); 248 249 case KIOCSDIRECT: 250 k->sc_event_mode = *(int *)data; 251 return (0); 252 253 case KIOCCMD: 254 cmd_data = *(int *)data; 255 return kbd_send_command(cmd_data); 256 257 case KIOCSLED: 258 kbdled = *(char *)data; 259 kbd_setLED(); 260 return (0); 261 262 case KIOCGLED: 263 *(char *)data = kbdled; 264 return (0); 265 266 case KIOCSBELL: 267 #if NBELL > 0 268 return opm_bell_setup((struct bell_info *)data); 269 #else 270 return (0); /* always success */ 271 #endif 272 273 case FIONBIO: /* we will remove this someday (soon???) */ 274 return (0); 275 276 case FIOASYNC: 277 k->sc_events.ev_async = *(int *)data != 0; 278 return (0); 279 280 case FIOSETOWN: 281 if (-*(int *)data != k->sc_events.ev_io->p_pgid 282 && *(int *)data != k->sc_events.ev_io->p_pid) 283 return (EPERM); 284 return 0; 285 286 case TIOCSPGRP: 287 if (*(int *)data != k->sc_events.ev_io->p_pgid) 288 return (EPERM); 289 return (0); 290 291 default: 292 return (ENOTTY); 293 } 294 295 /* 296 * We identified the ioctl, but we do not handle it. 297 */ 298 return (EOPNOTSUPP); /* misuse, but what the heck */ 299 } 300 301 302 int 303 kbdpoll(dev_t dev, int events, struct lwp *l) 304 { 305 struct kbd_softc *k; 306 307 k = device_lookup_private(&kbd_cd, minor(dev)); 308 return (ev_poll(&k->sc_events, events, l)); 309 } 310 311 int 312 kbdkqfilter(dev_t dev, struct knote *kn) 313 { 314 struct kbd_softc *k; 315 316 k = device_lookup_private(&kbd_cd, minor(dev)); 317 return (ev_kqfilter(&k->sc_events, kn)); 318 } 319 320 #define KBDBUFMASK 63 321 #define KBDBUFSIZ 64 322 static u_char kbdbuf[KBDBUFSIZ]; 323 static int kbdputoff = 0; 324 static int kbdgetoff = 0; 325 326 int 327 kbdintr(void *arg) 328 { 329 uint8_t c, st; 330 struct kbd_softc *sc = arg; 331 struct firm_event *fe; 332 int put; 333 334 /* clear receiver error if any */ 335 st = mfp_get_rsr(); 336 337 c = mfp_get_udr(); 338 339 if ((st & MFP_RSR_BF) == 0) 340 return 0; /* intr caused by an err -- no char received */ 341 342 /* if not in event mode, deliver straight to ite to process key stroke */ 343 if (!sc->sc_event_mode) { 344 kbdbuf[kbdputoff++ & KBDBUFMASK] = c; 345 softint_schedule(sc->sc_softintr_cookie); 346 return 0; 347 } 348 349 /* Keyboard is generating events. Turn this keystroke into an 350 event and put it in the queue. If the queue is full, the 351 keystroke is lost (sorry!). */ 352 353 put = sc->sc_events.ev_put; 354 fe = &sc->sc_events.ev_q[put]; 355 put = (put + 1) % EV_QSIZE; 356 if (put == sc->sc_events.ev_get) { 357 log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */ 358 return 0; 359 } 360 fe->id = KEY_CODE(c); 361 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN; 362 firm_gettime(fe); 363 sc->sc_events.ev_put = put; 364 softint_schedule(sc->sc_softintr_cookie); 365 366 return 0; 367 } 368 369 void 370 kbdsoftint(void *arg) /* what if ite is not configured? */ 371 { 372 struct kbd_softc *sc = arg; 373 374 if (sc->sc_event_mode) 375 ev_wakeup(&sc->sc_events); 376 377 mutex_enter(&sc->sc_lock); 378 while (kbdgetoff < kbdputoff) { 379 mutex_exit(&sc->sc_lock); 380 ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]); 381 mutex_enter(&sc->sc_lock); 382 } 383 kbdgetoff = kbdputoff = 0; 384 385 mutex_exit(&sc->sc_lock); 386 } 387 388 void 389 kbd_bell(int mode) 390 { 391 #if NBELL > 0 392 if (mode) 393 opm_bell_on(); 394 else 395 opm_bell_off(); 396 #endif 397 } 398 399 unsigned char kbdled; 400 401 void 402 kbd_setLED(void) 403 { 404 mfp_send_usart(~kbdled | 0x80); 405 } 406 407 int 408 kbd_send_command(int cmd) 409 { 410 switch (cmd) { 411 case KBD_CMD_RESET: 412 /* XXX */ 413 return 0; 414 415 case KBD_CMD_BELL: 416 kbd_bell(1); 417 return 0; 418 419 case KBD_CMD_NOBELL: 420 kbd_bell(0); 421 return 0; 422 423 default: 424 return ENOTTY; 425 } 426 } 427 428 /* 429 * for console 430 */ 431 #if NITE > 0 432 int 433 kbdcngetc(void) 434 { 435 int s; 436 u_char ints, c; 437 438 s = splhigh(); 439 ints = mfp_get_iera(); 440 441 mfp_bit_clear_iera(MFP_INTR_RCV_FULL); 442 mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE); 443 c = mfp_receive_usart(); 444 445 mfp_set_iera(ints); 446 splx(s); 447 448 return c; 449 } 450 #endif 451