xref: /openbsd-src/sys/dev/sun/z8530ms.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: z8530ms.c,v 1.1 2009/05/20 18:22:33 miod Exp $	*/
2 /*	$NetBSD: ms.c,v 1.12 1997/07/17 01:17:47 jtk Exp $	*/
3 
4 /*
5  * Copyright (c) 2002, 2009, Miodrag Vallat
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *
29  * Copyright (c) 1992, 1993
30  *	The Regents of the University of California.  All rights reserved.
31  *
32  * This software was developed by the Computer Systems Engineering group
33  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
34  * contributed to Berkeley.
35  *
36  * All advertising materials mentioning features or use of this software
37  * must display the following acknowledgement:
38  *	This product includes software developed by the University of
39  *	California, Lawrence Berkeley Laboratory.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. All advertising materials mentioning features or use of this software
50  *    must display the following acknowledgement:
51  *	This product includes software developed by the University of
52  *	California, Berkeley and its contributors.
53  * 4. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  *
69  *	@(#)ms.c	8.1 (Berkeley) 6/11/93
70  */
71 
72 /*
73  * Zilog Z8530 Dual UART driver (mouse interface)
74  *
75  * This is the "slave" driver that will be attached to
76  * the "zsc" driver for a Sun mouse.
77  */
78 
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/conf.h>
82 #include <sys/device.h>
83 #include <sys/ioctl.h>
84 #include <sys/kernel.h>
85 #include <sys/proc.h>
86 #include <sys/syslog.h>
87 
88 #ifndef __sparc64__	/* until zs driver is unified... */
89 #include <sparc/dev/z8530reg.h>
90 #else
91 #include <sparc64/dev/z8530reg.h>
92 #endif
93 #include <machine/z8530var.h>
94 
95 #include <dev/wscons/wsmousevar.h>
96 #include <dev/sun/sunmsvar.h>
97 
98 /*
99  * How many input characters we can buffer.
100  * Note: must be a power of two!
101  */
102 #define	MS_RX_RING_SIZE	256
103 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1)
104 
105 struct zsms_softc {
106 	struct	sunms_softc sc_base;
107 	struct	zs_chanstate *sc_cs;
108 
109 	/* Flags to communicate with zsms_softint() */
110 	volatile int sc_intr_flags;
111 #define	INTR_RX_OVERRUN 	0x01
112 #define INTR_TX_EMPTY   	0x02
113 #define INTR_ST_CHECK   	0x04
114 #define	INTR_BPS_CHANGE		0x08
115 
116 	/*
117 	 * The receive ring buffer.
118 	 */
119 	uint	sc_rbget;		/* ring buffer `get' index */
120 	volatile uint	sc_rbput;	/* ring buffer `put' index */
121 	uint16_t sc_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */
122 };
123 
124 /*
125  * autoconf glue.
126  */
127 
128 int	zsms_match(struct device *, void *, void *);
129 void	zsms_attach(struct device *, struct device *, void *);
130 
131 const struct cfattach zsms_ca = {
132 	sizeof(struct zsms_softc), zsms_match, zsms_attach
133 };
134 
135 struct cfdriver zsms_cd = {
136 	NULL, "zsms", DV_DULL
137 };
138 
139 /*
140  * wsmouse accessops.
141  */
142 
143 void	zsms_disable(void *);
144 int	zsms_enable(void *);
145 
146 const struct wsmouse_accessops zsms_accessops = {
147 	zsms_enable,
148 	sunms_ioctl,
149 	zsms_disable
150 };
151 
152 /*
153  * zs glue.
154  */
155 
156 void	zsms_rxint(struct zs_chanstate *);
157 void	zsms_softint(struct zs_chanstate *);
158 void	zsms_stint(struct zs_chanstate *, int);
159 void	zsms_txint(struct zs_chanstate *);
160 
161 struct zsops zsops_ms = {
162 	zsms_rxint,	/* receive char available */
163 	zsms_stint,	/* external/status */
164 	zsms_txint,	/* xmit buffer empty */
165 	zsms_softint	/* process software interrupt */
166 };
167 
168 void	zsms_speed_change(void *, uint);
169 
170 /*
171  * autoconf glue.
172  */
173 
174 int
175 zsms_match(struct device *parent, void *vcf, void *aux)
176 {
177 	struct cfdata *cf = vcf;
178 	struct zsc_attach_args *args = aux;
179 	int rc;
180 
181 	/* If we're not looking for a mouse, just exit */
182 	if (strcmp(args->type, "mouse") != 0)
183 		return 0;
184 
185 	rc = 10;
186 
187 	/* Exact match is better than wildcard. */
188 	if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel)
189 		rc += 2;
190 
191 	/* This driver accepts wildcard. */
192 	if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT)
193 		rc += 1;
194 
195 	return rc;
196 }
197 
198 void
199 zsms_attach(struct device *parent, struct device *self, void *aux)
200 {
201 	struct zsc_softc *zsc = (struct zsc_softc *)parent;
202 	struct zsms_softc *sc = (struct zsms_softc *)self;
203 	struct zsc_attach_args *args = aux;
204 	struct zs_chanstate *cs;
205 	int channel;
206 	int s;
207 
208 	channel = args->channel;
209 #ifndef __sparc64__	/* until driver is unified... */
210 	cs = &zsc->zsc_cs[channel];
211 #else
212 	cs = zsc->zsc_cs[channel];
213 #endif
214 	cs->cs_private = sc;
215 	cs->cs_ops = &zsops_ms;
216 	sc->sc_cs = cs;
217 
218 	/* Initialize hardware. */
219 	s = splzs();
220 	zs_write_reg(cs, 9, channel == 0 ?  ZSWR9_A_RESET : ZSWR9_B_RESET);
221 	/* disable interrupts until the mouse is enabled */
222 	CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE | ZSWR1_TIE);
223 	/* 8 data bits is already our default */
224 	/* no parity, 2 stop bits */
225 	CLR(cs->cs_preg[4], ZSWR4_SBMASK | ZSWR4_PARMASK);
226 	SET(cs->cs_preg[4], ZSWR4_TWOSB);
227 	(void)zs_set_speed(cs, INIT_SPEED);
228 	zs_loadchannelregs(cs);
229 	splx(s);
230 
231 	sc->sc_base.sc_speed_change = zsms_speed_change;
232 
233 	sunms_attach(&sc->sc_base, &zsms_accessops);
234 }
235 
236 /*
237  * wsmouse accessops.
238  */
239 
240 void
241 zsms_disable(void *v)
242 {
243 	struct zsms_softc *sc = v;
244 	struct zs_chanstate *cs = sc->sc_cs;
245 	int s;
246 
247 	s = splzs();
248 	/* disable RX and status change interrupts */
249 	CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
250 	zs_loadchannelregs(cs);
251 	splx(s);
252 }
253 
254 int
255 zsms_enable(void *v)
256 {
257 	struct zsms_softc *sc = v;
258 	struct zs_chanstate *cs = sc->sc_cs;
259 	int s;
260 
261 	s = splzs();
262 	/* enable RX and status change interrupts */
263 	SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
264 	zs_loadchannelregs(cs);
265 	splx(s);
266 
267 	return 0;
268 }
269 
270 /*
271  * zs glue.
272  */
273 
274 void
275 zsms_rxint(struct zs_chanstate *cs)
276 {
277 	struct zsms_softc *sc = cs->cs_private;
278 	int put, put_next;
279 	u_char rr0, rr1, c;
280 
281 	put = sc->sc_rbput;
282 
283 	for (;;) {
284 		/*
285 		 * First read the status, because reading the received char
286 		 * destroys the status of this char.
287 		 */
288 		rr1 = zs_read_reg(cs, 1);
289 		c = zs_read_data(cs);
290 
291 		/*
292 		 * Note that we do not try to change speed upon encountering
293 		 * framing errors, as this is not as reliable as breaks.
294 		 */
295 		if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
296 			/* Clear the receive error. */
297 			zs_write_csr(cs, ZSWR0_RESET_ERRORS);
298 		}
299 
300 		if (sc->sc_base.sc_state != STATE_RATE_CHANGE) {
301 			sc->sc_rbuf[put] = (c << 8) | rr1;
302 			put_next = (put + 1) & MS_RX_RING_MASK;
303 
304 			/* Would overrun if increment makes (put==get). */
305 			if (put_next == sc->sc_rbget) {
306 				sc->sc_intr_flags |= INTR_RX_OVERRUN;
307 				break;
308 			} else {
309 				/* OK, really increment. */
310 				put = put_next;
311 			}
312 		}
313 
314 		rr0 = zs_read_csr(cs);
315 		if (!ISSET(rr0, ZSRR0_RX_READY))
316 			break;
317 	}
318 
319 	/* Done reading. */
320 	sc->sc_rbput = put;
321 
322 	cs->cs_softreq = 1;
323 }
324 
325 void
326 zsms_txint(struct zs_chanstate *cs)
327 {
328 	/*
329 	 * This function should never be invoked as we don't accept TX
330 	 * interrupts.  If someone alters our configuration behind our
331 	 * back, just disable TX interrupts again.
332 	 */
333 	zs_write_csr(cs, ZSWR0_RESET_TXINT);
334 
335 	/* disable tx interrupts */
336 	CLR(cs->cs_preg[1], ZSWR1_TIE);
337 	zs_loadchannelregs(cs);
338 }
339 
340 void
341 zsms_stint(struct zs_chanstate *cs, int force)
342 {
343 	struct zsms_softc *sc = cs->cs_private;
344 	uint8_t rr0, delta;
345 
346 	rr0 = zs_read_csr(cs);
347 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
348 
349 	/*
350 	 * A break can occur if the speed is not correct.
351 	 * However, we do not change speed until we get the second
352 	 * break, for switching speed when the mouse is unplugged
353 	 * will trigger a break and thus we'd loop changing speeds
354 	 * until the mouse is plugged again.
355 	 */
356 	if (!force && ISSET(rr0, ZSRR0_BREAK)) {
357 		if (sc->sc_base.sc_state != STATE_RATE_CHANGE &&
358 		    ++sc->sc_base.sc_brk > 1) {
359 			sc->sc_intr_flags |= INTR_BPS_CHANGE;
360 			sc->sc_base.sc_state = STATE_RATE_CHANGE;
361 			cs->cs_softreq = 1;
362 #ifdef DEBUG
363 			printf("%s: break detected, changing speed\n",
364 			    sc->sc_base.sc_dev.dv_xname);
365 #endif
366 		}
367 	}
368 
369 	if (!force)
370 		delta = rr0 ^ cs->cs_rr0;
371 	else
372 		delta = cs->cs_rr0_mask;
373 	cs->cs_rr0 = rr0;
374 
375 	if (ISSET(delta, cs->cs_rr0_mask)) {
376 		SET(cs->cs_rr0_delta, delta);
377 
378 		sc->sc_intr_flags |= INTR_ST_CHECK;
379 		cs->cs_softreq = 1;
380 	}
381 }
382 
383 void
384 zsms_softint(struct zs_chanstate *cs)
385 {
386 	struct zsms_softc *sc;
387 	int get, c, s, s2;
388 	int intr_flags;
389 	u_short ring_data;
390 
391 	sc = cs->cs_private;
392 
393 	/* Atomically get and clear flags. */
394 	s = spltty();
395 	s2 = splzs();
396 	intr_flags = sc->sc_intr_flags;
397 	sc->sc_intr_flags = 0;
398 	/* Now lower to spltty for the rest. */
399 	splx(s2);
400 
401 	/*
402 	 * If we have a baud rate change pending, do it now.
403 	 * This will reset the rx ring, so we can proceed safely.
404 	 */
405 	if (ISSET(intr_flags, INTR_BPS_CHANGE)) {
406 		CLR(intr_flags, INTR_RX_OVERRUN);
407 		sunms_speed_change(&sc->sc_base);
408 		splx(s);
409 	}
410 
411 	/*
412 	 * Copy data from the receive ring, if any, to the event layer.
413 	 */
414 	get = sc->sc_rbget;
415 	while (get != sc->sc_rbput) {
416 		ring_data = sc->sc_rbuf[get];
417 		get = (get + 1) & MS_RX_RING_MASK;
418 
419 		/* low byte of ring_data is rr1 */
420 		c = (ring_data >> 8) & 0xff;
421 
422 		if (ring_data & ZSRR1_DO)
423 			SET(intr_flags, INTR_RX_OVERRUN);
424 
425 		/* Pass this up to the "middle" layer. */
426 		sunms_input(&sc->sc_base, c);
427 	}
428 	if (ISSET(intr_flags, INTR_RX_OVERRUN))
429 		log(LOG_ERR, "%s: input overrun\n",
430 		    sc->sc_base.sc_dev.dv_xname);
431 	sc->sc_rbget = get;
432 
433 	/*
434 	 * Status line change.  Not expected except for break conditions.
435 	 */
436 	if (ISSET(intr_flags, INTR_ST_CHECK)) {
437 		cs->cs_rr0_delta = 0;
438 	}
439 
440 	splx(s);
441 }
442 
443 /*
444  * Reinitialize the line to a different speed.  Invoked at spltty().
445  */
446 void
447 zsms_speed_change(void *v, uint bps)
448 {
449 	struct zsms_softc *sc = v;
450 	struct zs_chanstate *cs = sc->sc_cs;
451 	uint8_t rr0;
452 	int s;
453 
454 	s = splzs();
455 
456 	/*
457 	 * Eat everything on the line.
458 	 */
459 	for (;;) {
460 		rr0 = zs_read_csr(cs);
461 		if (!ISSET(rr0, ZSRR0_RX_READY))
462 			break;
463 		(void)zs_read_data(cs);
464 	}
465 
466 	(void)zs_set_speed(cs, sc->sc_base.sc_bps);
467 	zs_loadchannelregs(cs);
468 	zsms_stint(cs, 1);
469 
470 	sc->sc_rbget = sc->sc_rbput = 0;
471 
472 	splx(s);
473 }
474