vserver 2.0 rc7
[linux-2.6.git] / drivers / input / joystick / sidewinder.c
index b29d576..47144a7 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * $Id: sidewinder.c,v 1.29 2002/01/22 20:28:51 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *  Copyright (c) 1998-2005 Vojtech Pavlik
  */
 
 /*
 #include <linux/input.h>
 #include <linux/gameport.h>
 
+#define DRIVER_DESC    "Microsoft SideWinder joystick family driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Microsoft SideWinder joystick family driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -45,18 +45,18 @@ MODULE_LICENSE("GPL");
  * as well as break everything.
  */
 
-/* #define SW_DEBUG */
+#undef SW_DEBUG
+#undef SW_DEBUG_DATA
 
-#define SW_START       400     /* The time we wait for the first bit [400 us] */
-#define SW_STROBE      45      /* Max time per bit [45 us] */
-#define SW_TIMEOUT     4000    /* Wait for everything to settle [4 ms] */
+#define SW_START       600     /* The time we wait for the first bit [600 us] */
+#define SW_STROBE      60      /* Max time per bit [60 us] */
+#define SW_TIMEOUT     6       /* Wait for everything to settle [6 ms] */
 #define SW_KICK                45      /* Wait after A0 fall till kick [45 us] */
 #define SW_END         8       /* Number of bits before end of packet to kick */
 #define SW_FAIL                16      /* Number of packet read errors to fail and reinitialize */
 #define SW_BAD         2       /* Number of packet read errors to switch off 3d Pro optimization */
 #define SW_OK          64      /* Number of packet read successes to switch optimization back on */
 #define SW_LENGTH      512     /* Max number of bits in a packet */
-#define SW_REFRESH     HZ/50   /* Time to wait between updates of joystick data [20 ms] */
 
 #ifdef SW_DEBUG
 #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
@@ -113,7 +113,6 @@ static struct {
 
 struct sw {
        struct gameport *gameport;
-       struct timer_list timer;
        struct input_dev dev[4];
        char name[64];
        char phys[4][32];
@@ -125,7 +124,6 @@ struct sw {
        int ok;
        int reads;
        int bads;
-       int used;
 };
 
 /*
@@ -141,7 +139,7 @@ static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int len
        unsigned char pending, u, v;
 
        i = -id;                                                /* Don't care about data, only want ID */
-       timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0; /* Set up global timeout for ID packet */
+       timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 0; /* Set up global timeout for ID packet */
        kick = id ? gameport_time(gameport, SW_KICK) : 0;       /* Set up kick timeout for ID packet */
        start = gameport_time(gameport, SW_START);
        strobe = gameport_time(gameport, SW_STROBE);
@@ -160,7 +158,8 @@ static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int len
                v = gameport_read(gameport);
        } while (!(~v & u & 0x10) && (bitout > 0));             /* Wait for first falling edge on clock */
 
-       if (bitout > 0) bitout = strobe;                        /* Extend time if not timed out */
+       if (bitout > 0)
+               bitout = strobe;                                /* Extend time if not timed out */
 
        while ((timeout > 0 || bitout > 0) && (i < length)) {
 
@@ -194,7 +193,7 @@ static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int len
 
        local_irq_restore(flags);                                       /* Done - relax */
 
-#ifdef SW_DEBUG
+#ifdef SW_DEBUG_DATA
        {
                int j;
                printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
@@ -249,7 +248,7 @@ static void sw_init_digital(struct gameport *gameport)
        i = 0;
         do {
                 gameport_trigger(gameport);                    /* Trigger */
-               t = gameport_time(gameport, SW_TIMEOUT);
+               t = gameport_time(gameport, SW_TIMEOUT * 1000);
                while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */
                 udelay(seq[i]);                                        /* Delay magic time */
         } while (seq[++i]);
@@ -266,6 +265,7 @@ static void sw_init_digital(struct gameport *gameport)
 static int sw_parity(__u64 t)
 {
        int x = t ^ (t >> 32);
+
        x ^= x >> 16;
        x ^= x >> 8;
        x ^= x >> 4;
@@ -307,7 +307,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw)
 
                case SW_ID_3DP:
 
-                       if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
+                       if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8)
+                               return -1;
 
                        input_report_abs(dev, ABS_X,        (GB( 3,3) << 7) | GB(16,7));
                        input_report_abs(dev, ABS_Y,        (GB( 0,3) << 7) | GB(24,7));
@@ -331,7 +332,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw)
 
                        for (i = 0; i < sw->number; i ++) {
 
-                               if (sw_parity(GB(i*15,15))) return -1;
+                               if (sw_parity(GB(i*15,15)))
+                                       return -1;
 
                                input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
                                input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
@@ -347,7 +349,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw)
                case SW_ID_PP:
                case SW_ID_FFP:
 
-                       if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
+                       if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8)
+                               return -1;
 
                        input_report_abs(dev, ABS_X,        GB( 9,10));
                        input_report_abs(dev, ABS_Y,        GB(19,10));
@@ -366,7 +369,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw)
 
                case SW_ID_FSP:
 
-                       if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
+                       if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8)
+                               return -1;
 
                        input_report_abs(dev, ABS_X,        GB( 0,10));
                        input_report_abs(dev, ABS_Y,        GB(16,10));
@@ -389,7 +393,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw)
 
                case SW_ID_FFW:
 
-                       if (!sw_parity(GB(0,33))) return -1;
+                       if (!sw_parity(GB(0,33)))
+                               return -1;
 
                        input_report_abs(dev, ABS_RX,       GB( 0,10));
                        input_report_abs(dev, ABS_RUDDER,   GB(10, 6));
@@ -466,19 +471,20 @@ static int sw_read(struct sw *sw)
                sw->length = 66;
        }
 
-       if (sw->fail < SW_FAIL) return -1;                                      /* Not enough, don't reinitialize yet */
+       if (sw->fail < SW_FAIL)
+               return -1;                                                      /* Not enough, don't reinitialize yet */
 
        printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s"
                " - reinitializing joystick.\n", sw->gameport->phys);
 
        if (!i && sw->type == SW_ID_3DP) {                                      /* 3D Pro can be in analog mode */
-               udelay(3 * SW_TIMEOUT);
+               mdelay(3 * SW_TIMEOUT);
                sw_init_digital(sw->gameport);
        }
 
-       udelay(SW_TIMEOUT);
+       mdelay(SW_TIMEOUT);
        i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0);                    /* Read normal data packet */
-       udelay(SW_TIMEOUT);
+       mdelay(SW_TIMEOUT);
        sw_read_packet(sw->gameport, buf, SW_LENGTH, i);                        /* Read ID packet, this initializes the stick */
 
        sw->fail = SW_FAIL;
@@ -486,28 +492,28 @@ static int sw_read(struct sw *sw)
        return -1;
 }
 
-static void sw_timer(unsigned long private)
+static void sw_poll(struct gameport *gameport)
 {
-       struct sw *sw = (void *) private;
+       struct sw *sw = gameport_get_drvdata(gameport);
 
        sw->reads++;
-       if (sw_read(sw)) sw->bads++;
-       mod_timer(&sw->timer, jiffies + SW_REFRESH);
+       if (sw_read(sw))
+               sw->bads++;
 }
 
 static int sw_open(struct input_dev *dev)
 {
        struct sw *sw = dev->private;
-       if (!sw->used++)
-               mod_timer(&sw->timer, jiffies + SW_REFRESH);
+
+       gameport_start_polling(sw->gameport);
        return 0;
 }
 
 static void sw_close(struct input_dev *dev)
 {
        struct sw *sw = dev->private;
-       if (!--sw->used)
-               del_timer(&sw->timer);
+
+       gameport_stop_polling(sw->gameport);
 }
 
 /*
@@ -561,7 +567,10 @@ static int sw_guess_mode(unsigned char *buf, int len)
 {
        int i;
        unsigned char xor = 0;
-       for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
+
+       for (i = 1; i < len; i++)
+               xor |= (buf[i - 1] ^ buf[i]) & 6;
+
        return !!xor * 2 + 1;
 }
 
@@ -569,10 +578,11 @@ static int sw_guess_mode(unsigned char *buf, int len)
  * sw_connect() probes for SideWinder type joysticks.
  */
 
-static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
        struct sw *sw;
        int i, j, k, l;
+       int err;
        unsigned char *buf = NULL;      /* [SW_LENGTH] */
        unsigned char *idbuf = NULL;    /* [SW_LENGTH] */
        unsigned char m = 1;
@@ -580,50 +590,55 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
 
        comment[0] = 0;
 
-       if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
-       memset(sw, 0, sizeof(struct sw));
-
+       sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL);
        buf = kmalloc(SW_LENGTH, GFP_KERNEL);
        idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
-       if (!buf || !idbuf)
+       if (!sw || !buf || !idbuf) {
+               err = -ENOMEM;
                goto fail1;
-
-       gameport->private = sw;
+       }
 
        sw->gameport = gameport;
-       init_timer(&sw->timer);
-       sw->timer.data = (long) sw;
-       sw->timer.function = sw_timer;
 
-       if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+       gameport_set_drvdata(gameport, sw);
+
+       err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+       if (err)
                goto fail1;
 
        dbg("Init 0: Opened %s, io %#x, speed %d",
                gameport->phys, gameport->io, gameport->speed);
 
        i = sw_read_packet(gameport, buf, SW_LENGTH, 0);                /* Read normal packet */
-       udelay(SW_TIMEOUT);
+       msleep(SW_TIMEOUT);
        dbg("Init 1: Mode %d. Length %d.", m , i);
 
        if (!i) {                                                       /* No data. 3d Pro analog mode? */
                sw_init_digital(gameport);                              /* Switch to digital */
-               udelay(SW_TIMEOUT);
+               msleep(SW_TIMEOUT);
                i = sw_read_packet(gameport, buf, SW_LENGTH, 0);        /* Retry reading packet */
-               udelay(SW_TIMEOUT);
+               msleep(SW_TIMEOUT);
                dbg("Init 1b: Length %d.", i);
-               if (!i) goto fail2;                                     /* No data -> FAIL */
+               if (!i) {                                               /* No data -> FAIL */
+                       err = -ENODEV;
+                       goto fail2;
+               }
        }
 
        j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);              /* Read ID. This initializes the stick */
        m |= sw_guess_mode(idbuf, j);                                   /* ID packet should carry mode info [3DP] */
-       dbg("Init 2: Mode %d. ID Length %d.", m , j);
+       dbg("Init 2: Mode %d. ID Length %d.", m, j);
 
-       if (!j) {                                                       /* Read ID failed. Happens in 1-bit mode on PP */
-               udelay(SW_TIMEOUT);
+       if (j <= 0) {                                                   /* Read ID failed. Happens in 1-bit mode on PP */
+               msleep(SW_TIMEOUT);
                i = sw_read_packet(gameport, buf, SW_LENGTH, 0);        /* Retry reading packet */
+               m |= sw_guess_mode(buf, i);
                dbg("Init 2b: Mode %d. Length %d.", m, i);
-               if (!i) goto fail2;
-               udelay(SW_TIMEOUT);
+               if (!i) {
+                       err = -ENODEV;
+                       goto fail2;
+               }
+               msleep(SW_TIMEOUT);
                j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);      /* Retry reading ID */
                dbg("Init 2c: ID Length %d.", j);
        }
@@ -634,7 +649,7 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
 
        do {
                k--;
-               udelay(SW_TIMEOUT);
+               msleep(SW_TIMEOUT);
                i = sw_read_packet(gameport, buf, SW_LENGTH, 0);        /* Read data packet */
                dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
 
@@ -686,13 +701,14 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
                        }
                }
 
-       } while (k && (sw->type == -1));
+       } while (k && sw->type == -1);
 
        if (sw->type == -1) {
                printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
                        "on %s, contact <vojtech@ucw.cz>\n", gameport->phys);
                sw_print_packet("ID", j * 3, idbuf, 3);
                sw_print_packet("Data", i * m, buf, m);
+               err = -ENODEV;
                goto fail2;
        }
 
@@ -701,6 +717,9 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
        sw_print_packet("Data", i * m, buf, m);
 #endif
 
+       gameport_set_poll_handler(gameport, sw_poll);
+       gameport_set_poll_interval(gameport, 20);
+
        k = i;
        l = j;
 
@@ -742,38 +761,46 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
                        sw->name, comment, gameport->phys, m, l, k);
        }
 
-       return;
+       return 0;
+
 fail2: gameport_close(gameport);
-fail1: kfree(sw);
+fail1: gameport_set_drvdata(gameport, NULL);
+       kfree(sw);
        kfree(buf);
        kfree(idbuf);
+       return err;
 }
 
 static void sw_disconnect(struct gameport *gameport)
 {
+       struct sw *sw = gameport_get_drvdata(gameport);
        int i;
 
-       struct sw *sw = gameport->private;
        for (i = 0; i < sw->number; i++)
                input_unregister_device(sw->dev + i);
        gameport_close(gameport);
+       gameport_set_drvdata(gameport, NULL);
        kfree(sw);
 }
 
-static struct gameport_dev sw_dev = {
-       .connect =      sw_connect,
-       .disconnect =   sw_disconnect,
+static struct gameport_driver sw_drv = {
+       .driver         = {
+               .name   = "sidewinder",
+       },
+       .description    = DRIVER_DESC,
+       .connect        = sw_connect,
+       .disconnect     = sw_disconnect,
 };
 
-int __init sw_init(void)
+static int __init sw_init(void)
 {
-       gameport_register_device(&sw_dev);
+       gameport_register_driver(&sw_drv);
        return 0;
 }
 
-void __exit sw_exit(void)
+static void __exit sw_exit(void)
 {
-       gameport_unregister_device(&sw_dev);
+       gameport_unregister_driver(&sw_drv);
 }
 
 module_init(sw_init);