1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Copyright (c) 1998-2005 Vojtech Pavlik 3*1da177e4SLinus Torvalds */ 4*1da177e4SLinus Torvalds 5*1da177e4SLinus Torvalds /* 6*1da177e4SLinus Torvalds * Logitech ADI joystick family driver for Linux 7*1da177e4SLinus Torvalds */ 8*1da177e4SLinus Torvalds 9*1da177e4SLinus Torvalds /* 10*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 11*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 12*1da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 13*1da177e4SLinus Torvalds * (at your option) any later version. 14*1da177e4SLinus Torvalds * 15*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 16*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*1da177e4SLinus Torvalds * GNU General Public License for more details. 19*1da177e4SLinus Torvalds * 20*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 21*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 22*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23*1da177e4SLinus Torvalds * 24*1da177e4SLinus Torvalds * Should you need to contact me, the author, you can do so either by 25*1da177e4SLinus Torvalds * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 26*1da177e4SLinus Torvalds * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 27*1da177e4SLinus Torvalds */ 28*1da177e4SLinus Torvalds 29*1da177e4SLinus Torvalds #include <linux/delay.h> 30*1da177e4SLinus Torvalds #include <linux/kernel.h> 31*1da177e4SLinus Torvalds #include <linux/module.h> 32*1da177e4SLinus Torvalds #include <linux/string.h> 33*1da177e4SLinus Torvalds #include <linux/slab.h> 34*1da177e4SLinus Torvalds #include <linux/input.h> 35*1da177e4SLinus Torvalds #include <linux/gameport.h> 36*1da177e4SLinus Torvalds #include <linux/init.h> 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds #define DRIVER_DESC "Logitech ADI joystick family driver" 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 41*1da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 42*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 43*1da177e4SLinus Torvalds 44*1da177e4SLinus Torvalds /* 45*1da177e4SLinus Torvalds * Times, array sizes, flags, ids. 46*1da177e4SLinus Torvalds */ 47*1da177e4SLinus Torvalds 48*1da177e4SLinus Torvalds #define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */ 49*1da177e4SLinus Torvalds #define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */ 50*1da177e4SLinus Torvalds #define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */ 51*1da177e4SLinus Torvalds #define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */ 52*1da177e4SLinus Torvalds 53*1da177e4SLinus Torvalds #define ADI_MAX_LENGTH 256 54*1da177e4SLinus Torvalds #define ADI_MIN_LENGTH 8 55*1da177e4SLinus Torvalds #define ADI_MIN_LEN_LENGTH 10 56*1da177e4SLinus Torvalds #define ADI_MIN_ID_LENGTH 66 57*1da177e4SLinus Torvalds #define ADI_MAX_NAME_LENGTH 48 58*1da177e4SLinus Torvalds #define ADI_MAX_CNAME_LENGTH 16 59*1da177e4SLinus Torvalds #define ADI_MAX_PHYS_LENGTH 64 60*1da177e4SLinus Torvalds 61*1da177e4SLinus Torvalds #define ADI_FLAG_HAT 0x04 62*1da177e4SLinus Torvalds #define ADI_FLAG_10BIT 0x08 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds #define ADI_ID_TPD 0x01 65*1da177e4SLinus Torvalds #define ADI_ID_WGP 0x06 66*1da177e4SLinus Torvalds #define ADI_ID_WGPE 0x08 67*1da177e4SLinus Torvalds #define ADI_ID_MAX 0x0a 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds /* 70*1da177e4SLinus Torvalds * Names, buttons, axes ... 71*1da177e4SLinus Torvalds */ 72*1da177e4SLinus Torvalds 73*1da177e4SLinus Torvalds static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", 74*1da177e4SLinus Torvalds "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", 75*1da177e4SLinus Torvalds "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", 76*1da177e4SLinus Torvalds "WingMan GamePad USB", "Unknown Device %#x" }; 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y }; 79*1da177e4SLinus Torvalds static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; 80*1da177e4SLinus Torvalds static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y }; 81*1da177e4SLinus Torvalds static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; 82*1da177e4SLinus Torvalds static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }; 85*1da177e4SLinus Torvalds static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA }; 86*1da177e4SLinus Torvalds static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 }; 87*1da177e4SLinus Torvalds static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs, 90*1da177e4SLinus Torvalds adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs }; 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key, 93*1da177e4SLinus Torvalds adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key }; 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds /* 96*1da177e4SLinus Torvalds * Hat to axis conversion arrays. 97*1da177e4SLinus Torvalds */ 98*1da177e4SLinus Torvalds 99*1da177e4SLinus Torvalds static struct { 100*1da177e4SLinus Torvalds int x; 101*1da177e4SLinus Torvalds int y; 102*1da177e4SLinus Torvalds } adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds /* 105*1da177e4SLinus Torvalds * Per-port information. 106*1da177e4SLinus Torvalds */ 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds struct adi { 109*1da177e4SLinus Torvalds struct input_dev dev; 110*1da177e4SLinus Torvalds int length; 111*1da177e4SLinus Torvalds int ret; 112*1da177e4SLinus Torvalds int idx; 113*1da177e4SLinus Torvalds unsigned char id; 114*1da177e4SLinus Torvalds char buttons; 115*1da177e4SLinus Torvalds char axes10; 116*1da177e4SLinus Torvalds char axes8; 117*1da177e4SLinus Torvalds signed char pad; 118*1da177e4SLinus Torvalds char hats; 119*1da177e4SLinus Torvalds char *abs; 120*1da177e4SLinus Torvalds short *key; 121*1da177e4SLinus Torvalds char name[ADI_MAX_NAME_LENGTH]; 122*1da177e4SLinus Torvalds char cname[ADI_MAX_CNAME_LENGTH]; 123*1da177e4SLinus Torvalds char phys[ADI_MAX_PHYS_LENGTH]; 124*1da177e4SLinus Torvalds unsigned char data[ADI_MAX_LENGTH]; 125*1da177e4SLinus Torvalds }; 126*1da177e4SLinus Torvalds 127*1da177e4SLinus Torvalds struct adi_port { 128*1da177e4SLinus Torvalds struct gameport *gameport; 129*1da177e4SLinus Torvalds struct adi adi[2]; 130*1da177e4SLinus Torvalds int bad; 131*1da177e4SLinus Torvalds int reads; 132*1da177e4SLinus Torvalds }; 133*1da177e4SLinus Torvalds 134*1da177e4SLinus Torvalds /* 135*1da177e4SLinus Torvalds * adi_read_packet() reads a Logitech ADI packet. 136*1da177e4SLinus Torvalds */ 137*1da177e4SLinus Torvalds 138*1da177e4SLinus Torvalds static void adi_read_packet(struct adi_port *port) 139*1da177e4SLinus Torvalds { 140*1da177e4SLinus Torvalds struct adi *adi = port->adi; 141*1da177e4SLinus Torvalds struct gameport *gameport = port->gameport; 142*1da177e4SLinus Torvalds unsigned char u, v, w, x, z; 143*1da177e4SLinus Torvalds int t[2], s[2], i; 144*1da177e4SLinus Torvalds unsigned long flags; 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 147*1da177e4SLinus Torvalds adi[i].ret = -1; 148*1da177e4SLinus Torvalds t[i] = gameport_time(gameport, ADI_MAX_START); 149*1da177e4SLinus Torvalds s[i] = 0; 150*1da177e4SLinus Torvalds } 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds local_irq_save(flags); 153*1da177e4SLinus Torvalds 154*1da177e4SLinus Torvalds gameport_trigger(gameport); 155*1da177e4SLinus Torvalds v = z = gameport_read(gameport); 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds do { 158*1da177e4SLinus Torvalds u = v; 159*1da177e4SLinus Torvalds w = u ^ (v = x = gameport_read(gameport)); 160*1da177e4SLinus Torvalds for (i = 0; i < 2; i++, w >>= 2, x >>= 2) { 161*1da177e4SLinus Torvalds t[i]--; 162*1da177e4SLinus Torvalds if ((w & 0x30) && s[i]) { 163*1da177e4SLinus Torvalds if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) { 164*1da177e4SLinus Torvalds adi[i].data[++adi[i].ret] = w; 165*1da177e4SLinus Torvalds t[i] = gameport_time(gameport, ADI_MAX_STROBE); 166*1da177e4SLinus Torvalds } else t[i] = 0; 167*1da177e4SLinus Torvalds } else if (!(x & 0x30)) s[i] = 1; 168*1da177e4SLinus Torvalds } 169*1da177e4SLinus Torvalds } while (t[0] > 0 || t[1] > 0); 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds local_irq_restore(flags); 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds return; 174*1da177e4SLinus Torvalds } 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds /* 177*1da177e4SLinus Torvalds * adi_move_bits() detects a possible 2-stream mode, and moves 178*1da177e4SLinus Torvalds * the bits accordingly. 179*1da177e4SLinus Torvalds */ 180*1da177e4SLinus Torvalds 181*1da177e4SLinus Torvalds static void adi_move_bits(struct adi_port *port, int length) 182*1da177e4SLinus Torvalds { 183*1da177e4SLinus Torvalds int i; 184*1da177e4SLinus Torvalds struct adi *adi = port->adi; 185*1da177e4SLinus Torvalds 186*1da177e4SLinus Torvalds adi[0].idx = adi[1].idx = 0; 187*1da177e4SLinus Torvalds 188*1da177e4SLinus Torvalds if (adi[0].ret <= 0 || adi[1].ret <= 0) return; 189*1da177e4SLinus Torvalds if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return; 190*1da177e4SLinus Torvalds 191*1da177e4SLinus Torvalds for (i = 1; i <= adi[1].ret; i++) 192*1da177e4SLinus Torvalds adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i]; 193*1da177e4SLinus Torvalds 194*1da177e4SLinus Torvalds adi[0].ret += adi[1].ret; 195*1da177e4SLinus Torvalds adi[1].ret = -1; 196*1da177e4SLinus Torvalds } 197*1da177e4SLinus Torvalds 198*1da177e4SLinus Torvalds /* 199*1da177e4SLinus Torvalds * adi_get_bits() gathers bits from the data packet. 200*1da177e4SLinus Torvalds */ 201*1da177e4SLinus Torvalds 202*1da177e4SLinus Torvalds static inline int adi_get_bits(struct adi *adi, int count) 203*1da177e4SLinus Torvalds { 204*1da177e4SLinus Torvalds int bits = 0; 205*1da177e4SLinus Torvalds int i; 206*1da177e4SLinus Torvalds if ((adi->idx += count) > adi->ret) return 0; 207*1da177e4SLinus Torvalds for (i = 0; i < count; i++) 208*1da177e4SLinus Torvalds bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; 209*1da177e4SLinus Torvalds return bits; 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds 212*1da177e4SLinus Torvalds /* 213*1da177e4SLinus Torvalds * adi_decode() decodes Logitech joystick data into input events. 214*1da177e4SLinus Torvalds */ 215*1da177e4SLinus Torvalds 216*1da177e4SLinus Torvalds static int adi_decode(struct adi *adi) 217*1da177e4SLinus Torvalds { 218*1da177e4SLinus Torvalds struct input_dev *dev = &adi->dev; 219*1da177e4SLinus Torvalds char *abs = adi->abs; 220*1da177e4SLinus Torvalds short *key = adi->key; 221*1da177e4SLinus Torvalds int i, t; 222*1da177e4SLinus Torvalds 223*1da177e4SLinus Torvalds if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4))) 224*1da177e4SLinus Torvalds return -1; 225*1da177e4SLinus Torvalds 226*1da177e4SLinus Torvalds for (i = 0; i < adi->axes10; i++) 227*1da177e4SLinus Torvalds input_report_abs(dev, *abs++, adi_get_bits(adi, 10)); 228*1da177e4SLinus Torvalds 229*1da177e4SLinus Torvalds for (i = 0; i < adi->axes8; i++) 230*1da177e4SLinus Torvalds input_report_abs(dev, *abs++, adi_get_bits(adi, 8)); 231*1da177e4SLinus Torvalds 232*1da177e4SLinus Torvalds for (i = 0; i < adi->buttons && i < 63; i++) { 233*1da177e4SLinus Torvalds if (i == adi->pad) { 234*1da177e4SLinus Torvalds t = adi_get_bits(adi, 4); 235*1da177e4SLinus Torvalds input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1)); 236*1da177e4SLinus Torvalds input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1)); 237*1da177e4SLinus Torvalds } 238*1da177e4SLinus Torvalds input_report_key(dev, *key++, adi_get_bits(adi, 1)); 239*1da177e4SLinus Torvalds } 240*1da177e4SLinus Torvalds 241*1da177e4SLinus Torvalds for (i = 0; i < adi->hats; i++) { 242*1da177e4SLinus Torvalds if ((t = adi_get_bits(adi, 4)) > 8) t = 0; 243*1da177e4SLinus Torvalds input_report_abs(dev, *abs++, adi_hat_to_axis[t].x); 244*1da177e4SLinus Torvalds input_report_abs(dev, *abs++, adi_hat_to_axis[t].y); 245*1da177e4SLinus Torvalds } 246*1da177e4SLinus Torvalds 247*1da177e4SLinus Torvalds for (i = 63; i < adi->buttons; i++) 248*1da177e4SLinus Torvalds input_report_key(dev, *key++, adi_get_bits(adi, 1)); 249*1da177e4SLinus Torvalds 250*1da177e4SLinus Torvalds input_sync(dev); 251*1da177e4SLinus Torvalds 252*1da177e4SLinus Torvalds return 0; 253*1da177e4SLinus Torvalds } 254*1da177e4SLinus Torvalds 255*1da177e4SLinus Torvalds /* 256*1da177e4SLinus Torvalds * adi_read() reads the data packet and decodes it. 257*1da177e4SLinus Torvalds */ 258*1da177e4SLinus Torvalds 259*1da177e4SLinus Torvalds static int adi_read(struct adi_port *port) 260*1da177e4SLinus Torvalds { 261*1da177e4SLinus Torvalds int i; 262*1da177e4SLinus Torvalds int result = 0; 263*1da177e4SLinus Torvalds 264*1da177e4SLinus Torvalds adi_read_packet(port); 265*1da177e4SLinus Torvalds adi_move_bits(port, port->adi[0].length); 266*1da177e4SLinus Torvalds 267*1da177e4SLinus Torvalds for (i = 0; i < 2; i++) 268*1da177e4SLinus Torvalds if (port->adi[i].length) 269*1da177e4SLinus Torvalds result |= adi_decode(port->adi + i); 270*1da177e4SLinus Torvalds 271*1da177e4SLinus Torvalds return result; 272*1da177e4SLinus Torvalds } 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds /* 275*1da177e4SLinus Torvalds * adi_poll() repeatedly polls the Logitech joysticks. 276*1da177e4SLinus Torvalds */ 277*1da177e4SLinus Torvalds 278*1da177e4SLinus Torvalds static void adi_poll(struct gameport *gameport) 279*1da177e4SLinus Torvalds { 280*1da177e4SLinus Torvalds struct adi_port *port = gameport_get_drvdata(gameport); 281*1da177e4SLinus Torvalds 282*1da177e4SLinus Torvalds port->bad -= adi_read(port); 283*1da177e4SLinus Torvalds port->reads++; 284*1da177e4SLinus Torvalds } 285*1da177e4SLinus Torvalds 286*1da177e4SLinus Torvalds /* 287*1da177e4SLinus Torvalds * adi_open() is a callback from the input open routine. 288*1da177e4SLinus Torvalds */ 289*1da177e4SLinus Torvalds 290*1da177e4SLinus Torvalds static int adi_open(struct input_dev *dev) 291*1da177e4SLinus Torvalds { 292*1da177e4SLinus Torvalds struct adi_port *port = dev->private; 293*1da177e4SLinus Torvalds 294*1da177e4SLinus Torvalds gameport_start_polling(port->gameport); 295*1da177e4SLinus Torvalds return 0; 296*1da177e4SLinus Torvalds } 297*1da177e4SLinus Torvalds 298*1da177e4SLinus Torvalds /* 299*1da177e4SLinus Torvalds * adi_close() is a callback from the input close routine. 300*1da177e4SLinus Torvalds */ 301*1da177e4SLinus Torvalds 302*1da177e4SLinus Torvalds static void adi_close(struct input_dev *dev) 303*1da177e4SLinus Torvalds { 304*1da177e4SLinus Torvalds struct adi_port *port = dev->private; 305*1da177e4SLinus Torvalds 306*1da177e4SLinus Torvalds gameport_stop_polling(port->gameport); 307*1da177e4SLinus Torvalds } 308*1da177e4SLinus Torvalds 309*1da177e4SLinus Torvalds /* 310*1da177e4SLinus Torvalds * adi_init_digital() sends a trigger & delay sequence 311*1da177e4SLinus Torvalds * to reset and initialize a Logitech joystick into digital mode. 312*1da177e4SLinus Torvalds */ 313*1da177e4SLinus Torvalds 314*1da177e4SLinus Torvalds static void adi_init_digital(struct gameport *gameport) 315*1da177e4SLinus Torvalds { 316*1da177e4SLinus Torvalds int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 }; 317*1da177e4SLinus Torvalds int i; 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds for (i = 0; seq[i]; i++) { 320*1da177e4SLinus Torvalds gameport_trigger(gameport); 321*1da177e4SLinus Torvalds if (seq[i] > 0) msleep(seq[i]); 322*1da177e4SLinus Torvalds if (seq[i] < 0) { 323*1da177e4SLinus Torvalds mdelay(-seq[i]); 324*1da177e4SLinus Torvalds udelay(-seq[i]*14); /* It looks like mdelay() is off by approx 1.4% */ 325*1da177e4SLinus Torvalds } 326*1da177e4SLinus Torvalds } 327*1da177e4SLinus Torvalds } 328*1da177e4SLinus Torvalds 329*1da177e4SLinus Torvalds static void adi_id_decode(struct adi *adi, struct adi_port *port) 330*1da177e4SLinus Torvalds { 331*1da177e4SLinus Torvalds int i, t; 332*1da177e4SLinus Torvalds 333*1da177e4SLinus Torvalds if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */ 334*1da177e4SLinus Torvalds return; 335*1da177e4SLinus Torvalds 336*1da177e4SLinus Torvalds if (adi->ret < (t = adi_get_bits(adi, 10))) { 337*1da177e4SLinus Torvalds printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); 338*1da177e4SLinus Torvalds return; 339*1da177e4SLinus Torvalds } 340*1da177e4SLinus Torvalds 341*1da177e4SLinus Torvalds adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4); 342*1da177e4SLinus Torvalds 343*1da177e4SLinus Torvalds if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++; 344*1da177e4SLinus Torvalds 345*1da177e4SLinus Torvalds adi->length = adi_get_bits(adi, 10); 346*1da177e4SLinus Torvalds 347*1da177e4SLinus Torvalds if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) { 348*1da177e4SLinus Torvalds printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length); 349*1da177e4SLinus Torvalds adi->length = 0; 350*1da177e4SLinus Torvalds return; 351*1da177e4SLinus Torvalds } 352*1da177e4SLinus Torvalds 353*1da177e4SLinus Torvalds adi->axes8 = adi_get_bits(adi, 4); 354*1da177e4SLinus Torvalds adi->buttons = adi_get_bits(adi, 6); 355*1da177e4SLinus Torvalds 356*1da177e4SLinus Torvalds if (adi_get_bits(adi, 6) != 8 && adi->hats) { 357*1da177e4SLinus Torvalds printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n"); 358*1da177e4SLinus Torvalds adi->length = 0; 359*1da177e4SLinus Torvalds return; 360*1da177e4SLinus Torvalds } 361*1da177e4SLinus Torvalds 362*1da177e4SLinus Torvalds adi->buttons += adi_get_bits(adi, 6); 363*1da177e4SLinus Torvalds adi->hats += adi_get_bits(adi, 4); 364*1da177e4SLinus Torvalds 365*1da177e4SLinus Torvalds i = adi_get_bits(adi, 4); 366*1da177e4SLinus Torvalds 367*1da177e4SLinus Torvalds if (t & ADI_FLAG_10BIT) { 368*1da177e4SLinus Torvalds adi->axes10 = adi->axes8 - i; 369*1da177e4SLinus Torvalds adi->axes8 = i; 370*1da177e4SLinus Torvalds } 371*1da177e4SLinus Torvalds 372*1da177e4SLinus Torvalds t = adi_get_bits(adi, 4); 373*1da177e4SLinus Torvalds 374*1da177e4SLinus Torvalds for (i = 0; i < t; i++) 375*1da177e4SLinus Torvalds adi->cname[i] = adi_get_bits(adi, 8); 376*1da177e4SLinus Torvalds adi->cname[i] = 0; 377*1da177e4SLinus Torvalds 378*1da177e4SLinus Torvalds t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4; 379*1da177e4SLinus Torvalds if (adi->length != t && adi->length != t + (t & 1)) { 380*1da177e4SLinus Torvalds printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length); 381*1da177e4SLinus Torvalds adi->length = 0; 382*1da177e4SLinus Torvalds return; 383*1da177e4SLinus Torvalds } 384*1da177e4SLinus Torvalds 385*1da177e4SLinus Torvalds switch (adi->id) { 386*1da177e4SLinus Torvalds case ADI_ID_TPD: 387*1da177e4SLinus Torvalds adi->pad = 4; 388*1da177e4SLinus Torvalds adi->buttons -= 4; 389*1da177e4SLinus Torvalds break; 390*1da177e4SLinus Torvalds case ADI_ID_WGP: 391*1da177e4SLinus Torvalds adi->pad = 0; 392*1da177e4SLinus Torvalds adi->buttons -= 4; 393*1da177e4SLinus Torvalds break; 394*1da177e4SLinus Torvalds default: 395*1da177e4SLinus Torvalds adi->pad = -1; 396*1da177e4SLinus Torvalds break; 397*1da177e4SLinus Torvalds } 398*1da177e4SLinus Torvalds } 399*1da177e4SLinus Torvalds 400*1da177e4SLinus Torvalds static void adi_init_input(struct adi *adi, struct adi_port *port, int half) 401*1da177e4SLinus Torvalds { 402*1da177e4SLinus Torvalds int i, t; 403*1da177e4SLinus Torvalds char buf[ADI_MAX_NAME_LENGTH]; 404*1da177e4SLinus Torvalds 405*1da177e4SLinus Torvalds if (!adi->length) return; 406*1da177e4SLinus Torvalds 407*1da177e4SLinus Torvalds init_input_dev(&adi->dev); 408*1da177e4SLinus Torvalds 409*1da177e4SLinus Torvalds t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX; 410*1da177e4SLinus Torvalds 411*1da177e4SLinus Torvalds snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id); 412*1da177e4SLinus Torvalds snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s", buf); 413*1da177e4SLinus Torvalds snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half); 414*1da177e4SLinus Torvalds 415*1da177e4SLinus Torvalds adi->abs = adi_abs[t]; 416*1da177e4SLinus Torvalds adi->key = adi_key[t]; 417*1da177e4SLinus Torvalds 418*1da177e4SLinus Torvalds adi->dev.open = adi_open; 419*1da177e4SLinus Torvalds adi->dev.close = adi_close; 420*1da177e4SLinus Torvalds 421*1da177e4SLinus Torvalds adi->dev.name = adi->name; 422*1da177e4SLinus Torvalds adi->dev.phys = adi->phys; 423*1da177e4SLinus Torvalds adi->dev.id.bustype = BUS_GAMEPORT; 424*1da177e4SLinus Torvalds adi->dev.id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; 425*1da177e4SLinus Torvalds adi->dev.id.product = adi->id; 426*1da177e4SLinus Torvalds adi->dev.id.version = 0x0100; 427*1da177e4SLinus Torvalds 428*1da177e4SLinus Torvalds adi->dev.private = port; 429*1da177e4SLinus Torvalds adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); 430*1da177e4SLinus Torvalds 431*1da177e4SLinus Torvalds for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) 432*1da177e4SLinus Torvalds set_bit(adi->abs[i], adi->dev.absbit); 433*1da177e4SLinus Torvalds 434*1da177e4SLinus Torvalds for (i = 0; i < adi->buttons; i++) 435*1da177e4SLinus Torvalds set_bit(adi->key[i], adi->dev.keybit); 436*1da177e4SLinus Torvalds } 437*1da177e4SLinus Torvalds 438*1da177e4SLinus Torvalds static void adi_init_center(struct adi *adi) 439*1da177e4SLinus Torvalds { 440*1da177e4SLinus Torvalds int i, t, x; 441*1da177e4SLinus Torvalds 442*1da177e4SLinus Torvalds if (!adi->length) 443*1da177e4SLinus Torvalds return; 444*1da177e4SLinus Torvalds 445*1da177e4SLinus Torvalds for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { 446*1da177e4SLinus Torvalds 447*1da177e4SLinus Torvalds t = adi->abs[i]; 448*1da177e4SLinus Torvalds x = adi->dev.abs[t]; 449*1da177e4SLinus Torvalds 450*1da177e4SLinus Torvalds if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) 451*1da177e4SLinus Torvalds x = i < adi->axes10 ? 512 : 128; 452*1da177e4SLinus Torvalds 453*1da177e4SLinus Torvalds if (i < adi->axes10) 454*1da177e4SLinus Torvalds input_set_abs_params(&adi->dev, t, 64, x * 2 - 64, 2, 16); 455*1da177e4SLinus Torvalds else if (i < adi->axes10 + adi->axes8) 456*1da177e4SLinus Torvalds input_set_abs_params(&adi->dev, t, 48, x * 2 - 48, 1, 16); 457*1da177e4SLinus Torvalds else 458*1da177e4SLinus Torvalds input_set_abs_params(&adi->dev, t, -1, 1, 0, 0); 459*1da177e4SLinus Torvalds } 460*1da177e4SLinus Torvalds } 461*1da177e4SLinus Torvalds 462*1da177e4SLinus Torvalds /* 463*1da177e4SLinus Torvalds * adi_connect() probes for Logitech ADI joysticks. 464*1da177e4SLinus Torvalds */ 465*1da177e4SLinus Torvalds 466*1da177e4SLinus Torvalds static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) 467*1da177e4SLinus Torvalds { 468*1da177e4SLinus Torvalds struct adi_port *port; 469*1da177e4SLinus Torvalds int i; 470*1da177e4SLinus Torvalds int err; 471*1da177e4SLinus Torvalds 472*1da177e4SLinus Torvalds if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL))) 473*1da177e4SLinus Torvalds return -ENOMEM; 474*1da177e4SLinus Torvalds 475*1da177e4SLinus Torvalds port->gameport = gameport; 476*1da177e4SLinus Torvalds 477*1da177e4SLinus Torvalds gameport_set_drvdata(gameport, port); 478*1da177e4SLinus Torvalds 479*1da177e4SLinus Torvalds err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); 480*1da177e4SLinus Torvalds if (err) { 481*1da177e4SLinus Torvalds kfree(port); 482*1da177e4SLinus Torvalds return err; 483*1da177e4SLinus Torvalds } 484*1da177e4SLinus Torvalds 485*1da177e4SLinus Torvalds adi_init_digital(gameport); 486*1da177e4SLinus Torvalds adi_read_packet(port); 487*1da177e4SLinus Torvalds 488*1da177e4SLinus Torvalds if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH) 489*1da177e4SLinus Torvalds adi_move_bits(port, adi_get_bits(port->adi, 10)); 490*1da177e4SLinus Torvalds 491*1da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 492*1da177e4SLinus Torvalds adi_id_decode(port->adi + i, port); 493*1da177e4SLinus Torvalds adi_init_input(port->adi + i, port, i); 494*1da177e4SLinus Torvalds } 495*1da177e4SLinus Torvalds 496*1da177e4SLinus Torvalds if (!port->adi[0].length && !port->adi[1].length) { 497*1da177e4SLinus Torvalds gameport_close(gameport); 498*1da177e4SLinus Torvalds kfree(port); 499*1da177e4SLinus Torvalds return -ENODEV; 500*1da177e4SLinus Torvalds } 501*1da177e4SLinus Torvalds 502*1da177e4SLinus Torvalds gameport_set_poll_handler(gameport, adi_poll); 503*1da177e4SLinus Torvalds gameport_set_poll_interval(gameport, 20); 504*1da177e4SLinus Torvalds 505*1da177e4SLinus Torvalds msleep(ADI_INIT_DELAY); 506*1da177e4SLinus Torvalds if (adi_read(port)) { 507*1da177e4SLinus Torvalds msleep(ADI_DATA_DELAY); 508*1da177e4SLinus Torvalds adi_read(port); 509*1da177e4SLinus Torvalds } 510*1da177e4SLinus Torvalds 511*1da177e4SLinus Torvalds for (i = 0; i < 2; i++) 512*1da177e4SLinus Torvalds if (port->adi[i].length > 0) { 513*1da177e4SLinus Torvalds adi_init_center(port->adi + i); 514*1da177e4SLinus Torvalds input_register_device(&port->adi[i].dev); 515*1da177e4SLinus Torvalds printk(KERN_INFO "input: %s [%s] on %s\n", 516*1da177e4SLinus Torvalds port->adi[i].name, port->adi[i].cname, gameport->phys); 517*1da177e4SLinus Torvalds } 518*1da177e4SLinus Torvalds 519*1da177e4SLinus Torvalds return 0; 520*1da177e4SLinus Torvalds } 521*1da177e4SLinus Torvalds 522*1da177e4SLinus Torvalds static void adi_disconnect(struct gameport *gameport) 523*1da177e4SLinus Torvalds { 524*1da177e4SLinus Torvalds int i; 525*1da177e4SLinus Torvalds struct adi_port *port = gameport_get_drvdata(gameport); 526*1da177e4SLinus Torvalds 527*1da177e4SLinus Torvalds for (i = 0; i < 2; i++) 528*1da177e4SLinus Torvalds if (port->adi[i].length > 0) 529*1da177e4SLinus Torvalds input_unregister_device(&port->adi[i].dev); 530*1da177e4SLinus Torvalds gameport_close(gameport); 531*1da177e4SLinus Torvalds gameport_set_drvdata(gameport, NULL); 532*1da177e4SLinus Torvalds kfree(port); 533*1da177e4SLinus Torvalds } 534*1da177e4SLinus Torvalds 535*1da177e4SLinus Torvalds /* 536*1da177e4SLinus Torvalds * The gameport device structure. 537*1da177e4SLinus Torvalds */ 538*1da177e4SLinus Torvalds 539*1da177e4SLinus Torvalds static struct gameport_driver adi_drv = { 540*1da177e4SLinus Torvalds .driver = { 541*1da177e4SLinus Torvalds .name = "adi", 542*1da177e4SLinus Torvalds }, 543*1da177e4SLinus Torvalds .description = DRIVER_DESC, 544*1da177e4SLinus Torvalds .connect = adi_connect, 545*1da177e4SLinus Torvalds .disconnect = adi_disconnect, 546*1da177e4SLinus Torvalds }; 547*1da177e4SLinus Torvalds 548*1da177e4SLinus Torvalds static int __init adi_init(void) 549*1da177e4SLinus Torvalds { 550*1da177e4SLinus Torvalds gameport_register_driver(&adi_drv); 551*1da177e4SLinus Torvalds return 0; 552*1da177e4SLinus Torvalds } 553*1da177e4SLinus Torvalds 554*1da177e4SLinus Torvalds static void __exit adi_exit(void) 555*1da177e4SLinus Torvalds { 556*1da177e4SLinus Torvalds gameport_unregister_driver(&adi_drv); 557*1da177e4SLinus Torvalds } 558*1da177e4SLinus Torvalds 559*1da177e4SLinus Torvalds module_init(adi_init); 560*1da177e4SLinus Torvalds module_exit(adi_exit); 561