diff options
Diffstat (limited to 'drivers/input/touchscreen/dynapro.c')
-rw-r--r-- | drivers/input/touchscreen/dynapro.c | 206 |
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 | |||
31 | MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>"); | ||
32 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
33 | MODULE_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 | |||
56 | struct 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 | |||
64 | static 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 | |||
79 | static 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 | |||
95 | static 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 | |||
113 | static 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 | |||
168 | static 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 | |||
178 | MODULE_DEVICE_TABLE(serio, dynapro_serio_ids); | ||
179 | |||
180 | static 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 | |||
195 | static int __init dynapro_init(void) | ||
196 | { | ||
197 | return serio_register_driver(&dynapro_drv); | ||
198 | } | ||
199 | |||
200 | static void __exit dynapro_exit(void) | ||
201 | { | ||
202 | serio_unregister_driver(&dynapro_drv); | ||
203 | } | ||
204 | |||
205 | module_init(dynapro_init); | ||
206 | module_exit(dynapro_exit); | ||