1 /* $NetBSD: kbd.c,v 1.2 1995/04/10 08:54:41 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Leo Weppelman 5 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/ioctl.h> 41 #include <sys/tty.h> 42 #include <sys/proc.h> 43 #include <sys/conf.h> 44 #include <sys/file.h> 45 #include <sys/kernel.h> 46 #include <sys/syslog.h> 47 #include <dev/cons.h> 48 #include <machine/cpu.h> 49 #include <machine/iomap.h> 50 #include <machine/mfp.h> 51 #include <machine/acia.h> 52 #include <machine/video.h> 53 #include <atari/dev/itevar.h> 54 #include <atari/dev/kbdreg.h> 55 #include <atari/dev/event_var.h> 56 #include <atari/dev/vuid_event.h> 57 58 /* 59 * The ringbuffer is the interface between the hard and soft interrupt handler. 60 * The hard interrupt runs straight from the MFP interrupt. 61 */ 62 #define KBD_RING_SIZE 16 /* Size of the ring buffer, must be power of 2 */ 63 #define KBD_RING_MASK 15 /* Modulo mask for above */ 64 65 static u_char kbd_ring[KBD_RING_SIZE]; 66 static volatile u_int kbd_rbput = 0; /* 'put' index */ 67 static u_int kbd_rbget = 0; /* 'get' index */ 68 static u_char kbd_soft = 0; /* 1: Softint has been scheduled*/ 69 70 struct kbd_softc { 71 int k_event_mode; /* if 1, collect events, */ 72 /* else pass to ite */ 73 struct evvar k_events; /* event queue state */ 74 }; 75 76 static struct kbd_softc kbd_softc; 77 78 static void kbdsoft __P((void)); 79 static void kbdattach __P((struct device *, struct device *, void *)); 80 static int kbdmatch __P((struct device *, struct cfdata *, void *)); 81 82 struct cfdriver kbdcd = { 83 NULL, "kbd", (cfmatch_t)kbdmatch, kbdattach, 84 DV_DULL, sizeof(struct device), NULL, 0 }; 85 86 87 /*ARGSUSED*/ 88 static int 89 kbdmatch(pdp, cfp, auxp) 90 struct device *pdp; 91 struct cfdata *cfp; 92 void *auxp; 93 { 94 if(!strcmp((char *)auxp, "kbd")) 95 return(1); 96 return(0); 97 } 98 99 /*ARGSUSED*/ 100 static void 101 kbdattach(pdp, dp, auxp) 102 struct device *pdp, *dp; 103 void *auxp; 104 { 105 printf("\n"); 106 } 107 108 /* definitions for atari keyboard encoding. */ 109 #define KEY_CODE(c) ((c) & 0x7f) 110 #define KEY_UP(c) ((c) & 0x80) 111 112 void 113 kbdenable() 114 { 115 int s, code; 116 117 s = spltty(); 118 /* 119 * Initialize ACIA port 120 */ 121 code = KBD->ac_da; /* Clear error conditions */ 122 123 /* divide by 16, 8 data, 1 stop, no parity, enable interrupts */ 124 KBD->ac_cs = KBD_INIT | A_RXINT; 125 #if 0 /* XXX Turn off mouse??? */ 126 KBD->ac_da = 0x12; 127 #endif 128 129 /* 130 * Enable interrupts from MFP 131 */ 132 MFP->mf_iprb &= ~IB_AINT; 133 MFP->mf_ierb |= IB_AINT; 134 MFP->mf_imrb |= IB_AINT; 135 code = KBD->ac_da; /* Clear error conditions */ 136 137 kbd_softc.k_event_mode = 0; 138 kbd_softc.k_events.ev_io = 0; 139 splx(s); 140 } 141 142 int kbdopen(dev_t dev, int flags, int mode, struct proc *p) 143 { 144 int s, error; 145 146 if(kbd_softc.k_events.ev_io) 147 return EBUSY; 148 149 kbd_softc.k_events.ev_io = p; 150 ev_init(&kbd_softc.k_events); 151 return (0); 152 } 153 154 int 155 kbdclose(dev_t dev, int flags, int mode, struct proc *p) 156 { 157 /* Turn off event mode, dump the queue */ 158 kbd_softc.k_event_mode = 0; 159 ev_fini(&kbd_softc.k_events); 160 kbd_softc.k_events.ev_io = NULL; 161 return (0); 162 } 163 164 int 165 kbdread(dev_t dev, struct uio *uio, int flags) 166 { 167 return ev_read(&kbd_softc.k_events, uio, flags); 168 } 169 170 int 171 kbdioctl(dev_t dev,u_long cmd,register caddr_t data,int flag,struct proc *p) 172 { 173 register struct kbd_softc *k = &kbd_softc; 174 175 switch (cmd) { 176 case KIOCTRANS: 177 if(*(int *)data == TR_UNTRANS_EVENT) 178 return 0; 179 break; 180 181 case KIOCGTRANS: 182 /* 183 * Get translation mode 184 */ 185 *(int *)data = TR_UNTRANS_EVENT; 186 return 0; 187 188 case KIOCSDIRECT: 189 k->k_event_mode = *(int *)data; 190 return 0; 191 192 case FIONBIO: /* we will remove this someday (soon???) */ 193 return 0; 194 195 case FIOASYNC: 196 k->k_events.ev_async = *(int *)data != 0; 197 return 0; 198 199 case TIOCSPGRP: 200 if(*(int *)data != k->k_events.ev_io->p_pgid) 201 return EPERM; 202 return 0; 203 204 default: 205 return ENOTTY; 206 } 207 208 /* 209 * We identified the ioctl, but we do not handle it. 210 */ 211 return EOPNOTSUPP; /* misuse, but what the heck */ 212 } 213 214 int 215 kbdselect (dev_t dev, int rw, struct proc *p) 216 { 217 return ev_select (&kbd_softc.k_events, rw, p); 218 } 219 220 /* 221 * Keyboard interrupt handler called straight from MFP. 222 */ 223 int 224 kbdintr(sr) 225 int sr; /* sr at time of interrupt */ 226 { 227 int code; 228 229 /* 230 * There may be multiple keys available. Read them all. 231 */ 232 while(KBD->ac_cs & (A_IRQ|A_RXRDY)) { 233 if(KBD->ac_cs & (A_OE|A_PE)) { 234 code = KBD->ac_da; /* Silently ignore overruns */ 235 continue; 236 } 237 kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da; 238 } 239 if(!BASEPRI(sr)) { 240 if(!kbd_soft++) 241 add_sicallback(kbdsoft, 0, 0); 242 } 243 else { 244 spl1(); 245 kbdsoft(); 246 } 247 } 248 249 /* 250 * Keyboard soft interrupt handler 251 */ 252 void 253 kbdsoft() 254 { 255 int s; 256 u_char code; 257 struct kbd_softc *k = &kbd_softc; 258 struct firm_event *fe; 259 int put; 260 int n, get; 261 262 kbd_soft = 0; 263 get = kbd_rbget; 264 265 for(;;) { 266 n = kbd_rbput; 267 if(get == n) /* We're done */ 268 break; 269 n -= get; 270 if(n > KBD_RING_SIZE) { /* Ring buffer overflow */ 271 get += n - KBD_RING_SIZE; 272 n = KBD_RING_SIZE; 273 } 274 while(--n >= 0) { 275 code = kbd_ring[get++ & KBD_RING_MASK]; 276 277 /* 278 * if not in event mode, deliver straight to ite to 279 * process key stroke 280 */ 281 if(!k->k_event_mode) { 282 /* Gets to spltty() by itself */ 283 ite_filter(code, ITEFILT_TTY); 284 continue; 285 } 286 287 /* 288 * Keyboard is generating events. Turn this keystroke 289 * into an event and put it in the queue. If the queue 290 * is full, the keystroke is lost (sorry!). 291 */ 292 s = spltty(); 293 put = k->k_events.ev_put; 294 fe = &k->k_events.ev_q[put]; 295 put = (put + 1) % EV_QSIZE; 296 if(put == k->k_events.ev_get) { 297 log(LOG_WARNING, 298 "keyboard event queue overflow\n"); 299 splx(s); 300 continue; 301 } 302 fe->id = KEY_CODE(code); 303 fe->value = KEY_UP(code) ? VKEY_UP : VKEY_DOWN; 304 fe->time = time; 305 k->k_events.ev_put = put; 306 EV_WAKEUP(&k->k_events); 307 splx(s); 308 } 309 kbd_rbget = get; 310 } 311 } 312 313 static char sound[] = { 314 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, 315 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 316 }; 317 318 int 319 kbdbell() 320 { 321 register int i, sps; 322 323 sps = spltty(); 324 for(i = 0; i < sizeof(sound); i++) { 325 SOUND->sd_selr = i; 326 SOUND->sd_wdat = sound[i]; 327 } 328 splx(sps); 329 } 330 331 int 332 kbdgetcn() 333 { 334 u_char code; 335 int s = spltty(); 336 337 MFP->mf_imrb &= ~IB_AINT; 338 while(!(KBD->ac_cs & A_IRQ)) 339 ; /* Wait for key */ 340 341 MFP->mf_iprb &= ~IB_AINT; 342 MFP->mf_imrb |= IB_AINT; 343 344 code = KBD->ac_da; 345 splx (s); 346 return code; 347 } 348