1 // SPDX-License-Identifier: GPL-2.0-only
3 * Penmount serial touchscreen driver
5 * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
6 * Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
8 * Based on ELO driver (drivers/input/touchscreen/elo.c)
9 * Copyright (c) 2004 Vojtech Pavlik
13 #include <linux/errno.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <linux/input.h>
18 #include <linux/input/mt.h>
19 #include <linux/serio.h>
21 #define DRIVER_DESC "PenMount serial touchscreen driver"
23 MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
24 MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
25 MODULE_DESCRIPTION(DRIVER_DESC
);
26 MODULE_LICENSE("GPL");
29 * Definitions & global arrays.
32 #define PM_MAX_LENGTH 6
33 #define PM_MAX_MTSLOT 16
34 #define PM_3000_MTSLOT 2
35 #define PM_6250_MTSLOT 12
43 bool active
; /* is the touch valid? */
47 * Per-touchscreen data.
51 struct input_dev
*dev
;
54 unsigned char data
[PM_MAX_LENGTH
];
56 unsigned char packetsize
;
57 unsigned char maxcontacts
;
58 struct mt_slot slots
[PM_MAX_MTSLOT
];
59 void (*parse_packet
)(struct pm
*);
63 * pm_mtevent() sends mt events and also emulates pointer movement
66 static void pm_mtevent(struct pm
*pm
, struct input_dev
*input
)
70 for (i
= 0; i
< pm
->maxcontacts
; ++i
) {
71 input_mt_slot(input
, i
);
72 input_mt_report_slot_state(input
, MT_TOOL_FINGER
,
74 if (pm
->slots
[i
].active
) {
75 input_event(input
, EV_ABS
, ABS_MT_POSITION_X
, pm
->slots
[i
].x
);
76 input_event(input
, EV_ABS
, ABS_MT_POSITION_Y
, pm
->slots
[i
].y
);
80 input_mt_report_pointer_emulation(input
, true);
85 * pm_checkpacket() checks if data packet is valid
88 static bool pm_checkpacket(unsigned char *packet
)
93 for (i
= 0; i
< 5; i
++)
96 return packet
[5] == (unsigned char)~(total
& 0xff);
99 static void pm_parse_9000(struct pm
*pm
)
101 struct input_dev
*dev
= pm
->dev
;
103 if ((pm
->data
[0] & 0x80) && pm
->packetsize
== ++pm
->idx
) {
104 input_report_abs(dev
, ABS_X
, pm
->data
[1] * 128 + pm
->data
[2]);
105 input_report_abs(dev
, ABS_Y
, pm
->data
[3] * 128 + pm
->data
[4]);
106 input_report_key(dev
, BTN_TOUCH
, !!(pm
->data
[0] & 0x40));
112 static void pm_parse_6000(struct pm
*pm
)
114 struct input_dev
*dev
= pm
->dev
;
116 if ((pm
->data
[0] & 0xbf) == 0x30 && pm
->packetsize
== ++pm
->idx
) {
117 if (pm_checkpacket(pm
->data
)) {
118 input_report_abs(dev
, ABS_X
,
119 pm
->data
[2] * 256 + pm
->data
[1]);
120 input_report_abs(dev
, ABS_Y
,
121 pm
->data
[4] * 256 + pm
->data
[3]);
122 input_report_key(dev
, BTN_TOUCH
, pm
->data
[0] & 0x40);
129 static void pm_parse_3000(struct pm
*pm
)
131 struct input_dev
*dev
= pm
->dev
;
133 if ((pm
->data
[0] & 0xce) == 0x40 && pm
->packetsize
== ++pm
->idx
) {
134 if (pm_checkpacket(pm
->data
)) {
135 int slotnum
= pm
->data
[0] & 0x0f;
136 pm
->slots
[slotnum
].active
= pm
->data
[0] & 0x30;
137 pm
->slots
[slotnum
].x
= pm
->data
[2] * 256 + pm
->data
[1];
138 pm
->slots
[slotnum
].y
= pm
->data
[4] * 256 + pm
->data
[3];
145 static void pm_parse_6250(struct pm
*pm
)
147 struct input_dev
*dev
= pm
->dev
;
149 if ((pm
->data
[0] & 0xb0) == 0x30 && pm
->packetsize
== ++pm
->idx
) {
150 if (pm_checkpacket(pm
->data
)) {
151 int slotnum
= pm
->data
[0] & 0x0f;
152 pm
->slots
[slotnum
].active
= pm
->data
[0] & 0x40;
153 pm
->slots
[slotnum
].x
= pm
->data
[2] * 256 + pm
->data
[1];
154 pm
->slots
[slotnum
].y
= pm
->data
[4] * 256 + pm
->data
[3];
161 static irqreturn_t
pm_interrupt(struct serio
*serio
,
162 unsigned char data
, unsigned int flags
)
164 struct pm
*pm
= serio_get_drvdata(serio
);
166 pm
->data
[pm
->idx
] = data
;
168 pm
->parse_packet(pm
);
174 * pm_disconnect() is the opposite of pm_connect()
177 static void pm_disconnect(struct serio
*serio
)
179 struct pm
*pm
= serio_get_drvdata(serio
);
183 input_unregister_device(pm
->dev
);
186 serio_set_drvdata(serio
, NULL
);
190 * pm_connect() is the routine that is called when someone adds a
191 * new serio device that supports PenMount protocol and registers it as
195 static int pm_connect(struct serio
*serio
, struct serio_driver
*drv
)
198 struct input_dev
*input_dev
;
202 pm
= kzalloc(sizeof(struct pm
), GFP_KERNEL
);
203 input_dev
= input_allocate_device();
204 if (!pm
|| !input_dev
) {
211 snprintf(pm
->phys
, sizeof(pm
->phys
), "%s/input0", serio
->phys
);
214 input_dev
->name
= "PenMount Serial TouchScreen";
215 input_dev
->phys
= pm
->phys
;
216 input_dev
->id
.bustype
= BUS_RS232
;
217 input_dev
->id
.vendor
= SERIO_PENMOUNT
;
218 input_dev
->id
.product
= 0;
219 input_dev
->id
.version
= 0x0100;
220 input_dev
->dev
.parent
= &serio
->dev
;
222 input_dev
->evbit
[0] = BIT_MASK(EV_KEY
) | BIT_MASK(EV_ABS
);
223 input_dev
->keybit
[BIT_WORD(BTN_TOUCH
)] = BIT_MASK(BTN_TOUCH
);
225 switch (serio
->id
.id
) {
229 pm
->parse_packet
= pm_parse_9000
;
230 input_dev
->id
.product
= 0x9000;
231 max_x
= max_y
= 0x3ff;
236 pm
->parse_packet
= pm_parse_6000
;
237 input_dev
->id
.product
= 0x6000;
238 max_x
= max_y
= 0x3ff;
243 pm
->parse_packet
= pm_parse_3000
;
244 input_dev
->id
.product
= 0x3000;
245 max_x
= max_y
= 0x7ff;
246 pm
->maxcontacts
= PM_3000_MTSLOT
;
251 pm
->parse_packet
= pm_parse_6250
;
252 input_dev
->id
.product
= 0x6250;
253 max_x
= max_y
= 0x3ff;
254 pm
->maxcontacts
= PM_6250_MTSLOT
;
258 input_set_abs_params(pm
->dev
, ABS_X
, 0, max_x
, 0, 0);
259 input_set_abs_params(pm
->dev
, ABS_Y
, 0, max_y
, 0, 0);
261 if (pm
->maxcontacts
> 1) {
262 input_mt_init_slots(pm
->dev
, pm
->maxcontacts
, 0);
263 input_set_abs_params(pm
->dev
,
264 ABS_MT_POSITION_X
, 0, max_x
, 0, 0);
265 input_set_abs_params(pm
->dev
,
266 ABS_MT_POSITION_Y
, 0, max_y
, 0, 0);
269 serio_set_drvdata(serio
, pm
);
271 err
= serio_open(serio
, drv
);
275 err
= input_register_device(pm
->dev
);
281 fail3
: serio_close(serio
);
282 fail2
: serio_set_drvdata(serio
, NULL
);
283 fail1
: input_free_device(input_dev
);
289 * The serio driver structure.
292 static const struct serio_device_id pm_serio_ids
[] = {
295 .proto
= SERIO_PENMOUNT
,
302 MODULE_DEVICE_TABLE(serio
, pm_serio_ids
);
304 static struct serio_driver pm_drv
= {
306 .name
= "serio-penmount",
308 .description
= DRIVER_DESC
,
309 .id_table
= pm_serio_ids
,
310 .interrupt
= pm_interrupt
,
311 .connect
= pm_connect
,
312 .disconnect
= pm_disconnect
,
315 module_serio_driver(pm_drv
);