diff options
author | John Sung <penmount.touch@gmail.com> | 2011-09-09 16:33:12 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-09-21 01:46:29 -0400 |
commit | 90aba7d8b155c2c39e269608e4a446190e3cd704 (patch) | |
tree | 21883b5438253be3330645468b3507454e5f9ed2 | |
parent | c42e2e406ad49f320947ba044d3bbf9b05703089 (diff) |
Input: penmount - add PenMount 3000 support
Add dual touch support for PenMount 3000 touch controller.
Signed-off-by: John Sung <penmount.touch@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/touchscreen/penmount.c | 79 |
1 files changed, 75 insertions, 4 deletions
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index e9117adcf6df..71422b91dc46 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/input.h> | 21 | #include <linux/input.h> |
22 | #include <linux/input/mt.h> | ||
22 | #include <linux/serio.h> | 23 | #include <linux/serio.h> |
23 | #include <linux/init.h> | 24 | #include <linux/init.h> |
24 | 25 | ||
@@ -34,6 +35,17 @@ MODULE_LICENSE("GPL"); | |||
34 | */ | 35 | */ |
35 | 36 | ||
36 | #define PM_MAX_LENGTH 6 | 37 | #define PM_MAX_LENGTH 6 |
38 | #define PM_MAX_MTSLOT 16 | ||
39 | #define PM_3000_MTSLOT 2 | ||
40 | |||
41 | /* | ||
42 | * Multi-touch slot | ||
43 | */ | ||
44 | |||
45 | struct mt_slot { | ||
46 | unsigned short x, y; | ||
47 | bool active; /* is the touch valid? */ | ||
48 | }; | ||
37 | 49 | ||
38 | /* | 50 | /* |
39 | * Per-touchscreen data. | 51 | * Per-touchscreen data. |
@@ -46,9 +58,33 @@ struct pm { | |||
46 | unsigned char data[PM_MAX_LENGTH]; | 58 | unsigned char data[PM_MAX_LENGTH]; |
47 | char phys[32]; | 59 | char phys[32]; |
48 | unsigned char packetsize; | 60 | unsigned char packetsize; |
61 | unsigned char maxcontacts; | ||
62 | struct mt_slot slots[PM_MAX_MTSLOT]; | ||
49 | }; | 63 | }; |
50 | 64 | ||
51 | /* | 65 | /* |
66 | * pm_mtevent() sends mt events and also emulates pointer movement | ||
67 | */ | ||
68 | |||
69 | static void pm_mtevent(struct pm *pm, struct input_dev *input) | ||
70 | { | ||
71 | int i; | ||
72 | |||
73 | for (i = 0; i < pm->maxcontacts; ++i) { | ||
74 | input_mt_slot(input, i); | ||
75 | input_mt_report_slot_state(input, MT_TOOL_FINGER, | ||
76 | pm->slots[i].active); | ||
77 | if (pm->slots[i].active) { | ||
78 | input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x); | ||
79 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | input_mt_report_pointer_emulation(input, true); | ||
84 | input_sync(input); | ||
85 | } | ||
86 | |||
87 | /* | ||
52 | * pm_checkpacket() checks if data packet is valid | 88 | * pm_checkpacket() checks if data packet is valid |
53 | */ | 89 | */ |
54 | 90 | ||
@@ -99,6 +135,21 @@ static irqreturn_t pm_interrupt(struct serio *serio, | |||
99 | } | 135 | } |
100 | } | 136 | } |
101 | break; | 137 | break; |
138 | |||
139 | case 0x3000: | ||
140 | if ((pm->data[0] & 0xce) == 0x40) { | ||
141 | if (pm->packetsize == ++pm->idx) { | ||
142 | if (pm_checkpacket(pm->data)) { | ||
143 | int slotnum = pm->data[0] & 0x0f; | ||
144 | pm->slots[slotnum].active = pm->data[0] & 0x30; | ||
145 | pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1]; | ||
146 | pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3]; | ||
147 | pm_mtevent(pm, dev); | ||
148 | } | ||
149 | pm->idx = 0; | ||
150 | } | ||
151 | } | ||
152 | break; | ||
102 | } | 153 | } |
103 | 154 | ||
104 | return IRQ_HANDLED; | 155 | return IRQ_HANDLED; |
@@ -130,6 +181,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) | |||
130 | { | 181 | { |
131 | struct pm *pm; | 182 | struct pm *pm; |
132 | struct input_dev *input_dev; | 183 | struct input_dev *input_dev; |
184 | int max_x, max_y; | ||
133 | int err; | 185 | int err; |
134 | 186 | ||
135 | pm = kzalloc(sizeof(struct pm), GFP_KERNEL); | 187 | pm = kzalloc(sizeof(struct pm), GFP_KERNEL); |
@@ -142,6 +194,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) | |||
142 | pm->serio = serio; | 194 | pm->serio = serio; |
143 | pm->dev = input_dev; | 195 | pm->dev = input_dev; |
144 | snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); | 196 | snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); |
197 | pm->maxcontacts = 1; | ||
145 | 198 | ||
146 | input_dev->name = "PenMount Serial TouchScreen"; | 199 | input_dev->name = "PenMount Serial TouchScreen"; |
147 | input_dev->phys = pm->phys; | 200 | input_dev->phys = pm->phys; |
@@ -151,24 +204,42 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) | |||
151 | input_dev->id.version = 0x0100; | 204 | input_dev->id.version = 0x0100; |
152 | input_dev->dev.parent = &serio->dev; | 205 | input_dev->dev.parent = &serio->dev; |
153 | 206 | ||
154 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 207 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
155 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | 208 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
156 | input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0); | ||
157 | input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0); | ||
158 | 209 | ||
159 | switch (serio->id.id) { | 210 | switch (serio->id.id) { |
160 | default: | 211 | default: |
161 | case 0: | 212 | case 0: |
162 | pm->packetsize = 5; | 213 | pm->packetsize = 5; |
163 | input_dev->id.product = 0x9000; | 214 | input_dev->id.product = 0x9000; |
215 | max_x = max_y = 0x3ff; | ||
164 | break; | 216 | break; |
165 | 217 | ||
166 | case 1: | 218 | case 1: |
167 | pm->packetsize = 6; | 219 | pm->packetsize = 6; |
168 | input_dev->id.product = 0x6000; | 220 | input_dev->id.product = 0x6000; |
221 | max_x = max_y = 0x3ff; | ||
222 | break; | ||
223 | |||
224 | case 2: | ||
225 | pm->packetsize = 6; | ||
226 | input_dev->id.product = 0x3000; | ||
227 | max_x = max_y = 0x7ff; | ||
228 | pm->maxcontacts = PM_3000_MTSLOT; | ||
169 | break; | 229 | break; |
170 | } | 230 | } |
171 | 231 | ||
232 | input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0); | ||
233 | input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0); | ||
234 | |||
235 | if (pm->maxcontacts > 1) { | ||
236 | input_mt_init_slots(pm->dev, pm->maxcontacts); | ||
237 | input_set_abs_params(pm->dev, | ||
238 | ABS_MT_POSITION_X, 0, max_x, 0, 0); | ||
239 | input_set_abs_params(pm->dev, | ||
240 | ABS_MT_POSITION_Y, 0, max_y, 0, 0); | ||
241 | } | ||
242 | |||
172 | serio_set_drvdata(serio, pm); | 243 | serio_set_drvdata(serio, pm); |
173 | 244 | ||
174 | err = serio_open(serio, drv); | 245 | err = serio_open(serio, drv); |