dtkbd.c revision 1.8.32.1 1 /* $NetBSD: dtkbd.c,v 1.8.32.1 2011/06/23 14:19:27 cherry 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.8.32.1 2011/06/23 14:19:27 cherry 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
57 struct dtkbd_softc {
58 device_t sc_dev;
59 device_t sc_wskbddev;
60 int sc_enabled;
61 };
62
63 int dtkbd_match(device_t, cfdata_t, void *);
64 void dtkbd_attach(device_t, device_t, void *);
65 int dtkbd_enable(void *, int);
66 int dtkbd_ioctl(void *, u_long, void *, int, struct lwp *);
67 void dtkbd_cngetc(void *, u_int *, int *);
68 void dtkbd_cnpollc(void *, int);
69 int dtkbd_process_msg(struct dt_msg *, u_int *, int *);
70 void dtkbd_handler(void *, struct dt_msg *);
71 void dtkbd_set_leds(void *, int);
72
73 const struct wskbd_accessops dtkbd_accessops = {
74 dtkbd_enable,
75 dtkbd_set_leds,
76 dtkbd_ioctl,
77 };
78
79 const struct wskbd_consops dtkbd_consops = {
80 dtkbd_cngetc,
81 dtkbd_cnpollc,
82 };
83
84 CFATTACH_DECL_NEW(dtkbd, sizeof(struct dtkbd_softc),
85 dtkbd_match, dtkbd_attach, NULL, NULL);
86
87 const 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
96 int dtkbd_isconsole;
97 uint8_t dtkbd_map[10];
98 int dtkbd_maplen;
99
100 int
101 dtkbd_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
109 void
110 dtkbd_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
136 void
137 dtkbd_cnattach(void)
138 {
139
140 dtkbd_isconsole = 1;
141 dt_cninit();
142
143 wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata);
144 }
145
146 int
147 dtkbd_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
157 void
158 dtkbd_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
181 void
182 dtkbd_cnpollc(void *v, int on)
183 {
184
185 /* XXX */
186 }
187
188 int
189 dtkbd_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
205 void
206 dtkbd_set_leds(void *v, int state)
207 {
208
209 /* XXX */
210 }
211
212 void
213 dtkbd_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
229 int
230 dtkbd_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