1 /* $NetBSD: kbd.c,v 1.12 1994/12/01 17:25:25 chopps 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 * kbd.c 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 <amiga/amiga/device.h> 50 #include <amiga/amiga/custom.h> 51 #include <amiga/amiga/cia.h> 52 #include <amiga/dev/itevar.h> 53 #include <amiga/dev/kbdreg.h> 54 #include <amiga/dev/event_var.h> 55 #include <amiga/dev/vuid_event.h> 56 #include "kbd.h" 57 58 struct kbd_softc { 59 int k_event_mode; /* if true, collect events, else pass to ite */ 60 struct evvar k_events; /* event queue state */ 61 }; 62 struct kbd_softc kbd_softc; 63 64 void kbdattach __P((struct device *, struct device *, void *)); 65 int kbdmatch __P((struct device *, struct cfdata *, void *)); 66 67 struct cfdriver kbdcd = { 68 NULL, "kbd", (cfmatch_t)kbdmatch, kbdattach, DV_DULL, 69 sizeof(struct device), NULL, 0 }; 70 71 /*ARGSUSED*/ 72 int 73 kbdmatch(pdp, cfp, auxp) 74 struct device *pdp; 75 struct cfdata *cfp; 76 void *auxp; 77 { 78 if (matchname((char *)auxp, "kbd")) 79 return(1); 80 return(0); 81 } 82 83 /*ARGSUSED*/ 84 void 85 kbdattach(pdp, dp, auxp) 86 struct device *pdp, *dp; 87 void *auxp; 88 { 89 printf("\n"); 90 } 91 92 /* definitions for amiga keyboard encoding. */ 93 #define KEY_CODE(c) ((c) & 0x7f) 94 #define KEY_UP(c) ((c) & 0x80) 95 96 void 97 kbdenable () 98 { 99 int s; 100 101 /* 102 * collides with external ints from SCSI, watch out for this when 103 * enabling/disabling interrupts there !! 104 */ 105 s = spltty(); 106 custom.intena = INTF_SETCLR | INTF_PORTS; 107 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */ 108 ciaa.cra &= ~(1<<6); /* serial line == input */ 109 kbd_softc.k_event_mode = 0; 110 kbd_softc.k_events.ev_io = 0; 111 splx(s); 112 } 113 114 115 int 116 kbdopen (dev_t dev, int flags, int mode, struct proc *p) 117 { 118 int s, error; 119 120 if (kbd_softc.k_events.ev_io) 121 return EBUSY; 122 123 kbd_softc.k_events.ev_io = p; 124 ev_init(&kbd_softc.k_events); 125 return (0); 126 } 127 128 int 129 kbdclose (dev_t dev, int flags, int mode, struct proc *p) 130 { 131 /* Turn off event mode, dump the queue */ 132 kbd_softc.k_event_mode = 0; 133 ev_fini(&kbd_softc.k_events); 134 kbd_softc.k_events.ev_io = NULL; 135 return (0); 136 } 137 138 int 139 kbdread (dev_t dev, struct uio *uio, int flags) 140 { 141 return ev_read (&kbd_softc.k_events, uio, flags); 142 } 143 144 /* this routine should not exist, but is convenient to write here for now */ 145 int 146 kbdwrite (dev_t dev, struct uio *uio, int flags) 147 { 148 return EOPNOTSUPP; 149 } 150 151 int 152 kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p) 153 { 154 register struct kbd_softc *k = &kbd_softc; 155 156 switch (cmd) 157 { 158 case KIOCTRANS: 159 if (*(int *)data == TR_UNTRANS_EVENT) 160 return 0; 161 break; 162 163 case KIOCGTRANS: 164 /* 165 * Get translation mode 166 */ 167 *(int *)data = TR_UNTRANS_EVENT; 168 return 0; 169 170 case KIOCSDIRECT: 171 k->k_event_mode = *(int *)data; 172 return 0; 173 174 case FIONBIO: /* we will remove this someday (soon???) */ 175 return 0; 176 177 case FIOASYNC: 178 k->k_events.ev_async = *(int *)data != 0; 179 return 0; 180 181 case TIOCSPGRP: 182 if (*(int *)data != k->k_events.ev_io->p_pgid) 183 return EPERM; 184 return 0; 185 186 default: 187 return ENOTTY; 188 } 189 190 /* 191 * We identified the ioctl, but we do not handle it. 192 */ 193 return EOPNOTSUPP; /* misuse, but what the heck */ 194 } 195 196 int 197 kbdselect (dev_t dev, int rw, struct proc *p) 198 { 199 return ev_select (&kbd_softc.k_events, rw, p); 200 } 201 202 203 int 204 kbdintr (mask) 205 int mask; 206 { 207 u_char c, in; 208 struct kbd_softc *k = &kbd_softc; 209 struct firm_event *fe; 210 int put; 211 212 /* now only invoked from generic CIA interrupt handler if there *is* 213 a keyboard interrupt pending */ 214 215 in = ciaa.sdr; 216 /* ack */ 217 ciaa.cra |= (1 << 6); /* serial line output */ 218 /* wait 200 microseconds (for bloody Cherry keyboards..) */ 219 DELAY(200); 220 ciaa.cra &= ~(1 << 6); 221 222 c = ~in; /* keyboard data is inverted */ 223 224 /* process the character */ 225 226 c = (c >> 1) | (c << 7); /* rotate right once */ 227 228 229 /* if not in event mode, deliver straight to ite to process key stroke */ 230 if (! k->k_event_mode) 231 { 232 ite_filter (c, ITEFILT_TTY); 233 return; 234 } 235 236 /* Keyboard is generating events. Turn this keystroke into an 237 event and put it in the queue. If the queue is full, the 238 keystroke is lost (sorry!). */ 239 240 put = k->k_events.ev_put; 241 fe = &k->k_events.ev_q[put]; 242 put = (put + 1) % EV_QSIZE; 243 if (put == k->k_events.ev_get) 244 { 245 log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */ 246 return; 247 } 248 fe->id = KEY_CODE(c); 249 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN; 250 fe->time = time; 251 k->k_events.ev_put = put; 252 EV_WAKEUP(&k->k_events); 253 } 254 255 256 int 257 kbdbell() 258 { 259 /* nice, mykes provided audio-support! */ 260 cc_bell (); 261 } 262 263 264 int 265 kbdgetcn () 266 { 267 int s = spltty (); 268 u_char ints, mask, c, in; 269 270 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP); ints |= mask) ; 271 272 in = ciaa.sdr; 273 c = ~in; 274 275 /* ack */ 276 ciaa.cra |= (1 << 6); /* serial line output */ 277 ciaa.sdr = 0xff; /* ack */ 278 /* wait 200 microseconds */ 279 DELAY(2000); /* XXXX only works as long as DELAY doesn't use a timer and waits.. */ 280 ciaa.cra &= ~(1 << 6); 281 ciaa.sdr = in; 282 283 splx (s); 284 c = (c >> 1) | (c << 7); 285 286 /* take care that no CIA-interrupts are lost */ 287 if (ints) 288 dispatch_cia_ints (0, ints); 289 290 return c; 291 } 292