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