kbd.c revision 1.2 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