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