static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; int code; /* Only map fields from TouchScreen or TouchPad collections. * We need to ignore fields that belong to other collections * such as Mouse that might have the same GenericDesktop usages. */ if (field->application == HID_DG_TOUCHSCREEN) set_bit(INPUT_PROP_DIRECT, hi->input->propbit); else if (field->application != HID_DG_TOUCHPAD) return 0; /* In case of an indirect device (touchpad), we need to add * specific BTN_TOOL_* to be handled by the synaptics xorg * driver. * We also consider that touchscreens providing buttons are touchpads. */ if (field->application == HID_DG_TOUCHPAD || (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON || cls->is_indirect) { set_bit(INPUT_PROP_POINTER, hi->input->propbit); set_bit(BTN_TOOL_FINGER, hi->input->keybit); set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit); set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit); set_bit(BTN_TOOL_QUADTAP, hi->input->keybit); } /* eGalax devices provide a Digitizer.Stylus input which overrides * the correct Digitizers.Finger X/Y ranges. * Let's just ignore this input. */ if (field->physical == HID_DG_STYLUS) return -1; /* Only map fields from TouchScreen or TouchPad collections. * We need to ignore fields that belong to other collections * such as Mouse that might have the same GenericDesktop usages. */ if (field->application == HID_DG_TOUCHSCREEN) set_bit(INPUT_PROP_DIRECT, hi->input->propbit); else if (field->application == HID_DG_TOUCHPAD) set_bit(INPUT_PROP_POINTER, hi->input->propbit); else return 0; switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_GENDESK: switch (usage->hid) { case HID_GD_X: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); set_abs(hi->input, ABS_MT_POSITION_X, field, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_X, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_GD_Y: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); set_abs(hi->input, ABS_MT_POSITION_Y, field, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_Y, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; } return 0; case HID_UP_DIGITIZER: switch (usage->hid) { case HID_DG_INRANGE: mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_CONFIDENCE: mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_TIPSWITCH: hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_CONTACTID: if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; input_mt_init_slots(hi->input, td->maxcontacts); mt_store_field(usage, td, hi); td->last_field_index = field->index; td->touches_by_report++; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_TIPPRESSURE: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); /* touchscreen emulation */ set_abs(hi->input, ABS_PRESSURE, field, cls->sn_pressure); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_CONTACTCOUNT: td->last_field_index = field->index; return 1; case HID_DG_CONTACTMAX: /* we don't set td->last_slot_field as contactcount and * contact max are global to the report */ td->last_field_index = field->index; return -1; } case HID_DG_TOUCH: /* Legacy devices use TIPSWITCH and not TOUCH. * Let's just ignore this field. */ return -1; /* let hid-input decide for the others */ return 0; case HID_UP_BUTTON: code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); hid_map_usage(hi, usage, bit, max, EV_KEY, code); input_set_capability(hi->input, EV_KEY, code); return 1; case 0xff000000: /* we do not want to map these: no input-oriented meaning */ return -1; } return 0; }
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; int code; struct hid_usage *prev_usage = NULL; if (field->application == HID_DG_TOUCHSCREEN) td->mt_flags |= INPUT_MT_DIRECT; /* * Model touchscreens providing buttons as touchpads. */ if (field->application == HID_DG_TOUCHPAD || (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { td->mt_flags |= INPUT_MT_POINTER; td->inputmode_value = MT_INPUTMODE_TOUCHPAD; } /* count the buttons on touchpads */ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) td->buttons_count++; if (usage->usage_index) prev_usage = &field->usage[usage->usage_index - 1]; switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_GENDESK: switch (usage->hid) { case HID_GD_X: if (prev_usage && (prev_usage->hid == usage->hid)) { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOOL_X); set_abs(hi->input, ABS_MT_TOOL_X, field, cls->sn_move); } else { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); set_abs(hi->input, ABS_MT_POSITION_X, field, cls->sn_move); } mt_store_field(usage, td, hi); return 1; case HID_GD_Y: if (prev_usage && (prev_usage->hid == usage->hid)) { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOOL_Y); set_abs(hi->input, ABS_MT_TOOL_Y, field, cls->sn_move); } else { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); set_abs(hi->input, ABS_MT_POSITION_Y, field, cls->sn_move); } mt_store_field(usage, td, hi); return 1; } return 0; case HID_UP_DIGITIZER: switch (usage->hid) { case HID_DG_INRANGE: if (cls->quirks & MT_QUIRK_HOVERING) { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_DISTANCE); input_set_abs_params(hi->input, ABS_MT_DISTANCE, 0, 1, 0, 0); } mt_store_field(usage, td, hi); return 1; case HID_DG_CONFIDENCE: if (cls->name == MT_CLS_WIN_8 && field->application == HID_DG_TOUCHPAD) cls->quirks |= MT_QUIRK_CONFIDENCE; mt_store_field(usage, td, hi); return 1; case HID_DG_TIPSWITCH: hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH); mt_store_field(usage, td, hi); return 1; case HID_DG_CONTACTID: mt_store_field(usage, td, hi); td->touches_by_report++; td->mt_report_id = field->report->id; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); mt_store_field(usage, td, hi); return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) { set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); } mt_store_field(usage, td, hi); return 1; case HID_DG_TIPPRESSURE: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); mt_store_field(usage, td, hi); return 1; case HID_DG_CONTACTCOUNT: /* Ignore if indexes are out of bounds. */ if (field->index >= field->report->maxfield || usage->usage_index >= field->report_count) return 1; td->cc_index = field->index; td->cc_value_index = usage->usage_index; return 1; case HID_DG_CONTACTMAX: /* we don't set td->last_slot_field as contactcount and * contact max are global to the report */ return -1; case HID_DG_TOUCH: /* Legacy devices use TIPSWITCH and not TOUCH. * Let's just ignore this field. */ return -1; } /* let hid-input decide for the others */ return 0; case HID_UP_BUTTON: code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); /* * MS PTP spec says that external buttons left and right have * usages 2 and 3. */ if (cls->name == MT_CLS_WIN_8 && field->application == HID_DG_TOUCHPAD && (usage->hid & HID_USAGE) > 1) code--; hid_map_usage(hi, usage, bit, max, EV_KEY, code); input_set_capability(hi->input, EV_KEY, code); return 1; case 0xff000000: /* we do not want to map these: no input-oriented meaning */ return -1; } return 0; }
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; int code; struct hid_usage *prev_usage = NULL; if (field->application == HID_DG_TOUCHSCREEN) td->mt_flags |= INPUT_MT_DIRECT; /* * Model touchscreens providing buttons as touchpads. */ if (field->application == HID_DG_TOUCHPAD || (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) td->mt_flags |= INPUT_MT_POINTER; /* Only map fields from TouchScreen or TouchPad collections. * We need to ignore fields that belong to other collections * such as Mouse that might have the same GenericDesktop usages. */ if (field->application == HID_DG_TOUCHSCREEN) set_bit(INPUT_PROP_DIRECT, hi->input->propbit); else if (field->application == HID_DG_TOUCHPAD) set_bit(INPUT_PROP_POINTER, hi->input->propbit); else return 0; if (usage->usage_index) prev_usage = &field->usage[usage->usage_index - 1]; switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_GENDESK: switch (usage->hid) { case HID_GD_X: if (prev_usage && (prev_usage->hid == usage->hid)) { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOOL_X); set_abs(hi->input, ABS_MT_TOOL_X, field, cls->sn_move); } else { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); set_abs(hi->input, ABS_MT_POSITION_X, field, cls->sn_move); } mt_store_field(usage, td, hi); return 1; case HID_GD_Y: if (prev_usage && (prev_usage->hid == usage->hid)) { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOOL_Y); set_abs(hi->input, ABS_MT_TOOL_Y, field, cls->sn_move); } else { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); set_abs(hi->input, ABS_MT_POSITION_Y, field, cls->sn_move); } mt_store_field(usage, td, hi); return 1; } return 0; case HID_UP_DIGITIZER: switch (usage->hid) { case HID_DG_INRANGE: if (cls->quirks & MT_QUIRK_HOVERING) { hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_DISTANCE); input_set_abs_params(hi->input, ABS_MT_DISTANCE, 0, 1, 0, 0); } mt_store_field(usage, td, hi); return 1; case HID_DG_CONFIDENCE: mt_store_field(usage, td, hi); return 1; case HID_DG_TIPSWITCH: hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH); mt_store_field(usage, td, hi); return 1; case HID_DG_CONTACTID: mt_store_field(usage, td, hi); td->touches_by_report++; td->mt_report_id = field->report->id; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); mt_store_field(usage, td, hi); return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) { set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); } mt_store_field(usage, td, hi); return 1; case HID_DG_TIPPRESSURE: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); mt_store_field(usage, td, hi); return 1; case HID_DG_CONTACTCOUNT: td->cc_index = field->index; td->cc_value_index = usage->usage_index; return 1; case HID_DG_CONTACTMAX: /* we don't set td->last_slot_field as contactcount and * contact max are global to the report */ return -1; case HID_DG_TOUCH: /* Legacy devices use TIPSWITCH and not TOUCH. * Let's just ignore this field. */ return -1; } /* let hid-input decide for the others */ return 0; case HID_UP_BUTTON: code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); hid_map_usage(hi, usage, bit, max, EV_KEY, code); input_set_capability(hi->input, EV_KEY, code); return 1; case 0xff000000: /* we do not want to map these: no input-oriented meaning */ return -1; } return 0; }