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