1*f82ca6eeSskrll /* $NetBSD: qms.c,v 1.22 2022/09/27 06:36:42 skrll Exp $ */
2e4247411Sbjh21
3e4247411Sbjh21 /*-
4e4247411Sbjh21 * Copyright (c) 2001 Reinoud Zandijk
5e4247411Sbjh21 * All rights reserved.
6e4247411Sbjh21 *
7e4247411Sbjh21 * This code is derived from software contributed to The NetBSD Foundation
8e4247411Sbjh21 * by Reinoud Zandijk
9e4247411Sbjh21 *
10e4247411Sbjh21 * Redistribution and use in source and binary forms, with or without
11e4247411Sbjh21 * modification, are permitted provided that the following conditions
12e4247411Sbjh21 * are met:
13e4247411Sbjh21 * 1. Redistributions of source code must retain the above copyright
14e4247411Sbjh21 * notice, this list of conditions and the following disclaimer.
15e4247411Sbjh21 * 2. Redistributions in binary form must reproduce the above copyright
16e4247411Sbjh21 * notice, this list of conditions and the following disclaimer in the
17e4247411Sbjh21 * documentation and/or other materials provided with the distribution.
18e4247411Sbjh21 *
19e4247411Sbjh21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20e4247411Sbjh21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21e4247411Sbjh21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22e4247411Sbjh21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23e4247411Sbjh21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24e4247411Sbjh21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25e4247411Sbjh21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26e4247411Sbjh21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27e4247411Sbjh21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28e4247411Sbjh21 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e4247411Sbjh21 * POSSIBILITY OF SUCH DAMAGE.
30e4247411Sbjh21 */
31e4247411Sbjh21 /*
32e4247411Sbjh21 * Quadrature mouse driver for the wscons as used in the IOMD
33e4247411Sbjh21 */
34e4247411Sbjh21
35e4247411Sbjh21 #include <sys/param.h>
36e4247411Sbjh21
37*f82ca6eeSskrll __KERNEL_RCSID(0, "$NetBSD: qms.c,v 1.22 2022/09/27 06:36:42 skrll Exp $");
38e4247411Sbjh21
39e4247411Sbjh21 #include <sys/callout.h>
40e4247411Sbjh21 #include <sys/device.h>
41e4247411Sbjh21 #include <sys/errno.h>
42e4247411Sbjh21 #include <sys/ioctl.h>
43e4247411Sbjh21 #include <sys/kernel.h>
44e4247411Sbjh21 #include <sys/proc.h>
45e4247411Sbjh21 #include <sys/tty.h>
46e4247411Sbjh21 #include <sys/types.h>
47e4247411Sbjh21 #include <sys/syslog.h>
48e4247411Sbjh21 #include <sys/systm.h>
49e4247411Sbjh21 #include <sys/select.h>
50e4247411Sbjh21
51ed9977b1Sdyoung #include <sys/bus.h>
52e4247411Sbjh21 #include <machine/intr.h>
53e4247411Sbjh21
54e4247411Sbjh21 #include <arm/iomd/iomdvar.h>
55e4247411Sbjh21
56e4247411Sbjh21 #include <dev/wscons/wsconsio.h>
57e4247411Sbjh21 #include <dev/wscons/wsmousevar.h>
58e4247411Sbjh21
59e4247411Sbjh21 struct qms_softc {
60e0f866efSskrll device_t sc_dev;
61e0f866efSskrll device_t sc_wsmousedev;
62e4247411Sbjh21
63e4247411Sbjh21 bus_space_tag_t sc_iot; /* bus tag */
64e4247411Sbjh21 bus_space_handle_t sc_ioh; /* bus handle for XY */
65e4247411Sbjh21 bus_space_handle_t sc_butioh; /* bus handle for buttons */
66e4247411Sbjh21
67e4247411Sbjh21 struct callout sc_callout;
68e4247411Sbjh21
699ea87d7dSskrll uint16_t lastx;
709ea87d7dSskrll uint16_t lasty;
71e4247411Sbjh21 int lastb;
72e4247411Sbjh21 };
73e4247411Sbjh21
74e4247411Sbjh21 /* Offsets of hardware registers */
75e4247411Sbjh21 #define QMS_MOUSEX 0 /* 16 bits X register */
76e4247411Sbjh21 #define QMS_MOUSEY 1 /* 16 bits Y register */
77e4247411Sbjh21 #define QMS_BUTTONS 0 /* mouse buttons in bits 4,5,6 */
78e4247411Sbjh21
79e0f866efSskrll static int qms_match(device_t , cfdata_t , void *);
80e0f866efSskrll static void qms_attach(device_t , device_t , void *);
81e4247411Sbjh21
82e4247411Sbjh21 static int qms_enable(void *);
8353524e44Schristos static int qms_ioctl(void *, u_long, void *, int, struct lwp *);
84e4247411Sbjh21 static void qms_disable(void *cookie);
85e4247411Sbjh21 static void qms_intr(void *arg);
86e4247411Sbjh21
87e0f866efSskrll CFATTACH_DECL_NEW(qms, sizeof(struct qms_softc),
88e4247411Sbjh21 qms_match, qms_attach, NULL, NULL);
89e4247411Sbjh21
90e4247411Sbjh21 static struct wsmouse_accessops qms_accessops = {
91e4247411Sbjh21 qms_enable, qms_ioctl, qms_disable
92e4247411Sbjh21 };
93e4247411Sbjh21
94e4247411Sbjh21
95e4247411Sbjh21 static int
qms_match(device_t parent,cfdata_t cf,void * aux)96e0f866efSskrll qms_match(device_t parent, cfdata_t cf, void *aux)
97e4247411Sbjh21 {
98e4247411Sbjh21 struct qms_attach_args *qa = aux;
99e4247411Sbjh21
100e4247411Sbjh21 if (strcmp(qa->qa_name, "qms") == 0)
101758ec341Sbjh21 return 1;
102e4247411Sbjh21
103758ec341Sbjh21 return 0;
104e4247411Sbjh21 }
105e4247411Sbjh21
106e4247411Sbjh21
107e4247411Sbjh21 static void
qms_attach(device_t parent,device_t self,void * aux)108e0f866efSskrll qms_attach(device_t parent, device_t self, void *aux)
109e4247411Sbjh21 {
110e0f866efSskrll struct qms_softc *sc = device_private(self);
111e4247411Sbjh21 struct qms_attach_args *qa = aux;
112e4247411Sbjh21 struct wsmousedev_attach_args wsmouseargs;
113e4247411Sbjh21
114e0f866efSskrll sc->sc_dev = self;
115e4247411Sbjh21 sc->sc_iot = qa->qa_iot;
116e4247411Sbjh21 sc->sc_ioh = qa->qa_ioh;
117e4247411Sbjh21 sc->sc_butioh = qa->qa_ioh_but;
118e4247411Sbjh21
119e4247411Sbjh21 /* set up wsmouse attach arguments */
120e4247411Sbjh21 wsmouseargs.accessops = &qms_accessops;
121e4247411Sbjh21 wsmouseargs.accesscookie = sc;
122e4247411Sbjh21
123e0f866efSskrll aprint_normal("\n");
124e4247411Sbjh21
125e4247411Sbjh21 sc->sc_wsmousedev =
126c7fb772bSthorpej config_found(sc->sc_dev, &wsmouseargs, wsmousedevprint, CFARGS_NONE);
127e4247411Sbjh21
12888ab7da9Sad callout_init(&sc->sc_callout, 0);
129e4247411Sbjh21 }
130e4247411Sbjh21
131e4247411Sbjh21
132e4247411Sbjh21 static int
qms_enable(void * cookie)133e4247411Sbjh21 qms_enable(void *cookie)
134e4247411Sbjh21 {
135e4247411Sbjh21 struct qms_softc *sc = cookie;
136e4247411Sbjh21 int b;
137e4247411Sbjh21
138e4247411Sbjh21 /* We don't want the mouse to warp on open. */
139e4247411Sbjh21 sc->lastx = bus_space_read_4(sc->sc_iot, sc->sc_ioh, QMS_MOUSEX);
140e4247411Sbjh21 sc->lasty = bus_space_read_4(sc->sc_iot, sc->sc_ioh, QMS_MOUSEY);
141e4247411Sbjh21 b = bus_space_read_1(sc->sc_iot, sc->sc_butioh, QMS_BUTTONS) & 0x70;
142e4247411Sbjh21
143e4247411Sbjh21 /* patch up the buttons */
144e4247411Sbjh21 b >>= 4;
145e4247411Sbjh21 sc->lastb = ~( ((b & 1)<<2) | (b & 2) | ((b & 4)>>2));
146e4247411Sbjh21
147e4247411Sbjh21 callout_reset(&sc->sc_callout, hz / 100, qms_intr, sc);
148e4247411Sbjh21 return 0;
149e4247411Sbjh21 }
150e4247411Sbjh21
151e4247411Sbjh21
152e4247411Sbjh21 static void
qms_disable(void * cookie)153e4247411Sbjh21 qms_disable(void *cookie)
154e4247411Sbjh21 {
155e4247411Sbjh21 struct qms_softc *sc = cookie;
156e4247411Sbjh21
157e4247411Sbjh21 callout_stop(&sc->sc_callout);
158e4247411Sbjh21 }
159e4247411Sbjh21
160e4247411Sbjh21
161e4247411Sbjh21 static int
qms_ioctl(void * cookie,u_long cmd,void * data,int flag,struct lwp * l)16253524e44Schristos qms_ioctl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
163e4247411Sbjh21 {
164e4247411Sbjh21
165e4247411Sbjh21 switch (cmd) {
166e4247411Sbjh21 case WSMOUSEIO_GTYPE:
167e4247411Sbjh21 *(int *)data = WSMOUSE_TYPE_ARCHIMEDES;
168e4247411Sbjh21 return 0;
169e4247411Sbjh21 }
170e4247411Sbjh21
171e4247411Sbjh21 return EPASSTHROUGH;
172e4247411Sbjh21 }
173e4247411Sbjh21
174e4247411Sbjh21
175e4247411Sbjh21 static void
qms_intr(void * arg)176e4247411Sbjh21 qms_intr(void *arg)
177e4247411Sbjh21 {
178e4247411Sbjh21 struct qms_softc *sc = arg;
179e4247411Sbjh21 int b;
1809ea87d7dSskrll uint16_t x, y;
181e4247411Sbjh21 int16_t dx, dy;
182e4247411Sbjh21
183e4247411Sbjh21 x = bus_space_read_4(sc->sc_iot, sc->sc_ioh, QMS_MOUSEX);
184e4247411Sbjh21 y = bus_space_read_4(sc->sc_iot, sc->sc_ioh, QMS_MOUSEY);
185e4247411Sbjh21 b = bus_space_read_1(sc->sc_iot, sc->sc_butioh, QMS_BUTTONS) & 0x70;
186e4247411Sbjh21
187e4247411Sbjh21 /* patch up the buttons */
188e4247411Sbjh21 b >>= 4;
189e4247411Sbjh21 b = ~( ((b & 1)<<2) | (b & 2) | ((b & 4)>>2));
190e4247411Sbjh21
191e4247411Sbjh21 if ((x != sc->lastx) || (y != sc->lasty) || (b != sc->lastb)) {
192e4247411Sbjh21 /* This assumes that int16_t is two's complement. */
193e4247411Sbjh21 dx = x - sc->lastx;
194e4247411Sbjh21 dy = y - sc->lasty;
19557c0199dSplunky wsmouse_input(sc->sc_wsmousedev,
19657c0199dSplunky b,
19757c0199dSplunky dx, dy, 0, 0,
198e4247411Sbjh21 WSMOUSE_INPUT_DELTA);
199e4247411Sbjh21
200e4247411Sbjh21 /* save old values */
201e4247411Sbjh21 sc->lastx = x;
202e4247411Sbjh21 sc->lasty = y;
203e4247411Sbjh21 sc->lastb = b;
204758ec341Sbjh21 }
205e4247411Sbjh21 callout_reset(&sc->sc_callout, hz / 100, qms_intr, sc);
206e4247411Sbjh21 }
207e4247411Sbjh21
208e4247411Sbjh21
209e4247411Sbjh21 /* end of qms.c */
210