1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a5f523bcSTias Guns /*
3a5f523bcSTias Guns * Dynapro serial touchscreen driver
4a5f523bcSTias Guns *
5a5f523bcSTias Guns * Copyright (c) 2009 Tias Guns
6a5f523bcSTias Guns * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
7a5f523bcSTias Guns * Richard Lemon
8a5f523bcSTias Guns */
9a5f523bcSTias Guns
10a5f523bcSTias Guns
11a5f523bcSTias Guns /*
12a5f523bcSTias Guns * 2009/09/19 Tias Guns <tias@ulyssis.org>
13a5f523bcSTias Guns * Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
14a5f523bcSTias Guns */
15a5f523bcSTias Guns
16a5f523bcSTias Guns #include <linux/errno.h>
17a5f523bcSTias Guns #include <linux/kernel.h>
18a5f523bcSTias Guns #include <linux/module.h>
19a5f523bcSTias Guns #include <linux/slab.h>
20a5f523bcSTias Guns #include <linux/input.h>
21a5f523bcSTias Guns #include <linux/serio.h>
22a5f523bcSTias Guns
23a5f523bcSTias Guns #define DRIVER_DESC "Dynapro serial touchscreen driver"
24a5f523bcSTias Guns
25a5f523bcSTias Guns MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
26a5f523bcSTias Guns MODULE_DESCRIPTION(DRIVER_DESC);
27a5f523bcSTias Guns MODULE_LICENSE("GPL");
28a5f523bcSTias Guns
29a5f523bcSTias Guns /*
30a5f523bcSTias Guns * Definitions & global arrays.
31a5f523bcSTias Guns */
32a5f523bcSTias Guns
33a5f523bcSTias Guns #define DYNAPRO_FORMAT_TOUCH_BIT 0x40
34a5f523bcSTias Guns #define DYNAPRO_FORMAT_LENGTH 3
35a5f523bcSTias Guns #define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
36a5f523bcSTias Guns
37a5f523bcSTias Guns #define DYNAPRO_MIN_XC 0
38a5f523bcSTias Guns #define DYNAPRO_MAX_XC 0x3ff
39a5f523bcSTias Guns #define DYNAPRO_MIN_YC 0
40a5f523bcSTias Guns #define DYNAPRO_MAX_YC 0x3ff
41a5f523bcSTias Guns
42a5f523bcSTias Guns #define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
43a5f523bcSTias Guns #define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
44a5f523bcSTias Guns #define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
45a5f523bcSTias Guns
46a5f523bcSTias Guns /*
47a5f523bcSTias Guns * Per-touchscreen data.
48a5f523bcSTias Guns */
49a5f523bcSTias Guns
50a5f523bcSTias Guns struct dynapro {
51a5f523bcSTias Guns struct input_dev *dev;
52a5f523bcSTias Guns struct serio *serio;
53a5f523bcSTias Guns int idx;
54a5f523bcSTias Guns unsigned char data[DYNAPRO_FORMAT_LENGTH];
55a5f523bcSTias Guns char phys[32];
56a5f523bcSTias Guns };
57a5f523bcSTias Guns
dynapro_process_data(struct dynapro * pdynapro)58a5f523bcSTias Guns static void dynapro_process_data(struct dynapro *pdynapro)
59a5f523bcSTias Guns {
60a5f523bcSTias Guns struct input_dev *dev = pdynapro->dev;
61a5f523bcSTias Guns
62a5f523bcSTias Guns if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) {
63a5f523bcSTias Guns input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data));
64a5f523bcSTias Guns input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data));
65a5f523bcSTias Guns input_report_key(dev, BTN_TOUCH,
66a5f523bcSTias Guns DYNAPRO_GET_TOUCHED(pdynapro->data));
67a5f523bcSTias Guns input_sync(dev);
68a5f523bcSTias Guns
69a5f523bcSTias Guns pdynapro->idx = 0;
70a5f523bcSTias Guns }
71a5f523bcSTias Guns }
72a5f523bcSTias Guns
dynapro_interrupt(struct serio * serio,unsigned char data,unsigned int flags)73a5f523bcSTias Guns static irqreturn_t dynapro_interrupt(struct serio *serio,
74a5f523bcSTias Guns unsigned char data, unsigned int flags)
75a5f523bcSTias Guns {
76a5f523bcSTias Guns struct dynapro *pdynapro = serio_get_drvdata(serio);
77a5f523bcSTias Guns
78a5f523bcSTias Guns pdynapro->data[pdynapro->idx] = data;
79a5f523bcSTias Guns
80a5f523bcSTias Guns if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0])
81a5f523bcSTias Guns dynapro_process_data(pdynapro);
82a5f523bcSTias Guns else
83a5f523bcSTias Guns dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
84a5f523bcSTias Guns pdynapro->data[0]);
85a5f523bcSTias Guns
86a5f523bcSTias Guns return IRQ_HANDLED;
87a5f523bcSTias Guns }
88a5f523bcSTias Guns
dynapro_disconnect(struct serio * serio)89a5f523bcSTias Guns static void dynapro_disconnect(struct serio *serio)
90a5f523bcSTias Guns {
91a5f523bcSTias Guns struct dynapro *pdynapro = serio_get_drvdata(serio);
92a5f523bcSTias Guns
93a5f523bcSTias Guns input_get_device(pdynapro->dev);
94a5f523bcSTias Guns input_unregister_device(pdynapro->dev);
95a5f523bcSTias Guns serio_close(serio);
96a5f523bcSTias Guns serio_set_drvdata(serio, NULL);
97a5f523bcSTias Guns input_put_device(pdynapro->dev);
98a5f523bcSTias Guns kfree(pdynapro);
99a5f523bcSTias Guns }
100a5f523bcSTias Guns
101a5f523bcSTias Guns /*
102a5f523bcSTias Guns * dynapro_connect() is the routine that is called when someone adds a
103a5f523bcSTias Guns * new serio device that supports dynapro protocol and registers it as
104a5f523bcSTias Guns * an input device. This is usually accomplished using inputattach.
105a5f523bcSTias Guns */
106a5f523bcSTias Guns
dynapro_connect(struct serio * serio,struct serio_driver * drv)107a5f523bcSTias Guns static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
108a5f523bcSTias Guns {
109a5f523bcSTias Guns struct dynapro *pdynapro;
110a5f523bcSTias Guns struct input_dev *input_dev;
111a5f523bcSTias Guns int err;
112a5f523bcSTias Guns
113a5f523bcSTias Guns pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
114a5f523bcSTias Guns input_dev = input_allocate_device();
115a5f523bcSTias Guns if (!pdynapro || !input_dev) {
116a5f523bcSTias Guns err = -ENOMEM;
117a5f523bcSTias Guns goto fail1;
118a5f523bcSTias Guns }
119a5f523bcSTias Guns
120a5f523bcSTias Guns pdynapro->serio = serio;
121a5f523bcSTias Guns pdynapro->dev = input_dev;
122a5f523bcSTias Guns snprintf(pdynapro->phys, sizeof(pdynapro->phys),
123a5f523bcSTias Guns "%s/input0", serio->phys);
124a5f523bcSTias Guns
125a5f523bcSTias Guns input_dev->name = "Dynapro Serial TouchScreen";
126a5f523bcSTias Guns input_dev->phys = pdynapro->phys;
127a5f523bcSTias Guns input_dev->id.bustype = BUS_RS232;
128a5f523bcSTias Guns input_dev->id.vendor = SERIO_DYNAPRO;
129a5f523bcSTias Guns input_dev->id.product = 0;
130a5f523bcSTias Guns input_dev->id.version = 0x0001;
131a5f523bcSTias Guns input_dev->dev.parent = &serio->dev;
132a5f523bcSTias Guns input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
133a5f523bcSTias Guns input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
134a5f523bcSTias Guns input_set_abs_params(pdynapro->dev, ABS_X,
135a5f523bcSTias Guns DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0);
136a5f523bcSTias Guns input_set_abs_params(pdynapro->dev, ABS_Y,
137a5f523bcSTias Guns DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0);
138a5f523bcSTias Guns
139a5f523bcSTias Guns serio_set_drvdata(serio, pdynapro);
140a5f523bcSTias Guns
141a5f523bcSTias Guns err = serio_open(serio, drv);
142a5f523bcSTias Guns if (err)
143a5f523bcSTias Guns goto fail2;
144a5f523bcSTias Guns
145a5f523bcSTias Guns err = input_register_device(pdynapro->dev);
146a5f523bcSTias Guns if (err)
147a5f523bcSTias Guns goto fail3;
148a5f523bcSTias Guns
149a5f523bcSTias Guns return 0;
150a5f523bcSTias Guns
151a5f523bcSTias Guns fail3: serio_close(serio);
152a5f523bcSTias Guns fail2: serio_set_drvdata(serio, NULL);
153a5f523bcSTias Guns fail1: input_free_device(input_dev);
154a5f523bcSTias Guns kfree(pdynapro);
155a5f523bcSTias Guns return err;
156a5f523bcSTias Guns }
157a5f523bcSTias Guns
158a5f523bcSTias Guns /*
159a5f523bcSTias Guns * The serio driver structure.
160a5f523bcSTias Guns */
161a5f523bcSTias Guns
162fe11d25eSArvind Yadav static const struct serio_device_id dynapro_serio_ids[] = {
163a5f523bcSTias Guns {
164a5f523bcSTias Guns .type = SERIO_RS232,
165a5f523bcSTias Guns .proto = SERIO_DYNAPRO,
166a5f523bcSTias Guns .id = SERIO_ANY,
167a5f523bcSTias Guns .extra = SERIO_ANY,
168a5f523bcSTias Guns },
169a5f523bcSTias Guns { 0 }
170a5f523bcSTias Guns };
171a5f523bcSTias Guns
172a5f523bcSTias Guns MODULE_DEVICE_TABLE(serio, dynapro_serio_ids);
173a5f523bcSTias Guns
174a5f523bcSTias Guns static struct serio_driver dynapro_drv = {
175a5f523bcSTias Guns .driver = {
176a5f523bcSTias Guns .name = "dynapro",
177a5f523bcSTias Guns },
178a5f523bcSTias Guns .description = DRIVER_DESC,
179a5f523bcSTias Guns .id_table = dynapro_serio_ids,
180a5f523bcSTias Guns .interrupt = dynapro_interrupt,
181a5f523bcSTias Guns .connect = dynapro_connect,
182a5f523bcSTias Guns .disconnect = dynapro_disconnect,
183a5f523bcSTias Guns };
184a5f523bcSTias Guns
18565ac9f7aSAxel Lin module_serio_driver(dynapro_drv);
186