diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-multitouch.c | 52 |
1 files changed, 37 insertions, 15 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index ee01e65e22d6..b9f9eeceaa98 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -60,8 +60,9 @@ struct mt_device { | |||
60 | __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ | 60 | __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ |
61 | __u8 num_received; /* how many contacts we received */ | 61 | __u8 num_received; /* how many contacts we received */ |
62 | __u8 num_expected; /* expected last contact index */ | 62 | __u8 num_expected; /* expected last contact index */ |
63 | __u8 maxcontacts; | ||
63 | bool curvalid; /* is the current contact valid? */ | 64 | bool curvalid; /* is the current contact valid? */ |
64 | struct mt_slot slots[0]; /* first slot */ | 65 | struct mt_slot *slots; |
65 | }; | 66 | }; |
66 | 67 | ||
67 | struct mt_class { | 68 | struct mt_class { |
@@ -79,6 +80,8 @@ struct mt_class { | |||
79 | #define MT_CLS_CYPRESS 4 | 80 | #define MT_CLS_CYPRESS 4 |
80 | #define MT_CLS_EGALAX 5 | 81 | #define MT_CLS_EGALAX 5 |
81 | 82 | ||
83 | #define MT_DEFAULT_MAXCONTACT 10 | ||
84 | |||
82 | /* | 85 | /* |
83 | * these device-dependent functions determine what slot corresponds | 86 | * these device-dependent functions determine what slot corresponds |
84 | * to a valid contact that was just read. | 87 | * to a valid contact that was just read. |
@@ -95,12 +98,12 @@ static int cypress_compute_slot(struct mt_device *td) | |||
95 | static int find_slot_from_contactid(struct mt_device *td) | 98 | static int find_slot_from_contactid(struct mt_device *td) |
96 | { | 99 | { |
97 | int i; | 100 | int i; |
98 | for (i = 0; i < td->mtclass->maxcontacts; ++i) { | 101 | for (i = 0; i < td->maxcontacts; ++i) { |
99 | if (td->slots[i].contactid == td->curdata.contactid && | 102 | if (td->slots[i].contactid == td->curdata.contactid && |
100 | td->slots[i].touch_state) | 103 | td->slots[i].touch_state) |
101 | return i; | 104 | return i; |
102 | } | 105 | } |
103 | for (i = 0; i < td->mtclass->maxcontacts; ++i) { | 106 | for (i = 0; i < td->maxcontacts; ++i) { |
104 | if (!td->slots[i].seen_in_this_frame && | 107 | if (!td->slots[i].seen_in_this_frame && |
105 | !td->slots[i].touch_state) | 108 | !td->slots[i].touch_state) |
106 | return i; | 109 | return i; |
@@ -113,8 +116,7 @@ static int find_slot_from_contactid(struct mt_device *td) | |||
113 | 116 | ||
114 | struct mt_class mt_classes[] = { | 117 | struct mt_class mt_classes[] = { |
115 | { .name = MT_CLS_DEFAULT, | 118 | { .name = MT_CLS_DEFAULT, |
116 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, | 119 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, |
117 | .maxcontacts = 10 }, | ||
118 | { .name = MT_CLS_DUAL_INRANGE_CONTACTID, | 120 | { .name = MT_CLS_DUAL_INRANGE_CONTACTID, |
119 | .quirks = MT_QUIRK_VALID_IS_INRANGE | | 121 | .quirks = MT_QUIRK_VALID_IS_INRANGE | |
120 | MT_QUIRK_SLOT_IS_CONTACTID, | 122 | MT_QUIRK_SLOT_IS_CONTACTID, |
@@ -142,9 +144,19 @@ struct mt_class mt_classes[] = { | |||
142 | static void mt_feature_mapping(struct hid_device *hdev, | 144 | static void mt_feature_mapping(struct hid_device *hdev, |
143 | struct hid_field *field, struct hid_usage *usage) | 145 | struct hid_field *field, struct hid_usage *usage) |
144 | { | 146 | { |
145 | if (usage->hid == HID_DG_INPUTMODE) { | 147 | struct mt_device *td = hid_get_drvdata(hdev); |
146 | struct mt_device *td = hid_get_drvdata(hdev); | 148 | |
149 | switch (usage->hid) { | ||
150 | case HID_DG_INPUTMODE: | ||
147 | td->inputmode = field->report->id; | 151 | td->inputmode = field->report->id; |
152 | break; | ||
153 | case HID_DG_CONTACTMAX: | ||
154 | td->maxcontacts = field->value[0]; | ||
155 | if (td->mtclass->maxcontacts) | ||
156 | /* check if the maxcontacts is given by the class */ | ||
157 | td->maxcontacts = td->mtclass->maxcontacts; | ||
158 | |||
159 | break; | ||
148 | } | 160 | } |
149 | } | 161 | } |
150 | 162 | ||
@@ -208,8 +220,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
208 | td->last_slot_field = usage->hid; | 220 | td->last_slot_field = usage->hid; |
209 | return 1; | 221 | return 1; |
210 | case HID_DG_CONTACTID: | 222 | case HID_DG_CONTACTID: |
211 | input_mt_init_slots(hi->input, | 223 | input_mt_init_slots(hi->input, td->maxcontacts); |
212 | td->mtclass->maxcontacts); | ||
213 | td->last_slot_field = usage->hid; | 224 | td->last_slot_field = usage->hid; |
214 | return 1; | 225 | return 1; |
215 | case HID_DG_WIDTH: | 226 | case HID_DG_WIDTH: |
@@ -292,7 +303,7 @@ static void mt_complete_slot(struct mt_device *td) | |||
292 | if (td->curvalid) { | 303 | if (td->curvalid) { |
293 | int slotnum = mt_compute_slot(td); | 304 | int slotnum = mt_compute_slot(td); |
294 | 305 | ||
295 | if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts) | 306 | if (slotnum >= 0 && slotnum < td->maxcontacts) |
296 | td->slots[slotnum] = td->curdata; | 307 | td->slots[slotnum] = td->curdata; |
297 | } | 308 | } |
298 | td->num_received++; | 309 | td->num_received++; |
@@ -307,7 +318,7 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) | |||
307 | { | 318 | { |
308 | int i; | 319 | int i; |
309 | 320 | ||
310 | for (i = 0; i < td->mtclass->maxcontacts; ++i) { | 321 | for (i = 0; i < td->maxcontacts; ++i) { |
311 | struct mt_slot *s = &(td->slots[i]); | 322 | struct mt_slot *s = &(td->slots[i]); |
312 | if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && | 323 | if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && |
313 | !s->seen_in_this_frame) { | 324 | !s->seen_in_this_frame) { |
@@ -341,7 +352,7 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, | |||
341 | struct mt_device *td = hid_get_drvdata(hid); | 352 | struct mt_device *td = hid_get_drvdata(hid); |
342 | __s32 quirks = td->mtclass->quirks; | 353 | __s32 quirks = td->mtclass->quirks; |
343 | 354 | ||
344 | if (hid->claimed & HID_CLAIMED_INPUT) { | 355 | if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { |
345 | switch (usage->hid) { | 356 | switch (usage->hid) { |
346 | case HID_DG_INRANGE: | 357 | case HID_DG_INRANGE: |
347 | if (quirks & MT_QUIRK_VALID_IS_INRANGE) | 358 | if (quirks & MT_QUIRK_VALID_IS_INRANGE) |
@@ -442,9 +453,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
442 | */ | 453 | */ |
443 | hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; | 454 | hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; |
444 | 455 | ||
445 | td = kzalloc(sizeof(struct mt_device) + | 456 | td = kzalloc(sizeof(struct mt_device), GFP_KERNEL); |
446 | mtclass->maxcontacts * sizeof(struct mt_slot), | ||
447 | GFP_KERNEL); | ||
448 | if (!td) { | 457 | if (!td) { |
449 | dev_err(&hdev->dev, "cannot allocate multitouch data\n"); | 458 | dev_err(&hdev->dev, "cannot allocate multitouch data\n"); |
450 | return -ENOMEM; | 459 | return -ENOMEM; |
@@ -461,6 +470,18 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
461 | if (ret) | 470 | if (ret) |
462 | goto fail; | 471 | goto fail; |
463 | 472 | ||
473 | if (!td->maxcontacts) | ||
474 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; | ||
475 | |||
476 | td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), | ||
477 | GFP_KERNEL); | ||
478 | if (!td->slots) { | ||
479 | dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); | ||
480 | hid_hw_stop(hdev); | ||
481 | ret = -ENOMEM; | ||
482 | goto fail; | ||
483 | } | ||
484 | |||
464 | mt_set_input_mode(hdev); | 485 | mt_set_input_mode(hdev); |
465 | 486 | ||
466 | return 0; | 487 | return 0; |
@@ -482,6 +503,7 @@ static void mt_remove(struct hid_device *hdev) | |||
482 | { | 503 | { |
483 | struct mt_device *td = hid_get_drvdata(hdev); | 504 | struct mt_device *td = hid_get_drvdata(hdev); |
484 | hid_hw_stop(hdev); | 505 | hid_hw_stop(hdev); |
506 | kfree(td->slots); | ||
485 | kfree(td); | 507 | kfree(td); |
486 | hid_set_drvdata(hdev, NULL); | 508 | hid_set_drvdata(hdev, NULL); |
487 | } | 509 | } |