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