xref: /netbsd-src/sys/dev/sun/ms.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: ms.c,v 1.11 1996/12/17 20:46:16 gwr Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratory.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by the University of
27  *	California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *	@(#)ms.c	8.1 (Berkeley) 6/11/93
45  */
46 
47 /*
48  * Mouse driver (/dev/mouse)
49  */
50 
51 /*
52  * Zilog Z8530 Dual UART driver (mouse interface)
53  *
54  * This is the "slave" driver that will be attached to
55  * the "zsc" driver for a Sun mouse.
56  */
57 
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/conf.h>
61 #include <sys/device.h>
62 #include <sys/ioctl.h>
63 #include <sys/kernel.h>
64 #include <sys/proc.h>
65 #include <sys/signal.h>
66 #include <sys/signalvar.h>
67 #include <sys/time.h>
68 #include <sys/syslog.h>
69 #include <sys/select.h>
70 #include <sys/poll.h>
71 
72 #include <machine/vuid_event.h>
73 
74 #include <dev/ic/z8530reg.h>
75 #include <machine/z8530var.h>
76 
77 #include "event_var.h"
78 
79 /*
80  * How many input characters we can buffer.
81  * The port-specific var.h may override this.
82  * Note: must be a power of two!
83  */
84 #define	MS_RX_RING_SIZE	256
85 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1)
86 /*
87  * Output buffer.  Only need a few chars.
88  */
89 #define	MS_TX_RING_SIZE	16
90 #define MS_TX_RING_MASK (MS_TX_RING_SIZE-1)
91 /*
92  * Keyboard serial line speed is fixed at 1200 bps.
93  */
94 #define MS_BPS 1200
95 
96 /*
97  * Mouse state.  A Mouse Systems mouse is a fairly simple device,
98  * producing five-byte blobs of the form:
99  *
100  *	b dx dy dx dy
101  *
102  * where b is the button state, encoded as 0x80|(~buttons)---there are
103  * three buttons (4=left, 2=middle, 1=right)---and dx,dy are X and Y
104  * delta values, none of which have are in [0x80..0x87].  (This lets
105  * us sync up with the mouse after an error.)
106  */
107 struct ms_softc {
108 	struct	device ms_dev;		/* required first: base device */
109 	struct	zs_chanstate *ms_cs;
110 
111 	/* Flags to communicate with ms_softintr() */
112 	volatile int ms_intr_flags;
113 #define	INTR_RX_OVERRUN 1
114 #define INTR_TX_EMPTY   2
115 #define INTR_ST_CHECK   4
116 
117 	/*
118 	 * The receive ring buffer.
119 	 */
120 	u_int	ms_rbget;	/* ring buffer `get' index */
121 	volatile u_int	ms_rbput;	/* ring buffer `put' index */
122 	u_short	ms_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */
123 
124 	/*
125 	 * State of input translator
126 	 */
127 	short	ms_byteno;		/* input byte number, for decode */
128 	char	ms_mb;			/* mouse button state */
129 	char	ms_ub;			/* user button state */
130 	int	ms_dx;			/* delta-x */
131 	int	ms_dy;			/* delta-y */
132 
133 	/*
134 	 * State of upper interface.
135 	 */
136 	volatile int ms_ready;		/* event queue is ready */
137 	struct	evvar ms_events;	/* event queue state */
138 } ms_softc;
139 
140 cdev_decl(ms);	/* open, close, read, write, ioctl, stop, ... */
141 
142 struct zsops zsops_ms;
143 
144 /****************************************************************
145  * Definition of the driver for autoconfig.
146  ****************************************************************/
147 
148 static int	ms_match(struct device *, struct cfdata *, void *);
149 static void	ms_attach(struct device *, struct device *, void *);
150 
151 struct cfattach ms_ca = {
152 	sizeof(struct ms_softc), ms_match, ms_attach
153 };
154 
155 struct cfdriver ms_cd = {
156 	NULL, "ms", DV_DULL
157 };
158 
159 
160 /*
161  * ms_match: how is this zs channel configured?
162  */
163 int
164 ms_match(parent, cf, aux)
165 	struct device *parent;
166 	struct cfdata *cf;
167 	void   *aux;
168 {
169 	struct zsc_attach_args *args = aux;
170 
171 	/* Exact match required for keyboard. */
172 	if (cf->cf_loc[0] == args->channel)
173 		return 2;
174 
175 	return 0;
176 }
177 
178 void
179 ms_attach(parent, self, aux)
180 	struct device *parent, *self;
181 	void   *aux;
182 
183 {
184 	struct zsc_softc *zsc = (void *) parent;
185 	struct ms_softc *ms = (void *) self;
186 	struct zsc_attach_args *args = aux;
187 	struct zs_chanstate *cs;
188 	struct cfdata *cf;
189 	int channel, ms_unit;
190 	int reset, s;
191 
192 	cf = ms->ms_dev.dv_cfdata;
193 	ms_unit = ms->ms_dev.dv_unit;
194 	channel = args->channel;
195 	cs = zsc->zsc_cs[channel];
196 	cs->cs_private = ms;
197 	cs->cs_ops = &zsops_ms;
198 	ms->ms_cs = cs;
199 
200 	printf("\n");
201 
202 	/* Initialize the speed, etc. */
203 	s = splzs();
204 	/* May need reset... */
205 	reset = (channel == 0) ?
206 		ZSWR9_A_RESET : ZSWR9_B_RESET;
207 	zs_write_reg(cs, 9, reset);
208 	/* These are OK as set by zscc: WR3, WR4, WR5 */
209 	/* We don't care about status or tx interrupts. */
210 	cs->cs_preg[1] = ZSWR1_RIE;
211 	(void) zs_set_speed(cs, MS_BPS);
212 	zs_loadchannelregs(cs);
213 	splx(s);
214 
215 	/* Initialize translator. */
216 	ms->ms_byteno = -1;
217 }
218 
219 /****************************************************************
220  *  Entry points for /dev/mouse
221  *  (open,close,read,write,...)
222  ****************************************************************/
223 
224 int
225 msopen(dev, flags, mode, p)
226 	dev_t dev;
227 	int flags, mode;
228 	struct proc *p;
229 {
230 	struct ms_softc *ms;
231 	int unit;
232 
233 	unit = minor(dev);
234 	if (unit >= ms_cd.cd_ndevs)
235 		return (ENXIO);
236 	ms = ms_cd.cd_devs[unit];
237 	if (ms == NULL)
238 		return (ENXIO);
239 
240 	/* This is an exclusive open device. */
241 	if (ms->ms_events.ev_io)
242 		return (EBUSY);
243 	ms->ms_events.ev_io = p;
244 	ev_init(&ms->ms_events);	/* may cause sleep */
245 
246 	ms->ms_ready = 1;		/* start accepting events */
247 	return (0);
248 }
249 
250 int
251 msclose(dev, flags, mode, p)
252 	dev_t dev;
253 	int flags, mode;
254 	struct proc *p;
255 {
256 	struct ms_softc *ms;
257 
258 	ms = ms_cd.cd_devs[minor(dev)];
259 	ms->ms_ready = 0;		/* stop accepting events */
260 	ev_fini(&ms->ms_events);
261 
262 	ms->ms_events.ev_io = NULL;
263 	return (0);
264 }
265 
266 int
267 msread(dev, uio, flags)
268 	dev_t dev;
269 	struct uio *uio;
270 	int flags;
271 {
272 	struct ms_softc *ms;
273 
274 	ms = ms_cd.cd_devs[minor(dev)];
275 	return (ev_read(&ms->ms_events, uio, flags));
276 }
277 
278 /* this routine should not exist, but is convenient to write here for now */
279 int
280 mswrite(dev, uio, flags)
281 	dev_t dev;
282 	struct uio *uio;
283 	int flags;
284 {
285 
286 	return (EOPNOTSUPP);
287 }
288 
289 int
290 msioctl(dev, cmd, data, flag, p)
291 	dev_t dev;
292 	u_long cmd;
293 	register caddr_t data;
294 	int flag;
295 	struct proc *p;
296 {
297 	struct ms_softc *ms;
298 
299 	ms = ms_cd.cd_devs[minor(dev)];
300 
301 	switch (cmd) {
302 
303 	case FIONBIO:		/* we will remove this someday (soon???) */
304 		return (0);
305 
306 	case FIOASYNC:
307 		ms->ms_events.ev_async = *(int *)data != 0;
308 		return (0);
309 
310 	case TIOCSPGRP:
311 		if (*(int *)data != ms->ms_events.ev_io->p_pgid)
312 			return (EPERM);
313 		return (0);
314 
315 	case VUIDGFORMAT:
316 		/* we only do firm_events */
317 		*(int *)data = VUID_FIRM_EVENT;
318 		return (0);
319 
320 	case VUIDSFORMAT:
321 		if (*(int *)data != VUID_FIRM_EVENT)
322 			return (EINVAL);
323 		return (0);
324 	}
325 	return (ENOTTY);
326 }
327 
328 int
329 mspoll(dev, events, p)
330 	dev_t dev;
331 	int events;
332 	struct proc *p;
333 {
334 	struct ms_softc *ms;
335 
336 	ms = ms_cd.cd_devs[minor(dev)];
337 	return (ev_poll(&ms->ms_events, events, p));
338 }
339 
340 
341 /****************************************************************
342  * Middle layer (translator)
343  ****************************************************************/
344 
345 static void ms_input __P((struct ms_softc *, int c));
346 
347 
348 /*
349  * Called by our ms_softint() routine on input.
350  */
351 void
352 ms_input(ms, c)
353 	register struct ms_softc *ms;
354 	register int c;
355 {
356 	register struct firm_event *fe;
357 	register int mb, ub, d, get, put, any;
358 	static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
359 	static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
360 
361 	/*
362 	 * Discard input if not ready.  Drop sync on parity or framing
363 	 * error; gain sync on button byte.
364 	 */
365 	if (ms->ms_ready == 0)
366 		return;
367 	if (c == -1) {
368 		ms->ms_byteno = -1;
369 		return;
370 	}
371 	if ((c & ~7) == 0x80)	/* if in 0x80..0x87 */
372 		ms->ms_byteno = 0;
373 
374 	/*
375 	 * Run the decode loop, adding to the current information.
376 	 * We add, rather than replace, deltas, so that if the event queue
377 	 * fills, we accumulate data for when it opens up again.
378 	 */
379 	switch (ms->ms_byteno) {
380 
381 	case -1:
382 		return;
383 
384 	case 0:
385 		/* buttons */
386 		ms->ms_byteno = 1;
387 		ms->ms_mb = (~c) & 0x7;
388 		return;
389 
390 	case 1:
391 		/* first delta-x */
392 		ms->ms_byteno = 2;
393 		ms->ms_dx += (char)c;
394 		return;
395 
396 	case 2:
397 		/* first delta-y */
398 		ms->ms_byteno = 3;
399 		ms->ms_dy += (char)c;
400 		return;
401 
402 	case 3:
403 		/* second delta-x */
404 		ms->ms_byteno = 4;
405 		ms->ms_dx += (char)c;
406 		return;
407 
408 	case 4:
409 		/* second delta-x */
410 		ms->ms_byteno = -1;	/* wait for button-byte again */
411 		ms->ms_dy += (char)c;
412 		break;
413 
414 	default:
415 		panic("ms_rint");
416 		/* NOTREACHED */
417 	}
418 
419 	/*
420 	 * We have at least one event (mouse button, delta-X, or
421 	 * delta-Y; possibly all three, and possibly three separate
422 	 * button events).  Deliver these events until we are out
423 	 * of changes or out of room.  As events get delivered,
424 	 * mark them `unchanged'.
425 	 */
426 	any = 0;
427 	get = ms->ms_events.ev_get;
428 	put = ms->ms_events.ev_put;
429 	fe = &ms->ms_events.ev_q[put];
430 
431 	/* NEXT prepares to put the next event, backing off if necessary */
432 #define	NEXT \
433 	if ((++put) % EV_QSIZE == get) { \
434 		put--; \
435 		goto out; \
436 	}
437 	/* ADVANCE completes the `put' of the event */
438 #define	ADVANCE \
439 	fe++; \
440 	if (put >= EV_QSIZE) { \
441 		put = 0; \
442 		fe = &ms->ms_events.ev_q[0]; \
443 	} \
444 	any = 1
445 
446 	mb = ms->ms_mb;
447 	ub = ms->ms_ub;
448 	while ((d = mb ^ ub) != 0) {
449 		/*
450 		 * Mouse button change.  Convert up to three changes
451 		 * to the `first' change, and drop it into the event queue.
452 		 */
453 		NEXT;
454 		d = to_one[d - 1];		/* from 1..7 to {1,2,4} */
455 		fe->id = to_id[d - 1];		/* from {1,2,4} to ID */
456 		fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
457 		fe->time = time;
458 		ADVANCE;
459 		ub ^= d;
460 	}
461 	if (ms->ms_dx) {
462 		NEXT;
463 		fe->id = LOC_X_DELTA;
464 		fe->value = ms->ms_dx;
465 		fe->time = time;
466 		ADVANCE;
467 		ms->ms_dx = 0;
468 	}
469 	if (ms->ms_dy) {
470 		NEXT;
471 		fe->id = LOC_Y_DELTA;
472 		fe->value = ms->ms_dy;
473 		fe->time = time;
474 		ADVANCE;
475 		ms->ms_dy = 0;
476 	}
477 out:
478 	if (any) {
479 		ms->ms_ub = ub;
480 		ms->ms_events.ev_put = put;
481 		EV_WAKEUP(&ms->ms_events);
482 	}
483 }
484 
485 /****************************************************************
486  * Interface to the lower layer (zscc)
487  ****************************************************************/
488 
489 static void ms_rxint __P((struct zs_chanstate *));
490 static void ms_txint __P((struct zs_chanstate *));
491 static void ms_stint __P((struct zs_chanstate *));
492 static void ms_softint __P((struct zs_chanstate *));
493 
494 static void
495 ms_rxint(cs)
496 	register struct zs_chanstate *cs;
497 {
498 	register struct ms_softc *ms;
499 	register int put, put_next;
500 	register u_char c, rr1;
501 
502 	ms = cs->cs_private;
503 	put = ms->ms_rbput;
504 
505 	/*
506 	 * First read the status, because reading the received char
507 	 * destroys the status of this char.
508 	 */
509 	rr1 = zs_read_reg(cs, 1);
510 	c = zs_read_data(cs);
511 
512 	if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
513 		/* Clear the receive error. */
514 		zs_write_csr(cs, ZSWR0_RESET_ERRORS);
515 	}
516 
517 	ms->ms_rbuf[put] = (c << 8) | rr1;
518 	put_next = (put + 1) & MS_RX_RING_MASK;
519 
520 	/* Would overrun if increment makes (put==get). */
521 	if (put_next == ms->ms_rbget) {
522 		ms->ms_intr_flags |= INTR_RX_OVERRUN;
523 	} else {
524 		/* OK, really increment. */
525 		put = put_next;
526 	}
527 
528 	/* Done reading. */
529 	ms->ms_rbput = put;
530 
531 	/* Ask for softint() call. */
532 	cs->cs_softreq = 1;
533 }
534 
535 
536 static void
537 ms_txint(cs)
538 	register struct zs_chanstate *cs;
539 {
540 	register struct ms_softc *ms;
541 
542 	ms = cs->cs_private;
543 	zs_write_csr(cs, ZSWR0_RESET_TXINT);
544 	ms->ms_intr_flags |= INTR_TX_EMPTY;
545 	/* Ask for softint() call. */
546 	cs->cs_softreq = 1;
547 }
548 
549 
550 static void
551 ms_stint(cs)
552 	register struct zs_chanstate *cs;
553 {
554 	register struct ms_softc *ms;
555 	register int rr0;
556 
557 	ms = cs->cs_private;
558 
559 	rr0 = zs_read_csr(cs);
560 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
561 
562 	/*
563 	 * We have to accumulate status line changes here.
564 	 * Otherwise, if we get multiple status interrupts
565 	 * before the softint runs, we could fail to notice
566 	 * some status line changes in the softint routine.
567 	 * Fix from Bill Studenmund, October 1996.
568 	 */
569 	cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0);
570 	cs->cs_rr0 = rr0;
571 	ms->ms_intr_flags |= INTR_ST_CHECK;
572 
573 	/* Ask for softint() call. */
574 	cs->cs_softreq = 1;
575 }
576 
577 
578 static void
579 ms_softint(cs)
580 	struct zs_chanstate *cs;
581 {
582 	register struct ms_softc *ms;
583 	register int get, c, s;
584 	int intr_flags;
585 	register u_short ring_data;
586 
587 	ms = cs->cs_private;
588 
589 	/* Atomically get and clear flags. */
590 	s = splzs();
591 	intr_flags = ms->ms_intr_flags;
592 	ms->ms_intr_flags = 0;
593 
594 	/* Now lower to spltty for the rest. */
595 	(void) spltty();
596 
597 	/*
598 	 * Copy data from the receive ring to the event layer.
599 	 */
600 	get = ms->ms_rbget;
601 	while (get != ms->ms_rbput) {
602 		ring_data = ms->ms_rbuf[get];
603 		get = (get + 1) & MS_RX_RING_MASK;
604 
605 		/* low byte of ring_data is rr1 */
606 		c = (ring_data >> 8) & 0xff;
607 
608 		if (ring_data & ZSRR1_DO)
609 			intr_flags |= INTR_RX_OVERRUN;
610 		if (ring_data & (ZSRR1_FE | ZSRR1_PE)) {
611 			log(LOG_ERR, "%s: input error (0x%x)\n",
612 				ms->ms_dev.dv_xname, ring_data);
613 			c = -1;	/* signal input error */
614 		}
615 
616 		/* Pass this up to the "middle" layer. */
617 		ms_input(ms, c);
618 	}
619 	if (intr_flags & INTR_RX_OVERRUN) {
620 		log(LOG_ERR, "%s: input overrun\n",
621 		    ms->ms_dev.dv_xname);
622 	}
623 	ms->ms_rbget = get;
624 
625 	if (intr_flags & INTR_TX_EMPTY) {
626 		/*
627 		 * Transmit done.  (Not expected.)
628 		 */
629 		log(LOG_ERR, "%s: transmit interrupt?\n",
630 		    ms->ms_dev.dv_xname);
631 	}
632 
633 	if (intr_flags & INTR_ST_CHECK) {
634 		/*
635 		 * Status line change.  (Not expected.)
636 		 */
637 		log(LOG_ERR, "%s: status interrupt?\n",
638 		    ms->ms_dev.dv_xname);
639 		cs->cs_rr0_delta = 0;
640 	}
641 
642 	splx(s);
643 }
644 
645 struct zsops zsops_ms = {
646 	ms_rxint,	/* receive char available */
647 	ms_stint,	/* external/status */
648 	ms_txint,	/* xmit buffer empty */
649 	ms_softint,	/* process software interrupt */
650 };
651