1*c7fb772bSthorpej /* $NetBSD: zs_ms.c,v 1.10 2021/08/07 16:19:04 thorpej 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 mouse driver attached to zs channel 1 at 4800bps.
325110af7aSsekiya * This layer feeds wsmouse.
335110af7aSsekiya *
345110af7aSsekiya * 5 byte packets: sync, x1, y1, x2, y2
355110af7aSsekiya * sync format: binary 10000LMR (left, middle, right) 0 is down
365110af7aSsekiya */
375110af7aSsekiya
385110af7aSsekiya #include <sys/cdefs.h>
39*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: zs_ms.c,v 1.10 2021/08/07 16:19:04 thorpej Exp $");
405110af7aSsekiya
415110af7aSsekiya #include <sys/param.h>
425110af7aSsekiya #include <sys/systm.h>
435110af7aSsekiya #include <sys/conf.h>
445110af7aSsekiya #include <sys/device.h>
455110af7aSsekiya
465110af7aSsekiya #include <dev/wscons/wsconsio.h>
475110af7aSsekiya #include <dev/wscons/wsmousevar.h>
485110af7aSsekiya
495110af7aSsekiya #include <dev/ic/z8530reg.h>
505110af7aSsekiya #include <machine/machtype.h>
515110af7aSsekiya #include <machine/z8530var.h>
525110af7aSsekiya
535110af7aSsekiya #define ZSMS_BAUD 4800
545110af7aSsekiya #define ZSMS_RXQ_LEN 64 /* power of 2 */
555110af7aSsekiya
565110af7aSsekiya /* protocol */
575110af7aSsekiya #define ZSMS_SYNC 0x80
585110af7aSsekiya #define ZSMS_SYNC_MASK 0xf8
595110af7aSsekiya #define ZSMS_SYNC_BTN_R 0x01
605110af7aSsekiya #define ZSMS_SYNC_BTN_M 0x02
615110af7aSsekiya #define ZSMS_SYNC_BTN_L 0x04
625110af7aSsekiya #define ZSMS_SYNC_BTN_MASK 0x07
635110af7aSsekiya
645110af7aSsekiya struct zsms_softc {
6502cb47caStsutsui device_t sc_dev;
665110af7aSsekiya
675110af7aSsekiya /* tail-chasing fifo */
6802cb47caStsutsui uint8_t rxq[ZSMS_RXQ_LEN];
6902cb47caStsutsui uint8_t rxq_head;
7002cb47caStsutsui uint8_t rxq_tail;
715110af7aSsekiya
725110af7aSsekiya /* 5-byte packet as described above */
735110af7aSsekiya #define ZSMS_PACKET_SYNC 0
745110af7aSsekiya #define ZSMS_PACKET_X1 1
755110af7aSsekiya #define ZSMS_PACKET_Y1 2
765110af7aSsekiya #define ZSMS_PACKET_X2 3
775110af7aSsekiya #define ZSMS_PACKET_Y2 4
78c68fe159Stsutsui int8_t packet[5];
795110af7aSsekiya
805110af7aSsekiya #define ZSMS_STATE_SYNC 0x01
815110af7aSsekiya #define ZSMS_STATE_X1 0x02
825110af7aSsekiya #define ZSMS_STATE_Y1 0x04
835110af7aSsekiya #define ZSMS_STATE_X2 0x08
845110af7aSsekiya #define ZSMS_STATE_Y2 0x10
8502cb47caStsutsui uint8_t state;
865110af7aSsekiya
875110af7aSsekiya /* wsmouse bits */
885110af7aSsekiya int enabled;
89cbab9cadSchs device_t wsmousedev;
905110af7aSsekiya };
915110af7aSsekiya
9202cb47caStsutsui static int zsms_match(device_t, cfdata_t, void *);
9302cb47caStsutsui static void zsms_attach(device_t, device_t, void *);
945110af7aSsekiya static void zsms_rxint(struct zs_chanstate *);
955110af7aSsekiya static void zsms_txint(struct zs_chanstate *);
965110af7aSsekiya static void zsms_stint(struct zs_chanstate *, int);
975110af7aSsekiya static void zsms_softint(struct zs_chanstate *);
985110af7aSsekiya
995110af7aSsekiya static void zsms_wsmouse_input(struct zsms_softc *);
1005110af7aSsekiya static int zsms_wsmouse_enable(void *);
1015110af7aSsekiya static void zsms_wsmouse_disable(void *);
10253524e44Schristos static int zsms_wsmouse_ioctl(void *, u_long, void *, int,
10395e1ffb1Schristos struct lwp *);
1045110af7aSsekiya
10502cb47caStsutsui CFATTACH_DECL_NEW(zsms, sizeof(struct zsms_softc),
1065110af7aSsekiya zsms_match, zsms_attach, NULL, NULL);
1075110af7aSsekiya
1085110af7aSsekiya static struct zsops zsms_zsops = {
1095110af7aSsekiya zsms_rxint,
1105110af7aSsekiya zsms_stint,
1115110af7aSsekiya zsms_txint,
1125110af7aSsekiya zsms_softint
1135110af7aSsekiya };
1145110af7aSsekiya
1155110af7aSsekiya static const struct wsmouse_accessops zsms_wsmouse_accessops = {
1165110af7aSsekiya zsms_wsmouse_enable,
1175110af7aSsekiya zsms_wsmouse_ioctl,
1185110af7aSsekiya zsms_wsmouse_disable
1195110af7aSsekiya };
1205110af7aSsekiya
1215110af7aSsekiya int
zsms_match(device_t parent,cfdata_t cf,void * aux)12202cb47caStsutsui zsms_match(device_t parent, cfdata_t cf, void *aux)
1235110af7aSsekiya {
12402cb47caStsutsui
1255110af7aSsekiya if (mach_type == MACH_SGI_IP12 || mach_type == MACH_SGI_IP20) {
1265110af7aSsekiya struct zsc_attach_args *args = aux;
1275110af7aSsekiya
1285110af7aSsekiya if (args->channel == 1)
1295110af7aSsekiya return (1);
1305110af7aSsekiya }
1315110af7aSsekiya
1325110af7aSsekiya return (0);
1335110af7aSsekiya }
1345110af7aSsekiya
1355110af7aSsekiya void
zsms_attach(device_t parent,device_t self,void * aux)13602cb47caStsutsui zsms_attach(device_t parent, device_t self, void *aux)
1375110af7aSsekiya {
1385110af7aSsekiya int s, channel;
13902cb47caStsutsui struct zsc_softc *zsc;
14002cb47caStsutsui struct zsms_softc *sc;
14102cb47caStsutsui struct zsc_attach_args *args;
1425110af7aSsekiya struct zs_chanstate *cs;
1435110af7aSsekiya struct wsmousedev_attach_args wsmaa;
1445110af7aSsekiya
14502cb47caStsutsui zsc = device_private(parent);
14602cb47caStsutsui sc = device_private(self);
14702cb47caStsutsui sc->sc_dev = self;
14802cb47caStsutsui args = aux;
14902cb47caStsutsui
1505110af7aSsekiya /* Establish ourself with the MD z8530 driver */
1515110af7aSsekiya channel = args->channel;
1525110af7aSsekiya cs = zsc->zsc_cs[channel];
1535110af7aSsekiya cs->cs_ops = &zsms_zsops;
1545110af7aSsekiya cs->cs_private = sc;
1555110af7aSsekiya
1565110af7aSsekiya sc->enabled = 0;
1575110af7aSsekiya sc->rxq_head = 0;
1585110af7aSsekiya sc->rxq_tail = 0;
1595110af7aSsekiya sc->state = ZSMS_STATE_SYNC;
1605110af7aSsekiya
16102cb47caStsutsui aprint_normal(": baud rate %d\n", ZSMS_BAUD);
1625110af7aSsekiya
1635110af7aSsekiya s = splzs();
1645110af7aSsekiya zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET);
1655110af7aSsekiya cs->cs_preg[1] = ZSWR1_RIE;
1665110af7aSsekiya zs_set_speed(cs, ZSMS_BAUD);
1675110af7aSsekiya zs_loadchannelregs(cs);
1685110af7aSsekiya splx(s);
1695110af7aSsekiya
1705110af7aSsekiya /* attach wsmouse */
1715110af7aSsekiya wsmaa.accessops = &zsms_wsmouse_accessops;
1725110af7aSsekiya wsmaa.accesscookie = sc;
1732685996bSthorpej sc->wsmousedev = config_found(self, &wsmaa, wsmousedevprint,
174*c7fb772bSthorpej CFARGS_NONE);
1755110af7aSsekiya }
1765110af7aSsekiya
1775110af7aSsekiya void
zsms_rxint(struct zs_chanstate * cs)1785110af7aSsekiya zsms_rxint(struct zs_chanstate *cs)
1795110af7aSsekiya {
18002cb47caStsutsui uint8_t c, r;
18102cb47caStsutsui struct zsms_softc *sc = cs->cs_private;
1825110af7aSsekiya
1835110af7aSsekiya /* clear errors */
1845110af7aSsekiya r = zs_read_reg(cs, 1);
1855110af7aSsekiya if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE))
1865110af7aSsekiya zs_write_csr(cs, ZSWR0_RESET_ERRORS);
1875110af7aSsekiya
1885110af7aSsekiya /* read byte and append to our queue */
1895110af7aSsekiya c = zs_read_data(cs);
1905110af7aSsekiya
1915110af7aSsekiya sc->rxq[sc->rxq_tail] = c;
1925110af7aSsekiya sc->rxq_tail = (sc->rxq_tail + 1) & ~ZSMS_RXQ_LEN;
1935110af7aSsekiya
1945110af7aSsekiya cs->cs_softreq = 1;
1955110af7aSsekiya }
1965110af7aSsekiya
1975110af7aSsekiya /* We should never get here. */
1985110af7aSsekiya void
zsms_txint(struct zs_chanstate * cs)1995110af7aSsekiya zsms_txint(struct zs_chanstate *cs)
2005110af7aSsekiya {
20102cb47caStsutsui
2025110af7aSsekiya zs_write_reg(cs, 0, ZSWR0_RESET_TXINT);
2035110af7aSsekiya
2045110af7aSsekiya /* seems like the in thing to do */
2055110af7aSsekiya cs->cs_softreq = 1;
2065110af7aSsekiya }
2075110af7aSsekiya
2085110af7aSsekiya void
zsms_stint(struct zs_chanstate * cs,int force)2095110af7aSsekiya zsms_stint(struct zs_chanstate *cs, int force)
2105110af7aSsekiya {
21102cb47caStsutsui
2125110af7aSsekiya zs_write_csr(cs, ZSWR0_RESET_STATUS);
2135110af7aSsekiya cs->cs_softreq = 1;
2145110af7aSsekiya }
2155110af7aSsekiya
2165110af7aSsekiya void
zsms_softint(struct zs_chanstate * cs)2175110af7aSsekiya zsms_softint(struct zs_chanstate *cs)
2185110af7aSsekiya {
21902cb47caStsutsui struct zsms_softc *sc = cs->cs_private;
2205110af7aSsekiya
2215110af7aSsekiya /* No need to keep score if nobody is listening */
2225110af7aSsekiya if (!sc->enabled) {
2235110af7aSsekiya sc->rxq_head = sc->rxq_tail;
2245110af7aSsekiya return;
2255110af7aSsekiya }
2265110af7aSsekiya
2275110af7aSsekiya /*
2285110af7aSsekiya * Here's the real action. Read a full packet and
2295110af7aSsekiya * then let wsmouse know what has happened.
2305110af7aSsekiya */
2315110af7aSsekiya while (sc->rxq_head != sc->rxq_tail) {
232c68fe159Stsutsui int8_t c = sc->rxq[sc->rxq_head];
2335110af7aSsekiya
2345110af7aSsekiya switch (sc->state) {
2355110af7aSsekiya case ZSMS_STATE_SYNC:
2365110af7aSsekiya if ((c & ZSMS_SYNC_MASK) == ZSMS_SYNC) {
2375110af7aSsekiya sc->packet[ZSMS_PACKET_SYNC] = c;
2385110af7aSsekiya sc->state = ZSMS_STATE_X1;
2395110af7aSsekiya }
2405110af7aSsekiya break;
2415110af7aSsekiya
2425110af7aSsekiya case ZSMS_STATE_X1:
2435110af7aSsekiya sc->packet[ZSMS_PACKET_X1] = c;
2445110af7aSsekiya sc->state = ZSMS_STATE_Y1;
2455110af7aSsekiya break;
2465110af7aSsekiya
2475110af7aSsekiya case ZSMS_STATE_Y1:
2485110af7aSsekiya sc->packet[ZSMS_PACKET_Y1] = c;
2495110af7aSsekiya sc->state = ZSMS_STATE_X2;
2505110af7aSsekiya break;
2515110af7aSsekiya
2525110af7aSsekiya case ZSMS_STATE_X2:
2535110af7aSsekiya sc->packet[ZSMS_PACKET_X2] = c;
2545110af7aSsekiya sc->state = ZSMS_STATE_Y2;
2555110af7aSsekiya break;
2565110af7aSsekiya
2575110af7aSsekiya case ZSMS_STATE_Y2:
2585110af7aSsekiya sc->packet[ZSMS_PACKET_Y2] = c;
2595110af7aSsekiya
2605110af7aSsekiya /* tweak wsmouse */
2615110af7aSsekiya zsms_wsmouse_input(sc);
2625110af7aSsekiya
2635110af7aSsekiya sc->state = ZSMS_STATE_SYNC;
2645110af7aSsekiya }
2655110af7aSsekiya
2665110af7aSsekiya sc->rxq_head = (sc->rxq_head + 1) & ~ZSMS_RXQ_LEN;
2675110af7aSsekiya }
2685110af7aSsekiya }
2695110af7aSsekiya
2705110af7aSsekiya /******************************************************************************
2715110af7aSsekiya * wsmouse glue
2725110af7aSsekiya ******************************************************************************/
2735110af7aSsekiya
2745110af7aSsekiya static void
zsms_wsmouse_input(struct zsms_softc * sc)2755110af7aSsekiya zsms_wsmouse_input(struct zsms_softc *sc)
2765110af7aSsekiya {
2775110af7aSsekiya u_int btns;
278c68fe159Stsutsui int bl, bm, br;
279c68fe159Stsutsui int x, y;
2805110af7aSsekiya
281c68fe159Stsutsui btns = (uint8_t)sc->packet[ZSMS_PACKET_SYNC] & ZSMS_SYNC_BTN_MASK;
2825110af7aSsekiya
283c68fe159Stsutsui bl = (btns & ZSMS_SYNC_BTN_L) == 0;
284c68fe159Stsutsui bm = (btns & ZSMS_SYNC_BTN_M) == 0;
285c68fe159Stsutsui br = (btns & ZSMS_SYNC_BTN_R) == 0;
286c68fe159Stsutsui
287c68fe159Stsutsui /* for wsmouse(4), 1 is down, 0 is up, the most left button is LSB */
288c68fe159Stsutsui btns = (bl ? (1 << 0) : 0) | (bm ? (1 << 1) : 0) | (br ? (1 << 2) : 0);
289c68fe159Stsutsui
290c68fe159Stsutsui x = (int)sc->packet[ZSMS_PACKET_X1] + (int)sc->packet[ZSMS_PACKET_X2];
291c68fe159Stsutsui y = (int)sc->packet[ZSMS_PACKET_Y1] + (int)sc->packet[ZSMS_PACKET_Y2];
2925110af7aSsekiya
29357c0199dSplunky wsmouse_input(sc->wsmousedev, btns, x, y, 0, 0, WSMOUSE_INPUT_DELTA);
2945110af7aSsekiya }
2955110af7aSsekiya
2965110af7aSsekiya static int
zsms_wsmouse_enable(void * cookie)2975110af7aSsekiya zsms_wsmouse_enable(void *cookie)
2985110af7aSsekiya {
29902cb47caStsutsui struct zsms_softc *sc = cookie;
3005110af7aSsekiya
3015110af7aSsekiya if (sc->enabled)
3025110af7aSsekiya return (EBUSY);
3035110af7aSsekiya
3045110af7aSsekiya sc->state = ZSMS_STATE_SYNC;
3055110af7aSsekiya sc->enabled = 1;
3065110af7aSsekiya
3075110af7aSsekiya return (0);
3085110af7aSsekiya }
3095110af7aSsekiya
3105110af7aSsekiya void
zsms_wsmouse_disable(void * cookie)3115110af7aSsekiya zsms_wsmouse_disable(void *cookie)
3125110af7aSsekiya {
31302cb47caStsutsui struct zsms_softc *sc = cookie;
3145110af7aSsekiya
3155110af7aSsekiya sc->enabled = 0;
3165110af7aSsekiya }
3175110af7aSsekiya
3185110af7aSsekiya static int
zsms_wsmouse_ioctl(void * cookie,u_long cmd,void * data,int flag,struct lwp * l)3195110af7aSsekiya zsms_wsmouse_ioctl(void *cookie, u_long cmd,
32053524e44Schristos void *data, int flag, struct lwp *l)
3215110af7aSsekiya {
32202cb47caStsutsui
3235110af7aSsekiya switch (cmd) {
3245110af7aSsekiya case WSMOUSEIO_GTYPE:
3255110af7aSsekiya *(u_int *)data = WSMOUSE_TYPE_SGI;
3265110af7aSsekiya break;
3275110af7aSsekiya
3285110af7aSsekiya #ifdef notyet
3295110af7aSsekiya case WSMOUSEIO_SRES:
3305110af7aSsekiya case WSMOUSEIO_SSCALE:
3315110af7aSsekiya case WSMOUSEIO_SRATE:
3325110af7aSsekiya case WSMOUSEIO_SCALIBCOORDS:
3335110af7aSsekiya case WSMOUSEIO_GCALIBCOORDS:
3345110af7aSsekiya case WSMOUSEIO_GETID:
3355110af7aSsekiya #endif
3365110af7aSsekiya
3375110af7aSsekiya default:
3385110af7aSsekiya return (EPASSTHROUGH);
3395110af7aSsekiya }
3405110af7aSsekiya
3415110af7aSsekiya return (0);
3425110af7aSsekiya }
343