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