kbd.c revision 1.10 1 /*
2 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * kbd.c
34 * $Id: kbd.c,v 1.10 1994/10/06 19:54:30 chopps Exp $
35 */
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/ioctl.h>
40 #include <sys/tty.h>
41 #include <sys/proc.h>
42 #include <sys/conf.h>
43 #include <sys/file.h>
44 #include <sys/kernel.h>
45 #include <sys/syslog.h>
46 #include <dev/cons.h>
47 #include <machine/cpu.h>
48 #include <amiga/amiga/device.h>
49 #include <amiga/amiga/custom.h>
50 #include <amiga/amiga/cia.h>
51 #include <amiga/dev/itevar.h>
52 #include <amiga/dev/kbdreg.h>
53 #include <amiga/dev/event_var.h>
54 #include <amiga/dev/vuid_event.h>
55 #include "kbd.h"
56
57 struct kbd_softc {
58 int k_event_mode; /* if true, collect events, else pass to ite */
59 struct evvar k_events; /* event queue state */
60 };
61 struct kbd_softc kbd_softc;
62
63 void kbdattach __P((struct device *, struct device *, void *));
64 int kbdmatch __P((struct device *, struct cfdata *, void *));
65
66 struct cfdriver kbdcd = {
67 NULL, "kbd", kbdmatch, kbdattach, DV_DULL,
68 sizeof(struct device), NULL, 0 };
69
70 /*ARGSUSED*/
71 int
72 kbdmatch(pdp, cfp, auxp)
73 struct device *pdp;
74 struct cfdata *cfp;
75 void *auxp;
76 {
77 if (matchname((char *)auxp, "kbd"))
78 return(1);
79 return(0);
80 }
81
82 /*ARGSUSED*/
83 void
84 kbdattach(pdp, dp, auxp)
85 struct device *pdp, *dp;
86 void *auxp;
87 {
88 printf("\n");
89 }
90
91 /* definitions for amiga keyboard encoding. */
92 #define KEY_CODE(c) ((c) & 0x7f)
93 #define KEY_UP(c) ((c) & 0x80)
94
95 void
96 kbdenable ()
97 {
98 int s;
99
100 /*
101 * collides with external ints from SCSI, watch out for this when
102 * enabling/disabling interrupts there !!
103 */
104 s = spltty();
105 custom.intena = INTF_SETCLR | INTF_PORTS;
106 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */
107 ciaa.cra &= ~(1<<6); /* serial line == input */
108 kbd_softc.k_event_mode = 0;
109 kbd_softc.k_events.ev_io = 0;
110 splx(s);
111 }
112
113
114 int
115 kbdopen (dev_t dev, int flags, int mode, struct proc *p)
116 {
117 int s, error;
118
119 if (kbd_softc.k_events.ev_io)
120 return EBUSY;
121
122 kbd_softc.k_events.ev_io = p;
123 ev_init(&kbd_softc.k_events);
124 return (0);
125 }
126
127 int
128 kbdclose (dev_t dev, int flags, int mode, struct proc *p)
129 {
130 /* Turn off event mode, dump the queue */
131 kbd_softc.k_event_mode = 0;
132 ev_fini(&kbd_softc.k_events);
133 kbd_softc.k_events.ev_io = NULL;
134 return (0);
135 }
136
137 int
138 kbdread (dev_t dev, struct uio *uio, int flags)
139 {
140 return ev_read (&kbd_softc.k_events, uio, flags);
141 }
142
143 /* this routine should not exist, but is convenient to write here for now */
144 int
145 kbdwrite (dev_t dev, struct uio *uio, int flags)
146 {
147 return EOPNOTSUPP;
148 }
149
150 int
151 kbdioctl (dev_t dev, int cmd, register caddr_t data, int flag, struct proc *p)
152 {
153 register struct kbd_softc *k = &kbd_softc;
154
155 switch (cmd)
156 {
157 case KIOCTRANS:
158 if (*(int *)data == TR_UNTRANS_EVENT)
159 return 0;
160 break;
161
162 case KIOCGTRANS:
163 /*
164 * Get translation mode
165 */
166 *(int *)data = TR_UNTRANS_EVENT;
167 return 0;
168
169 case KIOCSDIRECT:
170 k->k_event_mode = *(int *)data;
171 return 0;
172
173 case FIONBIO: /* we will remove this someday (soon???) */
174 return 0;
175
176 case FIOASYNC:
177 k->k_events.ev_async = *(int *)data != 0;
178 return 0;
179
180 case TIOCSPGRP:
181 if (*(int *)data != k->k_events.ev_io->p_pgid)
182 return EPERM;
183 return 0;
184
185 default:
186 return ENOTTY;
187 }
188
189 /*
190 * We identified the ioctl, but we do not handle it.
191 */
192 return EOPNOTSUPP; /* misuse, but what the heck */
193 }
194
195 int
196 kbdselect (dev_t dev, int rw, struct proc *p)
197 {
198 return ev_select (&kbd_softc.k_events, rw, p);
199 }
200
201
202 int
203 kbdintr (mask)
204 int mask;
205 {
206 u_char c, in;
207 struct kbd_softc *k = &kbd_softc;
208 struct firm_event *fe;
209 int put;
210
211 /* now only invoked from generic CIA interrupt handler if there *is*
212 a keyboard interrupt pending */
213
214 in = ciaa.sdr;
215 /* ack */
216 ciaa.cra |= (1 << 6); /* serial line output */
217 /* wait 200 microseconds (for bloody Cherry keyboards..) */
218 DELAY(200);
219 ciaa.cra &= ~(1 << 6);
220
221 c = ~in; /* keyboard data is inverted */
222
223 /* process the character */
224
225 c = (c >> 1) | (c << 7); /* rotate right once */
226
227
228 /* if not in event mode, deliver straight to ite to process key stroke */
229 if (! k->k_event_mode)
230 {
231 ite_filter (c, ITEFILT_TTY);
232 return;
233 }
234
235 /* Keyboard is generating events. Turn this keystroke into an
236 event and put it in the queue. If the queue is full, the
237 keystroke is lost (sorry!). */
238
239 put = k->k_events.ev_put;
240 fe = &k->k_events.ev_q[put];
241 put = (put + 1) % EV_QSIZE;
242 if (put == k->k_events.ev_get)
243 {
244 log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */
245 return;
246 }
247 fe->id = KEY_CODE(c);
248 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
249 fe->time = time;
250 k->k_events.ev_put = put;
251 EV_WAKEUP(&k->k_events);
252 }
253
254
255 int
256 kbdbell()
257 {
258 /* nice, mykes provided audio-support! */
259 cc_bell ();
260 }
261
262
263 int
264 kbdgetcn ()
265 {
266 int s = spltty ();
267 u_char ints, mask, c, in;
268
269 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP); ints |= mask) ;
270
271 in = ciaa.sdr;
272 c = ~in;
273
274 /* ack */
275 ciaa.cra |= (1 << 6); /* serial line output */
276 ciaa.sdr = 0xff; /* ack */
277 /* wait 200 microseconds */
278 DELAY(2000); /* XXXX only works as long as DELAY doesn't use a timer and waits.. */
279 ciaa.cra &= ~(1 << 6);
280 ciaa.sdr = in;
281
282 splx (s);
283 c = (c >> 1) | (c << 7);
284
285 /* take care that no CIA-interrupts are lost */
286 if (ints)
287 dispatch_cia_ints (0, ints);
288
289 return c;
290 }
291