diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Kconfig | 98 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 13 | ||||
-rw-r--r-- | drivers/input/touchscreen/corgi_ts.c | 380 | ||||
-rw-r--r-- | drivers/input/touchscreen/elo.c | 315 | ||||
-rw-r--r-- | drivers/input/touchscreen/gunze.c | 205 | ||||
-rw-r--r-- | drivers/input/touchscreen/h3600_ts_input.c | 528 | ||||
-rw-r--r-- | drivers/input/touchscreen/hp680_ts_input.c | 135 | ||||
-rw-r--r-- | drivers/input/touchscreen/mk712.c | 222 | ||||
-rw-r--r-- | drivers/input/touchscreen/mtouch.c | 219 |
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 | # | ||
4 | menuconfig 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 | |||
12 | if INPUT_TOUCHSCREEN | ||
13 | |||
14 | config 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 | |||
26 | config 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 | |||
39 | config 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 | |||
51 | config 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 | |||
63 | config 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 | |||
75 | config 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 | |||
86 | config 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 | |||
98 | endif | ||
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 | |||
7 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o | ||
8 | obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o | ||
9 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o | ||
10 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o | ||
11 | obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o | ||
12 | obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o | ||
13 | obj-$(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 | |||
37 | struct ts_event { | ||
38 | short pressure; | ||
39 | short x; | ||
40 | short y; | ||
41 | }; | ||
42 | |||
43 | struct 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 */ | ||
72 | extern int w100fb_get_xres(void); | ||
73 | extern int w100fb_get_blanking(void); | ||
74 | extern int w100fb_get_fastsysclk(void); | ||
75 | extern unsigned int get_clk_frequency_khz(int info); | ||
76 | |||
77 | static 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 | |||
97 | static 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 | |||
143 | static 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 | |||
187 | static 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 | |||
205 | static 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 | |||
233 | static 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 | |||
239 | static 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 | ||
247 | static 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 | |||
265 | static 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 | |||
282 | static 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 | |||
345 | static 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 | |||
356 | static 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 | |||
365 | static int __devinit corgits_init(void) | ||
366 | { | ||
367 | return driver_register(&corgits_driver); | ||
368 | } | ||
369 | |||
370 | static void __exit corgits_exit(void) | ||
371 | { | ||
372 | driver_unregister(&corgits_driver); | ||
373 | } | ||
374 | |||
375 | module_init(corgits_init); | ||
376 | module_exit(corgits_exit); | ||
377 | |||
378 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); | ||
379 | MODULE_DESCRIPTION("Corgi TouchScreen Driver"); | ||
380 | MODULE_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 | |||
29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
30 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* | ||
34 | * Definitions & global arrays. | ||
35 | */ | ||
36 | |||
37 | #define ELO_MAX_LENGTH 10 | ||
38 | |||
39 | static char *elo_name = "Elo Serial TouchScreen"; | ||
40 | |||
41 | /* | ||
42 | * Per-touchscreen data. | ||
43 | */ | ||
44 | |||
45 | struct 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 | |||
55 | static 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 | |||
92 | static 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 | |||
140 | static 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 | |||
163 | static 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 | |||
190 | static 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 | |||
206 | static 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 | |||
276 | static 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 | |||
286 | MODULE_DEVICE_TABLE(serio, elo_serio_ids); | ||
287 | |||
288 | static 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 | |||
303 | static int __init elo_init(void) | ||
304 | { | ||
305 | serio_register_driver(&elo_drv); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void __exit elo_exit(void) | ||
310 | { | ||
311 | serio_unregister_driver(&elo_drv); | ||
312 | } | ||
313 | |||
314 | module_init(elo_init); | ||
315 | module_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 | |||
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
42 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | /* | ||
46 | * Definitions & global arrays. | ||
47 | */ | ||
48 | |||
49 | #define GUNZE_MAX_LENGTH 10 | ||
50 | |||
51 | static char *gunze_name = "Gunze AHL-51S TouchScreen"; | ||
52 | |||
53 | /* | ||
54 | * Per-touchscreen data. | ||
55 | */ | ||
56 | |||
57 | struct 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 | |||
65 | static 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 | |||
83 | static 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 | |||
102 | static 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 | |||
118 | static 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 | |||
166 | static 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 | |||
176 | MODULE_DEVICE_TABLE(serio, gunze_serio_ids); | ||
177 | |||
178 | static 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 | |||
193 | static int __init gunze_init(void) | ||
194 | { | ||
195 | serio_register_driver(&gunze_drv); | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static void __exit gunze_exit(void) | ||
200 | { | ||
201 | serio_unregister_driver(&gunze_drv); | ||
202 | } | ||
203 | |||
204 | module_init(gunze_init); | ||
205 | module_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 | |||
50 | MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); | ||
51 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
52 | MODULE_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 | |||
96 | static char *h3600_name = "H3600 TouchScreen"; | ||
97 | |||
98 | /* | ||
99 | * Per-touchscreen data. | ||
100 | */ | ||
101 | struct 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 | |||
114 | static 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 | |||
126 | static 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 | |||
145 | static int flite_brightness = 25; | ||
146 | |||
147 | enum 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 */ | ||
154 | unsigned 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 | |||
166 | static int suspended = 0; | ||
167 | static 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 | */ | ||
200 | static 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 | */ | ||
295 | static 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 | |||
324 | static 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 | |||
332 | static 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 | */ | ||
380 | static 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 | |||
473 | static 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 | |||
489 | static 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 | |||
499 | MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids); | ||
500 | |||
501 | static 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 | |||
516 | static int __init h3600ts_init(void) | ||
517 | { | ||
518 | serio_register_driver(&h3600ts_drv); | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static void __exit h3600ts_exit(void) | ||
523 | { | ||
524 | serio_unregister_driver(&h3600ts_drv); | ||
525 | } | ||
526 | |||
527 | module_init(h3600ts_init); | ||
528 | module_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 | |||
22 | static void do_softint(void *data); | ||
23 | |||
24 | static struct input_dev hp680_ts_dev; | ||
25 | static DECLARE_WORK(work, do_softint, 0); | ||
26 | static char *hp680_ts_name = "HP Jornada touchscreen"; | ||
27 | static char *hp680_ts_phys = "input0"; | ||
28 | |||
29 | static 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 | |||
72 | static 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 | |||
80 | static 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 | |||
122 | static 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 | |||
130 | module_init(hp680_ts_init); | ||
131 | module_exit(hp680_ts_exit); | ||
132 | |||
133 | MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua"); | ||
134 | MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver"); | ||
135 | MODULE_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 | |||
49 | MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>"); | ||
50 | MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver"); | ||
51 | MODULE_LICENSE("GPL"); | ||
52 | |||
53 | static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */ | ||
54 | module_param_named(io, mk712_io, uint, 0); | ||
55 | MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller"); | ||
56 | |||
57 | static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */ | ||
58 | module_param_named(irq, mk712_irq, uint, 0); | ||
59 | MODULE_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 | |||
80 | static int mk712_used = 0; | ||
81 | static struct input_dev mk712_dev; | ||
82 | static DEFINE_SPINLOCK(mk712_lock); | ||
83 | |||
84 | static 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 | |||
118 | end: | ||
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 | |||
127 | static 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 | |||
150 | static 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 | |||
162 | static 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 | |||
181 | int __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 | |||
214 | static 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 | |||
221 | module_init(mk712_init); | ||
222 | module_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 | |||
28 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
29 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
30 | MODULE_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 | |||
54 | static char *mtouch_name = "MicroTouch Serial TouchScreen"; | ||
55 | |||
56 | /* | ||
57 | * Per-touchscreen data. | ||
58 | */ | ||
59 | |||
60 | struct 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 | |||
68 | static 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 | |||
83 | static 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 | |||
94 | static 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 | |||
115 | static 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 | |||
131 | static 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 | |||
180 | static 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 | |||
190 | MODULE_DEVICE_TABLE(serio, mtouch_serio_ids); | ||
191 | |||
192 | static 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 | |||
207 | static int __init mtouch_init(void) | ||
208 | { | ||
209 | serio_register_driver(&mtouch_drv); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static void __exit mtouch_exit(void) | ||
214 | { | ||
215 | serio_unregister_driver(&mtouch_drv); | ||
216 | } | ||
217 | |||
218 | module_init(mtouch_init); | ||
219 | module_exit(mtouch_exit); | ||