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 <sys/errno.h>
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/kernel.h>
38 #ifdef DEVFS
39 #include <sys/devfsext.h>
40 #endif /*DEVFS*/
41
42 #include <machine/clock.h>
43 #include <machine/joystick.h>
44
45 #include <i386/isa/isa.h>
46 #include <i386/isa/isa_device.h>
47 #include <i386/isa/timerreg.h>
48
49 /* The game port can manage 4 buttons and 4 variable resistors (usually 2
50 * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201.
51 * Getting the state of the buttons is done by reading the game port:
52 * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2)
53 * to bits 0-3.
54 * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0
55 * to get the value of a resistor, write the value 0xff at port and
56 * wait until the corresponding bit returns to 0.
57 */
58
59
60 /* the formulae below only work if u is ``not too large''. See also
61 * the discussion in microtime.s */
62 #define usec2ticks(u) (((u) * 19549)>>14)
63 #define ticks2usec(u) (((u) * 3433)>>12)
64
65
66 #define joypart(d) minor(d)&1
67 #define UNIT(d) minor(d)>>1&3
68 #ifndef JOY_TIMEOUT
69 #define JOY_TIMEOUT 2000 /* 2 milliseconds */
70 #endif
71
72 static struct {
73 int port;
74 int x_off[2], y_off[2];
75 int timeout[2];
76 #ifdef DEVFS
77 void *devfs_token;
78 #endif
79 } joy[NJOY];
80
81
82 static int joyprobe (struct isa_device *);
83 static int joyattach (struct isa_device *);
84
85 struct isa_driver joydriver = {joyprobe, joyattach, "joy"};
86
87 #define CDEV_MAJOR 51
88 static d_open_t joyopen;
89 static d_close_t joyclose;
90 static d_read_t joyread;
91 static d_ioctl_t joyioctl;
92
93 static struct cdevsw joy_cdevsw =
94 { joyopen, joyclose, joyread, nowrite, /*51*/
95 joyioctl, nostop, nullreset, nodevtotty,/*joystick */
96 seltrue, nommap, NULL, "joy", NULL, -1 };
97
98 static int get_tick __P((void));
99
100
101 static int
102 joyprobe (struct isa_device *dev)
103 {
104 #ifdef WANT_JOYSTICK_CONNECTED
105 outb (dev->id_iobase, 0xff);
106 DELAY (10000); /* 10 ms delay */
107 return (inb (dev->id_iobase) & 0x0f) != 0x0f;
108 #else
109 return 1;
110 #endif
111 }
112
113 static int
114 joyattach (struct isa_device *dev)
115 {
116 int unit = dev->id_unit;
117
118 joy[unit].port = dev->id_iobase;
119 joy[unit].timeout[0] = joy[unit].timeout[1] = 0;
120 printf("joy%d: joystick\n", unit);
121 #ifdef DEVFS
122 joy[dev->id_unit].devfs_token =
123 devfs_add_devswf(&joy_cdevsw, 0, DV_CHR, 0, 0,
124 0600, "joy%d", unit);
125 #endif
126 return 1;
127 }
128
129 static int
130 joyopen (dev_t dev, int flags, int fmt, struct proc *p)
131 {
132 int unit = UNIT (dev);
133 int i = joypart (dev);
134
135 if (joy[unit].timeout[i])
136 return EBUSY;
137 joy[unit].x_off[i] = joy[unit].y_off[i] = 0;
138 joy[unit].timeout[i] = JOY_TIMEOUT;
139 return 0;
140 }
141 static int
142 joyclose (dev_t dev, int flags, int fmt, struct proc *p)
143 {
144 int unit = UNIT (dev);
145 int i = joypart (dev);
146
147 joy[unit].timeout[i] = 0;
148 return 0;
149 }
150
151 static int
152 joyread (dev_t dev, struct uio *uio, int flag)
153 {
154 int unit = UNIT(dev);
155 int port = joy[unit].port;
156 int i, t0, t1;
157 int state = 0, x = 0, y = 0;
158 struct joystick c;
159
160 disable_intr ();
161 outb (port, 0xff);
162 t0 = get_tick ();
163 t1 = t0;
164 i = usec2ticks(joy[unit].timeout[joypart(dev)]);
165 while (t0-t1 < i) {
166 state = inb (port);
167 if (joypart(dev) == 1)
168 state >>= 2;
169 t1 = get_tick ();
170 if (t1 > t0)
171 t1 -= timer0_max_count;
172 if (!x && !(state & 0x01))
173 x = t1;
174 if (!y && !(state & 0x02))
175 y = t1;
176 if (x && y)
177 break;
178 }
179 enable_intr ();
180 c.x = x ? joy[unit].x_off[joypart(dev)] + ticks2usec(t0-x) : 0x80000000;
181 c.y = y ? joy[unit].y_off[joypart(dev)] + ticks2usec(t0-y) : 0x80000000;
182 state >>= 4;
183 c.b1 = ~state & 1;
184 c.b2 = ~(state >> 1) & 1;
185 return uiomove ((caddr_t)&c, sizeof(struct joystick), uio);
186 }
187
188 static int
189 joyioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
190 {
191 int unit = UNIT (dev);
192 int i = joypart (dev);
193 int x;
194
195 switch (cmd) {
196 case JOY_SETTIMEOUT:
197 x = *(int *) data;
198 if (x < 1 || x > 10000) /* 10ms maximum! */
199 return EINVAL;
200 joy[unit].timeout[i] = x;
201 break;
202 case JOY_GETTIMEOUT:
203 *(int *) data = joy[unit].timeout[i];
204 break;
205 case JOY_SET_X_OFFSET:
206 joy[unit].x_off[i] = *(int *) data;
207 break;
208 case JOY_SET_Y_OFFSET:
209 joy[unit].y_off[i] = *(int *) data;
210 break;
211 case JOY_GET_X_OFFSET:
212 *(int *) data = joy[unit].x_off[i];
213 break;
214 case JOY_GET_Y_OFFSET:
215 *(int *) data = joy[unit].y_off[i];
216 break;
217 default:
218 return ENXIO;
219 }
220 return 0;
221 }
222
223 static int
224 get_tick ()
225 {
226 int low, high;
227
228 outb (TIMER_MODE, TIMER_SEL0);
229 low = inb (TIMER_CNTR0);
230 high = inb (TIMER_CNTR0);
231
232 return (high << 8) | low;
233 }
234
235
236 static joy_devsw_installed = 0;
237
238 static void joy_drvinit(void *unused)
239 {
240 dev_t dev;
241
242 if( ! joy_devsw_installed ) {
243 dev = makedev(CDEV_MAJOR,0);
244 cdevsw_add(&dev,&joy_cdevsw,NULL);
245 joy_devsw_installed = 1;
246 }
247 }
248
249 SYSINIT(joydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,joy_drvinit,NULL)
250
251 #ifdef JOY_MODULE
252
253 #include <sys/exec.h>
254 #include <sys/sysent.h>
255 #include <sys/sysproto.h>
256 #include <sys/lkm.h>
257
258 MOD_DEV (joy, LM_DT_CHAR, CDEV_MAJOR, &joy_cdevsw);
259
260 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};
261
262 int
263 joy_load (struct lkm_table *lkmtp, int cmd)
264 {
265 if (joyprobe (&dev)) {
266 joyattach (&dev);
267 /* joy_drvinit (0);*/
268 uprintf ("Joystick driver loaded\n");
269 return 0;
270 } else {
271 uprintf ("Joystick driver: probe failed\n");
272 return 1;
273 }
274 }
275
276 int
277 joy_unload (struct lkm_table *lkmtp, int cmd)
278 {
279 uprintf ("Joystick driver unloaded\n");
280 return 0;
281 }
282 int
283 joy_stat (struct lkm_table *lkmtp, int cmd)
284 {
285 return 0;
286 }
287 int
288 joy_mod (struct lkm_table *lkmtp, int cmd, int ver)
289 {
290 DISPATCH(lkmtp, cmd, ver, joy_load, joy_unload, joy_stat);
291 }
292
293 #endif /* JOY_MODULE */
294
295
296 #endif /* NJOY > 0 */
Cache object: a51a36f495e2d9a04d4c7a22aff5dd7f
|