#include <linux/input.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
+#include <linux/jiffies.h>
+
+#define DRIVER_DESC "Gravis Grip Multiport driver"
MODULE_AUTHOR("Brian Bonnlander");
-MODULE_DESCRIPTION("Gravis Grip Multiport driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
#ifdef GRIP_DEBUG
#define dbg(format, arg...) do {} while (0)
#endif
+#define GRIP_MAX_PORTS 4
/*
* Grip multiport state
*/
+struct grip_port {
+ struct input_dev *dev;
+ int mode;
+ int registered;
+
+ /* individual gamepad states */
+ int buttons;
+ int xaxes;
+ int yaxes;
+ int dirty; /* has the state been updated? */
+};
+
struct grip_mp {
struct gameport *gameport;
- struct timer_list timer;
- struct input_dev dev[4];
- int mode[4];
- int registered[4];
- int used;
+ struct grip_port *port[GRIP_MAX_PORTS];
int reads;
int bads;
-
- /* individual gamepad states */
- int buttons[4];
- int xaxes[4];
- int yaxes[4];
- int dirty[4]; /* has the state been updated? */
};
/*
*/
#define GRIP_INIT_DELAY 2000 /* 2 ms */
-#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
#define GRIP_MODE_NONE 0
#define GRIP_MODE_RESET 1
#define GRIP_MODE_GP 2
#define GRIP_MODE_C64 3
-static int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
-static int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
+static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
+static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
-static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
-static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
+static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
+static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
-static int *grip_abs[] = { 0, 0, grip_abs_gp, grip_abs_c64 };
-static int *grip_btn[] = { 0, 0, grip_btn_gp, grip_btn_c64 };
+static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
+static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
-static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
+static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
static const int init_seq[] = {
1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
-static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };
+static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };
+
+static int register_slot(int i, struct grip_mp *grip);
/*
* Returns whether an odd or even number of bits are on in pkt.
*packet = 0;
raw_data = gameport_read(gameport);
if (raw_data & 1)
- return IO_RETRY;
+ return IO_RETRY;
for (i = 0; i < 64; i++) {
raw_data = gameport_read(gameport);
static int get_and_decode_packet(struct grip_mp *grip, int flags)
{
+ struct grip_port *port;
u32 packet;
int joytype = 0;
- int slot = 0;
- static void register_slot(int i, struct grip_mp *grip);
+ int slot;
/* Get a packet and check for validity */
if ((slot < 0) || (slot > 3))
return flags;
+ port = grip->port[slot];
+
/*
* Handle "reset" packets, which occur at startup, and when gamepads
* are removed or plugged in. May contain configuration of a new gamepad.
joytype = (packet >> 16) & 0x1f;
if (!joytype) {
- if (grip->registered[slot]) {
+ if (port->registered) {
printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
- grip_name[grip->mode[slot]], slot);
- input_unregister_device(grip->dev + slot);
- grip->registered[slot] = 0;
+ grip_name[port->mode], slot);
+ input_unregister_device(port->dev);
+ port->registered = 0;
}
dbg("Reset: grip multiport slot %d\n", slot);
- grip->mode[slot] = GRIP_MODE_RESET;
+ port->mode = GRIP_MODE_RESET;
flags |= IO_SLOT_CHANGE;
return flags;
}
if (joytype == 0x1f) {
int dir = (packet >> 8) & 0xf; /* eight way directional value */
- grip->buttons[slot] = (~packet) & 0xff;
- grip->yaxes[slot] = ((axis_map[dir] >> 2) & 3) - 1;
- grip->xaxes[slot] = (axis_map[dir] & 3) - 1;
- grip->dirty[slot] = 1;
+ port->buttons = (~packet) & 0xff;
+ port->yaxes = ((axis_map[dir] >> 2) & 3) - 1;
+ port->xaxes = (axis_map[dir] & 3) - 1;
+ port->dirty = 1;
- if (grip->mode[slot] == GRIP_MODE_RESET)
+ if (port->mode == GRIP_MODE_RESET)
flags |= IO_SLOT_CHANGE;
- grip->mode[slot] = GRIP_MODE_GP;
+ port->mode = GRIP_MODE_GP;
- if (!grip->registered[slot]) {
+ if (!port->registered) {
dbg("New Grip pad in multiport slot %d.\n", slot);
- register_slot(slot, grip);
+ if (register_slot(slot, grip)) {
+ port->mode = GRIP_MODE_RESET;
+ port->dirty = 0;
+ }
}
return flags;
}
return 0;
for (slot = 0; slot < 4; slot++) {
- if (grip->mode[slot] == GRIP_MODE_RESET)
+ if (grip->port[slot]->mode == GRIP_MODE_RESET)
invalid = 1;
- if (grip->mode[slot] != GRIP_MODE_NONE)
+ if (grip->port[slot]->mode != GRIP_MODE_NONE)
active = 1;
}
}
if (dig_mode)
- dbg("multiport_init(): digital mode achieved.\n");
+ dbg("multiport_init(): digital mode activated.\n");
else {
- dbg("multiport_init(): unable to achieve digital mode.\n");
+ dbg("multiport_init(): unable to activate digital mode.\n");
return 0;
}
/* Get packets, store multiport state, and check state's validity */
for (tries = 0; tries < 4096; tries++) {
- if ( slots_valid(grip) ) {
+ if (slots_valid(grip)) {
initialized = 1;
break;
}
static void report_slot(struct grip_mp *grip, int slot)
{
- struct input_dev *dev = &(grip->dev[slot]);
- int i, buttons = grip->buttons[slot];
+ struct grip_port *port = grip->port[slot];
+ int i;
/* Store button states with linux input driver */
for (i = 0; i < 8; i++)
- input_report_key(dev, grip_btn_gp[i], (buttons >> i) & 1);
+ input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1);
/* Store axis states with linux driver */
- input_report_abs(dev, ABS_X, grip->xaxes[slot]);
- input_report_abs(dev, ABS_Y, grip->yaxes[slot]);
+ input_report_abs(port->dev, ABS_X, port->xaxes);
+ input_report_abs(port->dev, ABS_Y, port->yaxes);
/* Tell the receiver of the events to process them */
- input_sync(dev);
+ input_sync(port->dev);
- grip->dirty[slot] = 0;
+ port->dirty = 0;
}
/*
* Get the multiport state.
*/
-static void get_and_report_mp_state(struct grip_mp *grip)
+static void grip_poll(struct gameport *gameport)
{
+ struct grip_mp *grip = gameport_get_drvdata(gameport);
int i, npkts, flags;
for (npkts = 0; npkts < 4; npkts++) {
}
for (i = 0; i < 4; i++)
- if (grip->dirty[i])
+ if (grip->port[i]->dirty)
report_slot(grip, i);
}
static int grip_open(struct input_dev *dev)
{
struct grip_mp *grip = dev->private;
- if (!grip->used++)
- mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+
+ gameport_start_polling(grip->gameport);
return 0;
}
static void grip_close(struct input_dev *dev)
{
struct grip_mp *grip = dev->private;
- if (!--grip->used)
- del_timer(&grip->timer);
+
+ gameport_start_polling(grip->gameport);
}
/*
* Tell the linux input layer about a newly plugged-in gamepad.
*/
-static void register_slot(int slot, struct grip_mp *grip)
+static int register_slot(int slot, struct grip_mp *grip)
{
+ struct grip_port *port = grip->port[slot];
+ struct input_dev *input_dev;
int j, t;
+ int err;
- grip->dev[slot].private = grip;
- grip->dev[slot].open = grip_open;
- grip->dev[slot].close = grip_close;
- grip->dev[slot].name = grip_name[grip->mode[slot]];
- grip->dev[slot].id.bustype = BUS_GAMEPORT;
- grip->dev[slot].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
- grip->dev[slot].id.product = 0x0100 + grip->mode[slot];
- grip->dev[slot].id.version = 0x0100;
- grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) {
- set_bit(t, grip->dev[slot].absbit);
- grip->dev[slot].absmin[t] = -1;
- grip->dev[slot].absmax[t] = 1;
- }
+ port->dev = input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
- for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++)
- if (t > 0)
- set_bit(t, grip->dev[slot].keybit);
+ input_dev->name = grip_name[port->mode];
+ input_dev->id.bustype = BUS_GAMEPORT;
+ input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
+ input_dev->id.product = 0x0100 + port->mode;
+ input_dev->id.version = 0x0100;
+ input_dev->cdev.dev = &grip->gameport->dev;
+ input_dev->private = grip;
- input_register_device(grip->dev + slot);
- grip->registered[slot] = 1;
+ input_dev->open = grip_open;
+ input_dev->close = grip_close;
- if (grip->dirty[slot]) /* report initial state, if any */
- report_slot(grip, slot);
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- printk(KERN_INFO "grip_mp: added %s, slot %d\n",
- grip_name[grip->mode[slot]], slot);
-}
+ for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)
+ input_set_abs_params(input_dev, t, -1, 1, 0, 0);
-/*
- * Repeatedly polls the multiport and generates events.
- */
+ for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++)
+ if (t > 0)
+ set_bit(t, input_dev->keybit);
-static void grip_timer(unsigned long private)
-{
- struct grip_mp *grip = (void*) private;
- get_and_report_mp_state(grip);
- mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+ err = input_register_device(port->dev);
+ if (err) {
+ input_free_device(port->dev);
+ return err;
+ }
+
+ port->registered = 1;
+
+ if (port->dirty) /* report initial state, if any */
+ report_slot(grip, slot);
+
+ return 0;
}
-static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
{
struct grip_mp *grip;
+ int err;
+
+ if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
+ return -ENOMEM;
- if (!(grip = kmalloc(sizeof(struct grip_mp), GFP_KERNEL)))
- return;
- memset(grip, 0, sizeof(struct grip_mp));
- gameport->private = grip;
grip->gameport = gameport;
- init_timer(&grip->timer);
- grip->timer.data = (long) grip;
- grip->timer.function = grip_timer;
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ gameport_set_drvdata(gameport, grip);
+
+ err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+ if (err)
goto fail1;
- if (!multiport_init(grip))
+
+ gameport_set_poll_handler(gameport, grip_poll);
+ gameport_set_poll_interval(gameport, 20);
+
+ if (!multiport_init(grip)) {
+ err = -ENODEV;
goto fail2;
- if (!grip->mode[0] && !grip->mode[1] && /* nothing plugged in */
- !grip->mode[2] && !grip->mode[3])
+ }
+
+ if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) {
+ /* nothing plugged in */
+ err = -ENODEV;
goto fail2;
- return;
+ }
+
+ return 0;
fail2: gameport_close(gameport);
-fail1: kfree(grip);
+fail1: gameport_set_drvdata(gameport, NULL);
+ kfree(grip);
+ return err;
}
static void grip_disconnect(struct gameport *gameport)
{
+ struct grip_mp *grip = gameport_get_drvdata(gameport);
int i;
- struct grip_mp *grip = gameport->private;
for (i = 0; i < 4; i++)
- if (grip->registered[i])
- input_unregister_device(grip->dev + i);
+ if (grip->port[i]->registered)
+ input_unregister_device(grip->port[i]->dev);
gameport_close(gameport);
+ gameport_set_drvdata(gameport, NULL);
kfree(grip);
}
-static struct gameport_dev grip_dev = {
+static struct gameport_driver grip_drv = {
+ .driver = {
+ .name = "grip_mp",
+ },
+ .description = DRIVER_DESC,
.connect = grip_connect,
.disconnect = grip_disconnect,
};
-static int grip_init(void)
+static int __init grip_init(void)
{
- gameport_register_device(&grip_dev);
+ gameport_register_driver(&grip_drv);
return 0;
}
-static void grip_exit(void)
+static void __exit grip_exit(void)
{
- gameport_unregister_device(&grip_dev);
+ gameport_unregister_driver(&grip_drv);
}
module_init(grip_init);