vrkiu.c revision 1.26 1 /* $NetBSD: vrkiu.c,v 1.26 2001/02/22 18:38:05 uch Exp $ */
2
3 /*-
4 * Copyright (c) 1999 SASAKI Takesi All rights reserved.
5 * Copyright (c) 1999,2000 TAKEMRUA, Shin All rights reserved.
6 * Copyright (c) 1999 PocketBSD Project. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the PocketBSD project
19 * and its contributors.
20 * 4. Neither the name of the project nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 */
37
38 #include <sys/param.h>
39 #include <sys/tty.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/conf.h>
43 #include <sys/kernel.h>
44 #include <sys/proc.h>
45
46 #include <machine/intr.h>
47 #include <machine/cpu.h>
48 #include <machine/bus.h>
49 #include <machine/platid.h>
50 #include <machine/platid_mask.h>
51
52 #include <hpcmips/vr/vr.h>
53 #include <hpcmips/vr/vripvar.h>
54 #include <hpcmips/vr/vrkiuvar.h>
55 #include <hpcmips/vr/vrkiureg.h>
56 #include <hpcmips/vr/icureg.h>
57 #include <dev/hpc/hpckbdvar.h>
58
59 #include "opt_wsdisplay_compat.h"
60 #include "opt_pckbd_layout.h"
61 #include <dev/wscons/wsconsio.h>
62 #include <dev/wscons/wskbdvar.h>
63 #include <dev/wscons/wsksymdef.h>
64 #include <dev/wscons/wsksymvar.h>
65 #include <dev/pckbc/wskbdmap_mfii.h>
66 #ifdef WSDISPLAY_COMPAT_RAWKBD
67 #include <dev/hpc/pckbd_encode.h>
68 #endif
69
70 #define VRKIUDEBUG
71 #ifdef VRKIUDEBUG
72 int vrkiu_debug = 0;
73 #define DPRINTF(arg) if (vrkiu_debug) printf arg;
74 #else
75 #define DPRINTF(arg)
76 #endif
77
78 /*
79 * structure and data types
80 */
81 struct vrkiu_chip {
82 bus_space_tag_t kc_iot;
83 bus_space_handle_t kc_ioh;
84 unsigned short kc_scandata[KIU_NSCANLINE/2];
85 int kc_enabled;
86 struct vrkiu_softc* kc_sc; /* back link */
87 struct hpckbd_ic_if kc_if;
88 struct hpckbd_if *kc_hpckbd;
89 };
90
91 struct vrkiu_softc {
92 struct device sc_dev;
93 struct vrkiu_chip *sc_chip;
94 struct vrkiu_chip sc_chip_body;
95 void *sc_handler;
96 };
97
98 /*
99 * function prototypes
100 */
101 static int vrkiumatch __P((struct device *, struct cfdata *, void *));
102 static void vrkiuattach __P((struct device *, struct device *, void *));
103
104 int vrkiu_intr __P((void *));
105
106 static int vrkiu_init(struct vrkiu_chip*, bus_space_tag_t, bus_space_handle_t);
107 static void vrkiu_write __P((struct vrkiu_chip *, int, unsigned short));
108 static unsigned short vrkiu_read __P((struct vrkiu_chip *, int));
109 static int vrkiu_is_console(bus_space_tag_t, bus_space_handle_t);
110 static void vrkiu_scan __P((struct vrkiu_chip *));
111 static int countbits(int);
112 static void eliminate_phantom_keys(struct vrkiu_chip*, unsigned short *);
113 static int vrkiu_poll __P((void*));
114 static int vrkiu_input_establish __P((void*, struct hpckbd_if*));
115
116 /*
117 * global/static data
118 */
119 struct cfattach vrkiu_ca = {
120 sizeof(struct vrkiu_softc), vrkiumatch, vrkiuattach
121 };
122
123 struct vrkiu_chip *vrkiu_consdata = NULL;
124
125 /*
126 * utilities
127 */
128 static inline void
129 vrkiu_write(chip, port, val)
130 struct vrkiu_chip *chip;
131 int port;
132 unsigned short val;
133 {
134 bus_space_write_2(chip->kc_iot, chip->kc_ioh, port, val);
135 }
136
137 static inline unsigned short
138 vrkiu_read(chip, port)
139 struct vrkiu_chip *chip;
140 int port;
141 {
142 return bus_space_read_2(chip->kc_iot, chip->kc_ioh, port);
143 }
144
145 static inline int
146 vrkiu_is_console(iot, ioh)
147 bus_space_tag_t iot;
148 bus_space_handle_t ioh;
149 {
150 if (vrkiu_consdata &&
151 vrkiu_consdata->kc_iot == iot &&
152 vrkiu_consdata->kc_ioh == ioh) {
153 return 1;
154 } else {
155 return 0;
156 }
157 }
158
159 /*
160 * initialize device
161 */
162 static int
163 vrkiu_init(chip, iot, ioh)
164 struct vrkiu_chip* chip;
165 bus_space_tag_t iot;
166 bus_space_handle_t ioh;
167 {
168 memset(chip, 0, sizeof(struct vrkiu_chip));
169 chip->kc_iot = iot;
170 chip->kc_ioh = ioh;
171 chip->kc_enabled = 0;
172
173 chip->kc_if.hii_ctx = chip;
174 chip->kc_if.hii_establish = vrkiu_input_establish;
175 chip->kc_if.hii_poll = vrkiu_poll;
176
177 /* set KIU */
178 vrkiu_write(chip, KIURST, 1); /* reset */
179 vrkiu_write(chip, KIUSCANLINE, 0); /* 96keys */
180 vrkiu_write(chip, KIUWKS, 0x18a4); /* XXX: scan timing! */
181 vrkiu_write(chip, KIUWKI, 450);
182 vrkiu_write(chip, KIUSCANREP, 0x8023);
183 /* KEYEN | STPREP = 2 | ATSTP | ATSCAN */
184
185 return 0;
186 }
187
188 /*
189 * probe
190 */
191 static int
192 vrkiumatch(parent, cf, aux)
193 struct device *parent;
194 struct cfdata *cf;
195 void *aux;
196 {
197 return 1;
198 }
199
200 /*
201 * attach
202 */
203 static void
204 vrkiuattach(parent, self, aux)
205 struct device *parent;
206 struct device *self;
207 void *aux;
208 {
209 struct vrkiu_softc *sc = (struct vrkiu_softc *)self;
210 struct vrip_attach_args *va = aux;
211 struct hpckbd_attach_args haa;
212 int isconsole;
213
214 bus_space_tag_t iot = va->va_iot;
215 bus_space_handle_t ioh;
216
217 if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
218 printf(": can't map bus space\n");
219 return;
220 }
221
222 isconsole = vrkiu_is_console(iot, ioh);
223 if (isconsole) {
224 sc->sc_chip = vrkiu_consdata;
225 } else {
226 sc->sc_chip = &sc->sc_chip_body;
227 vrkiu_init(sc->sc_chip, iot, ioh);
228 }
229 sc->sc_chip->kc_sc = sc;
230
231 if (!(sc->sc_handler =
232 vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY,
233 vrkiu_intr, sc))) {
234 printf (": can't map interrupt line.\n");
235 return;
236 }
237 /* Level2 register setting */
238 vrip_intr_setmask2(va->va_vc, sc->sc_handler, KIUINT_KDATRDY, 1);
239
240 printf("\n");
241
242 /* attach hpckbd */
243 haa.haa_ic = &sc->sc_chip->kc_if;
244 config_found(self, &haa, hpckbd_print);
245 }
246
247 int
248 vrkiu_intr(arg)
249 void *arg;
250 {
251 struct vrkiu_softc *sc = arg;
252
253 /* When key scan finisshed, this entry is called. */
254 #if 0
255 DPRINTF(("vrkiu_intr: intr=%x scan=%x\n",
256 vrkiu_read(sc->sc_chip, KIUINT) & 7,
257 vrkiu_read(sc->sc_chip, KIUSCANS) & KIUSCANS_SSTAT_MASK));
258 #endif
259
260 /*
261 * First, we must clear the interrupt register because
262 * vrkiu_scan() may takes long time if a bitmap screen
263 * scrolls up and it makes us to miss some key release
264 * event.
265 */
266 vrkiu_write(sc->sc_chip, KIUINT, 0x7); /* Clear all interrupt */
267
268 #if 1
269 /* just return if kiu is scanning keyboard. */
270 if ((vrkiu_read(sc->sc_chip, KIUSCANS) & KIUSCANS_SSTAT_MASK) ==
271 KIUSCANS_SSTAT_SCANNING)
272 return (0);
273 #endif
274 vrkiu_scan(sc->sc_chip);
275
276 return (0);
277 }
278
279 static int
280 countbits(d)
281 int d;
282 {
283 int i, n;
284
285 for (i = 0, n = 0; i < NBBY; i++)
286 if (d & (1 << i))
287 n++;
288 return n;
289 }
290
291 static void
292 eliminate_phantom_keys(chip, scandata)
293 struct vrkiu_chip* chip;
294 unsigned short *scandata;
295 {
296 unsigned char inkey[KIU_NSCANLINE], *prevkey, *reskey;
297 int i, j;
298 #ifdef VRKIUDEBUG
299 int modified = 0;
300 static int prevmod = 0;
301 #endif
302
303 reskey = (unsigned char *)scandata;
304 for (i = 0; i < KIU_NSCANLINE; i++)
305 inkey[i] = reskey[i];
306 prevkey = (unsigned char *)chip->kc_scandata;
307
308 for (i = 0; i < KIU_NSCANLINE; i++) {
309 if (countbits(inkey[i]) > 1) {
310 for (j = 0; j < KIU_NSCANLINE; j++) {
311 if (i != j && (inkey[i] & inkey[j])) {
312 #ifdef VRKIUDEBUG
313 modified = 1;
314 if (!prevmod) {
315 DPRINTF(("vrkiu_scan: %x:%02x->%02x",
316 i, inkey[i], prevkey[i]));
317 DPRINTF((" %x:%02x->%02x\n",
318 j, inkey[j], prevkey[j]));
319 }
320 #endif
321 reskey[i] = prevkey[i];
322 reskey[j] = prevkey[j];
323 }
324 }
325 }
326 }
327 #ifdef VRKIUDEBUG
328 prevmod = modified;
329 #endif
330 }
331
332 static void
333 vrkiu_scan(chip)
334 struct vrkiu_chip* chip;
335 {
336 int i, j, modified, mask;
337 unsigned short scandata[KIU_NSCANLINE/2];
338
339 if (!chip->kc_enabled)
340 return;
341
342 for (i = 0; i < KIU_NSCANLINE / 2; i++) {
343 scandata[i] = vrkiu_read(chip, KIUDATP + i * 2);
344 }
345 eliminate_phantom_keys(chip, scandata);
346
347 for (i = 0; i < KIU_NSCANLINE / 2; i++) {
348 modified = scandata[i] ^ chip->kc_scandata[i];
349 chip->kc_scandata[i] = scandata[i];
350 mask = 1;
351 for (j = 0; j < 16; j++, mask <<= 1) {
352 /*
353 * Simultaneous keypresses are resolved by registering
354 * the one with the lowest bit index first.
355 */
356 if (modified & mask) {
357 int key = i * 16 + j;
358 DPRINTF(("vrkiu_scan: %s(%d,%d)\n",
359 (scandata[i] & mask) ? "down" : "up",
360 i, j));
361 hpckbd_input(chip->kc_hpckbd,
362 (scandata[i] & mask), key);
363 }
364 }
365 }
366 }
367
368 /* called from bicons.c */
369 int
370 vrkiu_getc()
371 {
372 static int flag = 1;
373
374 /*
375 * XXX, currently
376 */
377 if (flag) {
378 flag = 0;
379 printf("%s(%d): vrkiu_getc() is not implemented\n",
380 __FILE__, __LINE__);
381 }
382 return 0;
383 }
384
385 /*
386 * hpckbd interface routines
387 */
388 int
389 vrkiu_input_establish(ic, kbdif)
390 void *ic;
391 struct hpckbd_if *kbdif;
392 {
393 struct vrkiu_chip *kc = ic;
394
395 /* save hpckbd interface */
396 kc->kc_hpckbd = kbdif;
397
398 kc->kc_enabled = 1;
399
400 return 0;
401 }
402
403 int
404 vrkiu_poll(ic)
405 void *ic;
406 {
407 struct vrkiu_chip *kc = ic;
408
409 #if 1
410 /* wait until kiu completes keyboard scan. */
411 while ((vrkiu_read(kc, KIUSCANS) & KIUSCANS_SSTAT_MASK) ==
412 KIUSCANS_SSTAT_SCANNING)
413 /* wait until kiu completes keyboard scan */;
414 #endif
415
416 vrkiu_scan(kc);
417
418 return 0;
419 }
420
421 /*
422 * console support routine
423 */
424 int
425 vrkiu_cnattach(iot, iobase)
426 bus_space_tag_t iot;
427 int iobase;
428 {
429 static struct vrkiu_chip vrkiu_consdata_body;
430 bus_space_handle_t ioh;
431
432 if (vrkiu_consdata) {
433 panic("vrkiu is already attached as the console");
434 }
435 if (bus_space_map(iot, iobase, 1, 0, &ioh)) {
436 printf("%s(%d): can't map bus space\n", __FILE__, __LINE__);
437 return -1;
438 }
439
440 if (vrkiu_init(&vrkiu_consdata_body, iot, ioh) != 0) {
441 DPRINTF(("%s(%d): vrkiu_init() failed\n", __FILE__, __LINE__));
442 return -1;
443 }
444 vrkiu_consdata = &vrkiu_consdata_body;
445
446 hpckbd_cnattach(&vrkiu_consdata_body.kc_if);
447
448 return (0);
449 }
450