1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Penmount serial touchscreen driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
6*4882a593Smuzhiyun * Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Based on ELO driver (drivers/input/touchscreen/elo.c)
9*4882a593Smuzhiyun * Copyright (c) 2004 Vojtech Pavlik
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/input.h>
18*4882a593Smuzhiyun #include <linux/input/mt.h>
19*4882a593Smuzhiyun #include <linux/serio.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define DRIVER_DESC "PenMount serial touchscreen driver"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
24*4882a593Smuzhiyun MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
25*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
26*4882a593Smuzhiyun MODULE_LICENSE("GPL");
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun * Definitions & global arrays.
30*4882a593Smuzhiyun */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define PM_MAX_LENGTH 6
33*4882a593Smuzhiyun #define PM_MAX_MTSLOT 16
34*4882a593Smuzhiyun #define PM_3000_MTSLOT 2
35*4882a593Smuzhiyun #define PM_6250_MTSLOT 12
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun * Multi-touch slot
39*4882a593Smuzhiyun */
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun struct mt_slot {
42*4882a593Smuzhiyun unsigned short x, y;
43*4882a593Smuzhiyun bool active; /* is the touch valid? */
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /*
47*4882a593Smuzhiyun * Per-touchscreen data.
48*4882a593Smuzhiyun */
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun struct pm {
51*4882a593Smuzhiyun struct input_dev *dev;
52*4882a593Smuzhiyun struct serio *serio;
53*4882a593Smuzhiyun int idx;
54*4882a593Smuzhiyun unsigned char data[PM_MAX_LENGTH];
55*4882a593Smuzhiyun char phys[32];
56*4882a593Smuzhiyun unsigned char packetsize;
57*4882a593Smuzhiyun unsigned char maxcontacts;
58*4882a593Smuzhiyun struct mt_slot slots[PM_MAX_MTSLOT];
59*4882a593Smuzhiyun void (*parse_packet)(struct pm *);
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun * pm_mtevent() sends mt events and also emulates pointer movement
64*4882a593Smuzhiyun */
65*4882a593Smuzhiyun
pm_mtevent(struct pm * pm,struct input_dev * input)66*4882a593Smuzhiyun static void pm_mtevent(struct pm *pm, struct input_dev *input)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun int i;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun for (i = 0; i < pm->maxcontacts; ++i) {
71*4882a593Smuzhiyun input_mt_slot(input, i);
72*4882a593Smuzhiyun input_mt_report_slot_state(input, MT_TOOL_FINGER,
73*4882a593Smuzhiyun pm->slots[i].active);
74*4882a593Smuzhiyun if (pm->slots[i].active) {
75*4882a593Smuzhiyun input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x);
76*4882a593Smuzhiyun input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun input_mt_report_pointer_emulation(input, true);
81*4882a593Smuzhiyun input_sync(input);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /*
85*4882a593Smuzhiyun * pm_checkpacket() checks if data packet is valid
86*4882a593Smuzhiyun */
87*4882a593Smuzhiyun
pm_checkpacket(unsigned char * packet)88*4882a593Smuzhiyun static bool pm_checkpacket(unsigned char *packet)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun int total = 0;
91*4882a593Smuzhiyun int i;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun for (i = 0; i < 5; i++)
94*4882a593Smuzhiyun total += packet[i];
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return packet[5] == (unsigned char)~(total & 0xff);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
pm_parse_9000(struct pm * pm)99*4882a593Smuzhiyun static void pm_parse_9000(struct pm *pm)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun struct input_dev *dev = pm->dev;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) {
104*4882a593Smuzhiyun input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
105*4882a593Smuzhiyun input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
106*4882a593Smuzhiyun input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
107*4882a593Smuzhiyun input_sync(dev);
108*4882a593Smuzhiyun pm->idx = 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
pm_parse_6000(struct pm * pm)112*4882a593Smuzhiyun static void pm_parse_6000(struct pm *pm)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun struct input_dev *dev = pm->dev;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) {
117*4882a593Smuzhiyun if (pm_checkpacket(pm->data)) {
118*4882a593Smuzhiyun input_report_abs(dev, ABS_X,
119*4882a593Smuzhiyun pm->data[2] * 256 + pm->data[1]);
120*4882a593Smuzhiyun input_report_abs(dev, ABS_Y,
121*4882a593Smuzhiyun pm->data[4] * 256 + pm->data[3]);
122*4882a593Smuzhiyun input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40);
123*4882a593Smuzhiyun input_sync(dev);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun pm->idx = 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
pm_parse_3000(struct pm * pm)129*4882a593Smuzhiyun static void pm_parse_3000(struct pm *pm)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun struct input_dev *dev = pm->dev;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) {
134*4882a593Smuzhiyun if (pm_checkpacket(pm->data)) {
135*4882a593Smuzhiyun int slotnum = pm->data[0] & 0x0f;
136*4882a593Smuzhiyun pm->slots[slotnum].active = pm->data[0] & 0x30;
137*4882a593Smuzhiyun pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
138*4882a593Smuzhiyun pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
139*4882a593Smuzhiyun pm_mtevent(pm, dev);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun pm->idx = 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
pm_parse_6250(struct pm * pm)145*4882a593Smuzhiyun static void pm_parse_6250(struct pm *pm)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun struct input_dev *dev = pm->dev;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) {
150*4882a593Smuzhiyun if (pm_checkpacket(pm->data)) {
151*4882a593Smuzhiyun int slotnum = pm->data[0] & 0x0f;
152*4882a593Smuzhiyun pm->slots[slotnum].active = pm->data[0] & 0x40;
153*4882a593Smuzhiyun pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
154*4882a593Smuzhiyun pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
155*4882a593Smuzhiyun pm_mtevent(pm, dev);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun pm->idx = 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
pm_interrupt(struct serio * serio,unsigned char data,unsigned int flags)161*4882a593Smuzhiyun static irqreturn_t pm_interrupt(struct serio *serio,
162*4882a593Smuzhiyun unsigned char data, unsigned int flags)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun struct pm *pm = serio_get_drvdata(serio);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun pm->data[pm->idx] = data;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun pm->parse_packet(pm);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun return IRQ_HANDLED;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /*
174*4882a593Smuzhiyun * pm_disconnect() is the opposite of pm_connect()
175*4882a593Smuzhiyun */
176*4882a593Smuzhiyun
pm_disconnect(struct serio * serio)177*4882a593Smuzhiyun static void pm_disconnect(struct serio *serio)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun struct pm *pm = serio_get_drvdata(serio);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun serio_close(serio);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun input_unregister_device(pm->dev);
184*4882a593Smuzhiyun kfree(pm);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun serio_set_drvdata(serio, NULL);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /*
190*4882a593Smuzhiyun * pm_connect() is the routine that is called when someone adds a
191*4882a593Smuzhiyun * new serio device that supports PenMount protocol and registers it as
192*4882a593Smuzhiyun * an input device.
193*4882a593Smuzhiyun */
194*4882a593Smuzhiyun
pm_connect(struct serio * serio,struct serio_driver * drv)195*4882a593Smuzhiyun static int pm_connect(struct serio *serio, struct serio_driver *drv)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun struct pm *pm;
198*4882a593Smuzhiyun struct input_dev *input_dev;
199*4882a593Smuzhiyun int max_x, max_y;
200*4882a593Smuzhiyun int err;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
203*4882a593Smuzhiyun input_dev = input_allocate_device();
204*4882a593Smuzhiyun if (!pm || !input_dev) {
205*4882a593Smuzhiyun err = -ENOMEM;
206*4882a593Smuzhiyun goto fail1;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun pm->serio = serio;
210*4882a593Smuzhiyun pm->dev = input_dev;
211*4882a593Smuzhiyun snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
212*4882a593Smuzhiyun pm->maxcontacts = 1;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun input_dev->name = "PenMount Serial TouchScreen";
215*4882a593Smuzhiyun input_dev->phys = pm->phys;
216*4882a593Smuzhiyun input_dev->id.bustype = BUS_RS232;
217*4882a593Smuzhiyun input_dev->id.vendor = SERIO_PENMOUNT;
218*4882a593Smuzhiyun input_dev->id.product = 0;
219*4882a593Smuzhiyun input_dev->id.version = 0x0100;
220*4882a593Smuzhiyun input_dev->dev.parent = &serio->dev;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
223*4882a593Smuzhiyun input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun switch (serio->id.id) {
226*4882a593Smuzhiyun default:
227*4882a593Smuzhiyun case 0:
228*4882a593Smuzhiyun pm->packetsize = 5;
229*4882a593Smuzhiyun pm->parse_packet = pm_parse_9000;
230*4882a593Smuzhiyun input_dev->id.product = 0x9000;
231*4882a593Smuzhiyun max_x = max_y = 0x3ff;
232*4882a593Smuzhiyun break;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun case 1:
235*4882a593Smuzhiyun pm->packetsize = 6;
236*4882a593Smuzhiyun pm->parse_packet = pm_parse_6000;
237*4882a593Smuzhiyun input_dev->id.product = 0x6000;
238*4882a593Smuzhiyun max_x = max_y = 0x3ff;
239*4882a593Smuzhiyun break;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun case 2:
242*4882a593Smuzhiyun pm->packetsize = 6;
243*4882a593Smuzhiyun pm->parse_packet = pm_parse_3000;
244*4882a593Smuzhiyun input_dev->id.product = 0x3000;
245*4882a593Smuzhiyun max_x = max_y = 0x7ff;
246*4882a593Smuzhiyun pm->maxcontacts = PM_3000_MTSLOT;
247*4882a593Smuzhiyun break;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun case 3:
250*4882a593Smuzhiyun pm->packetsize = 6;
251*4882a593Smuzhiyun pm->parse_packet = pm_parse_6250;
252*4882a593Smuzhiyun input_dev->id.product = 0x6250;
253*4882a593Smuzhiyun max_x = max_y = 0x3ff;
254*4882a593Smuzhiyun pm->maxcontacts = PM_6250_MTSLOT;
255*4882a593Smuzhiyun break;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0);
259*4882a593Smuzhiyun input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun if (pm->maxcontacts > 1) {
262*4882a593Smuzhiyun input_mt_init_slots(pm->dev, pm->maxcontacts, 0);
263*4882a593Smuzhiyun input_set_abs_params(pm->dev,
264*4882a593Smuzhiyun ABS_MT_POSITION_X, 0, max_x, 0, 0);
265*4882a593Smuzhiyun input_set_abs_params(pm->dev,
266*4882a593Smuzhiyun ABS_MT_POSITION_Y, 0, max_y, 0, 0);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun serio_set_drvdata(serio, pm);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun err = serio_open(serio, drv);
272*4882a593Smuzhiyun if (err)
273*4882a593Smuzhiyun goto fail2;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun err = input_register_device(pm->dev);
276*4882a593Smuzhiyun if (err)
277*4882a593Smuzhiyun goto fail3;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun return 0;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun fail3: serio_close(serio);
282*4882a593Smuzhiyun fail2: serio_set_drvdata(serio, NULL);
283*4882a593Smuzhiyun fail1: input_free_device(input_dev);
284*4882a593Smuzhiyun kfree(pm);
285*4882a593Smuzhiyun return err;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /*
289*4882a593Smuzhiyun * The serio driver structure.
290*4882a593Smuzhiyun */
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun static const struct serio_device_id pm_serio_ids[] = {
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun .type = SERIO_RS232,
295*4882a593Smuzhiyun .proto = SERIO_PENMOUNT,
296*4882a593Smuzhiyun .id = SERIO_ANY,
297*4882a593Smuzhiyun .extra = SERIO_ANY,
298*4882a593Smuzhiyun },
299*4882a593Smuzhiyun { 0 }
300*4882a593Smuzhiyun };
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun MODULE_DEVICE_TABLE(serio, pm_serio_ids);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun static struct serio_driver pm_drv = {
305*4882a593Smuzhiyun .driver = {
306*4882a593Smuzhiyun .name = "serio-penmount",
307*4882a593Smuzhiyun },
308*4882a593Smuzhiyun .description = DRIVER_DESC,
309*4882a593Smuzhiyun .id_table = pm_serio_ids,
310*4882a593Smuzhiyun .interrupt = pm_interrupt,
311*4882a593Smuzhiyun .connect = pm_connect,
312*4882a593Smuzhiyun .disconnect = pm_disconnect,
313*4882a593Smuzhiyun };
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun module_serio_driver(pm_drv);
316