11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for the Gravis Grip Multiport, a gamepad "hub" that 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * connects up to four 9-pin digital gamepads/joysticks. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thanks to Chris Gassib for helpful advice. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2002 Brian Bonnlander, Bill Soudan 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1998-2000 Vojtech Pavlik 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/gameport.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/input.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 204e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/jiffies.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Gravis Grip Multiport driver" 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Brian Bonnlander"); 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef GRIP_DEBUG 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dbg(format, arg...) do {} while (0) 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov#define GRIP_MAX_PORTS 4 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Grip multiport state 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstruct grip_port { 4017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct input_dev *dev; 4117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int mode; 4217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int registered; 4317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov 4417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov /* individual gamepad states */ 4517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int buttons; 4617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int xaxes; 4717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int yaxes; 4817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int dirty; /* has the state been updated? */ 4917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov}; 5017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct grip_mp { 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gameport *gameport; 5317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct grip_port *port[GRIP_MAX_PORTS]; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reads; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bads; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Multiport packet interpretation 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PACKET_FULL 0x80000000 /* packet is full */ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PACKET_MP_DONE 0x02000000 /* multiport done sending */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Packet status code interpretation 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_GOT_PACKET 0x0100 /* Got a packet */ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_DONE 0x1000 /* Multiport is done sending packets */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_RETRY 0x4000 /* Try again later to get packet */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IO_RESET 0x8000 /* Force multiport to resend all packets */ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gamepad configuration data. Other 9-pin digital joystick devices 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may work with the multiport, so this may not be an exhaustive list! 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Commodore 64 joystick remains untested. 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GRIP_INIT_DELAY 2000 /* 2 ms */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GRIP_MODE_NONE 0 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GRIP_MODE_RESET 1 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GRIP_MODE_GP 2 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GRIP_MODE_C64 3 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; 9317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; 9617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; 9917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const int init_seq[] = { 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 }; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic int register_slot(int i, struct grip_mp *grip); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns whether an odd or even number of bits are on in pkt. 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bit_parity(u32 pkt) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x = pkt ^ (pkt >> 16); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x ^= x >> 8; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x ^= x >> 4; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x ^= x >> 2; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x ^= x >> 1; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return x & 1; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Poll gameport; return true if all bits set in 'onbits' are on and 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all bits set in 'offbits' are off. 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, nloops; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nloops = gameport_time(gp, u_sec); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < nloops; i++) { 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *data = gameport_read(gp); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*data & onbits) == onbits && 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (~(*data) & offbits) == offbits) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("gameport timed out after %d microseconds.\n", u_sec); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gets a 28-bit packet from the multiport. 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After getting a packet successfully, commands encoded by sendcode may 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be sent to the multiport. 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The multiport clock value is reflected in gameport bit B4. 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns a packet status code indicating whether packet is valid, the transfer 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mode, and any error conditions. 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sendflags: current I/O status 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sendcode: data to send to the multiport if sendflags is nonzero 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 raw_data; /* raw data from gameport */ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 data_mask; /* packet data bits from raw_data */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pkt; /* packet temporary storage */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bits_per_read; /* num packet bits per gameport read */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int portvals = 0; /* used for port value sanity check */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *packet = 0; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raw_data = gameport_read(gameport); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (raw_data & 1) 178ab0c3443ad2de03383f2549195badf64779d08a1Dmitry Torokhov return IO_RETRY; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 64; i++) { 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raw_data = gameport_read(gameport); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (portvals == 1) { /* B4, B5 off */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raw_data = gameport_read(gameport); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds portvals = raw_data & 0xf0; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (raw_data & 0x31) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0x10, 0, 308, gameport, &raw_data)) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RETRY; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine packet transfer mode and prepare for packet construction. */ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (raw_data & 0x20) { /* 3 data bits/read */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (portvals != 0xb) 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_mask = 7; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits_per_read = 3; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* 1 data bit/read */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_mask = 1; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bits_per_read = 1; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Construct a packet. Final data bits must be zero. */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0, 0x10, 77, gameport, &raw_data)) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raw_data = (raw_data >> 5) & data_mask; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt & PACKET_FULL) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt = (pkt << bits_per_read) | raw_data; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0x10, 0, 77, gameport, &raw_data)) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (raw_data) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If 3 bits/read used, drop from 30 bits to 28. */ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bits_per_read == 3) { 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt = (pkt >> 2) | 0xf0000000; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bit_parity(pkt) == 1) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Acknowledge packet receipt */ 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0x30, 0, 77, gameport, &raw_data)) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raw_data = gameport_read(gameport); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (raw_data & 1) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0, 0x20, 77, gameport, &raw_data)) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_RESET; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return if we just wanted the packet or multiport wants to send more */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *packet = pkt; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE))) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt & PACKET_MP_MORE) 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET | IO_RETRY; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Multiport is done sending packets and is ready to receive data */ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0x20, 0, 77, gameport, &raw_data)) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET | IO_RESET; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raw_data = gameport_read(gameport); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (raw_data & 1) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET | IO_RESET; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Trigger gameport based on bits in sendcode */ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0x20, 0x10, 116, gameport, &raw_data)) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET | IO_RESET; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_until(0x30, 0, 193, gameport, &raw_data)) 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET | IO_RESET; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (raw_data & 1) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET | IO_RESET; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sendcode & 1) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sendcode >>= 1; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (sendcode); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IO_GOT_PACKET | IO_MODE_FAST; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disables and restores interrupts for mp_io(), which does the actual I/O. 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = mp_io(gameport, sendflags, sendcode, packet); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts multiport into digital mode. Multiport LED turns green. 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns true if a valid digital packet was received, false otherwise. 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dig_mode_start(struct gameport *gameport, u32 *packet) 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3215ec1f7f3e4a4896062dc6a64d38036588733bc23Andi Drebes int i; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags, tries = 0, bads = 0; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3245ec1f7f3e4a4896062dc6a64d38036588733bc23Andi Drebes for (i = 0; i < ARRAY_SIZE(init_seq); i++) { /* Send magic sequence */ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init_seq[i]) 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_trigger(gameport); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(GRIP_INIT_DELAY); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) /* Wait for multiport to settle */ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(GRIP_INIT_DELAY); 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = multiport_io(gameport, IO_RESET, 0x27, packet); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & IO_MODE_FAST) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & IO_RETRY) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tries++; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bads++; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Packet structure: B0-B15 => gamepad state 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * B16-B20 => gamepad device type 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * B21-B24 => multiport slot index (1-4) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist. 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the packet status. 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_and_decode_packet(struct grip_mp *grip, int flags) 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct grip_port *port; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 packet; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int joytype = 0; 36317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int slot; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get a packet and check for validity */ 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags &= IO_RESET | IO_RETRY; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = multiport_io(grip->gameport, flags, 0, &packet); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds grip->reads++; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (packet & PACKET_MP_DONE) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= IO_DONE; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags && !(flags & IO_GOT_PACKET)) { 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds grip->bads++; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return flags; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ignore non-gamepad packets, e.g. multiport hardware version */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot = ((packet >> 21) & 0xf) - 1; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((slot < 0) || (slot > 3)) 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return flags; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port = grip->port[slot]; 38617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle "reset" packets, which occur at startup, and when gamepads 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are removed or plugged in. May contain configuration of a new gamepad. 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds joytype = (packet >> 16) & 0x1f; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!joytype) { 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (port->registered) { 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "grip_mp: removing %s, slot %d\n", 39717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov grip_name[port->mode], slot); 39817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_unregister_device(port->dev); 39917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->registered = 0; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("Reset: grip multiport slot %d\n", slot); 40217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->mode = GRIP_MODE_RESET; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= IO_SLOT_CHANGE; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return flags; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Interpret a grip pad packet */ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (joytype == 0x1f) { 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dir = (packet >> 8) & 0xf; /* eight way directional value */ 41217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->buttons = (~packet) & 0xff; 41317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->yaxes = ((axis_map[dir] >> 2) & 3) - 1; 41417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->xaxes = (axis_map[dir] & 3) - 1; 41517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->dirty = 1; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (port->mode == GRIP_MODE_RESET) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags |= IO_SLOT_CHANGE; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->mode = GRIP_MODE_GP; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (!port->registered) { 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("New Grip pad in multiport slot %d.\n", slot); 424127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov if (register_slot(slot, grip)) { 425127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov port->mode = GRIP_MODE_RESET; 426127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov port->dirty = 0; 427127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov } 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return flags; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle non-grip device codes. For now, just print diagnostics. */ 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int strange_code = 0; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strange_code != joytype) { 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "Possible non-grip pad/joystick detected.\n"); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strange_code = joytype; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return flags; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns true if all multiport slot states appear valid. 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int slots_valid(struct grip_mp *grip) 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags, slot, invalid = 0, active = 0; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = get_and_decode_packet(grip, 0); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(flags & IO_GOT_PACKET)) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = 0; slot < 4; slot++) { 45817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (grip->port[slot]->mode == GRIP_MODE_RESET) 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds invalid = 1; 46017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (grip->port[slot]->mode != GRIP_MODE_NONE) 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds active = 1; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return true if no active slot but multiport sent all its data */ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!active) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (flags & IO_DONE) ? 1 : 0; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return false if invalid device code received */ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return invalid ? 0 : 1; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns whether the multiport was placed into digital mode and 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * able to communicate its state successfully. 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int multiport_init(struct grip_mp *grip) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dig_mode, initialized = 0, tries = 0; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 packet; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dig_mode = dig_mode_start(grip->gameport, &packet); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!dig_mode && tries < 4) { 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dig_mode = dig_mode_start(grip->gameport, &packet); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tries++; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dig_mode) 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("multiport_init(): digital mode activated.\n"); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("multiport_init(): unable to activate digital mode.\n"); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get packets, store multiport state, and check state's validity */ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (tries = 0; tries < 4096; tries++) { 49717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (slots_valid(grip)) { 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initialized = 1; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("multiport_init(): initialized == %d\n", initialized); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return initialized; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reports joystick state to the linux input layer. 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void report_slot(struct grip_mp *grip, int slot) 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 51217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct grip_port *port = grip->port[slot]; 51317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov int i; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store button states with linux input driver */ 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 51817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store axis states with linux driver */ 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_report_abs(port->dev, ABS_X, port->xaxes); 52317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_report_abs(port->dev, ABS_Y, port->yaxes); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tell the receiver of the events to process them */ 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_sync(port->dev); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->dirty = 0; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the multiport state. 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void grip_poll(struct gameport *gameport) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct grip_mp *grip = gameport_get_drvdata(gameport); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, npkts, flags; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (npkts = 0; npkts < 4; npkts++) { 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = IO_RETRY; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 32; i++) { 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = get_and_decode_packet(grip, flags); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY)) 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & IO_DONE) 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 55317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (grip->port[i]->dirty) 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds report_slot(grip, i); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called when a joystick device file is opened 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int grip_open(struct input_dev *dev) 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5638715c1cfadf8cce24e79d254f95bd4a84c7741f0Dmitry Torokhov struct grip_mp *grip = input_get_drvdata(dev); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_start_polling(grip->gameport); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called when a joystick device file is closed 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void grip_close(struct input_dev *dev) 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5758715c1cfadf8cce24e79d254f95bd4a84c7741f0Dmitry Torokhov struct grip_mp *grip = input_get_drvdata(dev); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5778715c1cfadf8cce24e79d254f95bd4a84c7741f0Dmitry Torokhov gameport_stop_polling(grip->gameport); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tell the linux input layer about a newly plugged-in gamepad. 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhovstatic int register_slot(int slot, struct grip_mp *grip) 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 58617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct grip_port *port = grip->port[slot]; 58717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov struct input_dev *input_dev; 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j, t; 589127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov int err; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->dev = input_dev = input_allocate_device(); 59217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (!input_dev) 59317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov return -ENOMEM; 59417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov 59517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->name = grip_name[port->mode]; 59617dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.bustype = BUS_GAMEPORT; 59717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; 59817dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.product = 0x0100 + port->mode; 59917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->id.version = 0x0100; 600935e658e89678a7e3427b90cd7a1c86025d95bfeDmitry Torokhov input_dev->dev.parent = &grip->gameport->dev; 6018715c1cfadf8cce24e79d254f95bd4a84c7741f0Dmitry Torokhov 6028715c1cfadf8cce24e79d254f95bd4a84c7741f0Dmitry Torokhov input_set_drvdata(input_dev, grip); 60317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov 60417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->open = grip_open; 60517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_dev->close = grip_close; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6077b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60917dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++) 61017dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_set_abs_params(input_dev, t, -1, 1, 0, 0); 61117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov 61217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++) 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (t > 0) 61417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov set_bit(t, input_dev->keybit); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 616127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov err = input_register_device(port->dev); 617127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov if (err) { 618127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov input_free_device(port->dev); 619127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov return err; 620127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov } 621127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov 62217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov port->registered = 1; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (port->dirty) /* report initial state, if any */ 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds report_slot(grip, slot); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62717dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov return 0; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int grip_connect(struct gameport *gameport, struct gameport_driver *drv) 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct grip_mp *grip; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 635a97e148a8b8da8b04bc3e18ceb824a8f5f56d567Pekka Enberg if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL))) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds grip->gameport = gameport; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_drvdata(gameport, grip); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail1; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_poll_handler(gameport, grip_poll); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_poll_interval(gameport, 20); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!multiport_init(grip)) { 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENODEV; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail2; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) { 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* nothing plugged in */ 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENODEV; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail2; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail2: gameport_close(gameport); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail1: gameport_set_drvdata(gameport, NULL); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(grip); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void grip_disconnect(struct gameport *gameport) 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct grip_mp *grip = gameport_get_drvdata(gameport); 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) 67417dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (grip->port[i]->registered) 67517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_unregister_device(grip->port[i]->dev); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_close(gameport); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_set_drvdata(gameport, NULL); 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(grip); 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct gameport_driver grip_drv = { 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "grip_mp", 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = DRIVER_DESC, 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .connect = grip_connect, 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = grip_disconnect, 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init grip_init(void) 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6922547203d583cc267b98f518d5d93e3a0469d8f62Dmitry Torokhov return gameport_register_driver(&grip_drv); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit grip_exit(void) 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gameport_unregister_driver(&grip_drv); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(grip_init); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(grip_exit); 702