xref: /openbsd-src/sys/dev/sun/sunms.c (revision 4b1a56afb1a28c97103da3911d326d1216798a6e)
1*4b1a56afSjsg /*	$OpenBSD: sunms.c,v 1.3 2022/01/09 05:43:00 jsg Exp $	*/
219cddadbSmiod 
319cddadbSmiod /*
419cddadbSmiod  * Copyright (c) 2002, 2009, Miodrag Vallat
519cddadbSmiod  * All rights reserved.
619cddadbSmiod  *
719cddadbSmiod  * Redistribution and use in source and binary forms, with or without
819cddadbSmiod  * modification, are permitted provided that the following conditions
919cddadbSmiod  * are met:
1019cddadbSmiod  * 1. Redistributions of source code must retain the above copyright
1119cddadbSmiod  *    notice, this list of conditions and the following disclaimer.
1219cddadbSmiod  * 2. Redistributions in binary form must reproduce the above copyright
1319cddadbSmiod  *    notice, this list of conditions and the following disclaimer in the
1419cddadbSmiod  *    documentation and/or other materials provided with the distribution.
1519cddadbSmiod  *
1619cddadbSmiod  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1719cddadbSmiod  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1819cddadbSmiod  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919cddadbSmiod  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2019cddadbSmiod  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2119cddadbSmiod  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2219cddadbSmiod  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2319cddadbSmiod  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2419cddadbSmiod  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2519cddadbSmiod  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2619cddadbSmiod  */
2719cddadbSmiod 
2819cddadbSmiod /*
2919cddadbSmiod  * Common Sun mouse handling code.
3019cddadbSmiod  *
3119cddadbSmiod  * This code supports 3- and 5- byte Mouse Systems protocols, and speeds of
3219cddadbSmiod  * 1200, 4800 and 9600 bps.
3319cddadbSmiod  */
3419cddadbSmiod 
3519cddadbSmiod #include <sys/param.h>
3619cddadbSmiod #include <sys/systm.h>
3719cddadbSmiod #include <sys/conf.h>
3819cddadbSmiod #include <sys/device.h>
3919cddadbSmiod #include <sys/ioctl.h>
4019cddadbSmiod #include <sys/kernel.h>
4119cddadbSmiod #include <sys/proc.h>
4219cddadbSmiod #include <sys/time.h>
4319cddadbSmiod #include <sys/timeout.h>
4419cddadbSmiod 
4519cddadbSmiod #include <dev/wscons/wsconsio.h>
4619cddadbSmiod #include <dev/wscons/wsmousevar.h>
4719cddadbSmiod 
4819cddadbSmiod #include <dev/sun/sunmsvar.h>
4919cddadbSmiod 
5019cddadbSmiod void
sunms_attach(struct sunms_softc * sc,const struct wsmouse_accessops * ao)5119cddadbSmiod sunms_attach(struct sunms_softc *sc, const struct wsmouse_accessops *ao)
5219cddadbSmiod {
5319cddadbSmiod 	struct wsmousedev_attach_args a;
5419cddadbSmiod 
5519cddadbSmiod 	printf("\n");
5619cddadbSmiod 
5719cddadbSmiod 	/* Initialize state machine. */
5819cddadbSmiod 	sc->sc_state = STATE_PROBING;
5919cddadbSmiod 	sc->sc_bps = INIT_SPEED;
6019cddadbSmiod 	timeout_set(&sc->sc_abort_tmo, sunms_abort_input, sc);
6119cddadbSmiod 
6219cddadbSmiod 	/*
6319cddadbSmiod 	 * Note that it doesn't matter if a long time elapses between this
6419cddadbSmiod 	 * and the moment interrupts are enabled, as we either have the
6519cddadbSmiod 	 * right speed, and will switch to decode state, or get a break
6619cddadbSmiod 	 * or a framing error, causing an immediate speed change.
6719cddadbSmiod 	 */
6819cddadbSmiod 	getmicrotime(&sc->sc_lastbpschange);
6919cddadbSmiod 
7019cddadbSmiod 	a.accessops = ao;
7119cddadbSmiod 	a.accesscookie = sc;
7219cddadbSmiod 	sc->sc_wsmousedev = config_found(&sc->sc_dev, &a, wsmousedevprint);
7319cddadbSmiod }
7419cddadbSmiod 
7519cddadbSmiod int
sunms_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)7619cddadbSmiod sunms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
7719cddadbSmiod {
7819cddadbSmiod #if 0
7919cddadbSmiod 	struct sunms_softc *sc = v;
8019cddadbSmiod #endif
8119cddadbSmiod 
8219cddadbSmiod 	switch (cmd) {
8319cddadbSmiod 	case WSMOUSEIO_GTYPE:
8419cddadbSmiod 		*(u_int *)data = WSMOUSE_TYPE_SUN;
8519cddadbSmiod 		break;
8619cddadbSmiod 
8719cddadbSmiod 	default:
8819cddadbSmiod 		return -1;
8919cddadbSmiod 	}
9019cddadbSmiod 
9119cddadbSmiod 	return 0;
9219cddadbSmiod }
9319cddadbSmiod 
9419cddadbSmiod /*
9519cddadbSmiod  * Reinitialize the line to a different speed.  Invoked at spltty().
9619cddadbSmiod  */
9719cddadbSmiod void
sunms_speed_change(struct sunms_softc * sc)9819cddadbSmiod sunms_speed_change(struct sunms_softc *sc)
9919cddadbSmiod {
10019cddadbSmiod 	uint bps;
10119cddadbSmiod 
10219cddadbSmiod 	switch (sc->sc_bps) {
10319cddadbSmiod 	default:
10419cddadbSmiod 	case 9600:
10519cddadbSmiod 		bps = 4800;
10619cddadbSmiod 		break;
10719cddadbSmiod 	case 4800:
10819cddadbSmiod 		bps = 1200;
10919cddadbSmiod 		break;
11019cddadbSmiod 	case 1200:
11119cddadbSmiod 		bps = 9600;
11219cddadbSmiod 		break;
11319cddadbSmiod 	}
11419cddadbSmiod 
11519cddadbSmiod #ifdef DEBUG
11619cddadbSmiod 	printf("%s: %d bps\n", sc->sc_dev.dv_xname, bps);
11719cddadbSmiod #endif
11819cddadbSmiod 	microtime(&sc->sc_lastbpschange);
11919cddadbSmiod 
12019cddadbSmiod 	(*sc->sc_speed_change)(sc, bps);
12119cddadbSmiod 	sc->sc_state = STATE_PROBING;
12219cddadbSmiod 	sc->sc_bps = bps;
12319cddadbSmiod 	sc->sc_brk = 0;
12419cddadbSmiod 	timeout_del(&sc->sc_abort_tmo);
12519cddadbSmiod }
12619cddadbSmiod 
12719cddadbSmiod /*
12819cddadbSmiod  * Process actual mouse data.  Invoked at spltty().
12919cddadbSmiod  */
13019cddadbSmiod void
sunms_input(struct sunms_softc * sc,int c)13119cddadbSmiod sunms_input(struct sunms_softc *sc, int c)
13219cddadbSmiod {
13319cddadbSmiod 	struct timeval curtime;
13419cddadbSmiod 
13519cddadbSmiod 	if (sc->sc_wsmousedev == NULL)
13619cddadbSmiod 		return;	/* why bother */
13719cddadbSmiod 
13819cddadbSmiod 	if (sc->sc_state == STATE_RATE_CHANGE)
13919cddadbSmiod 		return;	/* not ready yet */
14019cddadbSmiod 
14119cddadbSmiod 	/*
14219cddadbSmiod 	 * If we have changed speed recently, ignore data for a few
14319cddadbSmiod 	 * milliseconds to make sure that either we'll detect the speed
14419cddadbSmiod 	 * is still not correct, or discard potential noise resulting
14519cddadbSmiod 	 * from the speed change.
14619cddadbSmiod 	 */
14719cddadbSmiod 	if (sc->sc_state == STATE_PROBING) {
14819cddadbSmiod 		microtime(&curtime);
14919cddadbSmiod 		timersub(&curtime, &sc->sc_lastbpschange, &curtime);
15019cddadbSmiod 		if (curtime.tv_sec != 0 ||
15119cddadbSmiod 		    curtime.tv_usec >= 200 * 1000) {
15219cddadbSmiod 			sc->sc_state = STATE_DECODING;
15319cddadbSmiod 			sc->sc_byteno = -1;
15419cddadbSmiod 		} else
15519cddadbSmiod 			return;
15619cddadbSmiod 	}
15719cddadbSmiod 
15819cddadbSmiod 	/*
15919cddadbSmiod 	 * The Sun mice use either 3 byte or 5 byte packets. The
16019cddadbSmiod 	 * first byte of each packet has the topmost bit set;
16119cddadbSmiod 	 * however motion parts of the packet may have the topmost
16219cddadbSmiod 	 * bit set too; so we only check for a first byte pattern
16319cddadbSmiod 	 * when we are not currently processing a packet.
16419cddadbSmiod 	 */
16519cddadbSmiod 	if (sc->sc_byteno < 0) {
16619cddadbSmiod 		if (ISSET(c, 0x80) && !ISSET(c, 0x30))
16719cddadbSmiod 			sc->sc_byteno = 0;
16819cddadbSmiod 		else
16919cddadbSmiod 			return;
17019cddadbSmiod 	}
17119cddadbSmiod 
17219cddadbSmiod 	switch (sc->sc_byteno) {
17319cddadbSmiod 	case 0:
17419cddadbSmiod 		/*
17519cddadbSmiod 		 * First packet has bit 7 set; bits 0-2 are button states,
17619cddadbSmiod 		 * and bit 3 is set if it is a short (3 byte) packet.
17719cddadbSmiod 		 * On the Tadpole SPARCbook, mice connected to the external
17819cddadbSmiod 		 * connector will also have bit 6 set to allow it to be
179*4b1a56afSjsg 		 * differentiated from the onboard pointer.
18019cddadbSmiod 		 */
18119cddadbSmiod 		sc->sc_pktlen = ISSET(c, 0x08) ? 3 : 5;
18219cddadbSmiod 		sc->sc_mb = 0;
18319cddadbSmiod 		if (!ISSET(c, 1 << 2))	/* left button */
18419cddadbSmiod 			sc->sc_mb |= 1 << 0;
18519cddadbSmiod 		if (!ISSET(c, 1 << 1))	/* middle button */
18619cddadbSmiod 			sc->sc_mb |= 1 << 1;
18719cddadbSmiod 		if (!ISSET(c, 1 << 0))	/* right button */
18819cddadbSmiod 			sc->sc_mb |= 1 << 2;
18919cddadbSmiod 		sc->sc_byteno++;
19019cddadbSmiod 
19119cddadbSmiod 		/*
19219cddadbSmiod 		 * In case we do not receive the whole packet, we need
19319cddadbSmiod 		 * to be able to reset sc_byteno.
19419cddadbSmiod 		 *
19519cddadbSmiod 		 * At 1200bps 8N2, a five byte packet will span 50 bits
19619cddadbSmiod 		 * and thus will transmit in 1/24 second, or about 42ms.
19719cddadbSmiod 		 *
19819cddadbSmiod 		 * A reset timeout of 100ms will be more than enough.
19919cddadbSmiod 		 */
20019cddadbSmiod 		timeout_add_msec(&sc->sc_abort_tmo, 100);
20119cddadbSmiod 
20219cddadbSmiod 		break;
20319cddadbSmiod 	case 1:
20419cddadbSmiod 	case 3:
20519cddadbSmiod 		/*
20619cddadbSmiod 		 * Following bytes contain signed 7 bit X, then Y deltas.
20719cddadbSmiod 		 * Short packets only have one set of deltas (and are
20819cddadbSmiod 		 * thus usually used on 4800 baud mice).
20919cddadbSmiod 		 */
21019cddadbSmiod 		sc->sc_dx += (int8_t)c;
21119cddadbSmiod 		sc->sc_byteno++;
21219cddadbSmiod 		break;
21319cddadbSmiod 	case 2:
21419cddadbSmiod 	case 4:
21519cddadbSmiod 		sc->sc_dy += (int8_t)c;
21619cddadbSmiod 		sc->sc_byteno++;
21719cddadbSmiod 		break;
21819cddadbSmiod 	}
21919cddadbSmiod 
22019cddadbSmiod 	if (sc->sc_byteno == sc->sc_pktlen) {
22119cddadbSmiod 		timeout_del(&sc->sc_abort_tmo);
22219cddadbSmiod 		sc->sc_byteno = -1;
22394712de5Sbru 		WSMOUSE_INPUT(sc->sc_wsmousedev,
22494712de5Sbru 		    sc->sc_mb, sc->sc_dx, sc->sc_dy, 0, 0);
22519cddadbSmiod 		sc->sc_dx = sc->sc_dy = 0;
22619cddadbSmiod 	}
22719cddadbSmiod }
22819cddadbSmiod 
22919cddadbSmiod void
sunms_abort_input(void * v)23019cddadbSmiod sunms_abort_input(void *v)
23119cddadbSmiod {
23219cddadbSmiod 	struct sunms_softc *sc = v;
23319cddadbSmiod 	int s;
23419cddadbSmiod 
23519cddadbSmiod #ifdef DEBUG
23619cddadbSmiod 	printf("aborting incomplete packet\n");
23719cddadbSmiod #endif
23819cddadbSmiod 	s = spltty();
23919cddadbSmiod 	sc->sc_byteno = -1;
24019cddadbSmiod 	splx(s);
24119cddadbSmiod }
242