fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / input / joystick / sidewinder.c
index 084643d..e58b22c 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/init.h>
 #include <linux/input.h>
 #include <linux/gameport.h>
+#include <linux/jiffies.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 +46,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,8 +114,7 @@ static struct {
 
 struct sw {
        struct gameport *gameport;
-       struct timer_list timer;
-       struct input_dev dev[4];
+       struct input_dev *dev[4];
        char name[64];
        char phys[4][32];
        int length;
@@ -125,7 +125,6 @@ struct sw {
        int ok;
        int reads;
        int bads;
-       int used;
 };
 
 /*
@@ -141,7 +140,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 +159,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 +194,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 +249,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 +266,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;
@@ -301,13 +302,16 @@ static int sw_check(__u64 t)
 static int sw_parse(unsigned char *buf, struct sw *sw)
 {
        int hat, i, j;
-       struct input_dev *dev = sw->dev;
+       struct input_dev *dev;
 
        switch (sw->type) {
 
                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;
+
+                       dev = sw->dev[0];
 
                        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,15 +335,16 @@ 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));
+                               input_report_abs(sw->dev[i], ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
+                               input_report_abs(sw->dev[i], ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
 
                                for (j = 0; j < 10; j++)
-                                       input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
+                                       input_report_key(sw->dev[i], sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
 
-                               input_sync(dev + i);
+                               input_sync(sw->dev[i]);
                        }
 
                        return 0;
@@ -347,8 +352,10 @@ 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;
 
+                       dev = sw->dev[0];
                        input_report_abs(dev, ABS_X,        GB( 9,10));
                        input_report_abs(dev, ABS_Y,        GB(19,10));
                        input_report_abs(dev, ABS_RZ,       GB(36, 6));
@@ -366,8 +373,10 @@ 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;
 
+                       dev = sw->dev[0];
                        input_report_abs(dev, ABS_X,        GB( 0,10));
                        input_report_abs(dev, ABS_Y,        GB(16,10));
                        input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
@@ -389,8 +398,10 @@ 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;
 
+                       dev = sw->dev[0];
                        input_report_abs(dev, ABS_RX,       GB( 0,10));
                        input_report_abs(dev, ABS_RUDDER,   GB(10, 6));
                        input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
@@ -466,19 +477,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 +498,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);
 }
 
 /*
@@ -529,7 +541,7 @@ static void sw_print_packet(char *name, int length, unsigned char *buf, char bit
  * Unfortunately I don't know how to do this for the other SW types.
  */
 
-static void sw_3dp_id(unsigned char *buf, char *comment)
+static void sw_3dp_id(unsigned char *buf, char *comment, size_t size)
 {
        int i;
        char pnp[8], rev[9];
@@ -542,7 +554,7 @@ static void sw_3dp_id(unsigned char *buf, char *comment)
 
        pnp[7] = rev[8] = 0;
 
-       sprintf(comment, " [PnP %d.%02d id %s rev %s]",
+       snprintf(comment, size, " [PnP %d.%02d id %s rev %s]",
                (int) ((sw_get_bits(buf, 8, 6, 1) << 6) |               /* Two 6-bit values */
                        sw_get_bits(buf, 16, 6, 1)) / 100,
                (int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
@@ -561,7 +573,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 +584,12 @@ 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;
+       struct input_dev *input_dev;
        int i, j, k, l;
+       int err = 0;
        unsigned char *buf = NULL;      /* [SW_LENGTH] */
        unsigned char *idbuf = NULL;    /* [SW_LENGTH] */
        unsigned char m = 1;
@@ -580,50 +597,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 = kzalloc(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 +656,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);
 
@@ -673,7 +695,7 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
                                                sw->type = SW_ID_FFP;
                                                sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
                                        } else
-                                       sw->type = SW_ID_PP;
+                                               sw->type = SW_ID_PP;
                                        break;
                                case 66:
                                        sw->bits = 3;
@@ -681,18 +703,20 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
                                        sw->length = 22;
                                case 64:
                                        sw->type = SW_ID_3DP;
-                                       if (j == 160) sw_3dp_id(idbuf, comment);
+                                       if (j == 160)
+                                               sw_3dp_id(idbuf, comment, sizeof(comment));
                                        break;
                        }
                }
 
-       } 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,79 +725,105 @@ 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;
 
        for (i = 0; i < sw->number; i++) {
                int bits, code;
 
-               sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
-               sprintf(sw->phys[i], "%s/input%d", gameport->phys, i);
+               snprintf(sw->name, sizeof(sw->name),
+                        "Microsoft SideWinder %s", sw_name[sw->type]);
+               snprintf(sw->phys[i], sizeof(sw->phys[i]),
+                        "%s/input%d", gameport->phys, i);
 
-               sw->dev[i].private = sw;
+               sw->dev[i] = input_dev = input_allocate_device();
+               if (!input_dev) {
+                       err = -ENOMEM;
+                       goto fail3;
+               }
 
-               sw->dev[i].open = sw_open;
-               sw->dev[i].close = sw_close;
+               input_dev->name = sw->name;
+               input_dev->phys = sw->phys[i];
+               input_dev->id.bustype = BUS_GAMEPORT;
+               input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
+               input_dev->id.product = sw->type;
+               input_dev->id.version = 0x0100;
+               input_dev->cdev.dev = &gameport->dev;
+               input_dev->private = sw;
 
-               sw->dev[i].name = sw->name;
-               sw->dev[i].phys = sw->phys[i];
-               sw->dev[i].id.bustype = BUS_GAMEPORT;
-               sw->dev[i].id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
-               sw->dev[i].id.product = sw->type;
-               sw->dev[i].id.version = 0x0100;
+               input_dev->open = sw_open;
+               input_dev->close = sw_close;
 
-               sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+               input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
                for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
                        code = sw_abs[sw->type][j];
-                       set_bit(code, sw->dev[i].absbit);
-                       sw->dev[i].absmax[code] = (1 << bits) - 1;
-                       sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
-                       sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
+                       set_bit(code, input_dev->absbit);
+                       input_dev->absmax[code] = (1 << bits) - 1;
+                       input_dev->absmin[code] = (bits == 1) ? -1 : 0;
+                       input_dev->absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
                        if (code != ABS_THROTTLE)
-                               sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
+                               input_dev->absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
                }
 
                for (j = 0; (code = sw_btn[sw->type][j]); j++)
-                       set_bit(code, sw->dev[i].keybit);
+                       set_bit(code, input_dev->keybit);
+
+               dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k);
 
-               input_register_device(sw->dev + i);
-               printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n",
-                       sw->name, comment, gameport->phys, m, l, k);
+               err = input_register_device(sw->dev[i]);
+               if (err)
+                       goto fail4;
        }
 
-       return;
-fail2: gameport_close(gameport);
-fail1: kfree(sw);
-       kfree(buf);
+ out:  kfree(buf);
        kfree(idbuf);
+
+       return err;
+
+ fail4:        input_free_device(sw->dev[i]);
+ fail3:        while (--i >= 0)
+               input_unregister_device(sw->dev[i]);
+ fail2:        gameport_close(gameport);
+ fail1:        gameport_set_drvdata(gameport, NULL);
+       kfree(sw);
+       goto out;
 }
 
 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);
+               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",
+               .owner  = THIS_MODULE,
+       },
+       .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);