FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/joy.c
1 /*-
2 * Copyright (c) 1995 Jean-Marc Zucconi
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29 #include "joy.h"
30
31 #if NJOY > 0
32
33 #include "opt_devfs.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/kernel.h>
39 #ifdef DEVFS
40 #include <sys/devfsext.h>
41 #endif /*DEVFS*/
42 #include <sys/uio.h>
43
44 #include <machine/clock.h>
45 #include <machine/joystick.h>
46
47 #include <i386/isa/isa.h>
48 #include <i386/isa/isa_device.h>
49 #include <i386/isa/timerreg.h>
50
51 /* The game port can manage 4 buttons and 4 variable resistors (usually 2
52 * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201.
53 * Getting the state of the buttons is done by reading the game port:
54 * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2)
55 * to bits 0-3.
56 * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0
57 * to get the value of a resistor, write the value 0xff at port and
58 * wait until the corresponding bit returns to 0.
59 */
60
61
62 /* the formulae below only work if u is ``not too large''. See also
63 * the discussion in microtime.s */
64 #define usec2ticks(u) (((u) * 19549)>>14)
65 #define ticks2usec(u) (((u) * 3433)>>12)
66
67
68 #define joypart(d) minor(d)&1
69 #define UNIT(d) minor(d)>>1&3
70 #ifndef JOY_TIMEOUT
71 #define JOY_TIMEOUT 2000 /* 2 milliseconds */
72 #endif
73
74 static struct {
75 int port;
76 int x_off[2], y_off[2];
77 int timeout[2];
78 #ifdef DEVFS
79 void *devfs_token;
80 #endif
81 } joy[NJOY];
82
83
84 static int joyprobe (struct isa_device *);
85 static int joyattach (struct isa_device *);
86
87 struct isa_driver joydriver = {joyprobe, joyattach, "joy"};
88
89 #define CDEV_MAJOR 51
90 static d_open_t joyopen;
91 static d_close_t joyclose;
92 static d_read_t joyread;
93 static d_ioctl_t joyioctl;
94
95 static struct cdevsw joy_cdevsw =
96 { joyopen, joyclose, joyread, nowrite, /*51*/
97 joyioctl, nostop, nullreset, nodevtotty,/*joystick */
98 seltrue, nommap, NULL, "joy", NULL, -1 };
99
100 static int get_tick __P((void));
101
102
103 static int
104 joyprobe (struct isa_device *dev)
105 {
106 #ifdef WANT_JOYSTICK_CONNECTED
107 outb (dev->id_iobase, 0xff);
108 DELAY (10000); /* 10 ms delay */
109 return (inb (dev->id_iobase) & 0x0f) != 0x0f;
110 #else
111 return 1;
112 #endif
113 }
114
115 static int
116 joyattach (struct isa_device *dev)
117 {
118 int unit = dev->id_unit;
119
120 joy[unit].port = dev->id_iobase;
121 joy[unit].timeout[0] = joy[unit].timeout[1] = 0;
122 printf("joy%d: joystick\n", unit);
123 #ifdef DEVFS
124 joy[dev->id_unit].devfs_token =
125 devfs_add_devswf(&joy_cdevsw, 0, DV_CHR, 0, 0,
126 0600, "joy%d", unit);
127 #endif
128 return 1;
129 }
130
131 static int
132 joyopen (dev_t dev, int flags, int fmt, struct proc *p)
133 {
134 int unit = UNIT (dev);
135 int i = joypart (dev);
136
137 if (joy[unit].timeout[i])
138 return EBUSY;
139 joy[unit].x_off[i] = joy[unit].y_off[i] = 0;
140 joy[unit].timeout[i] = JOY_TIMEOUT;
141 return 0;
142 }
143 static int
144 joyclose (dev_t dev, int flags, int fmt, struct proc *p)
145 {
146 int unit = UNIT (dev);
147 int i = joypart (dev);
148
149 joy[unit].timeout[i] = 0;
150 return 0;
151 }
152
153 static int
154 joyread (dev_t dev, struct uio *uio, int flag)
155 {
156 int unit = UNIT(dev);
157 int port = joy[unit].port;
158 int i, t0, t1;
159 int state = 0, x = 0, y = 0;
160 struct joystick c;
161
162 disable_intr ();
163 outb (port, 0xff);
164 t0 = get_tick ();
165 t1 = t0;
166 i = usec2ticks(joy[unit].timeout[joypart(dev)]);
167 while (t0-t1 < i) {
168 state = inb (port);
169 if (joypart(dev) == 1)
170 state >>= 2;
171 t1 = get_tick ();
172 if (t1 > t0)
173 t1 -= timer0_max_count;
174 if (!x && !(state & 0x01))
175 x = t1;
176 if (!y && !(state & 0x02))
177 y = t1;
178 if (x && y)
179 break;
180 }
181 enable_intr ();
182 c.x = x ? joy[unit].x_off[joypart(dev)] + ticks2usec(t0-x) : 0x80000000;
183 c.y = y ? joy[unit].y_off[joypart(dev)] + ticks2usec(t0-y) : 0x80000000;
184 state >>= 4;
185 c.b1 = ~state & 1;
186 c.b2 = ~(state >> 1) & 1;
187 return uiomove ((caddr_t)&c, sizeof(struct joystick), uio);
188 }
189
190 static int
191 joyioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
192 {
193 int unit = UNIT (dev);
194 int i = joypart (dev);
195 int x;
196
197 switch (cmd) {
198 case JOY_SETTIMEOUT:
199 x = *(int *) data;
200 if (x < 1 || x > 10000) /* 10ms maximum! */
201 return EINVAL;
202 joy[unit].timeout[i] = x;
203 break;
204 case JOY_GETTIMEOUT:
205 *(int *) data = joy[unit].timeout[i];
206 break;
207 case JOY_SET_X_OFFSET:
208 joy[unit].x_off[i] = *(int *) data;
209 break;
210 case JOY_SET_Y_OFFSET:
211 joy[unit].y_off[i] = *(int *) data;
212 break;
213 case JOY_GET_X_OFFSET:
214 *(int *) data = joy[unit].x_off[i];
215 break;
216 case JOY_GET_Y_OFFSET:
217 *(int *) data = joy[unit].y_off[i];
218 break;
219 default:
220 return ENXIO;
221 }
222 return 0;
223 }
224
225 static int
226 get_tick ()
227 {
228 int low, high;
229
230 outb (TIMER_MODE, TIMER_SEL0);
231 low = inb (TIMER_CNTR0);
232 high = inb (TIMER_CNTR0);
233
234 return (high << 8) | low;
235 }
236
237
238 static joy_devsw_installed = 0;
239
240 static void joy_drvinit(void *unused)
241 {
242 dev_t dev;
243
244 if( ! joy_devsw_installed ) {
245 dev = makedev(CDEV_MAJOR,0);
246 cdevsw_add(&dev,&joy_cdevsw,NULL);
247 joy_devsw_installed = 1;
248 }
249 }
250
251 SYSINIT(joydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,joy_drvinit,NULL)
252
253 #ifdef JOY_MODULE
254
255 #include <sys/exec.h>
256 #include <sys/sysent.h>
257 #include <sys/lkm.h>
258
259 MOD_DEV (joy, LM_DT_CHAR, CDEV_MAJOR, &joy_cdevsw);
260
261 static struct isa_device dev = {0, &joydriver, IO_GAME, 0, -1, (caddr_t) 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0};
262
263 static int
264 joy_load (struct lkm_table *lkmtp, int cmd)
265 {
266 if (joyprobe (&dev)) {
267 joyattach (&dev);
268 /* joy_drvinit (0);*/
269 uprintf ("Joystick driver loaded\n");
270 return 0;
271 } else {
272 uprintf ("Joystick driver: probe failed\n");
273 return 1;
274 }
275 }
276
277 static int
278 joy_unload (struct lkm_table *lkmtp, int cmd)
279 {
280 uprintf ("Joystick driver unloaded\n");
281 return 0;
282 }
283
284 static int
285 joy_stat (struct lkm_table *lkmtp, int cmd)
286 {
287 return 0;
288 }
289
290 int
291 joy_mod (struct lkm_table *lkmtp, int cmd, int ver)
292 {
293 MOD_DISPATCH(joy, lkmtp, cmd, ver,
294 joy_load, joy_unload, joy_stat);
295 }
296
297 #endif /* JOY_MODULE */
298
299
300 #endif /* NJOY > 0 */
Cache object: d488d13e3bbe1f0ef3dcdc6ef386faa8
|