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