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