dtkbd.c revision 1.9
1/*	$NetBSD: dtkbd.c,v 1.9 2011/06/04 01:37:36 tsutsui Exp $	*/
2
3/*-
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: dtkbd.c,v 1.9 2011/06/04 01:37:36 tsutsui Exp $");
34
35#include "locators.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/device.h>
40#include <sys/ioctl.h>
41#include <sys/callout.h>
42
43#include <dev/wscons/wsconsio.h>
44#include <dev/wscons/wskbdvar.h>
45#include <dev/wscons/wsksymdef.h>
46#include <dev/wscons/wsksymvar.h>
47#include <dev/dec/wskbdmap_lk201.h>
48#include <dev/tc/tcvar.h>
49
50#include <machine/bus.h>
51
52#include <pmax/tc/dtreg.h>
53#include <pmax/tc/dtvar.h>
54
55#include <pmax/pmax/cons.h>
56
57struct dtkbd_softc {
58	device_t	sc_dev;
59	device_t	sc_wskbddev;
60	int		sc_enabled;
61};
62
63int	dtkbd_match(device_t, cfdata_t, void *);
64void	dtkbd_attach(device_t, device_t, void *);
65int	dtkbd_enable(void *, int);
66int	dtkbd_ioctl(void *, u_long, void *, int, struct lwp *);
67void	dtkbd_cngetc(void *, u_int *, int *);
68void	dtkbd_cnpollc(void *, int);
69int	dtkbd_process_msg(struct dt_msg *, u_int *, int *);
70void	dtkbd_handler(void *, struct dt_msg *);
71void	dtkbd_set_leds(void *, int);
72
73const struct wskbd_accessops dtkbd_accessops = {
74	dtkbd_enable,
75	dtkbd_set_leds,
76	dtkbd_ioctl,
77};
78
79const struct wskbd_consops dtkbd_consops = {
80	dtkbd_cngetc,
81	dtkbd_cnpollc,
82};
83
84CFATTACH_DECL_NEW(dtkbd, sizeof(struct dtkbd_softc),
85    dtkbd_match, dtkbd_attach, NULL, NULL);
86
87const struct wskbd_mapdata dtkbd_keymapdata = {
88	lkkbd_keydesctab,
89#ifdef DTKBD_LAYOUT
90	DTKBD_LAYOUT,
91#else
92	KB_US | KB_LK401,
93#endif
94};
95
96int	dtkbd_isconsole;
97uint8_t	dtkbd_map[10];
98int	dtkbd_maplen;
99
100int
101dtkbd_match(device_t parent, cfdata_t cf, void *aux)
102{
103	struct dt_attach_args *dta;
104
105	dta = aux;
106	return (dta->dta_addr == DT_ADDR_KBD);
107}
108
109void
110dtkbd_attach(device_t parent, device_t self, void *aux)
111{
112	struct dt_softc *dt;
113	struct dtkbd_softc *sc;
114	struct wskbddev_attach_args a;
115
116	dt = device_private(parent);
117	sc = device_private(self);
118	sc->sc_dev = self;
119
120	printf("\n");
121
122	if (dt_establish_handler(dt, &dt_kbd_dv, sc, dtkbd_handler)) {
123		printf("%s: unable to establish handler\n", device_xname(self));
124		return;
125	}
126
127	sc->sc_enabled = 1;
128
129	a.console = dtkbd_isconsole;
130	a.keymap = &dtkbd_keymapdata;
131	a.accessops = &dtkbd_accessops;
132	a.accesscookie = sc;
133	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
134}
135
136void
137dtkbd_cnattach(void)
138{
139
140	dtkbd_isconsole = 1;
141	dt_cninit();
142
143	wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata);
144}
145
146int
147dtkbd_enable(void *v, int on)
148{
149	struct dtkbd_softc *sc;
150
151	sc = v;
152	sc->sc_enabled = on;
153
154	return (0);
155}
156
157void
158dtkbd_cngetc(void *v, u_int *type, int *data)
159{
160	struct dt_msg msg;
161	static u_int types[20];
162	static int cnt, i, vals[20];
163
164	while (i >= cnt) {
165		for (;;) {
166			if (dt_msg_get(&msg, 0) == DT_GET_DONE)
167				if (msg.src == dt_kbd_addr &&
168				    !DT_CTL_P(msg.ctl))
169					break;
170			DELAY(1000);
171		}
172
173		cnt = dtkbd_process_msg(&msg, types, vals);
174		i = 0;
175	}
176
177	*type = types[i++];
178	*data = vals[i++];
179}
180
181void
182dtkbd_cnpollc(void *v, int on)
183{
184
185	/* XXX */
186}
187
188int
189dtkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
190{
191	struct dtkbd_softc *sc;
192
193	sc = v;
194
195	switch (cmd) {
196	case WSKBDIO_GTYPE:
197		*(int *)data = WSKBD_TYPE_LK201;
198		return 0;
199	default:
200		/* XXX */
201		return (EPASSTHROUGH);
202	}
203}
204
205void
206dtkbd_set_leds(void *v, int state)
207{
208
209	/* XXX */
210}
211
212void
213dtkbd_handler(void *cookie, struct dt_msg *msg)
214{
215	struct dtkbd_softc *sc;
216	u_int types[20];
217	int i, cnt, vals[20];
218
219	sc = cookie;
220
221	if (!sc->sc_enabled)
222		return;
223
224	cnt = dtkbd_process_msg(msg, types, vals);
225	for (i = 0; i < cnt; i++)
226		wskbd_input(sc->sc_wskbddev, types[i], vals[i]);
227}
228
229int
230dtkbd_process_msg(struct dt_msg *msg, u_int *types, int *vals)
231{
232	u_int len, c, count;
233	int i, j;
234
235	len = DT_CTL_LEN(msg->ctl);
236
237	if ((msg->body[0] < DT_KBD_KEY_MIN && msg->body[0] != DT_KBD_EMPTY) ||
238	    len > 10) {
239		printf("dtkbd0: error: %x %x %x\n", len, msg->body[0],
240		    msg->body[1]);
241
242		/*
243		 * Fake an "all ups" to avoid the stuck key syndrome.
244		 */
245		msg->body[0] = DT_KBD_EMPTY;
246		len = 1;
247	}
248
249	if (msg->body[0] == DT_KBD_EMPTY) {
250		types[0] = WSCONS_EVENT_ALL_KEYS_UP;
251		vals[0] = 0;
252		dtkbd_maplen = 0;
253		return (1);
254	}
255
256	count = 0;
257
258	for (i = 0; i < len; i++) {
259		c = msg->body[i];
260
261		for (j = 0; j < dtkbd_maplen; j++)
262			if (dtkbd_map[j] == c)
263				break;
264
265		if (j == dtkbd_maplen) {
266			types[count] = WSCONS_EVENT_KEY_DOWN;
267			vals[count] = c - MIN_LK201_KEY;
268			count++;
269		}
270	}
271
272	for (j = 0; j < dtkbd_maplen; j++) {
273		c = dtkbd_map[j];
274
275		for (i = 0; i < len; i++)
276			if (msg->body[i] == c)
277				break;
278
279		if (i == len) {
280			types[count] = WSCONS_EVENT_KEY_UP;
281			vals[count] = c - MIN_LK201_KEY;
282			count++;
283		}
284	}
285
286	memcpy(dtkbd_map, msg->body, len);
287	dtkbd_maplen = len;
288
289	return (count);
290}
291