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