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