zsms.c revision 1.1 1 /* $NetBSD: zsms.c,v 1.1 2000/07/05 02:48:50 nisimura 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 * VSXXX mice attached with channel A of the 1st SCC
49 */
50
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/device.h>
54 #include <sys/ioctl.h>
55 #include <sys/syslog.h>
56
57 #include <dev/ic/z8530reg.h>
58 #include <machine/z8530var.h>
59
60 #include <dev/dec/lk201.h>
61
62 #include <dev/wscons/wsconsio.h>
63 #include <dev/wscons/wsmousevar.h>
64
65 #include "locators.h"
66
67 /*
68 * How many input characters we can buffer.
69 * The port-specific var.h may override this.
70 * Note: must be a power of two!
71 */
72 #define ZSMS_RX_RING_SIZE 256
73 #define ZSMS_RX_RING_MASK (ZSMS_RX_RING_SIZE-1)
74 /*
75 * Output buffer. Only need a few chars.
76 */
77 #define ZSMS_TX_RING_SIZE 16
78 #define ZSMS_TX_RING_MASK (ZSMS_TX_RING_SIZE-1)
79
80 #define ZSMS_BPS 4800
81
82 struct zsms_softc { /* driver status information */
83 struct device zsms_dev; /* required first: base device */
84 struct zs_chanstate *zsms_cs;
85
86 /* Flags to communicate with zsms_softintr() */
87 volatile int zsms_intr_flags;
88 #define INTR_RX_OVERRUN 1
89 #define INTR_TX_EMPTY 2
90 #define INTR_ST_CHECK 4
91
92 /*
93 * The receive ring buffer.
94 */
95 u_int zsms_rbget; /* ring buffer `get' index */
96 volatile u_int zsms_rbput; /* ring buffer `put' index */
97 u_short zsms_rbuf[ZSMS_RX_RING_SIZE]; /* rr1, data pairs */
98
99 int sc_enabled; /* input enabled? */
100 int self_test;
101
102 int inputstate;
103 u_int buttons;
104 signed char dx;
105 signed char dy;
106
107 struct device *sc_wsmousedev;
108 };
109
110 struct zsops zsops_zsms;
111
112 static int zsms_match __P((struct device *, struct cfdata *, void *));
113 static void zsms_attach __P((struct device *, struct device *, void *));
114 static void zsms_input __P((void *, int));
115
116 struct cfattach zsms_ca = {
117 sizeof(struct zsms_softc), zsms_match, zsms_attach,
118 };
119
120 static int zsms_enable __P((void *));
121 static int zsms_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
122 static void zsms_disable __P((void *));
123
124 const struct wsmouse_accessops zsms_accessops = {
125 zsms_enable,
126 zsms_ioctl,
127 zsms_disable,
128 };
129
130 static int
131 zsms_match(parent, cf, aux)
132 struct device *parent;
133 struct cfdata *cf;
134 void *aux;
135 {
136 struct zsc_attach_args *args = aux;
137
138 /* Exact match is better than wildcard. */
139 if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel)
140 return 2;
141
142 /* This driver accepts wildcard. */
143 if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT)
144 return 1;
145
146 return 0;
147 }
148
149 static void
150 zsms_attach(parent, self, aux)
151 struct device *parent, *self;
152 void *aux;
153 {
154 struct zsc_softc *zsc = (void *)parent;
155 struct zsms_softc *zsms = (void *)self;
156 struct zsc_attach_args *args = aux;
157 struct zs_chanstate *cs;
158 struct wsmousedev_attach_args a;
159 int s;
160
161 cs = zsc->zsc_cs[args->channel];
162 cs->cs_private = zsms;
163 cs->cs_ops = &zsops_zsms;
164 zsms->zsms_cs = cs;
165
166 printf("\n");
167
168 /* Initialize the speed, etc. */
169 s = splzs();
170 /* May need reset... */
171 zs_write_reg(cs, 9, ZSWR9_A_RESET);
172 /* These are OK as set by zscc: WR3, WR5 */
173 /* We don't care about status or tx interrupts. */
174 cs->cs_preg[1] = ZSWR1_RIE;
175 (void) zs_set_speed(cs, ZSMS_BPS);
176
177 /* mouse wants odd parity */
178 cs->cs_preg[4] |= ZSWR4_PARENB;
179 /* cs->cs_preg[4] &= ~ZSWR4_EVENP; (no-op) */
180
181 zs_loadchannelregs(cs);
182 splx(s);
183
184 a.accessops = &zsms_accessops;
185 a.accesscookie = zsms;
186
187 /* XXX correct following comment block XXX
188 * Attach the wsmouse, saving a handle to it.
189 * Note that we don't need to check this pointer against NULL
190 * here or in pmsintr, because if this fails pms_enable() will
191 * never be called, so pmsintr() will never be called.
192 */
193 zsms->sc_enabled = 0;
194 zsms->self_test = 0;
195 zsms->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
196 }
197
198 static int
199 zsms_enable(v)
200 void *v;
201 {
202 struct zsms_softc *sc = v;
203
204 if (sc->sc_enabled)
205 return EBUSY;
206
207 /* XXX mice presence test should be done in match/attach context XXX */
208 sc->self_test = 1;
209 zs_write_data(sc->zsms_cs, MOUSE_SELF_TEST);
210 DELAY(100000);
211 if (sc->self_test < 0) {
212 sc->self_test = 0;
213 return EBUSY;
214 } else if (sc->self_test == 5) {
215 sc->self_test = 0;
216 sc->sc_enabled = 1;
217 }
218 sc->inputstate = 0;
219
220 zs_write_data(sc->zsms_cs, MOUSE_INCREMENTAL);
221
222 return 0;
223 }
224
225 static void
226 zsms_disable(v)
227 void *v;
228 {
229 struct zsms_softc *sc = v;
230
231 sc->sc_enabled = 0;
232 }
233
234 static int
235 zsms_ioctl(v, cmd, data, flag, p)
236 void *v;
237 u_long cmd;
238 caddr_t data;
239 int flag;
240 struct proc *p;
241 {
242 if (cmd == WSMOUSEIO_GTYPE) {
243 *(u_int *)data = WSMOUSE_TYPE_VSXXX;
244 return 0;
245 }
246 return -1;
247 }
248
249 static void
250 zsms_input(vsc, data)
251 void *vsc;
252 int data;
253 {
254 struct zsms_softc *sc = vsc;
255
256 /* XXX mice presence test should be done in match/attach context XXX */
257 if (!sc->sc_enabled) {
258 if (sc->self_test > 0) {
259 if (data < 0) {
260 printf("Timeout on 1st byte of mouse self-test report\n");
261 sc->self_test = -1;
262 } else {
263 sc->self_test++;
264 }
265 }
266 if (sc->self_test == 3) {
267 if ((data & 0x0f) != 0x2) {
268 printf("We don't have a mouse!!!\n");
269 sc->self_test = -1;
270 }
271 }
272 /* Interrupts are not expected. Discard the byte. */
273 return;
274 }
275
276 #define WSMS_BUTTON1 0x01
277 #define WSMS_BUTTON2 0x02
278 #define WSMS_BUTTON3 0x04
279
280 if ((data & MOUSE_START_FRAME) != 0)
281 sc->inputstate = 1;
282 else
283 sc->inputstate++;
284
285 if (sc->inputstate == 1) {
286 sc->buttons = 0;
287 if ((data & LEFT_BUTTON) != 0)
288 sc->buttons |= WSMS_BUTTON1;
289 if ((data & MIDDLE_BUTTON) != 0)
290 sc->buttons |= WSMS_BUTTON2;
291 if ((data & RIGHT_BUTTON) != 0)
292 sc->buttons |= WSMS_BUTTON3;
293
294 sc->dx = data & MOUSE_X_SIGN;
295 sc->dy = data & MOUSE_Y_SIGN;
296 } else if (sc->inputstate == 2) {
297 if (sc->dx == 0)
298 sc->dx = -data;
299 else
300 sc->dx = data;
301 } else if (sc->inputstate == 3) {
302 sc->inputstate = 0;
303 if (sc->dy == 0)
304 sc->dy = -data;
305 else
306 sc->dy = data;
307 wsmouse_input(sc->sc_wsmousedev, sc->buttons,
308 sc->dx, sc->dy, 0, WSMOUSE_INPUT_DELTA);
309 }
310
311 return;
312 }
313
314 /****************************************************************
315 * Interface to the lower layer (zscc)
316 ****************************************************************/
317
318 static void zsms_rxint __P((struct zs_chanstate *));
319 static void zsms_stint __P((struct zs_chanstate *, int));
320 static void zsms_txint __P((struct zs_chanstate *));
321 static void zsms_softint __P((struct zs_chanstate *));
322
323 static void
324 zsms_rxint(cs)
325 struct zs_chanstate *cs;
326 {
327 struct zsms_softc *zsms;
328 int put, put_next;
329 u_char c, rr1;
330
331 zsms = cs->cs_private;
332 put = zsms->zsms_rbput;
333
334 /*
335 * First read the status, because reading the received char
336 * destroys the status of this char.
337 */
338 rr1 = zs_read_reg(cs, 1);
339 c = zs_read_data(cs);
340 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
341 /* Clear the receive error. */
342 zs_write_csr(cs, ZSWR0_RESET_ERRORS);
343 }
344
345 zsms->zsms_rbuf[put] = (c << 8) | rr1;
346 put_next = (put + 1) & ZSMS_RX_RING_MASK;
347
348 /* Would overrun if increment makes (put==get). */
349 if (put_next == zsms->zsms_rbget) {
350 zsms->zsms_intr_flags |= INTR_RX_OVERRUN;
351 } else {
352 /* OK, really increment. */
353 put = put_next;
354 }
355
356 /* Done reading. */
357 zsms->zsms_rbput = put;
358
359 /* Ask for softint() call. */
360 cs->cs_softreq = 1;
361 }
362
363
364 static void
365 zsms_txint(cs)
366 struct zs_chanstate *cs;
367 {
368 struct zsms_softc *zsms;
369
370 zsms = cs->cs_private;
371 zs_write_csr(cs, ZSWR0_RESET_TXINT);
372 zsms->zsms_intr_flags |= INTR_TX_EMPTY;
373 /* Ask for softint() call. */
374 cs->cs_softreq = 1;
375 }
376
377
378 static void
379 zsms_stint(cs, force)
380 struct zs_chanstate *cs;
381 int force;
382 {
383 struct zsms_softc *zsms;
384 int rr0;
385
386 zsms = cs->cs_private;
387
388 rr0 = zs_read_csr(cs);
389 zs_write_csr(cs, ZSWR0_RESET_STATUS);
390
391 /*
392 * We have to accumulate status line changes here.
393 * Otherwise, if we get multiple status interrupts
394 * before the softint runs, we could fail to notice
395 * some status line changes in the softint routine.
396 * Fix from Bill Studenmund, October 1996.
397 */
398 cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0);
399 cs->cs_rr0 = rr0;
400 zsms->zsms_intr_flags |= INTR_ST_CHECK;
401
402 /* Ask for softint() call. */
403 cs->cs_softreq = 1;
404 }
405
406
407 static void
408 zsms_softint(cs)
409 struct zs_chanstate *cs;
410 {
411 struct zsms_softc *zsms;
412 int get, c, s;
413 int intr_flags;
414 u_short ring_data;
415
416 zsms = cs->cs_private;
417
418 /* Atomically get and clear flags. */
419 s = splzs();
420 intr_flags = zsms->zsms_intr_flags;
421 zsms->zsms_intr_flags = 0;
422
423 /* Now lower to spltty for the rest. */
424 (void) spltty();
425
426 /*
427 * Copy data from the receive ring to the event layer.
428 */
429 get = zsms->zsms_rbget;
430 while (get != zsms->zsms_rbput) {
431 ring_data = zsms->zsms_rbuf[get];
432 get = (get + 1) & ZSMS_RX_RING_MASK;
433
434 /* low byte of ring_data is rr1 */
435 c = (ring_data >> 8) & 0xff;
436
437 if (ring_data & ZSRR1_DO)
438 intr_flags |= INTR_RX_OVERRUN;
439 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) {
440 log(LOG_ERR, "%s: input error (0x%x)\n",
441 zsms->zsms_dev.dv_xname, ring_data);
442 c = -1; /* signal input error */
443 }
444
445 /* Pass this up to the "middle" layer. */
446 zsms_input(zsms, c);
447 }
448 if (intr_flags & INTR_RX_OVERRUN) {
449 log(LOG_ERR, "%s: input overrun\n",
450 zsms->zsms_dev.dv_xname);
451 }
452 zsms->zsms_rbget = get;
453
454 if (intr_flags & INTR_TX_EMPTY) {
455 /*
456 * Transmit done. (Not expected.)
457 */
458 log(LOG_ERR, "%s: transmit interrupt?\n",
459 zsms->zsms_dev.dv_xname);
460 }
461
462 if (intr_flags & INTR_ST_CHECK) {
463 /*
464 * Status line change. (Not expected.)
465 */
466 log(LOG_ERR, "%s: status interrupt?\n",
467 zsms->zsms_dev.dv_xname);
468 cs->cs_rr0_delta = 0;
469 }
470
471 splx(s);
472 }
473
474 struct zsops zsops_zsms = {
475 zsms_rxint, /* receive char available */
476 zsms_stint, /* external/status */
477 zsms_txint, /* xmit buffer empty */
478 zsms_softint, /* process software interrupt */
479 };
480