xref: /netbsd-src/sys/arch/x68k/dev/ms.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: ms.c,v 1.33 2014/03/26 08:17:59 christos 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. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)ms.c	8.1 (Berkeley) 6/11/93
41  */
42 
43 /*
44  * X68k mouse driver.
45  */
46 
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: ms.c,v 1.33 2014/03/26 08:17:59 christos Exp $");
49 
50 #include <sys/param.h>
51 #include <sys/conf.h>
52 #include <sys/ioctl.h>
53 #include <sys/kernel.h>
54 #include <sys/proc.h>
55 #include <sys/syslog.h>
56 #include <sys/systm.h>
57 #include <sys/tty.h>
58 #include <sys/device.h>
59 #include <sys/signalvar.h>
60 #include <sys/mutex.h>
61 
62 #include <dev/ic/z8530reg.h>
63 #include <machine/z8530var.h>
64 
65 #include <arch/x68k/dev/event_var.h>
66 #include <machine/vuid_event.h>
67 #include <arch/x68k/dev/mfp.h>
68 
69 #include "ioconf.h"
70 #include "locators.h"
71 
72 /*
73  * How many input characters we can buffer.
74  * The port-specific var.h may override this.
75  * Note: must be a power of two!
76  */
77 #define	MS_RX_RING_SIZE	256
78 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1)
79 /*
80  * Output buffer.  Only need a few chars.
81  */
82 #define	MS_TX_RING_SIZE	16
83 #define MS_TX_RING_MASK (MS_TX_RING_SIZE-1)
84 /*
85  * Mouse serial line is fixed at 4800 bps.
86  */
87 #define MS_BPS 4800
88 
89 /*
90  * Mouse state.  A SHARP X1/X680x0 mouse is a fairly simple device,
91  * producing three-byte blobs of the form:
92  *
93  *	b dx dy
94  *
95  * where b is the button state, encoded as 0x80|(buttons)---there are
96  * two buttons (2=left, 1=right)---and dx,dy are X and Y delta values.
97  *
98  * It needs a trigger for the transmission.  When zs RTS negated, the
99  * mouse begins the sequence.  RTS assertion has no effect.
100  */
101 struct ms_softc {
102 	device_t ms_dev;		/* required first: base device */
103 	struct	zs_chanstate *ms_cs;
104 
105 	struct callout ms_modem_ch;
106 
107 	/* Flags to communicate with ms_softintr() */
108 	volatile int ms_intr_flags;
109 #define	INTR_RX_OVERRUN 1
110 #define INTR_TX_EMPTY   2
111 #define INTR_ST_CHECK   4
112 
113 	/*
114 	 * The receive ring buffer.
115 	 */
116 	u_int	ms_rbget;	/* ring buffer `get' index */
117 	volatile u_int	ms_rbput;	/* ring buffer `put' index */
118 	u_short	ms_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */
119 
120 	/*
121 	 * State of input translator
122 	 */
123 	short	ms_byteno;		/* input byte number, for decode */
124 	char	ms_mb;			/* mouse button state */
125 	char	ms_ub;			/* user button state */
126 	int	ms_dx;			/* delta-x */
127 	int	ms_dy;			/* delta-y */
128 	int	ms_rts;			/* MSCTRL */
129 	int	ms_nodata;
130 
131 	/*
132 	 * State of upper interface.
133 	 */
134 	volatile int ms_ready;		/* event queue is ready */
135 	struct	evvar ms_events;	/* event queue state */
136 	kmutex_t ms_lock;
137 } ms_softc;
138 
139 static int ms_match(device_t, cfdata_t, void *);
140 static void ms_attach(device_t, device_t, void *);
141 static void ms_trigger(struct zs_chanstate *, int);
142 void ms_modem(void *);
143 
144 CFATTACH_DECL_NEW(ms, sizeof(struct ms_softc),
145     ms_match, ms_attach, NULL, NULL);
146 
147 static void ms_rxint(struct zs_chanstate *);
148 static void ms_stint(struct zs_chanstate *, int);
149 static void ms_txint(struct zs_chanstate *);
150 static void ms_softint(struct zs_chanstate *);
151 static void ms_input(struct ms_softc *, int);
152 
153 struct zsops zsops_ms = {
154 	ms_rxint,	/* receive char available */
155 	ms_stint,	/* external/status */
156 	ms_txint,	/* xmit buffer empty */
157 	ms_softint,	/* process software interrupt */
158 };
159 
160 dev_type_open(msopen);
161 dev_type_close(msclose);
162 dev_type_read(msread);
163 dev_type_ioctl(msioctl);
164 dev_type_poll(mspoll);
165 dev_type_kqfilter(mskqfilter);
166 
167 const struct cdevsw ms_cdevsw ={
168 	.d_open = msopen,
169 	.d_close = msclose,
170 	.d_read = msread,
171 	.d_write = nowrite,
172 	.d_ioctl = msioctl,
173 	.d_stop = nostop,
174 	.d_tty = notty,
175 	.d_poll = mspoll,
176 	.d_mmap = nommap,
177 	.d_kqfilter = mskqfilter,
178 	.d_flag = 0
179 };
180 
181 /*
182  * ms_match: how is this zs channel configured?
183  */
184 int
185 ms_match(device_t parent, cfdata_t cf, void *aux)
186 {
187 	struct zsc_attach_args *args = aux;
188 	struct zsc_softc *zsc = device_private(parent);
189 
190 	/* Exact match required for the mouse. */
191 	if (cf->cf_loc[ZSCCF_CHANNEL] != args->channel)
192 		return 0;
193 	if (args->channel != 1)
194 		return 0;
195 	if (&zsc->zsc_addr->zs_chan_b != (struct zschan *)ZSMS_PHYSADDR)
196 		return 0;
197 
198 	return 2;
199 }
200 
201 void
202 ms_attach(device_t parent, device_t self, void *aux)
203 {
204 	struct ms_softc *ms = device_private(self);
205 	struct zsc_softc *zsc = device_private(parent);
206 	struct zs_chanstate *cs;
207 	int reset;
208 
209 	ms->ms_dev = self;
210 	callout_init(&ms->ms_modem_ch, 0);
211 	mutex_init(&ms->ms_lock, MUTEX_DEFAULT, IPL_SERIAL);
212 
213 	cs = zsc->zsc_cs[1];
214 	cs->cs_private = ms;
215 	cs->cs_ops = &zsops_ms;
216 	ms->ms_cs = cs;
217 
218 	/* Initialize the speed, etc. */
219 	/* May need reset... */
220 	reset = ZSWR9_B_RESET;
221 	zs_write_reg(cs, 9, reset);
222 	/* We don't care about status or tx interrupts. */
223 	cs->cs_preg[1] = ZSWR1_RIE;
224 	cs->cs_preg[4] = ZSWR4_CLK_X16 | ZSWR4_TWOSB;
225 	(void)zs_set_speed(cs, MS_BPS);
226 	zs_loadchannelregs(cs);
227 
228 	/* Initialize translator. */
229 	ms->ms_ready = 0;
230 
231 	aprint_normal("\n");
232 }
233 
234 /****************************************************************
235  *  Entry points for /dev/mouse
236  *  (open,close,read,write,...)
237  ****************************************************************/
238 
239 int
240 msopen(dev_t dev, int flags, int mode, struct lwp *l)
241 {
242 	struct ms_softc *ms;
243 
244 	ms = device_lookup_private(&ms_cd, minor(dev));
245 	if (ms == NULL)
246 		return ENXIO;
247 
248 	/* This is an exclusive open device. */
249 	if (ms->ms_events.ev_io)
250 		return EBUSY;
251 	ms->ms_events.ev_io = l->l_proc;
252 	ev_init(&ms->ms_events, device_xname(ms->ms_dev), &ms->ms_lock);
253 
254 	ms->ms_ready = 1;		/* start accepting events */
255 	ms->ms_rts = 1;
256 	ms->ms_byteno = -1;
257 	ms->ms_nodata = 0;
258 
259 	/* start sequencer */
260 	ms_modem(ms);
261 
262 	return 0;
263 }
264 
265 int
266 msclose(dev_t dev, int flags, int mode, struct lwp *l)
267 {
268 	struct ms_softc *ms;
269 
270 	ms = device_lookup_private(&ms_cd, minor(dev));
271 	ms->ms_ready = 0;		/* stop accepting events */
272 	callout_stop(&ms->ms_modem_ch);
273 	ev_fini(&ms->ms_events);
274 
275 	ms->ms_events.ev_io = NULL;
276 	return 0;
277 }
278 
279 int
280 msread(dev_t dev, struct uio *uio, int flags)
281 {
282 	struct ms_softc *ms;
283 
284 	ms = device_lookup_private(&ms_cd, minor(dev));
285 	return ev_read(&ms->ms_events, uio, flags);
286 }
287 
288 int
289 msioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
290 {
291 	struct ms_softc *ms;
292 
293 	ms = device_lookup_private(&ms_cd, minor(dev));
294 
295 	switch (cmd) {
296 
297 	case FIONBIO:		/* we will remove this someday (soon???) */
298 		return 0;
299 
300 	case FIOASYNC:
301 		ms->ms_events.ev_async = *(int *)data != 0;
302 		return 0;
303 
304 	case FIOSETOWN:
305 		if (-*(int *)data != ms->ms_events.ev_io->p_pgid
306 		    && *(int *)data != ms->ms_events.ev_io->p_pid)
307 			return EPERM;
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_t dev, int events, struct lwp *l)
330 {
331 	struct ms_softc *ms;
332 
333 	ms = device_lookup_private(&ms_cd, minor(dev));
334 	return ev_poll(&ms->ms_events, events, l);
335 }
336 
337 int
338 mskqfilter(dev_t dev, struct knote *kn)
339 {
340 	struct ms_softc *ms;
341 
342 	ms = device_lookup_private(&ms_cd, minor(dev));
343 	return ev_kqfilter(&ms->ms_events, kn);
344 }
345 
346 /****************************************************************
347  * Middle layer (translator)
348  ****************************************************************/
349 
350 /*
351  * Called by our ms_softint() routine on input.
352  */
353 static void
354 ms_input(struct ms_softc *ms, int c)
355 {
356 	struct firm_event *fe;
357 	int mb, ub, d, get, put, any;
358 	static const char to_one[] = { 1, 2, 3 };
359 	static const int to_id[] = { MS_LEFT, MS_RIGHT, MS_MIDDLE };
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 
368 	ms->ms_nodata = 0;
369 	/*
370 	 * Run the decode loop, adding to the current information.
371 	 * We add, rather than replace, deltas, so that if the event queue
372 	 * fills, we accumulate data for when it opens up again.
373 	 */
374 	switch (ms->ms_byteno) {
375 
376 	case -1:
377 		return;
378 
379 	case 0:
380 		/* buttons */
381 		ms->ms_byteno = 1;
382 		ms->ms_mb = c & 0x3;
383 		return;
384 
385 	case 1:
386 		/* delta-x */
387 		ms->ms_byteno = 2;
388 		ms->ms_dx += (char)c;
389 		return;
390 
391 	case 2:
392 		/* delta-y */
393 		ms->ms_byteno = -1;
394 		ms->ms_dy += (char)c;
395 		break;
396 
397 	default:
398 		panic("ms_input");
399 		/* NOTREACHED */
400 	}
401 
402 	/*
403 	 * We have at least one event (mouse button, delta-X, or
404 	 * delta-Y; possibly all three, and possibly three separate
405 	 * button events).  Deliver these events until we are out
406 	 * of changes or out of room.  As events get delivered,
407 	 * mark them `unchanged'.
408 	 */
409 	any = 0;
410 	get = ms->ms_events.ev_get;
411 	put = ms->ms_events.ev_put;
412 	fe = &ms->ms_events.ev_q[put];
413 
414 	/* NEXT prepares to put the next event, backing off if necessary */
415 #define	NEXT \
416 	if ((++put) % EV_QSIZE == get) { \
417 		put--; \
418 		goto out; \
419 	}
420 	/* ADVANCE completes the `put' of the event */
421 #define	ADVANCE \
422 	fe++; \
423 	if (put >= EV_QSIZE) { \
424 		put = 0; \
425 		fe = &ms->ms_events.ev_q[0]; \
426 	} \
427 
428 	mb = ms->ms_mb;
429 	ub = ms->ms_ub;
430 	while ((d = mb ^ ub) != 0) {
431 		/*
432 		 * Mouse button change.  Convert up to three changes
433 		 * to the `first' change, and drop it into the event queue.
434 		 */
435 		NEXT;
436 		d = to_one[d - 1];		/* from 1..7 to {1,2,4} */
437 		fe->id = to_id[d - 1];		/* from {1,2,4} to ID */
438 		fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
439 		firm_gettime(fe);
440 		ADVANCE;
441 		ub ^= d;
442 		any++;
443 	}
444 	if (ms->ms_dx) {
445 		NEXT;
446 		fe->id = LOC_X_DELTA;
447 		fe->value = ms->ms_dx;
448 		firm_gettime(fe);
449 		ADVANCE;
450 		ms->ms_dx = 0;
451 		any++;
452 	}
453 	if (ms->ms_dy) {
454 		NEXT;
455 		fe->id = LOC_Y_DELTA;
456 		fe->value = -ms->ms_dy;	/* XXX? */
457 		firm_gettime(fe);
458 		ADVANCE;
459 		ms->ms_dy = 0;
460 		any++;
461 	}
462 out:
463 	if (any) {
464 		ms->ms_ub = ub;
465 		ms->ms_events.ev_put = put;
466 		ev_wakeup(&ms->ms_events);
467 	}
468 }
469 
470 /****************************************************************
471  * Interface to the lower layer (zscc)
472  ****************************************************************/
473 
474 static void
475 ms_rxint(struct zs_chanstate *cs)
476 {
477 	struct ms_softc *ms;
478 	int put, put_next;
479 	u_char c, rr1;
480 
481 	ms = cs->cs_private;
482 	put = ms->ms_rbput;
483 
484 	/*
485 	 * First read the status, because reading the received char
486 	 * destroys the status of this char.
487 	 */
488 	rr1 = zs_read_reg(cs, 1);
489 	c = zs_read_data(cs);
490 
491 	if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
492 		/* Clear the receive error. */
493 		zs_write_csr(cs, ZSWR0_RESET_ERRORS);
494 	}
495 
496 	ms->ms_rbuf[put] = (c << 8) | rr1;
497 	put_next = (put + 1) & MS_RX_RING_MASK;
498 
499 	/* Would overrun if increment makes (put==get). */
500 	if (put_next == ms->ms_rbget) {
501 		ms->ms_intr_flags |= INTR_RX_OVERRUN;
502 	} else {
503 		/* OK, really increment. */
504 		put = put_next;
505 	}
506 
507 	/* Done reading. */
508 	ms->ms_rbput = put;
509 
510 	/* Ask for softint() call. */
511 	cs->cs_softreq = 1;
512 }
513 
514 
515 static void
516 ms_txint(struct zs_chanstate *cs)
517 {
518 	struct ms_softc *ms;
519 
520 	ms = cs->cs_private;
521 	zs_write_csr(cs, ZSWR0_RESET_TXINT);
522 	ms->ms_intr_flags |= INTR_TX_EMPTY;
523 	/* Ask for softint() call. */
524 	cs->cs_softreq = 1;
525 }
526 
527 
528 static void
529 ms_stint(struct zs_chanstate *cs, int force)
530 {
531 	struct ms_softc *ms;
532 	int rr0;
533 
534 	ms = cs->cs_private;
535 
536 	rr0 = zs_read_csr(cs);
537 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
538 
539 	/*
540 	 * We have to accumulate status line changes here.
541 	 * Otherwise, if we get multiple status interrupts
542 	 * before the softint runs, we could fail to notice
543 	 * some status line changes in the softint routine.
544 	 * Fix from Bill Studenmund, October 1996.
545 	 */
546 	cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0);
547 	cs->cs_rr0 = rr0;
548 	ms->ms_intr_flags |= INTR_ST_CHECK;
549 
550 	/* Ask for softint() call. */
551 	cs->cs_softreq = 1;
552 }
553 
554 
555 static void
556 ms_softint(struct zs_chanstate *cs)
557 {
558 	struct ms_softc *ms;
559 	int get, c;
560 	int intr_flags;
561 	u_short ring_data;
562 
563 	ms = cs->cs_private;
564 
565 	mutex_enter(&ms->ms_lock);
566 	intr_flags = ms->ms_intr_flags;
567 	ms->ms_intr_flags = 0;
568 
569 	/*
570 	 * Copy data from the receive ring to the event layer.
571 	 */
572 	get = ms->ms_rbget;
573 	while (get != ms->ms_rbput) {
574 		ring_data = ms->ms_rbuf[get];
575 		mutex_exit(&ms->ms_lock);
576 		get = (get + 1) & MS_RX_RING_MASK;
577 
578 		/* low byte of ring_data is rr1 */
579 		c = (ring_data >> 8) & 0xff;
580 
581 		if (ring_data & ZSRR1_DO)
582 			intr_flags |= INTR_RX_OVERRUN;
583 		if (ring_data & (ZSRR1_FE | ZSRR1_PE)) {
584 			log(LOG_ERR, "%s: input error (0x%x)\n",
585 			    device_xname(ms->ms_dev), ring_data);
586 			c = -1;	/* signal input error */
587 		}
588 
589 		/* Pass this up to the "middle" layer. */
590 		ms_input(ms, c);
591 		mutex_enter(&ms->ms_lock);
592 	}
593 	mutex_exit(&ms->ms_lock);
594 
595 	if (intr_flags & INTR_RX_OVERRUN) {
596 		log(LOG_ERR, "%s: input overrun\n",
597 		    device_xname(ms->ms_dev));
598 	}
599 	ms->ms_rbget = get;
600 
601 	if (intr_flags & INTR_TX_EMPTY) {
602 		/*
603 		 * Transmit done.  (Not expected.)
604 		 */
605 		log(LOG_ERR, "%s: transmit interrupt?\n",
606 		    device_xname(ms->ms_dev));
607 	}
608 
609 	if (intr_flags & INTR_ST_CHECK) {
610 		/*
611 		 * Status line change.  (Not expected.)
612 		 */
613 		log(LOG_ERR, "%s: status interrupt?\n",
614 		    device_xname(ms->ms_dev));
615 		mutex_enter(&ms->ms_lock);
616 		cs->cs_rr0_delta = 0;
617 		mutex_exit(&ms->ms_lock);
618 	}
619 }
620 
621 
622 static void
623 ms_trigger(struct zs_chanstate *cs, int onoff)
624 {
625 	/* for front connected one */
626 	if (onoff)
627 		cs->cs_preg[5] |= ZSWR5_RTS;
628 	else
629 		cs->cs_preg[5] &= ~ZSWR5_RTS;
630 	cs->cs_creg[5] = cs->cs_preg[5];
631 	zs_write_reg(cs, 5, cs->cs_preg[5]);
632 
633 	/* for keyborad connected one */
634 	mfp_send_usart(onoff | 0x40);
635 }
636 
637 /*
638  * mouse timer interrupt.
639  * called after system tick interrupt is done.
640  */
641 void
642 ms_modem(void *arg)
643 {
644 	struct ms_softc *ms = arg;
645 
646 	if (!ms->ms_ready)
647 		return;
648 
649 	mutex_enter(&ms->ms_lock);
650 
651 	if (ms->ms_nodata++ > 250) { /* XXX */
652 		log(LOG_ERR, "%s: no data for 5 secs. resetting.\n",
653 		    device_xname(ms->ms_dev));
654 		ms->ms_byteno = -1;
655 		ms->ms_nodata = 0;
656 		ms->ms_rts = 0;
657 	}
658 
659 	if (ms->ms_rts) {
660 		if (ms->ms_byteno == -1) {
661 			/* start next sequence */
662 			ms->ms_rts = 0;
663 			ms_trigger(ms->ms_cs, ms->ms_rts);
664 			ms->ms_byteno = 0;
665 		}
666 	} else {
667 		ms->ms_rts = 1;
668 		ms_trigger(ms->ms_cs, ms->ms_rts);
669 	}
670 
671 	mutex_exit(&ms->ms_lock);
672 	callout_reset(&ms->ms_modem_ch, 2, ms_modem, ms);
673 }
674