blob: 71422b91dc46463d7a8d7cd7a0b217bc5c526c1c [file] [log] [blame]
Rick Kochee479992006-08-05 00:32:18 -04001/*
2 * Penmount serial touchscreen driver
3 *
4 * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
John Sung21ae5082011-09-09 13:33:12 -07005 * Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
Rick Kochee479992006-08-05 00:32:18 -04006 *
7 * Based on ELO driver (drivers/input/touchscreen/elo.c)
8 * Copyright (c) 2004 Vojtech Pavlik
9 */
10
11/*
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published
14 * by the Free Software Foundation.
15 */
16
17#include <linux/errno.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/slab.h>
21#include <linux/input.h>
John Sung90aba7d2011-09-09 13:33:12 -070022#include <linux/input/mt.h>
Rick Kochee479992006-08-05 00:32:18 -040023#include <linux/serio.h>
24#include <linux/init.h>
25
John Sung21ae5082011-09-09 13:33:12 -070026#define DRIVER_DESC "PenMount serial touchscreen driver"
Rick Kochee479992006-08-05 00:32:18 -040027
28MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
John Sung21ae5082011-09-09 13:33:12 -070029MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
Rick Kochee479992006-08-05 00:32:18 -040030MODULE_DESCRIPTION(DRIVER_DESC);
31MODULE_LICENSE("GPL");
32
33/*
34 * Definitions & global arrays.
35 */
36
John Sungc42e2e42011-09-09 13:33:12 -070037#define PM_MAX_LENGTH 6
John Sung90aba7d2011-09-09 13:33:12 -070038#define PM_MAX_MTSLOT 16
39#define PM_3000_MTSLOT 2
40
41/*
42 * Multi-touch slot
43 */
44
45struct mt_slot {
46 unsigned short x, y;
47 bool active; /* is the touch valid? */
48};
Rick Kochee479992006-08-05 00:32:18 -040049
50/*
51 * Per-touchscreen data.
52 */
53
54struct pm {
55 struct input_dev *dev;
56 struct serio *serio;
57 int idx;
58 unsigned char data[PM_MAX_LENGTH];
59 char phys[32];
John Sungc42e2e42011-09-09 13:33:12 -070060 unsigned char packetsize;
John Sung90aba7d2011-09-09 13:33:12 -070061 unsigned char maxcontacts;
62 struct mt_slot slots[PM_MAX_MTSLOT];
Rick Kochee479992006-08-05 00:32:18 -040063};
64
John Sungc42e2e42011-09-09 13:33:12 -070065/*
John Sung90aba7d2011-09-09 13:33:12 -070066 * pm_mtevent() sends mt events and also emulates pointer movement
67 */
68
69static 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/*
John Sungc42e2e42011-09-09 13:33:12 -070088 * pm_checkpacket() checks if data packet is valid
89 */
90
91static bool pm_checkpacket(unsigned char *packet)
92{
93 int total = 0;
94 int i;
95
96 for (i = 0; i < 5; i++)
97 total += packet[i];
98
99 return packet[5] == (unsigned char)~(total & 0xff);
100}
101
Rick Kochee479992006-08-05 00:32:18 -0400102static irqreturn_t pm_interrupt(struct serio *serio,
David Howells7d12e782006-10-05 14:55:46 +0100103 unsigned char data, unsigned int flags)
Rick Kochee479992006-08-05 00:32:18 -0400104{
105 struct pm *pm = serio_get_drvdata(serio);
106 struct input_dev *dev = pm->dev;
107
108 pm->data[pm->idx] = data;
109
John Sungc42e2e42011-09-09 13:33:12 -0700110 switch (pm->dev->id.product) {
111 case 0x9000:
112 if (pm->data[0] & 0x80) {
113 if (pm->packetsize == ++pm->idx) {
114 input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
115 input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
116 input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
117 input_sync(dev);
118 pm->idx = 0;
119 }
Rick Kochee479992006-08-05 00:32:18 -0400120 }
John Sungc42e2e42011-09-09 13:33:12 -0700121 break;
122
123 case 0x6000:
124 if ((pm->data[0] & 0xbf) == 0x30) {
125 if (pm->packetsize == ++pm->idx) {
126 if (pm_checkpacket(pm->data)) {
127 input_report_abs(dev, ABS_X,
128 pm->data[2] * 256 + pm->data[1]);
129 input_report_abs(dev, ABS_Y,
130 pm->data[4] * 256 + pm->data[3]);
131 input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
132 input_sync(dev);
133 }
134 pm->idx = 0;
135 }
136 }
137 break;
John Sung90aba7d2011-09-09 13:33:12 -0700138
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;
Rick Kochee479992006-08-05 00:32:18 -0400153 }
154
155 return IRQ_HANDLED;
156}
157
158/*
159 * pm_disconnect() is the opposite of pm_connect()
160 */
161
162static void pm_disconnect(struct serio *serio)
163{
164 struct pm *pm = serio_get_drvdata(serio);
165
166 input_get_device(pm->dev);
167 input_unregister_device(pm->dev);
168 serio_close(serio);
169 serio_set_drvdata(serio, NULL);
170 input_put_device(pm->dev);
171 kfree(pm);
172}
173
174/*
175 * pm_connect() is the routine that is called when someone adds a
John Sung21ae5082011-09-09 13:33:12 -0700176 * new serio device that supports PenMount protocol and registers it as
Rick Kochee479992006-08-05 00:32:18 -0400177 * an input device.
178 */
179
180static int pm_connect(struct serio *serio, struct serio_driver *drv)
181{
182 struct pm *pm;
183 struct input_dev *input_dev;
John Sung90aba7d2011-09-09 13:33:12 -0700184 int max_x, max_y;
Rick Kochee479992006-08-05 00:32:18 -0400185 int err;
186
187 pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
188 input_dev = input_allocate_device();
189 if (!pm || !input_dev) {
190 err = -ENOMEM;
191 goto fail1;
192 }
193
194 pm->serio = serio;
195 pm->dev = input_dev;
196 snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
John Sung90aba7d2011-09-09 13:33:12 -0700197 pm->maxcontacts = 1;
Rick Kochee479992006-08-05 00:32:18 -0400198
John Sung21ae5082011-09-09 13:33:12 -0700199 input_dev->name = "PenMount Serial TouchScreen";
Rick Kochee479992006-08-05 00:32:18 -0400200 input_dev->phys = pm->phys;
201 input_dev->id.bustype = BUS_RS232;
202 input_dev->id.vendor = SERIO_PENMOUNT;
203 input_dev->id.product = 0;
204 input_dev->id.version = 0x0100;
Dmitry Torokhova5394fb02007-04-12 01:35:14 -0400205 input_dev->dev.parent = &serio->dev;
Rick Kochee479992006-08-05 00:32:18 -0400206
John Sung90aba7d2011-09-09 13:33:12 -0700207 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
208 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
Rick Kochee479992006-08-05 00:32:18 -0400209
John Sungc42e2e42011-09-09 13:33:12 -0700210 switch (serio->id.id) {
211 default:
212 case 0:
213 pm->packetsize = 5;
214 input_dev->id.product = 0x9000;
John Sung90aba7d2011-09-09 13:33:12 -0700215 max_x = max_y = 0x3ff;
John Sungc42e2e42011-09-09 13:33:12 -0700216 break;
217
218 case 1:
219 pm->packetsize = 6;
220 input_dev->id.product = 0x6000;
John Sung90aba7d2011-09-09 13:33:12 -0700221 max_x = max_y = 0x3ff;
John Sungc42e2e42011-09-09 13:33:12 -0700222 break;
John Sung90aba7d2011-09-09 13:33:12 -0700223
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;
229 break;
230 }
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);
John Sungc42e2e42011-09-09 13:33:12 -0700241 }
242
Rick Kochee479992006-08-05 00:32:18 -0400243 serio_set_drvdata(serio, pm);
244
245 err = serio_open(serio, drv);
246 if (err)
247 goto fail2;
248
249 err = input_register_device(pm->dev);
250 if (err)
251 goto fail3;
252
253 return 0;
254
255 fail3: serio_close(serio);
256 fail2: serio_set_drvdata(serio, NULL);
257 fail1: input_free_device(input_dev);
258 kfree(pm);
259 return err;
260}
261
262/*
263 * The serio driver structure.
264 */
265
266static struct serio_device_id pm_serio_ids[] = {
267 {
268 .type = SERIO_RS232,
269 .proto = SERIO_PENMOUNT,
270 .id = SERIO_ANY,
271 .extra = SERIO_ANY,
272 },
273 { 0 }
274};
275
276MODULE_DEVICE_TABLE(serio, pm_serio_ids);
277
278static struct serio_driver pm_drv = {
279 .driver = {
John Sung21ae5082011-09-09 13:33:12 -0700280 .name = "serio-penmount",
Rick Kochee479992006-08-05 00:32:18 -0400281 },
282 .description = DRIVER_DESC,
283 .id_table = pm_serio_ids,
284 .interrupt = pm_interrupt,
285 .connect = pm_connect,
286 .disconnect = pm_disconnect,
287};
288
289/*
290 * The functions for inserting/removing us as a module.
291 */
292
293static int __init pm_init(void)
294{
Akinobu Mita153a9df02006-11-23 23:35:10 -0500295 return serio_register_driver(&pm_drv);
Rick Kochee479992006-08-05 00:32:18 -0400296}
297
298static void __exit pm_exit(void)
299{
300 serio_unregister_driver(&pm_drv);
301}
302
303module_init(pm_init);
304module_exit(pm_exit);