diff options
author | Hans-Christian Egtvedt <hcegtvedt@norway.atmel.com> | 2007-06-14 23:32:35 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-07-10 00:35:17 -0400 |
commit | 5f5655023f2814969b744c1e07494666587243aa (patch) | |
tree | dd4d387a5c4505df663a38299901d0cb81f4effa /drivers/input/mouse/gpio_mouse.c | |
parent | 9657d75c5f0f7d0a9cb507521d3ad1436aea28c9 (diff) |
Input: add gpio-mouse driver
Adds support for simulating a mouse using GPIO lines. The driver
needs an appropriate platform device to be created by architecture
code.
The driver has been tested on AT32AP7000 microprocessor using the
ATSTK1000 development board.
Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/mouse/gpio_mouse.c')
-rw-r--r-- | drivers/input/mouse/gpio_mouse.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c new file mode 100644 index 000000000000..0936d6ba015c --- /dev/null +++ b/drivers/input/mouse/gpio_mouse.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Driver for simulating a mouse on GPIO lines. | ||
3 | * | ||
4 | * Copyright (C) 2007 Atmel Corporation | ||
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 | #include <linux/init.h> | ||
12 | #include <linux/version.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/input-polldev.h> | ||
16 | #include <linux/gpio_mouse.h> | ||
17 | |||
18 | #include <asm/gpio.h> | ||
19 | |||
20 | /* | ||
21 | * Timer function which is run every scan_ms ms when the device is opened. | ||
22 | * The dev input varaible is set to the the input_dev pointer. | ||
23 | */ | ||
24 | static void gpio_mouse_scan(struct input_polled_dev *dev) | ||
25 | { | ||
26 | struct gpio_mouse_platform_data *gpio = dev->private; | ||
27 | struct input_dev *input = dev->input; | ||
28 | int x, y; | ||
29 | |||
30 | if (gpio->bleft >= 0) | ||
31 | input_report_key(input, BTN_LEFT, | ||
32 | gpio_get_value(gpio->bleft) ^ gpio->polarity); | ||
33 | if (gpio->bmiddle >= 0) | ||
34 | input_report_key(input, BTN_MIDDLE, | ||
35 | gpio_get_value(gpio->bmiddle) ^ gpio->polarity); | ||
36 | if (gpio->bright >= 0) | ||
37 | input_report_key(input, BTN_RIGHT, | ||
38 | gpio_get_value(gpio->bright) ^ gpio->polarity); | ||
39 | |||
40 | x = (gpio_get_value(gpio->right) ^ gpio->polarity) | ||
41 | - (gpio_get_value(gpio->left) ^ gpio->polarity); | ||
42 | y = (gpio_get_value(gpio->down) ^ gpio->polarity) | ||
43 | - (gpio_get_value(gpio->up) ^ gpio->polarity); | ||
44 | |||
45 | input_report_rel(input, REL_X, x); | ||
46 | input_report_rel(input, REL_Y, y); | ||
47 | input_sync(input); | ||
48 | } | ||
49 | |||
50 | static int __init gpio_mouse_probe(struct platform_device *pdev) | ||
51 | { | ||
52 | struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data; | ||
53 | struct input_polled_dev *input_poll; | ||
54 | struct input_dev *input; | ||
55 | int pin, i; | ||
56 | int error; | ||
57 | |||
58 | if (!pdata) { | ||
59 | dev_err(&pdev->dev, "no platform data\n"); | ||
60 | error = -ENXIO; | ||
61 | goto out; | ||
62 | } | ||
63 | |||
64 | if (pdata->scan_ms < 0) { | ||
65 | dev_err(&pdev->dev, "invalid scan time\n"); | ||
66 | error = -EINVAL; | ||
67 | goto out; | ||
68 | } | ||
69 | |||
70 | for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) { | ||
71 | pin = pdata->pins[i]; | ||
72 | |||
73 | if (pin < 0) { | ||
74 | |||
75 | if (i <= GPIO_MOUSE_PIN_RIGHT) { | ||
76 | /* Mouse direction is required. */ | ||
77 | dev_err(&pdev->dev, | ||
78 | "missing GPIO for directions\n"); | ||
79 | error = -EINVAL; | ||
80 | goto out_free_gpios; | ||
81 | } | ||
82 | |||
83 | if (i == GPIO_MOUSE_PIN_BLEFT) | ||
84 | dev_dbg(&pdev->dev, "no left button defined\n"); | ||
85 | |||
86 | } else { | ||
87 | error = gpio_request(pin, "gpio_mouse"); | ||
88 | if (error) { | ||
89 | dev_err(&pdev->dev, "fail %d pin (%d idx)\n", | ||
90 | pin, i); | ||
91 | goto out_free_gpios; | ||
92 | } | ||
93 | |||
94 | gpio_direction_input(pin); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | input_poll = input_allocate_polled_device(); | ||
99 | if (!input_poll) { | ||
100 | dev_err(&pdev->dev, "not enough memory for input device\n"); | ||
101 | error = -ENOMEM; | ||
102 | goto out_free_gpios; | ||
103 | } | ||
104 | |||
105 | platform_set_drvdata(pdev, input_poll); | ||
106 | |||
107 | /* set input-polldev handlers */ | ||
108 | input_poll->private = pdata; | ||
109 | input_poll->poll = gpio_mouse_scan; | ||
110 | input_poll->poll_interval = pdata->scan_ms; | ||
111 | |||
112 | input = input_poll->input; | ||
113 | input->name = pdev->name; | ||
114 | input->id.bustype = BUS_HOST; | ||
115 | input->dev.parent = &pdev->dev; | ||
116 | |||
117 | input_set_capability(input, EV_REL, REL_X); | ||
118 | input_set_capability(input, EV_REL, REL_Y); | ||
119 | if (pdata->bleft >= 0) | ||
120 | input_set_capability(input, EV_KEY, BTN_LEFT); | ||
121 | if (pdata->bmiddle >= 0) | ||
122 | input_set_capability(input, EV_KEY, BTN_MIDDLE); | ||
123 | if (pdata->bright >= 0) | ||
124 | input_set_capability(input, EV_KEY, BTN_RIGHT); | ||
125 | |||
126 | error = input_register_polled_device(input_poll); | ||
127 | if (error) { | ||
128 | dev_err(&pdev->dev, "could not register input device\n"); | ||
129 | goto out_free_polldev; | ||
130 | } | ||
131 | |||
132 | dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n", | ||
133 | pdata->scan_ms, | ||
134 | pdata->bleft < 0 ? "" : "left ", | ||
135 | pdata->bmiddle < 0 ? "" : "middle ", | ||
136 | pdata->bright < 0 ? "" : "right"); | ||
137 | |||
138 | return 0; | ||
139 | |||
140 | out_free_polldev: | ||
141 | input_free_polled_device(input_poll); | ||
142 | platform_set_drvdata(pdev, NULL); | ||
143 | |||
144 | out_free_gpios: | ||
145 | while (--i >= 0) { | ||
146 | pin = pdata->pins[i]; | ||
147 | if (pin) | ||
148 | gpio_free(pin); | ||
149 | } | ||
150 | out: | ||
151 | return error; | ||
152 | } | ||
153 | |||
154 | static int __devexit gpio_mouse_remove(struct platform_device *pdev) | ||
155 | { | ||
156 | struct input_polled_dev *input = platform_get_drvdata(pdev); | ||
157 | struct gpio_mouse_platform_data *pdata = input->private; | ||
158 | int pin, i; | ||
159 | |||
160 | input_unregister_polled_device(input); | ||
161 | input_free_polled_device(input); | ||
162 | |||
163 | for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) { | ||
164 | pin = pdata->pins[i]; | ||
165 | if (pin >= 0) | ||
166 | gpio_free(pin); | ||
167 | } | ||
168 | |||
169 | platform_set_drvdata(pdev, NULL); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | struct platform_driver gpio_mouse_device_driver = { | ||
175 | .remove = __devexit_p(gpio_mouse_remove), | ||
176 | .driver = { | ||
177 | .name = "gpio_mouse", | ||
178 | } | ||
179 | }; | ||
180 | |||
181 | static int __init gpio_mouse_init(void) | ||
182 | { | ||
183 | return platform_driver_probe(&gpio_mouse_device_driver, | ||
184 | gpio_mouse_probe); | ||
185 | } | ||
186 | module_init(gpio_mouse_init); | ||
187 | |||
188 | static void __exit gpio_mouse_exit(void) | ||
189 | { | ||
190 | platform_driver_unregister(&gpio_mouse_device_driver); | ||
191 | } | ||
192 | module_exit(gpio_mouse_exit); | ||
193 | |||
194 | MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); | ||
195 | MODULE_DESCRIPTION("GPIO mouse driver"); | ||
196 | MODULE_LICENSE("GPL"); | ||