joy.c revision 24674
15897Sjmz/*- 25897Sjmz * Copyright (c) 1995 Jean-Marc Zucconi 35897Sjmz * All rights reserved. 45897Sjmz * 55897Sjmz * Redistribution and use in source and binary forms, with or without 65897Sjmz * modification, are permitted provided that the following conditions 75897Sjmz * are met: 85897Sjmz * 1. Redistributions of source code must retain the above copyright 95897Sjmz * notice, this list of conditions and the following disclaimer 105897Sjmz * in this position and unchanged. 115897Sjmz * 2. Redistributions in binary form must reproduce the above copyright 125897Sjmz * notice, this list of conditions and the following disclaimer in the 135897Sjmz * documentation and/or other materials provided with the distribution. 145897Sjmz * 3. The name of the author may not be used to endorse or promote products 155897Sjmz * derived from this software withough specific prior written permission 165897Sjmz * 175897Sjmz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 185897Sjmz * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 195897Sjmz * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 205897Sjmz * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 215897Sjmz * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 225897Sjmz * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235897Sjmz * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245897Sjmz * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255897Sjmz * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 265897Sjmz * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275897Sjmz * 285897Sjmz */ 295897Sjmz#include "joy.h" 305897Sjmz 315897Sjmz#if NJOY > 0 325897Sjmz 3318207Sbde#include <sys/errno.h> 347430Sbde#include <sys/param.h> 357430Sbde#include <sys/systm.h> 3612675Sjulian#include <sys/conf.h> 3712675Sjulian#include <sys/kernel.h> 3812675Sjulian#ifdef DEVFS 3912675Sjulian#include <sys/devfsext.h> 4012675Sjulian#endif /*DEVFS*/ 416734Sbde 4212854Sbde#include <machine/clock.h> 436734Sbde#include <machine/joystick.h> 446734Sbde 455897Sjmz#include <i386/isa/isa.h> 466734Sbde#include <i386/isa/isa_device.h> 475897Sjmz#include <i386/isa/timerreg.h> 485897Sjmz 498876Srgrimes/* The game port can manage 4 buttons and 4 variable resistors (usually 2 505897Sjmz * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201. 515897Sjmz * Getting the state of the buttons is done by reading the game port: 525897Sjmz * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2) 535897Sjmz * to bits 0-3. 545897Sjmz * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0 555897Sjmz * to get the value of a resistor, write the value 0xff at port and 565897Sjmz * wait until the corresponding bit returns to 0. 575897Sjmz */ 585897Sjmz 595897Sjmz 608876Srgrimes/* the formulae below only work if u is ``not too large''. See also 615993Sjmz * the discussion in microtime.s */ 625998Sjmz#define usec2ticks(u) (((u) * 19549)>>14) 635998Sjmz#define ticks2usec(u) (((u) * 3433)>>12) 645897Sjmz 655897Sjmz 665897Sjmz#define joypart(d) minor(d)&1 675897Sjmz#define UNIT(d) minor(d)>>1&3 685897Sjmz#ifndef JOY_TIMEOUT 695897Sjmz#define JOY_TIMEOUT 2000 /* 2 milliseconds */ 705897Sjmz#endif 715897Sjmz 725897Sjmzstatic struct { 735897Sjmz int port; 745897Sjmz int x_off[2], y_off[2]; 755897Sjmz int timeout[2]; 7612675Sjulian#ifdef DEVFS 7712675Sjulian void *devfs_token; 7812675Sjulian#endif 795897Sjmz} joy[NJOY]; 805897Sjmz 815897Sjmz 8212724Sphkstatic int joyprobe (struct isa_device *); 8312724Sphkstatic int joyattach (struct isa_device *); 845897Sjmz 855897Sjmzstruct isa_driver joydriver = {joyprobe, joyattach, "joy"}; 865897Sjmz 8712675Sjulian#define CDEV_MAJOR 51 8812675Sjulianstatic d_open_t joyopen; 8912675Sjulianstatic d_close_t joyclose; 9012675Sjulianstatic d_read_t joyread; 9112675Sjulianstatic d_ioctl_t joyioctl; 9212675Sjulian 9312678Sphkstatic struct cdevsw joy_cdevsw = 9412675Sjulian { joyopen, joyclose, joyread, nowrite, /*51*/ 9512675Sjulian joyioctl, nostop, nullreset, nodevtotty,/*joystick */ 9612675Sjulian seltrue, nommap, NULL, "joy", NULL, -1 }; 9712675Sjulian 9812854Sbdestatic int get_tick __P((void)); 995897Sjmz 1005897Sjmz 10112724Sphkstatic int 1025897Sjmzjoyprobe (struct isa_device *dev) 1035897Sjmz{ 1045897Sjmz#ifdef WANT_JOYSTICK_CONNECTED 1055897Sjmz outb (dev->id_iobase, 0xff); 1065897Sjmz DELAY (10000); /* 10 ms delay */ 1075897Sjmz return (inb (dev->id_iobase) & 0x0f) != 0x0f; 1085897Sjmz#else 1095897Sjmz return 1; 1105897Sjmz#endif 1115897Sjmz} 1125897Sjmz 11312724Sphkstatic int 1145897Sjmzjoyattach (struct isa_device *dev) 1155897Sjmz{ 11612675Sjulian int unit = dev->id_unit; 1175897Sjmz 11812675Sjulian joy[unit].port = dev->id_iobase; 11912675Sjulian joy[unit].timeout[0] = joy[unit].timeout[1] = 0; 12012675Sjulian printf("joy%d: joystick\n", unit); 12112675Sjulian#ifdef DEVFS 12214873Sscrappy joy[dev->id_unit].devfs_token = 12314873Sscrappy devfs_add_devswf(&joy_cdevsw, 0, DV_CHR, 0, 0, 12414873Sscrappy 0600, "joy%d", unit); 12512675Sjulian#endif 1265897Sjmz return 1; 1275897Sjmz} 1285897Sjmz 12912675Sjulianstatic int 13010644Sbdejoyopen (dev_t dev, int flags, int fmt, struct proc *p) 1315897Sjmz{ 1325897Sjmz int unit = UNIT (dev); 1335897Sjmz int i = joypart (dev); 1345897Sjmz 1355897Sjmz if (joy[unit].timeout[i]) 1365897Sjmz return EBUSY; 1375897Sjmz joy[unit].x_off[i] = joy[unit].y_off[i] = 0; 1385897Sjmz joy[unit].timeout[i] = JOY_TIMEOUT; 1395897Sjmz return 0; 1405897Sjmz} 14112675Sjulianstatic int 14210644Sbdejoyclose (dev_t dev, int flags, int fmt, struct proc *p) 1435897Sjmz{ 1445897Sjmz int unit = UNIT (dev); 1455897Sjmz int i = joypart (dev); 1465897Sjmz 1475897Sjmz joy[unit].timeout[i] = 0; 1485897Sjmz return 0; 1495897Sjmz} 1505897Sjmz 15112675Sjulianstatic int 1525897Sjmzjoyread (dev_t dev, struct uio *uio, int flag) 1535897Sjmz{ 1545897Sjmz int unit = UNIT(dev); 1555897Sjmz int port = joy[unit].port; 1565897Sjmz int i, t0, t1; 1575897Sjmz int state = 0, x = 0, y = 0; 1586644Sjmz struct joystick c; 1598876Srgrimes 1605897Sjmz disable_intr (); 1615897Sjmz outb (port, 0xff); 1625897Sjmz t0 = get_tick (); 1635897Sjmz t1 = t0; 1645897Sjmz i = usec2ticks(joy[unit].timeout[joypart(dev)]); 1655897Sjmz while (t0-t1 < i) { 1665897Sjmz state = inb (port); 1678876Srgrimes if (joypart(dev) == 1) 1685897Sjmz state >>= 2; 1695897Sjmz t1 = get_tick (); 1705897Sjmz if (t1 > t0) 1715993Sjmz t1 -= timer0_max_count; 1725897Sjmz if (!x && !(state & 0x01)) 1735897Sjmz x = t1; 1745897Sjmz if (!y && !(state & 0x02)) 1755897Sjmz y = t1; 1768876Srgrimes if (x && y) 1775897Sjmz break; 1785897Sjmz } 1795897Sjmz enable_intr (); 1806644Sjmz c.x = x ? joy[unit].x_off[joypart(dev)] + ticks2usec(t0-x) : 0x80000000; 1816644Sjmz c.y = y ? joy[unit].y_off[joypart(dev)] + ticks2usec(t0-y) : 0x80000000; 1825897Sjmz state >>= 4; 1836644Sjmz c.b1 = ~state & 1; 1846644Sjmz c.b2 = ~(state >> 1) & 1; 1857430Sbde return uiomove ((caddr_t)&c, sizeof(struct joystick), uio); 1865897Sjmz} 18712675Sjulian 18812675Sjulianstatic int 18912675Sjulianjoyioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 1905897Sjmz{ 1915897Sjmz int unit = UNIT (dev); 1925897Sjmz int i = joypart (dev); 1935897Sjmz int x; 1945897Sjmz 1955897Sjmz switch (cmd) { 1965897Sjmz case JOY_SETTIMEOUT: 1975897Sjmz x = *(int *) data; 1985897Sjmz if (x < 1 || x > 10000) /* 10ms maximum! */ 1995897Sjmz return EINVAL; 2005897Sjmz joy[unit].timeout[i] = x; 2015897Sjmz break; 2025897Sjmz case JOY_GETTIMEOUT: 2035897Sjmz *(int *) data = joy[unit].timeout[i]; 2045897Sjmz break; 2055897Sjmz case JOY_SET_X_OFFSET: 2065897Sjmz joy[unit].x_off[i] = *(int *) data; 2075897Sjmz break; 2085897Sjmz case JOY_SET_Y_OFFSET: 2095897Sjmz joy[unit].y_off[i] = *(int *) data; 2105897Sjmz break; 2115897Sjmz case JOY_GET_X_OFFSET: 2125897Sjmz *(int *) data = joy[unit].x_off[i]; 2135897Sjmz break; 2145897Sjmz case JOY_GET_Y_OFFSET: 2155897Sjmz *(int *) data = joy[unit].y_off[i]; 2165897Sjmz break; 2175897Sjmz default: 2185897Sjmz return ENXIO; 2195897Sjmz } 2205897Sjmz return 0; 2215897Sjmz} 22212675Sjulian 2235897Sjmzstatic int 2245897Sjmzget_tick () 2255897Sjmz{ 2265897Sjmz int low, high; 2275897Sjmz 2285897Sjmz outb (TIMER_MODE, TIMER_SEL0); 2295897Sjmz low = inb (TIMER_CNTR0); 2305897Sjmz high = inb (TIMER_CNTR0); 2315897Sjmz 2325897Sjmz return (high << 8) | low; 2335897Sjmz} 2345897Sjmz 23512502Sjulian 23612502Sjulianstatic joy_devsw_installed = 0; 23712502Sjulian 23812517Sjulianstatic void joy_drvinit(void *unused) 23912502Sjulian{ 24012517Sjulian dev_t dev; 24112517Sjulian 24212502Sjulian if( ! joy_devsw_installed ) { 24312517Sjulian dev = makedev(CDEV_MAJOR,0); 24412517Sjulian cdevsw_add(&dev,&joy_cdevsw,NULL); 24512502Sjulian joy_devsw_installed = 1; 24612517Sjulian } 24712502Sjulian} 24812517Sjulian 24912517SjulianSYSINIT(joydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,joy_drvinit,NULL) 25012517Sjulian 25114633Sjmz#ifdef JOY_MODULE 25214633Sjmz 25314633Sjmz#include <sys/exec.h> 25414633Sjmz#include <sys/sysent.h> 25514633Sjmz#include <sys/sysproto.h> 25614633Sjmz#include <sys/lkm.h> 25714633Sjmz 25814633SjmzMOD_DEV (joy, LM_DT_CHAR, CDEV_MAJOR, &joy_cdevsw); 25914633Sjmz 26014634Sjmzstatic struct isa_device dev = {0, &joydriver, IO_GAME, 0, -1, (caddr_t) 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; 26114633Sjmz 26224674Sdufaultstatic int 26314633Sjmzjoy_load (struct lkm_table *lkmtp, int cmd) 26414633Sjmz{ 26514633Sjmz if (joyprobe (&dev)) { 26614633Sjmz joyattach (&dev); 26714633Sjmz/* joy_drvinit (0);*/ 26814633Sjmz uprintf ("Joystick driver loaded\n"); 26914633Sjmz return 0; 27014633Sjmz } else { 27114633Sjmz uprintf ("Joystick driver: probe failed\n"); 27214633Sjmz return 1; 27314633Sjmz } 27414633Sjmz} 27514633Sjmz 27624674Sdufaultstatic int 27714633Sjmzjoy_unload (struct lkm_table *lkmtp, int cmd) 27814633Sjmz{ 27914633Sjmz uprintf ("Joystick driver unloaded\n"); 28014633Sjmz return 0; 28114633Sjmz} 28224674Sdufault 28324674Sdufaultstatic int 28414633Sjmzjoy_stat (struct lkm_table *lkmtp, int cmd) 28514633Sjmz{ 28614633Sjmz return 0; 28714633Sjmz} 28824674Sdufault 28914633Sjmzint 29014633Sjmzjoy_mod (struct lkm_table *lkmtp, int cmd, int ver) 29114633Sjmz{ 29224674Sdufault MOD_DISPATCH(joy, lkmtp, cmd, ver, 29324674Sdufault joy_load, joy_unload, joy_stat); 29414633Sjmz} 29514633Sjmz 29614633Sjmz#endif /* JOY_MODULE */ 29714633Sjmz 29814633Sjmz 2995897Sjmz#endif /* NJOY > 0 */ 300