int left_button_state; /* left button state */
unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
- __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
- __s16 inputmode_index; /* InputMode HID feature index in the report */
- __s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
- -1 if non-existent */
- __u8 inputmode_value; /* InputMode HID feature value */
+ __u8 inputmode_value; /* InputMode HID feature value */
__u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */
__u8 maxcontacts;
struct mt_device *td = hid_get_drvdata(hdev);
switch (usage->hid) {
- case HID_DG_INPUTMODE:
- /* Ignore if value index is out of bounds. */
- if (usage->usage_index >= field->report_count) {
- dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
- break;
- }
-
- if (td->inputmode < 0) {
- td->inputmode = field->report->id;
- td->inputmode_index = usage->usage_index;
- } else {
- /*
- * Some elan panels wrongly declare 2 input mode
- * features, and silently ignore when we set the
- * value in the second field. Skip the second feature
- * and hope for the best.
- */
- dev_info(&hdev->dev,
- "Ignoring the extra HID_DG_INPUTMODE\n");
- }
-
- break;
case HID_DG_CONTACTMAX:
mt_get_feature(hdev, field->report);
- td->maxcontact_report_id = field->report->id;
td->maxcontacts = field->value[0];
if (!td->maxcontacts &&
field->logical_maximum <= MT_MAX_MAXCONTACT)
input_sync(field->hidinput->input);
}
-static void mt_set_input_mode(struct hid_device *hdev)
+static bool mt_need_to_apply_feature(struct hid_device *hdev,
+ struct hid_field *field,
+ struct hid_usage *usage)
{
struct mt_device *td = hid_get_drvdata(hdev);
- struct hid_report *r;
- struct hid_report_enum *re;
struct mt_class *cls = &td->mtclass;
+ struct hid_report *report = field->report;
+ unsigned int index = usage->usage_index;
char *buf;
u32 report_len;
+ int max;
- if (td->inputmode < 0)
- return;
-
- re = &(hdev->report_enum[HID_FEATURE_REPORT]);
- r = re->report_id_hash[td->inputmode];
- if (r) {
+ switch (usage->hid) {
+ case HID_DG_INPUTMODE:
if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) {
- report_len = hid_report_len(r);
- buf = hid_alloc_report_buf(r, GFP_KERNEL);
+ report_len = hid_report_len(report);
+ buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf) {
- hid_err(hdev, "failed to allocate buffer for report\n");
- return;
+ hid_err(hdev,
+ "failed to allocate buffer for report\n");
+ return false;
}
- hid_hw_raw_request(hdev, r->id, buf, report_len,
+ hid_hw_raw_request(hdev, report->id, buf, report_len,
HID_FEATURE_REPORT,
HID_REQ_GET_REPORT);
kfree(buf);
}
- r->field[0]->value[td->inputmode_index] = td->inputmode_value;
- hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
- }
-}
-static void mt_set_maxcontacts(struct hid_device *hdev)
-{
- struct mt_device *td = hid_get_drvdata(hdev);
- struct hid_report *r;
- struct hid_report_enum *re;
- int fieldmax, max;
+ field->value[index] = td->inputmode_value;
+ return true;
- if (td->maxcontact_report_id < 0)
- return;
+ case HID_DG_CONTACTMAX:
+ if (td->mtclass.maxcontacts) {
+ max = min_t(int, field->logical_maximum,
+ td->mtclass.maxcontacts);
+ if (field->value[index] != max) {
+ field->value[index] = max;
+ return true;
+ }
+ }
+ break;
+ }
- if (!td->mtclass.maxcontacts)
- return;
+ return false; /* no need to update the report */
+}
- re = &hdev->report_enum[HID_FEATURE_REPORT];
- r = re->report_id_hash[td->maxcontact_report_id];
- if (r) {
- max = td->mtclass.maxcontacts;
- fieldmax = r->field[0]->logical_maximum;
- max = min(fieldmax, max);
- if (r->field[0]->value[0] != max) {
- r->field[0]->value[0] = max;
- hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
+static void mt_set_modes(struct hid_device *hdev)
+{
+ struct hid_report_enum *rep_enum;
+ struct hid_report *rep;
+ struct hid_usage *usage;
+ int i, j;
+ bool update_report;
+
+ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(rep, &rep_enum->report_list, list) {
+ update_report = false;
+
+ for (i = 0; i < rep->maxfield; i++) {
+ /* Ignore if report count is out of bounds. */
+ if (rep->field[i]->report_count < 1)
+ continue;
+
+ for (j = 0; j < rep->field[i]->maxusage; j++) {
+ usage = &rep->field[i]->usage[j];
+
+ if (mt_need_to_apply_feature(hdev,
+ rep->field[i],
+ usage))
+ update_report = true;
+ }
}
+
+ if (update_report)
+ hid_hw_request(hdev, rep, HID_REQ_SET_REPORT);
}
}
}
td->hdev = hdev;
td->mtclass = *mtclass;
- td->inputmode = -1;
- td->maxcontact_report_id = -1;
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
td->cc_index = -1;
td->scantime_index = -1;
dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n",
hdev->name);
- mt_set_maxcontacts(hdev);
- mt_set_input_mode(hdev);
+ mt_set_modes(hdev);
/* release .fields memory as it is not used anymore */
devm_kfree(&hdev->dev, td->fields);
static int mt_reset_resume(struct hid_device *hdev)
{
mt_release_contacts(hdev);
- mt_set_maxcontacts(hdev);
- mt_set_input_mode(hdev);
+ mt_set_modes(hdev);
return 0;
}