1 /* $NetBSD: arckbd.c,v 1.17 2009/02/14 10:20:55 bjh21 Exp $ */
3 * Copyright (c) 1998, 1999, 2000 Ben Harris
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * arckbd.c - Archimedes keyboard driver
33 * Most of the information used to write this driver came from the
34 * A3000 Technical Reference Manual (ISBN 1-85250-074-3).
36 * We keep a queue of one command in the softc for use by the receive
37 * interrupt handler in case it finds the KART is already transmitting
38 * a command (presumably as a consequence of a user request) when it
39 * wants to. I think this is safe in all cases, and it will never
40 * happen more than once at a time (I hope).
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: arckbd.c,v 1.17 2009/02/14 10:20:55 bjh21 Exp $");
46 #include <sys/param.h>
47 #include <sys/device.h>
48 #include <sys/errno.h>
49 #include <sys/ioctl.h>
50 #include <sys/malloc.h>
52 #include <sys/reboot.h> /* For bootverbose */
53 #include <sys/syslog.h>
54 #include <sys/systm.h>
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58 #include <machine/irq.h>
60 #include <dev/wscons/wsconsio.h>
61 #include <dev/wscons/wskbdvar.h>
62 #include <dev/wscons/wsksymdef.h>
63 #include <dev/wscons/wsmousevar.h>
65 #include <arch/acorn26/iobus/iocreg.h>
66 #include <arch/acorn26/iobus/iocvar.h>
67 #include <arch/acorn26/ioc/arckbdreg.h>
68 #include <arch/acorn26/ioc/arckbdvar.h>
78 /* #define ARCKBD_DEBUG */
81 AS_HRST
, AS_RAK1
, AS_RAK2
, /* reset protocol */
82 AS_IDLE
, /* idle, waiting for data */
83 AS_KDDA
, AS_KUDA
, AS_MDAT
/* Receiving two-byte message */
86 static const char *arckbd_statenames
[] = {
87 "hrst", "rak1", "rak2", "idle", "kdda", "kuda", "mdat"
90 static int arckbd_match(device_t parent
, cfdata_t cf
, void *aux
);
91 static void arckbd_attach(device_t parent
, device_t self
, void *aux
);
92 #if 0 /* XXX should be used */
93 static kbd_t
arckbd_pick_layout(int kbid
);
96 static int arckbd_rint(void *self
);
97 static int arckbd_xint(void *self
);
98 static void arckbd_mousemoved(device_t self
, int byte1
, int byte2
);
99 static void arckbd_keyupdown(device_t self
, int byte1
, int byte2
);
100 static int arckbd_send(device_t self
, int data
,
101 enum arckbd_state newstate
, int waitok
);
103 static int arckbd_enable(void *cookie
, int on
);
104 static int arckbd_led_encode(int);
105 static int arckbd_led_decode(int);
106 static void arckbd_set_leds(void *cookie
, int new_state
);
107 static int arckbd_ioctl(void *cookie
, u_long cmd
, void *data
, int flag
,
110 static void arckbd_getc(void *cookie
, u_int
*typep
, int *valuep
);
111 static void arckbd_pollc(void *cookie
, int poll
);
114 static int arcmouse_enable(void *cookie
);
115 static int arcmouse_ioctl(void *cookie
, u_long cmd
, void *data
, int flag
,
117 static void arcmouse_disable(void *cookie
);
119 struct arckbd_softc
{
121 bus_space_tag_t sc_bst
;
122 bus_space_handle_t sc_bsh
;
123 u_int sc_mouse_buttons
;
124 enum arckbd_state sc_state
;
127 struct device
*sc_wskbddev
;
128 struct device
*sc_wsmousedev
;
129 struct wskbd_mapdata sc_mapdata
;
130 int sc_cmdqueue
; /* Single-command queue */
131 enum arckbd_state sc_statequeue
;
137 struct irq_handler
*sc_xirq
;
139 struct irq_handler
*sc_rirq
;
142 rndsource_element_t sc_rnd_source
;
146 #define AKF_WANTKBD 0x01
147 #define AKF_WANTMOUSE 0x02
148 #define AKF_SENTRQID 0x04
149 #define AKF_SENTLEDS 0x08
150 #define AKF_POLLING 0x10
152 CFATTACH_DECL_NEW(arckbd
, sizeof(struct arckbd_softc
),
153 arckbd_match
, arckbd_attach
, NULL
, NULL
);
155 static struct wskbd_accessops arckbd_accessops
= {
156 arckbd_enable
, arckbd_set_leds
, arckbd_ioctl
160 static struct wskbd_consops arckbd_consops
= {
161 arckbd_getc
, arckbd_pollc
165 static struct wsmouse_accessops arcmouse_accessops
= {
166 arcmouse_enable
, arcmouse_ioctl
, arcmouse_disable
171 arckbd_match(device_t parent
, cfdata_t cf
, void *aux
)
174 /* Assume presence for now */
179 arckbd_attach(device_t parent
, device_t self
, void *aux
)
181 struct arckbd_softc
*sc
= device_private(self
);
182 struct ioc_attach_args
*ioc
= aux
;
184 bus_space_handle_t bsh
;
185 struct wskbddev_attach_args wskbdargs
;
186 struct wsmousedev_attach_args wsmouseargs
;
188 bst
= sc
->sc_bst
= ioc
->ioc_fast_t
;
189 bsh
= sc
->sc_bsh
= ioc
->ioc_fast_h
;
192 evcnt_attach_dynamic(&sc
->sc_rev
, EVCNT_TYPE_INTR
, NULL
,
193 device_xname(sc
->sc_dev
), "rx intr");
194 sc
->sc_rirq
= irq_establish(IOC_IRQ_SRX
, IPL_TTY
, arckbd_rint
, self
,
196 aprint_verbose("\n%s: interrupting at %s (rx)", device_xname(self
),
197 irq_string(sc
->sc_rirq
));
199 evcnt_attach_dynamic(&sc
->sc_xev
, EVCNT_TYPE_INTR
, NULL
,
200 device_xname(sc
->sc_dev
), "tx intr");
201 sc
->sc_xirq
= irq_establish(IOC_IRQ_STX
, IPL_TTY
, arckbd_xint
, self
,
203 irq_disable(sc
->sc_xirq
);
204 aprint_verbose(" and %s (tx)", irq_string(sc
->sc_xirq
));
206 /* Initialisation of IOC KART per IOC Data Sheet section 6.2.3. */
208 /* Set up IOC counter 3 */
209 /* k_BAUD = 1/((latch+1)*16) MHz */
210 ioc_counter_start(parent
, 3, 62500 / ARCKBD_BAUD
- 1);
212 /* Read from Rx register and discard. */
213 (void)bus_space_read_1(bst
, bsh
, 0);
215 /* Kick the keyboard into life */
216 arckbd_send(self
, ARCKBD_HRST
, AS_HRST
, 0);
218 sc
->sc_mapdata
= arckbd_mapdata_default
;
219 sc
->sc_mapdata
.layout
= KB_UK
; /* Reasonable default */
221 /* Attach the wskbd console */
222 arckbd_cnattach(self
);
227 rnd_attach_source(&sc
->sc_rnd_source
, device_xname(self
),
231 wskbdargs
.console
= 1; /* XXX FIXME */
232 wskbdargs
.keymap
= &sc
->sc_mapdata
;
233 wskbdargs
.accessops
= &arckbd_accessops
;
234 wskbdargs
.accesscookie
= sc
;
235 sc
->sc_wskbddev
= config_found_ia(self
, "wskbddev", &wskbdargs
, NULL
);
237 wsmouseargs
.accessops
= &arcmouse_accessops
;
238 wsmouseargs
.accesscookie
= sc
;
240 config_found_ia(self
, "wsmousedev", &wsmouseargs
, NULL
);
243 #if 0 /* XXX should be used */
245 arckbd_pick_layout(int kbid
)
249 for (i
= 0; arckbd_kbidtab
[i
].kbid
!= 0; i
++) {
250 if (arckbd_kbidtab
[i
].kbid
== kbid
)
251 return arckbd_kbidtab
[i
].layout
;
258 * We don't really _need_ a console keyboard before
259 * autoconfiguration's finished, so for now this function's written to
260 * be called from arckbd_attach. The console functions should still
261 * try not to rely on much, and perhaps one day we should make it
262 * happen in consinit instead.
266 arckbd_cnattach(device_t self
)
269 struct arckbd_softc
*sc
= device_private(self
);
271 wskbd_cnattach(&arckbd_consops
, sc
, &arckbd_mapdata_default
);
277 arckbd_getc(void *cookie
, u_int
*typep
, int *valuep
)
279 struct arckbd_softc
*sc
= cookie
;
282 if (!(sc
->sc_flags
& AKF_POLLING
))
283 panic("%s: arckbd_getc called with polling disabled",
284 device_xname(sc
->sc_dev
));
285 while (sc
->sc_poll_type
== 0) {
286 if (ioc_irq_status(IOC_IRQ_STX
))
287 arckbd_xint(sc
->sc_dev
);
288 if (ioc_irq_status(IOC_IRQ_SRX
))
289 arckbd_rint(sc
->sc_dev
);
292 *typep
= sc
->sc_poll_type
;
293 *valuep
= sc
->sc_poll_value
;
294 sc
->sc_poll_type
= 0;
295 sc
->sc_poll_value
= 0;
300 arckbd_pollc(void *cookie
, int poll
)
302 struct arckbd_softc
*sc
= cookie
;
307 sc
->sc_flags
|= AKF_POLLING
;
308 irq_disable(sc
->sc_rirq
);
309 irq_disable(sc
->sc_xirq
);
311 sc
->sc_flags
&= ~AKF_POLLING
;
312 irq_enable(sc
->sc_rirq
);
313 irq_enable(sc
->sc_xirq
);
320 arckbd_send(device_t self
, int data
, enum arckbd_state newstate
, int waitok
)
322 struct arckbd_softc
*sc
= device_private(self
);
324 bus_space_tag_t bst
= sc
->sc_bst
;
325 bus_space_handle_t bsh
= sc
->sc_bsh
;
329 while (!ioc_irq_status(IOC_IRQ_STX
))
330 if ((sc
->sc_flags
& AKF_POLLING
) == 0) {
331 res
= tsleep(arckbd_send
, PWAIT
, "kbdsend", 0);
335 } else if (!ioc_irq_status(IOC_IRQ_STX
)) {
336 if (sc
->sc_cmdqueued
)
337 panic("%s: queue overflow", device_xname(sc
->sc_dev
));
339 sc
->sc_cmdqueue
= data
;
340 sc
->sc_statequeue
= newstate
;
341 sc
->sc_cmdqueued
= 1;
345 bus_space_write_1(bst
, bsh
, 0, data
);
346 sc
->sc_state
= newstate
;
348 log(LOG_DEBUG
, "%s: sent 0x%02x. now in state %s\n",
349 device_xname(sc
->sc_dev
), data
, arckbd_statenames
[newstate
]);
351 wakeup(&sc
->sc_state
);
353 if ((sc
->sc_flags
& AKF_POLLING
) == 0)
354 irq_enable(sc
->sc_xirq
);
359 arckbd_xint(void *cookie
)
361 struct arckbd_softc
*sc
= device_private(cookie
);
363 irq_disable(sc
->sc_xirq
);
364 /* First, process queued commands (acks from the last receive) */
365 if (sc
->sc_cmdqueued
) {
366 sc
->sc_cmdqueued
= 0;
367 arckbd_send(sc
->sc_dev
, sc
->sc_cmdqueue
, sc
->sc_statequeue
, 0);
368 } else if (sc
->sc_state
== AS_IDLE
) {
369 /* Do things that need doing after a reset */
370 if (!(sc
->sc_flags
& AKF_SENTRQID
)) {
371 arckbd_send(sc
->sc_dev
, ARCKBD_RQID
, AS_IDLE
, 0);
372 sc
->sc_flags
|= AKF_SENTRQID
;
373 } else if (!(sc
->sc_flags
& AKF_SENTLEDS
)) {
374 arckbd_send(sc
->sc_dev
, ARCKBD_LEDS
| sc
->sc_leds
,
376 sc
->sc_flags
|= AKF_SENTLEDS
;
378 } else if ((sc
->sc_flags
& AKF_POLLING
) == 0)
379 wakeup(&arckbd_send
);
384 arckbd_rint(void *cookie
)
386 device_t self
= cookie
;
387 struct arckbd_softc
*sc
= device_private(self
);
388 bus_space_tag_t bst
= sc
->sc_bst
;
389 bus_space_handle_t bsh
= sc
->sc_bsh
;
392 data
= bus_space_read_1(bst
, bsh
, 0);
394 log(LOG_DEBUG
, "%s: got 0x%02x in state %s\n", device_xname(self
), data
,
395 arckbd_statenames
[sc
->sc_state
]);
398 if (data
== ARCKBD_HRST
&& sc
->sc_state
== AS_HRST
)
399 arckbd_send(self
, ARCKBD_RAK1
, AS_RAK1
, 0);
400 else if (data
== ARCKBD_RAK1
&&
401 (sc
->sc_state
== AS_RAK1
|| sc
->sc_state
== AS_HRST
))
402 arckbd_send(self
, ARCKBD_RAK2
, AS_RAK2
, 0);
403 else if (data
== ARCKBD_RAK2
&& sc
->sc_state
== AS_RAK2
)
404 arckbd_send(self
, ARCKBD_SMAK
, AS_IDLE
, 0);
407 * Note that for data messages, we acknowledge first and
408 * _then_ process the data. This is important because the
409 * processing may end up trying to use the keyboard in polled
410 * mode (e.g. through DDB) and we'd like its state to be
415 else if (ARCKBD_IS_MDAT(data
) && sc
->sc_state
== AS_IDLE
) {
416 arckbd_send(self
, ARCKBD_BACK
, AS_MDAT
, 0);
417 sc
->sc_byteone
= data
;
418 } else if (ARCKBD_IS_MDAT(data
) && sc
->sc_state
== AS_MDAT
) {
419 arckbd_send(self
, ARCKBD_SMAK
, AS_IDLE
, 0);
420 arckbd_mousemoved(self
, sc
->sc_byteone
, data
);
424 else if (ARCKBD_IS_KDDA(data
) && sc
->sc_state
== AS_IDLE
) {
425 arckbd_send(self
, ARCKBD_BACK
, AS_KDDA
, 0);
426 sc
->sc_byteone
= data
;
427 } else if (ARCKBD_IS_KDDA(data
) && sc
->sc_state
== AS_KDDA
) {
428 arckbd_send(self
, ARCKBD_SMAK
, AS_IDLE
, 0);
429 arckbd_keyupdown(self
, sc
->sc_byteone
, data
);
433 else if (ARCKBD_IS_KUDA(data
) && sc
->sc_state
== AS_IDLE
) {
434 arckbd_send(self
, ARCKBD_BACK
, AS_KUDA
, 0);
435 sc
->sc_byteone
= data
;
436 } else if (ARCKBD_IS_KUDA(data
) && sc
->sc_state
== AS_KUDA
) {
437 arckbd_send(self
, ARCKBD_SMAK
, AS_IDLE
, 0);
438 arckbd_keyupdown(self
, sc
->sc_byteone
, data
);
442 else if (ARCKBD_IS_KBID(data
)) {
443 arckbd_send(self
, ARCKBD_SMAK
, AS_IDLE
, 0);
444 if (sc
->sc_kbid
!= data
) {
445 printf("%s: layout %d\n",
446 device_xname(self
), data
& ~ARCKBD_KBID
);
449 } else if (ARCKBD_IS_PDAT(data
))
450 /* unused -- ignore it */;
453 log(LOG_WARNING
, "%s: protocol error: got 0x%02x in state %s\n",
454 device_xname(self
), data
, arckbd_statenames
[sc
->sc_state
]);
455 arckbd_send(self
, ARCKBD_HRST
, AS_HRST
, 0);
461 arckbd_mousemoved(device_t self
, int byte1
, int byte2
)
463 #if NRND > 0 || NWSMOUSE > 0
464 struct arckbd_softc
*sc
= device_private(self
);
468 rnd_add_uint32(&sc
->sc_rnd_source
, byte1
);
471 if (sc
->sc_wsmousedev
!= NULL
) {
474 /* deltas are 7-bit signed */
475 dx
= byte1
< 0x40 ? byte1
: byte1
- 0x80;
476 dy
= byte2
< 0x40 ? byte2
: byte2
- 0x80;
477 wsmouse_input(sc
->sc_wsmousedev
,
478 sc
->sc_mouse_buttons
,
480 WSMOUSE_INPUT_DELTA
);
486 arckbd_keyupdown(device_t self
, int byte1
, int byte2
)
488 struct arckbd_softc
*sc
= device_private(self
);
493 rnd_add_uint32(&sc
->sc_rnd_source
, byte1
);
495 if ((byte1
& 0x0f) == 7) {
496 /* Mouse button event */
498 * This is all very silly, as the wsmouse driver then
499 * differentiates the button state to see if there's
500 * an event worth passing to the user.
502 * Oh well, at least NetBSD and Acorn number their
503 * mouse buttons the same way.
505 if (ARCKBD_IS_KDDA(byte1
))
506 sc
->sc_mouse_buttons
|= (1 << (byte2
& 0x0f));
508 sc
->sc_mouse_buttons
&= ~(1 << (byte2
& 0x0f));
510 if (sc
->sc_wsmousedev
!= NULL
)
511 wsmouse_input(sc
->sc_wsmousedev
,
512 sc
->sc_mouse_buttons
,
514 WSMOUSE_INPUT_DELTA
);
517 type
= ARCKBD_IS_KDDA(byte1
) ?
518 WSCONS_EVENT_KEY_DOWN
: WSCONS_EVENT_KEY_UP
;
519 value
= ((byte1
& 0x0f) << 4) | (byte2
& 0x0f);
520 if (sc
->sc_flags
& AKF_POLLING
) {
521 sc
->sc_poll_type
= type
;
522 sc
->sc_poll_value
= value
;
525 else if (sc
->sc_wskbddev
!= NULL
)
526 wskbd_input(sc
->sc_wskbddev
, type
, value
);
532 * Keyboard access functions
536 arckbd_enable(void *cookie
, int on
)
538 struct arckbd_softc
*sc
= cookie
;
541 sc
->sc_flags
|= AKF_WANTKBD
;
544 sc
->sc_flags
&= ~ AKF_WANTKBD
;
549 arckbd_led_encode(int wsleds
)
554 if (wsleds
& WSKBD_LED_CAPS
)
555 arcleds
|= ARCKBD_LEDS_CAPSLOCK
;
556 if (wsleds
& WSKBD_LED_NUM
)
557 arcleds
|= ARCKBD_LEDS_NUMLOCK
;
558 if (wsleds
& WSKBD_LED_SCROLL
)
559 arcleds
|= ARCKBD_LEDS_SCROLLLOCK
;
560 /* No "compose" LED */
565 arckbd_led_decode(int arcleds
)
570 if (arcleds
& ARCKBD_LEDS_CAPSLOCK
)
571 wsleds
|= WSKBD_LED_CAPS
;
572 if (arcleds
& ARCKBD_LEDS_NUMLOCK
)
573 wsleds
|= WSKBD_LED_NUM
;
574 if (arcleds
& ARCKBD_LEDS_SCROLLLOCK
)
575 wsleds
|= WSKBD_LED_SCROLL
;
576 /* No "compose" LED */
581 * Set the LEDs to the requested state.
583 * Be warned: This function gets called from interrupts.
586 arckbd_set_leds(void *cookie
, int new_state
)
588 struct arckbd_softc
*sc
= cookie
;
592 sc
->sc_leds
= arckbd_led_encode(new_state
);
593 if (arckbd_send(sc
->sc_dev
, ARCKBD_LEDS
| sc
->sc_leds
, AS_IDLE
, 0) == 0)
594 sc
->sc_flags
|= AKF_SENTLEDS
;
600 arckbd_ioctl(void *cookie
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
602 struct arckbd_softc
*sc
= cookie
;
606 *(int *)data
= WSKBD_TYPE_ARCHIMEDES
;
608 case WSKBDIO_SETLEDS
:
609 arckbd_set_leds(sc
, *(int *)data
);
611 case WSKBDIO_GETLEDS
:
612 *(int *)data
= arckbd_led_decode(sc
->sc_leds
);
619 * Mouse access functions
623 arcmouse_enable(void *cookie
)
625 struct arckbd_softc
*sc
= cookie
;
627 sc
->sc_flags
|= AKF_WANTMOUSE
;
634 arcmouse_ioctl(void *cookie
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
636 /* struct arckbd_softc *sc = cookie; */
639 case WSMOUSEIO_GTYPE
:
640 *(int *)data
= WSMOUSE_TYPE_ARCHIMEDES
;
647 arcmouse_disable(void *cookie
)
649 struct arckbd_softc
*sc
= cookie
;
651 sc
->sc_flags
&= ~AKF_WANTMOUSE
;