1 /* $NetBSD: zs_kbd.c,v 1.7 2007/03/04 06:00:39 christos Exp $ */
4 * Copyright (c) 2004 Steve Rumble
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * IP12/IP20 serial keyboard driver attached to zs channel 0 at 600bps.
32 * This layer is the parent of wskbd.
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: zs_kbd.c,v 1.7 2007/03/04 06:00:39 christos Exp $");
38 #include <sys/param.h>
39 #include <sys/malloc.h>
40 #include <sys/systm.h>
42 #include <sys/device.h>
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wscons/wskbdvar.h>
46 #include <dev/wscons/wsksymdef.h>
47 #include <dev/wscons/wsksymvar.h>
49 #include <dev/ic/z8530reg.h>
50 #include <machine/machtype.h>
51 #include <machine/z8530var.h>
53 #define ZSKBD_BAUD 600
54 #define ZSKBD_TXQ_LEN 16 /* power of 2 */
55 #define ZSKBD_RXQ_LEN 64 /* power of 2 */
57 #define ZSKBD_DIP_SYNC 0x6E
58 #define ZSKBD_KEY_UP 0x80
63 #define DPRINTF(_x) if (zskbd_debug) printf _x
71 struct zskbd_devconfig
*sc_dc
;
74 struct zskbd_devconfig
{
75 /* transmit tail-chasing fifo */
76 uint8_t txq
[ZSKBD_TXQ_LEN
];
80 /* receive tail-chasing fifo */
81 uint8_t rxq
[ZSKBD_RXQ_LEN
];
90 /* keyboard configuration */
91 #define ZSKBD_CTRL_A 0x0
92 #define ZSKBD_CTRL_A_SBEEP 0x2 /* 200 ms */
93 #define ZSKBD_CTRL_A_LBEEP 0x4 /* 1000 ms */
94 #define ZSKBD_CTRL_A_NOCLICK 0x8 /* turn off keyboard click */
95 #define ZSKBD_CTRL_A_RCB 0x10 /* request config byte */
96 #define ZSKBD_CTRL_A_NUMLK 0x20 /* num lock led */
97 #define ZSKBD_CTRL_A_CAPSLK 0x40 /* caps lock led */
98 #define ZSKBD_CTRL_A_AUTOREP 0x80 /* auto-repeat after 650 ms, 28x/sec */
100 #define ZSKBD_CTRL_B 0x1
101 #define ZSKBD_CTRL_B_CMPL_DS1_2 0x2 /* complement of ds1+ds2 (num+capslk) */
102 #define ZSKBD_CTRL_B_SCRLK 0x4 /* scroll lock light */
103 #define ZSKBD_CTRL_B_L1 0x8 /* user-configurable lights */
104 #define ZSKBD_CTRL_B_L2 0x10
105 #define ZSKBD_CTRL_B_L3 0x20
106 #define ZSKBD_CTRL_B_L4 0x40
109 /* dip switch settings */
113 struct device
*wskbddev
;
117 static int zskbd_match(device_t
, cfdata_t
, void *);
118 static void zskbd_attach(device_t
, device_t
, void *);
119 static void zskbd_rxint(struct zs_chanstate
*);
120 static void zskbd_stint(struct zs_chanstate
*, int);
121 static void zskbd_txint(struct zs_chanstate
*);
122 static void zskbd_softint(struct zs_chanstate
*);
123 static void zskbd_send(struct zs_chanstate
*, uint8_t *, u_int
);
124 static void zskbd_ctrl(struct zs_chanstate
*, uint8_t, uint8_t,
127 static void zskbd_wskbd_input(struct zs_chanstate
*, uint8_t);
128 static int zskbd_wskbd_enable(void *, int);
129 static void zskbd_wskbd_set_leds(void *, int);
130 static int zskbd_wskbd_get_leds(void *);
131 static void zskbd_wskbd_set_keyclick(void *, int);
132 static int zskbd_wskbd_get_keyclick(void *);
133 static int zskbd_wskbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
135 void zskbd_cnattach(int, int);
136 static void zskbd_wskbd_getc(void *, u_int
*, int *);
137 static void zskbd_wskbd_pollc(void *, int);
138 static void zskbd_wskbd_bell(void *, u_int
, u_int
, u_int
);
140 extern struct zschan
*zs_get_chan_addr(int, int);
141 extern int zs_getc(void *);
142 extern void zs_putc(void *, int);
144 CFATTACH_DECL_NEW(zskbd
, sizeof(struct zskbd_softc
),
145 zskbd_match
, zskbd_attach
, NULL
, NULL
);
147 static struct zsops zskbd_zsops
= {
154 extern const struct wscons_keydesc wssgi_keydesctab
[];
155 const struct wskbd_mapdata sgikbd_wskbd_keymapdata
= {
156 wssgi_keydesctab
, KB_US
159 const struct wskbd_accessops zskbd_wskbd_accessops
= {
161 zskbd_wskbd_set_leds
,
165 const struct wskbd_consops zskbd_wskbd_consops
= {
171 static struct zskbd_devconfig zskbd_console_dc
;
172 static int zskbd_is_console
= 0;
175 zskbd_match(device_t parent
, cfdata_t cf
, void *aux
)
178 if (mach_type
== MACH_SGI_IP12
|| mach_type
== MACH_SGI_IP20
) {
179 struct zsc_attach_args
*args
= aux
;
181 if (args
->channel
== 0)
189 zskbd_attach(device_t parent
, device_t self
, void *aux
)
191 struct zskbd_softc
*sc
;
192 struct zs_chanstate
*cs
;
193 struct zsc_softc
*zsc
;
194 struct zsc_attach_args
*args
;
195 struct wskbddev_attach_args wskaa
;
198 zsc
= device_private(parent
);
199 sc
= device_private(self
);
203 /* Establish ourself with the MD z8530 driver */
204 channel
= args
->channel
;
205 cs
= zsc
->zsc_cs
[channel
];
206 cs
->cs_ops
= &zskbd_zsops
;
209 if (zskbd_is_console
) {
210 sc
->sc_dc
= &zskbd_console_dc
;
212 sc
->sc_dc
->enabled
= 1;
216 sc
->sc_dc
= malloc(sizeof(struct zskbd_devconfig
), M_DEVBUF
,
218 if (sc
->sc_dc
== NULL
)
219 panic("zskbd out of memory");
221 sc
->sc_dc
->enabled
= 0;
224 sc
->sc_dc
->txq_head
= 0;
225 sc
->sc_dc
->txq_tail
= 0;
226 sc
->sc_dc
->rxq_head
= 0;
227 sc
->sc_dc
->rxq_tail
= 0;
228 sc
->sc_dc
->state
= TX_READY
;
230 sc
->sc_dc
->kbd_conf
[ZSKBD_CTRL_A
] = 0;
231 sc
->sc_dc
->kbd_conf
[ZSKBD_CTRL_B
] = 0;
233 aprint_normal(": baud rate %d\n", ZSKBD_BAUD
);
236 zs_write_reg(cs
, 9, (channel
== 0) ? ZSWR9_A_RESET
: ZSWR9_B_RESET
);
237 cs
->cs_preg
[1] = ZSWR1_RIE
| ZSWR1_TIE
;
238 cs
->cs_preg
[4] = (cs
->cs_preg
[4] & ZSWR4_CLK_MASK
) |
239 (ZSWR4_ONESB
| ZSWR4_PARENB
); /* 1 stop, odd parity */
240 zs_set_speed(cs
, ZSKBD_BAUD
);
241 zs_loadchannelregs(cs
);
243 /* request DIP switch settings just in case */
244 zskbd_ctrl(cs
, ZSKBD_CTRL_A_RCB
, 0, 0, 0);
249 wskaa
.keymap
= &sgikbd_wskbd_keymapdata
;
250 wskaa
.accessops
= &zskbd_wskbd_accessops
;
251 wskaa
.accesscookie
= cs
;
252 sc
->sc_dc
->wskbddev
= config_found(self
, &wskaa
, wskbddevprint
);
256 zskbd_rxint(struct zs_chanstate
*cs
)
258 struct zskbd_softc
*sc
;
259 struct zskbd_devconfig
*dc
;
266 r
= zs_read_reg(cs
, 1);
267 if (r
& (ZSRR1_FE
| ZSRR1_DO
| ZSRR1_PE
))
268 zs_write_csr(cs
, ZSWR0_RESET_ERRORS
);
270 /* read byte and append to our queue */
271 c
= zs_read_data(cs
);
273 dc
->rxq
[dc
->rxq_tail
] = c
;
274 dc
->rxq_tail
= (dc
->rxq_tail
+ 1) & ~ZSKBD_RXQ_LEN
;
280 zskbd_stint(struct zs_chanstate
*cs
, int force
)
283 zs_write_csr(cs
, ZSWR0_RESET_STATUS
);
288 zskbd_txint(struct zs_chanstate
*cs
)
290 struct zskbd_softc
*sc
;
293 zs_write_reg(cs
, 0, ZSWR0_RESET_TXINT
);
294 sc
->sc_dc
->state
|= TX_READY
;
299 zskbd_softint(struct zs_chanstate
*cs
)
301 struct zskbd_softc
*sc
;
302 struct zskbd_devconfig
*dc
;
307 /* handle pending transmissions */
308 if (dc
->txq_head
!= dc
->txq_tail
&& (dc
->state
& TX_READY
)) {
311 dc
->state
&= ~TX_READY
;
314 zs_write_data(cs
, dc
->txq
[dc
->txq_head
]);
317 dc
->txq_head
= (dc
->txq_head
+ 1) & ~ZSKBD_TXQ_LEN
;
320 /* don't bother if nobody is listening */
322 dc
->rxq_head
= dc
->rxq_tail
;
326 /* handle incoming keystrokes/config */
327 while (dc
->rxq_head
!= dc
->rxq_tail
) {
328 uint8_t key
= dc
->rxq
[dc
->rxq_head
];
330 if (dc
->state
& RX_DIP
) {
332 dc
->state
&= ~RX_DIP
;
333 } else if (key
== ZSKBD_DIP_SYNC
) {
336 /* toss wskbd a bone */
337 zskbd_wskbd_input(cs
, key
);
340 dc
->rxq_head
= (dc
->rxq_head
+ 1) & ~ZSKBD_RXQ_LEN
;
344 /* expects to be in splzs() */
346 zskbd_send(struct zs_chanstate
*cs
, uint8_t *c
, u_int len
)
349 struct zskbd_softc
*sc
;
350 struct zskbd_devconfig
*dc
;
355 for (i
= 0; i
< len
; i
++) {
356 if (dc
->state
& TX_READY
) {
357 zs_write_data(cs
, c
[i
]);
358 dc
->state
&= ~TX_READY
;
360 dc
->txq
[dc
->txq_tail
] = c
[i
];
361 dc
->txq_tail
= (dc
->txq_tail
+ 1) & ~ZSKBD_TXQ_LEN
;
367 /* expects to be in splzs() */
369 zskbd_ctrl(struct zs_chanstate
*cs
, uint8_t a_on
, uint8_t a_off
,
370 uint8_t b_on
, uint8_t b_off
)
372 struct zskbd_softc
*sc
;
373 struct zskbd_devconfig
*dc
;
378 dc
->kbd_conf
[ZSKBD_CTRL_A
] |= a_on
;
379 dc
->kbd_conf
[ZSKBD_CTRL_A
] &= ~(a_off
| ZSKBD_CTRL_B
);
380 dc
->kbd_conf
[ZSKBD_CTRL_B
] &= ~b_off
;
381 dc
->kbd_conf
[ZSKBD_CTRL_B
] |= (b_on
| ZSKBD_CTRL_B
);
383 zskbd_send(cs
, dc
->kbd_conf
, 2);
385 /* make sure we don't resend these each time */
386 dc
->kbd_conf
[ZSKBD_CTRL_A
] &= ~(ZSKBD_CTRL_A_RCB
| ZSKBD_CTRL_A_SBEEP
|
390 /******************************************************************************
392 ******************************************************************************/
395 zskbd_wskbd_input(struct zs_chanstate
*cs
, uint8_t key
)
397 struct zskbd_softc
*sc
;
402 if (key
& ZSKBD_KEY_UP
)
403 type
= WSCONS_EVENT_KEY_UP
;
405 type
= WSCONS_EVENT_KEY_DOWN
;
407 wskbd_input(sc
->sc_dc
->wskbddev
, type
, (key
& ~ZSKBD_KEY_UP
));
409 DPRINTF(("zskbd_wskbd_input: inputted key 0x%x\n", key
));
411 #ifdef WSDISPLAY_COMPAT_RAWKBD
412 wskbd_rawinput(sc
->sc_dc
->wskbddev
, &key
, 1);
417 zskbd_wskbd_enable(void *cookie
, int on
)
419 struct zskbd_softc
*sc
;
420 struct zs_chanstate
*cs
;
426 if (sc
->sc_dc
->enabled
)
429 sc
->sc_dc
->enabled
= 1;
431 sc
->sc_dc
->enabled
= 0;
433 DPRINTF(("zskbd_wskbd_enable: %s\n", on
? "enabled" : "disabled"));
439 zskbd_wskbd_set_leds(void *cookie
, int leds
)
441 struct zs_chanstate
*cs
;
443 uint8_t a_on
, a_off
, b_on
, b_off
;
445 a_on
= a_off
= b_on
= b_off
= 0;
447 if (leds
& WSKBD_LED_CAPS
)
448 a_on
|= ZSKBD_CTRL_A_CAPSLK
;
450 a_off
|= ZSKBD_CTRL_A_CAPSLK
;
452 if (leds
& WSKBD_LED_NUM
)
453 a_on
|= ZSKBD_CTRL_A_NUMLK
;
455 a_off
|= ZSKBD_CTRL_A_NUMLK
;
457 if (leds
& WSKBD_LED_SCROLL
)
458 b_on
|= ZSKBD_CTRL_B_SCRLK
;
460 b_off
|= ZSKBD_CTRL_B_SCRLK
;
464 zskbd_ctrl(cs
, a_on
, a_off
, b_on
, b_off
);
469 zskbd_wskbd_get_leds(void *cookie
)
471 struct zskbd_softc
*sc
;
472 struct zs_chanstate
*cs
;
479 if (sc
->sc_dc
->kbd_conf
[ZSKBD_CTRL_A
] & ZSKBD_CTRL_A_NUMLK
)
480 leds
|= WSKBD_LED_NUM
;
482 if (sc
->sc_dc
->kbd_conf
[ZSKBD_CTRL_A
] & ZSKBD_CTRL_A_CAPSLK
)
483 leds
|= WSKBD_LED_CAPS
;
485 if (sc
->sc_dc
->kbd_conf
[ZSKBD_CTRL_B
] & ZSKBD_CTRL_B_SCRLK
)
486 leds
|= WSKBD_LED_SCROLL
;
492 zskbd_wskbd_set_keyclick(void *cookie
, int on
)
495 struct zs_chanstate
*cs
;
500 if (!zskbd_wskbd_get_keyclick(cookie
)) {
502 zskbd_ctrl(cs
, 0, ZSKBD_CTRL_A_NOCLICK
, 0, 0);
506 if (zskbd_wskbd_get_keyclick(cookie
)) {
508 zskbd_ctrl(cs
, ZSKBD_CTRL_A_NOCLICK
, 0, 0, 0);
515 zskbd_wskbd_get_keyclick(void *cookie
)
517 struct zskbd_softc
*sc
;
518 struct zs_chanstate
*cs
;
523 if (sc
->sc_dc
->kbd_conf
[ZSKBD_CTRL_A
] & ZSKBD_CTRL_A_NOCLICK
)
530 zskbd_wskbd_ioctl(void *cookie
, u_long cmd
,
531 void *data
, int flag
, struct lwp
*l
)
536 *(int *)data
= WSKBD_TYPE_SGI
;
541 case WSKBDIO_COMPLEXBELL
:
542 case WSKBDIO_SETBELL
:
543 case WSKBDIO_GETBELL
:
544 case WSKBDIO_SETDEFAULTBELL
:
545 case WSKBDIO_GETDEFAULTBELL
:
546 case WSKBDIO_SETKEYREPEAT
:
547 case WSKBDIO_GETKEYREPEAT
:
548 case WSKBDIO_SETDEFAULTKEYREPEAT
:
549 case WSKBDIO_GETDEFAULTKEYREPEAT
:
552 case WSKBDIO_SETLEDS
:
553 zskbd_wskbd_set_leds(cookie
, *(int *)data
);
556 case WSKBDIO_GETLEDS
:
557 *(int *)data
= zskbd_wskbd_get_leds(cookie
);
563 case WSKBDIO_GETENCODING
:
564 case WSKBDIO_SETENCODING
:
565 case WSKBDIO_SETMODE
:
566 case WSKBDIO_GETMODE
:
569 case WSKBDIO_SETKEYCLICK
:
570 zskbd_wskbd_set_keyclick(cookie
, *(int *)data
);
573 case WSKBDIO_GETKEYCLICK
:
574 *(int *)data
= zskbd_wskbd_get_keyclick(cookie
);
578 return (EPASSTHROUGH
);
588 zskbd_cnattach(int zsunit
, int zschan
)
591 wskbd_cnattach(&zskbd_wskbd_consops
, zs_get_chan_addr(zsunit
, zschan
),
592 &sgikbd_wskbd_keymapdata
);
593 zskbd_is_console
= 1;
597 zskbd_wskbd_getc(void *cookie
, u_int
*type
, int *data
)
601 key
= zs_getc(cookie
);
603 if (key
& ZSKBD_KEY_UP
)
604 *type
= WSCONS_EVENT_KEY_UP
;
606 *type
= WSCONS_EVENT_KEY_DOWN
;
608 *data
= key
& ~ZSKBD_KEY_UP
;
612 zskbd_wskbd_pollc(void *cookie
, int on
)
617 zskbd_wskbd_bell(void *cookie
, u_int pitch
, u_int period
, u_int volume
)
621 * Since we don't have any state, this'll nuke our lights,
622 * key click, and other bits in ZSKBD_CTRL_A.
625 zs_putc(cookie
, ZSKBD_CTRL_A_LBEEP
);
627 zs_putc(cookie
, ZSKBD_CTRL_A_SBEEP
);