xref: /netbsd-src/sys/arch/sgimips/dev/zs_ms.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
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