FreeBSD/Linux Kernel Cross Reference
sys/dev/tc/zsms.c
1 /* $NetBSD: zsms.c,v 1.10 2003/08/07 16:31:28 agc 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 * VSXXX mice attached with channel A of the 1st SCC
45 */
46
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: zsms.c,v 1.10 2003/08/07 16:31:28 agc Exp $");
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/device.h>
53 #include <sys/ioctl.h>
54 #include <sys/syslog.h>
55 #include <sys/kernel.h>
56 #include <sys/proc.h>
57 #include <sys/tty.h>
58
59 #include <dev/ic/z8530reg.h>
60 #include <machine/z8530var.h>
61
62 #include <dev/dec/lk201.h>
63
64 #include <dev/wscons/wsconsio.h>
65 #include <dev/wscons/wsmousevar.h>
66
67 #include "locators.h"
68
69 /*
70 * How many input characters we can buffer.
71 * The port-specific var.h may override this.
72 * Note: must be a power of two!
73 */
74 #define ZSMS_RX_RING_SIZE 256
75 #define ZSMS_RX_RING_MASK (ZSMS_RX_RING_SIZE-1)
76 /*
77 * Output buffer. Only need a few chars.
78 */
79 #define ZSMS_TX_RING_SIZE 16
80 #define ZSMS_TX_RING_MASK (ZSMS_TX_RING_SIZE-1)
81
82 #define ZSMS_BPS 4800
83
84 struct zsms_softc { /* driver status information */
85 struct device zsms_dev; /* required first: base device */
86 struct zs_chanstate *zsms_cs;
87
88 /* Flags to communicate with zsms_softintr() */
89 volatile int zsms_intr_flags;
90 #define INTR_RX_OVERRUN 1
91 #define INTR_TX_EMPTY 2
92 #define INTR_ST_CHECK 4
93
94 /*
95 * The receive ring buffer.
96 */
97 u_int zsms_rbget; /* ring buffer `get' index */
98 volatile u_int zsms_rbput; /* ring buffer `put' index */
99 u_short zsms_rbuf[ZSMS_RX_RING_SIZE]; /* rr1, data pairs */
100
101 int sc_enabled; /* input enabled? */
102 int sc_selftest; /* self test in progress */
103
104 int inputstate;
105 u_int buttons;
106 int dx, dy;
107
108 struct device *sc_wsmousedev;
109 };
110
111 struct zsops zsops_zsms;
112
113 static int zsms_match __P((struct device *, struct cfdata *, void *));
114 static void zsms_attach __P((struct device *, struct device *, void *));
115 static void zsms_input __P((void *, int));
116
117 CFATTACH_DECL(zsms, sizeof(struct zsms_softc),
118 zsms_match, zsms_attach, NULL, NULL);
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 zsms->sc_enabled = 0;
188 zsms->sc_selftest = 0;
189 zsms->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
190 }
191
192 static int
193 zsms_enable(v)
194 void *v;
195 {
196 struct zsms_softc *sc = v;
197
198 if (sc->sc_enabled)
199 return EBUSY;
200
201 sc->sc_selftest = 4; /* wait for 4 byte reply upto 1/2 sec */
202 zs_write_data(sc->zsms_cs, MOUSE_SELF_TEST);
203 (void)tsleep(zsms_enable, TTIPRI, "zsmsopen", hz / 2);
204 if (sc->sc_selftest != 0) {
205 sc->sc_selftest = 0;
206 return ENXIO;
207 }
208 /* XXX DELAY before mode set? */
209 zs_write_data(sc->zsms_cs, MOUSE_INCREMENTAL);
210 sc->sc_enabled = 1;
211 sc->inputstate = 0;
212 return 0;
213 }
214
215 static void
216 zsms_disable(v)
217 void *v;
218 {
219 struct zsms_softc *sc = v;
220
221 sc->sc_enabled = 0;
222 }
223
224 static int
225 zsms_ioctl(v, cmd, data, flag, p)
226 void *v;
227 u_long cmd;
228 caddr_t data;
229 int flag;
230 struct proc *p;
231 {
232
233 if (cmd == WSMOUSEIO_GTYPE) {
234 *(u_int *)data = WSMOUSE_TYPE_VSXXX;
235 return 0;
236 }
237 return EPASSTHROUGH;
238 }
239
240 static void
241 zsms_input(vsc, data)
242 void *vsc;
243 int data;
244 {
245 struct zsms_softc *sc = vsc;
246
247 if (sc->sc_enabled == 0) {
248 if (sc->sc_selftest > 0) {
249 sc->sc_selftest -= 1;
250 if (sc->sc_selftest == 0)
251 wakeup(zsms_enable);
252 }
253 return;
254 }
255
256 if ((data & MOUSE_START_FRAME) != 0)
257 sc->inputstate = 1;
258 else
259 sc->inputstate++;
260
261 if (sc->inputstate == 1) {
262 /* LMR -> RML: wsevents counts 0 for the left-most */
263 sc->buttons = data & 02;
264 if (data & 01)
265 sc->buttons |= 04;
266 if (data & 04)
267 sc->buttons |= 01;
268 sc->dx = data & MOUSE_X_SIGN;
269 sc->dy = data & MOUSE_Y_SIGN;
270 } else if (sc->inputstate == 2) {
271 if (sc->dx == 0)
272 sc->dx = -data;
273 else
274 sc->dx = data;
275 } else if (sc->inputstate == 3) {
276 sc->inputstate = 0;
277 if (sc->dy == 0)
278 sc->dy = -data;
279 else
280 sc->dy = data;
281 wsmouse_input(sc->sc_wsmousedev, sc->buttons,
282 sc->dx, sc->dy, 0, WSMOUSE_INPUT_DELTA);
283 }
284
285 return;
286 }
287
288 /****************************************************************
289 * Interface to the lower layer (zscc)
290 ****************************************************************/
291
292 static void zsms_rxint __P((struct zs_chanstate *));
293 static void zsms_stint __P((struct zs_chanstate *, int));
294 static void zsms_txint __P((struct zs_chanstate *));
295 static void zsms_softint __P((struct zs_chanstate *));
296
297 static void
298 zsms_rxint(cs)
299 struct zs_chanstate *cs;
300 {
301 struct zsms_softc *zsms;
302 int put, put_next;
303 u_char c, rr1;
304
305 zsms = cs->cs_private;
306 put = zsms->zsms_rbput;
307
308 /*
309 * First read the status, because reading the received char
310 * destroys the status of this char.
311 */
312 rr1 = zs_read_reg(cs, 1);
313 c = zs_read_data(cs);
314 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
315 /* Clear the receive error. */
316 zs_write_csr(cs, ZSWR0_RESET_ERRORS);
317 }
318
319 zsms->zsms_rbuf[put] = (c << 8) | rr1;
320 put_next = (put + 1) & ZSMS_RX_RING_MASK;
321
322 /* Would overrun if increment makes (put==get). */
323 if (put_next == zsms->zsms_rbget) {
324 zsms->zsms_intr_flags |= INTR_RX_OVERRUN;
325 } else {
326 /* OK, really increment. */
327 put = put_next;
328 }
329
330 /* Done reading. */
331 zsms->zsms_rbput = put;
332
333 /* Ask for softint() call. */
334 cs->cs_softreq = 1;
335 }
336
337
338 static void
339 zsms_txint(cs)
340 struct zs_chanstate *cs;
341 {
342 struct zsms_softc *zsms;
343
344 zsms = cs->cs_private;
345 zs_write_csr(cs, ZSWR0_RESET_TXINT);
346 zsms->zsms_intr_flags |= INTR_TX_EMPTY;
347 /* Ask for softint() call. */
348 cs->cs_softreq = 1;
349 }
350
351
352 static void
353 zsms_stint(cs, force)
354 struct zs_chanstate *cs;
355 int force;
356 {
357 struct zsms_softc *zsms;
358 int rr0;
359
360 zsms = cs->cs_private;
361
362 rr0 = zs_read_csr(cs);
363 zs_write_csr(cs, ZSWR0_RESET_STATUS);
364
365 /*
366 * We have to accumulate status line changes here.
367 * Otherwise, if we get multiple status interrupts
368 * before the softint runs, we could fail to notice
369 * some status line changes in the softint routine.
370 * Fix from Bill Studenmund, October 1996.
371 */
372 cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0);
373 cs->cs_rr0 = rr0;
374 zsms->zsms_intr_flags |= INTR_ST_CHECK;
375
376 /* Ask for softint() call. */
377 cs->cs_softreq = 1;
378 }
379
380
381 static void
382 zsms_softint(cs)
383 struct zs_chanstate *cs;
384 {
385 struct zsms_softc *zsms;
386 int get, c, s;
387 int intr_flags;
388 u_short ring_data;
389
390 zsms = cs->cs_private;
391
392 /* Atomically get and clear flags. */
393 s = splzs();
394 intr_flags = zsms->zsms_intr_flags;
395 zsms->zsms_intr_flags = 0;
396
397 /* Now lower to spltty for the rest. */
398 (void) spltty();
399
400 /*
401 * Copy data from the receive ring to the event layer.
402 */
403 get = zsms->zsms_rbget;
404 while (get != zsms->zsms_rbput) {
405 ring_data = zsms->zsms_rbuf[get];
406 get = (get + 1) & ZSMS_RX_RING_MASK;
407
408 /* low byte of ring_data is rr1 */
409 c = (ring_data >> 8) & 0xff;
410
411 if (ring_data & ZSRR1_DO)
412 intr_flags |= INTR_RX_OVERRUN;
413 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) {
414 log(LOG_ERR, "%s: input error (0x%x)\n",
415 zsms->zsms_dev.dv_xname, ring_data);
416 c = -1; /* signal input error */
417 }
418
419 /* Pass this up to the "middle" layer. */
420 zsms_input(zsms, c);
421 }
422 if (intr_flags & INTR_RX_OVERRUN) {
423 log(LOG_ERR, "%s: input overrun\n",
424 zsms->zsms_dev.dv_xname);
425 }
426 zsms->zsms_rbget = get;
427
428 if (intr_flags & INTR_TX_EMPTY) {
429 /*
430 * Transmit done. (Not expected.)
431 */
432 log(LOG_ERR, "%s: transmit interrupt?\n",
433 zsms->zsms_dev.dv_xname);
434 }
435
436 if (intr_flags & INTR_ST_CHECK) {
437 /*
438 * Status line change. (Not expected.)
439 */
440 log(LOG_ERR, "%s: status interrupt?\n",
441 zsms->zsms_dev.dv_xname);
442 cs->cs_rr0_delta = 0;
443 }
444
445 splx(s);
446 }
447
448 struct zsops zsops_zsms = {
449 zsms_rxint, /* receive char available */
450 zsms_stint, /* external/status */
451 zsms_txint, /* xmit buffer empty */
452 zsms_softint, /* process software interrupt */
453 };
Cache object: 94094597947a5b1949fb73e1ff7a5d75
|