kbd.c revision 1.1.1.1 1 /* $NetBSD: kbd.c,v 1.1.1.1 1995/03/26 07:12:12 leo 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 /* this routine should not exist, but is convenient to write here for now */
171 int kbdwrite(dev_t dev, struct uio *uio, int flags)
172 {
173 return EOPNOTSUPP;
174 }
175
176 int
177 kbdioctl(dev_t dev,u_long cmd,register caddr_t data,int flag,struct proc *p)
178 {
179 register struct kbd_softc *k = &kbd_softc;
180
181 switch (cmd) {
182 case KIOCTRANS:
183 if(*(int *)data == TR_UNTRANS_EVENT)
184 return 0;
185 break;
186
187 case KIOCGTRANS:
188 /*
189 * Get translation mode
190 */
191 *(int *)data = TR_UNTRANS_EVENT;
192 return 0;
193
194 case KIOCSDIRECT:
195 k->k_event_mode = *(int *)data;
196 return 0;
197
198 case FIONBIO: /* we will remove this someday (soon???) */
199 return 0;
200
201 case FIOASYNC:
202 k->k_events.ev_async = *(int *)data != 0;
203 return 0;
204
205 case TIOCSPGRP:
206 if(*(int *)data != k->k_events.ev_io->p_pgid)
207 return EPERM;
208 return 0;
209
210 default:
211 return ENOTTY;
212 }
213
214 /*
215 * We identified the ioctl, but we do not handle it.
216 */
217 return EOPNOTSUPP; /* misuse, but what the heck */
218 }
219
220 int
221 kbdselect (dev_t dev, int rw, struct proc *p)
222 {
223 return ev_select (&kbd_softc.k_events, rw, p);
224 }
225
226 /*
227 * Keyboard interrupt handler called straight from MFP.
228 */
229 int
230 kbdintr(sr)
231 int sr; /* sr at time of interrupt */
232 {
233 int code;
234
235 /*
236 * There may be multiple keys available. Read them all.
237 */
238 while(KBD->ac_cs & (A_IRQ|A_RXRDY)) {
239 if(KBD->ac_cs & (A_OE|A_PE)) {
240 code = KBD->ac_da; /* Silently ignore overruns */
241 continue;
242 }
243 kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da;
244 }
245 if(!BASEPRI(sr)) {
246 if(!kbd_soft++)
247 add_sicallback(kbdsoft, 0, 0);
248 }
249 else {
250 spl1();
251 kbdsoft();
252 }
253 }
254
255 /*
256 * Keyboard soft interrupt handler
257 */
258 void
259 kbdsoft()
260 {
261 int s;
262 u_char code;
263 struct kbd_softc *k = &kbd_softc;
264 struct firm_event *fe;
265 int put;
266 int n, get;
267
268 kbd_soft = 0;
269 get = kbd_rbget;
270
271 for(;;) {
272 n = kbd_rbput;
273 if(get == n) /* We're done */
274 break;
275 n -= get;
276 if(n > KBD_RING_SIZE) { /* Ring buffer overflow */
277 get += n - KBD_RING_SIZE;
278 n = KBD_RING_SIZE;
279 }
280 while(--n >= 0) {
281 code = kbd_ring[get++ & KBD_RING_MASK];
282
283 /*
284 * if not in event mode, deliver straight to ite to
285 * process key stroke
286 */
287 if(!k->k_event_mode) {
288 /* Gets to spltty() by itself */
289 ite_filter(code, ITEFILT_TTY);
290 continue;
291 }
292
293 /*
294 * Keyboard is generating events. Turn this keystroke
295 * into an event and put it in the queue. If the queue
296 * is full, the keystroke is lost (sorry!).
297 */
298 s = spltty();
299 put = k->k_events.ev_put;
300 fe = &k->k_events.ev_q[put];
301 put = (put + 1) % EV_QSIZE;
302 if(put == k->k_events.ev_get) {
303 log(LOG_WARNING,
304 "keyboard event queue overflow\n");
305 splx(s);
306 continue;
307 }
308 fe->id = KEY_CODE(code);
309 fe->value = KEY_UP(code) ? VKEY_UP : VKEY_DOWN;
310 fe->time = time;
311 k->k_events.ev_put = put;
312 EV_WAKEUP(&k->k_events);
313 splx(s);
314 }
315 kbd_rbget = get;
316 }
317 }
318
319 static char sound[] = {
320 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00,
321 0xF8,0x10,0x10,0x10,0x00,0x20,0x03
322 };
323
324 int
325 kbdbell()
326 {
327 register int i, sps;
328
329 sps = spltty();
330 for(i = 0; i < sizeof(sound); i++) {
331 SOUND->sd_selr = i;
332 SOUND->sd_wdat = sound[i];
333 }
334 splx(sps);
335 }
336
337 int
338 kbdgetcn()
339 {
340 u_char code;
341 int s = spltty();
342
343 MFP->mf_imrb &= ~IB_AINT;
344 while(!(KBD->ac_cs & A_IRQ))
345 ; /* Wait for key */
346
347 MFP->mf_iprb &= ~IB_AINT;
348 MFP->mf_imrb |= IB_AINT;
349
350 code = KBD->ac_da;
351 splx (s);
352 return code;
353 }
354