joy.c revision 7430
1193323Sed/*-
2193323Sed * Copyright (c) 1995 Jean-Marc Zucconi
3193323Sed * All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions
7193323Sed * are met:
8193323Sed * 1. Redistributions of source code must retain the above copyright
9193323Sed *    notice, this list of conditions and the following disclaimer
10193323Sed *    in this position and unchanged.
11193323Sed * 2. Redistributions in binary form must reproduce the above copyright
12193323Sed *    notice, this list of conditions and the following disclaimer in the
13193323Sed *    documentation and/or other materials provided with the distribution.
14193323Sed * 3. The name of the author may not be used to endorse or promote products
15193323Sed *    derived from this software withough specific prior written permission
16193323Sed *
17193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18193323Sed * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19193323Sed * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20193323Sed * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21193323Sed * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22193323Sed * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23193323Sed * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24193323Sed * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25193323Sed * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26193323Sed * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27193323Sed *
28193323Sed */
29193323Sed#include "joy.h"
30193323Sed
31193323Sed#if NJOY > 0
32193323Sed
33193323Sed#include <errno.h>
34193323Sed
35193323Sed#include <sys/param.h>
36193323Sed#include <sys/systm.h>
37193323Sed
38193323Sed#include <machine/joystick.h>
39193323Sed
40193323Sed#include <i386/isa/isa.h>
41193323Sed#include <i386/isa/isa_device.h>
42193323Sed#include <i386/isa/timerreg.h>
43193323Sed
44193323Sed/* The game port can manage 4 buttons and 4 variable resistors (usually 2
45193323Sed * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201.
46193323Sed * Getting the state of the buttons is done by reading the game port:
47193323Sed * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2)
48193323Sed * to bits 0-3.
49193323Sed * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0
50193323Sed * to get the value of a resistor, write the value 0xff at port and
51193323Sed * wait until the corresponding bit returns to 0.
52193323Sed */
53193323Sed
54193323Sed
55193323Sed/* the formulae below only work if u is  ``not too large''. See also
56193323Sed * the discussion in microtime.s */
57193323Sed#define usec2ticks(u) 	(((u) * 19549)>>14)
58193323Sed#define ticks2usec(u) 	(((u) * 3433)>>12)
59193323Sed
60193323Sed
61193323Sed#define joypart(d) minor(d)&1
62193323Sed#define UNIT(d) minor(d)>>1&3
63193323Sed#ifndef JOY_TIMEOUT
64193323Sed#define JOY_TIMEOUT   2000 /* 2 milliseconds */
65193323Sed#endif
66193323Sed
67193323Sedstatic struct {
68193323Sed    int port;
69193323Sed    int x_off[2], y_off[2];
70193323Sed    int timeout[2];
71193323Sed} joy[NJOY];
72193323Sed
73193323Sed
74193323Sedextern int timer0_max_count;
75193323Sed
76193323Sedint joyprobe (struct isa_device *), joyattach (struct isa_device *);
77193323Sed
78193323Sedstruct isa_driver joydriver = {joyprobe, joyattach, "joy"};
79193323Sed
80193323Sedstatic int get_tick ();
81193323Sed
82193323Sed
83193323Sedint
84193323Sedjoyprobe (struct isa_device *dev)
85193323Sed{
86193323Sed#ifdef WANT_JOYSTICK_CONNECTED
87193323Sed    outb (dev->id_iobase, 0xff);
88193323Sed    DELAY (10000); /*  10 ms delay */
89193323Sed    return (inb (dev->id_iobase) & 0x0f) != 0x0f;
90193323Sed#else
91193323Sed    return 1;
92193323Sed#endif
93193323Sed}
94193323Sed
95193323Sedint
96193323Sedjoyattach (struct isa_device *dev)
97193323Sed{
98193323Sed    joy[dev->id_unit].port = dev->id_iobase;
99193323Sed    joy[dev->id_unit].timeout[0] = joy[dev->id_unit].timeout[1] = 0;
100193323Sed    printf("joy%d: joystick\n", dev->id_unit);
101193323Sed
102193323Sed    return 1;
103193323Sed}
104193323Sed
105193323Sedint
106193323Sedjoyopen (dev_t dev, int flag)
107193323Sed{
108193323Sed    int unit = UNIT (dev);
109193323Sed    int i = joypart (dev);
110193323Sed
111193323Sed    if (joy[unit].timeout[i])
112193323Sed	return EBUSY;
113193323Sed    joy[unit].x_off[i] = joy[unit].y_off[i] = 0;
114193323Sed    joy[unit].timeout[i] = JOY_TIMEOUT;
115193323Sed    return 0;
116193323Sed}
117193323Sedint
118193323Sedjoyclose (dev_t dev, int flag)
119193323Sed{
120193323Sed    int unit = UNIT (dev);
121193323Sed    int i = joypart (dev);
122193323Sed
123193323Sed    joy[unit].timeout[i] = 0;
124193323Sed    return 0;
125193323Sed}
126193323Sed
127193323Sedint
128193323Sedjoyread (dev_t dev, struct uio *uio, int flag)
129193323Sed{
130193323Sed    int unit = UNIT(dev);
131193323Sed    int port = joy[unit].port;
132193323Sed    int i, t0, t1;
133193323Sed    int state = 0, x = 0, y = 0;
134193323Sed    struct joystick c;
135193323Sed
136193323Sed    disable_intr ();
137193323Sed    outb (port, 0xff);
138193323Sed    t0 = get_tick ();
139193323Sed    t1 = t0;
140193323Sed    i = usec2ticks(joy[unit].timeout[joypart(dev)]);
141193323Sed    while (t0-t1 < i) {
142193323Sed	state = inb (port);
143193323Sed	if (joypart(dev) == 1)
144193323Sed	    state >>= 2;
145193323Sed	t1 = get_tick ();
146193323Sed	if (t1 > t0)
147193323Sed	    t1 -= timer0_max_count;
148193323Sed	if (!x && !(state & 0x01))
149193323Sed	    x = t1;
150193323Sed	if (!y && !(state & 0x02))
151193323Sed	    y =  t1;
152193323Sed	if (x && y)
153193323Sed	    break;
154193323Sed    }
155193323Sed    enable_intr ();
156193323Sed    c.x = x ? joy[unit].x_off[joypart(dev)] + ticks2usec(t0-x) : 0x80000000;
157193323Sed    c.y = y ? joy[unit].y_off[joypart(dev)] + ticks2usec(t0-y) : 0x80000000;
158193323Sed    state >>= 4;
159193323Sed    c.b1 = ~state & 1;
160193323Sed    c.b2 = ~(state >> 1) & 1;
161193323Sed    return uiomove ((caddr_t)&c, sizeof(struct joystick), uio);
162193323Sed}
163193323Sedint joyioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
164193323Sed{
165193323Sed    int unit = UNIT (dev);
166193323Sed    int i = joypart (dev);
167193323Sed    int x;
168193323Sed
169193323Sed    switch (cmd) {
170193323Sed    case JOY_SETTIMEOUT:
171193323Sed	x = *(int *) data;
172193323Sed	if (x < 1 || x > 10000) /* 10ms maximum! */
173193323Sed	    return EINVAL;
174193323Sed	joy[unit].timeout[i] = x;
175193323Sed	break;
176193323Sed    case JOY_GETTIMEOUT:
177193323Sed	*(int *) data = joy[unit].timeout[i];
178193323Sed	break;
179193323Sed    case JOY_SET_X_OFFSET:
180193323Sed	joy[unit].x_off[i] = *(int *) data;
181193323Sed	break;
182193323Sed    case JOY_SET_Y_OFFSET:
183193323Sed	joy[unit].y_off[i] = *(int *) data;
184193323Sed	break;
185193323Sed    case JOY_GET_X_OFFSET:
186193323Sed	*(int *) data = joy[unit].x_off[i];
187193323Sed	break;
188193323Sed    case JOY_GET_Y_OFFSET:
189193323Sed	*(int *) data = joy[unit].y_off[i];
190193323Sed	break;
191193323Sed    default:
192193323Sed	return ENXIO;
193193323Sed    }
194193323Sed    return 0;
195193323Sed}
196193323Sedstatic int
197193323Sedget_tick ()
198193323Sed{
199193323Sed    int low, high;
200193323Sed
201193323Sed    outb (TIMER_MODE, TIMER_SEL0);
202193323Sed    low = inb (TIMER_CNTR0);
203193323Sed    high = inb (TIMER_CNTR0);
204193323Sed
205193323Sed    return (high << 8) | low;
206193323Sed}
207193323Sed
208193323Sed#endif /* NJOY > 0 */
209193323Sed