1 /* $NetBSD: kbd.c,v 1.21 2004/12/13 02:14:13 chs 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.21 2004/12/13 02:14:13 chs 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 51 #include <machine/cpu.h> 52 #include <machine/bus.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 }; 71 72 void kbdenable __P((int)); 73 int kbdintr __P((void *)); 74 void kbdsoftint __P((void)); 75 void kbd_bell __P((int)); 76 int kbdcngetc __P((void)); 77 void kbd_setLED __P((void)); 78 int kbd_send_command __P((int)); 79 80 81 static int kbdmatch __P((struct device *, struct cfdata *, void *)); 82 static void kbdattach __P((struct device *, struct device *, void *)); 83 84 CFATTACH_DECL(kbd, sizeof(struct kbd_softc), 85 kbdmatch, kbdattach, NULL, NULL); 86 87 static int kbd_attached; 88 89 dev_type_open(kbdopen); 90 dev_type_close(kbdclose); 91 dev_type_read(kbdread); 92 dev_type_ioctl(kbdioctl); 93 dev_type_poll(kbdpoll); 94 dev_type_kqfilter(kbdkqfilter); 95 96 const struct cdevsw kbd_cdevsw = { 97 kbdopen, kbdclose, kbdread, nowrite, kbdioctl, 98 nostop, notty, kbdpoll, nommap, kbdkqfilter, 99 }; 100 101 static int 102 kbdmatch(parent, cf, aux) 103 struct device *parent; 104 struct cfdata *cf; 105 void *aux; 106 { 107 if (strcmp(aux, "kbd") != 0) 108 return (0); 109 if (kbd_attached) 110 return (0); 111 112 return (1); 113 } 114 115 static void 116 kbdattach(parent, self, aux) 117 struct device *parent, *self; 118 void *aux; 119 { 120 struct kbd_softc *k = (void*) self; 121 struct mfp_softc *mfp = (void*) parent; 122 int s = spltty(); 123 124 kbd_attached = 1; 125 126 /* MFP interrupt #12 is for USART receive buffer full */ 127 intio_intr_establish(mfp->sc_intr + 12, "kbd", kbdintr, self); 128 129 kbdenable(1); 130 k->sc_event_mode = 0; 131 k->sc_events.ev_io = 0; 132 splx(s); 133 134 printf("\n"); 135 } 136 137 138 /* definitions for x68k keyboard encoding. */ 139 #define KEY_CODE(c) ((c) & 0x7f) 140 #define KEY_UP(c) ((c) & 0x80) 141 142 void 143 kbdenable(mode) 144 int mode; /* 1: interrupt, 0: poll */ 145 { 146 intio_set_sysport_keyctrl(8); 147 mfp_bit_clear_iera(MFP_INTR_RCV_FULL | MFP_INTR_TIMER_B); 148 mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP); 149 mfp_set_tbdr(13); /* Timer B interrupt interval */ 150 mfp_set_tbcr(1); /* 1/4 delay mode */ 151 mfp_set_ucr(MFP_UCR_CLKX16 | MFP_UCR_RW_8 | MFP_UCR_ONESB); 152 mfp_set_rsr(MFP_RSR_RE); /* USART receive enable */ 153 mfp_set_tsr(MFP_TSR_TE); /* USART transmit enable */ 154 155 if (mode) { 156 mfp_bit_set_iera(MFP_INTR_RCV_FULL); 157 /* 158 * Perform null read in case that an input byte is in the 159 * receiver buffer, which prevents further interrupts. 160 * We could save the input, but probably not so valuable. 161 */ 162 (void) mfp_get_udr(); 163 } 164 165 kbdled = 0; /* all keyboard LED turn off. */ 166 kbd_setLED(); 167 168 if (!(intio_get_sysport_keyctrl() & 8)) 169 printf(" (no connected keyboard)"); 170 } 171 172 extern struct cfdriver kbd_cd; 173 174 int 175 kbdopen(dev, flags, mode, p) 176 dev_t dev; 177 int flags, mode; 178 struct proc *p; 179 { 180 struct kbd_softc *k; 181 int unit = minor(dev); 182 183 if (unit >= kbd_cd.cd_ndevs) 184 return (ENXIO); 185 k = kbd_cd.cd_devs[minor(dev)]; 186 if (k == NULL) 187 return (ENXIO); 188 189 if (k->sc_events.ev_io) 190 return (EBUSY); 191 k->sc_events.ev_io = p; 192 ev_init(&k->sc_events); 193 194 return (0); 195 } 196 197 int 198 kbdclose(dev, flags, mode, p) 199 dev_t dev; 200 int flags, mode; 201 struct proc *p; 202 { 203 struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)]; 204 205 /* Turn off event mode, dump the queue */ 206 k->sc_event_mode = 0; 207 ev_fini(&k->sc_events); 208 k->sc_events.ev_io = NULL; 209 210 return (0); 211 } 212 213 214 int 215 kbdread(dev, uio, flags) 216 dev_t dev; 217 struct uio *uio; 218 int flags; 219 { 220 struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)]; 221 222 return ev_read(&k->sc_events, uio, flags); 223 } 224 225 #if NBELL > 0 226 struct bell_info; 227 int opm_bell_setup __P((struct bell_info *)); 228 void opm_bell_on __P((void)); 229 void opm_bell_off __P((void)); 230 #endif 231 232 int 233 kbdioctl(dev, cmd, data, flag, p) 234 dev_t dev; 235 u_long cmd; 236 caddr_t data; 237 int flag; 238 struct proc *p; 239 { 240 register struct kbd_softc *k = kbd_cd.cd_devs[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); /* allways 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 int 310 kbdpoll(dev, events, p) 311 dev_t dev; 312 int events; 313 struct proc *p; 314 { 315 struct kbd_softc *k; 316 317 k = kbd_cd.cd_devs[minor(dev)]; 318 return (ev_poll(&k->sc_events, events, p)); 319 } 320 321 int 322 kbdkqfilter(dev_t dev, struct knote *kn) 323 { 324 struct kbd_softc *k; 325 326 k = kbd_cd.cd_devs[minor(dev)]; 327 return (ev_kqfilter(&k->sc_events, kn)); 328 } 329 330 #define KBDBUFMASK 63 331 #define KBDBUFSIZ 64 332 static u_char kbdbuf[KBDBUFSIZ]; 333 static int kbdputoff = 0; 334 static int kbdgetoff = 0; 335 336 int 337 kbdintr(arg) 338 void *arg; 339 { 340 u_char c, st; 341 struct kbd_softc *k = arg; /* XXX */ 342 struct firm_event *fe; 343 int put; 344 345 /* clear receiver error if any */ 346 st = mfp_get_rsr(); 347 348 c = mfp_get_udr(); 349 350 if ((st & MFP_RSR_BF) == 0) 351 return 0; /* intr caused by an err -- no char received */ 352 353 /* if not in event mode, deliver straight to ite to process key stroke */ 354 if (! k->sc_event_mode) { 355 kbdbuf[kbdputoff++ & KBDBUFMASK] = c; 356 setsoftkbd(); 357 return 0; 358 } 359 360 /* Keyboard is generating events. Turn this keystroke into an 361 event and put it in the queue. If the queue is full, the 362 keystroke is lost (sorry!). */ 363 364 put = k->sc_events.ev_put; 365 fe = &k->sc_events.ev_q[put]; 366 put = (put + 1) % EV_QSIZE; 367 if (put == k->sc_events.ev_get) { 368 log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */ 369 return 0; 370 } 371 fe->id = KEY_CODE(c); 372 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN; 373 fe->time = time; 374 k->sc_events.ev_put = put; 375 EV_WAKEUP(&k->sc_events); 376 377 return 0; 378 } 379 380 void 381 kbdsoftint() /* what if ite is not configured? */ 382 { 383 int s = spltty(); 384 385 while(kbdgetoff < kbdputoff) 386 ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]); 387 kbdgetoff = kbdputoff = 0; 388 389 splx(s); 390 } 391 392 void 393 kbd_bell(mode) 394 int mode; 395 { 396 #if NBELL > 0 397 if (mode) 398 opm_bell_on(); 399 else 400 opm_bell_off(); 401 #endif 402 } 403 404 unsigned char kbdled; 405 void 406 kbd_setLED() 407 { 408 mfp_send_usart(~kbdled | 0x80); 409 } 410 411 int 412 kbd_send_command(cmd) 413 int cmd; 414 { 415 switch (cmd) { 416 case KBD_CMD_RESET: 417 /* XXX */ 418 return 0; 419 420 case KBD_CMD_BELL: 421 kbd_bell(1); 422 return 0; 423 424 case KBD_CMD_NOBELL: 425 kbd_bell(0); 426 return 0; 427 428 default: 429 return ENOTTY; 430 } 431 } 432 433 /* 434 * for console 435 */ 436 #include "ite.h" 437 #if NITE > 0 438 int 439 kbdcngetc() 440 { 441 int s; 442 u_char ints, c; 443 444 s = splhigh(); 445 ints = mfp_get_iera(); 446 447 mfp_bit_clear_iera(MFP_INTR_RCV_FULL); 448 mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE); 449 c = mfp_receive_usart(); 450 451 mfp_set_iera(ints); 452 splx(s); 453 454 return c; 455 } 456 #endif 457