include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / hid / hid-ntrig.c
index 38b2364..9b24fc5 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 
 #include "hid-ids.h"
 
                                        EV_KEY, (c))
 
 struct ntrig_data {
-       __s32 x, y, id, w, h;
-       bool reading_a_point, found_contact_id;
-       bool pen_active;
-       bool finger_active;
-       bool inverted;
+       /* Incoming raw values for a single contact */
+       __u16 x, y, w, h;
+       __u16 id;
+       __u8 confidence;
+
+       bool reading_mt;
+       __u8 first_contact_confidence;
+
+       __u8 mt_footer[4];
+       __u8 mt_foot_count;
 };
 
 /*
@@ -42,12 +48,11 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
-       /* No special mappings needed for the pen */
-       if (field->application == HID_DG_PEN)
+       /* No special mappings needed for the pen and single touch */
+       if (field->physical)
                return 0;
 
        switch (usage->hid & HID_USAGE_PAGE) {
-
        case HID_UP_GENDESK:
                switch (usage->hid) {
                case HID_GD_X:
@@ -70,18 +75,12 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        case HID_UP_DIGITIZER:
                switch (usage->hid) {
                /* we do not want to map these for now */
-               case HID_DG_CONTACTID: /* value is useless */
+               case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */
                case HID_DG_INPUTMODE:
                case HID_DG_DEVICEINDEX:
-               case HID_DG_CONTACTCOUNT:
                case HID_DG_CONTACTMAX:
                        return -1;
 
-               /* original mapping by Rafi Rubin */
-               case HID_DG_CONFIDENCE:
-                       nt_map_key_clear(BTN_TOOL_DOUBLETAP);
-                       return 1;
-
                /* width/height mapped on TouchMajor/TouchMinor/Orientation */
                case HID_DG_WIDTH:
                        hid_map_usage(hi, usage, bit, max,
@@ -108,9 +107,10 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
-       /* No special mappings needed for the pen */
-       if (field->application == HID_DG_PEN)
+       /* No special mappings needed for the pen and single touch */
+       if (field->physical)
                return 0;
+
        if (usage->type == EV_KEY || usage->type == EV_REL
                        || usage->type == EV_ABS)
                clear_bit(usage->code, *bit);
@@ -136,29 +136,27 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
 
         if (hid->claimed & HID_CLAIMED_INPUT) {
                switch (usage->hid) {
-
-               case HID_DG_INRANGE:
-                       if (field->application & 0x3)
-                               nd->pen_active = (value != 0);
-                       else
-                               nd->finger_active = (value != 0);
-                       return 0;
-
-               case HID_DG_INVERT:
-                       nd->inverted = value;
-                       return 0;
-
+               case 0xff000001:
+                       /* Tag indicating the start of a multitouch group */
+                       nd->reading_mt = 1;
+                       nd->first_contact_confidence = 0;
+                       break;
+               case HID_DG_TIPSWITCH:
+                       /* Prevent emission of touch until validated */
+                       return 1;
+               case HID_DG_CONFIDENCE:
+                       nd->confidence = value;
+                       break;
                case HID_GD_X:
                        nd->x = value;
-                       nd->reading_a_point = 1;
+                       /* Clear the contact footer */
+                       nd->mt_foot_count = 0;
                        break;
                case HID_GD_Y:
                        nd->y = value;
                        break;
                case HID_DG_CONTACTID:
                        nd->id = value;
-                       /* we receive this only when in multitouch mode */
-                       nd->found_contact_id = 1;
                        break;
                case HID_DG_WIDTH:
                        nd->w = value;
@@ -170,33 +168,11 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                         * report received in a finger event. We want
                         * to emit a normal (X, Y) position
                         */
-                       if (!nd->found_contact_id) {
-                               if (nd->pen_active && nd->finger_active) {
-                                       input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
-                                       input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
-                               }
-                               input_event(input, EV_ABS, ABS_X, nd->x);
-                               input_event(input, EV_ABS, ABS_Y, nd->y);
-                       }
-                       break;
-               case HID_DG_TIPPRESSURE:
-                       /*
-                        * when in single touch mode, this is the last
-                        * report received in a pen event. We want
-                        * to emit a normal (X, Y) position
-                        */
-                       if (! nd->found_contact_id) {
-                               if (nd->pen_active && nd->finger_active) {
-                                       input_report_key(input,
-                                                       nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
-                                                       , 0);
-                                       input_report_key(input,
-                                                       nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
-                                                       , 1);
-                               }
+                       if (!nd->reading_mt) {
+                               input_report_key(input, BTN_TOOL_DOUBLETAP,
+                                                (nd->confidence != 0));
                                input_event(input, EV_ABS, ABS_X, nd->x);
                                input_event(input, EV_ABS, ABS_Y, nd->y);
-                               input_event(input, EV_ABS, ABS_PRESSURE, value);
                        }
                        break;
                case 0xff000002:
@@ -206,10 +182,34 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                         * this usage tells if the contact point is real
                         * or a placeholder
                         */
-                       if (!nd->reading_a_point || value != 1)
+
+                       /* Shouldn't get more than 4 footer packets, so skip */
+                       if (nd->mt_foot_count >= 4)
+                               break;
+
+                       nd->mt_footer[nd->mt_foot_count++] = value;
+
+                       /* if the footer isn't complete break */
+                       if (nd->mt_foot_count != 4)
+                               break;
+
+                       /* Pen activity signal, trigger end of touch. */
+                       if (nd->mt_footer[2]) {
+                               nd->confidence = 0;
+                               break;
+                       }
+
+                       /* If the contact was invalid */
+                       if (!(nd->confidence && nd->mt_footer[0])
+                                       || nd->w <= 250
+                                       || nd->h <= 190) {
+                               nd->confidence = 0;
                                break;
+                       }
+
                        /* emit a normal (X, Y) for the first point only */
                        if (nd->id == 0) {
+                               nd->first_contact_confidence = nd->confidence;
                                input_event(input, EV_ABS, ABS_X, nd->x);
                                input_event(input, EV_ABS, ABS_Y, nd->y);
                        }
@@ -231,8 +231,40 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                                                ABS_MT_TOUCH_MINOR, nd->w);
                        }
                        input_mt_sync(field->hidinput->input);
-                       nd->reading_a_point = 0;
-                       nd->found_contact_id = 0;
+                       break;
+
+               case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
+                       if (!nd->reading_mt)
+                               break;
+
+                       nd->reading_mt = 0;
+
+                       if (nd->first_contact_confidence) {
+                               switch (value) {
+                               case 0: /* for single touch devices */
+                               case 1:
+                                       input_report_key(input,
+                                                       BTN_TOOL_DOUBLETAP, 1);
+                                       break;
+                               case 2:
+                                       input_report_key(input,
+                                                       BTN_TOOL_TRIPLETAP, 1);
+                                       break;
+                               case 3:
+                               default:
+                                       input_report_key(input,
+                                                       BTN_TOOL_QUADTAP, 1);
+                               }
+                               input_report_key(input, BTN_TOUCH, 1);
+                       } else {
+                               input_report_key(input,
+                                               BTN_TOOL_DOUBLETAP, 0);
+                               input_report_key(input,
+                                               BTN_TOOL_TRIPLETAP, 0);
+                               input_report_key(input,
+                                               BTN_TOOL_QUADTAP, 0);
+                               input_report_key(input, BTN_TOUCH, 0);
+                       }
                        break;
 
                default:
@@ -263,8 +295,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
                dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
                return -ENOMEM;
        }
-       nd->reading_a_point = 0;
-       nd->found_contact_id = 0;
+
+       nd->reading_mt = 0;
        hid_set_drvdata(hdev, nd);
 
        ret = hid_parse(hdev);
@@ -281,12 +313,27 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 
        list_for_each_entry(hidinput, &hdev->inputs, list) {
+               if (hidinput->report->maxfield < 1)
+                       continue;
+
                input = hidinput->input;
                switch (hidinput->report->field[0]->application) {
                case HID_DG_PEN:
                        input->name = "N-Trig Pen";
                        break;
                case HID_DG_TOUCHSCREEN:
+                       /* These keys are redundant for fingers, clear them
+                        * to prevent incorrect identification */
+                       __clear_bit(BTN_TOOL_PEN, input->keybit);
+                       __clear_bit(BTN_TOOL_FINGER, input->keybit);
+                       __clear_bit(BTN_0, input->keybit);
+                       /*
+                        * A little something special to enable
+                        * two and three finger taps.
+                        */
+                       __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+                       __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+                       __set_bit(BTN_TOOL_QUADTAP, input->keybit);
                        /*
                         * The physical touchscreen (single touch)
                         * input has a value for physical, whereas