ms.c revision 1.17 1 /* $NetBSD: ms.c,v 1.17 2003/07/15 01:44:52 lukem 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 * X68k mouse driver.
49 */
50
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: ms.c,v 1.17 2003/07/15 01:44:52 lukem Exp $");
53
54 #include <sys/param.h>
55 #include <sys/conf.h>
56 #include <sys/ioctl.h>
57 #include <sys/kernel.h>
58 #include <sys/proc.h>
59 #include <sys/syslog.h>
60 #include <sys/systm.h>
61 #include <sys/tty.h>
62 #include <sys/device.h>
63 #include <sys/signalvar.h>
64
65 #include <dev/ic/z8530reg.h>
66 #include <machine/z8530var.h>
67
68 #include <arch/x68k/dev/event_var.h>
69 #include <machine/vuid_event.h>
70 #include <arch/x68k/dev/mfp.h>
71
72 #include "locators.h"
73
74 /*
75 * How many input characters we can buffer.
76 * The port-specific var.h may override this.
77 * Note: must be a power of two!
78 */
79 #define MS_RX_RING_SIZE 256
80 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1)
81 /*
82 * Output buffer. Only need a few chars.
83 */
84 #define MS_TX_RING_SIZE 16
85 #define MS_TX_RING_MASK (MS_TX_RING_SIZE-1)
86 /*
87 * Mouse serial line is fixed at 4800 bps.
88 */
89 #define MS_BPS 4800
90
91 /*
92 * Mouse state. A SHARP X1/X680x0 mouse is a fairly simple device,
93 * producing three-byte blobs of the form:
94 *
95 * b dx dy
96 *
97 * where b is the button state, encoded as 0x80|(buttons)---there are
98 * two buttons (2=left, 1=right)---and dx,dy are X and Y delta values.
99 *
100 * It needs a trigger for the transmission. When zs RTS negated, the
101 * mouse begins the sequence. RTS assertion has no effect.
102 */
103 struct ms_softc {
104 struct device ms_dev; /* required first: base device */
105 struct zs_chanstate *ms_cs;
106
107 struct callout ms_modem_ch;
108
109 /* Flags to communicate with ms_softintr() */
110 volatile int ms_intr_flags;
111 #define INTR_RX_OVERRUN 1
112 #define INTR_TX_EMPTY 2
113 #define INTR_ST_CHECK 4
114
115 /*
116 * The receive ring buffer.
117 */
118 u_int ms_rbget; /* ring buffer `get' index */
119 volatile u_int ms_rbput; /* ring buffer `put' index */
120 u_short ms_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */
121
122 /*
123 * State of input translator
124 */
125 short ms_byteno; /* input byte number, for decode */
126 char ms_mb; /* mouse button state */
127 char ms_ub; /* user button state */
128 int ms_dx; /* delta-x */
129 int ms_dy; /* delta-y */
130 int ms_rts; /* MSCTRL */
131 int ms_nodata;
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 static int ms_match __P((struct device*, struct cfdata*, void*));
141 static void ms_attach __P((struct device*, struct device*, void*));
142 static void ms_trigger __P((struct zs_chanstate*, int));
143 void ms_modem __P((void *));
144
145 CFATTACH_DECL(ms, sizeof(struct ms_softc),
146 ms_match, ms_attach, NULL, NULL);
147
148 extern struct zsops zsops_ms;
149 extern struct cfdriver ms_cd;
150
151 dev_type_open(msopen);
152 dev_type_close(msclose);
153 dev_type_read(msread);
154 dev_type_ioctl(msioctl);
155 dev_type_poll(mspoll);
156 dev_type_kqfilter(mskqfilter);
157
158 const struct cdevsw ms_cdevsw ={
159 msopen, msclose, msread, nowrite, msioctl,
160 nostop, notty, mspoll, nommap, mskqfilter,
161 };
162
163 /*
164 * ms_match: how is this zs channel configured?
165 */
166 int
167 ms_match(parent, cf, aux)
168 struct device *parent;
169 struct cfdata *cf;
170 void *aux;
171 {
172 struct zsc_attach_args *args = aux;
173 struct zsc_softc *zsc = (void*) parent;
174
175 /* Exact match required for the mouse. */
176 if (cf->cf_loc[ZSCCF_CHANNEL] != args->channel)
177 return 0;
178 if (args->channel != 1)
179 return 0;
180 if (&zsc->zsc_addr->zs_chan_b != (struct zschan *) ZSMS_PHYSADDR)
181 return 0;
182
183 return 2;
184 }
185
186 void
187 ms_attach(parent, self, aux)
188 struct device *parent, *self;
189 void *aux;
190
191 {
192 struct zsc_softc *zsc = (void *) parent;
193 struct ms_softc *ms = (void *) self;
194 struct zs_chanstate *cs;
195 struct cfdata *cf;
196 int reset, s;
197
198 callout_init(&ms->ms_modem_ch);
199
200 cf = ms->ms_dev.dv_cfdata;
201 cs = zsc->zsc_cs[1];
202 cs->cs_private = ms;
203 cs->cs_ops = &zsops_ms;
204 ms->ms_cs = cs;
205
206 /* Initialize the speed, etc. */
207 s = splzs();
208 /* May need reset... */
209 reset = ZSWR9_B_RESET;
210 zs_write_reg(cs, 9, reset);
211 /* We don't care about status or tx interrupts. */
212 cs->cs_preg[1] = ZSWR1_RIE;
213 cs->cs_preg[4] = ZSWR4_CLK_X16 | ZSWR4_TWOSB;
214 (void) zs_set_speed(cs, MS_BPS);
215 zs_loadchannelregs(cs);
216 splx(s);
217
218 /* Initialize translator. */
219 ms->ms_ready = 0;
220
221 printf ("\n");
222 }
223
224 /****************************************************************
225 * Entry points for /dev/mouse
226 * (open,close,read,write,...)
227 ****************************************************************/
228
229 int
230 msopen(dev, flags, mode, p)
231 dev_t dev;
232 int flags, mode;
233 struct proc *p;
234 {
235 struct ms_softc *ms;
236 int unit;
237
238 unit = minor(dev);
239 if (unit >= ms_cd.cd_ndevs)
240 return (ENXIO);
241 ms = ms_cd.cd_devs[unit];
242 if (ms == NULL)
243 return (ENXIO);
244
245 /* This is an exclusive open device. */
246 if (ms->ms_events.ev_io)
247 return (EBUSY);
248 ms->ms_events.ev_io = p;
249 ev_init(&ms->ms_events); /* may cause sleep */
250
251 ms->ms_ready = 1; /* start accepting events */
252 ms->ms_rts = 1;
253 ms->ms_byteno = -1;
254 ms->ms_nodata = 0;
255
256 /* start sequencer */
257 ms_modem(ms);
258
259 return (0);
260 }
261
262 int
263 msclose(dev, flags, mode, p)
264 dev_t dev;
265 int flags, mode;
266 struct proc *p;
267 {
268 struct ms_softc *ms;
269
270 ms = ms_cd.cd_devs[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, uio, flags)
281 dev_t dev;
282 struct uio *uio;
283 int flags;
284 {
285 struct ms_softc *ms;
286
287 ms = ms_cd.cd_devs[minor(dev)];
288 return (ev_read(&ms->ms_events, uio, flags));
289 }
290
291 int
292 msioctl(dev, cmd, data, flag, p)
293 dev_t dev;
294 u_long cmd;
295 register caddr_t data;
296 int flag;
297 struct proc *p;
298 {
299 struct ms_softc *ms;
300
301 ms = ms_cd.cd_devs[minor(dev)];
302
303 switch (cmd) {
304
305 case FIONBIO: /* we will remove this someday (soon???) */
306 return (0);
307
308 case FIOASYNC:
309 ms->ms_events.ev_async = *(int *)data != 0;
310 return (0);
311
312 case TIOCSPGRP:
313 if (*(int *)data != ms->ms_events.ev_io->p_pgid)
314 return (EPERM);
315 return (0);
316
317 case VUIDGFORMAT:
318 /* we only do firm_events */
319 *(int *)data = VUID_FIRM_EVENT;
320 return (0);
321
322 case VUIDSFORMAT:
323 if (*(int *)data != VUID_FIRM_EVENT)
324 return (EINVAL);
325 return (0);
326 }
327 return (ENOTTY);
328 }
329
330 int
331 mspoll(dev, events, p)
332 dev_t dev;
333 int events;
334 struct proc *p;
335 {
336 struct ms_softc *ms;
337
338 ms = ms_cd.cd_devs[minor(dev)];
339 return (ev_poll(&ms->ms_events, events, p));
340 }
341
342 int
343 mskqfilter(dev_t dev, struct knote *kn)
344 {
345 struct ms_softc *ms;
346
347 ms = ms_cd.cd_devs[minor(dev)];
348 return (ev_kqfilter(&ms->ms_events, kn));
349 }
350
351 /****************************************************************
352 * Middle layer (translator)
353 ****************************************************************/
354
355 static void ms_input __P((struct ms_softc *, int c));
356
357
358 /*
359 * Called by our ms_softint() routine on input.
360 */
361 static void
362 ms_input(ms, c)
363 register struct ms_softc *ms;
364 register int c;
365 {
366 register struct firm_event *fe;
367 register int mb, ub, d, get, put, any;
368 static const char to_one[] = { 1, 2, 3 };
369 static const int to_id[] = { MS_LEFT, MS_RIGHT, MS_MIDDLE };
370
371 /*
372 * Discard input if not ready. Drop sync on parity or framing
373 * error; gain sync on button byte.
374 */
375 if (ms->ms_ready == 0)
376 return;
377
378 ms->ms_nodata = 0;
379 /*
380 * Run the decode loop, adding to the current information.
381 * We add, rather than replace, deltas, so that if the event queue
382 * fills, we accumulate data for when it opens up again.
383 */
384 switch (ms->ms_byteno) {
385
386 case -1:
387 return;
388
389 case 0:
390 /* buttons */
391 ms->ms_byteno = 1;
392 ms->ms_mb = c & 0x3;
393 return;
394
395 case 1:
396 /* delta-x */
397 ms->ms_byteno = 2;
398 ms->ms_dx += (char)c;
399 return;
400
401 case 2:
402 /* delta-y */
403 ms->ms_byteno = -1;
404 ms->ms_dy += (char)c;
405 break;
406
407 default:
408 panic("ms_input");
409 /* NOTREACHED */
410 }
411
412 /*
413 * We have at least one event (mouse button, delta-X, or
414 * delta-Y; possibly all three, and possibly three separate
415 * button events). Deliver these events until we are out
416 * of changes or out of room. As events get delivered,
417 * mark them `unchanged'.
418 */
419 any = 0;
420 get = ms->ms_events.ev_get;
421 put = ms->ms_events.ev_put;
422 fe = &ms->ms_events.ev_q[put];
423
424 /* NEXT prepares to put the next event, backing off if necessary */
425 #define NEXT \
426 if ((++put) % EV_QSIZE == get) { \
427 put--; \
428 goto out; \
429 }
430 /* ADVANCE completes the `put' of the event */
431 #define ADVANCE \
432 fe++; \
433 if (put >= EV_QSIZE) { \
434 put = 0; \
435 fe = &ms->ms_events.ev_q[0]; \
436 } \
437
438 mb = ms->ms_mb;
439 ub = ms->ms_ub;
440 while ((d = mb ^ ub) != 0) {
441 /*
442 * Mouse button change. Convert up to three changes
443 * to the `first' change, and drop it into the event queue.
444 */
445 NEXT;
446 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */
447 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */
448 fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
449 fe->time = time;
450 ADVANCE;
451 ub ^= d;
452 any++;
453 }
454 if (ms->ms_dx) {
455 NEXT;
456 fe->id = LOC_X_DELTA;
457 fe->value = ms->ms_dx;
458 fe->time = time;
459 ADVANCE;
460 ms->ms_dx = 0;
461 any++;
462 }
463 if (ms->ms_dy) {
464 NEXT;
465 fe->id = LOC_Y_DELTA;
466 fe->value = -ms->ms_dy; /* XXX? */
467 fe->time = time;
468 ADVANCE;
469 ms->ms_dy = 0;
470 any++;
471 }
472 out:
473 if (any) {
474 ms->ms_ub = ub;
475 ms->ms_events.ev_put = put;
476 EV_WAKEUP(&ms->ms_events);
477 }
478 }
479
480 /****************************************************************
481 * Interface to the lower layer (zscc)
482 ****************************************************************/
483
484 static void ms_rxint __P((struct zs_chanstate *));
485 static void ms_stint __P((struct zs_chanstate *, int));
486 static void ms_txint __P((struct zs_chanstate *));
487 static void ms_softint __P((struct zs_chanstate *));
488
489 static void
490 ms_rxint(cs)
491 register struct zs_chanstate *cs;
492 {
493 register struct ms_softc *ms;
494 register int put, put_next;
495 register u_char c, rr1;
496
497 ms = cs->cs_private;
498 put = ms->ms_rbput;
499
500 /*
501 * First read the status, because reading the received char
502 * destroys the status of this char.
503 */
504 rr1 = zs_read_reg(cs, 1);
505 c = zs_read_data(cs);
506
507 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
508 /* Clear the receive error. */
509 zs_write_csr(cs, ZSWR0_RESET_ERRORS);
510 }
511
512 ms->ms_rbuf[put] = (c << 8) | rr1;
513 put_next = (put + 1) & MS_RX_RING_MASK;
514
515 /* Would overrun if increment makes (put==get). */
516 if (put_next == ms->ms_rbget) {
517 ms->ms_intr_flags |= INTR_RX_OVERRUN;
518 } else {
519 /* OK, really increment. */
520 put = put_next;
521 }
522
523 /* Done reading. */
524 ms->ms_rbput = put;
525
526 /* Ask for softint() call. */
527 cs->cs_softreq = 1;
528 }
529
530
531 static void
532 ms_txint(cs)
533 register struct zs_chanstate *cs;
534 {
535 register struct ms_softc *ms;
536
537 ms = cs->cs_private;
538 zs_write_csr(cs, ZSWR0_RESET_TXINT);
539 ms->ms_intr_flags |= INTR_TX_EMPTY;
540 /* Ask for softint() call. */
541 cs->cs_softreq = 1;
542 }
543
544
545 static void
546 ms_stint(cs, force)
547 register struct zs_chanstate *cs;
548 int force;
549 {
550 register struct ms_softc *ms;
551 register int rr0;
552
553 ms = cs->cs_private;
554
555 rr0 = zs_read_csr(cs);
556 zs_write_csr(cs, ZSWR0_RESET_STATUS);
557
558 /*
559 * We have to accumulate status line changes here.
560 * Otherwise, if we get multiple status interrupts
561 * before the softint runs, we could fail to notice
562 * some status line changes in the softint routine.
563 * Fix from Bill Studenmund, October 1996.
564 */
565 cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0);
566 cs->cs_rr0 = rr0;
567 ms->ms_intr_flags |= INTR_ST_CHECK;
568
569 /* Ask for softint() call. */
570 cs->cs_softreq = 1;
571 }
572
573
574 static void
575 ms_softint(cs)
576 struct zs_chanstate *cs;
577 {
578 register struct ms_softc *ms;
579 register int get, c, s;
580 int intr_flags;
581 register u_short ring_data;
582
583 ms = cs->cs_private;
584
585 /* Atomically get and clear flags. */
586 s = splzs();
587 intr_flags = ms->ms_intr_flags;
588 ms->ms_intr_flags = 0;
589
590 /* Now lower to spltty for the rest. */
591 (void) spltty();
592
593 /*
594 * Copy data from the receive ring to the event layer.
595 */
596 get = ms->ms_rbget;
597 while (get != ms->ms_rbput) {
598 ring_data = ms->ms_rbuf[get];
599 get = (get + 1) & MS_RX_RING_MASK;
600
601 /* low byte of ring_data is rr1 */
602 c = (ring_data >> 8) & 0xff;
603
604 if (ring_data & ZSRR1_DO)
605 intr_flags |= INTR_RX_OVERRUN;
606 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) {
607 log(LOG_ERR, "%s: input error (0x%x)\n",
608 ms->ms_dev.dv_xname, ring_data);
609 c = -1; /* signal input error */
610 }
611
612 /* Pass this up to the "middle" layer. */
613 ms_input(ms, c);
614 }
615 if (intr_flags & INTR_RX_OVERRUN) {
616 log(LOG_ERR, "%s: input overrun\n",
617 ms->ms_dev.dv_xname);
618 }
619 ms->ms_rbget = get;
620
621 if (intr_flags & INTR_TX_EMPTY) {
622 /*
623 * Transmit done. (Not expected.)
624 */
625 log(LOG_ERR, "%s: transmit interrupt?\n",
626 ms->ms_dev.dv_xname);
627 }
628
629 if (intr_flags & INTR_ST_CHECK) {
630 /*
631 * Status line change. (Not expected.)
632 */
633 log(LOG_ERR, "%s: status interrupt?\n",
634 ms->ms_dev.dv_xname);
635 cs->cs_rr0_delta = 0;
636 }
637
638 splx(s);
639 }
640
641 struct zsops zsops_ms = {
642 ms_rxint, /* receive char available */
643 ms_stint, /* external/status */
644 ms_txint, /* xmit buffer empty */
645 ms_softint, /* process software interrupt */
646 };
647
648
649 static void
650 ms_trigger (cs, onoff)
651 struct zs_chanstate *cs;
652 int onoff;
653 {
654 /* for front connected one */
655 if (onoff)
656 cs->cs_preg[5] |= ZSWR5_RTS;
657 else
658 cs->cs_preg[5] &= ~ZSWR5_RTS;
659 cs->cs_creg[5] = cs->cs_preg[5];
660 zs_write_reg(cs, 5, cs->cs_preg[5]);
661
662 /* for keyborad connected one */
663 mfp_send_usart (onoff | 0x40);
664 }
665
666 /*
667 * mouse timer interrupt.
668 * called after system tick interrupt is done.
669 */
670 void
671 ms_modem(arg)
672 void *arg;
673 {
674 struct ms_softc *ms = arg;
675 int s;
676
677 if (!ms->ms_ready)
678 return;
679
680 s = splzs();
681
682 if (ms->ms_nodata++ > 250) { /* XXX */
683 log(LOG_ERR, "%s: no data for 5 secs. resetting.\n",
684 ms->ms_dev.dv_xname);
685 ms->ms_byteno = -1;
686 ms->ms_nodata = 0;
687 ms->ms_rts = 0;
688 }
689
690 if (ms->ms_rts) {
691 if (ms->ms_byteno == -1) {
692 /* start next sequence */
693 ms->ms_rts = 0;
694 ms_trigger(ms->ms_cs, ms->ms_rts);
695 ms->ms_byteno = 0;
696 }
697 } else {
698 ms->ms_rts = 1;
699 ms_trigger(ms->ms_cs, ms->ms_rts);
700 }
701
702 (void) splx(s);
703 callout_reset(&ms->ms_modem_ch, 2, ms_modem, ms);
704 }
705