1 | /* $NetBSD: joy.c,v 1.20 2014/07/25 08:10:37 dholland Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software developed for The NetBSD Foundation |
8 | * by Andrew Doran. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /*- |
33 | * Copyright (c) 1995 Jean-Marc Zucconi |
34 | * All rights reserved. |
35 | * |
36 | * Ported to NetBSD by Matthieu Herrb <matthieu@laas.fr> |
37 | * |
38 | * Redistribution and use in source and binary forms, with or without |
39 | * modification, are permitted provided that the following conditions |
40 | * are met: |
41 | * 1. Redistributions of source code must retain the above copyright |
42 | * notice, this list of conditions and the following disclaimer |
43 | * in this position and unchanged. |
44 | * 2. Redistributions in binary form must reproduce the above copyright |
45 | * notice, this list of conditions and the following disclaimer in the |
46 | * documentation and/or other materials provided with the distribution. |
47 | * 3. The name of the author may not be used to endorse or promote products |
48 | * derived from this software without specific prior written permission |
49 | * |
50 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
51 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
52 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
53 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
54 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
55 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
56 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
57 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
58 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
59 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
60 | * |
61 | */ |
62 | |
63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: joy.c,v 1.20 2014/07/25 08:10:37 dholland Exp $" ); |
65 | |
66 | #include <sys/param.h> |
67 | #include <sys/systm.h> |
68 | #include <sys/kernel.h> |
69 | #include <sys/device.h> |
70 | #include <sys/errno.h> |
71 | #include <sys/conf.h> |
72 | #include <sys/event.h> |
73 | #include <sys/vnode.h> |
74 | #include <sys/bus.h> |
75 | #include <sys/joystick.h> |
76 | |
77 | #include <dev/ic/joyvar.h> |
78 | |
79 | /* |
80 | * The game port can manage 4 buttons and 4 variable resistors (usually 2 |
81 | * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201. |
82 | * Getting the state of the buttons is done by reading the game port; |
83 | * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2) |
84 | * to bits 0-3. If button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, |
85 | * 6, 7) is set to 0 to get the value of a resistor, write the value 0xff |
86 | * at port and wait until the corresponding bit returns to 0. |
87 | */ |
88 | |
89 | |
90 | #define JOYPART(d) (minor(d) & 1) |
91 | #define JOYUNIT(d) (minor(d) >> 1) |
92 | |
93 | #ifndef JOY_TIMEOUT |
94 | #define JOY_TIMEOUT 2000 /* 2 milliseconds */ |
95 | #endif |
96 | |
97 | extern struct cfdriver joy_cd; |
98 | |
99 | static dev_type_open(joyopen); |
100 | static dev_type_close(joyclose); |
101 | static dev_type_read(joyread); |
102 | static dev_type_ioctl(joyioctl); |
103 | |
104 | const struct cdevsw joy_cdevsw = { |
105 | .d_open = joyopen, |
106 | .d_close = joyclose, |
107 | .d_read = joyread, |
108 | .d_write = nowrite, |
109 | .d_ioctl = joyioctl, |
110 | .d_stop = nostop, |
111 | .d_tty = notty, |
112 | .d_poll = nopoll, |
113 | .d_mmap = nommap, |
114 | .d_kqfilter = nokqfilter, |
115 | .d_discard = nodiscard, |
116 | .d_flag = D_OTHER | D_MPSAFE |
117 | }; |
118 | |
119 | void |
120 | joyattach(struct joy_softc *sc) |
121 | { |
122 | |
123 | if (sc->sc_lock == NULL) { |
124 | panic("joyattach: no lock" ); |
125 | } |
126 | |
127 | sc->timeout[0] = 0; |
128 | sc->timeout[1] = 0; |
129 | |
130 | mutex_enter(sc->sc_lock); |
131 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0, 0xff); |
132 | DELAY(10000); /* 10 ms delay */ |
133 | aprint_normal_dev(sc->sc_dev, "joystick %sconnected\n" , |
134 | (bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0) & 0x0f) == 0x0f ? |
135 | "not " : "" ); |
136 | mutex_exit(sc->sc_lock); |
137 | } |
138 | |
139 | int |
140 | joydetach(struct joy_softc *sc, int flags) |
141 | { |
142 | int maj, mn; |
143 | |
144 | maj = cdevsw_lookup_major(&joy_cdevsw); |
145 | mn = device_unit(sc->sc_dev) << 1; |
146 | vdevgone(maj, mn, mn, VCHR); |
147 | vdevgone(maj, mn + 1, mn + 1, VCHR); |
148 | |
149 | return 0; |
150 | } |
151 | |
152 | static int |
153 | joyopen(dev_t dev, int flag, int mode, struct lwp *l) |
154 | { |
155 | int unit = JOYUNIT(dev); |
156 | int i = JOYPART(dev); |
157 | struct joy_softc *sc; |
158 | |
159 | sc = device_lookup_private(&joy_cd, unit); |
160 | if (sc == NULL) |
161 | return ENXIO; |
162 | |
163 | mutex_enter(sc->sc_lock); |
164 | if (sc->timeout[i]) { |
165 | mutex_exit(sc->sc_lock); |
166 | return EBUSY; |
167 | } |
168 | sc->x_off[i] = sc->y_off[i] = 0; |
169 | sc->timeout[i] = JOY_TIMEOUT; |
170 | mutex_exit(sc->sc_lock); |
171 | return 0; |
172 | } |
173 | |
174 | static int |
175 | joyclose(dev_t dev, int flag, int mode, struct lwp *l) |
176 | { |
177 | int unit = JOYUNIT(dev); |
178 | int i = JOYPART(dev); |
179 | struct joy_softc *sc = device_lookup_private(&joy_cd, unit); |
180 | |
181 | mutex_enter(sc->sc_lock); |
182 | sc->timeout[i] = 0; |
183 | mutex_exit(sc->sc_lock); |
184 | return 0; |
185 | } |
186 | |
187 | static int |
188 | joyread(dev_t dev, struct uio *uio, int flag) |
189 | { |
190 | int unit = JOYUNIT(dev); |
191 | struct joy_softc *sc = device_lookup_private(&joy_cd, unit); |
192 | bus_space_tag_t iot = sc->sc_iot; |
193 | bus_space_handle_t ioh = sc->sc_ioh; |
194 | struct joystick c; |
195 | struct timeval start, now, diff; |
196 | int state = 0, x = 0, y = 0, i; |
197 | |
198 | mutex_enter(sc->sc_lock); |
199 | bus_space_write_1(iot, ioh, 0, 0xff); |
200 | microtime(&start); |
201 | now = start; /* structure assignment */ |
202 | i = sc->timeout[JOYPART(dev)]; |
203 | for (;;) { |
204 | timersub(&now, &start, &diff); |
205 | if (diff.tv_sec > 0 || diff.tv_usec > i) |
206 | break; |
207 | state = bus_space_read_1(iot, ioh, 0); |
208 | if (JOYPART(dev) == 1) |
209 | state >>= 2; |
210 | if (!x && !(state & 0x01)) |
211 | x = diff.tv_usec; |
212 | if (!y && !(state & 0x02)) |
213 | y = diff.tv_usec; |
214 | if (x && y) |
215 | break; |
216 | microtime(&now); |
217 | } |
218 | mutex_exit(sc->sc_lock); |
219 | |
220 | c.x = x ? sc->x_off[JOYPART(dev)] + x : 0x80000000; |
221 | c.y = y ? sc->y_off[JOYPART(dev)] + y : 0x80000000; |
222 | state >>= 4; |
223 | c.b1 = ~state & 1; |
224 | c.b2 = ~(state >> 1) & 1; |
225 | return uiomove(&c, sizeof(struct joystick), uio); |
226 | } |
227 | |
228 | static int |
229 | joyioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) |
230 | { |
231 | int unit = JOYUNIT(dev); |
232 | struct joy_softc *sc = device_lookup_private(&joy_cd, unit); |
233 | int i = JOYPART(dev), x, error; |
234 | |
235 | mutex_enter(sc->sc_lock); |
236 | error = 0; |
237 | switch (cmd) { |
238 | case JOY_SETTIMEOUT: |
239 | x = *(int *)data; |
240 | if (x < 1 || x > 10000) { /* 10ms maximum! */ |
241 | error = EINVAL; |
242 | break; |
243 | } |
244 | sc->timeout[i] = x; |
245 | break; |
246 | case JOY_GETTIMEOUT: |
247 | *(int *)data = sc->timeout[i]; |
248 | break; |
249 | case JOY_SET_X_OFFSET: |
250 | sc->x_off[i] = *(int *)data; |
251 | break; |
252 | case JOY_SET_Y_OFFSET: |
253 | sc->y_off[i] = *(int *)data; |
254 | break; |
255 | case JOY_GET_X_OFFSET: |
256 | *(int *)data = sc->x_off[i]; |
257 | break; |
258 | case JOY_GET_Y_OFFSET: |
259 | *(int *)data = sc->y_off[i]; |
260 | break; |
261 | default: |
262 | error = ENXIO; |
263 | break; |
264 | } |
265 | mutex_exit(sc->sc_lock); |
266 | return error; |
267 | } |
268 | |