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