ms.c revision 1.6 1 /* $NetBSD: ms.c,v 1.6 1996/05/17 19:32:09 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/proc.h>
61 #include <sys/device.h>
62 #include <sys/conf.h>
63 #include <sys/ioctl.h>
64 #include <sys/kernel.h>
65 #include <sys/syslog.h>
66
67 #include <dev/ic/z8530reg.h>
68 #include <machine/z8530var.h>
69 #include <machine/vuid_event.h>
70
71 #include "event_var.h"
72
73 /*
74 * How many input characters we can buffer.
75 * The port-specific var.h may override this.
76 * Note: must be a power of two!
77 */
78 #define MS_RX_RING_SIZE 256
79 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1)
80 /*
81 * Output buffer. Only need a few chars.
82 */
83 #define MS_TX_RING_SIZE 16
84 #define MS_TX_RING_MASK (MS_TX_RING_SIZE-1)
85 /*
86 * Keyboard serial line speed is fixed at 1200 bps.
87 */
88 #define MS_BPS 1200
89
90 /*
91 * Mouse state. A Mouse Systems mouse is a fairly simple device,
92 * producing five-byte blobs of the form:
93 *
94 * b dx dy dx dy
95 *
96 * where b is the button state, encoded as 0x80|(~buttons)---there are
97 * three buttons (4=left, 2=middle, 1=right)---and dx,dy are X and Y
98 * delta values, none of which have are in [0x80..0x87]. (This lets
99 * us sync up with the mouse after an error.)
100 */
101 struct ms_softc {
102 struct device ms_dev; /* required first: base device */
103 struct zs_chanstate *ms_cs;
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
127 /*
128 * State of upper interface.
129 */
130 volatile int ms_ready; /* event queue is ready */
131 struct evvar ms_events; /* event queue state */
132 } ms_softc;
133
134 cdev_decl(ms); /* open, close, read, write, ioctl, stop, ... */
135
136 struct zsops zsops_ms;
137
138 /****************************************************************
139 * Definition of the driver for autoconfig.
140 ****************************************************************/
141
142 static int ms_match(struct device *, void *, void *);
143 static void ms_attach(struct device *, struct device *, void *);
144
145 struct cfattach ms_ca = {
146 sizeof(struct ms_softc), ms_match, ms_attach
147 };
148
149 struct cfdriver ms_cd = {
150 NULL, "ms", DV_DULL
151 };
152
153
154 /*
155 * ms_match: how is this zs channel configured?
156 */
157 int
158 ms_match(parent, match, aux)
159 struct device *parent;
160 void *match, *aux;
161 {
162 struct cfdata *cf = match;
163 struct zsc_attach_args *args = aux;
164
165 /* Exact match required for keyboard. */
166 if (cf->cf_loc[0] == args->channel)
167 return 2;
168
169 return 0;
170 }
171
172 void
173 ms_attach(parent, self, aux)
174 struct device *parent, *self;
175 void *aux;
176
177 {
178 struct zsc_softc *zsc = (void *) parent;
179 struct ms_softc *ms = (void *) self;
180 struct zsc_attach_args *args = aux;
181 struct zs_chanstate *cs;
182 struct cfdata *cf;
183 int channel, ms_unit;
184 int reset, s, tconst;
185
186 cf = ms->ms_dev.dv_cfdata;
187 ms_unit = ms->ms_dev.dv_unit;
188 channel = args->channel;
189 cs = &zsc->zsc_cs[channel];
190 cs->cs_private = ms;
191 cs->cs_ops = &zsops_ms;
192 ms->ms_cs = cs;
193
194 printf("\n");
195
196 /* Initialize the speed, etc. */
197 tconst = BPS_TO_TCONST(cs->cs_brg_clk, MS_BPS);
198 s = splzs();
199 /* May need reset... */
200 reset = (channel == 0) ?
201 ZSWR9_A_RESET : ZSWR9_B_RESET;
202 zs_write_reg(cs, 9, reset);
203 /* These are OK as set by zscc: WR3, WR4, WR5 */
204 cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
205 cs->cs_preg[12] = tconst;
206 cs->cs_preg[13] = tconst >> 8;
207 zs_loadchannelregs(cs);
208 splx(s);
209
210 /* Initialize translator. */
211 ms->ms_byteno = -1;
212 }
213
214 /****************************************************************
215 * Entry points for /dev/mouse
216 * (open,close,read,write,...)
217 ****************************************************************/
218
219 int
220 msopen(dev, flags, mode, p)
221 dev_t dev;
222 int flags, mode;
223 struct proc *p;
224 {
225 struct ms_softc *ms;
226 int error, s, unit;
227
228 unit = minor(dev);
229 if (unit >= ms_cd.cd_ndevs)
230 return (ENXIO);
231 ms = ms_cd.cd_devs[unit];
232 if (ms == NULL)
233 return (ENXIO);
234
235 /* This is an exclusive open device. */
236 if (ms->ms_events.ev_io)
237 return (EBUSY);
238 ms->ms_events.ev_io = p;
239 ev_init(&ms->ms_events); /* may cause sleep */
240
241 ms->ms_ready = 1; /* start accepting events */
242 return (0);
243 }
244
245 int
246 msclose(dev, flags, mode, p)
247 dev_t dev;
248 int flags, mode;
249 struct proc *p;
250 {
251 struct ms_softc *ms;
252
253 ms = ms_cd.cd_devs[minor(dev)];
254 ms->ms_ready = 0; /* stop accepting events */
255 ev_fini(&ms->ms_events);
256
257 ms->ms_events.ev_io = NULL;
258 return (0);
259 }
260
261 int
262 msread(dev, uio, flags)
263 dev_t dev;
264 struct uio *uio;
265 int flags;
266 {
267 struct ms_softc *ms;
268
269 ms = ms_cd.cd_devs[minor(dev)];
270 return (ev_read(&ms->ms_events, uio, flags));
271 }
272
273 /* this routine should not exist, but is convenient to write here for now */
274 int
275 mswrite(dev, uio, flags)
276 dev_t dev;
277 struct uio *uio;
278 int flags;
279 {
280
281 return (EOPNOTSUPP);
282 }
283
284 int
285 msioctl(dev, cmd, data, flag, p)
286 dev_t dev;
287 u_long cmd;
288 register caddr_t data;
289 int flag;
290 struct proc *p;
291 {
292 struct ms_softc *ms;
293
294 ms = ms_cd.cd_devs[minor(dev)];
295
296 switch (cmd) {
297
298 case FIONBIO: /* we will remove this someday (soon???) */
299 return (0);
300
301 case FIOASYNC:
302 ms->ms_events.ev_async = *(int *)data != 0;
303 return (0);
304
305 case TIOCSPGRP:
306 if (*(int *)data != ms->ms_events.ev_io->p_pgid)
307 return (EPERM);
308 return (0);
309
310 case VUIDGFORMAT:
311 /* we only do firm_events */
312 *(int *)data = VUID_FIRM_EVENT;
313 return (0);
314
315 case VUIDSFORMAT:
316 if (*(int *)data != VUID_FIRM_EVENT)
317 return (EINVAL);
318 return (0);
319 }
320 return (ENOTTY);
321 }
322
323 int
324 msselect(dev, rw, p)
325 dev_t dev;
326 int rw;
327 struct proc *p;
328 {
329 struct ms_softc *ms;
330
331 ms = ms_cd.cd_devs[minor(dev)];
332 return (ev_select(&ms->ms_events, rw, p));
333 }
334
335
336 /****************************************************************
337 * Middle layer (translator)
338 ****************************************************************/
339
340 /*
341 * Called by our ms_softint() routine on input.
342 */
343 void
344 ms_input(ms, c)
345 register struct ms_softc *ms;
346 register int c;
347 {
348 register struct firm_event *fe;
349 register int mb, ub, d, get, put, any;
350 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
351 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
352
353 /*
354 * Discard input if not ready. Drop sync on parity or framing
355 * error; gain sync on button byte.
356 */
357 if (ms->ms_ready == 0)
358 return;
359 if (c == -1) {
360 ms->ms_byteno = -1;
361 return;
362 }
363 if ((c & ~7) == 0x80) /* if in 0x80..0x87 */
364 ms->ms_byteno = 0;
365
366 /*
367 * Run the decode loop, adding to the current information.
368 * We add, rather than replace, deltas, so that if the event queue
369 * fills, we accumulate data for when it opens up again.
370 */
371 switch (ms->ms_byteno) {
372
373 case -1:
374 return;
375
376 case 0:
377 /* buttons */
378 ms->ms_byteno = 1;
379 ms->ms_mb = (~c) & 0x7;
380 return;
381
382 case 1:
383 /* first delta-x */
384 ms->ms_byteno = 2;
385 ms->ms_dx += (char)c;
386 return;
387
388 case 2:
389 /* first delta-y */
390 ms->ms_byteno = 3;
391 ms->ms_dy += (char)c;
392 return;
393
394 case 3:
395 /* second delta-x */
396 ms->ms_byteno = 4;
397 ms->ms_dx += (char)c;
398 return;
399
400 case 4:
401 /* second delta-x */
402 ms->ms_byteno = -1; /* wait for button-byte again */
403 ms->ms_dy += (char)c;
404 break;
405
406 default:
407 panic("ms_rint");
408 /* NOTREACHED */
409 }
410
411 /*
412 * We have at least one event (mouse button, delta-X, or
413 * delta-Y; possibly all three, and possibly three separate
414 * button events). Deliver these events until we are out
415 * of changes or out of room. As events get delivered,
416 * mark them `unchanged'.
417 */
418 any = 0;
419 get = ms->ms_events.ev_get;
420 put = ms->ms_events.ev_put;
421 fe = &ms->ms_events.ev_q[put];
422
423 /* NEXT prepares to put the next event, backing off if necessary */
424 #define NEXT \
425 if ((++put) % EV_QSIZE == get) { \
426 put--; \
427 goto out; \
428 }
429 /* ADVANCE completes the `put' of the event */
430 #define ADVANCE \
431 fe++; \
432 if (put >= EV_QSIZE) { \
433 put = 0; \
434 fe = &ms->ms_events.ev_q[0]; \
435 } \
436 any = 1
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 }
453 if (ms->ms_dx) {
454 NEXT;
455 fe->id = LOC_X_DELTA;
456 fe->value = ms->ms_dx;
457 fe->time = time;
458 ADVANCE;
459 ms->ms_dx = 0;
460 }
461 if (ms->ms_dy) {
462 NEXT;
463 fe->id = LOC_Y_DELTA;
464 fe->value = ms->ms_dy;
465 fe->time = time;
466 ADVANCE;
467 ms->ms_dy = 0;
468 }
469 out:
470 if (any) {
471 ms->ms_ub = ub;
472 ms->ms_events.ev_put = put;
473 EV_WAKEUP(&ms->ms_events);
474 }
475 }
476
477 /****************************************************************
478 * Interface to the lower layer (zscc)
479 ****************************************************************/
480
481 static void
482 ms_rxint(cs)
483 register struct zs_chanstate *cs;
484 {
485 register struct ms_softc *ms;
486 register int put, put_next;
487 register u_char c, rr1;
488
489 ms = cs->cs_private;
490 put = ms->ms_rbput;
491
492 /*
493 * First read the status, because reading the received char
494 * destroys the status of this char.
495 */
496 rr1 = zs_read_reg(cs, 1);
497 c = zs_read_data(cs);
498
499 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
500 /* Clear the receive error. */
501 zs_write_csr(cs, ZSWR0_RESET_ERRORS);
502 }
503
504 ms->ms_rbuf[put] = (c << 8) | rr1;
505 put_next = (put + 1) & MS_RX_RING_MASK;
506
507 /* Would overrun if increment makes (put==get). */
508 if (put_next == ms->ms_rbget) {
509 ms->ms_intr_flags |= INTR_RX_OVERRUN;
510 } else {
511 /* OK, really increment. */
512 put = put_next;
513 }
514
515 /* Done reading. */
516 ms->ms_rbput = put;
517
518 /* Ask for softint() call. */
519 cs->cs_softreq = 1;
520 }
521
522
523 static void
524 ms_txint(cs)
525 register struct zs_chanstate *cs;
526 {
527 register struct ms_softc *ms;
528
529 ms = cs->cs_private;
530 zs_write_csr(cs, ZSWR0_RESET_TXINT);
531 ms->ms_intr_flags |= INTR_TX_EMPTY;
532 /* Ask for softint() call. */
533 cs->cs_softreq = 1;
534 }
535
536
537 static void
538 ms_stint(cs)
539 register struct zs_chanstate *cs;
540 {
541 register struct ms_softc *ms;
542 register int rr0;
543
544 ms = cs->cs_private;
545
546 cs->cs_rr0_new = zs_read_csr(cs);
547 zs_write_csr(cs, ZSWR0_RESET_STATUS);
548
549 ms->ms_intr_flags |= INTR_ST_CHECK;
550 /* Ask for softint() call. */
551 cs->cs_softreq = 1;
552 }
553
554
555 static void
556 ms_softint(cs)
557 struct zs_chanstate *cs;
558 {
559 register struct ms_softc *ms;
560 register int get, c, s;
561 int intr_flags;
562 register u_short ring_data;
563 register u_char rr0, rr1;
564
565 ms = cs->cs_private;
566
567 /* Atomically get and clear flags. */
568 s = splzs();
569 intr_flags = ms->ms_intr_flags;
570 ms->ms_intr_flags = 0;
571
572 /* Now lower to spltty for the rest. */
573 (void) spltty();
574
575 /*
576 * Copy data from the receive ring to the event layer.
577 */
578 get = ms->ms_rbget;
579 while (get != ms->ms_rbput) {
580 ring_data = ms->ms_rbuf[get];
581 get = (get + 1) & MS_RX_RING_MASK;
582
583 /* low byte of ring_data is rr1 */
584 c = (ring_data >> 8) & 0xff;
585
586 if (ring_data & ZSRR1_DO)
587 intr_flags |= INTR_RX_OVERRUN;
588 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) {
589 log(LOG_ERR, "%s: input error (0x%x)\n",
590 ms->ms_dev.dv_xname, ring_data);
591 c = -1; /* signal input error */
592 }
593
594 /* Pass this up to the "middle" layer. */
595 ms_input(ms, c);
596 }
597 if (intr_flags & INTR_RX_OVERRUN) {
598 log(LOG_ERR, "%s: input overrun\n",
599 ms->ms_dev.dv_xname);
600 }
601 ms->ms_rbget = get;
602
603 if (intr_flags & INTR_TX_EMPTY) {
604 /*
605 * Transmit done. (Not expected.)
606 */
607 log(LOG_ERR, "%s: transmit interrupt?\n",
608 ms->ms_dev.dv_xname);
609 }
610
611 if (intr_flags & INTR_ST_CHECK) {
612 /*
613 * Status line change. (Not expected.)
614 */
615 log(LOG_ERR, "%s: status interrupt?\n",
616 ms->ms_dev.dv_xname);
617 cs->cs_rr0 = cs->cs_rr0_new;
618 }
619
620 splx(s);
621 }
622
623 struct zsops zsops_ms = {
624 ms_rxint, /* receive char available */
625 ms_stint, /* external/status */
626 ms_txint, /* xmit buffer empty */
627 ms_softint, /* process software interrupt */
628 };
629