Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / input / joystick / grip_mp.c
index 8e19496..6243894 100644 (file)
 #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
@@ -30,25 +33,28 @@ MODULE_LICENSE("GPL");
 #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? */
 };
 
 /*
@@ -79,23 +85,22 @@ struct grip_mp {
  */
 
 #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[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
-static int *grip_btn[] = { NULL, NULL, 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,
@@ -105,7 +110,9 @@ static const int init_seq[] = {
 
 /* 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.
@@ -170,7 +177,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
        *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);
@@ -352,10 +359,10 @@ static int dig_mode_start(struct gameport *gameport, u32 *packet)
 
 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 */
 
@@ -377,6 +384,8 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags)
        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.
@@ -385,14 +394,14 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags)
        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;
        }
@@ -402,17 +411,17 @@ static int get_and_decode_packet(struct grip_mp *grip, int 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);
                }
@@ -445,9 +454,9 @@ static int slots_valid(struct grip_mp *grip)
                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;
        }
 
@@ -476,15 +485,15 @@ static int multiport_init(struct grip_mp *grip)
        }
 
        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;
                }
@@ -499,32 +508,33 @@ static int multiport_init(struct grip_mp *grip)
 
 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++) {
@@ -539,7 +549,7 @@ static void get_and_report_mp_state(struct grip_mp *grip)
        }
 
        for (i = 0; i < 4; i++)
-               if (grip->dirty[i])
+               if (grip->port[i]->dirty)
                        report_slot(grip, i);
 }
 
@@ -550,8 +560,8 @@ static void get_and_report_mp_state(struct grip_mp *grip)
 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;
 }
 
@@ -562,111 +572,122 @@ static int grip_open(struct input_dev *dev)
 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;
 
-       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);
+       input_register_device(port->dev);
+       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);