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