xref: /openbsd/sys/arch/i386/isa/lms.c (revision db3296cf)
1 /*	$OpenBSD: lms.c,v 1.18 2002/03/14 01:26:33 millert Exp $	*/
2 /*	$NetBSD: lms.c,v 1.38 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/bus.h>
33 #include <machine/intr.h>
34 
35 #include <dev/isa/isavar.h>
36 
37 #include <dev/wscons/wsconsio.h>
38 #include <dev/wscons/wsmousevar.h>
39 
40 #define	LMS_DATA	0       /* offset for data port, read-only */
41 #define	LMS_SIGN	1       /* offset for signature port, read-write */
42 #define	LMS_INTR	2       /* offset for interrupt port, read-only */
43 #define	LMS_CNTRL	2       /* offset for control port, write-only */
44 #define	LMS_CONFIG	3	/* for configuration port, read-write */
45 #define	LMS_NPORTS	4
46 
47 struct lms_softc {		/* driver status information */
48 	struct device sc_dev;
49 	void *sc_ih;
50 
51 	bus_space_tag_t sc_iot;		/* bus i/o space identifier */
52 	bus_space_handle_t sc_ioh;	/* bus i/o handle */
53 
54 	int sc_enabled; /* device is open */
55 	int oldbuttons;	/* mouse button status */
56 
57 	struct device *sc_wsmousedev;
58 };
59 
60 int lmsprobe(struct device *, void *, void *);
61 void lmsattach(struct device *, struct device *, void *);
62 int lmsintr(void *);
63 
64 struct cfattach lms_ca = {
65 	sizeof(struct lms_softc), lmsprobe, lmsattach
66 };
67 
68 int	lms_enable(void *);
69 int	lms_ioctl(void *, u_long, caddr_t, int, struct proc *);
70 void	lms_disable(void *);
71 
72 const struct wsmouse_accessops lms_accessops = {
73 	lms_enable,
74 	lms_ioctl,
75 	lms_disable,
76 };
77 
78 int
79 lmsprobe(parent, match, aux)
80 	struct device *parent;
81 	void *match;
82 	void *aux;
83 {
84 	struct isa_attach_args *ia = aux;
85 	bus_space_tag_t iot = ia->ia_iot;
86 	bus_space_handle_t ioh;
87 	int rv;
88 
89 	/* Disallow wildcarded i/o base. */
90 	if (ia->ia_iobase == IOBASEUNK)
91 		return 0;
92 
93 	/* Map the i/o space. */
94 	if (bus_space_map(iot, ia->ia_iobase, LMS_NPORTS, 0, &ioh))
95 		return 0;
96 
97 	rv = 0;
98 
99 	/* Configure and check for port present. */
100 	bus_space_write_1(iot, ioh, LMS_CONFIG, 0x91);
101 	delay(10);
102 	bus_space_write_1(iot, ioh, LMS_SIGN, 0x0c);
103 	delay(10);
104 	if (bus_space_read_1(iot, ioh, LMS_SIGN) != 0x0c)
105 		goto out;
106 	bus_space_write_1(iot, ioh, LMS_SIGN, 0x50);
107 	delay(10);
108 	if (bus_space_read_1(iot, ioh, LMS_SIGN) != 0x50)
109 		goto out;
110 
111 	/* Disable interrupts. */
112 	bus_space_write_1(iot, ioh, LMS_CNTRL, 0x10);
113 
114 	rv = 1;
115 	ia->ia_iosize = LMS_NPORTS;
116 	ia->ia_msize = 0;
117 
118 out:
119 	bus_space_unmap(iot, ioh, LMS_NPORTS);
120 	return rv;
121 }
122 
123 void
124 lmsattach(parent, self, aux)
125 	struct device *parent, *self;
126 	void *aux;
127 {
128 	struct lms_softc *sc = (void *)self;
129 	struct isa_attach_args *ia = aux;
130 	bus_space_tag_t iot = ia->ia_iot;
131 	bus_space_handle_t ioh;
132 	struct wsmousedev_attach_args a;
133 
134 	printf("\n");
135 
136 	if (bus_space_map(iot, ia->ia_iobase, LMS_NPORTS, 0, &ioh)) {
137 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
138 		return;
139 	}
140 
141 	/* Other initialization was done by lmsprobe. */
142 	sc->sc_iot = iot;
143 	sc->sc_ioh = ioh;
144 	sc->sc_enabled = 0;
145 
146 	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_PULSE,
147 	    IPL_TTY, lmsintr, sc, sc->sc_dev.dv_xname);
148 
149 	a.accessops = &lms_accessops;
150 	a.accesscookie = sc;
151 
152 	/*
153 	 * Attach the wsmouse, saving a handle to it.
154 	 * Note that we don't need to check this pointer against NULL
155 	 * here or in psmintr, because if this fails lms_enable() will
156 	 * never be called, so lmsintr() will never be called.
157 	 */
158 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
159 }
160 
161 int
162 lms_enable(v)
163 	void *v;
164 {
165 	struct lms_softc *sc = v;
166 
167 	if (sc->sc_enabled)
168 		return EBUSY;
169 
170 	sc->sc_enabled = 1;
171 	sc->oldbuttons = 0;
172 
173 	/* Enable interrupts. */
174 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMS_CNTRL, 0);
175 
176 	return 0;
177 }
178 
179 void
180 lms_disable(v)
181 	void *v;
182 {
183 	struct lms_softc *sc = v;
184 
185 	/* Disable interrupts. */
186 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMS_CNTRL, 0x10);
187 
188 	sc->sc_enabled = 0;
189 }
190 
191 int
192 lms_ioctl(v, cmd, data, flag, p)
193 	void *v;
194 	u_long cmd;
195 	caddr_t data;
196 	int flag;
197 	struct proc *p;
198 {
199 #if 0
200 	struct lms_softc *sc = v;
201 #endif
202 
203 	switch (cmd) {
204 	case WSMOUSEIO_GTYPE:
205 		*(u_int *)data = WSMOUSE_TYPE_LMS;
206 		return (0);
207 	}
208 	return (-1);
209 }
210 
211 int
212 lmsintr(arg)
213 	void *arg;
214 {
215 	struct lms_softc *sc = arg;
216 	bus_space_tag_t iot = sc->sc_iot;
217 	bus_space_handle_t ioh = sc->sc_ioh;
218 	u_char hi, lo;
219 	signed char dx, dy;
220 	u_int buttons;
221 	int changed;
222 
223 	if (!sc->sc_enabled)
224 		/* Interrupts are not expected. */
225 		return 0;
226 
227 	bus_space_write_1(iot, ioh, LMS_CNTRL, 0xab);
228 	hi = bus_space_read_1(iot, ioh, LMS_DATA);
229 	bus_space_write_1(iot, ioh, LMS_CNTRL, 0x90);
230 	lo = bus_space_read_1(iot, ioh, LMS_DATA);
231 	dx = ((hi & 0x0f) << 4) | (lo & 0x0f);
232 	/* Bounding at -127 avoids a bug in XFree86. */
233 	dx = (dx == -128) ? -127 : dx;
234 
235 	bus_space_write_1(iot, ioh, LMS_CNTRL, 0xf0);
236 	hi = bus_space_read_1(iot, ioh, LMS_DATA);
237 	bus_space_write_1(iot, ioh, LMS_CNTRL, 0xd0);
238 	lo = bus_space_read_1(iot, ioh, LMS_DATA);
239 	dy = ((hi & 0x0f) << 4) | (lo & 0x0f);
240 	dy = (dy == -128) ? 127 : -dy;
241 
242 	bus_space_write_1(iot, ioh, LMS_CNTRL, 0);
243 
244 	buttons = ((hi & 0x80) ? 0 : 0x1) |
245 		((hi & 0x40) ? 0 : 0x2) |
246 		((hi & 0x20) ? 0 : 0x4);
247 	changed = (buttons ^ sc->oldbuttons);
248 	sc->oldbuttons = buttons;
249 
250 	if (dx || dy || changed)
251 		wsmouse_input(sc->sc_wsmousedev,
252 			      buttons, dx, dy, 0, WSMOUSE_INPUT_DELTA);
253 
254 	return -1;
255 }
256 
257 struct cfdriver lms_cd = {
258 	NULL, "lms", DV_DULL
259 };
260