1 /* $NetBSD: zsms.c,v 1.17 2008/03/29 19:15:36 tsutsui Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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.
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
40 * @(#)ms.c 8.1 (Berkeley) 6/11/93
44 * VSXXX mice attached with channel A of the 1st SCC
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: zsms.c,v 1.17 2008/03/29 19:15:36 tsutsui Exp $");
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>
59 #include <dev/ic/z8530reg.h>
60 #include <machine/z8530var.h>
62 #include <dev/dec/lk201.h>
64 #include <dev/wscons/wsconsio.h>
65 #include <dev/wscons/wsmousevar.h>
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!
74 #define ZSMS_RX_RING_SIZE 256
75 #define ZSMS_RX_RING_MASK (ZSMS_RX_RING_SIZE-1)
77 * Output buffer. Only need a few chars.
79 #define ZSMS_TX_RING_SIZE 16
80 #define ZSMS_TX_RING_MASK (ZSMS_TX_RING_SIZE-1)
84 struct zsms_softc
{ /* driver status information */
85 device_t zsms_dev
; /* required first: base device */
86 struct zs_chanstate
*zsms_cs
;
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
95 * The receive ring buffer.
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 */
101 int sc_enabled
; /* input enabled? */
102 int sc_selftest
; /* self test in progress */
108 device_t sc_wsmousedev
;
111 static struct zsops zsops_zsms
;
113 static int zsms_match(device_t
, cfdata_t
, void *);
114 static void zsms_attach(device_t
, device_t
, void *);
115 static void zsms_input(void *, int);
117 CFATTACH_DECL_NEW(zsms
, sizeof(struct zsms_softc
),
118 zsms_match
, zsms_attach
, NULL
, NULL
);
120 static int zsms_enable(void *);
121 static int zsms_ioctl(void *, u_long
, void *, int, struct lwp
*);
122 static void zsms_disable(void *);
124 static const struct wsmouse_accessops zsms_accessops
= {
131 zsms_match(device_t parent
, cfdata_t cf
, void *aux
)
133 struct zsc_attach_args
*args
= aux
;
135 /* Exact match is better than wildcard. */
136 if (cf
->cf_loc
[ZSCCF_CHANNEL
] == args
->channel
)
139 /* This driver accepts wildcard. */
140 if (cf
->cf_loc
[ZSCCF_CHANNEL
] == ZSCCF_CHANNEL_DEFAULT
)
147 zsms_attach(device_t parent
, device_t self
, void *aux
)
149 struct zsc_softc
*zsc
= device_private(parent
);
150 struct zsms_softc
*zsms
= device_private(self
);
151 struct zsc_attach_args
*args
= aux
;
152 struct zs_chanstate
*cs
;
153 struct wsmousedev_attach_args a
;
156 zsms
->zsms_dev
= self
;
157 cs
= zsc
->zsc_cs
[args
->channel
];
158 cs
->cs_private
= zsms
;
159 cs
->cs_ops
= &zsops_zsms
;
164 /* Initialize the speed, etc. */
166 /* May need reset... */
167 zs_write_reg(cs
, 9, ZSWR9_A_RESET
);
168 /* These are OK as set by zscc: WR3, WR5 */
169 /* We don't care about status or tx interrupts. */
170 cs
->cs_preg
[1] = ZSWR1_RIE
;
171 (void) zs_set_speed(cs
, ZSMS_BPS
);
173 /* mouse wants odd parity */
174 cs
->cs_preg
[4] |= ZSWR4_PARENB
;
175 /* cs->cs_preg[4] &= ~ZSWR4_EVENP; (no-op) */
177 zs_loadchannelregs(cs
);
180 a
.accessops
= &zsms_accessops
;
181 a
.accesscookie
= zsms
;
183 zsms
->sc_enabled
= 0;
184 zsms
->sc_selftest
= 0;
185 zsms
->sc_wsmousedev
= config_found(self
, &a
, wsmousedevprint
);
191 struct zsms_softc
*sc
= v
;
196 sc
->sc_selftest
= 4; /* wait for 4 byte reply upto 1/2 sec */
197 zs_write_data(sc
->zsms_cs
, MOUSE_SELF_TEST
);
198 (void)tsleep(zsms_enable
, TTIPRI
, "zsmsopen", hz
/ 2);
199 if (sc
->sc_selftest
!= 0) {
203 /* XXX DELAY before mode set? */
204 zs_write_data(sc
->zsms_cs
, MOUSE_INCREMENTAL
);
211 zsms_disable(void *v
)
213 struct zsms_softc
*sc
= v
;
219 zsms_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
222 if (cmd
== WSMOUSEIO_GTYPE
) {
223 *(u_int
*)data
= WSMOUSE_TYPE_VSXXX
;
230 zsms_input(void *vsc
, int data
)
232 struct zsms_softc
*sc
= vsc
;
234 if (sc
->sc_enabled
== 0) {
235 if (sc
->sc_selftest
> 0) {
236 sc
->sc_selftest
-= 1;
237 if (sc
->sc_selftest
== 0)
243 if ((data
& MOUSE_START_FRAME
) != 0)
248 if (sc
->inputstate
== 1) {
249 /* LMR -> RML: wsevents counts 0 for the left-most */
250 sc
->buttons
= data
& 02;
255 sc
->dx
= data
& MOUSE_X_SIGN
;
256 sc
->dy
= data
& MOUSE_Y_SIGN
;
257 } else if (sc
->inputstate
== 2) {
262 } else if (sc
->inputstate
== 3) {
268 wsmouse_input(sc
->sc_wsmousedev
,
270 sc
->dx
, sc
->dy
, 0, 0,
271 WSMOUSE_INPUT_DELTA
);
277 /****************************************************************
278 * Interface to the lower layer (zscc)
279 ****************************************************************/
281 static void zsms_rxint(struct zs_chanstate
*);
282 static void zsms_stint(struct zs_chanstate
*, int);
283 static void zsms_txint(struct zs_chanstate
*);
284 static void zsms_softint(struct zs_chanstate
*);
287 zsms_rxint(struct zs_chanstate
*cs
)
289 struct zsms_softc
*zsms
;
293 zsms
= cs
->cs_private
;
294 put
= zsms
->zsms_rbput
;
297 * First read the status, because reading the received char
298 * destroys the status of this char.
300 rr1
= zs_read_reg(cs
, 1);
301 c
= zs_read_data(cs
);
302 if (rr1
& (ZSRR1_FE
| ZSRR1_DO
| ZSRR1_PE
)) {
303 /* Clear the receive error. */
304 zs_write_csr(cs
, ZSWR0_RESET_ERRORS
);
307 zsms
->zsms_rbuf
[put
] = (c
<< 8) | rr1
;
308 put_next
= (put
+ 1) & ZSMS_RX_RING_MASK
;
310 /* Would overrun if increment makes (put==get). */
311 if (put_next
== zsms
->zsms_rbget
) {
312 zsms
->zsms_intr_flags
|= INTR_RX_OVERRUN
;
314 /* OK, really increment. */
319 zsms
->zsms_rbput
= put
;
321 /* Ask for softint() call. */
327 zsms_txint(struct zs_chanstate
*cs
)
329 struct zsms_softc
*zsms
;
331 zsms
= cs
->cs_private
;
332 zs_write_csr(cs
, ZSWR0_RESET_TXINT
);
333 zsms
->zsms_intr_flags
|= INTR_TX_EMPTY
;
334 /* Ask for softint() call. */
340 zsms_stint(struct zs_chanstate
*cs
, int force
)
342 struct zsms_softc
*zsms
;
345 zsms
= cs
->cs_private
;
347 rr0
= zs_read_csr(cs
);
348 zs_write_csr(cs
, ZSWR0_RESET_STATUS
);
351 * We have to accumulate status line changes here.
352 * Otherwise, if we get multiple status interrupts
353 * before the softint runs, we could fail to notice
354 * some status line changes in the softint routine.
355 * Fix from Bill Studenmund, October 1996.
357 cs
->cs_rr0_delta
|= (cs
->cs_rr0
^ rr0
);
359 zsms
->zsms_intr_flags
|= INTR_ST_CHECK
;
361 /* Ask for softint() call. */
367 zsms_softint(struct zs_chanstate
*cs
)
369 struct zsms_softc
*zsms
;
374 zsms
= cs
->cs_private
;
376 /* Atomically get and clear flags. */
378 intr_flags
= zsms
->zsms_intr_flags
;
379 zsms
->zsms_intr_flags
= 0;
381 /* Now lower to spltty for the rest. */
385 * Copy data from the receive ring to the event layer.
387 get
= zsms
->zsms_rbget
;
388 while (get
!= zsms
->zsms_rbput
) {
389 ring_data
= zsms
->zsms_rbuf
[get
];
390 get
= (get
+ 1) & ZSMS_RX_RING_MASK
;
392 /* low byte of ring_data is rr1 */
393 c
= (ring_data
>> 8) & 0xff;
395 if (ring_data
& ZSRR1_DO
)
396 intr_flags
|= INTR_RX_OVERRUN
;
397 if (ring_data
& (ZSRR1_FE
| ZSRR1_PE
)) {
398 log(LOG_ERR
, "%s: input error (0x%x)\n",
399 device_xname(zsms
->zsms_dev
), ring_data
);
400 c
= -1; /* signal input error */
403 /* Pass this up to the "middle" layer. */
406 if (intr_flags
& INTR_RX_OVERRUN
) {
407 log(LOG_ERR
, "%s: input overrun\n",
408 device_xname(zsms
->zsms_dev
));
410 zsms
->zsms_rbget
= get
;
412 if (intr_flags
& INTR_TX_EMPTY
) {
414 * Transmit done. (Not expected.)
416 log(LOG_ERR
, "%s: transmit interrupt?\n",
417 device_xname(zsms
->zsms_dev
));
420 if (intr_flags
& INTR_ST_CHECK
) {
422 * Status line change. (Not expected.)
424 log(LOG_ERR
, "%s: status interrupt?\n",
425 device_xname(zsms
->zsms_dev
));
426 cs
->cs_rr0_delta
= 0;
432 static struct zsops zsops_zsms
= {
433 zsms_rxint
, /* receive char available */
434 zsms_stint
, /* external/status */
435 zsms_txint
, /* xmit buffer empty */
436 zsms_softint
, /* process software interrupt */