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