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