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