Hi!

The attached patch fixes many different little bugs in the USB input,
joystick input and core input drivers maintained by me.

drivers/char/joystick/adi.c:
        Fix gamepad handling for Logitech ThunderPad Digital and WingMan Gamepad

drivers/char/joystick/gamecon.c
        Fix PSX gamepad support - patch by Nathan Hand

drivers/char/joystick/iforce.c
        Fix breakage caused by recent usb_submit_urb() changes

drivers/char/joystick/ns558.c
        Fix the already fixed 'oops on rmmod' problem in a slightly different way
        Fix another two possible causes for 'oops on rmmod'

drivers/char/joystick/sidewinder.c
        Fix a missing button for Microsoft ForceFeedback Wheel

drivers/char/joystick/tmdc.c
        Fix the ThrustMaster FragMaster by adding specific support,
        generic support isn't good enough

drivers/input/evdev.c
        Fix two possible overflow cases.
        Add event write() support, needed badly

drivers/input/joydev.c
        Fix two possible overflow cases.
        
drivers/input/mousedev.c
        Fix two possible overflow cases.
        Change 5-button support from GenPS/2 to ImExPS/2, making it
        finally useful with XFree (which only supports ImExPS/2 5-button mice)
        Add xmax and ymax module parameters, needed for binary distribution

drivers/usb/usbkbd.c
        Fix breakage caused by recent usb_submit_urb() changes

drivers/usb/usbmouse.c
        Unify the usb_submit_urb() fix to match usbkbd, wacom and others

drivers/usb/wacom.c
        Fix the Intuos 4DMouse and Intuos Lens tool behavior (James E. Blair)

The patch is against 2.4.0-test10-pre5.

TIA.

-- 
Vojtech Pavlik
SuSE Labs
diff -urN linux-test10-pre5-old/drivers/char/joystick/adi.c 
linux/drivers/char/joystick/adi.c
--- linux-test10-pre5-old/drivers/char/joystick/adi.c   Thu Jun 22 15:59:58 2000
+++ linux/drivers/char/joystick/adi.c   Thu Oct 26 23:02:11 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: adi.c,v 1.12 2000/06/03 20:18:52 vojtech Exp $
+ * $Id: adi.c,v 1.14 2000/10/23 07:28:57 vojtech Exp $
  *
  *  Copyright (c) 1998-2000 Vojtech Pavlik
  *
@@ -418,7 +418,7 @@
        adi->dev.private = port;
        adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-       for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++)
+       for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; 
+i++)
                set_bit(adi->abs[i], &adi->dev.absbit);
 
        for (i = 0; i < adi->buttons; i++)
@@ -431,7 +431,7 @@
 
        if (!adi->length) return;
 
-       for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++) {
+       for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; 
+i++) {
 
                t = adi->abs[i];
                x = adi->dev.abs[t];
diff -urN linux-test10-pre5-old/drivers/char/joystick/gamecon.c 
linux/drivers/char/joystick/gamecon.c
--- linux-test10-pre5-old/drivers/char/joystick/gamecon.c       Mon Aug 14 22:55:01 
2000
+++ linux/drivers/char/joystick/gamecon.c       Thu Oct 26 23:02:11 2000
@@ -1,11 +1,11 @@
 /*
- * $Id: gamecon.c,v 1.5 2000/06/25 09:56:58 vojtech Exp $
+ * $Id: gamecon.c,v 1.10 2000/08/19 19:51:02 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
  *  Based on the work of:
  *     Andree Borrmann         John Dahlstrom
- *     David Kuder
+ *     David Kuder             Nathan Hand
  *
  *  Sponsored by SuSE
  */
@@ -75,8 +75,7 @@
 static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
 
 static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem 
joystick",
-                               "Multisystem 2-button joystick", "N64 controller", 
"PSX pad",
-                               "PSX NegCon", "PSX Analog contoller" };
+                               "Multisystem 2-button joystick", "N64 controller", 
+"PSX controller" };
 /*
  * N64 support.
  */
@@ -205,22 +204,30 @@
 
 /*
  * PSX support
- */
-
-#define GC_PSX_DELAY   10
-#define GC_PSX_LENGTH  8       /* talk to the controller in bytes */
+ *
+ * See documentation at:
+ *     http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
+ *     http://www.gamesx.com/controldata/psxcont/psxcont.htm
+ *     ftp://milano.usal.es/pablo/
+ *     
+ */
+
+#define GC_PSX_DELAY   60              /* 60 usec */
+#define GC_PSX_LENGTH  8               /* talk to the controller in bytes */
+
+#define GC_PSX_MOUSE   1               /* Mouse */
+#define GC_PSX_NEGCON  2               /* NegCon */
+#define GC_PSX_NORMAL  4               /* Digital / Analog or Rumble in Digital mode  
+*/
+#define GC_PSX_ANALOG  5               /* Analog in Analog mode / Rumble in Green 
+mode */
+#define GC_PSX_RUMBLE  7               /* Rumble in Red mode */
+
+#define GC_PSX_CLOCK   0x04            /* Pin 4 */
+#define GC_PSX_COMMAND 0x01            /* Pin 1 */
+#define GC_PSX_POWER   0xf8            /* Pins 5-9 */
+#define GC_PSX_SELECT  0x02            /* Pin 3 */
 
-#define GC_PSX_MOUSE   0x12    /* PSX Mouse */
-#define GC_PSX_NEGCON  0x23    /* NegCon pad */
-#define GC_PSX_NORMAL  0x41    /* Standard Digital controller */
-#define GC_PSX_ANALOGR 0x73    /* Analog controller in Red mode */
-#define GC_PSX_ANALOGG 0x53    /* Analog controller in Green mode */
-
-#define GC_PSX_CLOCK   0x04    /* Pin 3 */
-#define GC_PSX_COMMAND 0x01    /* Pin 1 */
-#define GC_PSX_POWER   0xf8    /* Pins 5-9 */
-#define GC_PSX_SELECT  0x02    /* Pin 2 */
-#define GC_PSX_NOPOWER  0x04
+#define GC_PSX_ID(x)   ((x) >> 4)      /* High nibble is device type */
+#define GC_PSX_LEN(x)  ((x) & 0xf)     /* Low nibble is length in words */
 
 static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
 static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, 
BTN_Y,
@@ -233,19 +240,18 @@
 
 static int gc_psx_command(struct gc *gc, int b)
 {
-       int i, cmd, ret = 0;
+       int i, cmd, data = 0;
 
-       cmd = (b & 1) ? GC_PSX_COMMAND : 0;
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < 8; i++, b >>= 1) {
+               cmd = (b & 1) ? GC_PSX_COMMAND : 0;
                parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
                udelay(GC_PSX_DELAY);
-               ret |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) 
? (1 << i) : 0;
-               cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+               if (parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX])
+               data |= ((parport_read_status(gc->pd->port) ^ 0x80) & 
+gc->pads[GC_PSX]) ? (1 << i) : 0;
                parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
                udelay(GC_PSX_DELAY);
-               b >>= 1;
        }
-       return ret;
+       return data;
 }
 
 /*
@@ -253,29 +259,31 @@
  * device identifier code.
  */
 
-static int gc_psx_read_packet(struct gc *gc, int length, unsigned char *data)
+static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
 {
-       int i, ret;
+       int i, id;
        unsigned long flags;
 
+       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); 
+ /* Select pad */
+       udelay(GC_PSX_DELAY * 2);
+       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);                 
+ /* Deselect, begin command */
+       udelay(GC_PSX_DELAY * 2);
+
        __save_flags(flags);
        __cli();
 
-       parport_write_data(gc->pd->port, GC_PSX_POWER);
-
-       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); 
 /* Select pad */
-       udelay(GC_PSX_DELAY * 2);
        gc_psx_command(gc, 0x01);                                                      
 /* Access pad */
-       ret = gc_psx_command(gc, 0x42);                                                
 /* Get device id */
-       if (gc_psx_command(gc, 0) == 'Z')                                              
 /* okay? */
-               for (i = 0; i < length; i++)
+       id = gc_psx_command(gc, 0x42);                                                 
+ /* Get device id */
+       if (gc_psx_command(gc, 0) == 0x5a) {                                           
+ /* Okay? */
+               for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
                        data[i] = gc_psx_command(gc, 0);
-       else ret = -1;
+       } else id = 0;
 
-       parport_write_data(gc->pd->port, GC_PSX_SELECT | GC_PSX_CLOCK | GC_PSX_POWER);
        __restore_flags(flags);
 
-       return ret;
+       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
+
+       return GC_PSX_ID(id);
 }
 
 /*
@@ -316,8 +324,8 @@
                                input_report_abs(dev + i, ABS_X,  axes[0]);
                                input_report_abs(dev + i, ABS_Y, -axes[1]);
 
-                               input_report_abs(dev + i, ABS_HAT0X, !!(s & data[7]) - 
!!(s & data[6]));
-                               input_report_abs(dev + i, ABS_HAT0Y, !!(s & data[5]) - 
!!(s & data[4]));
+                               input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - 
+!(s & data[7]));
+                               input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - 
+!(s & data[5]));
 
                                for (j = 0; j < 10; j++)
                                        input_report_key(dev + i, gc_n64_btn[j], s & 
data[gc_n64_bytes[j]]);
@@ -338,8 +346,8 @@
                        s = gc_status_bit[i];
 
                        if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
-                               input_report_abs(dev + i, ABS_X, !!(s & data[7]) - 
!!(s & data[6]));
-                               input_report_abs(dev + i, ABS_Y, !!(s & data[5]) - 
!!(s & data[4]));
+                               input_report_abs(dev + i, ABS_X, ! - !(s & data[6]) - 
+!(s & data[7]));
+                               input_report_abs(dev + i, ABS_Y, ! - !(s & data[4]) - 
+!(s & data[5]));
                        }
 
                        if (s & gc->pads[GC_NES])
@@ -365,8 +373,8 @@
                        s = gc_status_bit[i];
 
                        if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
-                               input_report_abs(dev + i, ABS_X, !!(s & data[3]) - 
!!(s & data[2]));
-                               input_report_abs(dev + i, ABS_Y, !!(s & data[1]) - 
!!(s & data[0]));
+                               input_report_abs(dev + i, ABS_X,  !(s & data[2]) - !(s 
+& data[3]));
+                               input_report_abs(dev + i, ABS_Y,  !(s & data[0]) - !(s 
+& data[1]));
                                input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
                        }
 
@@ -385,37 +393,37 @@
                        if (gc->pads[GC_PSX] & gc_status_bit[i])
                                break;
 
-               switch (gc_psx_read_packet(gc, 6, data)) {
+               switch (gc_psx_read_packet(gc, data)) {
+
+                       case GC_PSX_RUMBLE:
+
+                               input_report_key(dev + i, BTN_THUMB,  ~data[0] & 0x04);
+                               input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+
+                       case GC_PSX_NEGCON:
+                       case GC_PSX_ANALOG:
 
-                       case GC_PSX_ANALOGG:
-       
                                for (j = 0; j < 4; j++)
                                        input_report_abs(dev + i, gc_psx_abs[j], 
data[j + 2]);
 
-                               input_report_abs(dev + i, ABS_HAT0X, !!(data[0]&0x20) 
- !!(data[0]&0x80));
-                               input_report_abs(dev + i, ABS_HAT0Y, !!(data[0]&0x40) 
- !!(data[0]&0x10));
+                               input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) 
+- !(data[0] & 0x80));
+                               input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) 
+- !(data[0] & 0x10));
 
                                for (j = 0; j < 8; j++)
-                                       input_report_key(dev + i, gc_psx_btn[j], 
~data[1] & (1 << i));
+                                       input_report_key(dev + i, gc_psx_btn[j], 
+~data[1] & (1 << j));
 
                                input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
                                input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
 
                                break;
 
-                       case GC_PSX_ANALOGR:
-
-                               input_report_key(dev + i, BTN_THUMB,  ~data[0] & 0x04);
-                               input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
-
                        case GC_PSX_NORMAL:
-                       case GC_PSX_NEGCON:
 
-                               input_report_abs(dev + i, ABS_X, 128 + !!(data[0] & 
0x20) * 127 - !!(data[0] & 0x80) * 128);
-                               input_report_abs(dev + i, ABS_Y, 128 + !!(data[0] & 
0x40) * 127 - !!(data[0] & 0x10) * 128);
+                               input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 
+0x20) * 127 - !(data[0] & 0x80) * 128);
+                               input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 
+0x40) * 127 - !(data[0] & 0x10) * 128);
 
                                for (j = 0; j < 8; j++)
-                                       input_report_key(dev + i, gc_psx_btn[j], 
~data[1] & (1 << i));
+                                       input_report_key(dev + i, gc_psx_btn[j], 
+~data[1] & (1 << j));
 
                                input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
                                input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
@@ -448,14 +456,12 @@
        }
 }
 
-
-
 static struct gc __init *gc_probe(int *config)
 {
        struct gc *gc;
        struct parport *pp;
-       int i, j, psx, pbtn;
-       unsigned char data[2];
+       int i, j, psx;
+       unsigned char data[32];
 
        if (config[0] < 0)
                return NULL;
@@ -545,44 +551,42 @@
 
                        case GC_PSX:
                                
-                               psx = gc_psx_read_packet(gc, 2, data);
+                               psx = gc_psx_read_packet(gc, data);
 
                                switch(psx) {
                                        case GC_PSX_NEGCON:
-                                               config[i + 1] += 1;
                                        case GC_PSX_NORMAL:
-                                               pbtn = 10;
-                                               break;
+                                       case GC_PSX_ANALOG:
+                                       case GC_PSX_RUMBLE:
 
-                                       case GC_PSX_ANALOGG:
-                                       case GC_PSX_ANALOGR:
-                                               config[i + 1] += 2;
-                                               pbtn = 12;
                                                for (j = 0; j < 6; j++) {
                                                        psx = gc_psx_abs[j];
                                                        set_bit(psx, 
gc->dev[i].absbit);
-                                                       gc->dev[i].absmin[psx] = 4;
-                                                       gc->dev[i].absmax[psx] = 252;
-                                                       gc->dev[i].absflat[psx] = 2;
+                                                       if (j < 4) {
+                                                               gc->dev[i].absmin[psx] 
+= 4;
+                                                               gc->dev[i].absmax[psx] 
+= 252;
+                                                               
+gc->dev[i].absflat[psx] = 2;
+                                                       } else {
+                                                               gc->dev[i].absmin[psx] 
+= -1;
+                                                               gc->dev[i].absmax[psx] 
+= 1;
+                                                       }
                                                }
+
+                                               for (j = 0; j < 12; j++)
+                                                       set_bit(gc_psx_btn[j], 
+gc->dev[i].keybit);
+
                                                break;
 
-                                       case -1:
+                                       case 0:
                                                gc->pads[GC_PSX] &= ~gc_status_bit[i];
-                                               pbtn = 0;
                                                printk(KERN_ERR "gamecon.c: No PSX 
controller found.\n");
                                                break;
 
                                        default:
                                                gc->pads[GC_PSX] &= ~gc_status_bit[i];
-                                               pbtn = 0;
                                                printk(KERN_WARNING "gamecon.c: 
Unsupported PSX controller %#x,"
                                                        " please report to 
<[EMAIL PROTECTED]>.\n", psx);
                                }
-
-                               for (j = 0; j < pbtn; j++)
-                                       set_bit(gc_psx_btn[j], gc->dev[i].keybit);
-
                                break;
                }
 
diff -urN linux-test10-pre5-old/drivers/char/joystick/iforce.c 
linux/drivers/char/joystick/iforce.c
--- linux-test10-pre5-old/drivers/char/joystick/iforce.c        Tue Aug 22 20:41:14 
2000
+++ linux/drivers/char/joystick/iforce.c        Thu Oct 26 23:13:29 2000
@@ -54,6 +54,7 @@
 
 struct iforce {
        signed char data[IFORCE_MAX_LENGTH];
+       struct usb_device *usbdev;
        struct input_dev dev;
        struct urb irq;
        int open;
@@ -113,9 +114,11 @@
 {
        struct iforce *iforce = dev->private;
 
-       if (dev->idbus == BUS_USB && !iforce->open++)
+       if (dev->idbus == BUS_USB && !iforce->open++) {
+               iforce->irq.dev = iforce->usbdev;
                if (usb_submit_urb(&iforce->irq))
                        return -EIO;
+       }
 
        return 0;
 }
diff -urN linux-test10-pre5-old/drivers/char/joystick/ns558.c 
linux/drivers/char/joystick/ns558.c
--- linux-test10-pre5-old/drivers/char/joystick/ns558.c Thu Oct 26 23:04:19 2000
+++ linux/drivers/char/joystick/ns558.c Thu Oct 26 23:02:53 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: ns558.c,v 1.16 2000/08/17 20:03:56 vojtech Exp $
+ * $Id: ns558.c,v 1.21 2000/10/18 12:29:35 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *  Copyright (c) 1999 Brian Gerst
@@ -37,6 +37,7 @@
 #include <linux/ioport.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/gameport.h>
 #include <linux/malloc.h>
 #include <linux/isapnp.h>
@@ -47,7 +48,7 @@
 #define NS558_PNP      2
 #define NS558_PCI      3
 
-static int ns558_isa_portlist[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
+static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 
+0x209,
                                    0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 
};
 
 struct ns558 {
@@ -58,7 +59,7 @@
 };
        
 static struct ns558 *ns558;
-static int have_pci_devices;
+static int ns558_pci;
 
 /*
  * ns558_isa_probe() tries to find an isa gameport at the
@@ -188,12 +189,10 @@
        }
        memset(port, 0, sizeof(struct ns558));
 
-       port->next = ns558;
        port->type = NS558_PCI;
        port->gameport.io = ioport;
        port->gameport.size = iolen;
        port->dev = pdev;
-       ns558 = port;
 
        pdev->driver_data = port;
 
@@ -312,13 +311,10 @@
 #endif
 
 /*
- * Probe for PCI ports.  Always probe for PCI first,
- * it is the least-invasive probe.
+ * Probe for PCI ports.
  */
 
-       i = pci_module_init(&ns558_pci_driver);
-       if (i == 0)
-               have_pci_devices = 1;
+       ns558_pci = !pci_module_init(&ns558_pci_driver);
 
 /*
  * Probe for ISA ports.
@@ -339,12 +335,15 @@
        }
 #endif
 
-       return ns558 ? 0 : -ENODEV;
+       return (ns558 || ns558_pci) ? 0 : -ENODEV;
 }
 
 void __exit ns558_exit(void)
 {
-       struct ns558 *port = ns558;
+       struct ns558 *next, *port = ns558;
+
+       if (ns558_pci)
+               pci_unregister_driver(&ns558_pci_driver);
 
        while (port) {
                gameport_unregister_port(&port->gameport);
@@ -365,11 +364,10 @@
                                break;
                }
                
-               port = port->next;
+               next = port->next;
+               kfree(port);
+               port = next;
        }
-
-       if (have_pci_devices)
-               pci_unregister_driver(&ns558_pci_driver);
 }
 
 module_init(ns558_init);
diff -urN linux-test10-pre5-old/drivers/char/joystick/sidewinder.c 
linux/drivers/char/joystick/sidewinder.c
--- linux-test10-pre5-old/drivers/char/joystick/sidewinder.c    Mon Aug 14 22:55:01 
2000
+++ linux/drivers/char/joystick/sidewinder.c    Thu Oct 26 23:02:53 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: sidewinder.c,v 1.16 2000/07/14 09:02:41 vojtech Exp $
+ * $Id: sidewinder.c,v 1.17 2000/10/25 09:56:09 vojtech Exp $
  *
  *  Copyright (c) 1998-2000 Vojtech Pavlik
  *
@@ -102,7 +102,7 @@
        { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, 
BTN_BASE4, BTN_SELECT },
        { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, 
BTN_BASE4, BTN_SELECT },
        { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, 
BTN_MODE, BTN_SELECT },
-       { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3 
}};
+       { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, 
+BTN_BASE4 }};
 
 static struct {
        int x;
diff -urN linux-test10-pre5-old/drivers/char/joystick/tmdc.c 
linux/drivers/char/joystick/tmdc.c
--- linux-test10-pre5-old/drivers/char/joystick/tmdc.c  Wed Jun 21 17:22:21 2000
+++ linux/drivers/char/joystick/tmdc.c  Thu Oct 26 23:24:34 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 vojtech Exp $
+ * $Id: tmdc.c,v 1.20 2000/08/25 16:28:03 vojtech Exp $
  *
  *  Copyright (c) 1998-2000 Vojtech Pavlik
  *
@@ -49,6 +49,7 @@
 
 #define TMDC_MODE_M3DI         1
 #define TMDC_MODE_3DRP         3
+#define TMDC_MODE_FM           8
 #define TMDC_MODE_FGP          163
 
 #define TMDC_BYTE_ID           10
@@ -192,6 +193,15 @@
 
                                        break;
 
+                               case TMDC_MODE_FM:
+
+                                       for (i = 0; i < 8; i++)
+                                               input_report_key(dev, tmdc_btn_joy[i],
+                                                       (data[j][tmdc_byte_d[0]] >> (i 
++ 0)) & 1);
+                                       for (i = 0; i < 2; i++)
+                                               input_report_key(dev, tmdc_btn_joy[i + 
+8],
+                                                       (data[j][tmdc_byte_d[1]] >> (i 
++ 6)) & 1);
+
                                default:
 
                                        for (i = 0; i < ((data[j][TMDC_BYTE_DEF] & 
0xf) << 3) && i < TMDC_BTN_JOY; i++)
@@ -239,6 +249,7 @@
                char padbtn;
        } models[] = {  {   1, "ThrustMaster Millenium 3D Inceptor",      6, 0, 6,  0 
},
                        {   3, "ThrustMaster Rage 3D Gamepad",            2, 0, 0, 10 
},
+                       {   8, "ThrustMaster FragMaster",                 4, 0, 0, 10 
+},
                        { 163, "Thrustmaster Fusion GamePad",             2, 0, 0, 10 
},
                        {   0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0,  0 
}};
        unsigned char data[2][TMDC_MAX_LENGTH];
diff -urN linux-test10-pre5-old/drivers/input/evdev.c linux/drivers/input/evdev.c
--- linux-test10-pre5-old/drivers/input/evdev.c Fri Jul 28 03:36:54 2000
+++ linux/drivers/input/evdev.c Thu Oct 26 23:02:53 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
+ * $Id: evdev.c,v 1.16 2000/10/17 07:41:53 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
@@ -123,7 +123,7 @@
        struct evdev_list *list;
        int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
 
-       if (i > EVDEV_MINORS || !evdev_table[i])
+       if (i >= EVDEV_MINORS || !evdev_table[i])
                return -ENODEV;
 
        if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
@@ -145,7 +145,19 @@
 
 static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, 
loff_t *ppos)
 {
-       return -EINVAL;
+       struct evdev_list *list = file->private_data;
+       struct input_event event;
+       int retval = 0;
+
+       while (retval < count) {
+
+               if (copy_from_user(&event, buffer + retval, sizeof(struct 
+input_event)))
+                       return -EFAULT;
+               input_event(list->evdev->handle.dev, event.type, event.code, 
+event.value);
+               retval += sizeof(struct input_event);
+       }
+
+       return retval;
 }
 
 static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t 
*ppos)
@@ -288,7 +300,7 @@
        int minor;
 
        for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
-       if (evdev_table[minor]) {
+       if (minor == EVDEV_MINORS) {
                printk(KERN_ERR "evdev: no more free evdev devices\n");
                return NULL;
        }
diff -urN linux-test10-pre5-old/drivers/input/joydev.c linux/drivers/input/joydev.c
--- linux-test10-pre5-old/drivers/input/joydev.c        Tue Aug 22 18:06:31 2000
+++ linux/drivers/input/joydev.c        Thu Oct 26 23:02:53 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: joydev.c,v 1.13 2000/08/14 21:05:26 vojtech Exp $
+ * $Id: joydev.c,v 1.15 2000/10/17 07:41:53 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik 
  *  Copyright (c) 1999 Colin Van Dyke 
@@ -193,7 +193,7 @@
        struct joydev_list *list;
        int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
 
-       if (i > JOYDEV_MINORS || !joydev_table[i])
+       if (i >= JOYDEV_MINORS || !joydev_table[i])
                return -ENODEV;
 
        if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
@@ -395,7 +395,7 @@
                || test_bit(BTN_1, dev->keybit)))) return NULL; 
 
        for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
-       if (joydev_table[minor]) {
+       if (minor == JOYDEV_MINORS) {
                printk(KERN_ERR "joydev: no more free joydev devices\n");
                return NULL;
        }
diff -urN linux-test10-pre5-old/drivers/input/mousedev.c linux/drivers/input/mousedev.c
--- linux-test10-pre5-old/drivers/input/mousedev.c      Tue Aug 22 18:06:31 2000
+++ linux/drivers/input/mousedev.c      Thu Oct 26 23:02:53 2000
@@ -1,9 +1,9 @@
 /*
- * $Id: mousedev.c,v 1.15 2000/08/14 21:05:26 vojtech Exp $
+ * $Id: mousedev.c,v 1.20 2000/10/18 12:12:26 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
- *  Input driver to PS/2 or ImPS/2 device driver module.
+ *  Input driver to ImExPS/2 device driver module.
  *
  *  Sponsored by SuSE
  */
@@ -65,20 +65,22 @@
        signed char ps2[6];
        unsigned long buttons;
        unsigned char ready, buffer, bufsiz;
-       unsigned char mode, genseq, impseq;
+       unsigned char mode, imexseq, impsseq;
 };
 
-#define MOUSEDEV_GENIUS_LEN    5
-#define MOUSEDEV_IMPS_LEN      6
+#define MOUSEDEV_SEQ_LEN       6
 
-static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
 static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
+static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 
 static struct input_handler mousedev_handler;
 
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
 
+static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
+static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
+
 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned 
int code, int value)
 {
        struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
@@ -96,12 +98,12 @@
                                        switch (code) {
                                                case ABS_X:     
                                                        size = 
handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-                                                       list->dx += (value * 
CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size;
+                                                       list->dx += (value * xres - 
+list->oldx) / size;
                                                        list->oldx += list->dx * size;
                                                        break;
                                                case ABS_Y:
                                                        size = 
handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-                                                       list->dy -= (value * 
CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+                                                       list->dy -= (value * yres - 
+list->oldy) / size;
                                                        list->oldy -= list->dy * size;
                                                        break;
                                        }
@@ -121,12 +123,12 @@
                                                case BTN_TOUCH:
                                                case BTN_LEFT:   index = 0; break;
                                                case BTN_4:
-                                               case BTN_EXTRA:  if (list->mode > 1) { 
index = 4; break; }
+                                               case BTN_EXTRA:  if (list->mode == 2) 
+{ index = 4; break; }
                                                case BTN_STYLUS:
                                                case BTN_1:
                                                case BTN_RIGHT:  index = 1; break;
                                                case BTN_3:
-                                               case BTN_SIDE:   if (list->mode > 1) { 
index = 3; break; }
+                                               case BTN_SIDE:   if (list->mode == 2) 
+{ index = 3; break; }
                                                case BTN_2:
                                                case BTN_STYLUS2:
                                                case BTN_MIDDLE: index = 2; break;     
 
@@ -213,7 +215,7 @@
        struct mousedev_list *list;
        int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
 
-       if (i > MOUSEDEV_MINORS || !mousedev_table[i])
+       if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
                return -ENODEV;
 
        if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
@@ -254,14 +256,19 @@
        list->dy -= list->ps2[off + 2];
        list->bufsiz = off + 3;
 
-       if (list->mode > 1)
-               list->ps2[off] |= ((list->buttons & 0x18) << 3);
+       if (list->mode == 2) {
+               list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : 
+list->dz)) & 0x0f;
+               list->dz -= list->ps2[off + 3];
+               list->ps2[off + 3] |= ((list->buttons & 0x18) << 1);
+               list->bufsiz++;
+       }
        
-       if (list->mode) {
+       if (list->mode == 1) {
                list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : 
list->dz));
-               list->bufsiz++;
                list->dz -= list->ps2[off + 3];
+               list->bufsiz++;
        }
+
        if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
        list->buffer = list->bufsiz;
 }
@@ -277,24 +284,23 @@
 
                c = buffer[i];
 
-               if (c == mousedev_genius_seq[list->genseq]) {
-                       if (++list->genseq == MOUSEDEV_GENIUS_LEN) {
-                               list->genseq = 0;
-                               list->ready = 1;
+               if (c == mousedev_imex_seq[list->imexseq]) {
+                       if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
+                               list->imexseq = 0;
                                list->mode = 2;
                        }
-               } else list->genseq = 0;
+               } else list->imexseq = 0;
 
-               if (c == mousedev_imps_seq[list->impseq]) {
-                       if (++list->impseq == MOUSEDEV_IMPS_LEN) {
-                               list->impseq = 0;
-                               list->ready = 1;
+               if (c == mousedev_imps_seq[list->impsseq]) {
+                       if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
+                               list->impsseq = 0;
                                list->mode = 1;
                        }
-               } else list->impseq = 0;
+               } else list->impsseq = 0;
 
                list->ps2[0] = 0xfa;
                list->bufsiz = 1;
+               list->ready = 1;
 
                switch (c) {
 
@@ -303,16 +309,16 @@
                                break;
 
                        case 0xf2: /* Get ID */
-                               list->ps2[1] = (list->mode == 1) ? 3 : 0;
+                               switch (list->mode) {
+                                       case 0: list->ps2[1] = 0;
+                                       case 1: list->ps2[1] = 3;
+                                       case 2: list->ps2[1] = 4;
+                               }
                                list->bufsiz = 2;
                                break;
 
                        case 0xe9: /* Get info */
-                               if (list->mode == 2) {
-                                       list->ps2[1] = 0x00; list->ps2[2] = 0x33; 
list->ps2[3] = 0x55;
-                               } else {
-                                       list->ps2[1] = 0x60; list->ps2[2] = 3; 
list->ps2[3] = 200;
-                               }
+                               list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 
+200;
                                list->bufsiz = 4;
                                break;
                }
@@ -407,7 +413,7 @@
                return NULL;
 
        for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
-       if (mousedev_table[minor]) {
+       if (minor == MOUSEDEV_MINORS) {
                printk(KERN_ERR "mousedev: no more free mousedev devices\n");
                return NULL;
        }
@@ -487,3 +493,7 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <[EMAIL PROTECTED]>");
 MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical screen resolution");
diff -urN linux-test10-pre5-old/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c
--- linux-test10-pre5-old/drivers/usb/usbkbd.c  Wed Aug 23 00:19:52 2000
+++ linux/drivers/usb/usbkbd.c  Thu Oct 26 23:11:19 2000
@@ -59,6 +59,7 @@
 
 struct usb_kbd {
        struct input_dev dev;
+       struct usb_device *usbdev;
        unsigned char new[8];
        unsigned char old[8];
        struct urb irq, led;
@@ -116,6 +117,7 @@
                return 0;
 
        kbd->leds = kbd->newleds;
+       kbd->led.dev = kbd->usbdev;
        if (usb_submit_urb(&kbd->led))
                err("usb_submit_urb(leds) failed");
 
@@ -133,6 +135,7 @@
                return;
 
        kbd->leds = kbd->newleds;
+       kbd->led.dev = kbd->usbdev;
        if (usb_submit_urb(&kbd->led))
                err("usb_submit_urb(leds) failed");
 }
@@ -144,6 +147,7 @@
        if (kbd->open++)
                return 0;
 
+       kbd->irq.dev = kbd->usbdev;
        if (usb_submit_urb(&kbd->irq))
                return -EIO;
 
@@ -186,6 +190,8 @@
 
        if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
        memset(kbd, 0, sizeof(struct usb_kbd));
+
+       kbd->usbdev = dev;
 
        kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
        kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | 
BIT(LED_COMPOSE) | BIT(LED_KANA);
diff -urN linux-test10-pre5-old/drivers/usb/usbmouse.c linux/drivers/usb/usbmouse.c
--- linux-test10-pre5-old/drivers/usb/usbmouse.c        Thu Oct 26 23:04:25 2000
+++ linux/drivers/usb/usbmouse.c        Thu Oct 26 23:10:38 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: usbmouse.c,v 1.5 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: usbmouse.c,v 1.6 2000/08/14 21:05:26 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
@@ -41,9 +41,9 @@
 struct usb_mouse {
        signed char data[8];
        char name[128];
+       struct usb_device *usbdev;
        struct input_dev dev;
        struct urb irq;
-       struct usb_device *my_usb_device;       // for resubmitting my urb
        int open;
 };
 
@@ -73,7 +73,7 @@
        if (mouse->open++)
                return 0;
 
-       mouse->irq.dev = mouse->my_usb_device;
+       mouse->irq.dev = mouse->usbdev;
        if (usb_submit_urb(&mouse->irq))
                return -EIO;
 
@@ -116,6 +116,8 @@
        if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
        memset(mouse, 0, sizeof(struct usb_mouse));
 
+       mouse->usbdev = dev;
+
        mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
        mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | 
BIT(BTN_MIDDLE);
        mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
@@ -150,7 +152,6 @@
 
        kfree(buf);
 
-       mouse->my_usb_device = dev;
        FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
                usb_mouse_irq, mouse, endpoint->bInterval);
 
diff -urN linux-test10-pre5-old/drivers/usb/wacom.c linux/drivers/usb/wacom.c
--- linux-test10-pre5-old/drivers/usb/wacom.c   Thu Oct 26 23:04:25 2000
+++ linux/drivers/usb/wacom.c   Thu Oct 26 23:27:27 2000
@@ -1,10 +1,11 @@
 /*
- * $Id: wacom.c,v 1.9 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: wacom.c,v 1.11 2000/10/18 12:12:26 vojtech Exp $
  *
  *  Copyright (c) 2000 Vojtech Pavlik          <[EMAIL PROTECTED]>
  *  Copyright (c) 2000 Andreas Bach Aaen       <[EMAIL PROTECTED]>
  *  Copyright (c) 2000 Clifford Wolf           <[EMAIL PROTECTED]>
  *  Copyright (c) 2000 Sam Mosel               <[EMAIL PROTECTED]>
+ *  Copyright (c) 2000 James E. Blair          <[EMAIL PROTECTED]>
  *
  *  USB Wacom Graphire and Wacom Intuos tablet support
  *
@@ -21,23 +22,25 @@
  *     v1.8 (vp)  - Submit URB only when operating, moved to CVS,
  *                     use input_report_key instead of report_btn and
  *                     other cleanups
+ *     v1.11 (vp) - Add URB ->dev setting for new kernels
+ *     v1.11 (jb) - Add support for the 4D Mouse & Lens
  */
 
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <[EMAIL PROTECTED]>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
@@ -70,17 +73,17 @@
  * byte 5: Y high bits
  * byte 6: pen pressure low bits / mouse wheel
  * byte 7: pen presure high bits / mouse distance
- * 
+ *
  * There are also two single-byte feature reports (2 and 3).
  *
  * Wacom Intuos status packet:
  *
  * byte 0: report ID (2)
- * byte 1: bit7                1 - sync bit 
+ * byte 1: bit7                1 - sync bit
  *        bit6         pointer in range
  *        bit5         pointer type report
  *        bit4         0 ?
- *        bit3         0 ?
+ *        bit3         mouse packet type
  *        bit2         pen button2
  *        bit1         pen button1
  *        bit0         0 ?
@@ -88,12 +91,38 @@
  * byte 3: X low bits
  * byte 4: Y high bits
  * byte 5: Y low bits
+ *
+ * Pen packet:
+ *
  * byte 6: bits 0-7: pressure  (bits 2-9)
  * byte 7: bits 6-7: pressure  (bits 0-1)
  * byte 7: bits 0-5: X tilt    (bits 1-6)
  * byte 8: bit    7: X tilt    (bit  0)
  * byte 8: bits 0-6: Y tilt    (bits 0-6)
  * byte 9: bits 4-7: distance
+ *
+ * Mouse packet type 0:
+ *
+ * byte 6: bits 0-7: wheel     (bits 2-9)
+ * byte 7: bits 6-7: wheel     (bits 0-1)
+ * byte 7: bits 0-5: 0
+ * byte 8: bits 6-7: 0
+ * byte 8: bit    5: left extra button
+ * byte 8: bit    4: right extra button
+ * byte 8: bit    3: wheel      (sign)
+ * byte 8: bit    2: right button
+ * byte 8: bit    1: middle button
+ * byte 8: bit    0: left button
+ * byte 9: bits 4-7: distance
+ *
+ * Mouse packet type 1:
+ *
+ * byte 6: bits 0-7: rotation  (bits 2-9)
+ * byte 7: bits 6-7: rotation  (bits 0-1)
+ * byte 7: bit    5: rotation  (sign)
+ * byte 7: bits 0-4: 0
+ * byte 8: bits 0-7: 0
+ * byte 9: bits 4-7: distance
  */
 
 #define USB_VENDOR_ID_WACOM    0x056a
@@ -192,7 +221,7 @@
                        case 0x0fa: wacom->tool = BTN_TOOL_RUBBER;      break;  /* 
Eraser */
                        case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH;    break;  /* 
Airbrush */
                        default:    wacom->tool = BTN_TOOL_PEN;         break;  /* 
Unknown tool */
-               }                       
+               }       
                input_report_key(dev, wacom->tool, 1);
                return;
        }
@@ -205,31 +234,63 @@
 
        input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
        input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
-       input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 
6) & 3));
        input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
-       input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
-       input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
 
-       input_report_key(dev, BTN_STYLUS, data[1] & 2);
-       input_report_key(dev, BTN_STYLUS2, data[1] & 4);
-       input_report_key(dev, BTN_TOUCH, t > 10);
+       switch (wacom->tool) {
+
+               case BTN_TOOL_PENCIL:
+               case BTN_TOOL_PEN:
+               case BTN_TOOL_BRUSH:
+               case BTN_TOOL_RUBBER:
+               case BTN_TOOL_AIRBRUSH:
+
+                       input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) 
+| ((data[7] >> 6) & 3));
+                       input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | 
+(data[8] >> 7));
+                       input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+                       input_report_key(dev, BTN_STYLUS, data[1] & 2);
+                       input_report_key(dev, BTN_STYLUS2, data[1] & 4);
+                       input_report_key(dev, BTN_TOUCH, t > 10);
+                       break;
+
+               case BTN_TOOL_MOUSE:
+               case BTN_TOOL_LENS:
+
+                       if (data[1] & 0x02) {                   /* Rotation packet */
+                               input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
+                                       ((__u32)data[6] << 2) | ((data[7] >> 6) & 3):
+                                       (-(((__u32)data[6] << 2) | ((data[7] >> 6) & 
+3))) - 1);
+                               break;
+                       }
+
+                       input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
+                       input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+                       input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
+                       input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
+                       input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
+                       input_report_abs(dev, ABS_THROTTLE,  (data[8] & 0x08) ?
+                               ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
+                               -((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+                       break;
+         }
 }
 
 #define WACOM_INTUOS_TOOLS     (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | 
BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
+#define WACOM_INTUOS_BUTTONS   (BIT(BTN_SIDE) | BIT(BTN_EXTRA))
+#define WACOM_INTUOS_ABS       (BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | 
+BIT(ABS_THROTTLE))
 
 struct wacom_features wacom_features[] = {
        { "Wacom Graphire",     0x10,  8, 10206,  7422,  511, 32, wacom_graphire_irq,
-               BIT(EV_REL), 0, BIT(REL_WHEEL), BIT(BTN_LEFT) | BIT(BTN_RIGHT) | 
BIT(BTN_MIDDLE), 0 },
+               BIT(EV_REL), 0, 0, 0 },
        { "Wacom Intuos 4x5",   0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq,
-               0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+               0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
        { "Wacom Intuos 6x8",   0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq,
-               0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+               0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
        { "Wacom Intuos 9x12",  0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq,
-               0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+               0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
        { "Wacom Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq,
-               0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+               0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
        { "Wacom Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
-               0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+               0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
        { NULL , 0 }
 };
 
@@ -275,7 +336,7 @@
        wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | wacom->features->evbit;
        wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | 
BIT(ABS_DISTANCE) | wacom->features->absbit;
        wacom->dev.relbit[0] |= wacom->features->relbit;
-       wacom->dev.keybit[LONG(BTN_LEFT)] |= wacom->features->btnbit;
+       wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | 
+BIT(BTN_MIDDLE) | wacom->features->btnbit;
        wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) 
| BIT(BTN_TOOL_MOUSE) |
                BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | 
wacom->features->digibit;
 
@@ -285,6 +346,14 @@
        wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max;
        wacom->dev.absmax[ABS_TILT_X] = 127;
        wacom->dev.absmax[ABS_TILT_Y] = 127;
+
+       wacom->dev.absmin[ABS_RZ] = -900;
+       wacom->dev.absmax[ABS_RZ] = 899;
+       wacom->dev.absmin[ABS_THROTTLE] = -1023;
+       wacom->dev.absmax[ABS_THROTTLE] = 1023;
+
+       wacom->dev.absfuzz[ABS_X] = 4;
+       wacom->dev.absfuzz[ABS_Y] = 4;
 
        wacom->dev.private = wacom;
        wacom->dev.open = wacom_open;

Reply via email to