xref: /netbsd/sys/arch/dreamcast/dev/maple/mkbd.c (revision c4a72b64)
1 /*	$NetBSD: mkbd.c,v 1.17 2002/11/15 13:30:21 itohy Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 Marcus Comstedt
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 Marcus Comstedt.
18  * 4. Neither the name of The NetBSD Foundation nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/fcntl.h>
38 #include <sys/poll.h>
39 #include <sys/select.h>
40 #include <sys/proc.h>
41 #include <sys/signalvar.h>
42 #include <sys/systm.h>
43 
44 #include "wskbd.h"
45 
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wskbdvar.h>
48 #include <dev/wscons/wsksymdef.h>
49 #include <dev/wscons/wsksymvar.h>
50 
51 #include <machine/cpu.h>
52 #include <machine/bus.h>
53 
54 #include <dreamcast/dev/maple/maple.h>
55 #include <dreamcast/dev/maple/mapleconf.h>
56 #include <dreamcast/dev/maple/mkbdvar.h>
57 #include <dreamcast/dev/maple/mkbdmap.h>
58 
59 /*
60  * Function declarations.
61  */
62 static	int mkbdmatch(struct device *, struct cfdata *, void *);
63 static	void mkbdattach(struct device *, struct device *, void *);
64 static	int mkbddetach(struct device *, int);
65 
66 int	mkbd_enable(void *, int);
67 void	mkbd_set_leds(void *, int);
68 int	mkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
69 
70 struct wskbd_accessops mkbd_accessops = {
71 	mkbd_enable,
72 	mkbd_set_leds,
73 	mkbd_ioctl,
74 };
75 
76 static void mkbd_intr(void *, struct maple_response *, int, int);
77 
78 void	mkbd_cngetc(void *, u_int *, int *);
79 void	mkbd_cnpollc(void *, int);
80 int	mkbd_cnattach(void);
81 
82 struct wskbd_consops mkbd_consops = {
83 	mkbd_cngetc,
84 	mkbd_cnpollc,
85 };
86 
87 struct wskbd_mapdata mkbd_keymapdata = {
88 	mkbd_keydesctab,
89 	KB_JP,
90 };
91 
92 static struct mkbd_softc *mkbd_console_softc;
93 
94 static int mkbd_is_console;
95 static int mkbd_console_initted;
96 
97 CFATTACH_DECL(mkbd, sizeof(struct mkbd_softc),
98     mkbdmatch, mkbdattach, mkbddetach, NULL);
99 
100 static int
101 mkbdmatch(struct device *parent, struct cfdata *cf, void *aux)
102 {
103 	struct maple_attach_args *ma = aux;
104 
105 	return (ma->ma_function == MAPLE_FN_KEYBOARD ? MAPLE_MATCH_FUNC : 0);
106 }
107 
108 static void
109 mkbdattach(struct device *parent, struct device *self, void *aux)
110 {
111 	struct mkbd_softc *sc = (struct mkbd_softc *) self;
112 	struct maple_attach_args *ma = aux;
113 #if NWSKBD > 0
114 	struct wskbddev_attach_args a;
115 #endif
116 	u_int32_t kbdtype;
117 
118 	sc->sc_parent = parent;
119 	sc->sc_unit = ma->ma_unit;
120 
121 	kbdtype = maple_get_function_data(ma->ma_devinfo,
122 	    MAPLE_FN_KEYBOARD) >> 24;
123 	switch (kbdtype) {
124 	case 1:
125 		printf(": Japanese keyboard");
126 		mkbd_keymapdata.layout = KB_JP;
127 		break;
128 	case 2:
129 		printf(": US keyboard");
130 		mkbd_keymapdata.layout = KB_US;
131 		break;
132 	case 3:
133 		printf(": European keyboard");
134 		mkbd_keymapdata.layout = KB_UK;
135 		break;
136 	default:
137 		printf(": Unknown keyboard %d", kbdtype);
138 	}
139 	printf("\n");
140 
141 #if NWSKBD > 0
142 	if ((a.console = mkbd_is_console) != 0) {
143 		mkbd_is_console = 0;
144 		if (!mkbd_console_initted)
145 			wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata);
146 		mkbd_console_softc = sc;
147 	}
148 	a.keymap = &mkbd_keymapdata;
149 	a.accessops = &mkbd_accessops;
150 	a.accesscookie = sc;
151 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
152 #endif
153 
154 	maple_set_callback(parent, sc->sc_unit, MAPLE_FN_KEYBOARD,
155 	    mkbd_intr, sc);
156 	maple_enable_periodic(parent, sc->sc_unit, MAPLE_FN_KEYBOARD, 1);
157 }
158 
159 static int
160 mkbddetach(struct device *self, int flags)
161 {
162 	struct mkbd_softc *sc = (struct mkbd_softc *) self;
163 	int rv = 0;
164 
165 	if (sc == mkbd_console_softc) {
166 		/*
167 		 * Hack to allow another Maple keyboard to be new console.
168 		 * XXX Should some other type device can be console.
169 		 */
170 		printf("%s: was console keyboard\n", sc->sc_dev.dv_xname);
171 		wskbd_cndetach();
172 		mkbd_console_softc = NULL;
173 		mkbd_console_initted = 0;
174 		mkbd_is_console = 1;
175 	}
176 	if (sc->sc_wskbddev)
177 		rv = config_detach(sc->sc_wskbddev, flags);
178 
179 	return rv;
180 }
181 
182 int
183 mkbd_enable(void *v, int on)
184 {
185 
186 	return (0);
187 }
188 
189 void
190 mkbd_set_leds(void *v, int on)
191 {
192 }
193 
194 int
195 mkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
196 {
197 
198 	switch (cmd) {
199 	case WSKBDIO_GTYPE:
200 		*(int *) data = WSKBD_TYPE_USB;	/* XXX */
201 		return (0);
202 	case WSKBDIO_SETLEDS:
203 		return (0);
204 	case WSKBDIO_GETLEDS:
205 		*(int *) data = 0;
206 		return (0);
207 	case WSKBDIO_BELL:
208 	case WSKBDIO_COMPLEXBELL:
209 		return (0);
210 	}
211 
212 	return (EPASSTHROUGH);
213 }
214 
215 int
216 mkbd_cnattach()
217 {
218 
219 	wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata);
220 	mkbd_console_initted = 1;
221 	mkbd_is_console = 1;
222 
223 	return (0);
224 }
225 
226 static int polledkey;
227 extern int maple_polling;
228 
229 #define SHIFT_KEYCODE_BASE 0xe0
230 #define UP_KEYCODE_FLAG 0x1000
231 
232 #define KEY_UP(n) do {							\
233 	if (maple_polling)						\
234 		polledkey = (n)|UP_KEYCODE_FLAG;			\
235 	else								\
236 		wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_UP, (n));	\
237 	} while (/*CONSTCOND*/0)
238 
239 #define KEY_DOWN(n) do {						\
240 	if (maple_polling)						\
241 		polledkey = (n);					\
242 	else								\
243 		wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, (n)); \
244 	} while (/*CONSTCOND*/0)
245 
246 #define SHIFT_UP(n)	KEY_UP((n) | SHIFT_KEYCODE_BASE)
247 #define SHIFT_DOWN(n)	KEY_DOWN((n) | SHIFT_KEYCODE_BASE)
248 
249 static void
250 mkbd_intr(void *arg, struct maple_response *response, int sz, int flags)
251 {
252 	struct mkbd_softc *sc = arg;
253 	struct mkbd_condition *kbddata = (void *) response->data;
254 
255 	if ((flags & MAPLE_FLAG_PERIODIC) &&
256 	    sz >= sizeof(struct mkbd_condition)) {
257 		int i, j, v;
258 
259 		v = sc->sc_condition.shift & ~kbddata->shift;
260 		if (v)
261 			for (i = 0; i < 8; i++)
262 				if (v & (1 << i))
263 					SHIFT_UP(i);
264 
265 		v = kbddata->shift & ~sc->sc_condition.shift;
266 		if (v)
267 			for (i = 0; i < 8; i++)
268 				if (v & (1 << i))
269 					SHIFT_DOWN(i);
270 
271 		for (i = 0, j = 0; i < 6; i++)
272 			if (sc->sc_condition.key[i] < 4)
273 				break;
274 			else if (sc->sc_condition.key[i] == kbddata->key[j])
275 				j++;
276 			else
277 				KEY_UP(sc->sc_condition.key[i]);
278 
279 		for (; j < 6; j++)
280 			if (kbddata->key[j] < 4)
281 				break;
282 			else
283 				KEY_DOWN(kbddata->key[j]);
284 
285 		memcpy(&sc->sc_condition, kbddata,
286 		    sizeof(struct mkbd_condition));
287 	}
288 }
289 
290 void
291 mkbd_cngetc(void *v, u_int *type, int *data)
292 {
293 	int key;
294 
295 	polledkey = -1;
296 	maple_polling = 1;
297 	while (polledkey == -1) {
298 		if (mkbd_console_softc != NULL ||
299 		    mkbd_console_softc->sc_parent != NULL) {
300 			int t;
301 			for (t = 0; t < 1000000; t++);
302 			maple_run_polling(mkbd_console_softc->sc_parent);
303 		}
304 	}
305 	maple_polling = 0;
306 	key = polledkey;
307 
308 	*data = key & ~UP_KEYCODE_FLAG;
309 	*type = (key & UP_KEYCODE_FLAG) ?
310 	    WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
311 }
312 
313 void
314 mkbd_cnpollc(void *v, int on)
315 {
316 }
317