xref: /netbsd-src/sys/arch/sgimips/dev/zs_ms.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: zs_ms.c,v 1.1 2004/07/08 22:30:53 sekiya Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 Steve Rumble
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * IP12/IP20 serial mouse driver attached to zs channel 1 at 4800bps.
32  * This layer feeds wsmouse.
33  *
34  * 5 byte packets: sync, x1, y1, x2, y2
35  * sync format: binary 10000LMR (left, middle, right) 0 is down
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: zs_ms.c,v 1.1 2004/07/08 22:30:53 sekiya Exp $");
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/conf.h>
44 #include <sys/device.h>
45 
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsmousevar.h>
48 
49 #include <dev/ic/z8530reg.h>
50 #include <machine/machtype.h>
51 #include <machine/z8530var.h>
52 
53 #define ZSMS_BAUD	4800
54 #define ZSMS_RXQ_LEN	64	/* power of 2 */
55 
56 /* protocol */
57 #define ZSMS_SYNC		0x80
58 #define ZSMS_SYNC_MASK		0xf8
59 #define ZSMS_SYNC_BTN_R		0x01
60 #define ZSMS_SYNC_BTN_M		0x02
61 #define ZSMS_SYNC_BTN_L		0x04
62 #define ZSMS_SYNC_BTN_MASK	0x07
63 
64 struct zsms_softc {
65 	struct device	sc_dev;
66 
67 	/* tail-chasing fifo */
68 	u_char		rxq[ZSMS_RXQ_LEN];
69 	u_char		rxq_head;
70 	u_char		rxq_tail;
71 
72 	/* 5-byte packet as described above */
73 #define	ZSMS_PACKET_SYNC	0
74 #define	ZSMS_PACKET_X1		1
75 #define	ZSMS_PACKET_Y1		2
76 #define	ZSMS_PACKET_X2		3
77 #define	ZSMS_PACKET_Y2		4
78 	u_char		packet[5];
79 
80 #define ZSMS_STATE_SYNC	0x01
81 #define ZSMS_STATE_X1	0x02
82 #define ZSMS_STATE_Y1	0x04
83 #define ZSMS_STATE_X2	0x08
84 #define ZSMS_STATE_Y2	0x10
85 	u_char		state;
86 
87 	/* wsmouse bits */
88 	int		enabled;
89 	struct device  *wsmousedev;
90 };
91 
92 static int	zsms_match(struct device *, struct cfdata *, void *);
93 static void	zsms_attach(struct device *, struct device *, void *);
94 static void	zsms_rxint(struct zs_chanstate *);
95 static void	zsms_txint(struct zs_chanstate *);
96 static void	zsms_stint(struct zs_chanstate *, int);
97 static void	zsms_softint(struct zs_chanstate *);
98 
99 static void	zsms_wsmouse_input(struct zsms_softc *);
100 static int	zsms_wsmouse_enable(void *);
101 static void	zsms_wsmouse_disable(void *);
102 static int	zsms_wsmouse_ioctl(void *, u_long, caddr_t, int,
103 						   struct proc *);
104 
105 CFATTACH_DECL(zsms, sizeof(struct zsms_softc),
106 	      zsms_match, zsms_attach, NULL, NULL);
107 
108 static struct zsops zsms_zsops = {
109 	zsms_rxint,
110 	zsms_stint,
111 	zsms_txint,
112 	zsms_softint
113 };
114 
115 static const struct wsmouse_accessops zsms_wsmouse_accessops = {
116 	zsms_wsmouse_enable,
117 	zsms_wsmouse_ioctl,
118 	zsms_wsmouse_disable
119 };
120 
121 int
122 zsms_match(struct device *parent, struct cfdata *cf, void *aux)
123 {
124 	if (mach_type == MACH_SGI_IP12 || mach_type == MACH_SGI_IP20) {
125 		struct zsc_attach_args *args = aux;
126 
127 		if (args->channel == 1)
128 			return (1);
129 	}
130 
131 	return (0);
132 }
133 
134 void
135 zsms_attach(struct device *parent, struct device *self, void *aux)
136 {
137 	int				s, channel;
138 	struct zsc_softc	       *zsc = (struct zsc_softc *)parent;
139 	struct zsms_softc	       *sc = (struct zsms_softc *)self;
140 	struct zsc_attach_args	       *args = aux;
141 	struct zs_chanstate	       *cs;
142 	struct wsmousedev_attach_args	wsmaa;
143 
144 	/* Establish ourself with the MD z8530 driver */
145 	channel = args->channel;
146 	cs = zsc->zsc_cs[channel];
147 	cs->cs_ops = &zsms_zsops;
148 	cs->cs_private = sc;
149 
150 	sc->enabled = 0;
151 	sc->rxq_head = 0;
152 	sc->rxq_tail = 0;
153 	sc->state = ZSMS_STATE_SYNC;
154 
155 	printf(": baud rate %d\n", ZSMS_BAUD);
156 
157 	s = splzs();
158 	zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET);
159 	cs->cs_preg[1] = ZSWR1_RIE;
160 	zs_set_speed(cs, ZSMS_BAUD);
161 	zs_loadchannelregs(cs);
162 	splx(s);
163 
164 	/* attach wsmouse */
165 	wsmaa.accessops =	&zsms_wsmouse_accessops;
166 	wsmaa.accesscookie =	sc;
167 	sc->wsmousedev =	config_found(self, &wsmaa, wsmousedevprint);
168 }
169 
170 void
171 zsms_rxint(struct zs_chanstate *cs)
172 {
173 	u_char c, r;
174 	struct zsms_softc *sc = (struct zsms_softc *)cs->cs_private;
175 
176 	/* clear errors */
177 	r = zs_read_reg(cs, 1);
178 	if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE))
179 		zs_write_csr(cs, ZSWR0_RESET_ERRORS);
180 
181 	/* read byte and append to our queue */
182 	c = zs_read_data(cs);
183 
184 	sc->rxq[sc->rxq_tail] = c;
185 	sc->rxq_tail = (sc->rxq_tail + 1) & ~ZSMS_RXQ_LEN;
186 
187 	cs->cs_softreq = 1;
188 }
189 
190 /* We should never get here. */
191 void
192 zsms_txint(struct zs_chanstate *cs)
193 {
194 	zs_write_reg(cs, 0, ZSWR0_RESET_TXINT);
195 
196 	/* seems like the in thing to do */
197 	cs->cs_softreq = 1;
198 }
199 
200 void
201 zsms_stint(struct zs_chanstate *cs, int force)
202 {
203 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
204 	cs->cs_softreq = 1;
205 }
206 
207 void
208 zsms_softint(struct zs_chanstate *cs)
209 {
210 	struct zsms_softc *sc = (struct zsms_softc *)cs->cs_private;
211 
212 	/* No need to keep score if nobody is listening */
213 	if (!sc->enabled) {
214 		sc->rxq_head = sc->rxq_tail;
215 		return;
216 	}
217 
218 	/*
219 	 * Here's the real action. Read a full packet and
220 	 * then let wsmouse know what has happened.
221 	 */
222 	while (sc->rxq_head != sc->rxq_tail) {
223 		u_char c = sc->rxq[sc->rxq_head];
224 
225 		switch (sc->state) {
226 		case ZSMS_STATE_SYNC:
227 			if ((c & ZSMS_SYNC_MASK) == ZSMS_SYNC) {
228 				sc->packet[ZSMS_PACKET_SYNC] = c;
229 				sc->state = ZSMS_STATE_X1;
230 			}
231 			break;
232 
233 		case ZSMS_STATE_X1:
234 			sc->packet[ZSMS_PACKET_X1] = c;
235 			sc->state = ZSMS_STATE_Y1;
236 			break;
237 
238 		case ZSMS_STATE_Y1:
239 			sc->packet[ZSMS_PACKET_Y1] = c;
240 			sc->state = ZSMS_STATE_X2;
241 			break;
242 
243 		case ZSMS_STATE_X2:
244 			sc->packet[ZSMS_PACKET_X2] = c;
245 			sc->state = ZSMS_STATE_Y2;
246 			break;
247 
248 		case ZSMS_STATE_Y2:
249 			sc->packet[ZSMS_PACKET_Y2] = c;
250 
251 			/* tweak wsmouse */
252 			zsms_wsmouse_input(sc);
253 
254 			sc->state = ZSMS_STATE_SYNC;
255 		}
256 
257 		sc->rxq_head = (sc->rxq_head + 1) & ~ZSMS_RXQ_LEN;
258 	}
259 }
260 
261 /******************************************************************************
262  * wsmouse glue
263  ******************************************************************************/
264 
265 static void
266 zsms_wsmouse_input(struct zsms_softc *sc)
267 {
268 	int	x, y;
269 	u_int	btns;
270 
271 	btns = sc->packet[ZSMS_PACKET_SYNC] & ZSMS_SYNC_BTN_MASK;
272 	x = sc->packet[ZSMS_PACKET_X1] + sc->packet[ZSMS_PACKET_X2];
273 	y = sc->packet[ZSMS_PACKET_Y1] + sc->packet[ZSMS_PACKET_Y2];
274 
275 	/*
276 	 * XXX - how does wsmouse want the buttons represented???
277 	 */
278 
279 	wsmouse_input(sc->wsmousedev, btns, x, y, 0, WSMOUSE_INPUT_DELTA);
280 }
281 
282 static int
283 zsms_wsmouse_enable(void *cookie)
284 {
285 	struct zsms_softc *sc = (struct zsms_softc *)cookie;
286 
287 	if (sc->enabled)
288 		return (EBUSY);
289 
290 	sc->state = ZSMS_STATE_SYNC;
291 	sc->enabled = 1;
292 
293 	return (0);
294 }
295 
296 void
297 zsms_wsmouse_disable(void *cookie)
298 {
299 	struct zsms_softc *sc = (struct zsms_softc *)cookie;
300 
301 	sc->enabled = 0;
302 }
303 
304 static int
305 zsms_wsmouse_ioctl(void *cookie, u_long cmd,
306 		   caddr_t data, int flag, struct proc *p)
307 {
308 	switch (cmd) {
309 	case WSMOUSEIO_GTYPE:
310 		*(u_int *)data = WSMOUSE_TYPE_SGI;
311 		break;
312 
313 #ifdef notyet
314 	case WSMOUSEIO_SRES:
315 	case WSMOUSEIO_SSCALE:
316 	case WSMOUSEIO_SRATE:
317 	case WSMOUSEIO_SCALIBCOORDS:
318 	case WSMOUSEIO_GCALIBCOORDS:
319 	case WSMOUSEIO_GETID:
320 #endif
321 
322 	default:
323 		return (EPASSTHROUGH);
324 	}
325 
326 	return (0);
327 }
328