---
 2.6.30/wacom_sys.c |  20 +++-
 2.6.30/wacom_wac.c | 224 +++++++++++++++++++++++++++++++++++++++++++
 2.6.30/wacom_wac.h |   8 ++
 2.6.36/wacom_sys.c |  20 +++-
 2.6.36/wacom_wac.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++++----
 2.6.36/wacom_wac.h |   8 ++
 2.6.38/wacom_sys.c |   9 ++
 2.6.38/wacom_wac.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++
 2.6.38/wacom_wac.h |   8 ++
 3.7/wacom_sys.c    |   9 ++
 3.7/wacom_wac.c    | 234 +++++++++++++++++++++++++++++++++++++++++++++
 3.7/wacom_wac.h    |   8 ++
 12 files changed, 1033 insertions(+), 23 deletions(-)

diff --git a/2.6.30/wacom_sys.c b/2.6.30/wacom_sys.c
index 517e293..37c30ec 100644
--- a/2.6.30/wacom_sys.c
+++ b/2.6.30/wacom_sys.c
@@ -235,11 +235,14 @@ static int wacom_parse_hid(struct usb_interface *intf, 
struct hid_descriptor *hi
                                        features->device_type = 
BTN_TOOL_DOUBLETAP;
                                        if (features->type == TABLETPC2FG ||
                                                         features->type == 
MTTPC ||
-                                                        features->type == 
MTTPC_B) {
+                                                        features->type == 
MTTPC_B ||
+                                                        features->type == 
WACOM_MSPROT) {
                                                /* need to reset back */
                                                features->pktlen = 
WACOM_PKGLEN_TPC2FG;
                                                if (features->type == MTTPC || 
features->type == MTTPC_B)
                                                        features->pktlen = 
WACOM_PKGLEN_MTTPC;
+                                               else if (features->type == 
WACOM_MSPROT)
+                                                       features->pktlen = 
WACOM_PKGLEN_MSPROT;
                                                features->device_type = 
BTN_TOOL_TRIPLETAP;
                                        }
                                        if (features->type == BAMBOO_PT) {
@@ -251,7 +254,8 @@ static int wacom_parse_hid(struct usb_interface *intf, 
struct hid_descriptor *hi
                                                features->x_max =
                                                        
get_unaligned_le16(&report[i + 8]);
                                                i += 15;
-                                       } else if (features->type == MTTPC_B) {
+                                       } else if (features->type == 
WACOM_MSPROT ||
+                                                  features->type == MTTPC_B) {
                                                features->x_max =
                                                        
get_unaligned_le16(&report[i + 3]);
                                                features->x_phy =
@@ -291,7 +295,8 @@ static int wacom_parse_hid(struct usb_interface *intf, 
struct hid_descriptor *hi
                                                features->y_phy =
                                                        
get_unaligned_le16(&report[i + 6]);
                                                i += 7;
-                                       } else if (features->type == MTTPC_B) {
+                                       } else if (features->type == 
WACOM_MSPROT ||
+                                                  features->type == MTTPC_B) {
                                                features->y_max =
                                                        
get_unaligned_le16(&report[i + 3]);
                                                features->y_phy =
@@ -383,6 +388,15 @@ static int wacom_query_tablet_data(struct usb_interface 
*intf, struct wacom_feat
                                        report_id, rep_data, 4, 1);
                        } while ((error < 0 || rep_data[1] != 4) && limit++ < 
5);
                }
+               else if (features->type == WACOM_MSPROT) {
+                       do {
+                               rep_data[0] = 14;
+                               rep_data[1] = 2;
+                               report_id = 14;
+                               error = wacom_set_report(intf, 
WAC_HID_FEATURE_REPORT,
+                                       report_id, rep_data, 2, 1);
+                       } while ((error < 0 || rep_data[1] != 2) && limit++ < 
5);
+               }
        } else if (features->type <= BAMBOO_PT) {
                do {
                        rep_data[0] = 2;
diff --git a/2.6.30/wacom_wac.c b/2.6.30/wacom_wac.c
index f24d7b8..3075f96 100644
--- a/2.6.30/wacom_wac.c
+++ b/2.6.30/wacom_wac.c
@@ -27,6 +27,8 @@
 static void wacom_report_numbered_buttons(struct input_dev *input_dev,
                                int button_count, int mask);
 
+static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid);
+
 static int wacom_penpartner_irq(struct wacom_wac *wacom)
 {
        unsigned char *data = wacom->data;
@@ -628,6 +630,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
                break;
 
        case 0x82a: /* Eraser */
+       case 0x84a:
        case 0x85a:
        case 0x91a:
        case 0xd1a:
@@ -1054,6 +1057,73 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        return 0;
 }
 
+static int wacom_msprot_irq(struct wacom_wac *wacom)
+{
+       struct input_dev *input = wacom->input;
+       unsigned char *data = wacom->data;
+       int i;
+       int current_num_contacts = data[2];
+       int contacts_to_send = 0;
+
+       wacom->tool[1] = BTN_TOOL_DOUBLETAP;
+       wacom->id[0] = TOUCH_DEVICE_ID;
+       wacom->tool[2] = BTN_TOOL_TRIPLETAP;
+
+       if (current_num_contacts)
+               wacom->num_contacts_left = current_num_contacts;
+
+       contacts_to_send = min(5, wacom->num_contacts_left);
+
+       for (i = 0; i < contacts_to_send; i++) {
+               int offset = WACOM_BYTES_PER_MSPROT_PACKET * i + 3;
+               bool touch = (data[offset] & 0x1) && 
!wacom->shared->stylus_in_proximity;
+               int id = get_unaligned_le16(&data[offset + 1]);
+               int slot = find_slot_from_contactid(wacom, id);
+
+               if (slot < 0)
+                       continue;
+
+               //input_mt_slot(input, slot);
+               //input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+               if (touch) {
+                       int x = get_unaligned_le16(&data[offset + 3]);
+                       int y = get_unaligned_le16(&data[offset + 5]);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+                       if (wacom->last_finger != slot) {
+                               if (x == input->abs[ABS_X])
+                                       x++;
+
+                               if (y == input->abs[ABS_Y])
+                                       y++;
+                       }
+#endif
+
+                       input_report_abs(input, ABS_X, x);
+                       input_report_abs(input, ABS_Y, y);
+               }
+               wacom->slots[slot] = touch ? id : -1;
+
+               input_report_abs(input, ABS_MISC, wacom->id[0]);
+               input_report_key(input, wacom->tool[slot+1], touch);
+               wacom->last_finger = slot + 1;
+               if (!slot)
+                       input_report_key(input, BTN_TOUCH, touch);
+               input_event(input, EV_MSC, MSC_SERIAL, slot + 1);
+               input_sync(input);
+       }
+
+       wacom->num_contacts_left -= contacts_to_send;
+       if (wacom->num_contacts_left <= 0) {
+               wacom->num_contacts_left = 0;
+               wacom->shared->touch_down = test_bit(BTN_TOOL_DOUBLETAP, 
input->key) ||
+                                           test_bit(BTN_TOOL_TRIPLETAP, 
input->key);
+       }
+
+       //input_mt_sync_frame(input);
+       return 1;
+}
+
 static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
 {
        struct wacom_features *features = &wacom->features;
@@ -1363,6 +1433,136 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, 
size_t len)
        return retval;
 }
 
+static int wacom_mspro_pad_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       int nbuttons = wacom->features.numbered_buttons;
+       bool prox;
+       int buttons, ring;
+
+       switch (nbuttons) {
+               case 11:
+                       buttons = (data[1] >> 1) | (data[3] << 6);
+                       break;
+               case 13:
+                       buttons = data[1] | (data[3] << 8);
+                       break;
+               default:
+                       dev_warn(input->dev.parent, "%s: unsupported device 
#%d\n", __func__, data[0]);
+                       return 0;
+       }
+
+       ring = le16_to_cpup((__le16 *)&data[4]);
+
+       prox = buttons || ring;
+
+       wacom_report_numbered_buttons(input, nbuttons, buttons);
+       input_report_abs(input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
+
+       input_report_key(input, wacom->tool[1], prox ? 1 : 0);
+       input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+
+       input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+       return 1;
+}
+
+static int wacom_mspro_pen_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       bool tip, sw1, sw2, range, proximity;
+       unsigned int x, y;
+       unsigned int pressure;
+       int tilt_x, tilt_y;
+       int rotation;
+       unsigned int fingerwheel;
+       unsigned int height;
+       u64 tool_uid;
+       unsigned int tool_type;
+
+       if (wacom->shared->touch_down)
+               return 1;
+
+       tip         = data[1] & 0x01;
+       sw1         = data[1] & 0x02;
+       sw2         = data[1] & 0x04;
+       /* eraser   = data[1] & 0x08; */
+       /* invert   = data[1] & 0x10; */
+       range       = data[1] & 0x20;
+       proximity   = data[1] & 0x40;
+       x           = le32_to_cpup((__le32 *)&data[2]) & 0xFFFFFF;
+       y           = le32_to_cpup((__le32 *)&data[5]) & 0xFFFFFF;
+       pressure    = le16_to_cpup((__le16 *)&data[8]);
+       tilt_x      = data[10];
+       tilt_y      = data[11];
+       rotation    = le16_to_cpup((__le16 *)&data[12]);
+       fingerwheel = le16_to_cpup((__le16 *)&data[14]);
+       height      = data[16];
+       tool_uid    = le64_to_cpup((__le64 *)&data[17]);
+       tool_type   = le16_to_cpup((__le16 *)&data[25]);
+
+       wacom->serial[0] = (tool_uid & 0xFFFFFFFF);
+       wacom->id[0]     = (tool_uid >> 32) | tool_type;
+       if (range) {
+               wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0] & 
0xFFFFF);
+       }
+
+       /* pointer going from fully "in range" to merely "in proximity" */
+       if (!range && wacom->tool[0]) {
+               height = wacom->features.distance_max;
+       }
+
+       /*
+        * only report data if there's a tool for userspace to associate
+        * the events with.
+        */
+       if (wacom->tool[0]) {
+               input_report_key(input, BTN_TOUCH, tip);
+               input_report_key(input, BTN_STYLUS, sw1);
+               input_report_key(input, BTN_STYLUS2, sw2);
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+               input_report_abs(input, ABS_PRESSURE, pressure);
+               input_report_abs(input, ABS_TILT_X, tilt_x);
+               input_report_abs(input, ABS_TILT_Y, tilt_y);
+               input_report_abs(input, ABS_Z, rotation);
+               input_report_abs(input, ABS_WHEEL, fingerwheel);
+               input_report_abs(input, ABS_DISTANCE, height);
+               input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
+               input_report_abs(input, ABS_MISC, 
wacom_intuos_id_mangle(wacom->id[0]));
+               input_report_key(input, wacom->tool[0], range ? 1 : 0);
+
+               if (!range)
+                       wacom->tool[0] = 0;
+       }
+
+       wacom->shared->stylus_in_proximity = proximity;
+
+       return 1;
+}
+
+static int wacom_mspro_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+
+       switch (data[0]) {
+               case WACOM_REPORT_MSPRO:
+                       return wacom_mspro_pen_irq(wacom);
+               case WACOM_REPORT_MSPROPAD:
+                       return wacom_mspro_pad_irq(wacom);
+               case WACOM_REPORT_MSPRODEVICE:
+                       return 0;
+               default:
+                       dev_dbg(input->dev.parent,
+                               "%s: received unknown report #%d\n", __func__, 
data[0]);
+                       break;
+       }
+       return 0;
+}
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 {
        bool sync;
@@ -1419,6 +1619,14 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t 
len)
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
+       case WACOM_MSPRO:
+               sync = wacom_mspro_irq(wacom_wac);
+               break;
+
+       case WACOM_MSPROT:
+               sync = wacom_msprot_irq(wacom_wac);
+               break;
+
        case INTUOS5S:
        case INTUOS5:
        case INTUOS5L:
@@ -1750,6 +1958,7 @@ void wacom_setup_input_capabilities(struct input_dev 
*input_dev,
                wacom_setup_cintiq(wacom_wac);
                break;
 
+       case WACOM_MSPRO:
        case WACOM_13HD:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                wacom_setup_cintiq(wacom_wac);
@@ -1813,6 +2022,7 @@ void wacom_setup_input_capabilities(struct input_dev 
*input_dev,
 
        case MTTPC:
        case MTTPC_B:
+       case WACOM_MSPROT:
                if (features->device_type == BTN_TOOL_TRIPLETAP) {
                        for (i = 0; i < 10; i++)
                                wacom_wac->slots[i] = -1;
@@ -2129,6 +2339,16 @@ static const struct wacom_features wacom_features_0x47 =
        { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 
31, INTUOS };
 static const struct wacom_features wacom_features_0x6004 =
        { "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800, 8000, 255, 0, 
TABLETPC };
+static const struct wacom_features wacom_features_0x34A =
+       { "Wacom MobileStudio Pro 13 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT }; /* Touch */
+static const struct wacom_features wacom_features_0x34B =
+       { "Wacom MobileStudio Pro 16 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT }; /* Touch */
+static const struct wacom_features wacom_features_0x34D =
+       { "Wacom MobileStudio Pro 13", WACOM_PKGLEN_MSPRO, 59552, 33848, 8191, 
63,
+         WACOM_MSPRO, 11, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, 
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
+static const struct wacom_features wacom_features_0x34E =
+       { "Wacom MobileStudio Pro 16", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 
63,
+         WACOM_MSPRO, 13, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, 
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 
 #define USB_DEVICE_WACOM(prod)                                 \
        USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
@@ -2279,6 +2499,10 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x32B) },
        { USB_DEVICE_WACOM(0x32F) },
        { USB_DEVICE_WACOM(0x343) },
+       { USB_DEVICE_WACOM(0x34A) },
+       { USB_DEVICE_WACOM(0x34B) },
+       { USB_DEVICE_WACOM(0x34D) },
+       { USB_DEVICE_WACOM(0x34E) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }
 };
diff --git a/2.6.30/wacom_wac.h b/2.6.30/wacom_wac.h
index 8e39ff8..8d444fc 100755
--- a/2.6.30/wacom_wac.h
+++ b/2.6.30/wacom_wac.h
@@ -28,9 +28,12 @@
 #define WACOM_PKGLEN_BBPEN      10
 #define WACOM_PKGLEN_DTUS      68
 #define WACOM_PKGLEN_PENABLED  8
+#define WACOM_PKGLEN_MSPRO     64
+#define WACOM_PKGLEN_MSPROT    50
 
 /* wacom data size per MT contact */
 #define WACOM_BYTES_PER_MT_PACKET      11
+#define WACOM_BYTES_PER_MSPROT_PACKET   9
 
 /* device IDs */
 #define STYLUS_DEVICE_ID       0x02
@@ -51,8 +54,11 @@
 #define WACOM_REPORT_TPCMT2            3
 #define WACOM_REPORT_DTUS              17
 #define WACOM_REPORT_CINTIQ            16
+#define WACOM_REPORT_MSPRO             16
 #define WACOM_REPORT_INTUOS_PEN                16
 #define WACOM_REPORT_CINTIQPAD         17
+#define WACOM_REPORT_MSPROPAD          17
+#define WACOM_REPORT_MSPRODEVICE       19
 
 /* device quirks */
 #define WACOM_QUIRK_BBTOUCH_LOWRES     0x0001
@@ -86,6 +92,7 @@ enum {
        WACOM_27QHD,
        DTK,
        WACOM_24HD,
+       WACOM_MSPRO,
        CINTIQ,
        WACOM_BEE,
        WACOM_13HD,
@@ -94,6 +101,7 @@ enum {
        INTUOSHT,
        INTUOSHT2,
        BAMBOO_PT,
+       WACOM_MSPROT,
        TABLETPC,
        TABLETPC2FG,
        MTTPC,
diff --git a/2.6.36/wacom_sys.c b/2.6.36/wacom_sys.c
index 55e54dc..87990b9 100644
--- a/2.6.36/wacom_sys.c
+++ b/2.6.36/wacom_sys.c
@@ -227,6 +227,8 @@ static int wacom_parse_hid(struct usb_interface *intf, 
struct hid_descriptor *hi
 
                                        if (features->type == MTSCREEN)
                                                features->pktlen = 
WACOM_PKGLEN_MTOUCH;
+                                       else if (features->type == WACOM_MSPROT)
+                                               features->pktlen = 
WACOM_PKGLEN_MSPROT;
 
                                        if (features->type == BAMBOO_PT) {
                                                features->pktlen = 
WACOM_PKGLEN_BBTOUCH;
@@ -236,6 +238,15 @@ static int wacom_parse_hid(struct usb_interface *intf, 
struct hid_descriptor *hi
                                                features->x_max =
                                                        
get_unaligned_le16(&report[i + 8]);
                                                i += 15;
+                                       } else if (features->type == 
WACOM_MSPROT) {
+                                               features->touch_max = 10;
+                                               features->x_max =
+                                                       
get_unaligned_le16(&report[i + 3]);
+                                               features->x_phy =
+                                                       
get_unaligned_le16(&report[i + 6]);
+                                               features->unit = report[i - 5];
+                                               features->unitExpo = report[i - 
3];
+                                               i += 9;
                                        } else {
                                                features->touch_max = 1;
                                                features->x_max =
@@ -271,6 +282,12 @@ static int wacom_parse_hid(struct usb_interface *intf, 
struct hid_descriptor *hi
                                                features->y_max =
                                                        
get_unaligned_le16(&report[i + 6]);
                                                i += 12;
+                                       } else if (features->type == 
WACOM_MSPROT) {
+                                               features->y_max =
+                                                       
get_unaligned_le16(&report[i + 3]);
+                                               features->y_phy =
+                                                       
get_unaligned_le16(&report[i + 6]);
+                                               i += 9;
                                        } else {
                                                features->y_max =
                                                        features->x_max;
@@ -387,7 +404,8 @@ static int wacom_retrieve_hid_descriptor(struct 
usb_interface *intf,
 
        /* only devices support touch need to retrieve the info */
        if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
-           (features->type != BAMBOO_PT) && (features->type != MTSCREEN))
+           (features->type != BAMBOO_PT) && (features->type != MTSCREEN) &&
+           (features->type != WACOM_MSPROT))
                goto out;
 
        if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
diff --git a/2.6.36/wacom_wac.c b/2.6.36/wacom_wac.c
index cf8556f..4537c9d 100644
--- a/2.6.36/wacom_wac.c
+++ b/2.6.36/wacom_wac.c
@@ -420,6 +420,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
                break;
 
        case 0x82a: /* Eraser */
+       case 0x84a:
        case 0x85a:
        case 0x91a:
        case 0xd1a:
@@ -847,13 +848,38 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        return 0;
 }
 
+static int find_slot_from_contactid(struct wacom_wac *wacom, int id)
+{
+       struct wacom_features *features = &wacom->features;
+       struct input_dev *input = wacom->input;
+       struct input_mt_slot *mt;
+       int i;
+
+       /* is there an existing slot for this contact? */
+       for (i = 0; i < features->touch_max; i++) {
+               mt = &input->mt[i];
+               if (input_mt_get_value(mt, ABS_MT_TRACKING_ID) == id )
+                       return i;
+       }
+
+       /* no. then find an unused slot to fill */
+       if (i >= features->touch_max) {
+               for (i = 0; i < features->touch_max; i++) {
+                       mt = &input->mt[i];
+                       if (input_mt_get_value(mt, ABS_MT_TRACKING_ID) == -1 )
+                               return i;
+               }
+       }
+
+       return -1;
+}
+
 static int wacom_mt_touch(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
-       struct input_mt_slot *mt;
-       int i, id = -1, j = 0, k = 4;
+       int i, id = -1, slot = -1, k = 4;
        int x = 0, y = 0, sx = 0, sy = 0, st = 0;
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
@@ -870,25 +896,10 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
 
        for (i = 0; i < contacts_to_send; i++) {
                id = get_unaligned_le16(&data[k]);
-
-               /* is there an existing slot for this contact? */
-               for (j = 0; j < features->touch_max; j++) {
-                       mt = &input->mt[j];
-                       if (input_mt_get_value(mt, ABS_MT_TRACKING_ID) == id )
-                               break;
-               }
-
-               /* no. then find an unused slot to fill */
-               if (j >= features->touch_max) {
-                       for (j = 0; j < features->touch_max; j++) {
-                               mt = &input->mt[j];
-                               if (input_mt_get_value(mt, ABS_MT_TRACKING_ID) 
== -1 )
-                                       break;
-                       }
-               }
+               slot = find_slot_from_contactid(wacom, id);
 
                touch = (data[k - 1] & 0x1) && 
!wacom->shared->stylus_in_proximity;
-               input_mt_slot(input, j);
+               input_mt_slot(input, slot);
                if (touch) {
                        x = get_unaligned_le16(&data[k + 6]);
                        y = get_unaligned_le16(&data[k + 8]);
@@ -1189,6 +1200,197 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, 
size_t len)
        return 0;
 }
 
+static int wacom_msprot_irq(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       struct input_dev *input = wacom->input;
+       unsigned char *data = wacom->data;
+       int i;
+       int current_num_contacts = data[2];
+       int contacts_to_send = 0;
+       int sx = 0, sy = 0;
+
+       if (current_num_contacts) {
+               features->num_contacts = 0;
+               features->num_contacts_left = current_num_contacts;
+       }
+
+       contacts_to_send = min(5, features->num_contacts_left);
+
+       for (i = 0; i < contacts_to_send; i++) {
+               int offset = WACOM_BYTES_PER_MSPROT_PACKET * i + 3;
+               bool touch = (data[offset] & 0x1) && 
!wacom->shared->stylus_in_proximity;
+               int id = get_unaligned_le16(&data[offset + 1]);
+               int slot = find_slot_from_contactid(wacom, id);
+
+               if (slot < 0)
+                       continue;
+
+               input_mt_slot(input, slot);
+               if (touch) {
+                       int x = get_unaligned_le16(&data[offset + 3]);
+                       int y = get_unaligned_le16(&data[offset + 5]);
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+
+                       features->num_contacts++;
+                       if (features->num_contacts == 1) {
+                               sx = x;
+                               sy = y;
+                       }
+               }
+               else
+                       id = -1;
+
+               input_report_abs(input, ABS_MT_TRACKING_ID, id);
+       }
+
+       features->num_contacts_left -= contacts_to_send;
+       if (features->num_contacts_left <= 0) {
+               features->num_contacts_left = 0;
+               wacom->shared->touch_down = features->num_contacts > 0;
+       }
+
+       if (features->num_contacts <= 1) {
+               input_report_key(input, BTN_TOUCH, features->num_contacts == 1);
+               input_report_abs(input, ABS_X, sx);
+               input_report_abs(input, ABS_Y, sy);
+       }
+
+       return 1;
+}
+
+static int wacom_mspro_pad_irq(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       int nbuttons = features->numbered_buttons;
+       bool prox;
+       int buttons, ring;
+
+       switch (nbuttons) {
+               case 11:
+                       buttons = (data[1] >> 1) | (data[3] << 6);
+                       break;
+               case 13:
+                       buttons = data[1] | (data[3] << 8);
+                       break;
+               default:
+                       dev_warn(input->dev.parent, "%s: unsupported device 
#%d\n", __func__, data[0]);
+                       return 0;
+       }
+
+       ring = le16_to_cpup((__le16 *)&data[4]);
+
+       prox = buttons || ring;
+
+       wacom_report_numbered_buttons(input, nbuttons, buttons);
+       input_report_abs(input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
+
+       input_report_key(input, wacom->tool[1], prox ? 1 : 0);
+       input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+
+       input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+       return 1;
+}
+
+static int wacom_mspro_pen_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       bool tip, sw1, sw2, range, proximity;
+       unsigned int x, y;
+       unsigned int pressure;
+       int tilt_x, tilt_y;
+       int rotation;
+       unsigned int fingerwheel;
+       unsigned int height;
+       u64 tool_uid;
+       unsigned int tool_type;
+
+       if (wacom->shared->touch_down)
+               return 1;
+
+       tip         = data[1] & 0x01;
+       sw1         = data[1] & 0x02;
+       sw2         = data[1] & 0x04;
+       /* eraser   = data[1] & 0x08; */
+       /* invert   = data[1] & 0x10; */
+       range       = data[1] & 0x20;
+       proximity   = data[1] & 0x40;
+       x           = le32_to_cpup((__le32 *)&data[2]) & 0xFFFFFF;
+       y           = le32_to_cpup((__le32 *)&data[5]) & 0xFFFFFF;
+       pressure    = le16_to_cpup((__le16 *)&data[8]);
+       tilt_x      = data[10];
+       tilt_y      = data[11];
+       rotation    = le16_to_cpup((__le16 *)&data[12]);
+       fingerwheel = le16_to_cpup((__le16 *)&data[14]);
+       height      = data[16];
+       tool_uid    = le64_to_cpup((__le64 *)&data[17]);
+       tool_type   = le16_to_cpup((__le16 *)&data[25]);
+
+       wacom->serial[0] = (tool_uid & 0xFFFFFFFF);
+       wacom->id[0]     = (tool_uid >> 32) | tool_type;
+       if (range) {
+               wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0] & 
0xFFFFF);
+       }
+
+       /* pointer going from fully "in range" to merely "in proximity" */
+       if (!range && wacom->tool[0]) {
+               height = wacom->features.distance_max;
+       }
+
+       /*
+        * only report data if there's a tool for userspace to associate
+        * the events with.
+        */
+       if (wacom->tool[0]) {
+               input_report_key(input, BTN_TOUCH, tip);
+               input_report_key(input, BTN_STYLUS, sw1);
+               input_report_key(input, BTN_STYLUS2, sw2);
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+               input_report_abs(input, ABS_PRESSURE, pressure);
+               input_report_abs(input, ABS_TILT_X, tilt_x);
+               input_report_abs(input, ABS_TILT_Y, tilt_y);
+               input_report_abs(input, ABS_Z, rotation);
+               input_report_abs(input, ABS_WHEEL, fingerwheel);
+               input_report_abs(input, ABS_DISTANCE, height);
+               input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
+               input_report_abs(input, ABS_MISC, 
wacom_intuos_id_mangle(wacom->id[0]));
+               input_report_key(input, wacom->tool[0], range ? 1 : 0);
+
+               if (!range)
+                       wacom->tool[0] = 0;
+       }
+
+       wacom->shared->stylus_in_proximity = proximity;
+
+       return 1;
+}
+
+static int wacom_mspro_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+
+       switch (data[0]) {
+               case WACOM_REPORT_MSPRO:
+                       return wacom_mspro_pen_irq(wacom);
+               case WACOM_REPORT_MSPROPAD:
+                       return wacom_mspro_pad_irq(wacom);
+               case WACOM_REPORT_MSPRODEVICE:
+                       return 0;
+               default:
+                       dev_dbg(input->dev.parent,
+                               "%s: received unknown report #%d\n", __func__, 
data[0]);
+                       break;
+       }
+       return 0;
+}
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 {
        bool sync;
@@ -1244,6 +1446,14 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t 
len)
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
+       case WACOM_MSPRO:
+               sync = wacom_mspro_irq(wacom_wac);
+               break;
+
+       case WACOM_MSPROT:
+               sync = wacom_msprot_irq(wacom_wac);
+               break;
+
        case TABLETPC:
        case TABLETPCE:
        case TABLETPC2FG:
@@ -1486,6 +1696,7 @@ void wacom_setup_input_capabilities(struct input_dev 
*input_dev,
                break;
 
        case WACOM_13HD:
+       case WACOM_MSPRO:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                wacom_setup_cintiq(wacom_wac);
                break;
@@ -1525,6 +1736,7 @@ void wacom_setup_input_capabilities(struct input_dev 
*input_dev,
                wacom_setup_intuos(wacom_wac);
                break;
 
+       case WACOM_MSPROT:
        case TABLETPC2FG:
        case MTSCREEN:
                if (features->device_type == BTN_TOOL_FINGER) {
@@ -1941,6 +2153,24 @@ static const struct wacom_features wacom_features_0x343 =
          0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
+static const struct wacom_features wacom_features_0x34A =
+       { "Wacom MobileStudio Pro 13 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT, /* Touch */
+       };
+static const struct wacom_features wacom_features_0x34B =
+       { "Wacom MobileStudio Pro 16 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT, /* Touch */
+       };
+static const struct wacom_features wacom_features_0x34D =
+       { "Wacom MobileStudio Pro 13", WACOM_PKGLEN_MSPRO, 59552, 33848, 8191, 
63,
+         WACOM_MSPRO, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 11,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET
+        };
+static const struct wacom_features wacom_features_0x34E =
+       { "Wacom MobileStudio Pro 16", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 
63,
+         WACOM_MSPRO, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 13,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+        };
 static const struct wacom_features wacom_features_0x6004 =
        { "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2070,6 +2300,10 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x12C) },
        { USB_DEVICE_WACOM(0x32F) },
        { USB_DEVICE_WACOM(0x343) },
+       { USB_DEVICE_WACOM(0x34A) },
+       { USB_DEVICE_WACOM(0x34B) },
+       { USB_DEVICE_WACOM(0x34D) },
+       { USB_DEVICE_WACOM(0x34E) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }
 };
diff --git a/2.6.36/wacom_wac.h b/2.6.36/wacom_wac.h
index 9e7024b..1615f2a 100644
--- a/2.6.36/wacom_wac.h
+++ b/2.6.36/wacom_wac.h
@@ -26,6 +26,8 @@
 #define WACOM_PKGLEN_MTOUCH    62
 #define WACOM_PKGLEN_BBTOUCH3   64
 #define WACOM_PKGLEN_DTUS      68
+#define WACOM_PKGLEN_MSPRO     64
+#define WACOM_PKGLEN_MSPROT    50
 
 /* device IDs */
 #define STYLUS_DEVICE_ID       0x02
@@ -46,9 +48,13 @@
 #define WACOM_REPORT_TPCHID            15
 #define WACOM_REPORT_TPCST             16
 #define WACOM_REPORT_DTUS              17
+#define WACOM_REPORT_MSPRO             16
+#define WACOM_REPORT_MSPROPAD          17
+#define WACOM_REPORT_MSPRODEVICE       19
 
 /* wacom data size per MT contact */
 #define WACOM_BYTES_PER_MT_PACKET      11
+#define WACOM_BYTES_PER_MSPROT_PACKET  9
 
 /* device quirks */
 #define WACOM_QUIRK_BBTOUCH_LOWRES     0x0001
@@ -83,10 +89,12 @@ enum {
        WACOM_22HD,
        DTK,
        WACOM_24HD,
+       WACOM_MSPRO,
        CINTIQ,
        WACOM_BEE,
        WACOM_13HD,
        WACOM_MO,
+       WACOM_MSPROT,
        TABLETPC,
        TABLETPCE,
        TABLETPC2FG,
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 97faf87..0654118 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -385,6 +385,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                features->pktlen = 
WACOM_PKGLEN_BBTOUCH;
                                                break;
 
+                                       case WACOM_MSPROT:
+                                               features->pktlen = 
WACOM_PKGLEN_MSPROT;
+                                               break;
+
                                        default:
                                                features->pktlen = 
WACOM_PKGLEN_GRAPHIRE;
                                                break;
@@ -421,6 +425,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                i += 9;
                                                break;
 
+                                       case WACOM_MSPROT:
                                        case MTTPC_B:
                                                features->x_max =
                                                        
get_unaligned_le16(&report[i + 3]);
@@ -491,6 +496,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                i += 12;
                                                break;
 
+                                       case WACOM_MSPROT:
                                        case MTTPC_B:
                                                features->y_max =
                                                        
get_unaligned_le16(&report[i + 3]);
@@ -613,6 +619,9 @@ static int wacom_query_tablet_data(struct usb_interface 
*intf, struct wacom_feat
                else if (features->type == WACOM_27QHDT) {
                        return wacom_set_device_mode(intf, 131, 3, 2);
                }
+               else if (features->type == WACOM_MSPROT) {
+                       return wacom_set_device_mode(intf, 14, 2, 2);
+               }
        } else if (features->device_type == BTN_TOOL_PEN) {
                if (features->type <= BAMBOO_PT) {
                        return wacom_set_device_mode(intf, 2, 2, 2);
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 56d603a..5933417 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -588,6 +588,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
                break;
 
        case 0x82a: /* Eraser */
+       case 0x84a:
        case 0x85a:
        case 0x91a:
        case 0xd1a:
@@ -1103,6 +1104,54 @@ static int wacom_wac_finger_count_touches(struct 
wacom_wac *wacom)
        return count;
 }
 
+static int wacom_msprot_irq(struct wacom_wac *wacom)
+{
+       struct input_dev *input = wacom->input;
+       unsigned char *data = wacom->data;
+       int i;
+       int current_num_contacts = data[2];
+       int contacts_to_send = 0;
+
+       if (current_num_contacts)
+               wacom->num_contacts_left = current_num_contacts;
+
+       contacts_to_send = min(5, wacom->num_contacts_left);
+
+       for (i = 0; i < contacts_to_send; i++) {
+               int offset = WACOM_BYTES_PER_MSPROT_PACKET * i + 3;
+               bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
+               int id = get_unaligned_le16(&data[offset + 1]);
+               int slot = find_slot_from_contactid(wacom, id);
+
+               if (slot < 0)
+                       continue;
+
+               input_mt_slot(input, slot);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+               if (touch) {
+                       int x = get_unaligned_le16(&data[offset + 3]);
+                       int y = get_unaligned_le16(&data[offset + 5]);
+                       int w = get_unaligned_le16(&data[offset + 7]);
+                       int h = get_unaligned_le16(&data[offset + 9]);
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       input_report_abs(input, ABS_MT_WIDTH_MAJOR, max(w, h));
+                       input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
+                       input_report_abs(input, ABS_MT_ORIENTATION, w > h);
+               }
+               wacom->slots[slot] = touch ? id : -1;
+       }
+
+       wacom->num_contacts_left -= contacts_to_send;
+       if (wacom->num_contacts_left <= 0) {
+               wacom->num_contacts_left = 0;
+               wacom->shared->touch_down = 
wacom_wac_finger_count_touches(wacom);
+       }
+
+       input_mt_report_pointer_emulation(input, true);
+       return 1;
+}
+
 static int wacom_24hdt_irq(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
@@ -1652,6 +1701,160 @@ static int wacom_status_irq(struct wacom_wac 
*wacom_wac, size_t len)
        return 0;
 }
 
+static int wacom_mspro_device_irq(struct wacom_wac *wacom)
+{
+       struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
+       struct wacom_features *features = &wacom->features;
+       unsigned char *data = wacom->data;
+       bool bat_charging;
+       int battery_level;
+
+       battery_level = data[1] & 0x7F;
+       bat_charging = data[1] & 0x80;
+
+       if (!w->battery.battery.dev &&
+           !(features->quirks & WACOM_QUIRK_BATTERY)) {
+               features->quirks |= WACOM_QUIRK_BATTERY;
+               wacom_schedule_work(wacom, WACOM_WORKER_BATTERY);
+       }
+
+       wacom_notify_battery(wacom, battery_level, bat_charging, 1,
+                            bat_charging);
+
+       return 0;
+}
+
+static int wacom_mspro_pad_irq(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       int nbuttons = features->numbered_buttons;
+       bool prox;
+       int buttons, ring;
+
+       switch (nbuttons) {
+               case 11:
+                       buttons = (data[1] >> 1) | (data[3] << 6);
+                       break;
+               case 13:
+                       buttons = data[1] | (data[3] << 8);
+                       break;
+               default:
+                       dev_warn(input->dev.parent, "%s: unsupported device 
#%d\n", __func__, data[0]);
+                       return 0;
+       }
+
+       ring = le16_to_cpup((__le16 *)&data[4]);
+
+       prox = buttons || ring;
+
+       wacom_report_numbered_buttons(input, nbuttons, buttons);
+       input_report_abs(input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
+
+       input_report_key(input, wacom->tool[1], prox ? 1 : 0);
+       input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+
+       input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+       return 1;
+}
+
+static int wacom_mspro_pen_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       bool tip, sw1, sw2, range, proximity;
+       unsigned int x, y;
+       unsigned int pressure;
+       int tilt_x, tilt_y;
+       int rotation;
+       unsigned int fingerwheel;
+       unsigned int height;
+       u64 tool_uid;
+       unsigned int tool_type;
+
+       if (delay_pen_events(wacom))
+               return 1;
+
+       tip         = data[1] & 0x01;
+       sw1         = data[1] & 0x02;
+       sw2         = data[1] & 0x04;
+       /* eraser   = data[1] & 0x08; */
+       /* invert   = data[1] & 0x10; */
+       range       = data[1] & 0x20;
+       proximity   = data[1] & 0x40;
+       x           = le32_to_cpup((__le32 *)&data[2]) & 0xFFFFFF;
+       y           = le32_to_cpup((__le32 *)&data[5]) & 0xFFFFFF;
+       pressure    = le16_to_cpup((__le16 *)&data[8]);
+       tilt_x      = data[10];
+       tilt_y      = data[11];
+       rotation    = le16_to_cpup((__le16 *)&data[12]);
+       fingerwheel = le16_to_cpup((__le16 *)&data[14]);
+       height      = data[16];
+       tool_uid    = le64_to_cpup((__le64 *)&data[17]);
+       tool_type   = le16_to_cpup((__le16 *)&data[25]);
+
+       wacom->serial[0] = (tool_uid & 0xFFFFFFFF);
+       wacom->id[0]     = (tool_uid >> 32) | tool_type;
+       if (range) {
+               wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0] & 
0xFFFFF);
+       }
+
+       /* pointer going from fully "in range" to merely "in proximity" */
+       if (!range && wacom->tool[0]) {
+               height = wacom->features.distance_max;
+       }
+
+       /*
+        * only report data if there's a tool for userspace to associate
+        * the events with.
+        */
+       if (wacom->tool[0]) {
+               input_report_key(input, BTN_TOUCH, tip);
+               input_report_key(input, BTN_STYLUS, sw1);
+               input_report_key(input, BTN_STYLUS2, sw2);
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+               input_report_abs(input, ABS_PRESSURE, pressure);
+               input_report_abs(input, ABS_TILT_X, tilt_x);
+               input_report_abs(input, ABS_TILT_Y, tilt_y);
+               input_report_abs(input, ABS_Z, rotation);
+               input_report_abs(input, ABS_WHEEL, fingerwheel);
+               input_report_abs(input, ABS_DISTANCE, height);
+               input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
+               input_report_abs(input, ABS_MISC, 
wacom_intuos_id_mangle(wacom->id[0]));
+               input_report_key(input, wacom->tool[0], range ? 1 : 0);
+
+               if (!range)
+                       wacom->tool[0] = 0;
+       }
+
+       wacom->shared->stylus_in_proximity = proximity;
+
+       return 1;
+}
+
+static int wacom_mspro_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+
+       switch (data[0]) {
+               case WACOM_REPORT_MSPRO:
+                       return wacom_mspro_pen_irq(wacom);
+               case WACOM_REPORT_MSPROPAD:
+                       return wacom_mspro_pad_irq(wacom);
+               case WACOM_REPORT_MSPRODEVICE:
+                       return wacom_mspro_device_irq(wacom);
+               default:
+                       dev_dbg(input->dev.parent,
+                               "%s: received unknown report #%d\n", __func__, 
data[0]);
+                       break;
+       }
+       return 0;
+}
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 {
        bool sync;
@@ -1704,6 +1907,14 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t 
len)
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
+       case WACOM_MSPRO:
+               sync = wacom_mspro_irq(wacom_wac);
+               break;
+
+       case WACOM_MSPROT:
+               sync = wacom_msprot_irq(wacom_wac);
+               break;
+
        case WACOM_24HDT:
        case WACOM_27QHDT:
                sync = wacom_24hdt_irq(wacom_wac);
@@ -2017,6 +2228,7 @@ int wacom_setup_input_capabilities(struct input_dev 
*input_dev,
        case WACOM_13HD:
        case CINTIQ_HYBRID:
        case CINTIQ_COMPANION_2:
+       case WACOM_MSPRO:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                /* fall through */
 
@@ -2104,6 +2316,7 @@ int wacom_setup_input_capabilities(struct input_dev 
*input_dev,
                }
                break;
 
+       case WACOM_MSPROT:
        case WACOM_24HDT:
                if (features->device_type == BTN_TOOL_FINGER) {
                        input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 
features->x_max, 0, 0);
@@ -2767,6 +2980,25 @@ static const struct wacom_features wacom_features_0x343 =
          0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET};
+static const struct wacom_features wacom_features_0x34A =
+       { "Wacom MobileStudio Pro 13 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT, /* Touch */
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34D };
+static const struct wacom_features wacom_features_0x34B =
+       { "Wacom MobileStudio Pro 16 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT, /* Touch */
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34E };
+static const struct wacom_features wacom_features_0x34D =
+       { "Wacom MobileStudio Pro 13", WACOM_PKGLEN_MSPRO, 59552, 33848, 8191, 
63,
+         WACOM_MSPRO, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 11,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34A };
+static const struct wacom_features wacom_features_0x34E =
+       { "Wacom MobileStudio Pro 16", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 
63,
+         WACOM_MSPRO, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 13,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34B };
+
 #define USB_DEVICE_WACOM(prod)                                 \
        USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
        .driver_info = (kernel_ulong_t)&wacom_features_##prod
@@ -2934,6 +3166,10 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_DETAILED(0x33D, USB_CLASS_HID, 0, 0) },
        { USB_DEVICE_DETAILED(0x33E, USB_CLASS_HID, 0, 0) },
        { USB_DEVICE_WACOM(0x343) },
+       { USB_DEVICE_WACOM(0x34A) },
+       { USB_DEVICE_WACOM(0x34B) },
+       { USB_DEVICE_WACOM(0x34D) },
+       { USB_DEVICE_WACOM(0x34E) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }
 };
diff --git a/2.6.38/wacom_wac.h b/2.6.38/wacom_wac.h
index cc34b0b..4caa2f5 100644
--- a/2.6.38/wacom_wac.h
+++ b/2.6.38/wacom_wac.h
@@ -35,11 +35,14 @@
 #define WACOM_PKGLEN_DTUS      68
 #define WACOM_PKGLEN_PENABLED   8
 #define WACOM_PKGLEN_27QHDT    64
+#define WACOM_PKGLEN_MSPRO     64
+#define WACOM_PKGLEN_MSPROT    50
 
 /* wacom data size per MT contact */
 #define WACOM_BYTES_PER_MT_PACKET      11
 #define WACOM_BYTES_PER_24HDT_PACKET   14
 #define WACOM_BYTES_PER_QHDTHID_PACKET  6
+#define WACOM_BYTES_PER_MSPROT_PACKET   9
 
 /* device IDs */
 #define STYLUS_DEVICE_ID       0x02
@@ -62,10 +65,13 @@
 #define WACOM_REPORT_TPCHID            15
 #define WACOM_REPORT_TPCST             16
 #define WACOM_REPORT_CINTIQ            16
+#define WACOM_REPORT_MSPRO             16
 #define WACOM_REPORT_INTUOS_PEN                16
 #define WACOM_REPORT_CINTIQPAD         17
 #define WACOM_REPORT_DTUS              17
+#define WACOM_REPORT_MSPROPAD          17
 #define WACOM_REPORT_TPC1FGE           18
+#define WACOM_REPORT_MSPRODEVICE       19
 #define WACOM_REPORT_24HDT             1
 #define WACOM_REPORT_WL                        128
 #define WACOM_REPORT_USB               192
@@ -107,6 +113,7 @@ enum {
        WACOM_27QHD,
        CINTIQ_HYBRID,
        CINTIQ_COMPANION_2,
+       WACOM_MSPRO,
        CINTIQ,
        WACOM_BEE,
        WACOM_13HD,
@@ -116,6 +123,7 @@ enum {
        BAMBOO_PT,
        WACOM_24HDT,
        WACOM_27QHDT,
+       WACOM_MSPROT,
        WIRELESS,
        REMOTE,
        TABLETPC,   /* add new TPC below */
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 75d363e..d54c71a 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -386,6 +386,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                features->pktlen = 
WACOM_PKGLEN_BBTOUCH;
                                                break;
 
+                                       case WACOM_MSPROT:
+                                               features->pktlen = 
WACOM_PKGLEN_MSPROT;
+                                               break;
+
                                        default:
                                                features->pktlen = 
WACOM_PKGLEN_GRAPHIRE;
                                                break;
@@ -422,6 +426,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                i += 9;
                                                break;
 
+                                       case WACOM_MSPROT:
                                        case MTTPC_B:
                                                features->x_max =
                                                        
get_unaligned_le16(&report[i + 3]);
@@ -492,6 +497,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                i += 12;
                                                break;
 
+                                       case WACOM_MSPROT:
                                        case MTTPC_B:
                                                features->y_max =
                                                        
get_unaligned_le16(&report[i + 3]);
@@ -614,6 +620,9 @@ static int wacom_query_tablet_data(struct usb_interface 
*intf, struct wacom_feat
                else if (features->type == WACOM_27QHDT) {
                        return wacom_set_device_mode(intf, 131, 3, 2);
                }
+               else if (features->type == WACOM_MSPROT) {
+                       return wacom_set_device_mode(intf, 14, 2, 2);
+               }
        } else if (features->device_type == BTN_TOOL_PEN) {
                if (features->type <= BAMBOO_PT) {
                        return wacom_set_device_mode(intf, 2, 2, 2);
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 0ea1f27..458b03b 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -588,6 +588,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
                break;
 
        case 0x82a: /* Eraser */
+       case 0x84a:
        case 0x85a:
        case 0x91a:
        case 0xd1a:
@@ -1084,6 +1085,53 @@ static int wacom_wac_finger_count_touches(struct 
wacom_wac *wacom)
        return count;
 }
 
+static int wacom_msprot_irq(struct wacom_wac *wacom)
+{
+       struct input_dev *input = wacom->input;
+       unsigned char *data = wacom->data;
+       int i;
+       int current_num_contacts = data[2];
+       int contacts_to_send = 0;
+
+       if (current_num_contacts)
+               wacom->num_contacts_left = current_num_contacts;
+
+       contacts_to_send = min(5, wacom->num_contacts_left);
+
+       for (i = 0; i < contacts_to_send; i++) {
+               int offset = WACOM_BYTES_PER_MSPROT_PACKET * i + 3;
+               bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
+               int id = get_unaligned_le16(&data[offset + 1]);
+               int slot = input_mt_get_slot_by_key(input, id);
+
+               if (slot < 0)
+                       continue;
+
+               input_mt_slot(input, slot);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+               if (touch) {
+                       int x = get_unaligned_le16(&data[offset + 3]);
+                       int y = get_unaligned_le16(&data[offset + 5]);
+                       int w = get_unaligned_le16(&data[offset + 7]);
+                       int h = get_unaligned_le16(&data[offset + 9]);
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       input_report_abs(input, ABS_MT_WIDTH_MAJOR, max(w, h));
+                       input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
+                       input_report_abs(input, ABS_MT_ORIENTATION, w > h);
+               }
+       }
+
+       wacom->num_contacts_left -= contacts_to_send;
+       if (wacom->num_contacts_left <= 0) {
+               wacom->num_contacts_left = 0;
+               wacom->shared->touch_down = 
wacom_wac_finger_count_touches(wacom);
+       }
+
+       input_mt_sync_frame(input);
+       return 1;
+}
+
 static int wacom_24hdt_irq(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
@@ -1633,6 +1681,160 @@ static int wacom_status_irq(struct wacom_wac 
*wacom_wac, size_t len)
        return 0;
 }
 
+static int wacom_mspro_device_irq(struct wacom_wac *wacom)
+{
+       struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
+       struct wacom_features *features = &wacom->features;
+       unsigned char *data = wacom->data;
+       bool bat_charging;
+       int battery_level;
+
+       battery_level = data[1] & 0x7F;
+       bat_charging = data[1] & 0x80;
+
+       if (!w->battery.battery.dev &&
+           !(features->quirks & WACOM_QUIRK_BATTERY)) {
+               features->quirks |= WACOM_QUIRK_BATTERY;
+               wacom_schedule_work(wacom, WACOM_WORKER_BATTERY);
+       }
+
+       wacom_notify_battery(wacom, battery_level, bat_charging, 1,
+                            bat_charging);
+
+       return 0;
+}
+
+static int wacom_mspro_pad_irq(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       int nbuttons = features->numbered_buttons;
+       bool prox;
+       int buttons, ring;
+
+       switch (nbuttons) {
+               case 11:
+                       buttons = (data[1] >> 1) | (data[3] << 6);
+                       break;
+               case 13:
+                       buttons = data[1] | (data[3] << 8);
+                       break;
+               default:
+                       dev_warn(input->dev.parent, "%s: unsupported device 
#%d\n", __func__, data[0]);
+                       return 0;
+       }
+
+       ring = le16_to_cpup((__le16 *)&data[4]);
+
+       prox = buttons || ring;
+
+       wacom_report_numbered_buttons(input, nbuttons, buttons);
+       input_report_abs(input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
+
+       input_report_key(input, wacom->tool[1], prox ? 1 : 0);
+       input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+
+       input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+       return 1;
+}
+
+static int wacom_mspro_pen_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       bool tip, sw1, sw2, range, proximity;
+       unsigned int x, y;
+       unsigned int pressure;
+       int tilt_x, tilt_y;
+       int rotation;
+       unsigned int fingerwheel;
+       unsigned int height;
+       u64 tool_uid;
+       unsigned int tool_type;
+
+       if (delay_pen_events(wacom))
+               return 1;
+
+       tip         = data[1] & 0x01;
+       sw1         = data[1] & 0x02;
+       sw2         = data[1] & 0x04;
+       /* eraser   = data[1] & 0x08; */
+       /* invert   = data[1] & 0x10; */
+       range       = data[1] & 0x20;
+       proximity   = data[1] & 0x40;
+       x           = le32_to_cpup((__le32 *)&data[2]) & 0xFFFFFF;
+       y           = le32_to_cpup((__le32 *)&data[5]) & 0xFFFFFF;
+       pressure    = le16_to_cpup((__le16 *)&data[8]);
+       tilt_x      = data[10];
+       tilt_y      = data[11];
+       rotation    = le16_to_cpup((__le16 *)&data[12]);
+       fingerwheel = le16_to_cpup((__le16 *)&data[14]);
+       height      = data[16];
+       tool_uid    = le64_to_cpup((__le64 *)&data[17]);
+       tool_type   = le16_to_cpup((__le16 *)&data[25]);
+
+       wacom->serial[0] = (tool_uid & 0xFFFFFFFF);
+       wacom->id[0]     = (tool_uid >> 32) | tool_type;
+       if (range) {
+               wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0] & 
0xFFFFF);
+       }
+
+       /* pointer going from fully "in range" to merely "in proximity" */
+       if (!range && wacom->tool[0]) {
+               height = wacom->features.distance_max;
+       }
+
+       /*
+        * only report data if there's a tool for userspace to associate
+        * the events with.
+        */
+       if (wacom->tool[0]) {
+               input_report_key(input, BTN_TOUCH, tip);
+               input_report_key(input, BTN_STYLUS, sw1);
+               input_report_key(input, BTN_STYLUS2, sw2);
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+               input_report_abs(input, ABS_PRESSURE, pressure);
+               input_report_abs(input, ABS_TILT_X, tilt_x);
+               input_report_abs(input, ABS_TILT_Y, tilt_y);
+               input_report_abs(input, ABS_Z, rotation);
+               input_report_abs(input, ABS_WHEEL, fingerwheel);
+               input_report_abs(input, ABS_DISTANCE, height);
+               input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
+               input_report_abs(input, ABS_MISC, 
wacom_intuos_id_mangle(wacom->id[0]));
+               input_report_key(input, wacom->tool[0], range ? 1 : 0);
+
+               if (!range)
+                       wacom->tool[0] = 0;
+       }
+
+       wacom->shared->stylus_in_proximity = proximity;
+
+       return 1;
+}
+
+static int wacom_mspro_irq(struct wacom_wac *wacom)
+{
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+
+       switch (data[0]) {
+               case WACOM_REPORT_MSPRO:
+                       return wacom_mspro_pen_irq(wacom);
+               case WACOM_REPORT_MSPROPAD:
+                       return wacom_mspro_pad_irq(wacom);
+               case WACOM_REPORT_MSPRODEVICE:
+                       return wacom_mspro_device_irq(wacom);
+               default:
+                       dev_dbg(input->dev.parent,
+                               "%s: received unknown report #%d\n", __func__, 
data[0]);
+                       break;
+       }
+       return 0;
+}
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 {
        bool sync;
@@ -1685,6 +1887,14 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t 
len)
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
+       case WACOM_MSPRO:
+               sync = wacom_mspro_irq(wacom_wac);
+               break;
+
+       case WACOM_MSPROT:
+               sync = wacom_msprot_irq(wacom_wac);
+               break;
+
        case WACOM_24HDT:
        case WACOM_27QHDT:
                sync = wacom_24hdt_irq(wacom_wac);
@@ -2003,6 +2213,7 @@ int wacom_setup_input_capabilities(struct input_dev 
*input_dev,
        case WACOM_13HD:
        case CINTIQ_HYBRID:
        case CINTIQ_COMPANION_2:
+       case WACOM_MSPRO:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                /* fall through */
 
@@ -2093,6 +2304,7 @@ int wacom_setup_input_capabilities(struct input_dev 
*input_dev,
                __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
 
+       case WACOM_MSPROT:
        case WACOM_24HDT:
                if (features->device_type == BTN_TOOL_FINGER) {
                        input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 
features->x_max, 0, 0);
@@ -2724,6 +2936,24 @@ static const struct wacom_features wacom_features_0x343 =
          DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
+static const struct wacom_features wacom_features_0x34A =
+       { "Wacom MobileStudio Pro 13 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT, /* Touch */
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34D };
+static const struct wacom_features wacom_features_0x34B =
+       { "Wacom MobileStudio Pro 16 Touch", WACOM_PKGLEN_MSPROT, .type = 
WACOM_MSPROT, /* Touch */
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34E };
+static const struct wacom_features wacom_features_0x34D =
+       { "Wacom MobileStudio Pro 13", WACOM_PKGLEN_MSPRO, 59552, 33848, 8191, 
63,
+         WACOM_MSPRO, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 11,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34A };
+static const struct wacom_features wacom_features_0x34E =
+       { "Wacom MobileStudio Pro 16", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 
63,
+         WACOM_MSPRO, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 13,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34B };
 
 #define USB_DEVICE_WACOM(prod)                                 \
        USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
@@ -2892,6 +3122,10 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_DETAILED(0x33D, USB_CLASS_HID, 0, 0) },
        { USB_DEVICE_DETAILED(0x33E, USB_CLASS_HID, 0, 0) },
        { USB_DEVICE_WACOM(0x343) },
+       { USB_DEVICE_WACOM(0x34A) },
+       { USB_DEVICE_WACOM(0x34B) },
+       { USB_DEVICE_WACOM(0x34D) },
+       { USB_DEVICE_WACOM(0x34E) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }
 };
diff --git a/3.7/wacom_wac.h b/3.7/wacom_wac.h
index 21fc30d..cb42c2e 100644
--- a/3.7/wacom_wac.h
+++ b/3.7/wacom_wac.h
@@ -35,11 +35,14 @@
 #define WACOM_PKGLEN_DTUS      68
 #define WACOM_PKGLEN_PENABLED   8
 #define WACOM_PKGLEN_27QHDT    64
+#define WACOM_PKGLEN_MSPRO     64
+#define WACOM_PKGLEN_MSPROT    50
 
 /* wacom data size per MT contact */
 #define WACOM_BYTES_PER_MT_PACKET      11
 #define WACOM_BYTES_PER_24HDT_PACKET   14
 #define WACOM_BYTES_PER_QHDTHID_PACKET  6
+#define WACOM_BYTES_PER_MSPROT_PACKET   9
 
 /* device IDs */
 #define STYLUS_DEVICE_ID       0x02
@@ -62,10 +65,13 @@
 #define WACOM_REPORT_TPCHID            15
 #define WACOM_REPORT_TPCST             16
 #define WACOM_REPORT_CINTIQ            16
+#define WACOM_REPORT_MSPRO             16
 #define WACOM_REPORT_INTUOS_PEN                16
 #define WACOM_REPORT_CINTIQPAD         17
 #define WACOM_REPORT_DTUS              17
+#define WACOM_REPORT_MSPROPAD          17
 #define WACOM_REPORT_TPC1FGE           18
+#define WACOM_REPORT_MSPRODEVICE       19
 #define WACOM_REPORT_24HDT             1
 #define WACOM_REPORT_WL                        128
 #define WACOM_REPORT_USB               192
@@ -107,6 +113,7 @@ enum {
        WACOM_27QHD,
        CINTIQ_HYBRID,
        CINTIQ_COMPANION_2,
+       WACOM_MSPRO,
        CINTIQ,
        WACOM_BEE,
        WACOM_13HD,
@@ -116,6 +123,7 @@ enum {
        BAMBOO_PT,
        WACOM_24HDT,
        WACOM_27QHDT,
+       WACOM_MSPROT,
        WIRELESS,
        REMOTE,
        TABLETPC,   /* add new TPC below */
-- 
2.10.2


------------------------------------------------------------------------------
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to