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