joy.c revision 12502
150477Speter/*-
22258Scsgr * Copyright (c) 1995 Jean-Marc Zucconi
32258Scsgr * All rights reserved.
42258Scsgr *
52258Scsgr * Redistribution and use in source and binary forms, with or without
62258Scsgr * modification, are permitted provided that the following conditions
72258Scsgr * are met:
82258Scsgr * 1. Redistributions of source code must retain the above copyright
92307Scsgr *    notice, this list of conditions and the following disclaimer
102258Scsgr *    in this position and unchanged.
112258Scsgr * 2. Redistributions in binary form must reproduce the above copyright
122258Scsgr *    notice, this list of conditions and the following disclaimer in the
1313343Speter *    documentation and/or other materials provided with the distribution.
1413343Speter * 3. The name of the author may not be used to endorse or promote products
1513343Speter *    derived from this software withough specific prior written permission
162258Scsgr *
17250881Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18250881Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19250881Sjkim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20250881Sjkim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21250881Sjkim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22250881Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23250881Sjkim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24250881Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252258Scsgr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26250881Sjkim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2796462Sru *
28132862Skan */
2913343Speter#include "joy.h"
3013343Speter
3113343Speter#if NJOY > 0
322258Scsgr
33250881Sjkim#include <errno.h>
34201386Sed
3553462Sdt#include <sys/param.h>
36250881Sjkim#include <sys/systm.h>
372258Scsgr
382258Scsgr#include <machine/joystick.h>
392258Scsgr
40250881Sjkim#include <i386/isa/isa.h>
4153462Sdt#include <i386/isa/isa_device.h>
42250881Sjkim#include <i386/isa/timerreg.h>
43250881Sjkim
44250881Sjkim#ifdef JREMOD
45250881Sjkim#include <sys/conf.h>
46250881Sjkim#define CDEV_MAJOR 51
47250881Sjkimstatic void 	joy_devsw_install();
48250881Sjkim#endif /*JREMOD*/
49250881Sjkim
50250881Sjkim/* The game port can manage 4 buttons and 4 variable resistors (usually 2
51250881Sjkim * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201.
52250881Sjkim * Getting the state of the buttons is done by reading the game port:
53250881Sjkim * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2)
54250881Sjkim * to bits 0-3.
5518372Speter * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0
56250881Sjkim * to get the value of a resistor, write the value 0xff at port and
572258Scsgr * wait until the corresponding bit returns to 0.
582258Scsgr */
59250881Sjkim
60250881Sjkim
61250881Sjkim/* the formulae below only work if u is  ``not too large''. See also
622258Scsgr * the discussion in microtime.s */
632258Scsgr#define usec2ticks(u) 	(((u) * 19549)>>14)
642258Scsgr#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} joy[NJOY];
78
79
80extern int timer0_max_count;
81
82int joyprobe (struct isa_device *), joyattach (struct isa_device *);
83
84struct isa_driver joydriver = {joyprobe, joyattach, "joy"};
85
86static int get_tick ();
87
88
89int
90joyprobe (struct isa_device *dev)
91{
92#ifdef WANT_JOYSTICK_CONNECTED
93    outb (dev->id_iobase, 0xff);
94    DELAY (10000); /*  10 ms delay */
95    return (inb (dev->id_iobase) & 0x0f) != 0x0f;
96#else
97    return 1;
98#endif
99}
100
101int
102joyattach (struct isa_device *dev)
103{
104    joy[dev->id_unit].port = dev->id_iobase;
105    joy[dev->id_unit].timeout[0] = joy[dev->id_unit].timeout[1] = 0;
106    printf("joy%d: joystick\n", dev->id_unit);
107
108#ifdef JREMOD
109    joy_devsw_install();
110#endif /*JREMOD*/
111
112    return 1;
113}
114
115int
116joyopen (dev_t dev, int flags, int fmt, struct proc *p)
117{
118    int unit = UNIT (dev);
119    int i = joypart (dev);
120
121    if (joy[unit].timeout[i])
122	return EBUSY;
123    joy[unit].x_off[i] = joy[unit].y_off[i] = 0;
124    joy[unit].timeout[i] = JOY_TIMEOUT;
125    return 0;
126}
127int
128joyclose (dev_t dev, int flags, int fmt, struct proc *p)
129{
130    int unit = UNIT (dev);
131    int i = joypart (dev);
132
133    joy[unit].timeout[i] = 0;
134    return 0;
135}
136
137int
138joyread (dev_t dev, struct uio *uio, int flag)
139{
140    int unit = UNIT(dev);
141    int port = joy[unit].port;
142    int i, t0, t1;
143    int state = 0, x = 0, y = 0;
144    struct joystick c;
145
146    disable_intr ();
147    outb (port, 0xff);
148    t0 = get_tick ();
149    t1 = t0;
150    i = usec2ticks(joy[unit].timeout[joypart(dev)]);
151    while (t0-t1 < i) {
152	state = inb (port);
153	if (joypart(dev) == 1)
154	    state >>= 2;
155	t1 = get_tick ();
156	if (t1 > t0)
157	    t1 -= timer0_max_count;
158	if (!x && !(state & 0x01))
159	    x = t1;
160	if (!y && !(state & 0x02))
161	    y =  t1;
162	if (x && y)
163	    break;
164    }
165    enable_intr ();
166    c.x = x ? joy[unit].x_off[joypart(dev)] + ticks2usec(t0-x) : 0x80000000;
167    c.y = y ? joy[unit].y_off[joypart(dev)] + ticks2usec(t0-y) : 0x80000000;
168    state >>= 4;
169    c.b1 = ~state & 1;
170    c.b2 = ~(state >> 1) & 1;
171    return uiomove ((caddr_t)&c, sizeof(struct joystick), uio);
172}
173int joyioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
174{
175    int unit = UNIT (dev);
176    int i = joypart (dev);
177    int x;
178
179    switch (cmd) {
180    case JOY_SETTIMEOUT:
181	x = *(int *) data;
182	if (x < 1 || x > 10000) /* 10ms maximum! */
183	    return EINVAL;
184	joy[unit].timeout[i] = x;
185	break;
186    case JOY_GETTIMEOUT:
187	*(int *) data = joy[unit].timeout[i];
188	break;
189    case JOY_SET_X_OFFSET:
190	joy[unit].x_off[i] = *(int *) data;
191	break;
192    case JOY_SET_Y_OFFSET:
193	joy[unit].y_off[i] = *(int *) data;
194	break;
195    case JOY_GET_X_OFFSET:
196	*(int *) data = joy[unit].x_off[i];
197	break;
198    case JOY_GET_Y_OFFSET:
199	*(int *) data = joy[unit].y_off[i];
200	break;
201    default:
202	return ENXIO;
203    }
204    return 0;
205}
206static int
207get_tick ()
208{
209    int low, high;
210
211    outb (TIMER_MODE, TIMER_SEL0);
212    low = inb (TIMER_CNTR0);
213    high = inb (TIMER_CNTR0);
214
215    return (high << 8) | low;
216}
217
218
219#ifdef JREMOD
220struct cdevsw joy_cdevsw =
221	{ joyopen,	joyclose,	joyread,	nowrite,	/*51*/
222	  joyioctl,	nostop,		nullreset,	nodevtotty,/*joystick */
223	  seltrue,	nommap,		NULL};
224
225static joy_devsw_installed = 0;
226
227static void 	joy_devsw_install()
228{
229	dev_t descript;
230	if( ! joy_devsw_installed ) {
231		descript = makedev(CDEV_MAJOR,0);
232		cdevsw_add(&descript,&joy_cdevsw,NULL);
233#if defined(BDEV_MAJOR)
234		descript = makedev(BDEV_MAJOR,0);
235		bdevsw_add(&descript,&joy_bdevsw,NULL);
236#endif /*BDEV_MAJOR*/
237		joy_devsw_installed = 1;
238	}
239}
240#endif /* JREMOD */
241#endif /* NJOY > 0 */
242