1 /* $OpenBSD: joy.c,v 1.13 2007/08/01 13:18:18 martin Exp $ */ 2 /* $NetBSD: joy.c,v 1.3 1996/05/05 19:46:15 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 1995 Jean-Marc Zucconi 6 * All rights reserved. 7 * 8 * Ported to NetBSD by Matthieu Herrb <matthieu@laas.fr> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer 15 * in this position and unchanged. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/device.h> 39 #include <sys/errno.h> 40 41 #include <machine/cpu.h> 42 #include <machine/pio.h> 43 #include <machine/cpufunc.h> 44 #include <machine/joystick.h> 45 #include <machine/conf.h> 46 47 #include <dev/isa/isavar.h> 48 #include <dev/isa/isareg.h> 49 #include <dev/ic/i8253reg.h> 50 #include <i386/isa/joyreg.h> 51 52 static int joy_get_tick(void); 53 54 struct cfdriver joy_cd = { 55 NULL, "joy", DV_DULL 56 }; 57 58 int 59 joyopen(dev_t dev, int flag, int mode, struct proc *p) 60 { 61 int unit = JOYUNIT(dev); 62 int i = JOYPART(dev); 63 struct joy_softc *sc; 64 65 if (unit >= joy_cd.cd_ndevs) 66 return (ENXIO); 67 68 sc = joy_cd.cd_devs[unit]; 69 if (sc == NULL) 70 return (ENXIO); 71 72 if (sc->timeout[i]) 73 return EBUSY; 74 75 sc->x_off[i] = sc->y_off[i] = 0; 76 sc->timeout[i] = JOY_TIMEOUT; 77 return 0; 78 } 79 80 int 81 joyclose(dev_t dev, int flag, int mode, struct proc *p) 82 { 83 int unit = JOYUNIT(dev); 84 int i = JOYPART(dev); 85 struct joy_softc *sc = joy_cd.cd_devs[unit]; 86 87 sc->timeout[i] = 0; 88 return 0; 89 } 90 91 int 92 joyread(dev_t dev, struct uio *uio, int flag) 93 { 94 int unit = JOYUNIT(dev); 95 struct joy_softc *sc = joy_cd.cd_devs[unit]; 96 struct joystick c; 97 int port = sc->port; 98 int i, t0, t1; 99 int state = 0, x = 0, y = 0; 100 101 disable_intr(); 102 outb(port, 0xff); 103 t0 = joy_get_tick(); 104 t1 = t0; 105 i = USEC2TICKS(sc->timeout[JOYPART(dev)]); 106 while (t0 - t1 < i) { 107 state = inb(port); 108 if (JOYPART(dev) == 1) 109 state >>= 2; 110 t1 = joy_get_tick(); 111 if (t1 > t0) 112 t1 -= TIMER_FREQ / hz; 113 if (!x && !(state & 0x01)) 114 x = t1; 115 if (!y && !(state & 0x02)) 116 y = t1; 117 if (x && y) 118 break; 119 } 120 enable_intr(); 121 c.x = x ? sc->x_off[JOYPART(dev)] + TICKS2USEC(t0 - x) : 0x80000000; 122 c.y = y ? sc->y_off[JOYPART(dev)] + TICKS2USEC(t0 - y) : 0x80000000; 123 state >>= 4; 124 c.b1 = ~state & 1; 125 c.b2 = ~(state >> 1) & 1; 126 return uiomove((caddr_t) & c, sizeof(struct joystick), uio); 127 } 128 129 int 130 joyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 131 { 132 int unit = JOYUNIT(dev); 133 struct joy_softc *sc = joy_cd.cd_devs[unit]; 134 int i = JOYPART(dev); 135 int x; 136 137 switch (cmd) { 138 case JOY_SETTIMEOUT: 139 x = *(int *) data; 140 if (x < 1 || x > 10000) /* 10ms maximum! */ 141 return EINVAL; 142 sc->timeout[i] = x; 143 break; 144 case JOY_GETTIMEOUT: 145 *(int *) data = sc->timeout[i]; 146 break; 147 case JOY_SET_X_OFFSET: 148 sc->x_off[i] = *(int *) data; 149 break; 150 case JOY_SET_Y_OFFSET: 151 sc->y_off[i] = *(int *) data; 152 break; 153 case JOY_GET_X_OFFSET: 154 *(int *) data = sc->x_off[i]; 155 break; 156 case JOY_GET_Y_OFFSET: 157 *(int *) data = sc->y_off[i]; 158 break; 159 default: 160 return ENXIO; 161 } 162 return 0; 163 } 164 165 static int 166 joy_get_tick(void) 167 { 168 int low, high; 169 170 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0); 171 low = inb(IO_TIMER1 + TIMER_CNTR0); 172 high = inb(IO_TIMER1 + TIMER_CNTR0); 173 174 return (high << 8) | low; 175 } 176