aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/touchscreen
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/Kconfig98
-rw-r--r--drivers/input/touchscreen/Makefile13
-rw-r--r--drivers/input/touchscreen/corgi_ts.c380
-rw-r--r--drivers/input/touchscreen/elo.c315
-rw-r--r--drivers/input/touchscreen/gunze.c205
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c528
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c135
-rw-r--r--drivers/input/touchscreen/mk712.c222
-rw-r--r--drivers/input/touchscreen/mtouch.c219
9 files changed, 2115 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
new file mode 100644
index 000000000000..7e991274ea40
--- /dev/null
+++ b/drivers/input/touchscreen/Kconfig
@@ -0,0 +1,98 @@
1#
2# Mouse driver configuration
3#
4menuconfig INPUT_TOUCHSCREEN
5 bool "Touchscreens"
6 help
7 Say Y here, and a list of supported touchscreens will be displayed.
8 This option doesn't affect the kernel.
9
10 If unsure, say Y.
11
12if INPUT_TOUCHSCREEN
13
14config TOUCHSCREEN_BITSY
15 tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
16 depends on SA1100_BITSY
17 select SERIO
18 help
19 Say Y here if you have the h3600 (Bitsy) touchscreen.
20
21 If unsure, say N.
22
23 To compile this driver as a module, choose M here: the
24 module will be called h3600_ts_input.
25
26config TOUCHSCREEN_CORGI
27 tristate "Corgi touchscreen (for Sharp SL-C7xx)"
28 depends on PXA_SHARPSL
29 default y
30 help
31 Say Y here to enable the driver for the touchscreen on the
32 Sharp SL-C7xx series of PDAs.
33
34 If unsure, say N.
35
36 To compile this driver as a module, choose M here: the
37 module will be called ads7846_ts.
38
39config TOUCHSCREEN_GUNZE
40 tristate "Gunze AHL-51S touchscreen"
41 select SERIO
42 help
43 Say Y here if you have the Gunze AHL-51 touchscreen connected to
44 your system.
45
46 If unsure, say N.
47
48 To compile this driver as a module, choose M here: the
49 module will be called gunze.
50
51config TOUCHSCREEN_ELO
52 tristate "Elo serial touchscreens"
53 select SERIO
54 help
55 Say Y here if you have an Elo serial touchscreen connected to
56 your system.
57
58 If unsure, say N.
59
60 To compile this driver as a module, choose M here: the
61 module will be called gunze.
62
63config TOUCHSCREEN_MTOUCH
64 tristate "MicroTouch serial touchscreens"
65 select SERIO
66 help
67 Say Y here if you have a MicroTouch (3M) serial touchscreen connected to
68 your system.
69
70 If unsure, say N.
71
72 To compile this driver as a module, choose M here: the
73 module will be called mtouch.
74
75config TOUCHSCREEN_MK712
76 tristate "ICS MicroClock MK712 touchscreen"
77 help
78 Say Y here if you have the ICS MicroClock MK712 touchscreen
79 controller chip in your system.
80
81 If unsure, say N.
82
83 To compile this driver as a module, choose M here: the
84 module will be called mk712.
85
86config TOUCHSCREEN_HP600
87 tristate "HP Jornada 680/690 touchscreen"
88 depends on SH_HP600 && SH_ADC
89 help
90 Say Y here if you have a HP Jornada 680 or 690 and want to
91 support the built-in touchscreen.
92
93 If unsure, say N.
94
95 To compile this driver as a module, choose M here: the
96 module will be called hp680_ts_input.
97
98endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
new file mode 100644
index 000000000000..6842869c9a26
--- /dev/null
+++ b/drivers/input/touchscreen/Makefile
@@ -0,0 +1,13 @@
1#
2# Makefile for the mouse drivers.
3#
4
5# Each configuration option enables a list of files.
6
7obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
8obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
9obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
10obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
11obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
12obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
13obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
new file mode 100644
index 000000000000..3f8b61cfbc37
--- /dev/null
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -0,0 +1,380 @@
1/*
2 * Touchscreen driver for Sharp Corgi models (SL-C7xx)
3 *
4 * Copyright (c) 2004-2005 Richard Purdie
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12
13#include <linux/delay.h>
14#include <linux/device.h>
15#include <linux/init.h>
16#include <linux/input.h>
17#include <linux/interrupt.h>
18#include <linux/module.h>
19#include <linux/slab.h>
20#include <asm/irq.h>
21
22#include <asm/arch/corgi.h>
23#include <asm/arch/hardware.h>
24#include <asm/arch/pxa-regs.h>
25
26
27#define PWR_MODE_ACTIVE 0
28#define PWR_MODE_SUSPEND 1
29
30#define X_AXIS_MAX 3830
31#define X_AXIS_MIN 150
32#define Y_AXIS_MAX 3830
33#define Y_AXIS_MIN 190
34#define PRESSURE_MIN 0
35#define PRESSURE_MAX 15000
36
37struct ts_event {
38 short pressure;
39 short x;
40 short y;
41};
42
43struct corgi_ts {
44 char phys[32];
45 struct input_dev input;
46 struct timer_list timer;
47 struct ts_event tc;
48 int pendown;
49 int power_mode;
50};
51
52#define STATUS_HSYNC (GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC))
53
54#define SyncHS() while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
55#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
56#define CCNT_ON() {int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
57#define CCNT_OFF() {int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
58
59#define WAIT_HS_400_VGA 7013U // 17.615us
60#define WAIT_HS_400_QVGA 16622U // 41.750us
61
62
63/* ADS7846 Touch Screen Controller bit definitions */
64#define ADSCTRL_PD0 (1u << 0) /* PD0 */
65#define ADSCTRL_PD1 (1u << 1) /* PD1 */
66#define ADSCTRL_DFR (1u << 2) /* SER/DFR */
67#define ADSCTRL_MOD (1u << 3) /* Mode */
68#define ADSCTRL_ADR_SH 4 /* Address setting */
69#define ADSCTRL_STS (1u << 7) /* Start Bit */
70
71/* External Functions */
72extern int w100fb_get_xres(void);
73extern int w100fb_get_blanking(void);
74extern int w100fb_get_fastsysclk(void);
75extern unsigned int get_clk_frequency_khz(int info);
76
77static unsigned long calc_waittime(void)
78{
79 int w100fb_xres = w100fb_get_xres();
80 unsigned int waittime = 0;
81
82 if (w100fb_xres == 480 || w100fb_xres == 640) {
83 waittime = WAIT_HS_400_VGA * get_clk_frequency_khz(0) / 398131U;
84
85 if (w100fb_get_fastsysclk() == 100)
86 waittime = waittime * 75 / 100;
87
88 if (w100fb_xres == 640)
89 waittime *= 3;
90
91 return waittime;
92 }
93
94 return WAIT_HS_400_QVGA * get_clk_frequency_khz(0) / 398131U;
95}
96
97static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
98{
99 int pos = 0;
100 unsigned long timer1 = 0, timer2;
101 int dosleep;
102
103 dosleep = !w100fb_get_blanking();
104
105 if (dosleep && doSend) {
106 CCNT_ON();
107 /* polling HSync */
108 SyncHS();
109 /* get CCNT */
110 CCNT(timer1);
111 }
112
113 if (doRecive)
114 pos = corgi_ssp_ads7846_get();
115
116 if (doSend) {
117 int cmd = ADSCTRL_PD0 | ADSCTRL_PD1 | (address << ADSCTRL_ADR_SH) | ADSCTRL_STS;
118 /* dummy command */
119 corgi_ssp_ads7846_put(cmd);
120 corgi_ssp_ads7846_get();
121
122 if (dosleep) {
123 /* Wait after HSync */
124 CCNT(timer2);
125 if (timer2-timer1 > wait_time) {
126 /* timeout */
127 SyncHS();
128 /* get OSCR */
129 CCNT(timer1);
130 /* Wait after HSync */
131 CCNT(timer2);
132 }
133 while (timer2 - timer1 < wait_time)
134 CCNT(timer2);
135 }
136 corgi_ssp_ads7846_put(cmd);
137 if (dosleep)
138 CCNT_OFF();
139 }
140 return pos;
141}
142
143static int read_xydata(struct corgi_ts *corgi_ts)
144{
145 unsigned int x, y, z1, z2;
146 unsigned long flags, wait_time;
147
148 /* critical section */
149 local_irq_save(flags);
150 corgi_ssp_ads7846_lock();
151 wait_time=calc_waittime();
152
153 /* Y-axis */
154 sync_receive_data_send_cmd(0, 1, 1u, wait_time);
155
156 /* Y-axis */
157 sync_receive_data_send_cmd(1, 1, 1u, wait_time);
158
159 /* X-axis */
160 y = sync_receive_data_send_cmd(1, 1, 5u, wait_time);
161
162 /* Z1 */
163 x = sync_receive_data_send_cmd(1, 1, 3u, wait_time);
164
165 /* Z2 */
166 z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time);
167 z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time);
168
169 /* Power-Down Enable */
170 corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
171 corgi_ssp_ads7846_get();
172
173 corgi_ssp_ads7846_unlock();
174 local_irq_restore(flags);
175
176 if (x== 0 || y == 0 || z1 == 0 || (x * (z2 - z1) / z1) >= 15000) {
177 corgi_ts->tc.pressure = 0;
178 return 0;
179 }
180
181 corgi_ts->tc.x = x;
182 corgi_ts->tc.y = y;
183 corgi_ts->tc.pressure = (x * (z2 - z1)) / z1;
184 return 1;
185}
186
187static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
188{
189 if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
190 return;
191
192 if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
193 return;
194
195 if (regs)
196 input_regs(&corgi_ts->input, regs);
197
198 input_report_abs(&corgi_ts->input, ABS_X, corgi_ts->tc.x);
199 input_report_abs(&corgi_ts->input, ABS_Y, corgi_ts->tc.y);
200 input_report_abs(&corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure);
201 input_report_key(&corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0));
202 input_sync(&corgi_ts->input);
203}
204
205static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
206{
207 if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) {
208 /* Disable Interrupt */
209 set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE);
210 if (read_xydata(corgi_ts)) {
211 corgi_ts->pendown = 1;
212 new_data(corgi_ts, regs);
213 }
214 mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
215 } else {
216 if (corgi_ts->pendown == 1 || corgi_ts->pendown == 2) {
217 mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
218 corgi_ts->pendown++;
219 return;
220 }
221
222 if (corgi_ts->pendown) {
223 corgi_ts->tc.pressure = 0;
224 new_data(corgi_ts, regs);
225 }
226
227 /* Enable Falling Edge */
228 set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
229 corgi_ts->pendown = 0;
230 }
231}
232
233static void corgi_ts_timer(unsigned long data)
234{
235 struct corgi_ts *corgits_data = (struct corgi_ts *) data;
236 ts_interrupt_main(corgits_data, 1, NULL);
237}
238
239static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
240{
241 struct corgi_ts *corgits_data = dev_id;
242 ts_interrupt_main(corgits_data, 0, regs);
243 return IRQ_HANDLED;
244}
245
246#ifdef CONFIG_PM
247static int corgits_suspend(struct device *dev, uint32_t state, uint32_t level)
248{
249 if (level == SUSPEND_POWER_DOWN) {
250 struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
251
252 if (corgi_ts->pendown) {
253 del_timer_sync(&corgi_ts->timer);
254 corgi_ts->tc.pressure = 0;
255 new_data(corgi_ts, NULL);
256 corgi_ts->pendown = 0;
257 }
258 corgi_ts->power_mode = PWR_MODE_SUSPEND;
259
260 corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
261 }
262 return 0;
263}
264
265static int corgits_resume(struct device *dev, uint32_t level)
266{
267 if (level == RESUME_POWER_ON) {
268 struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
269
270 corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
271 /* Enable Falling Edge */
272 set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
273 corgi_ts->power_mode = PWR_MODE_ACTIVE;
274 }
275 return 0;
276}
277#else
278#define corgits_suspend NULL
279#define corgits_resume NULL
280#endif
281
282static int __init corgits_probe(struct device *dev)
283{
284 struct corgi_ts *corgi_ts;
285
286 if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL)))
287 return -ENOMEM;
288
289 dev_set_drvdata(dev, corgi_ts);
290
291 memset(corgi_ts, 0, sizeof(struct corgi_ts));
292
293 init_input_dev(&corgi_ts->input);
294 corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
295 corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
296 input_set_abs_params(&corgi_ts->input, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
297 input_set_abs_params(&corgi_ts->input, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
298 input_set_abs_params(&corgi_ts->input, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
299
300 strcpy(corgi_ts->phys, "corgits/input0");
301
302 corgi_ts->input.private = corgi_ts;
303 corgi_ts->input.name = "Corgi Touchscreen";
304 corgi_ts->input.dev = dev;
305 corgi_ts->input.phys = corgi_ts->phys;
306 corgi_ts->input.id.bustype = BUS_HOST;
307 corgi_ts->input.id.vendor = 0x0001;
308 corgi_ts->input.id.product = 0x0002;
309 corgi_ts->input.id.version = 0x0100;
310
311 pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN);
312 pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
313
314 /* Initiaize ADS7846 Difference Reference mode */
315 corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
316 mdelay(5);
317 corgi_ssp_ads7846_putget((3u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
318 mdelay(5);
319 corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
320 mdelay(5);
321 corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
322 mdelay(5);
323
324 init_timer(&corgi_ts->timer);
325 corgi_ts->timer.data = (unsigned long) corgi_ts;
326 corgi_ts->timer.function = corgi_ts_timer;
327
328 input_register_device(&corgi_ts->input);
329 corgi_ts->power_mode = PWR_MODE_ACTIVE;
330
331 if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
332 input_unregister_device(&corgi_ts->input);
333 kfree(corgi_ts);
334 return -EBUSY;
335 }
336
337 /* Enable Falling Edge */
338 set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
339
340 printk(KERN_INFO "input: Corgi Touchscreen Registered\n");
341
342 return 0;
343}
344
345static int corgits_remove(struct device *dev)
346{
347 struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
348
349 free_irq(CORGI_IRQ_GPIO_TP_INT, NULL);
350 del_timer_sync(&corgi_ts->timer);
351 input_unregister_device(&corgi_ts->input);
352 kfree(corgi_ts);
353 return 0;
354}
355
356static struct device_driver corgits_driver = {
357 .name = "corgi-ts",
358 .bus = &platform_bus_type,
359 .probe = corgits_probe,
360 .remove = corgits_remove,
361 .suspend = corgits_suspend,
362 .resume = corgits_resume,
363};
364
365static int __devinit corgits_init(void)
366{
367 return driver_register(&corgits_driver);
368}
369
370static void __exit corgits_exit(void)
371{
372 driver_unregister(&corgits_driver);
373}
374
375module_init(corgits_init);
376module_exit(corgits_exit);
377
378MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
379MODULE_DESCRIPTION("Corgi TouchScreen Driver");
380MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
new file mode 100644
index 000000000000..546ce599334e
--- /dev/null
+++ b/drivers/input/touchscreen/elo.c
@@ -0,0 +1,315 @@
1/*
2 * Elo serial touchscreen driver
3 *
4 * Copyright (c) 2004 Vojtech Pavlik
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 */
12
13/*
14 * This driver can handle serial Elo touchscreens using either the Elo standard
15 * 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo
16 * legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol.
17 */
18
19#include <linux/errno.h>
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/input.h>
24#include <linux/serio.h>
25#include <linux/init.h>
26
27#define DRIVER_DESC "Elo serial touchscreen driver"
28
29MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
30MODULE_DESCRIPTION(DRIVER_DESC);
31MODULE_LICENSE("GPL");
32
33/*
34 * Definitions & global arrays.
35 */
36
37#define ELO_MAX_LENGTH 10
38
39static char *elo_name = "Elo Serial TouchScreen";
40
41/*
42 * Per-touchscreen data.
43 */
44
45struct elo {
46 struct input_dev dev;
47 struct serio *serio;
48 int id;
49 int idx;
50 unsigned char csum;
51 unsigned char data[ELO_MAX_LENGTH];
52 char phys[32];
53};
54
55static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs)
56{
57 struct input_dev *dev = &elo->dev;
58
59 elo->csum += elo->data[elo->idx] = data;
60
61 switch (elo->idx++) {
62
63 case 0:
64 if (data != 'U') {
65 elo->idx = 0;
66 elo->csum = 0;
67 }
68 break;
69
70 case 1:
71 if (data != 'T') {
72 elo->idx = 0;
73 elo->csum = 0;
74 }
75 break;
76
77 case 9:
78 if (elo->csum) {
79 input_regs(dev, regs);
80 input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
81 input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
82 input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]);
83 input_report_key(dev, BTN_TOUCH, elo->data[2] & 3);
84 input_sync(dev);
85 }
86 elo->idx = 0;
87 elo->csum = 0;
88 break;
89 }
90}
91
92static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs)
93{
94 struct input_dev *dev = &elo->dev;
95
96 elo->data[elo->idx] = data;
97
98 switch (elo->idx++) {
99
100 case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break;
101 case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break;
102 case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break;
103
104 case 3:
105 if (data & 0xc0) {
106 elo->idx = 0;
107 break;
108 }
109
110 input_regs(dev, regs);
111 input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
112 input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
113
114 if (elo->id == 2) {
115 input_report_key(dev, BTN_TOUCH, 1);
116 input_sync(dev);
117 elo->idx = 0;
118 }
119
120 break;
121
122 case 4:
123 if (data) {
124 input_sync(dev);
125 elo->idx = 0;
126 }
127 break;
128
129 case 5:
130 if ((data & 0xf0) == 0) {
131 input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
132 input_report_key(dev, BTN_TOUCH, elo->data[5]);
133 }
134 input_sync(dev);
135 elo->idx = 0;
136 break;
137 }
138}
139
140static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs)
141{
142 struct input_dev *dev = &elo->dev;
143
144 elo->data[elo->idx] = data;
145
146 switch (elo->idx++) {
147
148 case 0:
149 if ((data & 0x7f) != 0x01)
150 elo->idx = 0;
151 break;
152 case 2:
153 input_regs(dev, regs);
154 input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
155 input_report_abs(dev, ABS_X, elo->data[1]);
156 input_report_abs(dev, ABS_Y, elo->data[2]);
157 input_sync(dev);
158 elo->idx = 0;
159 break;
160 }
161}
162
163static irqreturn_t elo_interrupt(struct serio *serio,
164 unsigned char data, unsigned int flags, struct pt_regs *regs)
165{
166 struct elo* elo = serio_get_drvdata(serio);
167
168 switch(elo->id) {
169 case 0:
170 elo_process_data_10(elo, data, regs);
171 break;
172
173 case 1:
174 case 2:
175 elo_process_data_6(elo, data, regs);
176 break;
177
178 case 3:
179 elo_process_data_3(elo, data, regs);
180 break;
181 }
182
183 return IRQ_HANDLED;
184}
185
186/*
187 * elo_disconnect() is the opposite of elo_connect()
188 */
189
190static void elo_disconnect(struct serio *serio)
191{
192 struct elo* elo = serio_get_drvdata(serio);
193
194 input_unregister_device(&elo->dev);
195 serio_close(serio);
196 serio_set_drvdata(serio, NULL);
197 kfree(elo);
198}
199
200/*
201 * elo_connect() is the routine that is called when someone adds a
202 * new serio device that supports Gunze protocol and registers it as
203 * an input device.
204 */
205
206static int elo_connect(struct serio *serio, struct serio_driver *drv)
207{
208 struct elo *elo;
209 int err;
210
211 if (!(elo = kmalloc(sizeof(struct elo), GFP_KERNEL)))
212 return -ENOMEM;
213
214 memset(elo, 0, sizeof(struct elo));
215
216 init_input_dev(&elo->dev);
217 elo->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
218 elo->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
219
220 elo->id = serio->id.id;
221
222 switch (elo->id) {
223
224 case 0: /* 10-byte protocol */
225 input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0);
226 input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
227 input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
228 break;
229
230 case 1: /* 6-byte protocol */
231 input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
232
233 case 2: /* 4-byte protocol */
234 input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0);
235 input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
236 break;
237
238 case 3: /* 3-byte protocol */
239 input_set_abs_params(&elo->dev, ABS_X, 0, 255, 0, 0);
240 input_set_abs_params(&elo->dev, ABS_Y, 0, 255, 0, 0);
241 break;
242 }
243
244 elo->serio = serio;
245
246 sprintf(elo->phys, "%s/input0", serio->phys);
247
248 elo->dev.private = elo;
249 elo->dev.name = elo_name;
250 elo->dev.phys = elo->phys;
251 elo->dev.id.bustype = BUS_RS232;
252 elo->dev.id.vendor = SERIO_ELO;
253 elo->dev.id.product = elo->id;
254 elo->dev.id.version = 0x0100;
255
256 serio_set_drvdata(serio, elo);
257
258 err = serio_open(serio, drv);
259 if (err) {
260 serio_set_drvdata(serio, NULL);
261 kfree(elo);
262 return err;
263 }
264
265 input_register_device(&elo->dev);
266
267 printk(KERN_INFO "input: %s on %s\n", elo_name, serio->phys);
268
269 return 0;
270}
271
272/*
273 * The serio driver structure.
274 */
275
276static struct serio_device_id elo_serio_ids[] = {
277 {
278 .type = SERIO_RS232,
279 .proto = SERIO_ELO,
280 .id = SERIO_ANY,
281 .extra = SERIO_ANY,
282 },
283 { 0 }
284};
285
286MODULE_DEVICE_TABLE(serio, elo_serio_ids);
287
288static struct serio_driver elo_drv = {
289 .driver = {
290 .name = "elo",
291 },
292 .description = DRIVER_DESC,
293 .id_table = elo_serio_ids,
294 .interrupt = elo_interrupt,
295 .connect = elo_connect,
296 .disconnect = elo_disconnect,
297};
298
299/*
300 * The functions for inserting/removing us as a module.
301 */
302
303static int __init elo_init(void)
304{
305 serio_register_driver(&elo_drv);
306 return 0;
307}
308
309static void __exit elo_exit(void)
310{
311 serio_unregister_driver(&elo_drv);
312}
313
314module_init(elo_init);
315module_exit(elo_exit);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
new file mode 100644
index 000000000000..c9d0a153671c
--- /dev/null
+++ b/drivers/input/touchscreen/gunze.c
@@ -0,0 +1,205 @@
1/*
2 * $Id: gunze.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
3 *
4 * Copyright (c) 2000-2001 Vojtech Pavlik
5 */
6
7/*
8 * Gunze AHL-51S touchscreen driver for Linux
9 */
10
11/*
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * Should you need to contact me, the author, you can do so either by
27 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
28 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
29 */
30
31#include <linux/errno.h>
32#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/slab.h>
35#include <linux/input.h>
36#include <linux/serio.h>
37#include <linux/init.h>
38
39#define DRIVER_DESC "Gunze AHL-51S touchscreen driver"
40
41MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
42MODULE_DESCRIPTION(DRIVER_DESC);
43MODULE_LICENSE("GPL");
44
45/*
46 * Definitions & global arrays.
47 */
48
49#define GUNZE_MAX_LENGTH 10
50
51static char *gunze_name = "Gunze AHL-51S TouchScreen";
52
53/*
54 * Per-touchscreen data.
55 */
56
57struct gunze {
58 struct input_dev dev;
59 struct serio *serio;
60 int idx;
61 unsigned char data[GUNZE_MAX_LENGTH];
62 char phys[32];
63};
64
65static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs)
66{
67 struct input_dev *dev = &gunze->dev;
68
69 if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
70 (gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
71 gunze->data[10] = 0;
72 printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data);
73 return;
74 }
75
76 input_regs(dev, regs);
77 input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
78 input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
79 input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
80 input_sync(dev);
81}
82
83static irqreturn_t gunze_interrupt(struct serio *serio,
84 unsigned char data, unsigned int flags, struct pt_regs *regs)
85{
86 struct gunze* gunze = serio_get_drvdata(serio);
87
88 if (data == '\r') {
89 gunze_process_packet(gunze, regs);
90 gunze->idx = 0;
91 } else {
92 if (gunze->idx < GUNZE_MAX_LENGTH)
93 gunze->data[gunze->idx++] = data;
94 }
95 return IRQ_HANDLED;
96}
97
98/*
99 * gunze_disconnect() is the opposite of gunze_connect()
100 */
101
102static void gunze_disconnect(struct serio *serio)
103{
104 struct gunze* gunze = serio_get_drvdata(serio);
105
106 input_unregister_device(&gunze->dev);
107 serio_close(serio);
108 serio_set_drvdata(serio, NULL);
109 kfree(gunze);
110}
111
112/*
113 * gunze_connect() is the routine that is called when someone adds a
114 * new serio device that supports Gunze protocol and registers it as
115 * an input device.
116 */
117
118static int gunze_connect(struct serio *serio, struct serio_driver *drv)
119{
120 struct gunze *gunze;
121 int err;
122
123 if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL)))
124 return -ENOMEM;
125
126 memset(gunze, 0, sizeof(struct gunze));
127
128 init_input_dev(&gunze->dev);
129 gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
130 gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
131 input_set_abs_params(&gunze->dev, ABS_X, 24, 1000, 0, 0);
132 input_set_abs_params(&gunze->dev, ABS_Y, 24, 1000, 0, 0);
133
134 gunze->serio = serio;
135
136 sprintf(gunze->phys, "%s/input0", serio->phys);
137
138 gunze->dev.private = gunze;
139 gunze->dev.name = gunze_name;
140 gunze->dev.phys = gunze->phys;
141 gunze->dev.id.bustype = BUS_RS232;
142 gunze->dev.id.vendor = SERIO_GUNZE;
143 gunze->dev.id.product = 0x0051;
144 gunze->dev.id.version = 0x0100;
145
146 serio_set_drvdata(serio, gunze);
147
148 err = serio_open(serio, drv);
149 if (err) {
150 serio_set_drvdata(serio, NULL);
151 kfree(gunze);
152 return err;
153 }
154
155 input_register_device(&gunze->dev);
156
157 printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys);
158
159 return 0;
160}
161
162/*
163 * The serio driver structure.
164 */
165
166static struct serio_device_id gunze_serio_ids[] = {
167 {
168 .type = SERIO_RS232,
169 .proto = SERIO_GUNZE,
170 .id = SERIO_ANY,
171 .extra = SERIO_ANY,
172 },
173 { 0 }
174};
175
176MODULE_DEVICE_TABLE(serio, gunze_serio_ids);
177
178static struct serio_driver gunze_drv = {
179 .driver = {
180 .name = "gunze",
181 },
182 .description = DRIVER_DESC,
183 .id_table = gunze_serio_ids,
184 .interrupt = gunze_interrupt,
185 .connect = gunze_connect,
186 .disconnect = gunze_disconnect,
187};
188
189/*
190 * The functions for inserting/removing us as a module.
191 */
192
193static int __init gunze_init(void)
194{
195 serio_register_driver(&gunze_drv);
196 return 0;
197}
198
199static void __exit gunze_exit(void)
200{
201 serio_unregister_driver(&gunze_drv);
202}
203
204module_init(gunze_init);
205module_exit(gunze_exit);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
new file mode 100644
index 000000000000..acb9137a0226
--- /dev/null
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -0,0 +1,528 @@
1/*
2 * $Id: h3600_ts_input.c,v 1.4 2002/01/23 06:39:37 jsimmons Exp $
3 *
4 * Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com
5 *
6 * Sponsored by Transvirtual Technology.
7 *
8 * Derived from the code in h3600_ts.[ch] by Charles Flynn
9 */
10
11/*
12 * Driver for the h3600 Touch Screen and other Atmel controlled devices.
13 */
14
15/*
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 * Should you need to contact me, the author, you can do so by
31 * e-mail - mail your message to <jsimmons@transvirtual.com>.
32 */
33
34#include <linux/errno.h>
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/slab.h>
38#include <linux/input.h>
39#include <linux/serio.h>
40#include <linux/init.h>
41#include <linux/delay.h>
42#include <linux/pm.h>
43
44/* SA1100 serial defines */
45#include <asm/arch/hardware.h>
46#include <asm/arch/irqs.h>
47
48#define DRIVER_DESC "H3600 touchscreen driver"
49
50MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
51MODULE_DESCRIPTION(DRIVER_DESC);
52MODULE_LICENSE("GPL");
53
54/*
55 * Definitions & global arrays.
56 */
57
58/* The start and end of frame characters SOF and EOF */
59#define CHAR_SOF 0x02
60#define CHAR_EOF 0x03
61#define FRAME_OVERHEAD 3 /* CHAR_SOF,CHAR_EOF,LENGTH = 3 */
62
63/*
64 Atmel events and response IDs contained in frame.
65 Programmer has no control over these numbers.
66 TODO there are holes - specifically 1,7,0x0a
67*/
68#define VERSION_ID 0 /* Get Version (request/respose) */
69#define KEYBD_ID 2 /* Keyboard (event) */
70#define TOUCHS_ID 3 /* Touch Screen (event)*/
71#define EEPROM_READ_ID 4 /* (request/response) */
72#define EEPROM_WRITE_ID 5 /* (request/response) */
73#define THERMAL_ID 6 /* (request/response) */
74#define NOTIFY_LED_ID 8 /* (request/response) */
75#define BATTERY_ID 9 /* (request/response) */
76#define SPI_READ_ID 0x0b /* ( request/response) */
77#define SPI_WRITE_ID 0x0c /* ( request/response) */
78#define FLITE_ID 0x0d /* backlight ( request/response) */
79#define STX_ID 0xa1 /* extension pack status (req/resp) */
80
81#define MAX_ID 14
82
83#define H3600_MAX_LENGTH 16
84#define H3600_KEY 0xf
85
86#define H3600_SCANCODE_RECORD 1 /* 1 -> record button */
87#define H3600_SCANCODE_CALENDAR 2 /* 2 -> calendar */
88#define H3600_SCANCODE_CONTACTS 3 /* 3 -> contact */
89#define H3600_SCANCODE_Q 4 /* 4 -> Q button */
90#define H3600_SCANCODE_START 5 /* 5 -> start menu */
91#define H3600_SCANCODE_UP 6 /* 6 -> up */
92#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
93#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
94#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
95
96static char *h3600_name = "H3600 TouchScreen";
97
98/*
99 * Per-touchscreen data.
100 */
101struct h3600_dev {
102 struct input_dev dev;
103 struct pm_dev *pm_dev;
104 struct serio *serio;
105 struct pm_dev *pm_dev;
106 unsigned char event; /* event ID from packet */
107 unsigned char chksum;
108 unsigned char len;
109 unsigned char idx;
110 unsigned char buf[H3600_MAX_LENGTH];
111 char phys[32];
112};
113
114static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
115{
116 int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
117 struct input_dev *dev = (struct input_dev *) dev_id;
118
119 input_regs(dev, regs);
120 input_report_key(dev, KEY_ENTER, down);
121 input_sync(dev);
122
123 return IRQ_HANDLED;
124}
125
126static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
127{
128 int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
129 struct input_dev *dev = (struct input_dev *) dev_id;
130
131 /*
132 * This interrupt is only called when we release the key. So we have
133 * to fake a key press.
134 */
135 input_regs(dev, regs);
136 input_report_key(dev, KEY_SUSPEND, 1);
137 input_report_key(dev, KEY_SUSPEND, down);
138 input_sync(dev);
139
140 return IRQ_HANDLED;
141}
142
143#ifdef CONFIG_PM
144
145static int flite_brightness = 25;
146
147enum flite_pwr {
148 FLITE_PWR_OFF = 0,
149 FLITE_PWR_ON = 1
150};
151
152/*
153 * h3600_flite_power: enables or disables power to frontlight, using last bright */
154unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
155{
156 unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
157 struct h3600_dev *ts = dev->private;
158
159 /* Must be in this order */
160 ts->serio->write(ts->serio, 1);
161 ts->serio->write(ts->serio, pwr);
162 ts->serio->write(ts->serio, brightness);
163 return 0;
164}
165
166static int suspended = 0;
167static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
168 void *data)
169{
170 struct input_dev *dev = (struct input_dev *) data;
171
172 switch (req) {
173 case PM_SUSPEND: /* enter D1-D3 */
174 suspended = 1;
175 h3600_flite_power(dev, FLITE_PWR_OFF);
176 break;
177 case PM_BLANK:
178 if (!suspended)
179 h3600_flite_power(dev, FLITE_PWR_OFF);
180 break;
181 case PM_RESUME: /* enter D0 */
182 /* same as unblank */
183 case PM_UNBLANK:
184 if (suspended) {
185 //initSerial();
186 suspended = 0;
187 }
188 h3600_flite_power(dev, FLITE_PWR_ON);
189 break;
190 }
191 return 0;
192}
193#endif
194
195/*
196 * This function translates the native event packets to linux input event
197 * packets. Some packets coming from serial are not touchscreen related. In
198 * this case we send them off to be processed elsewhere.
199 */
200static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
201{
202 struct input_dev *dev = &ts->dev;
203 static int touched = 0;
204 int key, down = 0;
205
206 input_regs(dev, regs);
207
208 switch (ts->event) {
209 /*
210 Buttons - returned as a single byte
211 7 6 5 4 3 2 1 0
212 S x x x N N N N
213
214 S switch state ( 0=pressed 1=released)
215 x Unused.
216 NNNN switch number 0-15
217
218 Note: This is true for non interrupt generated key events.
219 */
220 case KEYBD_ID:
221 down = (ts->buf[0] & 0x80) ? 0 : 1;
222
223 switch (ts->buf[0] & 0x7f) {
224 case H3600_SCANCODE_RECORD:
225 key = KEY_RECORD;
226 break;
227 case H3600_SCANCODE_CALENDAR:
228 key = KEY_PROG1;
229 break;
230 case H3600_SCANCODE_CONTACTS:
231 key = KEY_PROG2;
232 break;
233 case H3600_SCANCODE_Q:
234 key = KEY_Q;
235 break;
236 case H3600_SCANCODE_START:
237 key = KEY_PROG3;
238 break;
239 case H3600_SCANCODE_UP:
240 key = KEY_UP;
241 break;
242 case H3600_SCANCODE_RIGHT:
243 key = KEY_RIGHT;
244 break;
245 case H3600_SCANCODE_LEFT:
246 key = KEY_LEFT;
247 break;
248 case H3600_SCANCODE_DOWN:
249 key = KEY_DOWN;
250 break;
251 default:
252 key = 0;
253 }
254 if (key)
255 input_report_key(dev, key, down);
256 break;
257 /*
258 * Native touchscreen event data is formatted as shown below:-
259 *
260 * +-------+-------+-------+-------+
261 * | Xmsb | Xlsb | Ymsb | Ylsb |
262 * +-------+-------+-------+-------+
263 * byte 0 1 2 3
264 */
265 case TOUCHS_ID:
266 if (!touched) {
267 input_report_key(dev, BTN_TOUCH, 1);
268 touched = 1;
269 }
270
271 if (ts->len) {
272 unsigned short x, y;
273
274 x = ts->buf[0]; x <<= 8; x += ts->buf[1];
275 y = ts->buf[2]; y <<= 8; y += ts->buf[3];
276
277 input_report_abs(dev, ABS_X, x);
278 input_report_abs(dev, ABS_Y, y);
279 } else {
280 input_report_key(dev, BTN_TOUCH, 0);
281 touched = 0;
282 }
283 break;
284 default:
285 /* Send a non input event elsewhere */
286 break;
287 }
288
289 input_sync(dev);
290}
291
292/*
293 * h3600ts_event() handles events from the input module.
294 */
295static int h3600ts_event(struct input_dev *dev, unsigned int type,
296 unsigned int code, int value)
297{
298 struct h3600_dev *ts = dev->private;
299
300 switch (type) {
301 case EV_LED: {
302 // ts->serio->write(ts->serio, SOME_CMD);
303 return 0;
304 }
305 }
306 return -1;
307}
308
309/*
310 Frame format
311 byte 1 2 3 len + 4
312 +-------+---------------+---------------+--=------------+
313 |SOF |id |len | len bytes | Chksum |
314 +-------+---------------+---------------+--=------------+
315 bit 0 7 8 11 12 15 16
316
317 +-------+---------------+-------+
318 |SOF |id |0 |Chksum | - Note Chksum does not include SOF
319 +-------+---------------+-------+
320 bit 0 7 8 11 12 15 16
321
322*/
323
324static int state;
325
326/* decode States */
327#define STATE_SOF 0 /* start of FRAME */
328#define STATE_ID 1 /* state where we decode the ID & len */
329#define STATE_DATA 2 /* state where we decode data */
330#define STATE_EOF 3 /* state where we decode checksum or EOF */
331
332static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
333 unsigned int flags, struct pt_regs *regs)
334{
335 struct h3600_dev *ts = serio_get_drvdata(serio);
336
337 /*
338 * We have a new frame coming in.
339 */
340 switch (state) {
341 case STATE_SOF:
342 if (data == CHAR_SOF)
343 state = STATE_ID;
344 break;
345 case STATE_ID:
346 ts->event = (data & 0xf0) >> 4;
347 ts->len = (data & 0xf);
348 ts->idx = 0;
349 if (ts->event >= MAX_ID) {
350 state = STATE_SOF;
351 break;
352 }
353 ts->chksum = data;
354 state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
355 break;
356 case STATE_DATA:
357 ts->chksum += data;
358 ts->buf[ts->idx]= data;
359 if(++ts->idx == ts->len)
360 state = STATE_EOF;
361 break;
362 case STATE_EOF:
363 state = STATE_SOF;
364 if (data == CHAR_EOF || data == ts->chksum)
365 h3600ts_process_packet(ts, regs);
366 break;
367 default:
368 printk("Error3\n");
369 break;
370 }
371
372 return IRQ_HANDLED;
373}
374
375/*
376 * h3600ts_connect() is the routine that is called when someone adds a
377 * new serio device that supports H3600 protocol and registers it as
378 * an input device.
379 */
380static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
381{
382 struct h3600_dev *ts;
383 int err;
384
385 if (!(ts = kmalloc(sizeof(struct h3600_dev), GFP_KERNEL)))
386 return -ENOMEM;
387
388 memset(ts, 0, sizeof(struct h3600_dev));
389
390 init_input_dev(&ts->dev);
391
392 /* Device specific stuff */
393 set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
394 set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
395
396 if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
397 SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
398 "h3600_action", &ts->dev)) {
399 printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
400 kfree(ts);
401 return -EBUSY;
402 }
403
404 if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
405 SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
406 "h3600_suspend", &ts->dev)) {
407 free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
408 printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
409 kfree(ts);
410 return -EBUSY;
411 }
412
413 /* Now we have things going we setup our input device */
414 ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
415 ts->dev.ledbit[0] = BIT(LED_SLEEP);
416 input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0);
417 input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0);
418
419 set_bit(KEY_RECORD, ts->dev.keybit);
420 set_bit(KEY_Q, ts->dev.keybit);
421 set_bit(KEY_PROG1, ts->dev.keybit);
422 set_bit(KEY_PROG2, ts->dev.keybit);
423 set_bit(KEY_PROG3, ts->dev.keybit);
424 set_bit(KEY_UP, ts->dev.keybit);
425 set_bit(KEY_RIGHT, ts->dev.keybit);
426 set_bit(KEY_LEFT, ts->dev.keybit);
427 set_bit(KEY_DOWN, ts->dev.keybit);
428 set_bit(KEY_ENTER, ts->dev.keybit);
429 ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
430 ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
431
432 ts->serio = serio;
433
434 sprintf(ts->phys, "%s/input0", serio->phys);
435
436 ts->dev.event = h3600ts_event;
437 ts->dev.private = ts;
438 ts->dev.name = h3600_name;
439 ts->dev.phys = ts->phys;
440 ts->dev.id.bustype = BUS_RS232;
441 ts->dev.id.vendor = SERIO_H3600;
442 ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */
443 ts->dev.id.version = 0x0100;
444
445 serio_set_drvdata(serio, ts);
446
447 err = serio_open(serio, drv);
448 if (err) {
449 free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
450 free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
451 serio_set_drvdata(serio, NULL);
452 kfree(ts);
453 return err;
454 }
455
456 //h3600_flite_control(1, 25); /* default brightness */
457#ifdef CONFIG_PM
458 ts->pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT,
459 h3600ts_pm_callback);
460 printk("registered pm callback\n");
461#endif
462 input_register_device(&ts->dev);
463
464 printk(KERN_INFO "input: %s on %s\n", h3600_name, serio->phys);
465
466 return 0;
467}
468
469/*
470 * h3600ts_disconnect() is the opposite of h3600ts_connect()
471 */
472
473static void h3600ts_disconnect(struct serio *serio)
474{
475 struct h3600_dev *ts = serio_get_drvdata(serio);
476
477 free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
478 free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
479 input_unregister_device(&ts->dev);
480 serio_close(serio);
481 serio_set_drvdata(serio, NULL);
482 kfree(ts);
483}
484
485/*
486 * The serio driver structure.
487 */
488
489static struct serio_device_id h3600ts_serio_ids[] = {
490 {
491 .type = SERIO_RS232,
492 .proto = SERIO_H3600,
493 .id = SERIO_ANY,
494 .extra = SERIO_ANY,
495 },
496 { 0 }
497};
498
499MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids);
500
501static struct serio_driver h3600ts_drv = {
502 .driver = {
503 .name = "h3600ts",
504 },
505 .description = DRIVER_DESC,
506 .id_table = h3600ts_serio_ids,
507 .interrupt = h3600ts_interrupt,
508 .connect = h3600ts_connect,
509 .disconnect = h3600ts_disconnect,
510};
511
512/*
513 * The functions for inserting/removing us as a module.
514 */
515
516static int __init h3600ts_init(void)
517{
518 serio_register_driver(&h3600ts_drv);
519 return 0;
520}
521
522static void __exit h3600ts_exit(void)
523{
524 serio_unregister_driver(&h3600ts_drv);
525}
526
527module_init(h3600ts_init);
528module_exit(h3600ts_exit);
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
new file mode 100644
index 000000000000..7e1404441eca
--- /dev/null
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -0,0 +1,135 @@
1#include <linux/input.h>
2#include <linux/module.h>
3#include <linux/init.h>
4
5#include <linux/interrupt.h>
6#include <asm/io.h>
7#include <asm/delay.h>
8#include <asm/adc.h>
9#include <asm/hp6xx/hp6xx.h>
10
11#define MODNAME "hp680_ts_input"
12
13#define HP680_TS_ABS_X_MIN 40
14#define HP680_TS_ABS_X_MAX 950
15#define HP680_TS_ABS_Y_MIN 80
16#define HP680_TS_ABS_Y_MAX 910
17
18#define SCPCR 0xa4000116
19#define PHDR 0xa400012e
20#define SCPDR 0xa4000136
21
22static void do_softint(void *data);
23
24static struct input_dev hp680_ts_dev;
25static DECLARE_WORK(work, do_softint, 0);
26static char *hp680_ts_name = "HP Jornada touchscreen";
27static char *hp680_ts_phys = "input0";
28
29static void do_softint(void *data)
30{
31 int absx = 0, absy = 0;
32 u8 scpdr;
33 int touched = 0;
34
35 if (ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN) {
36 scpdr = ctrl_inb(SCPDR);
37 scpdr |= SCPDR_TS_SCAN_ENABLE;
38 scpdr &= ~SCPDR_TS_SCAN_Y;
39 ctrl_outb(scpdr, SCPDR);
40 udelay(30);
41
42 absy = adc_single(ADC_CHANNEL_TS_Y);
43
44 scpdr = ctrl_inb(SCPDR);
45 scpdr |= SCPDR_TS_SCAN_Y;
46 scpdr &= ~SCPDR_TS_SCAN_X;
47 ctrl_outb(scpdr, SCPDR);
48 udelay(30);
49
50 absx = adc_single(ADC_CHANNEL_TS_X);
51
52 scpdr = ctrl_inb(SCPDR);
53 scpdr |= SCPDR_TS_SCAN_X;
54 scpdr &= ~SCPDR_TS_SCAN_ENABLE;
55 ctrl_outb(scpdr, SCPDR);
56 udelay(100);
57 touched = ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN;
58 }
59
60 if (touched) {
61 input_report_key(&hp680_ts_dev, BTN_TOUCH, 1);
62 input_report_abs(&hp680_ts_dev, ABS_X, absx);
63 input_report_abs(&hp680_ts_dev, ABS_Y, absy);
64 } else {
65 input_report_key(&hp680_ts_dev, BTN_TOUCH, 0);
66 }
67
68 input_sync(&hp680_ts_dev);
69 enable_irq(HP680_TS_IRQ);
70}
71
72static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs)
73{
74 disable_irq_nosync(irq);
75 schedule_delayed_work(&work, HZ / 20);
76
77 return IRQ_HANDLED;
78}
79
80static int __init hp680_ts_init(void)
81{
82 u8 scpdr;
83 u16 scpcr;
84
85 scpdr = ctrl_inb(SCPDR);
86 scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
87 scpdr &= ~SCPDR_TS_SCAN_ENABLE;
88 ctrl_outb(scpdr, SCPDR);
89
90 scpcr = ctrl_inw(SCPCR);
91 scpcr &= ~SCPCR_TS_MASK;
92 scpcr |= SCPCR_TS_ENABLE;
93 ctrl_outw(scpcr, SCPCR);
94
95 memset(&hp680_ts_dev, 0, sizeof(hp680_ts_dev));
96 init_input_dev(&hp680_ts_dev);
97
98 hp680_ts_dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
99 hp680_ts_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
100 hp680_ts_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
101
102 hp680_ts_dev.absmin[ABS_X] = HP680_TS_ABS_X_MIN;
103 hp680_ts_dev.absmin[ABS_Y] = HP680_TS_ABS_Y_MIN;
104 hp680_ts_dev.absmax[ABS_X] = HP680_TS_ABS_X_MAX;
105 hp680_ts_dev.absmax[ABS_Y] = HP680_TS_ABS_Y_MAX;
106
107 hp680_ts_dev.name = hp680_ts_name;
108 hp680_ts_dev.phys = hp680_ts_phys;
109 input_register_device(&hp680_ts_dev);
110
111 if (request_irq
112 (HP680_TS_IRQ, hp680_ts_interrupt, SA_INTERRUPT, MODNAME, 0) < 0) {
113 printk(KERN_ERR "hp680_touchscreen.c : Can't allocate irq %d\n",
114 HP680_TS_IRQ);
115 input_unregister_device(&hp680_ts_dev);
116 return -EBUSY;
117 }
118
119 return 0;
120}
121
122static void __exit hp680_ts_exit(void)
123{
124 free_irq(HP680_TS_IRQ, 0);
125 cancel_delayed_work(&work);
126 flush_scheduled_work();
127 input_unregister_device(&hp680_ts_dev);
128}
129
130module_init(hp680_ts_init);
131module_exit(hp680_ts_exit);
132
133MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
134MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
135MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
new file mode 100644
index 000000000000..2d14a57a05e5
--- /dev/null
+++ b/drivers/input/touchscreen/mk712.c
@@ -0,0 +1,222 @@
1/*
2 * ICS MK712 touchscreen controller driver
3 *
4 * Copyright (c) 1999-2002 Transmeta Corporation
5 * Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
6 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 */
14
15/*
16 * This driver supports the ICS MicroClock MK712 TouchScreen controller,
17 * found in Gateway AOL Connected Touchpad computers.
18 *
19 * Documentation for ICS MK712 can be found at:
20 * http://www.icst.com/pdf/mk712.pdf
21 */
22
23/*
24 * 1999-12-18: original version, Daniel Quinlan
25 * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
26 * to use queue_empty, Nathan Laredo
27 * 1999-12-20: improved random point rejection, Nathan Laredo
28 * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
29 * queue code, added module options, other fixes, Daniel Quinlan
30 * 2002-03-15: Clean up for kernel merge <alan@redhat.com>
31 * Fixed multi open race, fixed memory checks, fixed resource
32 * allocation, fixed close/powerdown bug, switched to new init
33 * 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
34 * 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
35 *
36 */
37
38#include <linux/module.h>
39#include <linux/moduleparam.h>
40#include <linux/kernel.h>
41#include <linux/init.h>
42#include <linux/errno.h>
43#include <linux/delay.h>
44#include <linux/ioport.h>
45#include <linux/interrupt.h>
46#include <linux/input.h>
47#include <asm/io.h>
48
49MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
50MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
51MODULE_LICENSE("GPL");
52
53static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */
54module_param_named(io, mk712_io, uint, 0);
55MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
56
57static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */
58module_param_named(irq, mk712_irq, uint, 0);
59MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
60
61/* eight 8-bit registers */
62#define MK712_STATUS 0
63#define MK712_X 2
64#define MK712_Y 4
65#define MK712_CONTROL 6
66#define MK712_RATE 7
67
68/* status */
69#define MK712_STATUS_TOUCH 0x10
70#define MK712_CONVERSION_COMPLETE 0x80
71
72/* control */
73#define MK712_ENABLE_INT 0x01
74#define MK712_INT_ON_CONVERSION_COMPLETE 0x02
75#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS 0x04
76#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x10
77#define MK712_READ_ONE_POINT 0x20
78#define MK712_POWERUP 0x40
79
80static int mk712_used = 0;
81static struct input_dev mk712_dev;
82static DEFINE_SPINLOCK(mk712_lock);
83
84static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
85{
86 unsigned char status;
87 static int debounce = 1;
88 static unsigned short last_x;
89 static unsigned short last_y;
90
91 spin_lock(&mk712_lock);
92 input_regs(&mk712_dev, regs);
93
94 status = inb(mk712_io + MK712_STATUS);
95
96 if (~status & MK712_CONVERSION_COMPLETE) {
97 debounce = 1;
98 goto end;
99 }
100
101 if (~status & MK712_STATUS_TOUCH)
102 {
103 debounce = 1;
104 input_report_key(&mk712_dev, BTN_TOUCH, 0);
105 goto end;
106 }
107
108 if (debounce)
109 {
110 debounce = 0;
111 goto end;
112 }
113
114 input_report_key(&mk712_dev, BTN_TOUCH, 1);
115 input_report_abs(&mk712_dev, ABS_X, last_x);
116 input_report_abs(&mk712_dev, ABS_Y, last_y);
117
118end:
119
120 last_x = inw(mk712_io + MK712_X) & 0x0fff;
121 last_y = inw(mk712_io + MK712_Y) & 0x0fff;
122 input_sync(&mk712_dev);
123 spin_unlock(&mk712_lock);
124 return IRQ_HANDLED;
125}
126
127static int mk712_open(struct input_dev *dev)
128{
129 unsigned long flags;
130
131 spin_lock_irqsave(&mk712_lock, flags);
132
133 if (!mk712_used++) {
134
135 outb(0, mk712_io + MK712_CONTROL); /* Reset */
136
137 outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
138 MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
139 MK712_ENABLE_PERIODIC_CONVERSIONS |
140 MK712_POWERUP, mk712_io + MK712_CONTROL);
141
142 outb(10, mk712_io + MK712_RATE); /* 187 points per second */
143 }
144
145 spin_unlock_irqrestore(&mk712_lock, flags);
146
147 return 0;
148}
149
150static void mk712_close(struct input_dev *dev)
151{
152 unsigned long flags;
153
154 spin_lock_irqsave(&mk712_lock, flags);
155
156 if (!--mk712_used)
157 outb(0, mk712_io + MK712_CONTROL);
158
159 spin_unlock_irqrestore(&mk712_lock, flags);
160}
161
162static struct input_dev mk712_dev = {
163 .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
164 .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
165 .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
166 .open = mk712_open,
167 .close = mk712_close,
168 .name = "ICS MicroClock MK712 TouchScreen",
169 .phys = "isa0260/input0",
170 .absmin = { [ABS_X] = 0, [ABS_Y] = 0 },
171 .absmax = { [ABS_X] = 0xfff, [ABS_Y] = 0xfff },
172 .absfuzz = { [ABS_X] = 88, [ABS_Y] = 88 },
173 .id = {
174 .bustype = BUS_ISA,
175 .vendor = 0x0005,
176 .product = 0x0001,
177 .version = 0x0100,
178 },
179};
180
181int __init mk712_init(void)
182{
183
184 if(!request_region(mk712_io, 8, "mk712"))
185 {
186 printk(KERN_WARNING "mk712: unable to get IO region\n");
187 return -ENODEV;
188 }
189
190 outb(0, mk712_io + MK712_CONTROL);
191
192 if ((inw(mk712_io + MK712_X) & 0xf000) || /* Sanity check */
193 (inw(mk712_io + MK712_Y) & 0xf000) ||
194 (inw(mk712_io + MK712_STATUS) & 0xf333)) {
195 printk(KERN_WARNING "mk712: device not present\n");
196 release_region(mk712_io, 8);
197 return -ENODEV;
198 }
199
200 if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712", &mk712_dev))
201 {
202 printk(KERN_WARNING "mk712: unable to get IRQ\n");
203 release_region(mk712_io, 8);
204 return -EBUSY;
205 }
206
207 input_register_device(&mk712_dev);
208
209 printk(KERN_INFO "input: ICS MicroClock MK712 TouchScreen at %#x irq %d\n", mk712_io, mk712_irq);
210
211 return 0;
212}
213
214static void __exit mk712_exit(void)
215{
216 input_unregister_device(&mk712_dev);
217 free_irq(mk712_irq, &mk712_dev);
218 release_region(mk712_io, 8);
219}
220
221module_init(mk712_init);
222module_exit(mk712_exit);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
new file mode 100644
index 000000000000..aa8ee7842179
--- /dev/null
+++ b/drivers/input/touchscreen/mtouch.c
@@ -0,0 +1,219 @@
1/*
2 * MicroTouch (3M) serial touchscreen driver
3 *
4 * Copyright (c) 2004 Vojtech Pavlik
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 */
12
13/*
14 * 2005/02/19 Dan Streetman <ddstreet@ieee.org>
15 * Copied elo.c and edited for MicroTouch protocol
16 */
17
18#include <linux/errno.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/slab.h>
22#include <linux/input.h>
23#include <linux/serio.h>
24#include <linux/init.h>
25
26#define DRIVER_DESC "MicroTouch serial touchscreen driver"
27
28MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
29MODULE_DESCRIPTION(DRIVER_DESC);
30MODULE_LICENSE("GPL");
31
32/*
33 * Definitions & global arrays.
34 */
35
36#define MTOUCH_FORMAT_TABLET_STATUS_BIT 0x80
37#define MTOUCH_FORMAT_TABLET_TOUCH_BIT 0x40
38#define MTOUCH_FORMAT_TABLET_LENGTH 5
39#define MTOUCH_RESPONSE_BEGIN_BYTE 0x01
40#define MTOUCH_RESPONSE_END_BYTE 0x0d
41
42/* todo: check specs for max length of all responses */
43#define MTOUCH_MAX_LENGTH 16
44
45#define MTOUCH_MIN_XC 0
46#define MTOUCH_MAX_XC 0x3fff
47#define MTOUCH_MIN_YC 0
48#define MTOUCH_MAX_YC 0x3fff
49
50#define MTOUCH_GET_XC(data) (((data[2])<<7) | data[1])
51#define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3])
52#define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0])
53
54static char *mtouch_name = "MicroTouch Serial TouchScreen";
55
56/*
57 * Per-touchscreen data.
58 */
59
60struct mtouch {
61 struct input_dev dev;
62 struct serio *serio;
63 int idx;
64 unsigned char data[MTOUCH_MAX_LENGTH];
65 char phys[32];
66};
67
68static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs)
69{
70 struct input_dev *dev = &mtouch->dev;
71
72 if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) {
73 input_regs(dev, regs);
74 input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data));
75 input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data));
76 input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data));
77 input_sync(dev);
78
79 mtouch->idx = 0;
80 }
81}
82
83static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs)
84{
85 if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) {
86 /* FIXME - process response */
87 mtouch->idx = 0;
88 } else if (MTOUCH_MAX_LENGTH == mtouch->idx) {
89 printk(KERN_ERR "mtouch.c: too many response bytes\n");
90 mtouch->idx = 0;
91 }
92}
93
94static irqreturn_t mtouch_interrupt(struct serio *serio,
95 unsigned char data, unsigned int flags, struct pt_regs *regs)
96{
97 struct mtouch* mtouch = serio_get_drvdata(serio);
98
99 mtouch->data[mtouch->idx] = data;
100
101 if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
102 mtouch_process_format_tablet(mtouch, regs);
103 else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
104 mtouch_process_response(mtouch, regs);
105 else
106 printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
107
108 return IRQ_HANDLED;
109}
110
111/*
112 * mtouch_disconnect() is the opposite of mtouch_connect()
113 */
114
115static void mtouch_disconnect(struct serio *serio)
116{
117 struct mtouch* mtouch = serio_get_drvdata(serio);
118
119 input_unregister_device(&mtouch->dev);
120 serio_close(serio);
121 serio_set_drvdata(serio, NULL);
122 kfree(mtouch);
123}
124
125/*
126 * mtouch_connect() is the routine that is called when someone adds a
127 * new serio device that supports MicroTouch (Format Tablet) protocol and registers it as
128 * an input device.
129 */
130
131static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
132{
133 struct mtouch *mtouch;
134 int err;
135
136 if (!(mtouch = kmalloc(sizeof(*mtouch), GFP_KERNEL)))
137 return -ENOMEM;
138
139 memset(mtouch, 0, sizeof(*mtouch));
140
141 init_input_dev(&mtouch->dev);
142 mtouch->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
143 mtouch->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
144
145 input_set_abs_params(&mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
146 input_set_abs_params(&mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0);
147
148 mtouch->serio = serio;
149
150 sprintf(mtouch->phys, "%s/input0", serio->phys);
151
152 mtouch->dev.private = mtouch;
153 mtouch->dev.name = mtouch_name;
154 mtouch->dev.phys = mtouch->phys;
155 mtouch->dev.id.bustype = BUS_RS232;
156 mtouch->dev.id.vendor = SERIO_MICROTOUCH;
157 mtouch->dev.id.product = 0;
158 mtouch->dev.id.version = 0x0100;
159
160 serio_set_drvdata(serio, mtouch);
161
162 err = serio_open(serio, drv);
163 if (err) {
164 serio_set_drvdata(serio, NULL);
165 kfree(mtouch);
166 return err;
167 }
168
169 input_register_device(&mtouch->dev);
170
171 printk(KERN_INFO "input: %s on %s\n", mtouch->dev.name, serio->phys);
172
173 return 0;
174}
175
176/*
177 * The serio driver structure.
178 */
179
180static struct serio_device_id mtouch_serio_ids[] = {
181 {
182 .type = SERIO_RS232,
183 .proto = SERIO_MICROTOUCH,
184 .id = SERIO_ANY,
185 .extra = SERIO_ANY,
186 },
187 { 0 }
188};
189
190MODULE_DEVICE_TABLE(serio, mtouch_serio_ids);
191
192static struct serio_driver mtouch_drv = {
193 .driver = {
194 .name = "mtouch",
195 },
196 .description = DRIVER_DESC,
197 .id_table = mtouch_serio_ids,
198 .interrupt = mtouch_interrupt,
199 .connect = mtouch_connect,
200 .disconnect = mtouch_disconnect,
201};
202
203/*
204 * The functions for inserting/removing us as a module.
205 */
206
207static int __init mtouch_init(void)
208{
209 serio_register_driver(&mtouch_drv);
210 return 0;
211}
212
213static void __exit mtouch_exit(void)
214{
215 serio_unregister_driver(&mtouch_drv);
216}
217
218module_init(mtouch_init);
219module_exit(mtouch_exit);