xref: /OK3568_Linux_fs/kernel/drivers/input/touchscreen/penmount.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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