Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq
[pandora-kernel.git] / drivers / input / tablet / wacom_wac.c
index 2638811..c896d6a 100644 (file)
@@ -283,10 +283,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 {
        unsigned char *data = wacom->data;
-       int idx;
+       int idx = 0;
 
        /* tool number */
-       idx = data[1] & 0x01;
+       if (wacom->features->type == INTUOS)
+               idx = data[1] & 0x01;
 
        /* Enter report */
        if ((data[1] & 0xfc) == 0xc0) {
@@ -299,6 +300,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                switch (wacom->id[idx]) {
                        case 0x812: /* Inking pen */
                        case 0x801: /* Intuos3 Inking pen */
+                       case 0x20802: /* Intuos4 Classic Pen */
                        case 0x012:
                                wacom->tool[idx] = BTN_TOOL_PENCIL;
                                break;
@@ -308,6 +310,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        case 0x823: /* Intuos3 Grip Pen */
                        case 0x813: /* Intuos3 Classic Pen */
                        case 0x885: /* Intuos3 Marker Pen */
+                       case 0x802: /* Intuos4 Grip Pen Eraser */
+                       case 0x804: /* Intuos4 Marker Pen */
+                       case 0x40802: /* Intuos4 Classic Pen */
                        case 0x022:
                                wacom->tool[idx] = BTN_TOOL_PEN;
                                break;
@@ -319,10 +324,12 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        case 0x09c:
                        case 0x094:
                        case 0x017: /* Intuos3 2D Mouse */
+                       case 0x806: /* Intuos4 Mouse */
                                wacom->tool[idx] = BTN_TOOL_MOUSE;
                                break;
                        case 0x096: /* Lens cursor */
                        case 0x097: /* Intuos3 Lens cursor */
+                       case 0x006: /* Intuos4 Lens cursor */
                                wacom->tool[idx] = BTN_TOOL_LENS;
                                break;
                        case 0x82a: /* Eraser */
@@ -333,12 +340,17 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        case 0x82b: /* Intuos3 Grip Pen Eraser */
                        case 0x81b: /* Intuos3 Classic Pen Eraser */
                        case 0x91b: /* Intuos3 Airbrush Eraser */
+                       case 0x80c: /* Intuos4 Marker Pen Eraser */
+                       case 0x80a: /* Intuos4 Grip Pen Eraser */
+                       case 0x4080a: /* Intuos4 Classic Pen Eraser */
+                       case 0x90a: /* Intuos4 Airbrush Eraser */
                                wacom->tool[idx] = BTN_TOOL_RUBBER;
                                break;
                        case 0xd12:
                        case 0x912:
                        case 0x112:
                        case 0x913: /* Intuos3 Airbrush */
+                       case 0x902: /* Intuos4 Airbrush */
                                wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
                                break;
                        default: /* Unknown tool */
@@ -349,9 +361,15 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 
        /* Exit report */
        if ((data[1] & 0xfe) == 0x80) {
+               /*
+                * Reset all states otherwise we lose the initial states
+                * when in-prox next time
+                */
                wacom_report_abs(wcombo, ABS_X, 0);
                wacom_report_abs(wcombo, ABS_Y, 0);
                wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+               wacom_report_abs(wcombo, ABS_TILT_X, 0);
+               wacom_report_abs(wcombo, ABS_TILT_Y, 0);
                if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
                        wacom_report_key(wcombo, BTN_LEFT, 0);
                        wacom_report_key(wcombo, BTN_MIDDLE, 0);
@@ -362,16 +380,17 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_abs(wcombo, ABS_RZ, 0);
                } else {
                        wacom_report_abs(wcombo, ABS_PRESSURE, 0);
-                       wacom_report_abs(wcombo, ABS_TILT_X, 0);
-                       wacom_report_abs(wcombo, ABS_TILT_Y, 0);
                        wacom_report_key(wcombo, BTN_STYLUS, 0);
                        wacom_report_key(wcombo, BTN_STYLUS2, 0);
                        wacom_report_key(wcombo, BTN_TOUCH, 0);
                        wacom_report_abs(wcombo, ABS_WHEEL, 0);
+                       if (wacom->features->type >= INTUOS3S)
+                               wacom_report_abs(wcombo, ABS_Z, 0);
                }
                wacom_report_key(wcombo, wacom->tool[idx], 0);
                wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
                wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+               wacom->id[idx] = 0;
                return 2;
        }
        return 0;
@@ -385,6 +404,8 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
        /* general pen packet */
        if ((data[1] & 0xb8) == 0xa0) {
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
+               if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L)
+                       t = (t << 1) | (data[1] & 1);
                wacom_report_abs(wcombo, ABS_PRESSURE, t);
                wacom_report_abs(wcombo, ABS_TILT_X,
                                ((data[7] << 1) & 0x7e) | (data[8] >> 7));
@@ -409,7 +430,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
 {
        unsigned char *data = wacom->data;
        unsigned int t;
-       int idx, result;
+       int idx = 0, result;
 
        if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
                dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
@@ -417,7 +438,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        }
 
        /* tool number */
-       idx = data[1] & 0x01;
+       if (wacom->features->type == INTUOS)
+               idx = data[1] & 0x01;
 
        /* pad packets. Works as a second tool and is always in prox */
        if (data[0] == 12) {
@@ -425,25 +447,54 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                if (wacom->tool[1] != BTN_TOOL_FINGER)
                        wacom->tool[1] = BTN_TOOL_FINGER;
 
-               wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
-               wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
-               wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
-               wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
-               wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
-               wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
-               wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
-               wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
-               wacom_report_key(wcombo, BTN_8, (data[5] & 0x10));
-               wacom_report_key(wcombo, BTN_9, (data[6] & 0x10));
-               wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
-               wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
-               if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) |
-                       data[2] | (data[3] & 0x1f) | data[4])
-                       wacom_report_key(wcombo, wacom->tool[1], 1);
-               else
-                       wacom_report_key(wcombo, wacom->tool[1], 0);
-               wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+               if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+                       wacom_report_key(wcombo, BTN_0, (data[2] & 0x01));
+                       wacom_report_key(wcombo, BTN_1, (data[3] & 0x01));
+                       wacom_report_key(wcombo, BTN_2, (data[3] & 0x02));
+                       wacom_report_key(wcombo, BTN_3, (data[3] & 0x04));
+                       wacom_report_key(wcombo, BTN_4, (data[3] & 0x08));
+                       wacom_report_key(wcombo, BTN_5, (data[3] & 0x10));
+                       wacom_report_key(wcombo, BTN_6, (data[3] & 0x20));
+                       if (data[1] & 0x80) {
+                               wacom_report_abs(wcombo, ABS_WHEEL, (data[1] & 0x7f));
+                       } else {
+                               /* Out of proximity, clear wheel value. */
+                               wacom_report_abs(wcombo, ABS_WHEEL, 0);
+                       }
+                       if (wacom->features->type != INTUOS4S) {
+                               wacom_report_key(wcombo, BTN_7, (data[3] & 0x40));
+                               wacom_report_key(wcombo, BTN_8, (data[3] & 0x80));
+                       }
+                       if (data[1] | (data[2] & 0x01) | data[3]) {
+                               wacom_report_key(wcombo, wacom->tool[1], 1);
+                               wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               wacom_report_key(wcombo, wacom->tool[1], 0);
+                               wacom_report_abs(wcombo, ABS_MISC, 0);
+                       }
+               } else {
+                       wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
+                       wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
+                       wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
+                       wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
+                       wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
+                       wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
+                       wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
+                       wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
+                       wacom_report_key(wcombo, BTN_8, (data[5] & 0x10));
+                       wacom_report_key(wcombo, BTN_9, (data[6] & 0x10));
+                       wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+                       wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+
+                       if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) |
+                               data[2] | (data[3] & 0x1f) | data[4]) {
+                               wacom_report_key(wcombo, wacom->tool[1], 1);
+                               wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               wacom_report_key(wcombo, wacom->tool[1], 0);
+                               wacom_report_abs(wcombo, ABS_MISC, 0);
+                       }
+               }
                wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
                 return 1;
        }
@@ -453,10 +504,16 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        if (result)
                 return result-1;
 
-       /* Only large I3 and I1 & I2 support Lense Cursor */
+       /* don't proceed if we don't know the ID */
+       if (!wacom->id[idx])
+               return 0;
+
+       /* Only large Intuos support Lense Cursor */
        if ((wacom->tool[idx] == BTN_TOOL_LENS)
                        && ((wacom->features->type == INTUOS3)
-                       || (wacom->features->type == INTUOS3S)))
+                       || (wacom->features->type == INTUOS3S)
+                       || (wacom->features->type == INTUOS4)
+                       || (wacom->features->type == INTUOS4S)))
                return 0;
 
        /* Cintiq doesn't send data when RDY bit isn't set */
@@ -476,8 +533,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        /* process general packets */
        wacom_intuos_general(wacom, wcombo);
 
-       /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
-       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
+       /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
+       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
 
                if (data[1] & 0x02) {
                        /* Rotation packet */
@@ -506,20 +563,36 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
 
                } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
-                       /* 2D mouse packet */
-                       wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x04);
-                       wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
-                       wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x10);
-                       wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
+                       /* I4 mouse */
+                       if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+                               wacom_report_key(wcombo, BTN_LEFT,   data[6] & 0x01);
+                               wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02);
+                               wacom_report_key(wcombo, BTN_RIGHT,  data[6] & 0x04);
+                               wacom_report_rel(wcombo, REL_WHEEL, ((data[7] & 0x80) >> 7)
+                                                - ((data[7] & 0x40) >> 6));
+                               wacom_report_key(wcombo, BTN_SIDE,   data[6] & 0x08);
+                               wacom_report_key(wcombo, BTN_EXTRA,  data[6] & 0x10);
+
+                               wacom_report_abs(wcombo, ABS_TILT_X,
+                                       ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+                               wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+                       } else {
+                               /* 2D mouse packet */
+                               wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x04);
+                               wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
+                               wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x10);
+                               wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
                                                 - ((data[8] & 0x02) >> 1));
 
-                       /* I3 2D mouse side buttons */
-                       if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
-                               wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
-                               wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
+                               /* I3 2D mouse side buttons */
+                               if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
+                                       wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
+                                       wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
+                               }
                        }
-
-               } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
+               } else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L ||
+                               wacom->features->type == INTUOS4L) &&
+                          wacom->tool[idx] == BTN_TOOL_LENS) {
                        /* Lens cursor packets */
                        wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
                        wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@@ -581,6 +654,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
                        }
                } else if (touchOut || !prox) { /* force touch out-prox */
                        wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID);
+                       wacom_report_key(wcombo, wacom->tool[1], 0);
                        wacom_report_key(wcombo, BTN_TOUCH, 0);
                        touchOut = 0;
                        touchInProx = 1;
@@ -669,6 +743,9 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
                case INTUOS3S:
                case INTUOS3:
                case INTUOS3L:
+               case INTUOS4S:
+               case INTUOS4:
+               case INTUOS4L:
                case CINTIQ:
                case WACOM_BEE:
                        return wacom_intuos_irq(wacom_wac, wcombo);
@@ -706,6 +783,14 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
                case INTUOS:
                        input_dev_i(input_dev, wacom_wac);
                        break;
+               case INTUOS4:
+               case INTUOS4L:
+                       input_dev_i4(input_dev, wacom_wac);
+                       /* fall through */
+               case INTUOS4S:
+                       input_dev_i4s(input_dev, wacom_wac);
+                       input_dev_i(input_dev, wacom_wac);
+                       break;
                case PL:
                case PTU:
                case TABLETPC:
@@ -753,6 +838,7 @@ static struct wacom_features wacom_features[] = {
        { "Wacom DTU710",        8,  34080, 27660,  511,  0, PL },
        { "Wacom DTF521",        8,   6282,  4762,  511,  0, PL },
        { "Wacom DTF720",        8,   6858,  5506,  511,  0, PL },
+       { "Wacom DTF720a",       8,   6858,  5506,  511,  0, PL },
        { "Wacom Cintiq Partner",8,  20480, 15360,  511,  0, PTU },
        { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 31, INTUOS },
        { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
@@ -766,6 +852,10 @@ static struct wacom_features wacom_features[] = {
        { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
        { "Wacom Intuos3 6x11",  10, 54204, 31750, 1023, 63, INTUOS3 },
        { "Wacom Intuos3 4x6",   10, 31496, 19685, 1023, 63, INTUOS3S },
+       { "Wacom Intuos4 4x6",   10, 31496, 19685, 2047, 63, INTUOS4S },
+       { "Wacom Intuos4 6x9",   10, 44704, 27940, 2047, 63, INTUOS4 },
+       { "Wacom Intuos4 8x13",  10, 65024, 40640, 2047, 63, INTUOS4L },
+       { "Wacom Intuos4 12x19", 10, 97536, 60960, 2047, 63, INTUOS4L },
        { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
        { "Wacom Cintiq 20WSX",  10, 86680, 54180, 1023, 63, WACOM_BEE },
        { "Wacom Cintiq 12WX",   10, 53020, 33440, 1023, 63, WACOM_BEE },
@@ -810,8 +900,9 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC2) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
@@ -825,6 +916,10 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },