xref: /netbsd-src/sys/arch/sgimips/dev/zs_kbd.c (revision 670906435277b2f8cd845f50c4b99ef0dfdd9ad9)
1*67090643Stsutsui /*	$NetBSD: zs_kbd.c,v 1.14 2021/09/18 15:14:41 tsutsui Exp $	*/
25110af7aSsekiya 
35110af7aSsekiya /*
45110af7aSsekiya  * Copyright (c) 2004 Steve Rumble
55110af7aSsekiya  * All rights reserved.
65110af7aSsekiya  *
75110af7aSsekiya  * Redistribution and use in source and binary forms, with or without
85110af7aSsekiya  * modification, are permitted provided that the following conditions
95110af7aSsekiya  * are met:
105110af7aSsekiya  * 1. Redistributions of source code must retain the above copyright
115110af7aSsekiya  *    notice, this list of conditions and the following disclaimer.
125110af7aSsekiya  * 2. Redistributions in binary form must reproduce the above copyright
135110af7aSsekiya  *    notice, this list of conditions and the following disclaimer in the
145110af7aSsekiya  *    documentation and/or other materials provided with the distribution.
155110af7aSsekiya  * 3. The name of the author may not be used to endorse or promote products
165110af7aSsekiya  *    derived from this software without specific prior written permission.
175110af7aSsekiya  *
185110af7aSsekiya  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
195110af7aSsekiya  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
205110af7aSsekiya  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
215110af7aSsekiya  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
225110af7aSsekiya  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
235110af7aSsekiya  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
245110af7aSsekiya  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
255110af7aSsekiya  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265110af7aSsekiya  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
275110af7aSsekiya  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
285110af7aSsekiya  */
295110af7aSsekiya 
305110af7aSsekiya /*
315110af7aSsekiya  * IP12/IP20 serial keyboard driver attached to zs channel 0 at 600bps.
325110af7aSsekiya  * This layer is the parent of wskbd.
335110af7aSsekiya  */
345110af7aSsekiya 
355110af7aSsekiya #include <sys/cdefs.h>
36*67090643Stsutsui __KERNEL_RCSID(0, "$NetBSD: zs_kbd.c,v 1.14 2021/09/18 15:14:41 tsutsui Exp $");
375110af7aSsekiya 
385110af7aSsekiya #include <sys/param.h>
3961a80495Sthorpej #include <sys/kmem.h>
405110af7aSsekiya #include <sys/systm.h>
415110af7aSsekiya #include <sys/conf.h>
425110af7aSsekiya #include <sys/device.h>
435110af7aSsekiya 
445110af7aSsekiya #include <dev/wscons/wsconsio.h>
455110af7aSsekiya #include <dev/wscons/wskbdvar.h>
465110af7aSsekiya #include <dev/wscons/wsksymdef.h>
475110af7aSsekiya #include <dev/wscons/wsksymvar.h>
485110af7aSsekiya 
495110af7aSsekiya #include <dev/ic/z8530reg.h>
505110af7aSsekiya #include <machine/machtype.h>
515110af7aSsekiya #include <machine/z8530var.h>
525110af7aSsekiya 
535110af7aSsekiya #define ZSKBD_BAUD	600
545110af7aSsekiya #define ZSKBD_TXQ_LEN	16		/* power of 2 */
555110af7aSsekiya #define ZSKBD_RXQ_LEN	64		/* power of 2 */
565110af7aSsekiya 
575110af7aSsekiya #define ZSKBD_DIP_SYNC	0x6E
585110af7aSsekiya #define ZSKBD_KEY_UP	0x80
595110af7aSsekiya 
605189fbb0Srumble #ifdef ZSKBD_DEBUG
615189fbb0Srumble int zskbd_debug = 0;
625189fbb0Srumble 
635189fbb0Srumble #define DPRINTF(_x) if (zskbd_debug) printf _x
645189fbb0Srumble #else
655189fbb0Srumble #define DPRINTF(_x)
665189fbb0Srumble #endif
675189fbb0Srumble 
685110af7aSsekiya struct zskbd_softc {
6902cb47caStsutsui 	device_t   	sc_dev;
705110af7aSsekiya 
715189fbb0Srumble 	struct zskbd_devconfig *sc_dc;
725189fbb0Srumble };
735189fbb0Srumble 
745189fbb0Srumble struct zskbd_devconfig {
755110af7aSsekiya 	/* transmit tail-chasing fifo */
7602cb47caStsutsui 	uint8_t		txq[ZSKBD_TXQ_LEN];
775110af7aSsekiya 	u_int		txq_head;
785110af7aSsekiya 	u_int		txq_tail;
795110af7aSsekiya 
805110af7aSsekiya 	/* receive tail-chasing fifo */
8102cb47caStsutsui 	uint8_t		rxq[ZSKBD_RXQ_LEN];
825110af7aSsekiya 	u_int		rxq_head;
835110af7aSsekiya 	u_int		rxq_tail;
845110af7aSsekiya 
855110af7aSsekiya 	/* state */
865110af7aSsekiya #define TX_READY	0x1
875110af7aSsekiya #define RX_DIP		0x2
885110af7aSsekiya 	u_int		state;
895110af7aSsekiya 
905110af7aSsekiya 	/* keyboard configuration */
915110af7aSsekiya #define ZSKBD_CTRL_A		0x0
925110af7aSsekiya #define ZSKBD_CTRL_A_SBEEP	0x2	/* 200 ms */
935110af7aSsekiya #define ZSKBD_CTRL_A_LBEEP	0x4	/* 1000 ms */
945110af7aSsekiya #define ZSKBD_CTRL_A_NOCLICK	0x8	/* turn off keyboard click */
955110af7aSsekiya #define ZSKBD_CTRL_A_RCB	0x10	/* request config byte */
965110af7aSsekiya #define ZSKBD_CTRL_A_NUMLK	0x20	/* num lock led */
975110af7aSsekiya #define ZSKBD_CTRL_A_CAPSLK	0x40	/* caps lock led */
985110af7aSsekiya #define ZSKBD_CTRL_A_AUTOREP	0x80	/* auto-repeat after 650 ms, 28x/sec */
995110af7aSsekiya 
1005110af7aSsekiya #define ZSKBD_CTRL_B		0x1
1015110af7aSsekiya #define ZSKBD_CTRL_B_CMPL_DS1_2	0x2	/* complement of ds1+ds2 (num+capslk) */
1025110af7aSsekiya #define ZSKBD_CTRL_B_SCRLK	0x4	/* scroll lock light */
1035110af7aSsekiya #define ZSKBD_CTRL_B_L1		0x8	/* user-configurable lights */
1045110af7aSsekiya #define ZSKBD_CTRL_B_L2		0x10
1055110af7aSsekiya #define ZSKBD_CTRL_B_L3		0x20
1065110af7aSsekiya #define ZSKBD_CTRL_B_L4		0x40
10702cb47caStsutsui 	uint8_t		kbd_conf[2];
1085110af7aSsekiya 
1095110af7aSsekiya 	/* dip switch settings */
11002cb47caStsutsui 	uint8_t		dip;
1115110af7aSsekiya 
1125110af7aSsekiya 	/* wscons glue */
113b8c34ff8Schs 	device_t	wskbddev;
1145110af7aSsekiya 	int		enabled;
1155110af7aSsekiya };
1165110af7aSsekiya 
11702cb47caStsutsui static int	zskbd_match(device_t, cfdata_t, void *);
11802cb47caStsutsui static void	zskbd_attach(device_t, device_t, void *);
1195110af7aSsekiya static void	zskbd_rxint(struct zs_chanstate *);
1205110af7aSsekiya static void	zskbd_stint(struct zs_chanstate *, int);
1215110af7aSsekiya static void	zskbd_txint(struct zs_chanstate *);
1225110af7aSsekiya static void	zskbd_softint(struct zs_chanstate *);
12302cb47caStsutsui static void	zskbd_send(struct zs_chanstate *, uint8_t *, u_int);
12402cb47caStsutsui static void	zskbd_ctrl(struct zs_chanstate *, uint8_t, uint8_t,
12502cb47caStsutsui 						  uint8_t, uint8_t);
1265110af7aSsekiya 
12702cb47caStsutsui static void	zskbd_wskbd_input(struct zs_chanstate *, uint8_t);
1285110af7aSsekiya static int	zskbd_wskbd_enable(void *, int);
1295110af7aSsekiya static void	zskbd_wskbd_set_leds(void *, int);
1305110af7aSsekiya static int	zskbd_wskbd_get_leds(void *);
1315110af7aSsekiya static void	zskbd_wskbd_set_keyclick(void *, int);
1325110af7aSsekiya static int	zskbd_wskbd_get_keyclick(void *);
13353524e44Schristos static int	zskbd_wskbd_ioctl(void *, u_long, void *, int, struct lwp *);
1345110af7aSsekiya 
1355110af7aSsekiya void		zskbd_cnattach(int, int);
1365110af7aSsekiya static void	zskbd_wskbd_getc(void *, u_int *, int *);
1375110af7aSsekiya static void	zskbd_wskbd_pollc(void *, int);
1385110af7aSsekiya static void	zskbd_wskbd_bell(void *, u_int, u_int, u_int);
1395110af7aSsekiya 
1405110af7aSsekiya extern struct zschan   *zs_get_chan_addr(int, int);
1415110af7aSsekiya extern int		zs_getc(void *);
1425110af7aSsekiya extern void		zs_putc(void *, int);
1435110af7aSsekiya 
14402cb47caStsutsui CFATTACH_DECL_NEW(zskbd, sizeof(struct zskbd_softc),
1455110af7aSsekiya     zskbd_match, zskbd_attach, NULL, NULL);
1465110af7aSsekiya 
1475110af7aSsekiya static struct zsops zskbd_zsops = {
1485110af7aSsekiya 	zskbd_rxint,
1495110af7aSsekiya 	zskbd_stint,
1505110af7aSsekiya 	zskbd_txint,
1515110af7aSsekiya 	zskbd_softint
1525110af7aSsekiya };
1535110af7aSsekiya 
1545110af7aSsekiya extern const struct wscons_keydesc wssgi_keydesctab[];
1555110af7aSsekiya const struct wskbd_mapdata sgikbd_wskbd_keymapdata = {
1565110af7aSsekiya 	wssgi_keydesctab, KB_US
1575110af7aSsekiya };
1585110af7aSsekiya 
1595110af7aSsekiya const struct wskbd_accessops zskbd_wskbd_accessops = {
1605110af7aSsekiya 	zskbd_wskbd_enable,
1615110af7aSsekiya 	zskbd_wskbd_set_leds,
1625110af7aSsekiya 	zskbd_wskbd_ioctl
1635110af7aSsekiya };
1645110af7aSsekiya 
1655110af7aSsekiya const struct wskbd_consops zskbd_wskbd_consops = {
1665110af7aSsekiya 	zskbd_wskbd_getc,
1675110af7aSsekiya 	zskbd_wskbd_pollc,
1685110af7aSsekiya 	zskbd_wskbd_bell
1695110af7aSsekiya };
1705110af7aSsekiya 
1715189fbb0Srumble static struct zskbd_devconfig	zskbd_console_dc;
1725189fbb0Srumble static int			zskbd_is_console = 0;
1735189fbb0Srumble 
1745110af7aSsekiya static int
zskbd_match(device_t parent,cfdata_t cf,void * aux)17502cb47caStsutsui zskbd_match(device_t parent, cfdata_t cf, void *aux)
1765110af7aSsekiya {
17744f3c135Srumble 
1785110af7aSsekiya 	if (mach_type == MACH_SGI_IP12 || mach_type == MACH_SGI_IP20) {
1795110af7aSsekiya 		struct zsc_attach_args *args = aux;
1805110af7aSsekiya 
1815110af7aSsekiya 		if (args->channel == 0)
1825110af7aSsekiya 			return (1);
1835110af7aSsekiya 	}
1845110af7aSsekiya 
1855110af7aSsekiya 	return (0);
1865110af7aSsekiya }
1875110af7aSsekiya 
1885110af7aSsekiya static void
zskbd_attach(device_t parent,device_t self,void * aux)18902cb47caStsutsui zskbd_attach(device_t parent, device_t self, void *aux)
1905110af7aSsekiya {
19144f3c135Srumble 	struct zskbd_softc	       *sc;
1925110af7aSsekiya 	struct zs_chanstate	       *cs;
19344f3c135Srumble 	struct zsc_softc      	       *zsc;
19444f3c135Srumble 	struct zsc_attach_args	       *args;
1955110af7aSsekiya 	struct wskbddev_attach_args	wskaa;
19644f3c135Srumble 	int				s, channel;
19744f3c135Srumble 
19802cb47caStsutsui 	zsc = device_private(parent);
19902cb47caStsutsui 	sc = device_private(self);
20002cb47caStsutsui 	sc->sc_dev = self;
20102cb47caStsutsui 	args = aux;
2025110af7aSsekiya 
2035110af7aSsekiya 	/* Establish ourself with the MD z8530 driver */
2045110af7aSsekiya 	channel = args->channel;
2055110af7aSsekiya 	cs = zsc->zsc_cs[channel];
2065110af7aSsekiya 	cs->cs_ops = &zskbd_zsops;
2075110af7aSsekiya 	cs->cs_private = sc;
2085110af7aSsekiya 
2095189fbb0Srumble 	if (zskbd_is_console) {
2105189fbb0Srumble 		sc->sc_dc = &zskbd_console_dc;
2115189fbb0Srumble 		wskaa.console = 1;
2125189fbb0Srumble 		sc->sc_dc->enabled = 1;
2135189fbb0Srumble 	} else {
2145189fbb0Srumble 		wskaa.console = 0;
2155189fbb0Srumble 
21661a80495Sthorpej 		sc->sc_dc = kmem_alloc(sizeof(struct zskbd_devconfig),
21761a80495Sthorpej 		    KM_SLEEP);
2185189fbb0Srumble 
2195189fbb0Srumble 		sc->sc_dc->enabled = 0;
2205189fbb0Srumble 	}
2215189fbb0Srumble 
2225189fbb0Srumble 	sc->sc_dc->txq_head = 0;
2235189fbb0Srumble 	sc->sc_dc->txq_tail = 0;
2245189fbb0Srumble 	sc->sc_dc->rxq_head = 0;
2255189fbb0Srumble 	sc->sc_dc->rxq_tail = 0;
2265189fbb0Srumble 	sc->sc_dc->state = TX_READY;
2275189fbb0Srumble 	sc->sc_dc->dip = 0;
2285189fbb0Srumble 	sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] = 0;
2295189fbb0Srumble 	sc->sc_dc->kbd_conf[ZSKBD_CTRL_B] = 0;
2305110af7aSsekiya 
23102cb47caStsutsui 	aprint_normal(": baud rate %d\n", ZSKBD_BAUD);
2325110af7aSsekiya 
2335110af7aSsekiya 	s = splzs();
2345110af7aSsekiya 	zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET);
2355110af7aSsekiya 	cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE;
2365110af7aSsekiya 	cs->cs_preg[4] = (cs->cs_preg[4] & ZSWR4_CLK_MASK) |
2375110af7aSsekiya 			 (ZSWR4_ONESB | ZSWR4_PARENB);	/* 1 stop, odd parity */
2385110af7aSsekiya 	zs_set_speed(cs, ZSKBD_BAUD);
2395110af7aSsekiya 	zs_loadchannelregs(cs);
2405110af7aSsekiya 
2415110af7aSsekiya 	/* request DIP switch settings just in case */
2425110af7aSsekiya 	zskbd_ctrl(cs, ZSKBD_CTRL_A_RCB, 0, 0, 0);
2435110af7aSsekiya 
2445110af7aSsekiya 	splx(s);
2455110af7aSsekiya 
2465110af7aSsekiya 	/* attach wskbd */
2475110af7aSsekiya 	wskaa.keymap =		&sgikbd_wskbd_keymapdata;
2485110af7aSsekiya 	wskaa.accessops =	&zskbd_wskbd_accessops;
2495110af7aSsekiya 	wskaa.accesscookie =	cs;
2502685996bSthorpej 	sc->sc_dc->wskbddev =	config_found(self, &wskaa, wskbddevprint,
251c7fb772bSthorpej 					     CFARGS_NONE);
2525110af7aSsekiya }
2535110af7aSsekiya 
2545110af7aSsekiya static void
zskbd_rxint(struct zs_chanstate * cs)2555110af7aSsekiya zskbd_rxint(struct zs_chanstate *cs)
2565110af7aSsekiya {
25744f3c135Srumble 	struct zskbd_softc     *sc;
25844f3c135Srumble 	struct zskbd_devconfig *dc;
25902cb47caStsutsui 	uint8_t			c, r;
26044f3c135Srumble 
26102cb47caStsutsui 	sc = cs->cs_private;
26244f3c135Srumble 	dc = sc->sc_dc;
2635110af7aSsekiya 
2645110af7aSsekiya 	/* clear errors */
2655110af7aSsekiya 	r = zs_read_reg(cs, 1);
2665110af7aSsekiya 	if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE))
2675110af7aSsekiya 		zs_write_csr(cs, ZSWR0_RESET_ERRORS);
2685110af7aSsekiya 
2695110af7aSsekiya 	/* read byte and append to our queue */
2705110af7aSsekiya 	c = zs_read_data(cs);
2715110af7aSsekiya 
2725189fbb0Srumble 	dc->rxq[dc->rxq_tail] = c;
2735189fbb0Srumble 	dc->rxq_tail = (dc->rxq_tail + 1) & ~ZSKBD_RXQ_LEN;
2745110af7aSsekiya 
2755110af7aSsekiya 	cs->cs_softreq = 1;
2765110af7aSsekiya }
2775110af7aSsekiya 
2785110af7aSsekiya static void
zskbd_stint(struct zs_chanstate * cs,int force)2795110af7aSsekiya zskbd_stint(struct zs_chanstate *cs, int force)
2805110af7aSsekiya {
28144f3c135Srumble 
2825110af7aSsekiya 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
2835110af7aSsekiya 	cs->cs_softreq = 1;
2845110af7aSsekiya }
2855110af7aSsekiya 
2865110af7aSsekiya static void
zskbd_txint(struct zs_chanstate * cs)2875110af7aSsekiya zskbd_txint(struct zs_chanstate *cs)
2885110af7aSsekiya {
28944f3c135Srumble 	struct zskbd_softc *sc;
2905110af7aSsekiya 
29102cb47caStsutsui 	sc = cs->cs_private;
2925110af7aSsekiya 	zs_write_reg(cs, 0, ZSWR0_RESET_TXINT);
2935189fbb0Srumble 	sc->sc_dc->state |= TX_READY;
2945110af7aSsekiya 	cs->cs_softreq = 1;
2955110af7aSsekiya }
2965110af7aSsekiya 
2975110af7aSsekiya static void
zskbd_softint(struct zs_chanstate * cs)2985110af7aSsekiya zskbd_softint(struct zs_chanstate *cs)
2995110af7aSsekiya {
30044f3c135Srumble 	struct zskbd_softc	*sc;
30144f3c135Srumble 	struct zskbd_devconfig	*dc;
30244f3c135Srumble 
30302cb47caStsutsui 	sc = cs->cs_private;
30444f3c135Srumble 	dc = sc->sc_dc;
3055189fbb0Srumble 
3065110af7aSsekiya 	/* handle pending transmissions */
3075189fbb0Srumble 	if (dc->txq_head != dc->txq_tail && (dc->state & TX_READY)) {
3085110af7aSsekiya 		int s;
3095110af7aSsekiya 
3105189fbb0Srumble 		dc->state &= ~TX_READY;
3115110af7aSsekiya 
3125110af7aSsekiya 		s = splzs();
3135189fbb0Srumble 		zs_write_data(cs, dc->txq[dc->txq_head]);
3145110af7aSsekiya 		splx(s);
3155110af7aSsekiya 
3165189fbb0Srumble 		dc->txq_head = (dc->txq_head + 1) & ~ZSKBD_TXQ_LEN;
3175110af7aSsekiya 	}
3185110af7aSsekiya 
3195110af7aSsekiya 	/* don't bother if nobody is listening */
3205189fbb0Srumble 	if (!dc->enabled) {
3215189fbb0Srumble 		dc->rxq_head = dc->rxq_tail;
3225110af7aSsekiya 		return;
3235110af7aSsekiya 	}
3245110af7aSsekiya 
3255110af7aSsekiya 	/* handle incoming keystrokes/config */
3265189fbb0Srumble 	while (dc->rxq_head != dc->rxq_tail) {
32702cb47caStsutsui 		uint8_t key = dc->rxq[dc->rxq_head];
3285110af7aSsekiya 
3295189fbb0Srumble 		if (dc->state & RX_DIP) {
3305189fbb0Srumble 			dc->dip = key;
3315189fbb0Srumble 			dc->state &= ~RX_DIP;
3325110af7aSsekiya 		} else if (key == ZSKBD_DIP_SYNC) {
3335189fbb0Srumble 			dc->state |= RX_DIP;
3345110af7aSsekiya 		} else {
3355110af7aSsekiya 			/* toss wskbd a bone */
3365110af7aSsekiya 			zskbd_wskbd_input(cs, key);
3375110af7aSsekiya 		}
3385110af7aSsekiya 
3395189fbb0Srumble 		dc->rxq_head = (dc->rxq_head + 1) & ~ZSKBD_RXQ_LEN;
3405110af7aSsekiya 	}
3415110af7aSsekiya }
3425110af7aSsekiya 
3435110af7aSsekiya /* expects to be in splzs() */
3445110af7aSsekiya static void
zskbd_send(struct zs_chanstate * cs,uint8_t * c,u_int len)34502cb47caStsutsui zskbd_send(struct zs_chanstate *cs, uint8_t *c, u_int len)
3465110af7aSsekiya {
3475110af7aSsekiya 	u_int			i;
34844f3c135Srumble 	struct zskbd_softc     *sc;
34944f3c135Srumble 	struct zskbd_devconfig *dc;
35044f3c135Srumble 
35102cb47caStsutsui 	sc = cs->cs_private;
35244f3c135Srumble 	dc = sc->sc_dc;
3535110af7aSsekiya 
3545110af7aSsekiya 	for (i = 0; i < len; i++) {
3555189fbb0Srumble 		if (dc->state & TX_READY) {
3565110af7aSsekiya 			zs_write_data(cs, c[i]);
3575189fbb0Srumble 			dc->state &= ~TX_READY;
3585110af7aSsekiya 		} else {
3595189fbb0Srumble 			dc->txq[dc->txq_tail] = c[i];
3605189fbb0Srumble 			dc->txq_tail = (dc->txq_tail + 1) & ~ZSKBD_TXQ_LEN;
3615189fbb0Srumble 			cs->cs_softreq = 1;
3625110af7aSsekiya 		}
3635110af7aSsekiya 	}
3645110af7aSsekiya }
3655110af7aSsekiya 
3665110af7aSsekiya /* expects to be in splzs() */
3675110af7aSsekiya static void
zskbd_ctrl(struct zs_chanstate * cs,uint8_t a_on,uint8_t a_off,uint8_t b_on,uint8_t b_off)36802cb47caStsutsui zskbd_ctrl(struct zs_chanstate *cs, uint8_t a_on, uint8_t a_off,
36902cb47caStsutsui 	   uint8_t b_on, uint8_t b_off)
3705110af7aSsekiya {
37144f3c135Srumble 	struct zskbd_softc	*sc;
37244f3c135Srumble 	struct zskbd_devconfig	*dc;
37344f3c135Srumble 
37402cb47caStsutsui 	sc = cs->cs_private;
37544f3c135Srumble 	dc = sc->sc_dc;
3765110af7aSsekiya 
3775189fbb0Srumble 	dc->kbd_conf[ZSKBD_CTRL_A] |=   a_on;
3785189fbb0Srumble 	dc->kbd_conf[ZSKBD_CTRL_A] &= ~(a_off | ZSKBD_CTRL_B);
3795189fbb0Srumble 	dc->kbd_conf[ZSKBD_CTRL_B] &=  ~b_off;
3805189fbb0Srumble 	dc->kbd_conf[ZSKBD_CTRL_B] |=  (b_on | ZSKBD_CTRL_B);
3815110af7aSsekiya 
3825189fbb0Srumble 	zskbd_send(cs, dc->kbd_conf, 2);
3835110af7aSsekiya 
3845110af7aSsekiya 	/* make sure we don't resend these each time */
3855189fbb0Srumble 	dc->kbd_conf[ZSKBD_CTRL_A] &= ~(ZSKBD_CTRL_A_RCB | ZSKBD_CTRL_A_SBEEP |
3865110af7aSsekiya 	    ZSKBD_CTRL_A_LBEEP);
3875110af7aSsekiya }
3885110af7aSsekiya 
3895110af7aSsekiya /******************************************************************************
3905110af7aSsekiya  * wskbd glue
3915110af7aSsekiya  ******************************************************************************/
3925110af7aSsekiya 
3935110af7aSsekiya static void
zskbd_wskbd_input(struct zs_chanstate * cs,uint8_t key)39402cb47caStsutsui zskbd_wskbd_input(struct zs_chanstate *cs, uint8_t key)
3955110af7aSsekiya {
39644f3c135Srumble 	struct zskbd_softc     *sc;
3975110af7aSsekiya 	u_int			type;
39844f3c135Srumble 
39902cb47caStsutsui 	sc = cs->cs_private;
4005110af7aSsekiya 
4015110af7aSsekiya 	if (key & ZSKBD_KEY_UP)
4025110af7aSsekiya 		type = WSCONS_EVENT_KEY_UP;
4035110af7aSsekiya 	else
4045110af7aSsekiya 		type = WSCONS_EVENT_KEY_DOWN;
4055110af7aSsekiya 
4065189fbb0Srumble 	wskbd_input(sc->sc_dc->wskbddev, type, (key & ~ZSKBD_KEY_UP));
4075189fbb0Srumble 
4085189fbb0Srumble 	DPRINTF(("zskbd_wskbd_input: inputted key 0x%x\n", key));
4095110af7aSsekiya 
4105110af7aSsekiya #ifdef WSDISPLAY_COMPAT_RAWKBD
4115189fbb0Srumble 	wskbd_rawinput(sc->sc_dc->wskbddev, &key, 1);
4125110af7aSsekiya #endif
4135110af7aSsekiya }
4145110af7aSsekiya 
4155110af7aSsekiya static int
zskbd_wskbd_enable(void * cookie,int on)4165110af7aSsekiya zskbd_wskbd_enable(void *cookie, int on)
4175110af7aSsekiya {
41844f3c135Srumble 	struct zskbd_softc *sc;
41902cb47caStsutsui 	struct zs_chanstate *cs;
42044f3c135Srumble 
42102cb47caStsutsui 	cs = cookie;
42202cb47caStsutsui 	sc = cs->cs_private;
42344f3c135Srumble 
4245110af7aSsekiya 	if (on) {
4255189fbb0Srumble 		if (sc->sc_dc->enabled)
4265110af7aSsekiya 			return (EBUSY);
4275110af7aSsekiya 		else
4285189fbb0Srumble 			sc->sc_dc->enabled = 1;
4295110af7aSsekiya 	} else
4305189fbb0Srumble 		sc->sc_dc->enabled = 0;
4315189fbb0Srumble 
4325189fbb0Srumble 	DPRINTF(("zskbd_wskbd_enable: %s\n", on ? "enabled" : "disabled"));
4335110af7aSsekiya 
4345110af7aSsekiya 	return (0);
4355110af7aSsekiya }
4365110af7aSsekiya 
4375110af7aSsekiya static void
zskbd_wskbd_set_leds(void * cookie,int leds)4385110af7aSsekiya zskbd_wskbd_set_leds(void *cookie, int leds)
4395110af7aSsekiya {
44002cb47caStsutsui 	struct zs_chanstate *cs;
4415110af7aSsekiya 	int 	s;
44202cb47caStsutsui 	uint8_t	a_on, a_off, b_on, b_off;
44344f3c135Srumble 
44444f3c135Srumble 	a_on = a_off = b_on = b_off = 0;
4455110af7aSsekiya 
4465110af7aSsekiya 	if (leds & WSKBD_LED_CAPS)
4475110af7aSsekiya 		a_on |=  ZSKBD_CTRL_A_CAPSLK;
4485110af7aSsekiya 	else
4495110af7aSsekiya 		a_off |= ZSKBD_CTRL_A_CAPSLK;
4505110af7aSsekiya 
4515110af7aSsekiya 	if (leds & WSKBD_LED_NUM)
4525110af7aSsekiya 		a_on |=  ZSKBD_CTRL_A_NUMLK;
4535110af7aSsekiya 	else
4545110af7aSsekiya 		a_off |= ZSKBD_CTRL_A_NUMLK;
4555110af7aSsekiya 
4565110af7aSsekiya 	if (leds & WSKBD_LED_SCROLL)
4575110af7aSsekiya 		b_on |=  ZSKBD_CTRL_B_SCRLK;
4585110af7aSsekiya 	else
4595110af7aSsekiya 		b_off |= ZSKBD_CTRL_B_SCRLK;
4605110af7aSsekiya 
46102cb47caStsutsui 	cs = cookie;
4625110af7aSsekiya 	s = splzs();
46302cb47caStsutsui 	zskbd_ctrl(cs, a_on, a_off, b_on, b_off);
4645110af7aSsekiya 	splx(s);
4655110af7aSsekiya }
4665110af7aSsekiya 
4675110af7aSsekiya static int
zskbd_wskbd_get_leds(void * cookie)4685110af7aSsekiya zskbd_wskbd_get_leds(void *cookie)
4695110af7aSsekiya {
47044f3c135Srumble 	struct zskbd_softc     *sc;
47102cb47caStsutsui 	struct zs_chanstate    *cs;
47244f3c135Srumble 	int		 	leds;
47344f3c135Srumble 
47402cb47caStsutsui 	cs = cookie;
47502cb47caStsutsui 	sc = cs->cs_private;
47644f3c135Srumble 	leds = 0;
4775110af7aSsekiya 
4785189fbb0Srumble 	if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_NUMLK)
4795110af7aSsekiya 		leds |= WSKBD_LED_NUM;
4805110af7aSsekiya 
4815189fbb0Srumble 	if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_CAPSLK)
4825110af7aSsekiya 		leds |= WSKBD_LED_CAPS;
4835110af7aSsekiya 
4845189fbb0Srumble 	if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_B] & ZSKBD_CTRL_B_SCRLK)
4855110af7aSsekiya 		leds |= WSKBD_LED_SCROLL;
4865110af7aSsekiya 
4875110af7aSsekiya 	return (leds);
4885110af7aSsekiya }
4895110af7aSsekiya 
4905110af7aSsekiya static void
zskbd_wskbd_set_keyclick(void * cookie,int on)4915110af7aSsekiya zskbd_wskbd_set_keyclick(void *cookie, int on)
4925110af7aSsekiya {
4935110af7aSsekiya 	int			s;
49444f3c135Srumble 	struct zs_chanstate    *cs;
49544f3c135Srumble 
49602cb47caStsutsui 	cs = cookie;
4975110af7aSsekiya 
4985110af7aSsekiya 	if (on) {
4995110af7aSsekiya 		if (!zskbd_wskbd_get_keyclick(cookie)) {
5005110af7aSsekiya 			s = splzs();
5015110af7aSsekiya 			zskbd_ctrl(cs, 0, ZSKBD_CTRL_A_NOCLICK, 0, 0);
5025110af7aSsekiya 			splx(s);
5035110af7aSsekiya 		}
5045110af7aSsekiya 	} else {
5055110af7aSsekiya 		if (zskbd_wskbd_get_keyclick(cookie)) {
5065110af7aSsekiya 			s = splzs();
5075110af7aSsekiya 			zskbd_ctrl(cs, ZSKBD_CTRL_A_NOCLICK, 0, 0, 0);
5085110af7aSsekiya 			splx(s);
5095110af7aSsekiya 		}
5105110af7aSsekiya 	}
5115110af7aSsekiya }
5125110af7aSsekiya 
5135110af7aSsekiya static int
zskbd_wskbd_get_keyclick(void * cookie)5145110af7aSsekiya zskbd_wskbd_get_keyclick(void *cookie)
5155110af7aSsekiya {
51644f3c135Srumble 	struct zskbd_softc *sc;
51702cb47caStsutsui 	struct zs_chanstate *cs;
51844f3c135Srumble 
51902cb47caStsutsui 	cs = cookie;
52002cb47caStsutsui 	sc = cs->cs_private;
5215110af7aSsekiya 
5225189fbb0Srumble 	if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_NOCLICK)
5235110af7aSsekiya 		return (0);
5245110af7aSsekiya 	else
5255110af7aSsekiya 		return (1);
5265110af7aSsekiya }
5275110af7aSsekiya 
5285110af7aSsekiya static int
zskbd_wskbd_ioctl(void * cookie,u_long cmd,void * data,int flag,struct lwp * l)5295110af7aSsekiya zskbd_wskbd_ioctl(void *cookie, u_long cmd,
53053524e44Schristos 		  void *data, int flag, struct lwp *l)
5315110af7aSsekiya {
53244f3c135Srumble 
5335110af7aSsekiya 	switch (cmd) {
5345110af7aSsekiya 	case WSKBDIO_GTYPE:
5355110af7aSsekiya 		*(int *)data = WSKBD_TYPE_SGI;
5365110af7aSsekiya 		break;
5375110af7aSsekiya 
5385110af7aSsekiya #ifdef notyet
5395110af7aSsekiya 	case WSKBDIO_COMPLEXBELL:
5405110af7aSsekiya 	case WSKBDIO_SETKEYREPEAT:
5415110af7aSsekiya 	case WSKBDIO_GETKEYREPEAT:
5425110af7aSsekiya 	case WSKBDIO_SETDEFAULTKEYREPEAT:
5435110af7aSsekiya 	case WSKBDIO_GETDEFAULTKEYREPEAT:
5445110af7aSsekiya #endif
5455110af7aSsekiya 
5465110af7aSsekiya 	case WSKBDIO_SETLEDS:
5475110af7aSsekiya 		zskbd_wskbd_set_leds(cookie, *(int *)data);
5485110af7aSsekiya 		break;
5495110af7aSsekiya 
5505110af7aSsekiya 	case WSKBDIO_GETLEDS:
5515110af7aSsekiya 		*(int *)data = zskbd_wskbd_get_leds(cookie);
5525110af7aSsekiya 		break;
5535110af7aSsekiya 
5545110af7aSsekiya #ifdef notyet
5555110af7aSsekiya 	case WSKBDIO_GETMAP:
5565110af7aSsekiya 	case WSKBDIO_SETMAP:
5575110af7aSsekiya 	case WSKBDIO_GETENCODING:
5585110af7aSsekiya 	case WSKBDIO_SETENCODING:
5595110af7aSsekiya 	case WSKBDIO_SETMODE:
5605110af7aSsekiya 	case WSKBDIO_GETMODE:
5615110af7aSsekiya #endif
5625110af7aSsekiya 
5635110af7aSsekiya 	case WSKBDIO_SETKEYCLICK:
5645110af7aSsekiya 		zskbd_wskbd_set_keyclick(cookie, *(int *)data);
5655110af7aSsekiya 		break;
5665110af7aSsekiya 
5675110af7aSsekiya 	case WSKBDIO_GETKEYCLICK:
5685110af7aSsekiya 		*(int *)data = zskbd_wskbd_get_keyclick(cookie);
5695110af7aSsekiya 		break;
5705110af7aSsekiya 
5715110af7aSsekiya 	default:
5725110af7aSsekiya 		return (EPASSTHROUGH);
5735110af7aSsekiya 	}
5745110af7aSsekiya 
5755110af7aSsekiya 	return (0);
5765110af7aSsekiya }
5775110af7aSsekiya 
5785110af7aSsekiya /*
5795110af7aSsekiya  * console routines
5805110af7aSsekiya  */
5815110af7aSsekiya void
zskbd_cnattach(int zsunit,int zschan)5825110af7aSsekiya zskbd_cnattach(int zsunit, int zschan)
5835110af7aSsekiya {
58444f3c135Srumble 
5855110af7aSsekiya 	wskbd_cnattach(&zskbd_wskbd_consops, zs_get_chan_addr(zsunit, zschan),
5865110af7aSsekiya 	    &sgikbd_wskbd_keymapdata);
5875189fbb0Srumble 	zskbd_is_console = 1;
5885110af7aSsekiya }
5895110af7aSsekiya 
5905110af7aSsekiya static void
zskbd_wskbd_getc(void * cookie,u_int * type,int * data)5915110af7aSsekiya zskbd_wskbd_getc(void *cookie, u_int *type, int *data)
5925110af7aSsekiya {
59344f3c135Srumble 	int key;
59444f3c135Srumble 
59544f3c135Srumble 	key = zs_getc(cookie);
5965110af7aSsekiya 
5975110af7aSsekiya 	if (key & ZSKBD_KEY_UP)
5985110af7aSsekiya 		*type = WSCONS_EVENT_KEY_UP;
5995110af7aSsekiya 	else
6005110af7aSsekiya 		*type = WSCONS_EVENT_KEY_DOWN;
6015110af7aSsekiya 
6025110af7aSsekiya 	*data = key & ~ZSKBD_KEY_UP;
6035110af7aSsekiya }
6045110af7aSsekiya 
6055110af7aSsekiya static void
zskbd_wskbd_pollc(void * cookie,int on)6065110af7aSsekiya zskbd_wskbd_pollc(void *cookie, int on)
6075110af7aSsekiya {
6085110af7aSsekiya }
6095110af7aSsekiya 
6105110af7aSsekiya static void
zskbd_wskbd_bell(void * cookie,u_int pitch,u_int period,u_int volume)6115110af7aSsekiya zskbd_wskbd_bell(void *cookie, u_int pitch, u_int period, u_int volume)
6125110af7aSsekiya {
61344f3c135Srumble 
6145110af7aSsekiya 	/*
6155110af7aSsekiya 	 * Since we don't have any state, this'll nuke our lights,
6165110af7aSsekiya 	 * key click, and other bits in ZSKBD_CTRL_A.
6175110af7aSsekiya 	 */
6185110af7aSsekiya 	if (period >= 1000)
6195110af7aSsekiya 		zs_putc(cookie, ZSKBD_CTRL_A_LBEEP);
6205110af7aSsekiya 	else
6215110af7aSsekiya 		zs_putc(cookie, ZSKBD_CTRL_A_SBEEP);
6225110af7aSsekiya }
623