aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/dynapro.c
diff options
context:
space:
mode:
authorTias Guns <tias@ulyssis.org>2009-10-25 15:13:58 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-10-26 14:01:30 -0400
commita5f523bc0cdee2a163a034344ebf1163799b3c5d (patch)
tree1c815ae6dccd562d5c192baf272639e31ee4f4dc /drivers/input/touchscreen/dynapro.c
parentb0aba1e66c38d64be2c7dbf4b08c71857031ab67 (diff)
Input: add driver for Dynapro serial touchscreen
This is a driver for Dynapro serial touchscreen, which used to be supported in Xorg. The driver needs updated inputattach utility to initialize serial port and create proper serio device before the driver will be bound to it. Signed-off-by: Tias Guns <tias@ulyssis.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/touchscreen/dynapro.c')
-rw-r--r--drivers/input/touchscreen/dynapro.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
new file mode 100644
index 000000000000..455353908bdf
--- /dev/null
+++ b/drivers/input/touchscreen/dynapro.c
@@ -0,0 +1,206 @@
1/*
2 * Dynapro serial touchscreen driver
3 *
4 * Copyright (c) 2009 Tias Guns
5 * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
6 * Richard Lemon
7 *
8 */
9
10/*
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 as published by
13 * the Free Software Foundation.
14 */
15
16/*
17 * 2009/09/19 Tias Guns <tias@ulyssis.org>
18 * Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
19 */
20
21#include <linux/errno.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/input.h>
26#include <linux/serio.h>
27#include <linux/init.h>
28
29#define DRIVER_DESC "Dynapro serial touchscreen driver"
30
31MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
32MODULE_DESCRIPTION(DRIVER_DESC);
33MODULE_LICENSE("GPL");
34
35/*
36 * Definitions & global arrays.
37 */
38
39#define DYNAPRO_FORMAT_TOUCH_BIT 0x40
40#define DYNAPRO_FORMAT_LENGTH 3
41#define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
42
43#define DYNAPRO_MIN_XC 0
44#define DYNAPRO_MAX_XC 0x3ff
45#define DYNAPRO_MIN_YC 0
46#define DYNAPRO_MAX_YC 0x3ff
47
48#define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
49#define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
50#define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
51
52/*
53 * Per-touchscreen data.
54 */
55
56struct dynapro {
57 struct input_dev *dev;
58 struct serio *serio;
59 int idx;
60 unsigned char data[DYNAPRO_FORMAT_LENGTH];
61 char phys[32];
62};
63
64static void dynapro_process_data(struct dynapro *pdynapro)
65{
66 struct input_dev *dev = pdynapro->dev;
67
68 if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) {
69 input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data));
70 input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data));
71 input_report_key(dev, BTN_TOUCH,
72 DYNAPRO_GET_TOUCHED(pdynapro->data));
73 input_sync(dev);
74
75 pdynapro->idx = 0;
76 }
77}
78
79static irqreturn_t dynapro_interrupt(struct serio *serio,
80 unsigned char data, unsigned int flags)
81{
82 struct dynapro *pdynapro = serio_get_drvdata(serio);
83
84 pdynapro->data[pdynapro->idx] = data;
85
86 if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0])
87 dynapro_process_data(pdynapro);
88 else
89 dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
90 pdynapro->data[0]);
91
92 return IRQ_HANDLED;
93}
94
95static void dynapro_disconnect(struct serio *serio)
96{
97 struct dynapro *pdynapro = serio_get_drvdata(serio);
98
99 input_get_device(pdynapro->dev);
100 input_unregister_device(pdynapro->dev);
101 serio_close(serio);
102 serio_set_drvdata(serio, NULL);
103 input_put_device(pdynapro->dev);
104 kfree(pdynapro);
105}
106
107/*
108 * dynapro_connect() is the routine that is called when someone adds a
109 * new serio device that supports dynapro protocol and registers it as
110 * an input device. This is usually accomplished using inputattach.
111 */
112
113static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
114{
115 struct dynapro *pdynapro;
116 struct input_dev *input_dev;
117 int err;
118
119 pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
120 input_dev = input_allocate_device();
121 if (!pdynapro || !input_dev) {
122 err = -ENOMEM;
123 goto fail1;
124 }
125
126 pdynapro->serio = serio;
127 pdynapro->dev = input_dev;
128 snprintf(pdynapro->phys, sizeof(pdynapro->phys),
129 "%s/input0", serio->phys);
130
131 input_dev->name = "Dynapro Serial TouchScreen";
132 input_dev->phys = pdynapro->phys;
133 input_dev->id.bustype = BUS_RS232;
134 input_dev->id.vendor = SERIO_DYNAPRO;
135 input_dev->id.product = 0;
136 input_dev->id.version = 0x0001;
137 input_dev->dev.parent = &serio->dev;
138 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
139 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
140 input_set_abs_params(pdynapro->dev, ABS_X,
141 DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0);
142 input_set_abs_params(pdynapro->dev, ABS_Y,
143 DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0);
144
145 serio_set_drvdata(serio, pdynapro);
146
147 err = serio_open(serio, drv);
148 if (err)
149 goto fail2;
150
151 err = input_register_device(pdynapro->dev);
152 if (err)
153 goto fail3;
154
155 return 0;
156
157 fail3: serio_close(serio);
158 fail2: serio_set_drvdata(serio, NULL);
159 fail1: input_free_device(input_dev);
160 kfree(pdynapro);
161 return err;
162}
163
164/*
165 * The serio driver structure.
166 */
167
168static struct serio_device_id dynapro_serio_ids[] = {
169 {
170 .type = SERIO_RS232,
171 .proto = SERIO_DYNAPRO,
172 .id = SERIO_ANY,
173 .extra = SERIO_ANY,
174 },
175 { 0 }
176};
177
178MODULE_DEVICE_TABLE(serio, dynapro_serio_ids);
179
180static struct serio_driver dynapro_drv = {
181 .driver = {
182 .name = "dynapro",
183 },
184 .description = DRIVER_DESC,
185 .id_table = dynapro_serio_ids,
186 .interrupt = dynapro_interrupt,
187 .connect = dynapro_connect,
188 .disconnect = dynapro_disconnect,
189};
190
191/*
192 * The functions for inserting/removing us as a module.
193 */
194
195static int __init dynapro_init(void)
196{
197 return serio_register_driver(&dynapro_drv);
198}
199
200static void __exit dynapro_exit(void)
201{
202 serio_unregister_driver(&dynapro_drv);
203}
204
205module_init(dynapro_init);
206module_exit(dynapro_exit);