xref: /openbsd-src/sys/dev/sun/z8530ms.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: z8530ms.c,v 1.3 2015/09/18 20:22:22 kettenis 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 #include <dev/ic/z8530reg.h>
89 #include <machine/z8530var.h>
90 
91 #include <dev/wscons/wsmousevar.h>
92 #include <dev/sun/sunmsvar.h>
93 
94 /*
95  * How many input characters we can buffer.
96  * Note: must be a power of two!
97  */
98 #define	MS_RX_RING_SIZE	256
99 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1)
100 
101 struct zsms_softc {
102 	struct	sunms_softc sc_base;
103 	struct	zs_chanstate *sc_cs;
104 
105 	/* Flags to communicate with zsms_softint() */
106 	volatile int sc_intr_flags;
107 #define	INTR_RX_OVERRUN 	0x01
108 #define INTR_TX_EMPTY   	0x02
109 #define INTR_ST_CHECK   	0x04
110 #define	INTR_BPS_CHANGE		0x08
111 
112 	/*
113 	 * The receive ring buffer.
114 	 */
115 	uint	sc_rbget;		/* ring buffer `get' index */
116 	volatile uint	sc_rbput;	/* ring buffer `put' index */
117 	uint16_t sc_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */
118 };
119 
120 /*
121  * autoconf glue.
122  */
123 
124 int	zsms_match(struct device *, void *, void *);
125 void	zsms_attach(struct device *, struct device *, void *);
126 
127 const struct cfattach zsms_ca = {
128 	sizeof(struct zsms_softc), zsms_match, zsms_attach
129 };
130 
131 struct cfdriver zsms_cd = {
132 	NULL, "zsms", DV_DULL
133 };
134 
135 /*
136  * wsmouse accessops.
137  */
138 
139 void	zsms_disable(void *);
140 int	zsms_enable(void *);
141 
142 const struct wsmouse_accessops zsms_accessops = {
143 	zsms_enable,
144 	sunms_ioctl,
145 	zsms_disable
146 };
147 
148 /*
149  * zs glue.
150  */
151 
152 void	zsms_rxint(struct zs_chanstate *);
153 void	zsms_softint(struct zs_chanstate *);
154 void	zsms_stint(struct zs_chanstate *, int);
155 void	zsms_txint(struct zs_chanstate *);
156 
157 struct zsops zsops_ms = {
158 	zsms_rxint,	/* receive char available */
159 	zsms_stint,	/* external/status */
160 	zsms_txint,	/* xmit buffer empty */
161 	zsms_softint	/* process software interrupt */
162 };
163 
164 void	zsms_speed_change(void *, uint);
165 
166 /*
167  * autoconf glue.
168  */
169 
170 int
171 zsms_match(struct device *parent, void *vcf, void *aux)
172 {
173 	struct cfdata *cf = vcf;
174 	struct zsc_attach_args *args = aux;
175 	int rc;
176 
177 	/* If we're not looking for a mouse, just exit */
178 	if (strcmp(args->type, "mouse") != 0)
179 		return 0;
180 
181 	rc = 10;
182 
183 	/* Exact match is better than wildcard. */
184 	if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel)
185 		rc += 2;
186 
187 	/* This driver accepts wildcard. */
188 	if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT)
189 		rc += 1;
190 
191 	return rc;
192 }
193 
194 void
195 zsms_attach(struct device *parent, struct device *self, void *aux)
196 {
197 	struct zsc_softc *zsc = (struct zsc_softc *)parent;
198 	struct zsms_softc *sc = (struct zsms_softc *)self;
199 	struct zsc_attach_args *args = aux;
200 	struct zs_chanstate *cs;
201 	int channel;
202 	int s;
203 
204 	channel = args->channel;
205 	cs = zsc->zsc_cs[channel];
206 	cs->cs_private = sc;
207 	cs->cs_ops = &zsops_ms;
208 	sc->sc_cs = cs;
209 
210 	/* Initialize hardware. */
211 	s = splzs();
212 	zs_write_reg(cs, 9, channel == 0 ?  ZSWR9_A_RESET : ZSWR9_B_RESET);
213 	/* disable interrupts until the mouse is enabled */
214 	CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE | ZSWR1_TIE);
215 	/* 8 data bits is already our default */
216 	/* no parity, 2 stop bits */
217 	CLR(cs->cs_preg[4], ZSWR4_SBMASK | ZSWR4_PARMASK);
218 	SET(cs->cs_preg[4], ZSWR4_TWOSB);
219 	(void)zs_set_speed(cs, INIT_SPEED);
220 	zs_loadchannelregs(cs);
221 	splx(s);
222 
223 	sc->sc_base.sc_speed_change = zsms_speed_change;
224 
225 	sunms_attach(&sc->sc_base, &zsms_accessops);
226 }
227 
228 /*
229  * wsmouse accessops.
230  */
231 
232 void
233 zsms_disable(void *v)
234 {
235 	struct zsms_softc *sc = v;
236 	struct zs_chanstate *cs = sc->sc_cs;
237 	int s;
238 
239 	s = splzs();
240 	/* disable RX and status change interrupts */
241 	CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
242 	zs_loadchannelregs(cs);
243 	splx(s);
244 }
245 
246 int
247 zsms_enable(void *v)
248 {
249 	struct zsms_softc *sc = v;
250 	struct zs_chanstate *cs = sc->sc_cs;
251 	int s;
252 
253 	s = splzs();
254 	/* enable RX and status change interrupts */
255 	SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
256 	zs_loadchannelregs(cs);
257 	splx(s);
258 
259 	return 0;
260 }
261 
262 /*
263  * zs glue.
264  */
265 
266 void
267 zsms_rxint(struct zs_chanstate *cs)
268 {
269 	struct zsms_softc *sc = cs->cs_private;
270 	int put, put_next;
271 	u_char rr0, rr1, c;
272 
273 	put = sc->sc_rbput;
274 
275 	for (;;) {
276 		/*
277 		 * First read the status, because reading the received char
278 		 * destroys the status of this char.
279 		 */
280 		rr1 = zs_read_reg(cs, 1);
281 		c = zs_read_data(cs);
282 
283 		/*
284 		 * Note that we do not try to change speed upon encountering
285 		 * framing errors, as this is not as reliable as breaks.
286 		 */
287 		if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
288 			/* Clear the receive error. */
289 			zs_write_csr(cs, ZSWR0_RESET_ERRORS);
290 		}
291 
292 		if (sc->sc_base.sc_state != STATE_RATE_CHANGE) {
293 			sc->sc_rbuf[put] = (c << 8) | rr1;
294 			put_next = (put + 1) & MS_RX_RING_MASK;
295 
296 			/* Would overrun if increment makes (put==get). */
297 			if (put_next == sc->sc_rbget) {
298 				sc->sc_intr_flags |= INTR_RX_OVERRUN;
299 				break;
300 			} else {
301 				/* OK, really increment. */
302 				put = put_next;
303 			}
304 		}
305 
306 		rr0 = zs_read_csr(cs);
307 		if (!ISSET(rr0, ZSRR0_RX_READY))
308 			break;
309 	}
310 
311 	/* Done reading. */
312 	sc->sc_rbput = put;
313 
314 	cs->cs_softreq = 1;
315 }
316 
317 void
318 zsms_txint(struct zs_chanstate *cs)
319 {
320 	/*
321 	 * This function should never be invoked as we don't accept TX
322 	 * interrupts.  If someone alters our configuration behind our
323 	 * back, just disable TX interrupts again.
324 	 */
325 	zs_write_csr(cs, ZSWR0_RESET_TXINT);
326 
327 	/* disable tx interrupts */
328 	CLR(cs->cs_preg[1], ZSWR1_TIE);
329 	zs_loadchannelregs(cs);
330 }
331 
332 void
333 zsms_stint(struct zs_chanstate *cs, int force)
334 {
335 	struct zsms_softc *sc = cs->cs_private;
336 	uint8_t rr0, delta;
337 
338 	rr0 = zs_read_csr(cs);
339 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
340 
341 	/*
342 	 * A break can occur if the speed is not correct.
343 	 * However, we do not change speed until we get the second
344 	 * break, for switching speed when the mouse is unplugged
345 	 * will trigger a break and thus we'd loop changing speeds
346 	 * until the mouse is plugged again.
347 	 */
348 	if (!force && ISSET(rr0, ZSRR0_BREAK)) {
349 		if (sc->sc_base.sc_state != STATE_RATE_CHANGE &&
350 		    ++sc->sc_base.sc_brk > 1) {
351 			sc->sc_intr_flags |= INTR_BPS_CHANGE;
352 			sc->sc_base.sc_state = STATE_RATE_CHANGE;
353 			cs->cs_softreq = 1;
354 #ifdef DEBUG
355 			printf("%s: break detected, changing speed\n",
356 			    sc->sc_base.sc_dev.dv_xname);
357 #endif
358 		}
359 	}
360 
361 	if (!force)
362 		delta = rr0 ^ cs->cs_rr0;
363 	else
364 		delta = cs->cs_rr0_mask;
365 	cs->cs_rr0 = rr0;
366 
367 	if (ISSET(delta, cs->cs_rr0_mask)) {
368 		SET(cs->cs_rr0_delta, delta);
369 
370 		sc->sc_intr_flags |= INTR_ST_CHECK;
371 		cs->cs_softreq = 1;
372 	}
373 }
374 
375 void
376 zsms_softint(struct zs_chanstate *cs)
377 {
378 	struct zsms_softc *sc;
379 	int get, c, s, s2;
380 	int intr_flags;
381 	u_short ring_data;
382 
383 	sc = cs->cs_private;
384 
385 	/* Atomically get and clear flags. */
386 	s = spltty();
387 	s2 = splzs();
388 	intr_flags = sc->sc_intr_flags;
389 	sc->sc_intr_flags = 0;
390 	/* Now lower to spltty for the rest. */
391 	splx(s2);
392 
393 	/*
394 	 * If we have a baud rate change pending, do it now.
395 	 * This will reset the rx ring, so we can proceed safely.
396 	 */
397 	if (ISSET(intr_flags, INTR_BPS_CHANGE)) {
398 		CLR(intr_flags, INTR_RX_OVERRUN);
399 		sunms_speed_change(&sc->sc_base);
400 	}
401 
402 	/*
403 	 * Copy data from the receive ring, if any, to the event layer.
404 	 */
405 	get = sc->sc_rbget;
406 	while (get != sc->sc_rbput) {
407 		ring_data = sc->sc_rbuf[get];
408 		get = (get + 1) & MS_RX_RING_MASK;
409 
410 		/* low byte of ring_data is rr1 */
411 		c = (ring_data >> 8) & 0xff;
412 
413 		if (ring_data & ZSRR1_DO)
414 			SET(intr_flags, INTR_RX_OVERRUN);
415 
416 		/* Pass this up to the "middle" layer. */
417 		sunms_input(&sc->sc_base, c);
418 	}
419 	if (ISSET(intr_flags, INTR_RX_OVERRUN))
420 		log(LOG_ERR, "%s: input overrun\n",
421 		    sc->sc_base.sc_dev.dv_xname);
422 	sc->sc_rbget = get;
423 
424 	/*
425 	 * Status line change.  Not expected except for break conditions.
426 	 */
427 	if (ISSET(intr_flags, INTR_ST_CHECK)) {
428 		cs->cs_rr0_delta = 0;
429 	}
430 
431 	splx(s);
432 }
433 
434 /*
435  * Reinitialize the line to a different speed.  Invoked at spltty().
436  */
437 void
438 zsms_speed_change(void *v, uint bps)
439 {
440 	struct zsms_softc *sc = v;
441 	struct zs_chanstate *cs = sc->sc_cs;
442 	uint8_t rr0;
443 	int s;
444 
445 	s = splzs();
446 
447 	/*
448 	 * Eat everything on the line.
449 	 */
450 	for (;;) {
451 		rr0 = zs_read_csr(cs);
452 		if (!ISSET(rr0, ZSRR0_RX_READY))
453 			break;
454 		(void)zs_read_data(cs);
455 	}
456 
457 	(void)zs_set_speed(cs, sc->sc_base.sc_bps);
458 	zs_loadchannelregs(cs);
459 	zsms_stint(cs, 1);
460 
461 	sc->sc_rbget = sc->sc_rbput = 0;
462 
463 	splx(s);
464 }
465