analog.c revision 4e57b6817880946a3a78d5d8cad1ace363f7e449
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * $Id: analog.c,v 1.68 2002/01/22 20:18:32 vojtech Exp $ 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1996-2001 Vojtech Pavlik 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Analog joystick and gamepad driver for Linux 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should you need to contact me, the author, you can do so either by 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/input.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/gameport.h> 414e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/jiffies.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/timex.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Analog joystick and gamepad driver" 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Option parsing. 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_PORTS 16 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *js[ANALOG_PORTS]; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int js_nargs; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int analog_options[ANALOG_PORTS]; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array_named(map, js, charp, &js_nargs, 0); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities"); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__obsolete_setup("js="); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Times, feature definitions. 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_RUDDER 0x00004 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_THROTTLE 0x00008 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_AXES_STD 0x0000f 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTNS_STD 0x000f0 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTNS_CHF 0x00100 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_HAT1_CHF 0x00200 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_HAT2_CHF 0x00400 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_HAT_FCS 0x00800 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_HATS_ALL 0x00e00 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTN_TL 0x01000 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTN_TR 0x02000 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTN_TL2 0x04000 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTN_TR2 0x08000 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTNS_TLR 0x03000 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTNS_TLR2 0x0c000 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_BTNS_GAMEPAD 0x0f000 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_HBTN_CHF 0x10000 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_ANY_CHF 0x10700 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_SAITEK 0x20000 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_EXTENSIONS 0x7ff00 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_GAMEPAD 0x80000 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_MAX_TIME 3 /* 3 ms */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_LOOP_TIME 2000 /* 2 * loop */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_SAITEK_DELAY 200 /* 200 us */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_SAITEK_TIME 2000 /* 2000 us */ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_AXIS_TIME 2 /* 2 * refresh */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_INIT_RETRIES 8 /* 8 times */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_FUZZ_BITS 2 /* 2 bit more */ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_MAX_NAME_LENGTH 128 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ANALOG_MAX_PHYS_LENGTH 32 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE }; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR }; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS }; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE }; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 }; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 }; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct analog { 11517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct input_dev *dev; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short *buttons; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char name[ANALOG_MAX_NAME_LENGTH]; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char phys[ANALOG_MAX_PHYS_LENGTH]; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct analog_port { 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gameport *gameport; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct analog analog[2]; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mask; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char saitek; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char cooked; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bads; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reads; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int speed; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int loop; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int fuzz; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int axes[4]; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int buttons; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int initial[4]; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int axtime; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Time macros. 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __i386__ 144306e440daf5f40b195afd83d05dee89fa63189e7Ingo Molnar 145306e440daf5f40b195afd83d05dee89fa63189e7Ingo Molnar#include <asm/i8253.h> 146306e440daf5f40b195afd83d05dee89fa63189e7Ingo Molnar 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0))) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TIME_NAME (cpu_has_tsc?"TSC":"PIT") 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int get_time_pit(void) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&i8253_lock, flags); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(0x00, 0x43); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = inb_p(0x40); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count |= inb_p(0x40) << 8; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&i8253_lock, flags); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif defined(__x86_64__) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_TIME(x) rdtscl(x) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DELTA(x,y) ((y)-(x)) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TIME_NAME "TSC" 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif defined(__alpha__) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_TIME(x) do { x = get_cycles(); } while (0) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DELTA(x,y) ((y)-(x)) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TIME_NAME "PCC" 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FAKE_TIME 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long analog_faketime = 0; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_TIME(x) do { x = analog_faketime++; } while(0) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DELTA(x,y) ((y)-(x)) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TIME_NAME "Unreliable" 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#warning Precise timer not defined for this architecture. 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_decode() decodes analog joystick data and reports input events. 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void analog_decode(struct analog *analog, int *axes, int *initial, int buttons) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct input_dev *dev = analog->dev; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_HAT_FCS) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) { 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buttons |= 1 << (i + 14); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = j = 0; i < 6; i++) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & (0x10 << i)) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_HBTN_CHF) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_BTN_TL) 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1)); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_BTN_TR) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1)); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_BTN_TL2) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1))); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_BTN_TR2) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1))); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = j = 0; i < 4; i++) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & (1 << i)) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, analog_axes[j++], axes[i]); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = j = 0; i < 3; i++) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & analog_exts[i]) { 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, analog_hats[j++], 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1)); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, analog_hats[j++], 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1)); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_cooked_read() reads analog joystick data. 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int analog_cooked_read(struct analog_port *port) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gameport *gameport = port->gameport; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int time[4], start, loop, now, loopout, timeout; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char data[4], this, last; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loopout = (ANALOG_LOOP_TIME * port->loop) / 1000; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = ANALOG_MAX_TIME * port->speed; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GET_TIME(now); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = now; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this = port->mask; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loop = now; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = this; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_disable(); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this = gameport_read(gameport) & port->mask; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GET_TIME(now); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((last ^ this) && (DELTA(loop, now) < loopout)) { 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[i] = last ^ this; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds time[i] = now; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (this && (i < 4) && (DELTA(start, now) < timeout)); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this <<= 4; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (--i; i >= 0; i--) { 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this |= data[i]; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < 4; j++) 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data[i] & (1 << j)) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -(this != port->mask); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int analog_button_read(struct analog_port *port, char saitek, char chf) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char u; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int t = 1, i = 0; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u = gameport_read(port->gameport); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!chf) { 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->buttons = (~u >> 4) & 0xf; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->buttons = 0; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((~u & 0xf0) && (i < 16) && t) { 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf]; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!saitek) return 0; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(ANALOG_SAITEK_DELAY); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = strobe; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(port->gameport); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (((u = gameport_read(port->gameport)) & port->mask) && t) t--; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -(!t || (i == 16)); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_poll() repeatedly polls the Analog joysticks. 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void analog_poll(struct gameport *gameport) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct analog_port *port = gameport_get_drvdata(gameport); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char saitek = !!(port->analog[0].mask & ANALOG_SAITEK); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->cooked) { 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (chf) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->reads++; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->axtime--) { 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->bads -= analog_cooked_read(port); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->bads -= analog_button_read(port, saitek, chf); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->reads++; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->axtime = ANALOG_AXIS_TIME - 1; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!saitek) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_button_read(port, saitek, chf); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->analog[i].mask) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_decode(port->analog + i, port->axes, port->initial, port->buttons); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_open() is a callback from the input open routine. 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int analog_open(struct input_dev *dev) 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct analog_port *port = dev->private; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_start_polling(port->gameport); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_close() is a callback from the input close routine. 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void analog_close(struct input_dev *dev) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct analog_port *port = dev->private; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_stop_polling(port->gameport); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_calibrate_timer() calibrates the timer and computes loop 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and timeout values for a joystick port. 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void analog_calibrate_timer(struct analog_port *port) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gameport *gameport = port->gameport; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i, t, tx, t1, t2, t3; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GET_TIME(t1); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef FAKE_TIME 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_faketime += 830; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(1); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GET_TIME(t2); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GET_TIME(t3); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->speed = DELTA(t1, t2) - DELTA(t2, t3); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx = ~0; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 50; i++) { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GET_TIME(t1); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); } 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GET_TIME(t3); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(i); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = DELTA(t1, t2) - DELTA(t2, t3); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (t < tx) tx = t; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->loop = tx / 50; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_name() constructs a name for an analog joystick. 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void analog_name(struct analog *analog) 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(analog->name, "Analog %d-axis %d-button", 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hweight8(analog->mask & ANALOG_AXES_STD), 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 + 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_HATS_ALL) 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(analog->name, "%s %d-hat", 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog->name, hweight16(analog->mask & ANALOG_HATS_ALL)); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_HAT_FCS) 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(analog->name, " FCS"); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_ANY_CHF) 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF"); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick"); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_init_device() 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic int analog_init_device(struct analog_port *port, struct analog *analog, int index) 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct input_dev *input_dev; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, t, v, w, x, y, z; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_name(analog); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(analog->phys, "%s/input%d", port->gameport->phys, index); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov analog->dev = input_dev = input_allocate_device(); 44217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (!input_dev) 44317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov return -ENOMEM; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->name = analog->name; 44617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->phys = analog->phys; 44717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.bustype = BUS_GAMEPORT; 44817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG; 44917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.product = analog->mask >> 4; 45017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.version = 0x0100; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->open = analog_open; 45317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->close = analog_close; 45417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->private = port; 45517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = j = 0; i < 4; i++) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & (1 << i)) { 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = analog_axes[j]; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = port->axes[i]; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds y = (port->axes[0] + port->axes[1]) >> 1; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z = y - port->axes[i]; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z = z > 0 ? z : -z; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = (x >> 3); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w = (x >> 3); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3))) 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = y; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_SAITEK) { 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == 2) x = port->axes[i]; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = x - (x >> 2); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w = (x >> 4); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_set_abs_params(input_dev, t, v, (x << 1) - v, port->fuzz, w); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j++; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = j = 0; i < 3; i++) 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & analog_exts[i]) 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (x = 0; x < 2; x++) { 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = analog_hats[j++]; 48517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_set_abs_params(input_dev, t, -1, 1, 0, 0); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = j = 0; i < 4; i++) 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & (0x10 << i)) 49017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov set_bit(analog->buttons[j++], input_dev->keybit); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_BTNS_CHF) 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) 49417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov set_bit(analog->buttons[j++], input_dev->keybit); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & ANALOG_HBTN_CHF) 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 49817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov set_bit(analog->buttons[j++], input_dev->keybit); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog->mask & (ANALOG_BTN_TL << i)) 50217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov set_bit(analog_pads[i], input_dev->keybit); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_decode(analog, port->axes, port->initial, port->buttons); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_register_device(analog->dev); 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov return 0; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * analog_init_devices() sets up device-specific values and registers the input devices. 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int analog_init_masks(struct analog_port *port) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct analog *analog = port->analog; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max[4]; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->mask) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((port->mask & 3) != 3 && port->mask != 0xc) { 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "analog.c: Unknown joystick device found " 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(data=%#x, %s), probably not analog joystick.\n", 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->mask, port->gameport->phys); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = analog_options[0]; /* FIXME !!! - need to specify options for different ports */ 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog[0].mask = i & 0xfffff; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | port->mask | ((port->mask << 8) & ANALOG_HAT_FCS) 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog[0].mask &= ~(ANALOG_HAT2_CHF) 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((~analog[0].mask & ANALOG_HAT_FCS) >> 8) 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((~analog[0].mask & ANALOG_HAT_FCS) << 2) 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((~analog[0].mask & ANALOG_HAT_FCS) << 4); 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER) 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12)); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->cooked) { 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_calibrate(port->gameport, port->axes, max); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->initial[i] = port->axes[i]; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -!(analog[0].mask || analog[1].mask); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int analog_init_port(struct gameport *gameport, struct gameport_driver *drv, struct analog_port *port) 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, t, u, v; 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->gameport = gameport; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_drvdata(gameport, port); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) { 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_calibrate_timer(port); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = gameport_read(gameport); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(ANALOG_MAX_TIME); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->mask = (gameport_read(gameport) ^ t) & t & 0xf; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ANALOG_INIT_RETRIES; i++) { 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!analog_cooked_read(port)) 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(ANALOG_MAX_TIME); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u = v = 0; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(ANALOG_MAX_TIME); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = gameport_time(gameport, ANALOG_MAX_TIME * 1000); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((gameport_read(port->gameport) & port->mask) && (u < t)) 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u++; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(ANALOG_SAITEK_DELAY); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = gameport_time(gameport, ANALOG_SAITEK_TIME); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((gameport_read(port->gameport) & port->mask) && (v < t)) 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v++; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (v < (u >> 1)) { /* FIXME - more than one port */ 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_options[0] |= /* FIXME - more than one port */ 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_close(gameport); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) { 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ANALOG_INIT_RETRIES; i++) 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!gameport_cooked_read(gameport, port->axes, &port->buttons)) 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->axes[i] != -1) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->mask |= 1 << i; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->fuzz = gameport->fuzz; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->cooked = 1; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return gameport_open(gameport, drv, GAMEPORT_MODE_RAW); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int analog_connect(struct gameport *gameport, struct gameport_driver *drv) 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct analog_port *port; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 645a97e148a8b8da8b04bc3e18ceb824a8f5f56d567Pekka Enberg if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL))) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return - ENOMEM; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = analog_init_port(gameport, drv, port); 64917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (err) 65017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov goto fail1; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = analog_init_masks(port); 65317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (err) 65417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov goto fail2; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_poll_handler(gameport, analog_poll); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_poll_interval(gameport, 10); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) 66017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (port->analog[i].mask) { 66117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov err = analog_init_device(port, port->analog + i, i); 66217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (err) 66317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov goto fail3; 66417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov } 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 66717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov 66817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov fail3: while (--i >= 0) 66917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_unregister_device(port->analog[i].dev); 67017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov fail2: gameport_close(gameport); 67117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov fail1: gameport_set_drvdata(gameport, NULL); 67217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov kfree(port); 67317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov return err; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void analog_disconnect(struct gameport *gameport) 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct analog_port *port = gameport_get_drvdata(gameport); 67917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int i; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->analog[i].mask) 68317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_unregister_device(port->analog[i].dev); 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_close(gameport); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_drvdata(gameport, NULL); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n", 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0, 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->gameport->phys); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(port); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct analog_types { 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *name; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct analog_types analog_types[] = { 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "none", 0x00000000 }, 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "auto", 0x000000ff }, 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "2btn", 0x0000003f }, 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "y-joy", 0x0cc00033 }, 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "y-pad", 0x8cc80033 }, 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "fcs", 0x000008f7 }, 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "chf", 0x000002ff }, 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "fullchf", 0x000007ff }, 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "gamepad", 0x000830f3 }, 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "gamepad8", 0x0008f0f3 }, 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { NULL, 0 } 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void analog_parse_options(void) 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j; 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *end; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < js_nargs; i++) { 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; analog_types[j].name; j++) 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!strcmp(analog_types[j].name, js[i])) { 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_options[i] = analog_types[j].value; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (analog_types[j].name) continue; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_options[i] = simple_strtoul(js[i], &end, 0); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (end != js[i]) continue; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_options[i] = 0xff; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!strlen(js[i])) continue; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; i < ANALOG_PORTS; i++) 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_options[i] = 0xff; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The gameport device structure. 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct gameport_driver analog_drv = { 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "analog", 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = DRIVER_DESC, 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .connect = analog_connect, 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = analog_disconnect, 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init analog_init(void) 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds analog_parse_options(); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_register_driver(&analog_drv); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit analog_exit(void) 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_unregister_driver(&analog_drv); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(analog_init); 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(analog_exit); 766