xref: /openbsd/sys/arch/i386/isa/mms.c (revision d485f761)
1 /*	$OpenBSD: mms.c,v 1.15 2001/08/07 19:24:27 jason Exp $ */
2 /*	$NetBSD: mms.c,v 1.35 2000/01/08 02:57:25 takemura Exp $	*/
3 
4 /*-
5  * Copyright (c) 1993, 1994 Charles M. Hannum.
6  * Copyright (c) 1992, 1993 Erik Forsberg.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
16  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
18  * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/ioctl.h>
30 #include <sys/device.h>
31 
32 #include <machine/intr.h>
33 #include <machine/bus.h>
34 
35 #include <dev/isa/isavar.h>
36 
37 #include <dev/wscons/wsconsio.h>
38 #include <dev/wscons/wsmousevar.h>
39 
40 #define	MMS_ADDR	0	/* offset for register select */
41 #define	MMS_DATA	1	/* offset for InPort data */
42 #define	MMS_IDENT	2	/* offset for identification register */
43 #define	MMS_NPORTS	4
44 
45 struct mms_softc {		/* driver status information */
46 	struct device sc_dev;
47 	void *sc_ih;
48 
49 	bus_space_tag_t sc_iot;
50 	bus_space_handle_t sc_ioh;
51 
52 	int sc_enabled; /* device is open */
53 
54 	struct device *sc_wsmousedev;
55 };
56 
57 int mmsprobe __P((struct device *, void *, void *));
58 void mmsattach __P((struct device *, struct device *, void *));
59 int mmsintr __P((void *));
60 
61 struct cfattach mms_ca = {
62 	sizeof(struct mms_softc), mmsprobe, mmsattach
63 };
64 
65 int	mms_enable __P((void *));
66 int	mms_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
67 void	mms_disable __P((void *));
68 
69 const struct wsmouse_accessops mms_accessops = {
70 	mms_enable,
71 	mms_ioctl,
72 	mms_disable,
73 };
74 
75 int
76 mmsprobe(parent, match, aux)
77 	struct device *parent;
78 	void *match;
79 	void *aux;
80 {
81 	struct isa_attach_args *ia = aux;
82 	bus_space_tag_t iot = ia->ia_iot;
83 	bus_space_handle_t ioh;
84 	int rv;
85 
86 	/* Disallow wildcarded i/o address. */
87 	if (ia->ia_iobase == IOBASEUNK)
88 		return 0;
89 
90 	/* Map the i/o space. */
91 	if (bus_space_map(iot, ia->ia_iobase, MMS_NPORTS, 0, &ioh))
92 		return 0;
93 
94 	rv = 0;
95 
96 	/* Read identification register to see if present */
97 	if (bus_space_read_1(iot, ioh, MMS_IDENT) != 0xde)
98 		goto out;
99 
100 	/* Seems it was there; reset. */
101 	bus_space_write_1(iot, ioh, MMS_ADDR, 0x87);
102 
103 	rv = 1;
104 	ia->ia_iosize = MMS_NPORTS;
105 	ia->ia_msize = 0;
106 
107 out:
108 	bus_space_unmap(iot, ioh, MMS_NPORTS);
109 	return rv;
110 }
111 
112 void
113 mmsattach(parent, self, aux)
114 	struct device *parent, *self;
115 	void *aux;
116 {
117 	struct mms_softc *sc = (void *)self;
118 	struct isa_attach_args *ia = aux;
119 	bus_space_tag_t iot = ia->ia_iot;
120 	bus_space_handle_t ioh;
121 	struct wsmousedev_attach_args a;
122 
123 	printf("\n");
124 
125 	if (bus_space_map(iot, ia->ia_iobase, MMS_NPORTS, 0, &ioh)) {
126 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
127 		return;
128 	}
129 
130 	/* Other initialization was done by mmsprobe. */
131 	sc->sc_iot = iot;
132 	sc->sc_ioh = ioh;
133 	sc->sc_enabled = 0;
134 
135 	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_PULSE,
136 	    IPL_TTY, mmsintr, sc, sc->sc_dev.dv_xname);
137 
138 	a.accessops = &mms_accessops;
139 	a.accesscookie = sc;
140 
141 	/*
142 	 * Attach the wsmouse, saving a handle to it.
143 	 * Note that we don't need to check this pointer against NULL
144 	 * here or in psmintr, because if this fails lms_enable() will
145 	 * never be called, so lmsintr() will never be called.
146 	 */
147 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
148 }
149 
150 int
151 mms_enable(v)
152 	void *v;
153 {
154 	struct mms_softc *sc = v;
155 
156 	if (sc->sc_enabled)
157 		return EBUSY;
158 
159 	sc->sc_enabled = 1;
160 
161 	/* Enable interrupts. */
162 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_ADDR, 0x07);
163 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_DATA, 0x09);
164 
165 	return 0;
166 }
167 
168 void
169 mms_disable(v)
170 	void *v;
171 {
172 	struct mms_softc *sc = v;
173 
174 	/* Disable interrupts. */
175 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_ADDR, 0x87);
176 
177 	sc->sc_enabled = 0;
178 }
179 
180 int
181 mms_ioctl(v, cmd, data, flag, p)
182 	void *v;
183 	u_long cmd;
184 	caddr_t data;
185 	int flag;
186 	struct proc *p;
187 {
188 #if 0
189 	struct mms_softc *sc = v;
190 #endif
191 
192 	switch (cmd) {
193 	case WSMOUSEIO_GTYPE:
194 		*(u_int *)data = WSMOUSE_TYPE_MMS;
195 		return (0);
196 	}
197 	return (-1);
198 }
199 
200 int
201 mmsintr(arg)
202 	void *arg;
203 {
204 	struct mms_softc *sc = arg;
205 	bus_space_tag_t iot = sc->sc_iot;
206 	bus_space_handle_t ioh = sc->sc_ioh;
207 	u_char status;
208 	signed char dx, dy;
209 	u_int buttons;
210 	int changed;
211 
212 	if (!sc->sc_enabled)
213 		/* Interrupts are not expected. */
214 		return 0;
215 
216 	/* Freeze InPort registers (disabling interrupts). */
217 	bus_space_write_1(iot, ioh, MMS_ADDR, 0x07);
218 	bus_space_write_1(iot, ioh, MMS_DATA, 0x29);
219 
220 	bus_space_write_1(iot, ioh, MMS_ADDR, 0x00);
221 	status = bus_space_read_1(iot, ioh, MMS_DATA);
222 
223 	if (status & 0x40) {
224 		bus_space_write_1(iot, ioh, MMS_ADDR, 1);
225 		dx = bus_space_read_1(iot, ioh, MMS_DATA);
226 		/* Bounding at -127 avoids a bug in XFree86. */
227 		dx = (dx == -128) ? -127 : dx;
228 
229 		bus_space_write_1(iot, ioh, MMS_ADDR, 2);
230 		dy = bus_space_read_1(iot, ioh, MMS_DATA);
231 		dy = (dy == -128) ? 127 : -dy;
232 	} else
233 		dx = dy = 0;
234 
235 	/* Unfreeze InPort registers (reenabling interrupts). */
236 	bus_space_write_1(iot, ioh, MMS_ADDR, 0x07);
237 	bus_space_write_1(iot, ioh, MMS_DATA, 0x09);
238 
239 	buttons = ((status & 0x04) ? 0x1 : 0) |
240 		((status & 0x02) ? 0x2 : 0) |
241 		((status & 0x01) ? 0x4 : 0);
242 	changed = status & 0x38;
243 
244 	if (dx || dy || changed)
245 		wsmouse_input(sc->sc_wsmousedev,
246 			      buttons, dx, dy, 0, WSMOUSE_INPUT_DELTA);
247 
248 	return -1;
249 }
250 
251 struct cfdriver mms_cd = {
252 	NULL, "mms", DV_DULL
253 };
254