Path: blob/master/drivers/input/joystick/grip_mp.c
15111 views
/*1* Driver for the Gravis Grip Multiport, a gamepad "hub" that2* connects up to four 9-pin digital gamepads/joysticks.3* Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5.4*5* Thanks to Chris Gassib for helpful advice.6*7* Copyright (c) 2002 Brian Bonnlander, Bill Soudan8* Copyright (c) 1998-2000 Vojtech Pavlik9*/1011#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/init.h>14#include <linux/slab.h>15#include <linux/gameport.h>16#include <linux/input.h>17#include <linux/delay.h>18#include <linux/proc_fs.h>19#include <linux/jiffies.h>2021#define DRIVER_DESC "Gravis Grip Multiport driver"2223MODULE_AUTHOR("Brian Bonnlander");24MODULE_DESCRIPTION(DRIVER_DESC);25MODULE_LICENSE("GPL");2627#ifdef GRIP_DEBUG28#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)29#else30#define dbg(format, arg...) do {} while (0)31#endif3233#define GRIP_MAX_PORTS 434/*35* Grip multiport state36*/3738struct grip_port {39struct input_dev *dev;40int mode;41int registered;4243/* individual gamepad states */44int buttons;45int xaxes;46int yaxes;47int dirty; /* has the state been updated? */48};4950struct grip_mp {51struct gameport *gameport;52struct grip_port *port[GRIP_MAX_PORTS];53int reads;54int bads;55};5657/*58* Multiport packet interpretation59*/6061#define PACKET_FULL 0x80000000 /* packet is full */62#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */63#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */64#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */65#define PACKET_MP_DONE 0x02000000 /* multiport done sending */6667/*68* Packet status code interpretation69*/7071#define IO_GOT_PACKET 0x0100 /* Got a packet */72#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */73#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */74#define IO_DONE 0x1000 /* Multiport is done sending packets */75#define IO_RETRY 0x4000 /* Try again later to get packet */76#define IO_RESET 0x8000 /* Force multiport to resend all packets */7778/*79* Gamepad configuration data. Other 9-pin digital joystick devices80* may work with the multiport, so this may not be an exhaustive list!81* Commodore 64 joystick remains untested.82*/8384#define GRIP_INIT_DELAY 2000 /* 2 ms */8586#define GRIP_MODE_NONE 087#define GRIP_MODE_RESET 188#define GRIP_MODE_GP 289#define GRIP_MODE_C64 39091static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };92static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 };9394static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };95static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };9697static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };98static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };99100static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };101102static const int init_seq[] = {1031, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,1041, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,1051, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,1060, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };107108/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */109110static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };111112static int register_slot(int i, struct grip_mp *grip);113114/*115* Returns whether an odd or even number of bits are on in pkt.116*/117118static int bit_parity(u32 pkt)119{120int x = pkt ^ (pkt >> 16);121x ^= x >> 8;122x ^= x >> 4;123x ^= x >> 2;124x ^= x >> 1;125return x & 1;126}127128/*129* Poll gameport; return true if all bits set in 'onbits' are on and130* all bits set in 'offbits' are off.131*/132133static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)134{135int i, nloops;136137nloops = gameport_time(gp, u_sec);138for (i = 0; i < nloops; i++) {139*data = gameport_read(gp);140if ((*data & onbits) == onbits &&141(~(*data) & offbits) == offbits)142return 1;143}144dbg("gameport timed out after %d microseconds.\n", u_sec);145return 0;146}147148/*149* Gets a 28-bit packet from the multiport.150*151* After getting a packet successfully, commands encoded by sendcode may152* be sent to the multiport.153*154* The multiport clock value is reflected in gameport bit B4.155*156* Returns a packet status code indicating whether packet is valid, the transfer157* mode, and any error conditions.158*159* sendflags: current I/O status160* sendcode: data to send to the multiport if sendflags is nonzero161*/162163static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)164{165u8 raw_data; /* raw data from gameport */166u8 data_mask; /* packet data bits from raw_data */167u32 pkt; /* packet temporary storage */168int bits_per_read; /* num packet bits per gameport read */169int portvals = 0; /* used for port value sanity check */170int i;171172/* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */173174*packet = 0;175raw_data = gameport_read(gameport);176if (raw_data & 1)177return IO_RETRY;178179for (i = 0; i < 64; i++) {180raw_data = gameport_read(gameport);181portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */182}183184if (portvals == 1) { /* B4, B5 off */185raw_data = gameport_read(gameport);186portvals = raw_data & 0xf0;187188if (raw_data & 0x31)189return IO_RESET;190gameport_trigger(gameport);191192if (!poll_until(0x10, 0, 308, gameport, &raw_data))193return IO_RESET;194} else195return IO_RETRY;196197/* Determine packet transfer mode and prepare for packet construction. */198199if (raw_data & 0x20) { /* 3 data bits/read */200portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */201202if (portvals != 0xb)203return 0;204data_mask = 7;205bits_per_read = 3;206pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;207} else { /* 1 data bit/read */208data_mask = 1;209bits_per_read = 1;210pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;211}212213/* Construct a packet. Final data bits must be zero. */214215while (1) {216if (!poll_until(0, 0x10, 77, gameport, &raw_data))217return IO_RESET;218raw_data = (raw_data >> 5) & data_mask;219220if (pkt & PACKET_FULL)221break;222pkt = (pkt << bits_per_read) | raw_data;223224if (!poll_until(0x10, 0, 77, gameport, &raw_data))225return IO_RESET;226}227228if (raw_data)229return IO_RESET;230231/* If 3 bits/read used, drop from 30 bits to 28. */232233if (bits_per_read == 3) {234pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);235pkt = (pkt >> 2) | 0xf0000000;236}237238if (bit_parity(pkt) == 1)239return IO_RESET;240241/* Acknowledge packet receipt */242243if (!poll_until(0x30, 0, 77, gameport, &raw_data))244return IO_RESET;245246raw_data = gameport_read(gameport);247248if (raw_data & 1)249return IO_RESET;250251gameport_trigger(gameport);252253if (!poll_until(0, 0x20, 77, gameport, &raw_data))254return IO_RESET;255256/* Return if we just wanted the packet or multiport wants to send more */257258*packet = pkt;259if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))260return IO_GOT_PACKET;261262if (pkt & PACKET_MP_MORE)263return IO_GOT_PACKET | IO_RETRY;264265/* Multiport is done sending packets and is ready to receive data */266267if (!poll_until(0x20, 0, 77, gameport, &raw_data))268return IO_GOT_PACKET | IO_RESET;269270raw_data = gameport_read(gameport);271if (raw_data & 1)272return IO_GOT_PACKET | IO_RESET;273274/* Trigger gameport based on bits in sendcode */275276gameport_trigger(gameport);277do {278if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))279return IO_GOT_PACKET | IO_RESET;280281if (!poll_until(0x30, 0, 193, gameport, &raw_data))282return IO_GOT_PACKET | IO_RESET;283284if (raw_data & 1)285return IO_GOT_PACKET | IO_RESET;286287if (sendcode & 1)288gameport_trigger(gameport);289290sendcode >>= 1;291} while (sendcode);292293return IO_GOT_PACKET | IO_MODE_FAST;294}295296/*297* Disables and restores interrupts for mp_io(), which does the actual I/O.298*/299300static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)301{302int status;303unsigned long flags;304305local_irq_save(flags);306status = mp_io(gameport, sendflags, sendcode, packet);307local_irq_restore(flags);308309return status;310}311312/*313* Puts multiport into digital mode. Multiport LED turns green.314*315* Returns true if a valid digital packet was received, false otherwise.316*/317318static int dig_mode_start(struct gameport *gameport, u32 *packet)319{320int i;321int flags, tries = 0, bads = 0;322323for (i = 0; i < ARRAY_SIZE(init_seq); i++) { /* Send magic sequence */324if (init_seq[i])325gameport_trigger(gameport);326udelay(GRIP_INIT_DELAY);327}328329for (i = 0; i < 16; i++) /* Wait for multiport to settle */330udelay(GRIP_INIT_DELAY);331332while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */333334flags = multiport_io(gameport, IO_RESET, 0x27, packet);335336if (flags & IO_MODE_FAST)337return 1;338339if (flags & IO_RETRY)340tries++;341else342bads++;343}344return 0;345}346347/*348* Packet structure: B0-B15 => gamepad state349* B16-B20 => gamepad device type350* B21-B24 => multiport slot index (1-4)351*352* Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist.353*354* Returns the packet status.355*/356357static int get_and_decode_packet(struct grip_mp *grip, int flags)358{359struct grip_port *port;360u32 packet;361int joytype = 0;362int slot;363364/* Get a packet and check for validity */365366flags &= IO_RESET | IO_RETRY;367flags = multiport_io(grip->gameport, flags, 0, &packet);368grip->reads++;369370if (packet & PACKET_MP_DONE)371flags |= IO_DONE;372373if (flags && !(flags & IO_GOT_PACKET)) {374grip->bads++;375return flags;376}377378/* Ignore non-gamepad packets, e.g. multiport hardware version */379380slot = ((packet >> 21) & 0xf) - 1;381if ((slot < 0) || (slot > 3))382return flags;383384port = grip->port[slot];385386/*387* Handle "reset" packets, which occur at startup, and when gamepads388* are removed or plugged in. May contain configuration of a new gamepad.389*/390391joytype = (packet >> 16) & 0x1f;392if (!joytype) {393394if (port->registered) {395printk(KERN_INFO "grip_mp: removing %s, slot %d\n",396grip_name[port->mode], slot);397input_unregister_device(port->dev);398port->registered = 0;399}400dbg("Reset: grip multiport slot %d\n", slot);401port->mode = GRIP_MODE_RESET;402flags |= IO_SLOT_CHANGE;403return flags;404}405406/* Interpret a grip pad packet */407408if (joytype == 0x1f) {409410int dir = (packet >> 8) & 0xf; /* eight way directional value */411port->buttons = (~packet) & 0xff;412port->yaxes = ((axis_map[dir] >> 2) & 3) - 1;413port->xaxes = (axis_map[dir] & 3) - 1;414port->dirty = 1;415416if (port->mode == GRIP_MODE_RESET)417flags |= IO_SLOT_CHANGE;418419port->mode = GRIP_MODE_GP;420421if (!port->registered) {422dbg("New Grip pad in multiport slot %d.\n", slot);423if (register_slot(slot, grip)) {424port->mode = GRIP_MODE_RESET;425port->dirty = 0;426}427}428return flags;429}430431/* Handle non-grip device codes. For now, just print diagnostics. */432433{434static int strange_code = 0;435if (strange_code != joytype) {436printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");437printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);438strange_code = joytype;439}440}441return flags;442}443444/*445* Returns true if all multiport slot states appear valid.446*/447448static int slots_valid(struct grip_mp *grip)449{450int flags, slot, invalid = 0, active = 0;451452flags = get_and_decode_packet(grip, 0);453if (!(flags & IO_GOT_PACKET))454return 0;455456for (slot = 0; slot < 4; slot++) {457if (grip->port[slot]->mode == GRIP_MODE_RESET)458invalid = 1;459if (grip->port[slot]->mode != GRIP_MODE_NONE)460active = 1;461}462463/* Return true if no active slot but multiport sent all its data */464if (!active)465return (flags & IO_DONE) ? 1 : 0;466467/* Return false if invalid device code received */468return invalid ? 0 : 1;469}470471/*472* Returns whether the multiport was placed into digital mode and473* able to communicate its state successfully.474*/475476static int multiport_init(struct grip_mp *grip)477{478int dig_mode, initialized = 0, tries = 0;479u32 packet;480481dig_mode = dig_mode_start(grip->gameport, &packet);482while (!dig_mode && tries < 4) {483dig_mode = dig_mode_start(grip->gameport, &packet);484tries++;485}486487if (dig_mode)488dbg("multiport_init(): digital mode activated.\n");489else {490dbg("multiport_init(): unable to activate digital mode.\n");491return 0;492}493494/* Get packets, store multiport state, and check state's validity */495for (tries = 0; tries < 4096; tries++) {496if (slots_valid(grip)) {497initialized = 1;498break;499}500}501dbg("multiport_init(): initialized == %d\n", initialized);502return initialized;503}504505/*506* Reports joystick state to the linux input layer.507*/508509static void report_slot(struct grip_mp *grip, int slot)510{511struct grip_port *port = grip->port[slot];512int i;513514/* Store button states with linux input driver */515516for (i = 0; i < 8; i++)517input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1);518519/* Store axis states with linux driver */520521input_report_abs(port->dev, ABS_X, port->xaxes);522input_report_abs(port->dev, ABS_Y, port->yaxes);523524/* Tell the receiver of the events to process them */525526input_sync(port->dev);527528port->dirty = 0;529}530531/*532* Get the multiport state.533*/534535static void grip_poll(struct gameport *gameport)536{537struct grip_mp *grip = gameport_get_drvdata(gameport);538int i, npkts, flags;539540for (npkts = 0; npkts < 4; npkts++) {541flags = IO_RETRY;542for (i = 0; i < 32; i++) {543flags = get_and_decode_packet(grip, flags);544if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))545break;546}547if (flags & IO_DONE)548break;549}550551for (i = 0; i < 4; i++)552if (grip->port[i]->dirty)553report_slot(grip, i);554}555556/*557* Called when a joystick device file is opened558*/559560static int grip_open(struct input_dev *dev)561{562struct grip_mp *grip = input_get_drvdata(dev);563564gameport_start_polling(grip->gameport);565return 0;566}567568/*569* Called when a joystick device file is closed570*/571572static void grip_close(struct input_dev *dev)573{574struct grip_mp *grip = input_get_drvdata(dev);575576gameport_stop_polling(grip->gameport);577}578579/*580* Tell the linux input layer about a newly plugged-in gamepad.581*/582583static int register_slot(int slot, struct grip_mp *grip)584{585struct grip_port *port = grip->port[slot];586struct input_dev *input_dev;587int j, t;588int err;589590port->dev = input_dev = input_allocate_device();591if (!input_dev)592return -ENOMEM;593594input_dev->name = grip_name[port->mode];595input_dev->id.bustype = BUS_GAMEPORT;596input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;597input_dev->id.product = 0x0100 + port->mode;598input_dev->id.version = 0x0100;599input_dev->dev.parent = &grip->gameport->dev;600601input_set_drvdata(input_dev, grip);602603input_dev->open = grip_open;604input_dev->close = grip_close;605606input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);607608for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)609input_set_abs_params(input_dev, t, -1, 1, 0, 0);610611for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++)612if (t > 0)613set_bit(t, input_dev->keybit);614615err = input_register_device(port->dev);616if (err) {617input_free_device(port->dev);618return err;619}620621port->registered = 1;622623if (port->dirty) /* report initial state, if any */624report_slot(grip, slot);625626return 0;627}628629static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)630{631struct grip_mp *grip;632int err;633634if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))635return -ENOMEM;636637grip->gameport = gameport;638639gameport_set_drvdata(gameport, grip);640641err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);642if (err)643goto fail1;644645gameport_set_poll_handler(gameport, grip_poll);646gameport_set_poll_interval(gameport, 20);647648if (!multiport_init(grip)) {649err = -ENODEV;650goto fail2;651}652653if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) {654/* nothing plugged in */655err = -ENODEV;656goto fail2;657}658659return 0;660661fail2: gameport_close(gameport);662fail1: gameport_set_drvdata(gameport, NULL);663kfree(grip);664return err;665}666667static void grip_disconnect(struct gameport *gameport)668{669struct grip_mp *grip = gameport_get_drvdata(gameport);670int i;671672for (i = 0; i < 4; i++)673if (grip->port[i]->registered)674input_unregister_device(grip->port[i]->dev);675gameport_close(gameport);676gameport_set_drvdata(gameport, NULL);677kfree(grip);678}679680static struct gameport_driver grip_drv = {681.driver = {682.name = "grip_mp",683},684.description = DRIVER_DESC,685.connect = grip_connect,686.disconnect = grip_disconnect,687};688689static int __init grip_init(void)690{691return gameport_register_driver(&grip_drv);692}693694static void __exit grip_exit(void)695{696gameport_unregister_driver(&grip_drv);697}698699module_init(grip_init);700module_exit(grip_exit);701702703