diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2018-08-20 12:06:30 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2018-08-20 12:06:30 -0400 |
| commit | 5a12d86ce3a93b6442963e5f6e6511e8f470f760 (patch) | |
| tree | cf455374db907523bc95ccd4027fea65ab912f68 | |
| parent | 415d2b3392d7a80903e0f97f051201aa02bf20e9 (diff) | |
| parent | e7ad3dc9f4a2a183f275c9a3becd0cdd5f69792e (diff) | |
Merge branch 'for-4.19/elan' into for-linus
Resolution/pressure fixes and new device support for hid-elan
| -rw-r--r-- | drivers/hid/hid-elan.c | 235 | ||||
| -rw-r--r-- | drivers/hid/hid-ids.h | 2 |
2 files changed, 184 insertions, 53 deletions
diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c index 803a725785cf..07e26c3567eb 100644 --- a/drivers/hid/hid-elan.c +++ b/drivers/hid/hid-elan.c | |||
| @@ -19,38 +19,49 @@ | |||
| 19 | 19 | ||
| 20 | #include "hid-ids.h" | 20 | #include "hid-ids.h" |
| 21 | 21 | ||
| 22 | #define ELAN_MT_I2C 0x5d | ||
| 22 | #define ELAN_SINGLE_FINGER 0x81 | 23 | #define ELAN_SINGLE_FINGER 0x81 |
| 23 | #define ELAN_MT_FIRST_FINGER 0x82 | 24 | #define ELAN_MT_FIRST_FINGER 0x82 |
| 24 | #define ELAN_MT_SECOND_FINGER 0x83 | 25 | #define ELAN_MT_SECOND_FINGER 0x83 |
| 25 | #define ELAN_INPUT_REPORT_SIZE 8 | 26 | #define ELAN_INPUT_REPORT_SIZE 8 |
| 27 | #define ELAN_I2C_REPORT_SIZE 32 | ||
| 28 | #define ELAN_FINGER_DATA_LEN 5 | ||
| 29 | #define ELAN_MAX_FINGERS 5 | ||
| 30 | #define ELAN_MAX_PRESSURE 255 | ||
| 31 | #define ELAN_TP_USB_INTF 1 | ||
| 32 | |||
| 33 | #define ELAN_FEATURE_REPORT 0x0d | ||
| 34 | #define ELAN_FEATURE_SIZE 5 | ||
| 35 | #define ELAN_PARAM_MAX_X 6 | ||
| 36 | #define ELAN_PARAM_MAX_Y 7 | ||
| 37 | #define ELAN_PARAM_RES 8 | ||
| 26 | 38 | ||
| 27 | #define ELAN_MUTE_LED_REPORT 0xBC | 39 | #define ELAN_MUTE_LED_REPORT 0xBC |
| 28 | #define ELAN_LED_REPORT_SIZE 8 | 40 | #define ELAN_LED_REPORT_SIZE 8 |
| 29 | 41 | ||
| 30 | struct elan_touchpad_settings { | 42 | #define ELAN_HAS_LED BIT(0) |
| 31 | u8 max_fingers; | ||
| 32 | u16 max_x; | ||
| 33 | u16 max_y; | ||
| 34 | u8 max_area_x; | ||
| 35 | u8 max_area_y; | ||
| 36 | u8 max_w; | ||
| 37 | int usb_bInterfaceNumber; | ||
| 38 | }; | ||
| 39 | 43 | ||
| 40 | struct elan_drvdata { | 44 | struct elan_drvdata { |
| 41 | struct input_dev *input; | 45 | struct input_dev *input; |
| 42 | u8 prev_report[ELAN_INPUT_REPORT_SIZE]; | 46 | u8 prev_report[ELAN_INPUT_REPORT_SIZE]; |
| 43 | struct led_classdev mute_led; | 47 | struct led_classdev mute_led; |
| 44 | u8 mute_led_state; | 48 | u8 mute_led_state; |
| 45 | struct elan_touchpad_settings *settings; | 49 | u16 max_x; |
| 50 | u16 max_y; | ||
| 51 | u16 res_x; | ||
| 52 | u16 res_y; | ||
| 46 | }; | 53 | }; |
| 47 | 54 | ||
| 48 | static int is_not_elan_touchpad(struct hid_device *hdev) | 55 | static int is_not_elan_touchpad(struct hid_device *hdev) |
| 49 | { | 56 | { |
| 50 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | 57 | if (hdev->bus == BUS_USB) { |
| 51 | struct elan_drvdata *drvdata = hid_get_drvdata(hdev); | 58 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); |
| 59 | |||
| 60 | return (intf->altsetting->desc.bInterfaceNumber != | ||
| 61 | ELAN_TP_USB_INTF); | ||
| 62 | } | ||
| 52 | 63 | ||
| 53 | return (intf->altsetting->desc.bInterfaceNumber != drvdata->settings->usb_bInterfaceNumber); | 64 | return 0; |
| 54 | } | 65 | } |
| 55 | 66 | ||
| 56 | static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi, | 67 | static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
| @@ -62,12 +73,86 @@ static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 62 | 73 | ||
| 63 | if (field->report->id == ELAN_SINGLE_FINGER || | 74 | if (field->report->id == ELAN_SINGLE_FINGER || |
| 64 | field->report->id == ELAN_MT_FIRST_FINGER || | 75 | field->report->id == ELAN_MT_FIRST_FINGER || |
| 65 | field->report->id == ELAN_MT_SECOND_FINGER) | 76 | field->report->id == ELAN_MT_SECOND_FINGER || |
| 77 | field->report->id == ELAN_MT_I2C) | ||
| 66 | return -1; | 78 | return -1; |
| 67 | 79 | ||
| 68 | return 0; | 80 | return 0; |
| 69 | } | 81 | } |
| 70 | 82 | ||
| 83 | static int elan_get_device_param(struct hid_device *hdev, | ||
| 84 | unsigned char *dmabuf, unsigned char param) | ||
| 85 | { | ||
| 86 | int ret; | ||
| 87 | |||
| 88 | dmabuf[0] = ELAN_FEATURE_REPORT; | ||
| 89 | dmabuf[1] = 0x05; | ||
| 90 | dmabuf[2] = 0x03; | ||
| 91 | dmabuf[3] = param; | ||
| 92 | dmabuf[4] = 0x01; | ||
| 93 | |||
| 94 | ret = hid_hw_raw_request(hdev, ELAN_FEATURE_REPORT, dmabuf, | ||
| 95 | ELAN_FEATURE_SIZE, HID_FEATURE_REPORT, | ||
| 96 | HID_REQ_SET_REPORT); | ||
| 97 | if (ret != ELAN_FEATURE_SIZE) { | ||
| 98 | hid_err(hdev, "Set report error for parm %d: %d\n", param, ret); | ||
| 99 | return ret; | ||
| 100 | } | ||
| 101 | |||
| 102 | ret = hid_hw_raw_request(hdev, ELAN_FEATURE_REPORT, dmabuf, | ||
| 103 | ELAN_FEATURE_SIZE, HID_FEATURE_REPORT, | ||
| 104 | HID_REQ_GET_REPORT); | ||
| 105 | if (ret != ELAN_FEATURE_SIZE) { | ||
| 106 | hid_err(hdev, "Get report error for parm %d: %d\n", param, ret); | ||
| 107 | return ret; | ||
| 108 | } | ||
| 109 | |||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | static unsigned int elan_convert_res(char val) | ||
| 114 | { | ||
| 115 | /* | ||
| 116 | * (value from firmware) * 10 + 790 = dpi | ||
| 117 | * dpi * 10 / 254 = dots/mm | ||
| 118 | */ | ||
| 119 | return (val * 10 + 790) * 10 / 254; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int elan_get_device_params(struct hid_device *hdev) | ||
| 123 | { | ||
| 124 | struct elan_drvdata *drvdata = hid_get_drvdata(hdev); | ||
| 125 | unsigned char *dmabuf; | ||
| 126 | int ret; | ||
| 127 | |||
| 128 | dmabuf = kmalloc(ELAN_FEATURE_SIZE, GFP_KERNEL); | ||
| 129 | if (!dmabuf) | ||
| 130 | return -ENOMEM; | ||
| 131 | |||
| 132 | ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_MAX_X); | ||
| 133 | if (ret) | ||
| 134 | goto err; | ||
| 135 | |||
| 136 | drvdata->max_x = (dmabuf[4] << 8) | dmabuf[3]; | ||
| 137 | |||
| 138 | ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_MAX_Y); | ||
| 139 | if (ret) | ||
| 140 | goto err; | ||
| 141 | |||
| 142 | drvdata->max_y = (dmabuf[4] << 8) | dmabuf[3]; | ||
| 143 | |||
| 144 | ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_RES); | ||
| 145 | if (ret) | ||
| 146 | goto err; | ||
| 147 | |||
| 148 | drvdata->res_x = elan_convert_res(dmabuf[3]); | ||
| 149 | drvdata->res_y = elan_convert_res(dmabuf[4]); | ||
| 150 | |||
| 151 | err: | ||
| 152 | kfree(dmabuf); | ||
| 153 | return ret; | ||
| 154 | } | ||
| 155 | |||
| 71 | static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) | 156 | static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) |
| 72 | { | 157 | { |
| 73 | int ret; | 158 | int ret; |
| @@ -77,6 +162,10 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) | |||
| 77 | if (is_not_elan_touchpad(hdev)) | 162 | if (is_not_elan_touchpad(hdev)) |
| 78 | return 0; | 163 | return 0; |
| 79 | 164 | ||
| 165 | ret = elan_get_device_params(hdev); | ||
| 166 | if (ret) | ||
| 167 | return ret; | ||
| 168 | |||
| 80 | input = devm_input_allocate_device(&hdev->dev); | 169 | input = devm_input_allocate_device(&hdev->dev); |
| 81 | if (!input) | 170 | if (!input) |
| 82 | return -ENOMEM; | 171 | return -ENOMEM; |
| @@ -90,25 +179,25 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) | |||
| 90 | input->id.version = hdev->version; | 179 | input->id.version = hdev->version; |
| 91 | input->dev.parent = &hdev->dev; | 180 | input->dev.parent = &hdev->dev; |
| 92 | 181 | ||
| 93 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, | 182 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, drvdata->max_x, |
| 94 | drvdata->settings->max_x, 0, 0); | 183 | 0, 0); |
| 95 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, | 184 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, drvdata->max_y, |
| 96 | drvdata->settings->max_y, 0, 0); | 185 | 0, 0); |
| 97 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, | 186 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, ELAN_MAX_PRESSURE, |
| 98 | drvdata->settings->max_fingers, 0, 0); | 187 | 0, 0); |
| 99 | input_set_abs_params(input, ABS_TOOL_WIDTH, 0, | ||
| 100 | drvdata->settings->max_w, 0, 0); | ||
| 101 | 188 | ||
| 102 | __set_bit(BTN_LEFT, input->keybit); | 189 | __set_bit(BTN_LEFT, input->keybit); |
| 103 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | 190 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); |
| 104 | 191 | ||
| 105 | ret = input_mt_init_slots(input, drvdata->settings->max_fingers, | 192 | ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER); |
| 106 | INPUT_MT_POINTER); | ||
| 107 | if (ret) { | 193 | if (ret) { |
| 108 | hid_err(hdev, "Failed to init elan MT slots: %d\n", ret); | 194 | hid_err(hdev, "Failed to init elan MT slots: %d\n", ret); |
| 109 | return ret; | 195 | return ret; |
| 110 | } | 196 | } |
| 111 | |||
