joy.c revision 34924
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 3332726Seivind#include "opt_devfs.h" 3432726Seivind 357430Sbde#include <sys/param.h> 367430Sbde#include <sys/systm.h> 3712675Sjulian#include <sys/conf.h> 3812675Sjulian#include <sys/kernel.h> 3912675Sjulian#ifdef DEVFS 4012675Sjulian#include <sys/devfsext.h> 4112675Sjulian#endif /*DEVFS*/ 4234924Sbde#include <sys/uio.h> 436734Sbde 4412854Sbde#include <machine/clock.h> 456734Sbde#include <machine/joystick.h> 466734Sbde 475897Sjmz#include <i386/isa/isa.h> 486734Sbde#include <i386/isa/isa_device.h> 495897Sjmz#include <i386/isa/timerreg.h> 505897Sjmz 518876Srgrimes/* The game port can manage 4 buttons and 4 variable resistors (usually 2 525897Sjmz * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201. 535897Sjmz * Getting the state of the buttons is done by reading the game port: 545897Sjmz * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2) 555897Sjmz * to bits 0-3. 565897Sjmz * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0 575897Sjmz * to get the value of a resistor, write the value 0xff at port and 585897Sjmz * wait until the corresponding bit returns to 0. 595897Sjmz */ 605897Sjmz 615897Sjmz 628876Srgrimes/* the formulae below only work if u is ``not too large''. See also 635993Sjmz * the discussion in microtime.s */ 645998Sjmz#define usec2ticks(u) (((u) * 19549)>>14) 655998Sjmz#define ticks2usec(u) (((u) * 3433)>>12) 665897Sjmz 675897Sjmz 685897Sjmz#define joypart(d) minor(d)&1 695897Sjmz#define UNIT(d) minor(d)>>1&3 705897Sjmz#ifndef JOY_TIMEOUT 715897Sjmz#define JOY_TIMEOUT 2000 /* 2 milliseconds */ 725897Sjmz#endif 735897Sjmz 745897Sjmzstatic struct { 755897Sjmz int port; 765897Sjmz int x_off[2], y_off[2]; 775897Sjmz int timeout[2]; 7812675Sjulian#ifdef DEVFS 7912675Sjulian void *devfs_token; 8012675Sjulian#endif 815897Sjmz} joy[NJOY]; 825897Sjmz 835897Sjmz 8412724Sphkstatic int joyprobe (struct isa_device *); 8512724Sphkstatic int joyattach (struct isa_device *); 865897Sjmz 875897Sjmzstruct isa_driver joydriver = {joyprobe, joyattach, "joy"}; 885897Sjmz 8912675Sjulian#define CDEV_MAJOR 51 9012675Sjulianstatic d_open_t joyopen; 9112675Sjulianstatic d_close_t joyclose; 9212675Sjulianstatic d_read_t joyread; 9312675Sjulianstatic d_ioctl_t joyioctl; 9412675Sjulian 9512678Sphkstatic struct cdevsw joy_cdevsw = 9612675Sjulian { joyopen, joyclose, joyread, nowrite, /*51*/ 9712675Sjulian joyioctl, nostop, nullreset, nodevtotty,/*joystick */ 9812675Sjulian seltrue, nommap, NULL, "joy", NULL, -1 }; 9912675Sjulian 10012854Sbdestatic int get_tick __P((void)); 1015897Sjmz 1025897Sjmz 10312724Sphkstatic int 1045897Sjmzjoyprobe (struct isa_device *dev) 1055897Sjmz{ 1065897Sjmz#ifdef WANT_JOYSTICK_CONNECTED 1075897Sjmz outb (dev->id_iobase, 0xff); 1085897Sjmz DELAY (10000); /* 10 ms delay */ 1095897Sjmz return (inb (dev->id_iobase) & 0x0f) != 0x0f; 1105897Sjmz#else 1115897Sjmz return 1; 1125897Sjmz#endif 1135897Sjmz} 1145897Sjmz 11512724Sphkstatic int 1165897Sjmzjoyattach (struct isa_device *dev) 1175897Sjmz{ 11812675Sjulian int unit = dev->id_unit; 1195897Sjmz 12012675Sjulian joy[unit].port = dev->id_iobase; 12112675Sjulian joy[unit].timeout[0] = joy[unit].timeout[1] = 0; 12212675Sjulian printf("joy%d: joystick\n", unit); 12312675Sjulian#ifdef DEVFS 12414873Sscrappy joy[dev->id_unit].devfs_token = 12514873Sscrappy devfs_add_devswf(&joy_cdevsw, 0, DV_CHR, 0, 0, 12614873Sscrappy 0600, "joy%d", unit); 12712675Sjulian#endif 1285897Sjmz return 1; 1295897Sjmz} 1305897Sjmz 13112675Sjulianstatic int 13210644Sbdejoyopen (dev_t dev, int flags, int fmt, struct proc *p) 1335897Sjmz{ 1345897Sjmz int unit = UNIT (dev); 1355897Sjmz int i = joypart (dev); 1365897Sjmz 1375897Sjmz if (joy[unit].timeout[i]) 1385897Sjmz return EBUSY; 1395897Sjmz joy[unit].x_off[i] = joy[unit].y_off[i] = 0; 1405897Sjmz joy[unit].timeout[i] = JOY_TIMEOUT; 1415897Sjmz return 0; 1425897Sjmz} 14312675Sjulianstatic int 14410644Sbdejoyclose (dev_t dev, int flags, int fmt, struct proc *p) 1455897Sjmz{ 1465897Sjmz int unit = UNIT (dev); 1475897Sjmz int i = joypart (dev); 1485897Sjmz 1495897Sjmz joy[unit].timeout[i] = 0; 1505897Sjmz return 0; 1515897Sjmz} 1525897Sjmz 15312675Sjulianstatic int 1545897Sjmzjoyread (dev_t dev, struct uio *uio, int flag) 1555897Sjmz{ 1565897Sjmz int unit = UNIT(dev); 1575897Sjmz int port = joy[unit].port; 1585897Sjmz int i, t0, t1; 1595897Sjmz int state = 0, x = 0, y = 0; 1606644Sjmz struct joystick c; 1618876Srgrimes 1625897Sjmz disable_intr (); 1635897Sjmz outb (port, 0xff); 1645897Sjmz t0 = get_tick (); 1655897Sjmz t1 = t0; 1665897Sjmz i = usec2ticks(joy[unit].timeout[joypart(dev)]); 1675897Sjmz while (t0-t1 < i) { 1685897Sjmz state = inb (port); 1698876Srgrimes if (joypart(dev) == 1) 1705897Sjmz state >>= 2; 1715897Sjmz t1 = get_tick (); 1725897Sjmz if (t1 > t0) 1735993Sjmz t1 -= timer0_max_count; 1745897Sjmz if (!x && !(state & 0x01)) 1755897Sjmz x = t1; 1765897Sjmz if (!y && !(state & 0x02)) 1775897Sjmz y = t1; 1788876Srgrimes if (x && y) 1795897Sjmz break; 1805897Sjmz } 1815897Sjmz enable_intr (); 1826644Sjmz c.x = x ? joy[unit].x_off[joypart(dev)] + ticks2usec(t0-x) : 0x80000000; 1836644Sjmz c.y = y ? joy[unit].y_off[joypart(dev)] + ticks2usec(t0-y) : 0x80000000; 1845897Sjmz state >>= 4; 1856644Sjmz c.b1 = ~state & 1; 1866644Sjmz c.b2 = ~(state >> 1) & 1; 1877430Sbde return uiomove ((caddr_t)&c, sizeof(struct joystick), uio); 1885897Sjmz} 18912675Sjulian 19012675Sjulianstatic int 19112675Sjulianjoyioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 1925897Sjmz{ 1935897Sjmz int unit = UNIT (dev); 1945897Sjmz int i = joypart (dev); 1955897Sjmz int x; 1965897Sjmz 1975897Sjmz switch (cmd) { 1985897Sjmz case JOY_SETTIMEOUT: 1995897Sjmz x = *(int *) data; 2005897Sjmz if (x < 1 || x > 10000) /* 10ms maximum! */ 2015897Sjmz return EINVAL; 2025897Sjmz joy[unit].timeout[i] = x; 2035897Sjmz break; 2045897Sjmz case JOY_GETTIMEOUT: 2055897Sjmz *(int *) data = joy[unit].timeout[i]; 2065897Sjmz break; 2075897Sjmz case JOY_SET_X_OFFSET: 2085897Sjmz joy[unit].x_off[i] = *(int *) data; 2095897Sjmz break; 2105897Sjmz case JOY_SET_Y_OFFSET: 2115897Sjmz joy[unit].y_off[i] = *(int *) data; 2125897Sjmz break; 2135897Sjmz case JOY_GET_X_OFFSET: 2145897Sjmz *(int *) data = joy[unit].x_off[i]; 2155897Sjmz break; 2165897Sjmz case JOY_GET_Y_OFFSET: 2175897Sjmz *(int *) data = joy[unit].y_off[i]; 2185897Sjmz break; 2195897Sjmz default: 2205897Sjmz return ENXIO; 2215897Sjmz } 2225897Sjmz return 0; 2235897Sjmz} 22412675Sjulian 2255897Sjmzstatic int 2265897Sjmzget_tick () 2275897Sjmz{ 2285897Sjmz int low, high; 2295897Sjmz 2305897Sjmz outb (TIMER_MODE, TIMER_SEL0); 2315897Sjmz low = inb (TIMER_CNTR0); 2325897Sjmz high = inb (TIMER_CNTR0); 2335897Sjmz 2345897Sjmz return (high << 8) | low; 2355897Sjmz} 2365897Sjmz 23712502Sjulian 23812502Sjulianstatic joy_devsw_installed = 0; 23912502Sjulian 24012517Sjulianstatic void joy_drvinit(void *unused) 24112502Sjulian{ 24212517Sjulian dev_t dev; 24312517Sjulian 24412502Sjulian if( ! joy_devsw_installed ) { 24512517Sjulian dev = makedev(CDEV_MAJOR,0); 24612517Sjulian cdevsw_add(&dev,&joy_cdevsw,NULL); 24712502Sjulian joy_devsw_installed = 1; 24812517Sjulian } 24912502Sjulian} 25012517Sjulian 25112517SjulianSYSINIT(joydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,joy_drvinit,NULL) 25212517Sjulian 25314633Sjmz#ifdef JOY_MODULE 25414633Sjmz 25514633Sjmz#include <sys/exec.h> 25614633Sjmz#include <sys/sysent.h> 25714633Sjmz#include <sys/lkm.h> 25814633Sjmz 25914633SjmzMOD_DEV (joy, LM_DT_CHAR, CDEV_MAJOR, &joy_cdevsw); 26014633Sjmz 26114634Sjmzstatic struct isa_device dev = {0, &joydriver, IO_GAME, 0, -1, (caddr_t) 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; 26214633Sjmz 26324674Sdufaultstatic int 26414633Sjmzjoy_load (struct lkm_table *lkmtp, int cmd) 26514633Sjmz{ 26614633Sjmz if (joyprobe (&dev)) { 26714633Sjmz joyattach (&dev); 26814633Sjmz/* joy_drvinit (0);*/ 26914633Sjmz uprintf ("Joystick driver loaded\n"); 27014633Sjmz return 0; 27114633Sjmz } else { 27214633Sjmz uprintf ("Joystick driver: probe failed\n"); 27314633Sjmz return 1; 27414633Sjmz } 27514633Sjmz} 27614633Sjmz 27724674Sdufaultstatic int 27814633Sjmzjoy_unload (struct lkm_table *lkmtp, int cmd) 27914633Sjmz{ 28014633Sjmz uprintf ("Joystick driver unloaded\n"); 28114633Sjmz return 0; 28214633Sjmz} 28324674Sdufault 28424674Sdufaultstatic int 28514633Sjmzjoy_stat (struct lkm_table *lkmtp, int cmd) 28614633Sjmz{ 28714633Sjmz return 0; 28814633Sjmz} 28924674Sdufault 29014633Sjmzint 29114633Sjmzjoy_mod (struct lkm_table *lkmtp, int cmd, int ver) 29214633Sjmz{ 29324674Sdufault MOD_DISPATCH(joy, lkmtp, cmd, ver, 29424674Sdufault joy_load, joy_unload, joy_stat); 29514633Sjmz} 29614633Sjmz 29714633Sjmz#endif /* JOY_MODULE */ 29814633Sjmz 29914633Sjmz 3005897Sjmz#endif /* NJOY > 0 */ 301