xref: /netbsd/sys/arch/next68k/dev/nextkbd.c (revision bf9ec67e)
1 /* $NetBSD: nextkbd.c,v 1.4 2002/03/17 19:40:47 atatat Exp $ */
2 /*
3  * Copyright (c) 1998 Matt DeBergalis
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Matt DeBergalis
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/proc.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/errno.h>
41 #include <sys/queue.h>
42 #include <sys/lock.h>
43 
44 #include <machine/autoconf.h>
45 #include <machine/cpu.h>
46 #include <machine/intr.h>
47 #include <machine/bus.h>
48 
49 #include <next68k/dev/nextkbdvar.h>
50 #include <next68k/dev/wskbdmap_next.h>
51 
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wscons/wskbdvar.h>
54 #include <dev/wscons/wsksymdef.h>
55 #include <dev/wscons/wsksymvar.h>
56 
57 #include <next68k/next68k/isr.h>
58 
59 struct nextkbd_internal {
60 	int num_ints; /* interrupt total */
61 	int polling;
62 	int isconsole;
63 
64 	bus_space_tag_t iot;
65 	bus_space_handle_t ioh;
66 	struct nextkbd_softc *t_sc; /* back pointer */
67 	u_int32_t mods;
68 };
69 
70 struct mon_regs {
71 	u_int32_t mon_csr;
72 	u_int32_t mon_1;
73 	u_int32_t mon_data;
74 };
75 
76 int nextkbd_match __P((struct device *, struct cfdata *, void *));
77 void nextkbd_attach __P((struct device *, struct device *, void *));
78 
79 int nextkbc_cnattach __P((bus_space_tag_t));
80 
81 struct cfattach nextkbd_ca = {
82 	sizeof(struct nextkbd_softc), nextkbd_match, nextkbd_attach
83 };
84 
85 int	nextkbd_enable __P((void *, int));
86 void	nextkbd_set_leds __P((void *, int));
87 int	nextkbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
88 
89 const struct wskbd_accessops nextkbd_accessops = {
90 	nextkbd_enable,
91 	nextkbd_set_leds,
92 	nextkbd_ioctl,
93 };
94 
95 void	nextkbd_cngetc __P((void *, u_int *, int *));
96 void	nextkbd_cnpollc __P((void *, int));
97 
98 const struct wskbd_consops nextkbd_consops = {
99 	nextkbd_cngetc,
100 	nextkbd_cnpollc,
101 };
102 
103 const struct wskbd_mapdata nextkbd_keymapdata = {
104 	nextkbd_keydesctab,
105 	KB_US,
106 };
107 
108 static int nextkbd_read_data __P((struct nextkbd_internal *));
109 static int nextkbd_decode __P((struct nextkbd_internal *, int, u_int *, int *));
110 
111 static struct nextkbd_internal nextkbd_consdata;
112 static int nextkbd_is_console __P((bus_space_tag_t bst));
113 
114 int nextkbdhard __P((void *));
115 
116 static int
117 nextkbd_is_console(bst)
118 	bus_space_tag_t bst;
119 {
120 	return (nextkbd_consdata.isconsole
121 			&& (bst == nextkbd_consdata.iot));
122 }
123 
124 int
125 nextkbd_match(parent, match, aux)
126 	struct device *parent;
127 	struct cfdata *match;
128 	void *aux;
129 {
130 	return 1;
131 }
132 
133 void
134 nextkbd_attach(parent, self, aux)
135 	struct device *parent, *self;
136 	void *aux;
137 {
138 	struct nextkbd_softc *sc = (struct nextkbd_softc *)self;
139 	int isconsole;
140 	struct wskbddev_attach_args a;
141 
142 	printf("\n");
143 
144 	isconsole = nextkbd_is_console(NEXT68K_INTIO_BUS_SPACE); /* XXX */
145 
146 	if (isconsole) {
147 		sc->id = &nextkbd_consdata;
148 	} else {
149 		sc->id = malloc(sizeof(struct nextkbd_internal),
150 				M_DEVBUF, M_WAITOK);
151 
152 		memset(sc->id, 0, sizeof(struct nextkbd_internal));
153 		sc->id->iot = NEXT68K_INTIO_BUS_SPACE;
154 		if (bus_space_map(sc->id->iot, NEXT_P_MON,
155 				sizeof(struct mon_regs),
156 				0, &sc->id->ioh)) {
157 			printf("%s: can't map mon status control register\n",
158 					sc->sc_dev.dv_xname);
159 			return;
160 		}
161 	}
162 
163 	sc->id->t_sc = sc; /* set back pointer */
164 
165 	isrlink_autovec(nextkbdhard, sc, NEXT_I_IPL(NEXT_I_KYBD_MOUSE), 0);
166 
167 	INTR_ENABLE(NEXT_I_KYBD_MOUSE);
168 
169 	a.console = isconsole;
170 	a.keymap = &nextkbd_keymapdata;
171 	a.accessops = &nextkbd_accessops;
172 	a.accesscookie = sc;
173 
174 	/*
175 	 * Attach the wskbd, saving a handle to it.
176 	 * XXX XXX XXX
177 	 */
178 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
179 }
180 
181 int
182 nextkbd_enable(v, on)
183 	void *v;
184 	int on;
185 {
186 	/* XXX not sure if this should do anything */
187 	/* printf("nextkbd_enable %d\n", on); */
188 	return 0;
189 }
190 
191 /* XXX not yet implemented */
192 void
193 nextkbd_set_leds(v, leds)
194 	void *v;
195 	int leds;
196 {
197 	return;
198 }
199 
200 int
201 nextkbd_ioctl(v, cmd, data, flag, p)
202 	void *v;
203 	u_long cmd;
204 	caddr_t data;
205 	int flag;
206 	struct proc *p;
207 {
208 	/* XXX struct nextkbd_softc *nc = v; */
209 
210 	switch (cmd) {
211 	case WSKBDIO_GTYPE:
212 		/* XXX */
213 		*(int *)data = WSKBD_TYPE_NEXT;
214 		return (0);
215 	case WSKBDIO_SETLEDS:
216 		return (0);
217 	case WSKBDIO_GETLEDS:
218 		*(int *)data = 0;
219 		return (0);
220 	case WSKBDIO_COMPLEXBELL:
221 		return (0);
222 	}
223 	return EPASSTHROUGH;
224 }
225 
226 int
227 nextkbdhard(arg)
228 	void *arg;
229 {
230 	register struct nextkbd_softc *sc = arg;
231 	int type, key, val;
232 
233 	if (!INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) return 0;
234 
235 #define CSR_INT 0x00800000
236 #define CSR_DATA 0x00400000
237 
238 #define KD_KEYMASK			0x007f
239 #define KD_DIRECTION		0x0080 /* pressed or released */
240 #define KD_CNTL					0x0100
241 #define KD_LSHIFT				0x0200
242 #define KD_RSHIFT				0x0400
243 #define KD_LCOMM				0x0800
244 #define KD_RCOMM				0x1000
245 #define KD_LALT					0x2000
246 #define KD_RALT					0x4000
247 #define KD_VALID				0x8000 /* only set for scancode keys ? */
248 #define KD_MODS					0x4f00
249 
250 	val = nextkbd_read_data(sc->id);
251 	if ((val != -1) && nextkbd_decode(sc->id, val, &type, &key)) {
252 		wskbd_input(sc->sc_wskbddev, type, key);
253 	}
254 	return(1);
255 }
256 
257 int
258 nextkbd_cnattach(bst)
259 	bus_space_tag_t bst;
260 {
261 	bus_space_handle_t bsh;
262 
263 	if (bus_space_map(bst, NEXT_P_MON, sizeof(struct mon_regs),
264 			0, &bsh))
265 		return (ENXIO);
266 
267 	memset(&nextkbd_consdata, 0, sizeof(nextkbd_consdata));
268 
269 	nextkbd_consdata.iot = bst;
270 	nextkbd_consdata.ioh = bsh;
271 	nextkbd_consdata.isconsole = 1;
272 
273 	wskbd_cnattach(&nextkbd_consops, &nextkbd_consdata,
274 			&nextkbd_keymapdata);
275 
276 	return (0);
277 }
278 
279 void
280 nextkbd_cngetc(v, type, data)
281 	void *v;
282 	u_int *type;
283 	int *data;
284 {
285 	struct nextkbd_internal *t = v;
286 	int val;
287 
288 	for (;;) {
289 		if (INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) {
290 			val = nextkbd_read_data(t);
291 			if ((val != -1) && nextkbd_decode(t, val, type, data))
292 				return;
293 		}
294 	}
295 }
296 
297 void
298 nextkbd_cnpollc(v, on)
299 	void *v;
300 	int on;
301 {
302 	struct nextkbd_internal *t = v;
303 
304 	t->polling = on;
305 	if (on) {
306 		INTR_DISABLE(NEXT_I_KYBD_MOUSE);
307 	} else {
308 		INTR_ENABLE(NEXT_I_KYBD_MOUSE);
309 	}
310 
311 }
312 
313 static int
314 nextkbd_read_data(struct nextkbd_internal *id)
315 {
316 	unsigned char device;
317 	struct mon_regs stat;
318 
319 	bus_space_read_region_4(id->iot, id->ioh, 0, &stat, 3);
320 	if ((stat.mon_csr & CSR_INT) && (stat.mon_csr & CSR_DATA)) {
321 		stat.mon_csr &= ~CSR_INT;
322 		id->num_ints++;
323 		bus_space_write_4(id->iot, id->ioh, 0, stat.mon_csr);
324 		device = stat.mon_data >> 28;
325 		if (device != 1) return (-1); /* XXX: mouse */
326 		return (stat.mon_data & 0xffff);
327 	}
328 	return (-1);
329 }
330 
331 static int
332 nextkbd_decode(id, datain, type, dataout)
333 	struct nextkbd_internal *id;
334 	int datain;
335 	u_int *type;
336 	int *dataout;
337 {
338 	/* printf("datain %08x mods %08x\n", datain, id->mods); */
339 
340 	if ((datain ^ id->mods) & KD_LSHIFT) {
341 		id->mods ^= KD_LSHIFT;
342 		*dataout = 90;
343 		if (datain & KD_LSHIFT)
344 			*type = WSCONS_EVENT_KEY_DOWN;
345 		else
346 			*type = WSCONS_EVENT_KEY_UP;
347 	} else if ((datain ^ id->mods) & KD_RSHIFT) {
348 		id->mods ^= KD_RSHIFT;
349 		*dataout = 91;
350 		if (datain & KD_RSHIFT)
351 			*type = WSCONS_EVENT_KEY_DOWN;
352 		else
353 			*type = WSCONS_EVENT_KEY_UP;
354 	} else if ((datain ^ id->mods) & KD_LALT) {
355 		id->mods ^= KD_LALT;
356 		*dataout = 92;
357 		if (datain & KD_LALT)
358 			*type = WSCONS_EVENT_KEY_DOWN;
359 		else
360 			*type = WSCONS_EVENT_KEY_UP;
361 	} else if ((datain ^ id->mods) & KD_RALT) {
362 		id->mods ^= KD_RALT;
363 		*dataout = 93;
364 		if (datain & KD_RALT)
365 			*type = WSCONS_EVENT_KEY_DOWN;
366 		else
367 			*type = WSCONS_EVENT_KEY_UP;
368 	} else if ((datain ^ id->mods) & KD_CNTL) {
369 		id->mods ^= KD_CNTL;
370 		*dataout = 94;
371 		if (datain & KD_CNTL)
372 			*type = WSCONS_EVENT_KEY_DOWN;
373 		else
374 			*type = WSCONS_EVENT_KEY_UP;
375 	} else if ((datain ^ id->mods) & KD_LCOMM) {
376 		id->mods ^= KD_LCOMM;
377 		*dataout = 95;
378 		if (datain & KD_LCOMM)
379 			*type = WSCONS_EVENT_KEY_DOWN;
380 		else
381 			*type = WSCONS_EVENT_KEY_UP;
382 	} else if ((datain ^ id->mods) & KD_RCOMM) {
383 		id->mods ^= KD_RCOMM;
384 		*dataout = 96;
385 		if (datain & KD_RCOMM)
386 			*type = WSCONS_EVENT_KEY_DOWN;
387 		else
388 			*type = WSCONS_EVENT_KEY_UP;
389 	} else if (datain & KD_KEYMASK) {
390 		if (datain & KD_DIRECTION)
391 			*type = WSCONS_EVENT_KEY_UP;
392 		else
393 			*type = WSCONS_EVENT_KEY_DOWN;
394 
395 		*dataout = (datain & KD_KEYMASK);
396 	} else {
397 		*dataout = 0;
398 	}
399 
400 	return 1;
401 }
402