| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
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 | * $FreeBSD: src/sys/isa/joy.c,v 1.38.2.1 2001/09/01 05:55:31 murray Exp $ | |
| c8b4f0e6 | 29 | * $DragonFly: src/sys/dev/misc/joy/joy.c,v 1.12 2007/10/23 03:04:49 y0netan1 Exp $ |
| 984263bc MD |
30 | */ |
| 31 | ||
| 32 | #include <sys/param.h> | |
| 33 | #include <sys/systm.h> | |
| 34 | #include <sys/conf.h> | |
| fef8985e | 35 | #include <sys/device.h> |
| 984263bc MD |
36 | #include <sys/uio.h> |
| 37 | #include <sys/kernel.h> | |
| 38 | #include <sys/module.h> | |
| 39 | #include <sys/bus.h> | |
| 984263bc | 40 | #include <sys/rman.h> |
| 6434890e | 41 | #include <sys/thread2.h> |
| 984263bc MD |
42 | #include <sys/time.h> |
| 43 | #include <sys/joystick.h> | |
| 44 | ||
| 1f2de5d4 | 45 | #include <bus/isa/isavar.h> |
| 984263bc MD |
46 | #include "isa_if.h" |
| 47 | ||
| 48 | /* The game port can manage 4 buttons and 4 variable resistors (usually 2 | |
| 49 | * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201. | |
| 50 | * Getting the state of the buttons is done by reading the game port: | |
| 51 | * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2) | |
| 52 | * to bits 0-3. | |
| 53 | * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0 | |
| 54 | * to get the value of a resistor, write the value 0xff at port and | |
| 55 | * wait until the corresponding bit returns to 0. | |
| 56 | */ | |
| 57 | ||
| 58 | #define joypart(d) (minor(d)&1) | |
| 59 | #define UNIT(d) ((minor(d)>>1)&3) | |
| 60 | #ifndef JOY_TIMEOUT | |
| 61 | #define JOY_TIMEOUT 2000 /* 2 milliseconds */ | |
| 62 | #endif | |
| 63 | ||
| 64 | struct joy_softc { | |
| 65 | bus_space_tag_t bt; | |
| 66 | bus_space_handle_t port; | |
| 67 | int x_off[2], y_off[2]; | |
| 68 | int timeout[2]; | |
| 69 | }; | |
| 70 | ||
| 71 | #define JOY_SOFTC(unit) (struct joy_softc *) \ | |
| 72 | devclass_get_softc(joy_devclass,(unit)) | |
| 73 | ||
| 74 | static int joy_probe (device_t); | |
| 75 | static int joy_attach (device_t); | |
| 76 | ||
| 77 | #define CDEV_MAJOR 51 | |
| 78 | static d_open_t joyopen; | |
| 79 | static d_close_t joyclose; | |
| 80 | static d_read_t joyread; | |
| 81 | static d_ioctl_t joyioctl; | |
| 82 | ||
| fef8985e MD |
83 | static struct dev_ops joy_ops = { |
| 84 | { "joy", CDEV_MAJOR, 0 }, | |
| 85 | .d_open = joyopen, | |
| 86 | .d_close = joyclose, | |
| 87 | .d_read = joyread, | |
| 88 | .d_ioctl = joyioctl, | |
| 984263bc MD |
89 | }; |
| 90 | ||
| 91 | devclass_t joy_devclass; | |
| 92 | ||
| 93 | static struct isa_pnp_id joy_ids[] = { | |
| 94 | {0x0100630e, "CSC0001 PnP Joystick"}, /* CSC0001 */ | |
| 95 | {0x0101630e, "CSC0101 PnP Joystick"}, /* CSC0101 */ | |
| 96 | {0x01100002, "ALS0110 PnP Joystick"}, /* @P@1001 */ | |
| 97 | {0x01200002, "ALS0120 PnP Joystick"}, /* @P@2001 */ | |
| 98 | {0x01007316, "ESS0001 PnP Joystick"}, /* ESS0001 */ | |
| 99 | {0x2fb0d041, "Generic PnP Joystick"}, /* PNPb02f */ | |
| 100 | {0x2200a865, "YMH0022 PnP Joystick"}, /* YMH0022 */ | |
| 101 | {0x82719304, NULL}, /* ADS7182 */ | |
| 102 | {0} | |
| 103 | }; | |
| 104 | ||
| 105 | static int | |
| 106 | joy_probe (device_t dev) | |
| 107 | { | |
| 108 | if (ISA_PNP_PROBE(device_get_parent(dev), dev, joy_ids) == ENXIO) | |
| 109 | return ENXIO; | |
| 110 | #ifdef WANT_JOYSTICK_CONNECTED | |
| 111 | #ifdef notyet | |
| 112 | outb (dev->id_iobase, 0xff); | |
| 113 | DELAY (10000); /* 10 ms delay */ | |
| 114 | return (inb (dev->id_iobase) & 0x0f) != 0x0f; | |
| 115 | #endif | |
| 116 | #else | |
| 117 | return 0; | |
| 118 | #endif | |
| 119 | } | |
| 120 | ||
| 121 | static int | |
| 122 | joy_attach (device_t dev) | |
| 123 | { | |
| 124 | int unit = device_get_unit(dev); | |
| 125 | int rid = 0; | |
| 126 | struct resource *res; | |
| 127 | struct joy_softc *joy = device_get_softc(dev); | |
| 128 | ||
| 129 | res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); | |
| 130 | if (res == NULL) | |
| 131 | return ENXIO; | |
| 132 | joy->bt = rman_get_bustag(res); | |
| 133 | joy->port = rman_get_bushandle(res); | |
| 134 | joy->timeout[0] = joy->timeout[1] = 0; | |
| fef8985e | 135 | make_dev(&joy_ops, unit, 0, 0, 0600, "joy%d", unit); |
| 984263bc MD |
136 | return 0; |
| 137 | } | |
| 138 | ||
| 139 | static device_method_t joy_methods[] = { | |
| 140 | DEVMETHOD(device_probe, joy_probe), | |
| 141 | DEVMETHOD(device_attach, joy_attach), | |
| 142 | { 0, 0 } | |
| 143 | }; | |
| 144 | ||
| 145 | static driver_t joy_isa_driver = { | |
| 146 | "joy", | |
| 147 | joy_methods, | |
| 148 | sizeof (struct joy_softc) | |
| 149 | }; | |
| 150 | ||
| 151 | DRIVER_MODULE(joy, isa, joy_isa_driver, joy_devclass, 0, 0); | |
| c8b4f0e6 | 152 | DRIVER_MODULE(joy, acpi, joy_isa_driver, joy_devclass, 0, 0); |
| 984263bc MD |
153 | |
| 154 | static int | |
| fef8985e | 155 | joyopen(struct dev_open_args *ap) |
| 984263bc | 156 | { |
| b13267a5 | 157 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
158 | int i = joypart (dev); |
| 159 | struct joy_softc *joy = JOY_SOFTC(UNIT(dev)); | |
| 160 | ||
| 161 | if (joy->timeout[i]) | |
| 162 | return EBUSY; | |
| 163 | joy->x_off[i] = joy->y_off[i] = 0; | |
| 164 | joy->timeout[i] = JOY_TIMEOUT; | |
| 165 | return 0; | |
| 166 | } | |
| 167 | ||
| 168 | static int | |
| fef8985e | 169 | joyclose(struct dev_close_args *ap) |
| 984263bc | 170 | { |
| b13267a5 | 171 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
172 | int i = joypart (dev); |
| 173 | struct joy_softc *joy = JOY_SOFTC(UNIT(dev)); | |
| 174 | ||
| 175 | joy->timeout[i] = 0; | |
| 176 | return 0; | |
| 177 | } | |
| 178 | ||
| 179 | static int | |
| fef8985e | 180 | joyread(struct dev_read_args *ap) |
| 984263bc | 181 | { |
| b13267a5 | 182 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 183 | struct uio *uio = ap->a_uio; |
| 984263bc MD |
184 | struct joy_softc *joy = JOY_SOFTC(UNIT(dev)); |
| 185 | bus_space_handle_t port = joy->port; | |
| 186 | bus_space_tag_t bt = joy->bt; | |
| 187 | struct timespec t, start, end; | |
| 188 | int state = 0; | |
| 189 | struct timespec x, y; | |
| 190 | struct joystick c; | |
| 984263bc | 191 | |
| 6434890e JS |
192 | crit_enter(); |
| 193 | ||
| 984263bc MD |
194 | bus_space_write_1 (bt, port, 0, 0xff); |
| 195 | nanotime(&start); | |
| 196 | end.tv_sec = 0; | |
| 197 | end.tv_nsec = joy->timeout[joypart(dev)] * 1000; | |
| 198 | timespecadd(&end, &start); | |
| 199 | t = start; | |
| 200 | timespecclear(&x); | |
| 201 | timespecclear(&y); | |
| 202 | while (timespeccmp(&t, &end, <)) { | |
| 203 | state = bus_space_read_1 (bt, port, 0); | |
| 204 | if (joypart(dev) == 1) | |
| 205 | state >>= 2; | |
| 206 | nanotime(&t); | |
| 207 | if (!timespecisset(&x) && !(state & 0x01)) | |
| 208 | x = t; | |
| 209 | if (!timespecisset(&y) && !(state & 0x02)) | |
| 210 | y = t; | |
| 211 | if (timespecisset(&x) && timespecisset(&y)) | |
| 212 | break; | |
| 213 | } | |
| 6434890e JS |
214 | |
| 215 | crit_exit(); | |
| 216 | ||
| 984263bc MD |
217 | if (timespecisset(&x)) { |
| 218 | timespecsub(&x, &start); | |
| 219 | c.x = joy->x_off[joypart(dev)] + x.tv_nsec / 1000; | |
| 220 | } else | |
| 221 | c.x = 0x80000000; | |
| 222 | if (timespecisset(&y)) { | |
| 223 | timespecsub(&y, &start); | |
| 224 | c.y = joy->y_off[joypart(dev)] + y.tv_nsec / 1000; | |
| 225 | } else | |
| 226 | c.y = 0x80000000; | |
| 227 | state >>= 4; | |
| 228 | c.b1 = ~state & 1; | |
| 229 | c.b2 = ~(state >> 1) & 1; | |
| 230 | return uiomove ((caddr_t)&c, sizeof(struct joystick), uio); | |
| 231 | } | |
| 232 | ||
| 233 | static int | |
| fef8985e | 234 | joyioctl(struct dev_ioctl_args *ap) |
| 984263bc | 235 | { |
| b13267a5 | 236 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 237 | caddr_t data = ap->a_data; |
| 984263bc MD |
238 | struct joy_softc *joy = JOY_SOFTC(UNIT(dev)); |
| 239 | int i = joypart (dev); | |
| 240 | int x; | |
| 241 | ||
| fef8985e | 242 | switch (ap->a_cmd) { |
| 984263bc MD |
243 | case JOY_SETTIMEOUT: |
| 244 | x = *(int *) data; | |
| 245 | if (x < 1 || x > 10000) /* 10ms maximum! */ | |
| 246 | return EINVAL; | |
| 247 | joy->timeout[i] = x; | |
| 248 | break; | |
| 249 | case JOY_GETTIMEOUT: | |
| 250 | *(int *) data = joy->timeout[i]; | |
| 251 | break; | |
| 252 | case JOY_SET_X_OFFSET: | |
| 253 | joy->x_off[i] = *(int *) data; | |
| 254 | break; | |
| 255 | case JOY_SET_Y_OFFSET: | |
| 256 | joy->y_off[i] = *(int *) data; | |
| 257 | break; | |
| 258 | case JOY_GET_X_OFFSET: | |
| 259 | *(int *) data = joy->x_off[i]; | |
| 260 | break; | |
| 261 | case JOY_GET_Y_OFFSET: | |
| 262 | *(int *) data = joy->y_off[i]; | |
| 263 | break; | |
| 264 | default: | |
| 265 | return ENXIO; | |
| 266 | } | |
| 267 | return 0; | |
| 268 | } |