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