]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - drivers/hid/hid-multitouch.c
Merge branches 'for-3.9/logitech', 'for-3.9/multitouch', 'for-3.9/ntrig', 'for-3...
[linux-imx.git] / drivers / hid / hid-multitouch.c
index 46d8136daf99f0ce312ce89394795e48ff02d15c..7a1ebb867cf499596e9c4fe5b1a43860b86d4351 100644 (file)
@@ -54,6 +54,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_NO_AREA               (1 << 9)
 #define MT_QUIRK_IGNORE_DUPLICATES     (1 << 10)
 #define MT_QUIRK_HOVERING              (1 << 11)
+#define MT_QUIRK_CONTACT_CNT_ACCURATE  (1 << 12)
 
 struct mt_slot {
        __s32 x, y, cx, cy, p, w, h;
@@ -83,8 +84,11 @@ struct mt_device {
        struct mt_class mtclass;        /* our mt device class */
        struct mt_fields *fields;       /* temporary placeholder for storing the
                                           multitouch fields */
+       int cc_index;   /* contact count field index in the report */
+       int cc_value_index;     /* contact count value index in the field */
        unsigned last_field_index;      /* last field index of the report */
        unsigned last_slot_field;       /* the last field of a slot */
+       unsigned mt_report_id;  /* the report ID of the multitouch device */
        __s8 inputmode;         /* InputMode HID feature, -1 if non-existent */
        __s8 inputmode_index;   /* InputMode HID feature index in the report */
        __s8 maxcontact_report_id;      /* Maximum Contact Number HID feature,
@@ -111,6 +115,9 @@ struct mt_device {
 #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER      0x0007
 #define MT_CLS_DUAL_NSMU_CONTACTID             0x0008
 #define MT_CLS_INRANGE_CONTACTNUMBER           0x0009
+#define MT_CLS_NSMU                            0x000a
+#define MT_CLS_DUAL_CONTACT_NUMBER             0x0010
+#define MT_CLS_DUAL_CONTACT_ID                 0x0011
 
 /* vendor specific classes */
 #define MT_CLS_3M                              0x0101
@@ -144,6 +151,9 @@ static int cypress_compute_slot(struct mt_device *td)
 
 static struct mt_class mt_classes[] = {
        { .name = MT_CLS_DEFAULT,
+               .quirks = MT_QUIRK_ALWAYS_VALID |
+                       MT_QUIRK_CONTACT_CNT_ACCURATE },
+       { .name = MT_CLS_NSMU,
                .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
        { .name = MT_CLS_SERIAL,
                .quirks = MT_QUIRK_ALWAYS_VALID},
@@ -170,6 +180,16 @@ static struct mt_class mt_classes[] = {
        { .name = MT_CLS_INRANGE_CONTACTNUMBER,
                .quirks = MT_QUIRK_VALID_IS_INRANGE |
                        MT_QUIRK_SLOT_IS_CONTACTNUMBER },
+       { .name = MT_CLS_DUAL_CONTACT_NUMBER,
+               .quirks = MT_QUIRK_ALWAYS_VALID |
+                       MT_QUIRK_CONTACT_CNT_ACCURATE |
+                       MT_QUIRK_SLOT_IS_CONTACTNUMBER,
+               .maxcontacts = 2 },
+       { .name = MT_CLS_DUAL_CONTACT_ID,
+               .quirks = MT_QUIRK_ALWAYS_VALID |
+                       MT_QUIRK_CONTACT_CNT_ACCURATE |
+                       MT_QUIRK_SLOT_IS_CONTACTID,
+               .maxcontacts = 2 },
 
        /*
         * vendor specific classes
@@ -250,6 +270,9 @@ static ssize_t mt_set_quirks(struct device *dev,
 
        td->mtclass.quirks = val;
 
+       if (td->cc_index < 0)
+               td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
+
        return count;
 }
 
@@ -301,6 +324,7 @@ static void mt_feature_mapping(struct hid_device *hdev,
                        *quirks |= MT_QUIRK_ALWAYS_VALID;
                        *quirks |= MT_QUIRK_IGNORE_DUPLICATES;
                        *quirks |= MT_QUIRK_HOVERING;
+                       *quirks |= MT_QUIRK_CONTACT_CNT_ACCURATE;
                        *quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
                        *quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
                        *quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
@@ -428,6 +452,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        td->touches_by_report++;
+                       td->mt_report_id = field->report->id;
                        return 1;
                case HID_DG_WIDTH:
                        hid_map_usage(hi, usage, bit, max,
@@ -459,6 +484,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTCOUNT:
+                       td->cc_index = field->index;
+                       td->cc_value_index = usage->usage_index;
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTMAX:
@@ -523,6 +550,10 @@ static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
  */
 static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 {
+       if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
+           td->num_received >= td->num_expected)
+               return;
+
        if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
                int slotnum = mt_compute_slot(td, input);
                struct mt_slot *s = &td->curdata;
@@ -577,6 +608,16 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
 
 static int mt_event(struct hid_device *hid, struct hid_field *field,
                                struct hid_usage *usage, __s32 value)
+{
+       /* we will handle the hidinput part later, now remains hiddev */
+       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+               hid->hiddev_hid_event(hid, field, usage, value);
+
+       return 1;
+}
+
+static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
+                               struct hid_usage *usage, __s32 value)
 {
        struct mt_device *td = hid_get_drvdata(hid);
        __s32 quirks = td->mtclass.quirks;
@@ -623,20 +664,13 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
                        td->curdata.h = value;
                        break;
                case HID_DG_CONTACTCOUNT:
-                       /*
-                        * Includes multi-packet support where subsequent
-                        * packets are sent with zero contactcount.
-                        */
-                       if (value)
-                               td->num_expected = value;
                        break;
                case HID_DG_TOUCH:
                        /* do nothing */
                        break;
 
                default:
-                       /* fallback to the generic hidinput handling */
-                       return 0;
+                       return;
                }
 
                if (usage->usage_index + 1 == field->report_count) {
@@ -650,12 +684,43 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
                }
 
        }
+}
 
-       /* we have handled the hidinput part, now remains hiddev */
-       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
-               hid->hiddev_hid_event(hid, field, usage, value);
+static void mt_report(struct hid_device *hid, struct hid_report *report)
+{
+       struct mt_device *td = hid_get_drvdata(hid);
+       struct hid_field *field;
+       unsigned count;
+       int r, n;
 
-       return 1;
+       if (report->id != td->mt_report_id)
+               return;
+
+       if (!(hid->claimed & HID_CLAIMED_INPUT))
+               return;
+
+       /*
+        * Includes multi-packet support where subsequent
+        * packets are sent with zero contactcount.
+        */
+       if (td->cc_index >= 0) {
+               struct hid_field *field = report->field[td->cc_index];
+               int value = field->value[td->cc_value_index];
+               if (value)
+                       td->num_expected = value;
+       }
+
+       for (r = 0; r < report->maxfield; r++) {
+               field = report->field[r];
+               count = field->report_count;
+
+               if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
+                       continue;
+
+               for (n = 0; n < count; n++)
+                       mt_process_mt_event(hid, field, &field->usage[n],
+                                       field->value[n]);
+       }
 }
 
 static void mt_set_input_mode(struct hid_device *hdev)
@@ -711,6 +776,7 @@ static void mt_post_parse_default_settings(struct mt_device *td)
                quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
                quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
                quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
+               quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
        }
 
        td->mtclass.quirks = quirks;
@@ -719,11 +785,15 @@ static void mt_post_parse_default_settings(struct mt_device *td)
 static void mt_post_parse(struct mt_device *td)
 {
        struct mt_fields *f = td->fields;
+       struct mt_class *cls = &td->mtclass;
 
        if (td->touches_by_report > 0) {
                int field_count_per_touch = f->length / td->touches_by_report;
                td->last_slot_field = f->usages[field_count_per_touch - 1];
        }
+
+       if (td->cc_index < 0)
+               cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 }
 
 static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
@@ -781,6 +851,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        td->mtclass = *mtclass;
        td->inputmode = -1;
        td->maxcontact_report_id = -1;
+       td->cc_index = -1;
        hid_set_drvdata(hdev, td);
 
        td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
@@ -875,7 +946,7 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_3M3266) },
 
        /* ActionStar panels */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
                        USB_DEVICE_ID_ACTIONSTAR_1011) },
 
@@ -888,14 +959,14 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
 
        /* Baanto multitouch devices */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
                        USB_DEVICE_ID_BAANTO_MT_190W2) },
        /* Cando panels */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
                MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
-       { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+       { .driver_data = MT_CLS_DUAL_CONTACT_NUMBER,
                MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
@@ -906,12 +977,12 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
 
        /* Chunghwa Telecom touch panels */
-       {  .driver_data = MT_CLS_DEFAULT,
+       {  .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
                        USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
 
        /* CVTouch panels */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
                        USB_DEVICE_ID_CVTOUCH_SCREEN) },
 
@@ -982,7 +1053,7 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
 
        /* Elo TouchSystems IntelliTouch Plus panel */
-       { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
+       { .driver_data = MT_CLS_DUAL_CONTACT_ID,
                MT_USB_DEVICE(USB_VENDOR_ID_ELO,
                        USB_DEVICE_ID_ELO_TS2515) },
 
@@ -1000,12 +1071,12 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) },
 
        /* Gametel game controller */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
                        USB_DEVICE_ID_GAMETEL_MT_MODE) },
 
        /* GoodTouch panels */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
                        USB_DEVICE_ID_GOODTOUCH_000f) },
 
@@ -1023,7 +1094,7 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_IDEACOM_IDC6651) },
 
        /* Ilitek dual touch panel */
-       {  .driver_data = MT_CLS_DEFAULT,
+       {  .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
                        USB_DEVICE_ID_ILITEK_MULTITOUCH) },
 
@@ -1056,6 +1127,11 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
                        USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
 
+       /* Nexio panels */
+       { .driver_data = MT_CLS_DEFAULT,
+               MT_USB_DEVICE(USB_VENDOR_ID_NEXIO,
+                       USB_DEVICE_ID_NEXIO_MULTITOUCH_420)},
+
        /* Panasonic panels */
        { .driver_data = MT_CLS_PANASONIC,
                MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
@@ -1065,7 +1141,7 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_PANABOARD_UBT880) },
 
        /* Novatek Panel */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
                        USB_DEVICE_ID_NOVATEK_PCT) },
 
@@ -1111,7 +1187,7 @@ static const struct hid_device_id mt_devices[] = {
        { .driver_data = MT_CLS_CONFIDENCE,
                MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
                        USB_DEVICE_ID_MTP_STM)},
-       { .driver_data = MT_CLS_CONFIDENCE,
+       { .driver_data = MT_CLS_DEFAULT,
                MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
                        USB_DEVICE_ID_MTP_SITRONIX)},
 
@@ -1121,48 +1197,48 @@ static const struct hid_device_id mt_devices[] = {
                        USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
 
        /* Touch International panels */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
                        USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
 
        /* Unitec panels */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
                        USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
                        USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
        /* XAT */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XAT,
                        USB_DEVICE_ID_XAT_CSR) },
 
        /* Xiroku */
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_SPX) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_MPX) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_CSR) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_SPX1) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_MPX1) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_CSR1) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_SPX2) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_MPX2) },
-       { .driver_data = MT_CLS_DEFAULT,
+       { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_CSR2) },
 
@@ -1193,6 +1269,7 @@ static struct hid_driver mt_driver = {
        .feature_mapping = mt_feature_mapping,
        .usage_table = mt_grabbed_usages,
        .event = mt_event,
+       .report = mt_report,
 #ifdef CONFIG_PM
        .reset_resume = mt_reset_resume,
        .resume = mt_resume,