diff options
| -rw-r--r-- | drivers/hid/hid-3m-pct.c | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c index d2fda7848f59..3c380e1c5b60 100644 --- a/drivers/hid/hid-3m-pct.c +++ b/drivers/hid/hid-3m-pct.c | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | * HID driver for 3M PCT multitouch panels | 2 | * HID driver for 3M PCT multitouch panels |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> | 4 | * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> |
| 5 | * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
| 6 | * Copyright (c) 2010 Canonical, Ltd. | ||
| 5 | * | 7 | * |
| 6 | */ | 8 | */ |
| 7 | 9 | ||
| @@ -25,16 +27,24 @@ MODULE_LICENSE("GPL"); | |||
| 25 | #include "hid-ids.h" | 27 | #include "hid-ids.h" |
| 26 | 28 | ||
| 27 | #define MAX_SLOTS 60 | 29 | #define MAX_SLOTS 60 |
| 28 | #define MAX_TRKID 59 | 30 | #define MAX_TRKID USHRT_MAX |
| 31 | #define MAX_EVENTS 360 | ||
| 32 | |||
| 33 | /* estimated signal-to-noise ratios */ | ||
| 34 | #define SN_MOVE 2048 | ||
| 35 | #define SN_WIDTH 128 | ||
| 29 | 36 | ||
| 30 | struct mmm_finger { | 37 | struct mmm_finger { |
| 31 | __s32 x, y, w, h; | 38 | __s32 x, y, w, h; |
| 39 | __u16 id; | ||
| 32 | __u8 rank; | 40 | __u8 rank; |
| 41 | bool prev_touch; | ||
| 33 | bool touch, valid; | 42 | bool touch, valid; |
| 34 | }; | 43 | }; |
| 35 | 44 | ||
| 36 | struct mmm_data { | 45 | struct mmm_data { |
| 37 | struct mmm_finger f[MAX_SLOTS]; | 46 | struct mmm_finger f[MAX_SLOTS]; |
| 47 | __u16 id; | ||
| 38 | __u8 curid, num; | 48 | __u8 curid, num; |
| 39 | __u8 nexp, nreal; | 49 | __u8 nexp, nreal; |
| 40 | bool touch, valid; | 50 | bool touch, valid; |
| @@ -44,6 +54,10 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 44 | struct hid_field *field, struct hid_usage *usage, | 54 | struct hid_field *field, struct hid_usage *usage, |
| 45 | unsigned long **bit, int *max) | 55 | unsigned long **bit, int *max) |
| 46 | { | 56 | { |
| 57 | int f1 = field->logical_minimum; | ||
| 58 | int f2 = field->logical_maximum; | ||
| 59 | int df = f2 - f1; | ||
| 60 | |||
| 47 | switch (usage->hid & HID_USAGE_PAGE) { | 61 | switch (usage->hid & HID_USAGE_PAGE) { |
| 48 | 62 | ||
| 49 | case HID_UP_BUTTON: | 63 | case HID_UP_BUTTON: |
| @@ -54,18 +68,20 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 54 | case HID_GD_X: | 68 | case HID_GD_X: |
| 55 | hid_map_usage(hi, usage, bit, max, | 69 | hid_map_usage(hi, usage, bit, max, |
| 56 | EV_ABS, ABS_MT_POSITION_X); | 70 | EV_ABS, ABS_MT_POSITION_X); |
| 71 | input_set_abs_params(hi->input, ABS_MT_POSITION_X, | ||
| 72 | f1, f2, df / SN_MOVE, 0); | ||
| 57 | /* touchscreen emulation */ | 73 | /* touchscreen emulation */ |
| 58 | input_set_abs_params(hi->input, ABS_X, | 74 | input_set_abs_params(hi->input, ABS_X, |
| 59 | field->logical_minimum, | 75 | f1, f2, df / SN_MOVE, 0); |
| 60 | field->logical_maximum, 0, 0); | ||
| 61 | return 1; | 76 | return 1; |
| 62 | case HID_GD_Y: | 77 | case HID_GD_Y: |
| 63 | hid_map_usage(hi, usage, bit, max, | 78 | hid_map_usage(hi, usage, bit, max, |
| 64 | EV_ABS, ABS_MT_POSITION_Y); | 79 | EV_ABS, ABS_MT_POSITION_Y); |
| 80 | input_set_abs_params(hi->input, ABS_MT_POSITION_Y, | ||
| 81 | f1, f2, df / SN_MOVE, 0); | ||
| 65 | /* touchscreen emulation */ | 82 | /* touchscreen emulation */ |
| 66 | input_set_abs_params(hi->input, ABS_Y, | 83 | input_set_abs_params(hi->input, ABS_Y, |
| 67 | field->logical_minimum, | 84 | f1, f2, df / SN_MOVE, 0); |
| 68 | field->logical_maximum, 0, 0); | ||
| 69 | return 1; | 85 | return 1; |
| 70 | } | 86 | } |
| 71 | return 0; | 87 | return 0; |
| @@ -85,14 +101,19 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 85 | case HID_DG_TIPSWITCH: | 101 | case HID_DG_TIPSWITCH: |
| 86 | /* touchscreen emulation */ | 102 | /* touchscreen emulation */ |
| 87 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | 103 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); |
| 104 | input_set_capability(hi->input, EV_KEY, BTN_TOUCH); | ||
| 88 | return 1; | 105 | return 1; |
| 89 | case HID_DG_WIDTH: | 106 | case HID_DG_WIDTH: |
| 90 | hid_map_usage(hi, usage, bit, max, | 107 | hid_map_usage(hi, usage, bit, max, |
| 91 | EV_ABS, ABS_MT_TOUCH_MAJOR); | 108 | EV_ABS, ABS_MT_TOUCH_MAJOR); |
| 109 | input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR, | ||
| 110 | f1, f2, df / SN_WIDTH, 0); | ||
| 92 | return 1; | 111 | return 1; |
| 93 | case HID_DG_HEIGHT: | 112 | case HID_DG_HEIGHT: |
| 94 | hid_map_usage(hi, usage, bit, max, | 113 | hid_map_usage(hi, usage, bit, max, |
| 95 | EV_ABS, ABS_MT_TOUCH_MINOR); | 114 | EV_ABS, ABS_MT_TOUCH_MINOR); |
| 115 | input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR, | ||
| 116 | f1, f2, df / SN_WIDTH, 0); | ||
| 96 | input_set_abs_params(hi->input, ABS_MT_ORIENTATION, | 117 | input_set_abs_params(hi->input, ABS_MT_ORIENTATION, |
| 97 | 0, 1, 0, 0); | 118 | 0, 1, 0, 0); |
| 98 | return 1; | 119 | return 1; |
| @@ -100,6 +121,11 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 100 | field->logical_maximum = MAX_TRKID; | 121 | field->logical_maximum = MAX_TRKID; |
| 101 | hid_map_usage(hi, usage, bit, max, | 122 | hid_map_usage(hi, usage, bit, max, |
| 102 | EV_ABS, ABS_MT_TRACKING_ID); | 123 | EV_ABS, ABS_MT_TRACKING_ID); |
| 124 | input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, | ||
| 125 | 0, MAX_TRKID, 0, 0); | ||
| 126 | if (!hi->input->mt) | ||
| 127 | input_mt_create_slots(hi->input, MAX_SLOTS); | ||
| 128 | input_set_events_per_packet(hi->input, MAX_EVENTS); | ||
| 103 | return 1; | 129 | return 1; |
| 104 | } | 130 | } |
| 105 | /* let hid-input decide for the others */ | 131 | /* let hid-input decide for the others */ |
| @@ -117,10 +143,10 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
| 117 | struct hid_field *field, struct hid_usage *usage, | 143 | struct hid_field *field, struct hid_usage *usage, |
| 118 | unsigned long **bit, int *max) | 144 | unsigned long **bit, int *max) |
| 119 | { | 145 | { |
| 146 | /* tell hid-input to skip setup of these event types */ | ||
| 120 | if (usage->type == EV_KEY || usage->type == EV_ABS) | 147 | if (usage->type == EV_KEY || usage->type == EV_ABS) |
| 121 | clear_bit(usage->code, *bit); | 148 | set_bit(usage->type, hi->input->evbit); |
| 122 | 149 | return -1; | |
| 123 | return 0; | ||
| 124 | } | 150 | } |
| 125 | 151 | ||
| 126 | /* | 152 | /* |
| @@ -141,10 +167,15 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) | |||
| 141 | struct mmm_finger *f = &md->f[i]; | 167 | struct mmm_finger *f = &md->f[i]; |
| 142 | if (!f->valid) { | 168 | if (!f->valid) { |
| 143 | /* this finger is just placeholder data, ignore */ | 169 | /* this finger is just placeholder data, ignore */ |
| 144 | } else if (f->touch) { | 170 | continue; |
| 171 | } | ||
| 172 | input_mt_slot(input, i); | ||
| 173 | if (f->touch) { | ||
| 145 | /* this finger is on the screen */ | 174 | /* this finger is on the screen */ |
| 146 | int wide = (f->w > f->h); | 175 | int wide = (f->w > f->h); |
| 147 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i); | 176 | if (!f->prev_touch) |
| 177 | f->id = md->id++; | ||
| 178 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id); | ||
| 148 | input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); | 179 | input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); |
| 149 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); | 180 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); |
| 150 | input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); | 181 | input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); |
| @@ -152,7 +183,6 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) | |||
| 152 | wide ? f->w : f->h); | 183 | wide ? f->w : f->h); |
| 153 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, | 184 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, |
| 154 | wide ? f->h : f->w); | 185 | wide ? f->h : f->w); |
| 155 | input_mt_sync(input); | ||
| 156 | /* | 186 | /* |
| 157 | * touchscreen emulation: maintain the age rank | 187 | * touchscreen emulation: maintain the age rank |
| 158 | * of this finger, decide if we have a press | 188 | * of this finger, decide if we have a press |
| @@ -181,7 +211,9 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) | |||
| 181 | --(md->num); | 211 | --(md->num); |
| 182 | if (md->num == 0) | 212 | if (md->num == 0) |
| 183 | released = true; | 213 | released = true; |
| 214 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1); | ||
| 184 | } | 215 | } |
| 216 | f->prev_touch = f->touch; | ||
| 185 | f->valid = 0; | 217 | f->valid = 0; |
| 186 | } | 218 | } |
| 187 | 219 | ||
