1 /* $NetBSD: kbms_sbdio.c,v 1.8 2008/03/29 08:14:41 tsutsui Exp $ */
4 * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: kbms_sbdio.c,v 1.8 2008/03/29 08:14:41 tsutsui Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
39 #include <dev/wscons/wsconsio.h>
40 #include <dev/wscons/wskbdvar.h>
41 #include <dev/wscons/wsmousevar.h>
43 #include <dev/wscons/wsksymdef.h>
44 #include <dev/wscons/wsksymvar.h>
46 #include <dev/ic/z8530reg.h>
48 #include <machine/sbdiovar.h>
50 #include <ews4800mips/dev/ews4800keymap.h>
52 /* 85C30 keyboard, mouse driver */
55 volatile uint8_t *kbd_csr
;
56 volatile uint8_t *kbd_data
;
57 volatile uint8_t *mouse_csr
;
58 volatile uint8_t *mouse_data
;
61 enum { MOUSE_PACKET_LEN
= 5 };
64 struct device
*sc_wskbd
;
65 struct device
*sc_wsmouse
;
66 struct kbms_reg sc_reg
;
71 int8_t sc_mouse_buf
[MOUSE_PACKET_LEN
];
74 int kbms_sbdio_match(device_t
, cfdata_t
, void *);
75 void kbms_sbdio_attach(device_t
, device_t
, void *);
76 int kbms_sbdio_intr(void *);
78 CFATTACH_DECL_NEW(kbms_sbdio
, sizeof(struct kbms_softc
),
79 kbms_sbdio_match
, kbms_sbdio_attach
, NULL
, NULL
);
81 int kbd_enable(void *, int);
82 void kbd_set_leds(void *, int);
83 int kbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
85 int mouse_enable(void *);
86 void mouse_disable(void *);
87 int mouse_ioctl(void *, u_long
, void *, int, struct lwp
*);
89 bool kbd_init(struct kbms_softc
*);
90 bool kbd_reset(struct kbms_softc
*, int);
92 void mouse_init(struct kbms_softc
*);
94 void mouse_debug_print(u_int
, int, int);
97 int kbd_sbdio_cnattach(uint32_t, uint32_t);
98 void kbd_cngetc(void *, u_int
*, int *);
99 void kbd_cnpollc(void *, int);
101 static struct kbms_reg kbms_consreg
;
103 const struct wskbd_consops kbd_consops
= {
108 const struct wskbd_accessops kbd_accessops
= {
114 struct wskbd_mapdata kbd_keymapdata
= {
115 ews4800kbd_keydesctab
,
119 const struct wsmouse_accessops mouse_accessops
= {
125 #define KBMS_PCLK (9600 * 512)
129 kbms_sbdio_match(device_t parent
, cfdata_t cf
, void *aux
)
131 struct sbdio_attach_args
*sa
= aux
;
133 return strcmp(sa
->sa_name
, "zkbms") ? 0 : 1;
137 kbms_sbdio_attach(device_t parent
, device_t self
, void *aux
)
139 struct kbms_softc
*sc
= device_private(self
);
140 struct sbdio_attach_args
*sa
= aux
;
141 struct wsmousedev_attach_args ma
;
142 struct wskbddev_attach_args ka
;
143 struct kbms_reg
*reg
= &sc
->sc_reg
;
149 base
= (uint8_t *)MIPS_PHYS_TO_KSEG1(sa
->sa_addr1
);
150 reg
->kbd_csr
= base
+ 0x00; /* port B */
151 reg
->kbd_data
= base
+ 0x04;
152 reg
->mouse_csr
= base
+ 0x08; /* port A */
153 reg
->mouse_data
= base
+ 0x0c;
155 if (reg
->kbd_csr
== kbms_consreg
.kbd_csr
&&
156 reg
->kbd_data
== kbms_consreg
.kbd_data
)
161 ka
.keymap
= &kbd_keymapdata
;
162 ka
.accessops
= &kbd_accessops
;
163 ka
.accesscookie
= self
;
165 if (kbd_init(sc
) == false) {
166 printf("keyboard not connected\n");
170 sc
->sc_wskbd
= config_found(self
, &ka
, wskbddevprint
);
172 ma
.accessops
= &mouse_accessops
;
173 ma
.accesscookie
= self
;
175 if (sa
->sa_flags
== 0x0001)
177 sc
->sc_mouse_sig
= 0x80;
178 if (sc
->sc_flags
== 1) /* ER/TR?? */
179 sc
->sc_mouse_sig
= 0x88;
182 sc
->sc_wsmouse
= config_found(self
, &ma
, wsmousedevprint
);
184 intr_establish(sa
->sa_irq
, kbms_sbdio_intr
, self
);
188 kbms_sbdio_intr(void *arg
)
190 struct kbms_softc
*sc
= (void *)arg
;
191 struct kbms_reg
*reg
= &sc
->sc_reg
;
194 if (*reg
->kbd_csr
& ZSRR0_RX_READY
) {
196 wskbd_input(sc
->sc_wskbd
,
197 v
& 0x80 ? WSCONS_EVENT_KEY_UP
: WSCONS_EVENT_KEY_DOWN
,
201 while (*reg
->mouse_csr
& ZSRR0_RX_READY
) {
202 int8_t *buf
= sc
->sc_mouse_buf
;
204 if (((v
= *reg
->mouse_csr
) &
205 (ZSRR1_FE
| ZSRR1_DO
| ZSRR1_PE
)) != 0) {
206 /* Error occured. re-initialize */
207 printf("initialize mouse. error=%02x\n", v
);
210 v
= *reg
->mouse_data
;
211 if ((sc
->sc_mouse_cnt
== 0) &&
212 (v
& 0xf8) != sc
->sc_mouse_sig
) {
213 printf("missing first packet. reset. %x\n", v
);
217 buf
[sc
->sc_mouse_cnt
++] = v
;
219 if (sc
->sc_mouse_cnt
== MOUSE_PACKET_LEN
) {
222 buttons
= ~buf
[0] & 0x7;
223 if (sc
->sc_flags
== 0) {
224 u_int b1
= (buttons
& 0x1) << 2;
225 u_int b3
= (buttons
& 0x4) >> 2;
226 buttons
= (buttons
& 0x2) | b1
| b3
;
231 mouse_debug_print(buttons
, x
, y
);
233 wsmouse_input(sc
->sc_wsmouse
,
236 WSMOUSE_INPUT_DELTA
);
237 sc
->sc_mouse_cnt
= 0;
241 *reg
->mouse_csr
= ZSWR1_REQ_RX
| ZSWR1_RIE
| ZSWR1_RIE_FIRST
;
242 (void)*reg
->mouse_csr
;
248 #define __REG_WR(r, v) \
254 } while (/*CONSTCOND*/ 0)
257 kbd_init(struct kbms_softc
*sc
)
259 struct kbms_reg
*reg
= &sc
->sc_reg
;
260 volatile uint8_t *csr
= reg
->kbd_csr
;
262 int reset_retry
= 100;
265 __REG_WR(9, ZSWR9_B_RESET
);
267 __REG_WR(9, ZSWR9_MASTER_IE
| ZSWR9_NO_VECTOR
);
269 __REG_WR(4, ZSWR4_CLK_X16
| ZSWR4_ONESB
| ZSWR4_PARENB
);
270 __REG_WR(12, BPS_TO_TCONST(KBMS_PCLK
/ 16, 4800));
272 __REG_WR(5, ZSWR5_TX_8
| ZSWR5_RTS
);
273 __REG_WR(3, ZSWR3_RX_8
);
275 __REG_WR(11, ZSWR11_RXCLK_BAUD
| ZSWR11_TXCLK_BAUD
|
276 ZSWR11_TRXC_OUT_ENA
| ZSWR11_TRXC_BAUD
);
277 __REG_WR(14, ZSWR14_BAUD_FROM_PCLK
| ZSWR14_BAUD_ENA
);
279 __REG_WR(5, ZSWR5_TX_8
| ZSWR5_TX_ENABLE
);
280 __REG_WR(3, ZSWR3_RX_8
| ZSWR3_RX_ENABLE
);
282 } while (!kbd_reset(sc
, reset_retry
) && --retry
> 0);
285 printf("keyboard initialize failed.\n");
293 kbd_reset(struct kbms_softc
*sc
, int retry
)
295 #define __RETRY_LOOP(x, y) \
297 for (i = 0; (x) && (i < retry); i++) { \
303 } while (/*CONSTCOND*/ 0)
305 struct kbms_reg
*reg
= &sc
->sc_reg
;
306 volatile uint8_t *csr
= reg
->kbd_csr
;
307 volatile uint8_t *data
= reg
->kbd_data
;
308 volatile uint8_t dummy
;
310 __REG_WR(5, ZSWR5_DTR
| ZSWR5_TX_8
| ZSWR5_TX_ENABLE
);
312 __RETRY_LOOP(*csr
& ZSRR0_RX_READY
, dummy
= *data
);
314 __REG_WR(5, ZSWR5_TX_8
| ZSWR5_TX_ENABLE
| ZSWR5_RTS
);
315 __RETRY_LOOP((*csr
& ZSRR0_RX_READY
) == 0, 0);
317 __RETRY_LOOP((*csr
& (ZSRR1_FE
| ZSRR1_DO
| ZSRR1_PE
)) != 0, 0);
318 __RETRY_LOOP(*data
!= 0xa0, 0);
319 __RETRY_LOOP((*csr
& ZSRR0_RX_READY
) == 0, 0);
321 __RETRY_LOOP((*csr
& (ZSRR1_FE
| ZSRR1_DO
| ZSRR1_PE
)) != 0, 0);
322 __REG_WR(1, ZSWR1_RIE
);
325 (void)*reg
->kbd_data
;
329 printf("retry failed.\n");
334 mouse_init(struct kbms_softc
*sc
)
336 struct kbms_reg
*reg
= &sc
->sc_reg
;
337 volatile uint8_t *csr
= reg
->mouse_csr
;
338 volatile uint8_t *data
= reg
->mouse_data
;
339 uint8_t d
[] = { 0x02, 0x52, 0x53, 0x3b, 0x4d, 0x54, 0x2c, 0x36, 0x0d };
342 __REG_WR(9, ZSWR9_A_RESET
);
344 __REG_WR(9, ZSWR9_MASTER_IE
| ZSWR9_NO_VECTOR
);
346 __REG_WR(4, ZSWR4_CLK_X16
| ZSWR4_ONESB
);
347 if (sc
->sc_flags
& 0x1) {
348 __REG_WR(12, BPS_TO_TCONST(KBMS_PCLK
/ 16, 4800));
351 __REG_WR(12, BPS_TO_TCONST(KBMS_PCLK
/ 16, 1200));
354 __REG_WR(5, ZSWR5_DTR
| ZSWR5_TX_8
| ZSWR5_RTS
);
355 __REG_WR(3, ZSWR3_RX_8
);
357 __REG_WR(11, ZSWR11_RXCLK_BAUD
| ZSWR11_TXCLK_BAUD
|
358 ZSWR11_TRXC_OUT_ENA
| ZSWR11_TRXC_BAUD
);
359 __REG_WR(14, ZSWR14_BAUD_FROM_PCLK
);
361 __REG_WR(5, ZSWR5_DTR
| ZSWR5_TX_8
| ZSWR5_TX_ENABLE
);
362 __REG_WR(3, ZSWR3_RX_8
| ZSWR3_RX_ENABLE
);
364 if (sc
->sc_flags
& 0x1) {
365 for (i
= 0; i
< sizeof d
; i
++) {
366 while ((*csr
& ZSRR0_TX_READY
) == 0)
372 __REG_WR(1, ZSWR1_RIE
);
376 kbd_enable(void *arg
, int on
)
384 kbd_set_leds(void *arg
, int leds
)
386 struct kbms_softc
*sc
= arg
;
387 struct kbms_reg
*reg
= &sc
->sc_reg
;
390 if (leds
& WSKBD_LED_CAPS
)
391 *reg
->kbd_data
= 0x92;
393 *reg
->kbd_data
= 0x90;
397 kbd_ioctl(void *arg
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
399 struct kbms_softc
*sc
= arg
;
403 *(int *)data
= WSKBD_TYPE_EWS4800
;
405 case WSKBDIO_SETLEDS
:
406 kbd_set_leds(arg
, *(int *)data
);
408 case WSKBDIO_GETLEDS
:
409 *(int *)data
= sc
->sc_leds
;
412 case WSKBDIO_COMPLEXBELL
:
420 kbd_sbdio_cnattach(uint32_t csr
, uint32_t data
)
422 struct kbms_softc __softc
, *sc
;
423 struct kbms_reg
*reg
;
425 kbms_consreg
.kbd_csr
= (void *)csr
;
426 kbms_consreg
.kbd_data
= (void *)data
;
428 /* setup dummy softc for kbd_init() */
430 memset(sc
, 0, sizeof(struct kbms_softc
));
432 reg
->kbd_csr
= (void *)csr
;
433 reg
->kbd_data
= (void *)data
;
435 if (kbd_init(sc
) == false)
438 wskbd_cnattach(&kbd_consops
, &kbms_consreg
, &kbd_keymapdata
);
443 kbd_cngetc(void *arg
, u_int
*type
, int *data
)
445 struct kbms_reg
*reg
= (void *)arg
;
448 while ((*reg
->kbd_csr
& ZSRR0_RX_READY
) == 0)
451 *type
= v
& 0x80 ? WSCONS_EVENT_KEY_UP
: WSCONS_EVENT_KEY_DOWN
;
456 kbd_cnpollc(void *arg
, int on
)
458 static bool __polling
= false;
461 if (on
&& !__polling
) {
462 s
= splhigh(); /* Disable interrupt driven I/O */
464 } else if (!on
&& __polling
) {
466 splx(s
); /* Enable interrupt driven I/O */
471 mouse_enable(void *arg
)
479 mouse_disable(void *arg
)
486 mouse_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
494 mouse_debug_print(u_int buttons
, int x
, int y
)
496 #define MINMAX(x, min, max) \
497 ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
498 static int k
, __x
, __y
;
502 __x
= MINMAX(__x
+ x
, 0, FB_WIDTH
);
503 __y
= MINMAX(__y
+ y
, 0, FB_HEIGHT
);
504 *(uint8_t *)(fb
.fb_addr
+ __x
+ __y
* FB_LINEBYTES
) = 0xff;
506 sprintf(buf
, "%8d %8d", x
, y
);
507 for (i
= 0; i
< 64 && buf
[i
]; i
++)
508 fb_drawchar(480 + i
* 12, k
, buf
[i
]);
511 for (j
= 0x80; j
> 0; j
>>= 1, i
++) {
512 fb_drawchar(480 + i
* 12, k
, buttons
& j
? '|' : '.');