diff options
Diffstat (limited to 'drivers/input')
125 files changed, 39668 insertions, 0 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig new file mode 100644 index 000000000000..58223b5d842a --- /dev/null +++ b/drivers/input/Kconfig | |||
@@ -0,0 +1,157 @@ | |||
1 | # | ||
2 | # Input device configuration | ||
3 | # | ||
4 | |||
5 | menu "Input device support" | ||
6 | |||
7 | config INPUT | ||
8 | tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED | ||
9 | default y | ||
10 | ---help--- | ||
11 | Say Y here if you have any input device (mouse, keyboard, tablet, | ||
12 | joystick, steering wheel ...) connected to your system and want | ||
13 | it to be available to applications. This includes standard PS/2 | ||
14 | keyboard and mouse. | ||
15 | |||
16 | Say N here if you have a headless (no monitor, no keyboard) system. | ||
17 | |||
18 | More information is available: <file:Documentation/input/input.txt> | ||
19 | |||
20 | If unsure, say Y. | ||
21 | |||
22 | To compile this driver as a module, choose M here: the | ||
23 | module will be called input. | ||
24 | |||
25 | if INPUT | ||
26 | |||
27 | comment "Userland interfaces" | ||
28 | |||
29 | config INPUT_MOUSEDEV | ||
30 | tristate "Mouse interface" if EMBEDDED | ||
31 | default y | ||
32 | ---help--- | ||
33 | Say Y here if you want your mouse to be accessible as char devices | ||
34 | 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an | ||
35 | emulated IntelliMouse Explorer PS/2 mouse. That way, all user space | ||
36 | programs (including SVGAlib, GPM and X) will be able to use your | ||
37 | mouse. | ||
38 | |||
39 | If unsure, say Y. | ||
40 | |||
41 | To compile this driver as a module, choose M here: the | ||
42 | module will be called mousedev. | ||
43 | |||
44 | config INPUT_MOUSEDEV_PSAUX | ||
45 | bool "Provide legacy /dev/psaux device" | ||
46 | default y | ||
47 | depends on INPUT_MOUSEDEV | ||
48 | ---help--- | ||
49 | Say Y here if you want your mouse also be accessible as char device | ||
50 | 10:1 - /dev/psaux. The data available through /dev/psaux is exactly | ||
51 | the same as the data from /dev/input/mice. | ||
52 | |||
53 | If unsure, say Y. | ||
54 | |||
55 | |||
56 | config INPUT_MOUSEDEV_SCREEN_X | ||
57 | int "Horizontal screen resolution" | ||
58 | depends on INPUT_MOUSEDEV | ||
59 | default "1024" | ||
60 | help | ||
61 | If you're using a digitizer, or a graphic tablet, and want to use | ||
62 | it as a mouse then the mousedev driver needs to know the X window | ||
63 | screen resolution you are using to correctly scale the data. If | ||
64 | you're not using a digitizer, this value is ignored. | ||
65 | |||
66 | config INPUT_MOUSEDEV_SCREEN_Y | ||
67 | int "Vertical screen resolution" | ||
68 | depends on INPUT_MOUSEDEV | ||
69 | default "768" | ||
70 | help | ||
71 | If you're using a digitizer, or a graphic tablet, and want to use | ||
72 | it as a mouse then the mousedev driver needs to know the X window | ||
73 | screen resolution you are using to correctly scale the data. If | ||
74 | you're not using a digitizer, this value is ignored. | ||
75 | |||
76 | config INPUT_JOYDEV | ||
77 | tristate "Joystick interface" | ||
78 | ---help--- | ||
79 | Say Y here if you want your joystick or gamepad to be | ||
80 | accessible as char device 13:0+ - /dev/input/jsX device. | ||
81 | |||
82 | If unsure, say Y. | ||
83 | |||
84 | More information is available: <file:Documentation/input/joystick.txt> | ||
85 | |||
86 | To compile this driver as a module, choose M here: the | ||
87 | module will be called joydev. | ||
88 | |||
89 | config INPUT_TSDEV | ||
90 | tristate "Touchscreen interface" | ||
91 | ---help--- | ||
92 | Say Y here if you have an application that only can understand the | ||
93 | Compaq touchscreen protocol for absolute pointer data. This is | ||
94 | useful namely for embedded configurations. | ||
95 | |||
96 | If unsure, say N. | ||
97 | |||
98 | To compile this driver as a module, choose M here: the | ||
99 | module will be called tsdev. | ||
100 | |||
101 | config INPUT_TSDEV_SCREEN_X | ||
102 | int "Horizontal screen resolution" | ||
103 | depends on INPUT_TSDEV | ||
104 | default "240" | ||
105 | |||
106 | config INPUT_TSDEV_SCREEN_Y | ||
107 | int "Vertical screen resolution" | ||
108 | depends on INPUT_TSDEV | ||
109 | default "320" | ||
110 | |||
111 | config INPUT_EVDEV | ||
112 | tristate "Event interface" | ||
113 | help | ||
114 | Say Y here if you want your input device events be accessible | ||
115 | under char device 13:64+ - /dev/input/eventX in a generic way. | ||
116 | |||
117 | To compile this driver as a module, choose M here: the | ||
118 | module will be called evdev. | ||
119 | |||
120 | config INPUT_EVBUG | ||
121 | tristate "Event debugging" | ||
122 | ---help--- | ||
123 | Say Y here if you have a problem with the input subsystem and | ||
124 | want all events (keypresses, mouse movements), to be output to | ||
125 | the system log. While this is useful for debugging, it's also | ||
126 | a security threat - your keypresses include your passwords, of | ||
127 | course. | ||
128 | |||
129 | If unsure, say N. | ||
130 | |||
131 | To compile this driver as a module, choose M here: the | ||
132 | module will be called evbug. | ||
133 | |||
134 | comment "Input Device Drivers" | ||
135 | |||
136 | source "drivers/input/keyboard/Kconfig" | ||
137 | |||
138 | source "drivers/input/mouse/Kconfig" | ||
139 | |||
140 | source "drivers/input/joystick/Kconfig" | ||
141 | |||
142 | source "drivers/input/touchscreen/Kconfig" | ||
143 | |||
144 | source "drivers/input/misc/Kconfig" | ||
145 | |||
146 | endif | ||
147 | |||
148 | menu "Hardware I/O ports" | ||
149 | |||
150 | source "drivers/input/serio/Kconfig" | ||
151 | |||
152 | source "drivers/input/gameport/Kconfig" | ||
153 | |||
154 | endmenu | ||
155 | |||
156 | endmenu | ||
157 | |||
diff --git a/drivers/input/Makefile b/drivers/input/Makefile new file mode 100644 index 000000000000..1a6ff4982f30 --- /dev/null +++ b/drivers/input/Makefile | |||
@@ -0,0 +1,19 @@ | |||
1 | # | ||
2 | # Makefile for the input core drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_INPUT) += input.o | ||
8 | obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o | ||
9 | obj-$(CONFIG_INPUT_JOYDEV) += joydev.o | ||
10 | obj-$(CONFIG_INPUT_EVDEV) += evdev.o | ||
11 | obj-$(CONFIG_INPUT_TSDEV) += tsdev.o | ||
12 | obj-$(CONFIG_INPUT_POWER) += power.o | ||
13 | obj-$(CONFIG_INPUT_EVBUG) += evbug.o | ||
14 | |||
15 | obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ | ||
16 | obj-$(CONFIG_INPUT_MOUSE) += mouse/ | ||
17 | obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ | ||
18 | obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ | ||
19 | obj-$(CONFIG_INPUT_MISC) += misc/ | ||
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c new file mode 100644 index 000000000000..d7828936fd8f --- /dev/null +++ b/drivers/input/evbug.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Input driver event debug module - dumps all events into syslog | ||
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/slab.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/input.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/device.h> | ||
36 | |||
37 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
38 | MODULE_DESCRIPTION("Input driver event debug module"); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | static char evbug_name[] = "evbug"; | ||
42 | |||
43 | static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | ||
44 | { | ||
45 | printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); | ||
46 | } | ||
47 | |||
48 | static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | ||
49 | { | ||
50 | struct input_handle *handle; | ||
51 | |||
52 | if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) | ||
53 | return NULL; | ||
54 | memset(handle, 0, sizeof(struct input_handle)); | ||
55 | |||
56 | handle->dev = dev; | ||
57 | handle->handler = handler; | ||
58 | handle->name = evbug_name; | ||
59 | |||
60 | input_open_device(handle); | ||
61 | |||
62 | printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys); | ||
63 | |||
64 | return handle; | ||
65 | } | ||
66 | |||
67 | static void evbug_disconnect(struct input_handle *handle) | ||
68 | { | ||
69 | printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys); | ||
70 | |||
71 | input_close_device(handle); | ||
72 | |||
73 | kfree(handle); | ||
74 | } | ||
75 | |||
76 | static struct input_device_id evbug_ids[] = { | ||
77 | { .driver_info = 1 }, /* Matches all devices */ | ||
78 | { }, /* Terminating zero entry */ | ||
79 | }; | ||
80 | |||
81 | MODULE_DEVICE_TABLE(input, evbug_ids); | ||
82 | |||
83 | static struct input_handler evbug_handler = { | ||
84 | .event = evbug_event, | ||
85 | .connect = evbug_connect, | ||
86 | .disconnect = evbug_disconnect, | ||
87 | .name = "evbug", | ||
88 | .id_table = evbug_ids, | ||
89 | }; | ||
90 | |||
91 | static int __init evbug_init(void) | ||
92 | { | ||
93 | input_register_handler(&evbug_handler); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static void __exit evbug_exit(void) | ||
98 | { | ||
99 | input_unregister_handler(&evbug_handler); | ||
100 | } | ||
101 | |||
102 | module_init(evbug_init); | ||
103 | module_exit(evbug_exit); | ||
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c new file mode 100644 index 000000000000..17552a29978b --- /dev/null +++ b/drivers/input/evdev.c | |||
@@ -0,0 +1,492 @@ | |||
1 | /* | ||
2 | * Event char devices, giving access to raw input device events. | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #define EVDEV_MINOR_BASE 64 | ||
12 | #define EVDEV_MINORS 32 | ||
13 | #define EVDEV_BUFFER_SIZE 64 | ||
14 | |||
15 | #include <linux/poll.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/major.h> | ||
21 | #include <linux/smp_lock.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/devfs_fs_kernel.h> | ||
24 | |||
25 | struct evdev { | ||
26 | int exist; | ||
27 | int open; | ||
28 | int minor; | ||
29 | char name[16]; | ||
30 | struct input_handle handle; | ||
31 | wait_queue_head_t wait; | ||
32 | struct evdev_list *grab; | ||
33 | struct list_head list; | ||
34 | }; | ||
35 | |||
36 | struct evdev_list { | ||
37 | struct input_event buffer[EVDEV_BUFFER_SIZE]; | ||
38 | int head; | ||
39 | int tail; | ||
40 | struct fasync_struct *fasync; | ||
41 | struct evdev *evdev; | ||
42 | struct list_head node; | ||
43 | }; | ||
44 | |||
45 | static struct evdev *evdev_table[EVDEV_MINORS]; | ||
46 | |||
47 | static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | ||
48 | { | ||
49 | struct evdev *evdev = handle->private; | ||
50 | struct evdev_list *list; | ||
51 | |||
52 | if (evdev->grab) { | ||
53 | list = evdev->grab; | ||
54 | |||
55 | do_gettimeofday(&list->buffer[list->head].time); | ||
56 | list->buffer[list->head].type = type; | ||
57 | list->buffer[list->head].code = code; | ||
58 | list->buffer[list->head].value = value; | ||
59 | list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); | ||
60 | |||
61 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
62 | } else | ||
63 | list_for_each_entry(list, &evdev->list, node) { | ||
64 | |||
65 | do_gettimeofday(&list->buffer[list->head].time); | ||
66 | list->buffer[list->head].type = type; | ||
67 | list->buffer[list->head].code = code; | ||
68 | list->buffer[list->head].value = value; | ||
69 | list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); | ||
70 | |||
71 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
72 | } | ||
73 | |||
74 | wake_up_interruptible(&evdev->wait); | ||
75 | } | ||
76 | |||
77 | static int evdev_fasync(int fd, struct file *file, int on) | ||
78 | { | ||
79 | int retval; | ||
80 | struct evdev_list *list = file->private_data; | ||
81 | retval = fasync_helper(fd, file, on, &list->fasync); | ||
82 | return retval < 0 ? retval : 0; | ||
83 | } | ||
84 | |||
85 | static int evdev_flush(struct file * file) | ||
86 | { | ||
87 | struct evdev_list *list = file->private_data; | ||
88 | if (!list->evdev->exist) return -ENODEV; | ||
89 | return input_flush_device(&list->evdev->handle, file); | ||
90 | } | ||
91 | |||
92 | static void evdev_free(struct evdev *evdev) | ||
93 | { | ||
94 | evdev_table[evdev->minor] = NULL; | ||
95 | kfree(evdev); | ||
96 | } | ||
97 | |||
98 | static int evdev_release(struct inode * inode, struct file * file) | ||
99 | { | ||
100 | struct evdev_list *list = file->private_data; | ||
101 | |||
102 | if (list->evdev->grab == list) { | ||
103 | input_release_device(&list->evdev->handle); | ||
104 | list->evdev->grab = NULL; | ||
105 | } | ||
106 | |||
107 | evdev_fasync(-1, file, 0); | ||
108 | list_del(&list->node); | ||
109 | |||
110 | if (!--list->evdev->open) { | ||
111 | if (list->evdev->exist) | ||
112 | input_close_device(&list->evdev->handle); | ||
113 | else | ||
114 | evdev_free(list->evdev); | ||
115 | } | ||
116 | |||
117 | kfree(list); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int evdev_open(struct inode * inode, struct file * file) | ||
122 | { | ||
123 | struct evdev_list *list; | ||
124 | int i = iminor(inode) - EVDEV_MINOR_BASE; | ||
125 | int accept_err; | ||
126 | |||
127 | if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist) | ||
128 | return -ENODEV; | ||
129 | |||
130 | if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) | ||
131 | return accept_err; | ||
132 | |||
133 | if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) | ||
134 | return -ENOMEM; | ||
135 | memset(list, 0, sizeof(struct evdev_list)); | ||
136 | |||
137 | list->evdev = evdev_table[i]; | ||
138 | list_add_tail(&list->node, &evdev_table[i]->list); | ||
139 | file->private_data = list; | ||
140 | |||
141 | if (!list->evdev->open++) | ||
142 | if (list->evdev->exist) | ||
143 | input_open_device(&list->evdev->handle); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | ||
149 | { | ||
150 | struct evdev_list *list = file->private_data; | ||
151 | struct input_event event; | ||
152 | int retval = 0; | ||
153 | |||
154 | if (!list->evdev->exist) return -ENODEV; | ||
155 | |||
156 | while (retval < count) { | ||
157 | |||
158 | if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) | ||
159 | return -EFAULT; | ||
160 | input_event(list->evdev->handle.dev, event.type, event.code, event.value); | ||
161 | retval += sizeof(struct input_event); | ||
162 | } | ||
163 | |||
164 | return retval; | ||
165 | } | ||
166 | |||
167 | static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) | ||
168 | { | ||
169 | struct evdev_list *list = file->private_data; | ||
170 | int retval; | ||
171 | |||
172 | if (count < sizeof(struct input_event)) | ||
173 | return -EINVAL; | ||
174 | |||
175 | if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) | ||
176 | return -EAGAIN; | ||
177 | |||
178 | retval = wait_event_interruptible(list->evdev->wait, | ||
179 | list->head != list->tail || (!list->evdev->exist)); | ||
180 | |||
181 | if (retval) | ||
182 | return retval; | ||
183 | |||
184 | if (!list->evdev->exist) | ||
185 | return -ENODEV; | ||
186 | |||
187 | while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { | ||
188 | if (copy_to_user(buffer + retval, list->buffer + list->tail, | ||
189 | sizeof(struct input_event))) return -EFAULT; | ||
190 | list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); | ||
191 | retval += sizeof(struct input_event); | ||
192 | } | ||
193 | |||
194 | return retval; | ||
195 | } | ||
196 | |||
197 | /* No kernel lock - fine */ | ||
198 | static unsigned int evdev_poll(struct file *file, poll_table *wait) | ||
199 | { | ||
200 | struct evdev_list *list = file->private_data; | ||
201 | poll_wait(file, &list->evdev->wait, wait); | ||
202 | return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | | ||
203 | (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); | ||
204 | } | ||
205 | |||
206 | static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
207 | { | ||
208 | struct evdev_list *list = file->private_data; | ||
209 | struct evdev *evdev = list->evdev; | ||
210 | struct input_dev *dev = evdev->handle.dev; | ||
211 | struct input_absinfo abs; | ||
212 | void __user *p = (void __user *)arg; | ||
213 | int __user *ip = (int __user *)arg; | ||
214 | int i, t, u, v; | ||
215 | |||
216 | if (!evdev->exist) return -ENODEV; | ||
217 | |||
218 | switch (cmd) { | ||
219 | |||
220 | case EVIOCGVERSION: | ||
221 | return put_user(EV_VERSION, ip); | ||
222 | |||
223 | case EVIOCGID: | ||
224 | return copy_to_user(p, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0; | ||
225 | |||
226 | case EVIOCGKEYCODE: | ||
227 | if (get_user(t, ip)) return -EFAULT; | ||
228 | if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; | ||
229 | if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT; | ||
230 | return 0; | ||
231 | |||
232 | case EVIOCSKEYCODE: | ||
233 | if (get_user(t, ip)) return -EFAULT; | ||
234 | if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; | ||
235 | if (get_user(v, ip + 1)) return -EFAULT; | ||
236 | if (v < 0 || v > KEY_MAX) return -EINVAL; | ||
237 | u = SET_INPUT_KEYCODE(dev, t, v); | ||
238 | clear_bit(u, dev->keybit); | ||
239 | set_bit(v, dev->keybit); | ||
240 | for (i = 0; i < dev->keycodemax; i++) | ||
241 | if (INPUT_KEYCODE(dev,i) == u) | ||
242 | set_bit(u, dev->keybit); | ||
243 | return 0; | ||
244 | |||
245 | case EVIOCSFF: | ||
246 | if (dev->upload_effect) { | ||
247 | struct ff_effect effect; | ||
248 | int err; | ||
249 | |||
250 | if (copy_from_user(&effect, p, sizeof(effect))) | ||
251 | return -EFAULT; | ||
252 | err = dev->upload_effect(dev, &effect); | ||
253 | if (put_user(effect.id, &(((struct ff_effect __user *)arg)->id))) | ||
254 | return -EFAULT; | ||
255 | return err; | ||
256 | } | ||
257 | else return -ENOSYS; | ||
258 | |||
259 | case EVIOCRMFF: | ||
260 | if (dev->erase_effect) { | ||
261 | return dev->erase_effect(dev, (int)arg); | ||
262 | } | ||
263 | else return -ENOSYS; | ||
264 | |||
265 | case EVIOCGEFFECTS: | ||
266 | if (put_user(dev->ff_effects_max, ip)) | ||
267 | return -EFAULT; | ||
268 | return 0; | ||
269 | |||
270 | case EVIOCGRAB: | ||
271 | if (arg) { | ||
272 | if (evdev->grab) | ||
273 | return -EBUSY; | ||
274 | if (input_grab_device(&evdev->handle)) | ||
275 | return -EBUSY; | ||
276 | evdev->grab = list; | ||
277 | return 0; | ||
278 | } else { | ||
279 | if (evdev->grab != list) | ||
280 | return -EINVAL; | ||
281 | input_release_device(&evdev->handle); | ||
282 | evdev->grab = NULL; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | default: | ||
287 | |||
288 | if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) | ||
289 | return -EINVAL; | ||
290 | |||
291 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { | ||
292 | |||
293 | long *bits; | ||
294 | int len; | ||
295 | |||
296 | switch (_IOC_NR(cmd) & EV_MAX) { | ||
297 | case 0: bits = dev->evbit; len = EV_MAX; break; | ||
298 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; | ||
299 | case EV_REL: bits = dev->relbit; len = REL_MAX; break; | ||
300 | case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; | ||
301 | case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; | ||
302 | case EV_LED: bits = dev->ledbit; len = LED_MAX; break; | ||
303 | case EV_SND: bits = dev->sndbit; len = SND_MAX; break; | ||
304 | case EV_FF: bits = dev->ffbit; len = FF_MAX; break; | ||
305 | default: return -EINVAL; | ||
306 | } | ||
307 | len = NBITS(len) * sizeof(long); | ||
308 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
309 | return copy_to_user(p, bits, len) ? -EFAULT : len; | ||
310 | } | ||
311 | |||
312 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { | ||
313 | int len; | ||
314 | len = NBITS(KEY_MAX) * sizeof(long); | ||
315 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
316 | return copy_to_user(p, dev->key, len) ? -EFAULT : len; | ||
317 | } | ||
318 | |||
319 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { | ||
320 | int len; | ||
321 | len = NBITS(LED_MAX) * sizeof(long); | ||
322 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
323 | return copy_to_user(p, dev->led, len) ? -EFAULT : len; | ||
324 | } | ||
325 | |||
326 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { | ||
327 | int len; | ||
328 | len = NBITS(SND_MAX) * sizeof(long); | ||
329 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
330 | return copy_to_user(p, dev->snd, len) ? -EFAULT : len; | ||
331 | } | ||
332 | |||
333 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { | ||
334 | int len; | ||
335 | if (!dev->name) return -ENOENT; | ||
336 | len = strlen(dev->name) + 1; | ||
337 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
338 | return copy_to_user(p, dev->name, len) ? -EFAULT : len; | ||
339 | } | ||
340 | |||
341 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { | ||
342 | int len; | ||
343 | if (!dev->phys) return -ENOENT; | ||
344 | len = strlen(dev->phys) + 1; | ||
345 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
346 | return copy_to_user(p, dev->phys, len) ? -EFAULT : len; | ||
347 | } | ||
348 | |||
349 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { | ||
350 | int len; | ||
351 | if (!dev->uniq) return -ENOENT; | ||
352 | len = strlen(dev->uniq) + 1; | ||
353 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
354 | return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; | ||
355 | } | ||
356 | |||
357 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | ||
358 | |||
359 | int t = _IOC_NR(cmd) & ABS_MAX; | ||
360 | |||
361 | abs.value = dev->abs[t]; | ||
362 | abs.minimum = dev->absmin[t]; | ||
363 | abs.maximum = dev->absmax[t]; | ||
364 | abs.fuzz = dev->absfuzz[t]; | ||
365 | abs.flat = dev->absflat[t]; | ||
366 | |||
367 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) | ||
368 | return -EFAULT; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { | ||
374 | |||
375 | int t = _IOC_NR(cmd) & ABS_MAX; | ||
376 | |||
377 | if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) | ||
378 | return -EFAULT; | ||
379 | |||
380 | dev->abs[t] = abs.value; | ||
381 | dev->absmin[t] = abs.minimum; | ||
382 | dev->absmax[t] = abs.maximum; | ||
383 | dev->absfuzz[t] = abs.fuzz; | ||
384 | dev->absflat[t] = abs.flat; | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | } | ||
389 | return -EINVAL; | ||
390 | } | ||
391 | |||
392 | static struct file_operations evdev_fops = { | ||
393 | .owner = THIS_MODULE, | ||
394 | .read = evdev_read, | ||
395 | .write = evdev_write, | ||
396 | .poll = evdev_poll, | ||
397 | .open = evdev_open, | ||
398 | .release = evdev_release, | ||
399 | .ioctl = evdev_ioctl, | ||
400 | .fasync = evdev_fasync, | ||
401 | .flush = evdev_flush | ||
402 | }; | ||
403 | |||
404 | static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | ||
405 | { | ||
406 | struct evdev *evdev; | ||
407 | int minor; | ||
408 | |||
409 | for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); | ||
410 | if (minor == EVDEV_MINORS) { | ||
411 | printk(KERN_ERR "evdev: no more free evdev devices\n"); | ||
412 | return NULL; | ||
413 | } | ||
414 | |||
415 | if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL))) | ||
416 | return NULL; | ||
417 | memset(evdev, 0, sizeof(struct evdev)); | ||
418 | |||
419 | INIT_LIST_HEAD(&evdev->list); | ||
420 | init_waitqueue_head(&evdev->wait); | ||
421 | |||
422 | evdev->exist = 1; | ||
423 | evdev->minor = minor; | ||
424 | evdev->handle.dev = dev; | ||
425 | evdev->handle.name = evdev->name; | ||
426 | evdev->handle.handler = handler; | ||
427 | evdev->handle.private = evdev; | ||
428 | sprintf(evdev->name, "event%d", minor); | ||
429 | |||
430 | evdev_table[minor] = evdev; | ||
431 | |||
432 | devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), | ||
433 | S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); | ||
434 | class_simple_device_add(input_class, | ||
435 | MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), | ||
436 | dev->dev, "event%d", minor); | ||
437 | |||
438 | return &evdev->handle; | ||
439 | } | ||
440 | |||
441 | static void evdev_disconnect(struct input_handle *handle) | ||
442 | { | ||
443 | struct evdev *evdev = handle->private; | ||
444 | struct evdev_list *list; | ||
445 | |||
446 | class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); | ||
447 | devfs_remove("input/event%d", evdev->minor); | ||
448 | evdev->exist = 0; | ||
449 | |||
450 | if (evdev->open) { | ||
451 | input_close_device(handle); | ||
452 | wake_up_interruptible(&evdev->wait); | ||
453 | list_for_each_entry(list, &evdev->list, node) | ||
454 | kill_fasync(&list->fasync, SIGIO, POLL_HUP); | ||
455 | } else | ||
456 | evdev_free(evdev); | ||
457 | } | ||
458 | |||
459 | static struct input_device_id evdev_ids[] = { | ||
460 | { .driver_info = 1 }, /* Matches all devices */ | ||
461 | { }, /* Terminating zero entry */ | ||
462 | }; | ||
463 | |||
464 | MODULE_DEVICE_TABLE(input, evdev_ids); | ||
465 | |||
466 | static struct input_handler evdev_handler = { | ||
467 | .event = evdev_event, | ||
468 | .connect = evdev_connect, | ||
469 | .disconnect = evdev_disconnect, | ||
470 | .fops = &evdev_fops, | ||
471 | .minor = EVDEV_MINOR_BASE, | ||
472 | .name = "evdev", | ||
473 | .id_table = evdev_ids, | ||
474 | }; | ||
475 | |||
476 | static int __init evdev_init(void) | ||
477 | { | ||
478 | input_register_handler(&evdev_handler); | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static void __exit evdev_exit(void) | ||
483 | { | ||
484 | input_unregister_handler(&evdev_handler); | ||
485 | } | ||
486 | |||
487 | module_init(evdev_init); | ||
488 | module_exit(evdev_exit); | ||
489 | |||
490 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
491 | MODULE_DESCRIPTION("Input driver event char devices"); | ||
492 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig new file mode 100644 index 000000000000..6282f460aba0 --- /dev/null +++ b/drivers/input/gameport/Kconfig | |||
@@ -0,0 +1,90 @@ | |||
1 | # | ||
2 | # Gameport configuration | ||
3 | # | ||
4 | config GAMEPORT | ||
5 | tristate "Gameport support" | ||
6 | ---help--- | ||
7 | Gameport support is for the standard 15-pin PC gameport. If you | ||
8 | have a joystick, gamepad, gameport card, a soundcard with a gameport | ||
9 | or anything else that uses the gameport, say Y or M here and also to | ||
10 | at least one of the hardware specific drivers. | ||
11 | |||
12 | For Ensoniq AudioPCI (ES1370), AudioPCI 97 (ES1371), ESS Solo1, | ||
13 | S3 SonicVibes, Trident 4DWave, SiS7018, and ALi 5451 gameport | ||
14 | support is provided by the sound drivers, so you won't need any | ||
15 | from the below listed modules. You still need to say Y here. | ||
16 | |||
17 | If unsure, say Y. | ||
18 | |||
19 | To compile this driver as a module, choose M here: the | ||
20 | module will be called gameport. | ||
21 | |||
22 | if GAMEPORT | ||
23 | |||
24 | config GAMEPORT_NS558 | ||
25 | tristate "Classic ISA and PnP gameport support" | ||
26 | help | ||
27 | Say Y here if you have an ISA or PnP gameport. | ||
28 | |||
29 | If unsure, say Y. | ||
30 | |||
31 | To compile this driver as a module, choose M here: the | ||
32 | module will be called ns558. | ||
33 | |||
34 | config GAMEPORT_L4 | ||
35 | tristate "PDPI Lightning 4 gamecard support" | ||
36 | help | ||
37 | Say Y here if you have a PDPI Lightning 4 gamecard. | ||
38 | |||
39 | To compile this driver as a module, choose M here: the | ||
40 | module will be called lightning. | ||
41 | |||
42 | config GAMEPORT_EMU10K1 | ||
43 | tristate "SB Live and Audigy gameport support" | ||
44 | depends on PCI | ||
45 | help | ||
46 | Say Y here if you have a SoundBlaster Live! or SoundBlaster | ||
47 | Audigy card and want to use its gameport. | ||
48 | |||
49 | To compile this driver as a module, choose M here: the | ||
50 | module will be called emu10k1-gp. | ||
51 | |||
52 | config GAMEPORT_VORTEX | ||
53 | tristate "Aureal Vortex, Vortex 2 gameport support" | ||
54 | depends on PCI | ||
55 | help | ||
56 | Say Y here if you have an Aureal Vortex 1 or 2 card and want | ||
57 | to use its gameport. | ||
58 | |||
59 | To compile this driver as a module, choose M here: the | ||
60 | module will be called vortex. | ||
61 | |||
62 | config GAMEPORT_FM801 | ||
63 | tristate "ForteMedia FM801 gameport support" | ||
64 | depends on PCI | ||
65 | |||
66 | config GAMEPORT_CS461X | ||
67 | tristate "Crystal SoundFusion gameport support" | ||
68 | depends on PCI | ||
69 | |||
70 | endif | ||
71 | |||
72 | # Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on | ||
73 | # in every .config. Please don't touch it. It is here to handle an | ||
74 | # unusual dependency between GAMEPORT and sound drivers. | ||
75 | # | ||
76 | # Some sound drivers call gameport functions. If GAMEPORT is | ||
77 | # not selected, empty stubs are provided for the functions and all is | ||
78 | # well. | ||
79 | # If GAMEPORT is built in, everything is fine. | ||
80 | # If GAMEPORT is a module, however, it would need to be loaded for the | ||
81 | # sound driver to be able to link properly. Therefore, the sound | ||
82 | # driver must be a module as well in that case. Since there's no way | ||
83 | # to express that directly in Kconfig, we use SOUND_GAMEPORT to | ||
84 | # express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm', | ||
85 | # anything that depends on SOUND_GAMEPORT must be 'm' as well. if | ||
86 | # GAMEPORT is 'y' or 'n', it can be anything". | ||
87 | config SOUND_GAMEPORT | ||
88 | tristate | ||
89 | default m if GAMEPORT=m | ||
90 | default y | ||
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile new file mode 100644 index 000000000000..5367b4267adf --- /dev/null +++ b/drivers/input/gameport/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for the gameport drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_GAMEPORT) += gameport.o | ||
8 | obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o | ||
9 | obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o | ||
10 | obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o | ||
11 | obj-$(CONFIG_GAMEPORT_L4) += lightning.o | ||
12 | obj-$(CONFIG_GAMEPORT_NS558) += ns558.o | ||
13 | obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o | ||
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c new file mode 100644 index 000000000000..d4013ff98623 --- /dev/null +++ b/drivers/input/gameport/cs461x.c | |||
@@ -0,0 +1,322 @@ | |||
1 | /* | ||
2 | The all defines and part of code (such as cs461x_*) are | ||
3 | contributed from ALSA 0.5.8 sources. | ||
4 | See http://www.alsa-project.org/ for sources | ||
5 | |||
6 | Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610 | ||
7 | */ | ||
8 | |||
9 | #include <asm/io.h> | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/ioport.h> | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/gameport.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/pci.h> | ||
18 | |||
19 | MODULE_AUTHOR("Victor Krapivin"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | |||
22 | /* | ||
23 | These options are experimental | ||
24 | |||
25 | #define CS461X_FULL_MAP | ||
26 | */ | ||
27 | |||
28 | |||
29 | #ifndef PCI_VENDOR_ID_CIRRUS | ||
30 | #define PCI_VENDOR_ID_CIRRUS 0x1013 | ||
31 | #endif | ||
32 | #ifndef PCI_DEVICE_ID_CIRRUS_4610 | ||
33 | #define PCI_DEVICE_ID_CIRRUS_4610 0x6001 | ||
34 | #endif | ||
35 | #ifndef PCI_DEVICE_ID_CIRRUS_4612 | ||
36 | #define PCI_DEVICE_ID_CIRRUS_4612 0x6003 | ||
37 | #endif | ||
38 | #ifndef PCI_DEVICE_ID_CIRRUS_4615 | ||
39 | #define PCI_DEVICE_ID_CIRRUS_4615 0x6004 | ||
40 | #endif | ||
41 | |||
42 | /* Registers */ | ||
43 | |||
44 | #define BA0_JSPT 0x00000480 | ||
45 | #define BA0_JSCTL 0x00000484 | ||
46 | #define BA0_JSC1 0x00000488 | ||
47 | #define BA0_JSC2 0x0000048C | ||
48 | #define BA0_JSIO 0x000004A0 | ||
49 | |||
50 | /* Bits for JSPT */ | ||
51 | |||
52 | #define JSPT_CAX 0x00000001 | ||
53 | #define JSPT_CAY 0x00000002 | ||
54 | #define JSPT_CBX 0x00000004 | ||
55 | #define JSPT_CBY 0x00000008 | ||
56 | #define JSPT_BA1 0x00000010 | ||
57 | #define JSPT_BA2 0x00000020 | ||
58 | #define JSPT_BB1 0x00000040 | ||
59 | #define JSPT_BB2 0x00000080 | ||
60 | |||
61 | /* Bits for JSCTL */ | ||
62 | |||
63 | #define JSCTL_SP_MASK 0x00000003 | ||
64 | #define JSCTL_SP_SLOW 0x00000000 | ||
65 | #define JSCTL_SP_MEDIUM_SLOW 0x00000001 | ||
66 | #define JSCTL_SP_MEDIUM_FAST 0x00000002 | ||
67 | #define JSCTL_SP_FAST 0x00000003 | ||
68 | #define JSCTL_ARE 0x00000004 | ||
69 | |||
70 | /* Data register pairs masks */ | ||
71 | |||
72 | #define JSC1_Y1V_MASK 0x0000FFFF | ||
73 | #define JSC1_X1V_MASK 0xFFFF0000 | ||
74 | #define JSC1_Y1V_SHIFT 0 | ||
75 | #define JSC1_X1V_SHIFT 16 | ||
76 | #define JSC2_Y2V_MASK 0x0000FFFF | ||
77 | #define JSC2_X2V_MASK 0xFFFF0000 | ||
78 | #define JSC2_Y2V_SHIFT 0 | ||
79 | #define JSC2_X2V_SHIFT 16 | ||
80 | |||
81 | /* JS GPIO */ | ||
82 | |||
83 | #define JSIO_DAX 0x00000001 | ||
84 | #define JSIO_DAY 0x00000002 | ||
85 | #define JSIO_DBX 0x00000004 | ||
86 | #define JSIO_DBY 0x00000008 | ||
87 | #define JSIO_AXOE 0x00000010 | ||
88 | #define JSIO_AYOE 0x00000020 | ||
89 | #define JSIO_BXOE 0x00000040 | ||
90 | #define JSIO_BYOE 0x00000080 | ||
91 | |||
92 | /* | ||
93 | The card initialization code is obfuscated; the module cs461x | ||
94 | need to be loaded after ALSA modules initialized and something | ||
95 | played on the CS 4610 chip (see sources for details of CS4610 | ||
96 | initialization code from ALSA) | ||
97 | */ | ||
98 | |||
99 | /* Card specific definitions */ | ||
100 | |||
101 | #define CS461X_BA0_SIZE 0x2000 | ||
102 | #define CS461X_BA1_DATA0_SIZE 0x3000 | ||
103 | #define CS461X_BA1_DATA1_SIZE 0x3800 | ||
104 | #define CS461X_BA1_PRG_SIZE 0x7000 | ||
105 | #define CS461X_BA1_REG_SIZE 0x0100 | ||
106 | |||
107 | #define BA1_SP_DMEM0 0x00000000 | ||
108 | #define BA1_SP_DMEM1 0x00010000 | ||
109 | #define BA1_SP_PMEM 0x00020000 | ||
110 | #define BA1_SP_REG 0x00030000 | ||
111 | |||
112 | #define BA1_DWORD_SIZE (13 * 1024 + 512) | ||
113 | #define BA1_MEMORY_COUNT 3 | ||
114 | |||
115 | /* | ||
116 | Only one CS461x card is still suppoted; the code requires | ||
117 | redesign to avoid this limitatuion. | ||
118 | */ | ||
119 | |||
120 | static unsigned long ba0_addr; | ||
121 | static unsigned int __iomem *ba0; | ||
122 | |||
123 | #ifdef CS461X_FULL_MAP | ||
124 | static unsigned long ba1_addr; | ||
125 | static union ba1_t { | ||
126 | struct { | ||
127 | unsigned int __iomem *data0; | ||
128 | unsigned int __iomem *data1; | ||
129 | unsigned int __iomem *pmem; | ||
130 | unsigned int __iomem *reg; | ||
131 | } name; | ||
132 | unsigned int __iomem *idx[4]; | ||
133 | } ba1; | ||
134 | |||
135 | static void cs461x_poke(unsigned long reg, unsigned int val) | ||
136 | { | ||
137 | writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]); | ||
138 | } | ||
139 | |||
140 | static unsigned int cs461x_peek(unsigned long reg) | ||
141 | { | ||
142 | return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]); | ||
143 | } | ||
144 | |||
145 | #endif | ||
146 | |||
147 | static void cs461x_pokeBA0(unsigned long reg, unsigned int val) | ||
148 | { | ||
149 | writel(val, &ba0[reg >> 2]); | ||
150 | } | ||
151 | |||
152 | static unsigned int cs461x_peekBA0(unsigned long reg) | ||
153 | { | ||
154 | return readl(&ba0[reg >> 2]); | ||
155 | } | ||
156 | |||
157 | static int cs461x_free(struct pci_dev *pdev) | ||
158 | { | ||
159 | struct gameport *port = pci_get_drvdata(pdev); | ||
160 | |||
161 | if (port) | ||
162 | gameport_unregister_port(port); | ||
163 | |||
164 | if (ba0) iounmap(ba0); | ||
165 | #ifdef CS461X_FULL_MAP | ||
166 | if (ba1.name.data0) iounmap(ba1.name.data0); | ||
167 | if (ba1.name.data1) iounmap(ba1.name.data1); | ||
168 | if (ba1.name.pmem) iounmap(ba1.name.pmem); | ||
169 | if (ba1.name.reg) iounmap(ba1.name.reg); | ||
170 | #endif | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static void cs461x_gameport_trigger(struct gameport *gameport) | ||
175 | { | ||
176 | cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF); | ||
177 | } | ||
178 | |||
179 | static unsigned char cs461x_gameport_read(struct gameport *gameport) | ||
180 | { | ||
181 | return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io); | ||
182 | } | ||
183 | |||
184 | static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons) | ||
185 | { | ||
186 | unsigned js1, js2, jst; | ||
187 | |||
188 | js1 = cs461x_peekBA0(BA0_JSC1); | ||
189 | js2 = cs461x_peekBA0(BA0_JSC2); | ||
190 | jst = cs461x_peekBA0(BA0_JSPT); | ||
191 | |||
192 | *buttons = (~jst >> 4) & 0x0F; | ||
193 | |||
194 | axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF; | ||
195 | axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF; | ||
196 | axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF; | ||
197 | axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF; | ||
198 | |||
199 | for(jst=0;jst<4;++jst) | ||
200 | if(axes[jst]==0xFFFF) axes[jst] = -1; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int cs461x_gameport_open(struct gameport *gameport, int mode) | ||
205 | { | ||
206 | switch (mode) { | ||
207 | case GAMEPORT_MODE_COOKED: | ||
208 | case GAMEPORT_MODE_RAW: | ||
209 | return 0; | ||
210 | default: | ||
211 | return -1; | ||
212 | } | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static struct pci_device_id cs461x_pci_tbl[] = { | ||
217 | { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */ | ||
218 | { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */ | ||
219 | { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */ | ||
220 | { 0, } | ||
221 | }; | ||
222 | MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl); | ||
223 | |||
224 | static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
225 | { | ||
226 | int rc; | ||
227 | struct gameport* port; | ||
228 | |||
229 | rc = pci_enable_device(pdev); | ||
230 | if (rc) { | ||
231 | printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n", | ||
232 | pdev->bus->number, pdev->devfn, rc); | ||
233 | return rc; | ||
234 | } | ||
235 | |||
236 | ba0_addr = pci_resource_start(pdev, 0); | ||
237 | #ifdef CS461X_FULL_MAP | ||
238 | ba1_addr = pci_resource_start(pdev, 1); | ||
239 | #endif | ||
240 | if (ba0_addr == 0 || ba0_addr == ~0 | ||
241 | #ifdef CS461X_FULL_MAP | ||
242 | || ba1_addr == 0 || ba1_addr == ~0 | ||
243 | #endif | ||
244 | ) { | ||
245 | printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr); | ||
246 | #ifdef CS461X_FULL_MAP | ||
247 | printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr); | ||
248 | #endif | ||
249 | cs461x_free(pdev); | ||
250 | return -ENOMEM; | ||
251 | } | ||
252 | |||
253 | ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE); | ||
254 | #ifdef CS461X_FULL_MAP | ||
255 | ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); | ||
256 | ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); | ||
257 | ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); | ||
258 | ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); | ||
259 | |||
260 | if (ba0 == NULL || ba1.name.data0 == NULL || | ||
261 | ba1.name.data1 == NULL || ba1.name.pmem == NULL || | ||
262 | ba1.name.reg == NULL) { | ||
263 | cs461x_free(pdev); | ||
264 | return -ENOMEM; | ||
265 | } | ||
266 | #else | ||
267 | if (ba0 == NULL) { | ||
268 | cs461x_free(pdev); | ||
269 | return -ENOMEM; | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | if (!(port = gameport_allocate_port())) { | ||
274 | printk(KERN_ERR "cs461x: Memory allocation failed\n"); | ||
275 | cs461x_free(pdev); | ||
276 | return -ENOMEM; | ||
277 | } | ||
278 | |||
279 | pci_set_drvdata(pdev, port); | ||
280 | |||
281 | port->open = cs461x_gameport_open; | ||
282 | port->trigger = cs461x_gameport_trigger; | ||
283 | port->read = cs461x_gameport_read; | ||
284 | port->cooked_read = cs461x_gameport_cooked_read; | ||
285 | |||
286 | gameport_set_name(port, "CS416x"); | ||
287 | gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev)); | ||
288 | port->dev.parent = &pdev->dev; | ||
289 | |||
290 | cs461x_pokeBA0(BA0_JSIO, 0xFF); // ? | ||
291 | cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW); | ||
292 | |||
293 | gameport_register_port(port); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static void __devexit cs461x_pci_remove(struct pci_dev *pdev) | ||
299 | { | ||
300 | cs461x_free(pdev); | ||
301 | } | ||
302 | |||
303 | static struct pci_driver cs461x_pci_driver = { | ||
304 | .name = "CS461x_gameport", | ||
305 | .id_table = cs461x_pci_tbl, | ||
306 | .probe = cs461x_pci_probe, | ||
307 | .remove = __devexit_p(cs461x_pci_remove), | ||
308 | }; | ||
309 | |||
310 | static int __init cs461x_init(void) | ||
311 | { | ||
312 | return pci_register_driver(&cs461x_pci_driver); | ||
313 | } | ||
314 | |||
315 | static void __exit cs461x_exit(void) | ||
316 | { | ||
317 | pci_unregister_driver(&cs461x_pci_driver); | ||
318 | } | ||
319 | |||
320 | module_init(cs461x_init); | ||
321 | module_exit(cs461x_exit); | ||
322 | |||
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c new file mode 100644 index 000000000000..a0118038330a --- /dev/null +++ b/drivers/input/gameport/emu10k1-gp.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * $Id: emu10k1-gp.c,v 1.8 2002/01/22 20:40:46 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * EMU10k1 - SB Live / Audigy - gameport 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 <asm/io.h> | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/ioport.h> | ||
35 | #include <linux/config.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/gameport.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/pci.h> | ||
40 | |||
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
42 | MODULE_DESCRIPTION("EMU10k1 gameport driver"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | struct emu { | ||
46 | struct pci_dev *dev; | ||
47 | struct gameport *gameport; | ||
48 | int io; | ||
49 | int size; | ||
50 | }; | ||
51 | |||
52 | static struct pci_device_id emu_tbl[] = { | ||
53 | |||
54 | { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ | ||
55 | { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ | ||
56 | { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ | ||
57 | { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */ | ||
58 | { 0, } | ||
59 | }; | ||
60 | |||
61 | MODULE_DEVICE_TABLE(pci, emu_tbl); | ||
62 | |||
63 | static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
64 | { | ||
65 | int ioport, iolen; | ||
66 | struct emu *emu; | ||
67 | struct gameport *port; | ||
68 | |||
69 | if (pci_enable_device(pdev)) | ||
70 | return -EBUSY; | ||
71 | |||
72 | ioport = pci_resource_start(pdev, 0); | ||
73 | iolen = pci_resource_len(pdev, 0); | ||
74 | |||
75 | if (!request_region(ioport, iolen, "emu10k1-gp")) | ||
76 | return -EBUSY; | ||
77 | |||
78 | emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL); | ||
79 | port = gameport_allocate_port(); | ||
80 | if (!emu || !port) { | ||
81 | printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n"); | ||
82 | release_region(ioport, iolen); | ||
83 | kfree(emu); | ||
84 | gameport_free_port(port); | ||
85 | return -ENOMEM; | ||
86 | } | ||
87 | |||
88 | emu->io = ioport; | ||
89 | emu->size = iolen; | ||
90 | emu->dev = pdev; | ||
91 | emu->gameport = port; | ||
92 | |||
93 | gameport_set_name(port, "EMU10K1"); | ||
94 | gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev)); | ||
95 | port->dev.parent = &pdev->dev; | ||
96 | port->io = ioport; | ||
97 | |||
98 | pci_set_drvdata(pdev, emu); | ||
99 | |||
100 | gameport_register_port(port); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static void __devexit emu_remove(struct pci_dev *pdev) | ||
106 | { | ||
107 | struct emu *emu = pci_get_drvdata(pdev); | ||
108 | |||
109 | gameport_unregister_port(emu->gameport); | ||
110 | release_region(emu->io, emu->size); | ||
111 | kfree(emu); | ||
112 | } | ||
113 | |||
114 | static struct pci_driver emu_driver = { | ||
115 | .name = "Emu10k1_gameport", | ||
116 | .id_table = emu_tbl, | ||
117 | .probe = emu_probe, | ||
118 | .remove = __devexit_p(emu_remove), | ||
119 | }; | ||
120 | |||
121 | static int __init emu_init(void) | ||
122 | { | ||
123 | return pci_register_driver(&emu_driver); | ||
124 | } | ||
125 | |||
126 | static void __exit emu_exit(void) | ||
127 | { | ||
128 | pci_unregister_driver(&emu_driver); | ||
129 | } | ||
130 | |||
131 | module_init(emu_init); | ||
132 | module_exit(emu_exit); | ||
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c new file mode 100644 index 000000000000..57615bc63906 --- /dev/null +++ b/drivers/input/gameport/fm801-gp.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * FM801 gameport driver for Linux | ||
3 | * | ||
4 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/gameport.h> | ||
33 | |||
34 | #define PCI_VENDOR_ID_FORTEMEDIA 0x1319 | ||
35 | #define PCI_DEVICE_ID_FM801_GP 0x0802 | ||
36 | |||
37 | #define HAVE_COOKED | ||
38 | |||
39 | struct fm801_gp { | ||
40 | struct gameport *gameport; | ||
41 | struct resource *res_port; | ||
42 | }; | ||
43 | |||
44 | #ifdef HAVE_COOKED | ||
45 | static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons) | ||
46 | { | ||
47 | unsigned short w; | ||
48 | |||
49 | w = inw(gameport->io + 2); | ||
50 | *buttons = (~w >> 14) & 0x03; | ||
51 | axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); | ||
52 | w = inw(gameport->io + 4); | ||
53 | axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); | ||
54 | w = inw(gameport->io + 6); | ||
55 | *buttons |= ((~w >> 14) & 0x03) << 2; | ||
56 | axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); | ||
57 | w = inw(gameport->io + 8); | ||
58 | axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); | ||
59 | outw(0xff, gameport->io); /* reset */ | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | #endif | ||
64 | |||
65 | static int fm801_gp_open(struct gameport *gameport, int mode) | ||
66 | { | ||
67 | switch (mode) { | ||
68 | #ifdef HAVE_COOKED | ||
69 | case GAMEPORT_MODE_COOKED: | ||
70 | return 0; | ||
71 | #endif | ||
72 | case GAMEPORT_MODE_RAW: | ||
73 | return 0; | ||
74 | default: | ||
75 | return -1; | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id) | ||
82 | { | ||
83 | struct fm801_gp *gp; | ||
84 | struct gameport *port; | ||
85 | |||
86 | gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL); | ||
87 | port = gameport_allocate_port(); | ||
88 | if (!gp || !port) { | ||
89 | printk(KERN_ERR "fm801-gp: Memory allocation failed\n"); | ||
90 | kfree(gp); | ||
91 | gameport_free_port(port); | ||
92 | return -ENOMEM; | ||
93 | } | ||
94 | |||
95 | pci_enable_device(pci); | ||
96 | |||
97 | port->open = fm801_gp_open; | ||
98 | #ifdef HAVE_COOKED | ||
99 | port->cooked_read = fm801_gp_cooked_read; | ||
100 | #endif | ||
101 | gameport_set_name(port, "FM801"); | ||
102 | gameport_set_phys(port, "pci%s/gameport0", pci_name(pci)); | ||
103 | port->dev.parent = &pci->dev; | ||
104 | port->io = pci_resource_start(pci, 0); | ||
105 | |||
106 | gp->gameport = port; | ||
107 | gp->res_port = request_region(port->io, 0x10, "FM801 GP"); | ||
108 | if (!gp->res_port) { | ||
109 | kfree(gp); | ||
110 | gameport_free_port(port); | ||
111 | printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n", | ||
112 | port->io, port->io + 0x0f); | ||
113 | return -EBUSY; | ||
114 | } | ||
115 | |||
116 | pci_set_drvdata(pci, gp); | ||
117 | |||
118 | outb(0x60, port->io + 0x0d); /* enable joystick 1 and 2 */ | ||
119 | gameport_register_port(port); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void __devexit fm801_gp_remove(struct pci_dev *pci) | ||
125 | { | ||
126 | struct fm801_gp *gp = pci_get_drvdata(pci); | ||
127 | |||
128 | if (gp) { | ||
129 | gameport_unregister_port(gp->gameport); | ||
130 | release_resource(gp->res_port); | ||
131 | kfree(gp); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static struct pci_device_id fm801_gp_id_table[] = { | ||
136 | { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
137 | { 0 } | ||
138 | }; | ||
139 | |||
140 | static struct pci_driver fm801_gp_driver = { | ||
141 | .name = "FM801_gameport", | ||
142 | .id_table = fm801_gp_id_table, | ||
143 | .probe = fm801_gp_probe, | ||
144 | .remove = __devexit_p(fm801_gp_remove), | ||
145 | }; | ||
146 | |||
147 | static int __init fm801_gp_init(void) | ||
148 | { | ||
149 | return pci_register_driver(&fm801_gp_driver); | ||
150 | } | ||
151 | |||
152 | static void __exit fm801_gp_exit(void) | ||
153 | { | ||
154 | pci_unregister_driver(&fm801_gp_driver); | ||
155 | } | ||
156 | |||
157 | module_init(fm801_gp_init); | ||
158 | module_exit(fm801_gp_exit); | ||
159 | |||
160 | MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); | ||
161 | |||
162 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | ||
163 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c new file mode 100644 index 000000000000..f20c3f23388b --- /dev/null +++ b/drivers/input/gameport/gameport.c | |||
@@ -0,0 +1,797 @@ | |||
1 | /* | ||
2 | * Generic gameport layer | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * Copyright (c) 2005 Dmitry Torokhov | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/stddef.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/gameport.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <linux/completion.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/smp_lock.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/delay.h> | ||
25 | |||
26 | /*#include <asm/io.h>*/ | ||
27 | |||
28 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
29 | MODULE_DESCRIPTION("Generic gameport layer"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | EXPORT_SYMBOL(__gameport_register_port); | ||
33 | EXPORT_SYMBOL(gameport_unregister_port); | ||
34 | EXPORT_SYMBOL(__gameport_register_driver); | ||
35 | EXPORT_SYMBOL(gameport_unregister_driver); | ||
36 | EXPORT_SYMBOL(gameport_open); | ||
37 | EXPORT_SYMBOL(gameport_close); | ||
38 | EXPORT_SYMBOL(gameport_rescan); | ||
39 | EXPORT_SYMBOL(gameport_cooked_read); | ||
40 | EXPORT_SYMBOL(gameport_set_name); | ||
41 | EXPORT_SYMBOL(gameport_set_phys); | ||
42 | EXPORT_SYMBOL(gameport_start_polling); | ||
43 | EXPORT_SYMBOL(gameport_stop_polling); | ||
44 | |||
45 | /* | ||
46 | * gameport_sem protects entire gameport subsystem and is taken | ||
47 | * every time gameport port or driver registrered or unregistered. | ||
48 | */ | ||
49 | static DECLARE_MUTEX(gameport_sem); | ||
50 | |||
51 | static LIST_HEAD(gameport_list); | ||
52 | |||
53 | static struct bus_type gameport_bus = { | ||
54 | .name = "gameport", | ||
55 | }; | ||
56 | |||
57 | static void gameport_add_port(struct gameport *gameport); | ||
58 | static void gameport_destroy_port(struct gameport *gameport); | ||
59 | static void gameport_reconnect_port(struct gameport *gameport); | ||
60 | static void gameport_disconnect_port(struct gameport *gameport); | ||
61 | |||
62 | #if defined(__i386__) | ||
63 | |||
64 | #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0)) | ||
65 | #define GET_TIME(x) do { x = get_time_pit(); } while (0) | ||
66 | |||
67 | static unsigned int get_time_pit(void) | ||
68 | { | ||
69 | extern spinlock_t i8253_lock; | ||
70 | unsigned long flags; | ||
71 | unsigned int count; | ||
72 | |||
73 | spin_lock_irqsave(&i8253_lock, flags); | ||
74 | outb_p(0x00, 0x43); | ||
75 | count = inb_p(0x40); | ||
76 | count |= inb_p(0x40) << 8; | ||
77 | spin_unlock_irqrestore(&i8253_lock, flags); | ||
78 | |||
79 | return count; | ||
80 | } | ||
81 | |||
82 | #endif | ||
83 | |||
84 | |||
85 | |||
86 | /* | ||
87 | * gameport_measure_speed() measures the gameport i/o speed. | ||
88 | */ | ||
89 | |||
90 | static int gameport_measure_speed(struct gameport *gameport) | ||
91 | { | ||
92 | #if defined(__i386__) | ||
93 | |||
94 | unsigned int i, t, t1, t2, t3, tx; | ||
95 | unsigned long flags; | ||
96 | |||
97 | if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW)) | ||
98 | return 0; | ||
99 | |||
100 | tx = 1 << 30; | ||
101 | |||
102 | for(i = 0; i < 50; i++) { | ||
103 | local_irq_save(flags); | ||
104 | GET_TIME(t1); | ||
105 | for (t = 0; t < 50; t++) gameport_read(gameport); | ||
106 | GET_TIME(t2); | ||
107 | GET_TIME(t3); | ||
108 | local_irq_restore(flags); | ||
109 | udelay(i * 10); | ||
110 | if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; | ||
111 | } | ||
112 | |||
113 | gameport_close(gameport); | ||
114 | return 59659 / (tx < 1 ? 1 : tx); | ||
115 | |||
116 | #elif defined (__x86_64__) | ||
117 | |||
118 | unsigned int i, t; | ||
119 | unsigned long tx, t1, t2, flags; | ||
120 | |||
121 | if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW)) | ||
122 | return 0; | ||
123 | |||
124 | tx = 1 << 30; | ||
125 | |||
126 | for(i = 0; i < 50; i++) { | ||
127 | local_irq_save(flags); | ||
128 | rdtscl(t1); | ||
129 | for (t = 0; t < 50; t++) gameport_read(gameport); | ||
130 | rdtscl(t2); | ||
131 | local_irq_restore(flags); | ||
132 | udelay(i * 10); | ||
133 | if (t2 - t1 < tx) tx = t2 - t1; | ||
134 | } | ||
135 | |||
136 | gameport_close(gameport); | ||
137 | return (cpu_data[_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx); | ||
138 | |||
139 | #else | ||
140 | |||
141 | unsigned int j, t = 0; | ||
142 | |||
143 | if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW)) | ||
144 | return 0; | ||
145 | |||
146 | j = jiffies; while (j == jiffies); | ||
147 | j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); } | ||
148 | |||
149 | gameport_close(gameport); | ||
150 | return t * HZ / 1000; | ||
151 | |||
152 | #endif | ||
153 | } | ||
154 | |||
155 | void gameport_start_polling(struct gameport *gameport) | ||
156 | { | ||
157 | spin_lock(&gameport->timer_lock); | ||
158 | |||
159 | if (!gameport->poll_cnt++) { | ||
160 | BUG_ON(!gameport->poll_handler); | ||
161 | BUG_ON(!gameport->poll_interval); | ||
162 | mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval)); | ||
163 | } | ||
164 | |||
165 | spin_unlock(&gameport->timer_lock); | ||
166 | } | ||
167 | |||
168 | void gameport_stop_polling(struct gameport *gameport) | ||
169 | { | ||
170 | spin_lock(&gameport->timer_lock); | ||
171 | |||
172 | if (!--gameport->poll_cnt) | ||
173 | del_timer(&gameport->poll_timer); | ||
174 | |||
175 | spin_unlock(&gameport->timer_lock); | ||
176 | } | ||
177 | |||
178 | static void gameport_run_poll_handler(unsigned long d) | ||
179 | { | ||
180 | struct gameport *gameport = (struct gameport *)d; | ||
181 | |||
182 | gameport->poll_handler(gameport); | ||
183 | if (gameport->poll_cnt) | ||
184 | mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval)); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * Basic gameport -> driver core mappings | ||
189 | */ | ||
190 | |||
191 | static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv) | ||
192 | { | ||
193 | down_write(&gameport_bus.subsys.rwsem); | ||
194 | |||
195 | gameport->dev.driver = &drv->driver; | ||
196 | if (drv->connect(gameport, drv)) { | ||
197 | gameport->dev.driver = NULL; | ||
198 | goto out; | ||
199 | } | ||
200 | device_bind_driver(&gameport->dev); | ||
201 | out: | ||
202 | up_write(&gameport_bus.subsys.rwsem); | ||
203 | } | ||
204 | |||
205 | static void gameport_release_driver(struct gameport *gameport) | ||
206 | { | ||
207 | down_write(&gameport_bus.subsys.rwsem); | ||
208 | device_release_driver(&gameport->dev); | ||
209 | up_write(&gameport_bus.subsys.rwsem); | ||
210 | } | ||
211 | |||
212 | static void gameport_find_driver(struct gameport *gameport) | ||
213 | { | ||
214 | down_write(&gameport_bus.subsys.rwsem); | ||
215 | device_attach(&gameport->dev); | ||
216 | up_write(&gameport_bus.subsys.rwsem); | ||
217 | } | ||
218 | |||
219 | |||
220 | /* | ||
221 | * Gameport event processing. | ||
222 | */ | ||
223 | |||
224 | enum gameport_event_type { | ||
225 | GAMEPORT_RESCAN, | ||
226 | GAMEPORT_RECONNECT, | ||
227 | GAMEPORT_REGISTER_PORT, | ||
228 | GAMEPORT_REGISTER_DRIVER, | ||
229 | }; | ||
230 | |||
231 | struct gameport_event { | ||
232 | enum gameport_event_type type; | ||
233 | void *object; | ||
234 | struct module *owner; | ||
235 | struct list_head node; | ||
236 | }; | ||
237 | |||
238 | static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */ | ||
239 | static LIST_HEAD(gameport_event_list); | ||
240 | static DECLARE_WAIT_QUEUE_HEAD(gameport_wait); | ||
241 | static DECLARE_COMPLETION(gameport_exited); | ||
242 | static int gameport_pid; | ||
243 | |||
244 | static void gameport_queue_event(void *object, struct module *owner, | ||
245 | enum gameport_event_type event_type) | ||
246 | { | ||
247 | unsigned long flags; | ||
248 | struct gameport_event *event; | ||
249 | |||
250 | spin_lock_irqsave(&gameport_event_lock, flags); | ||
251 | |||
252 | /* | ||
253 | * Scan event list for the other events for the same gameport port, | ||
254 | * starting with the most recent one. If event is the same we | ||
255 | * do not need add new one. If event is of different type we | ||
256 | * need to add this event and should not look further because | ||
257 | * we need to preseve sequence of distinct events. | ||
258 | */ | ||
259 | list_for_each_entry_reverse(event, &gameport_event_list, node) { | ||
260 | if (event->object == object) { | ||
261 | if (event->type == event_type) | ||
262 | goto out; | ||
263 | break; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) { | ||
268 | if (!try_module_get(owner)) { | ||
269 | printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type); | ||
270 | goto out; | ||
271 | } | ||
272 | |||
273 | event->type = event_type; | ||
274 | event->object = object; | ||
275 | event->owner = owner; | ||
276 | |||
277 | list_add_tail(&event->node, &gameport_event_list); | ||
278 | wake_up(&gameport_wait); | ||
279 | } else { | ||
280 | printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type); | ||
281 | } | ||
282 | out: | ||
283 | spin_unlock_irqrestore(&gameport_event_lock, flags); | ||
284 | } | ||
285 | |||
286 | static void gameport_free_event(struct gameport_event *event) | ||
287 | { | ||
288 | module_put(event->owner); | ||
289 | kfree(event); | ||
290 | } | ||
291 | |||
292 | static void gameport_remove_duplicate_events(struct gameport_event *event) | ||
293 | { | ||
294 | struct list_head *node, *next; | ||
295 | struct gameport_event *e; | ||
296 | unsigned long flags; | ||
297 | |||
298 | spin_lock_irqsave(&gameport_event_lock, flags); | ||
299 | |||
300 | list_for_each_safe(node, next, &gameport_event_list) { | ||
301 | e = list_entry(node, struct gameport_event, node); | ||
302 | if (event->object == e->object) { | ||
303 | /* | ||
304 | * If this event is of different type we should not | ||
305 | * look further - we only suppress duplicate events | ||
306 | * that were sent back-to-back. | ||
307 | */ | ||
308 | if (event->type != e->type) | ||
309 | break; | ||
310 | |||
311 | list_del_init(node); | ||
312 | gameport_free_event(e); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | spin_unlock_irqrestore(&gameport_event_lock, flags); | ||
317 | } | ||
318 | |||
319 | |||
320 | static struct gameport_event *gameport_get_event(void) | ||
321 | { | ||
322 | struct gameport_event *event; | ||
323 | struct list_head *node; | ||
324 | unsigned long flags; | ||
325 | |||
326 | spin_lock_irqsave(&gameport_event_lock, flags); | ||
327 | |||
328 | if (list_empty(&gameport_event_list)) { | ||
329 | spin_unlock_irqrestore(&gameport_event_lock, flags); | ||
330 | return NULL; | ||
331 | } | ||
332 | |||
333 | node = gameport_event_list.next; | ||
334 | event = list_entry(node, struct gameport_event, node); | ||
335 | list_del_init(node); | ||
336 | |||
337 | spin_unlock_irqrestore(&gameport_event_lock, flags); | ||
338 | |||
339 | return event; | ||
340 | } | ||
341 | |||
342 | static void gameport_handle_events(void) | ||
343 | { | ||
344 | struct gameport_event *event; | ||
345 | struct gameport_driver *gameport_drv; | ||
346 | |||
347 | down(&gameport_sem); | ||
348 | |||
349 | while ((event = gameport_get_event())) { | ||
350 | |||
351 | switch (event->type) { | ||
352 | case GAMEPORT_REGISTER_PORT: | ||
353 | gameport_add_port(event->object); | ||
354 | break; | ||
355 | |||
356 | case GAMEPORT_RECONNECT: | ||
357 | gameport_reconnect_port(event->object); | ||
358 | break; | ||
359 | |||
360 | case GAMEPORT_RESCAN: | ||
361 | gameport_disconnect_port(event->object); | ||
362 | gameport_find_driver(event->object); | ||
363 | break; | ||
364 | |||
365 | case GAMEPORT_REGISTER_DRIVER: | ||
366 | gameport_drv = event->object; | ||
367 | driver_register(&gameport_drv->driver); | ||
368 | break; | ||
369 | |||
370 | default: | ||
371 | break; | ||
372 | } | ||
373 | |||
374 | gameport_remove_duplicate_events(event); | ||
375 | gameport_free_event(event); | ||
376 | } | ||
377 | |||
378 | up(&gameport_sem); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Remove all events that have been submitted for a given gameport port. | ||
383 | */ | ||
384 | static void gameport_remove_pending_events(struct gameport *gameport) | ||
385 | { | ||
386 | struct list_head *node, *next; | ||
387 | struct gameport_event *event; | ||
388 | unsigned long flags; | ||
389 | |||
390 | spin_lock_irqsave(&gameport_event_lock, flags); | ||
391 | |||
392 | list_for_each_safe(node, next, &gameport_event_list) { | ||
393 | event = list_entry(node, struct gameport_event, node); | ||
394 | if (event->object == gameport) { | ||
395 | list_del_init(node); | ||
396 | gameport_free_event(event); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | spin_unlock_irqrestore(&gameport_event_lock, flags); | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Destroy child gameport port (if any) that has not been fully registered yet. | ||
405 | * | ||
406 | * Note that we rely on the fact that port can have only one child and therefore | ||
407 | * only one child registration request can be pending. Additionally, children | ||
408 | * are registered by driver's connect() handler so there can't be a grandchild | ||
409 | * pending registration together with a child. | ||
410 | */ | ||
411 | static struct gameport *gameport_get_pending_child(struct gameport *parent) | ||
412 | { | ||
413 | struct gameport_event *event; | ||
414 | struct gameport *gameport, *child = NULL; | ||
415 | unsigned long flags; | ||
416 | |||
417 | spin_lock_irqsave(&gameport_event_lock, flags); | ||
418 | |||
419 | list_for_each_entry(event, &gameport_event_list, node) { | ||
420 | if (event->type == GAMEPORT_REGISTER_PORT) { | ||
421 | gameport = event->object; | ||
422 | if (gameport->parent == parent) { | ||
423 | child = gameport; | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | spin_unlock_irqrestore(&gameport_event_lock, flags); | ||
430 | return child; | ||
431 | } | ||
432 | |||
433 | static int gameport_thread(void *nothing) | ||
434 | { | ||
435 | lock_kernel(); | ||
436 | daemonize("kgameportd"); | ||
437 | allow_signal(SIGTERM); | ||
438 | |||
439 | do { | ||
440 | gameport_handle_events(); | ||
441 | wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list)); | ||
442 | try_to_freeze(PF_FREEZE); | ||
443 | } while (!signal_pending(current)); | ||
444 | |||
445 | printk(KERN_DEBUG "gameport: kgameportd exiting\n"); | ||
446 | |||
447 | unlock_kernel(); | ||
448 | complete_and_exit(&gameport_exited, 0); | ||
449 | } | ||
450 | |||
451 | |||
452 | /* | ||
453 | * Gameport port operations | ||
454 | */ | ||
455 | |||
456 | static ssize_t gameport_show_description(struct device *dev, char *buf) | ||
457 | { | ||
458 | struct gameport *gameport = to_gameport_port(dev); | ||
459 | return sprintf(buf, "%s\n", gameport->name); | ||
460 | } | ||
461 | |||
462 | static ssize_t gameport_rebind_driver(struct device *dev, const char *buf, size_t count) | ||
463 | { | ||
464 | struct gameport *gameport = to_gameport_port(dev); | ||
465 | struct device_driver *drv; | ||
466 | int retval; | ||
467 | |||
468 | retval = down_interruptible(&gameport_sem); | ||
469 | if (retval) | ||
470 | return retval; | ||
471 | |||
472 | retval = count; | ||
473 | if (!strncmp(buf, "none", count)) { | ||
474 | gameport_disconnect_port(gameport); | ||
475 | } else if (!strncmp(buf, "reconnect", count)) { | ||
476 | gameport_reconnect_port(gameport); | ||
477 | } else if (!strncmp(buf, "rescan", count)) { | ||
478 | gameport_disconnect_port(gameport); | ||
479 | gameport_find_driver(gameport); | ||
480 | } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) { | ||
481 | gameport_disconnect_port(gameport); | ||
482 | gameport_bind_driver(gameport, to_gameport_driver(drv)); | ||
483 | put_driver(drv); | ||
484 | } else { | ||
485 | retval = -EINVAL; | ||
486 | } | ||
487 | |||
488 | up(&gameport_sem); | ||
489 | |||
490 | return retval; | ||
491 | } | ||
492 | |||
493 | static struct device_attribute gameport_device_attrs[] = { | ||
494 | __ATTR(description, S_IRUGO, gameport_show_description, NULL), | ||
495 | __ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver), | ||
496 | __ATTR_NULL | ||
497 | }; | ||
498 | |||
499 | static void gameport_release_port(struct device *dev) | ||
500 | { | ||
501 | struct gameport *gameport = to_gameport_port(dev); | ||
502 | |||
503 | kfree(gameport); | ||
504 | module_put(THIS_MODULE); | ||
505 | } | ||
506 | |||
507 | void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) | ||
508 | { | ||
509 | va_list args; | ||
510 | |||
511 | va_start(args, fmt); | ||
512 | vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args); | ||
513 | va_end(args); | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * Prepare gameport port for registration. | ||
518 | */ | ||
519 | static void gameport_init_port(struct gameport *gameport) | ||
520 | { | ||
521 | static atomic_t gameport_no = ATOMIC_INIT(0); | ||
522 | |||
523 | __module_get(THIS_MODULE); | ||
524 | |||
525 | init_MUTEX(&gameport->drv_sem); | ||
526 | device_initialize(&gameport->dev); | ||
527 | snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id), | ||
528 | "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1); | ||
529 | gameport->dev.bus = &gameport_bus; | ||
530 | gameport->dev.release = gameport_release_port; | ||
531 | if (gameport->parent) | ||
532 | gameport->dev.parent = &gameport->parent->dev; | ||
533 | |||
534 | spin_lock_init(&gameport->timer_lock); | ||
535 | init_timer(&gameport->poll_timer); | ||
536 | gameport->poll_timer.function = gameport_run_poll_handler; | ||
537 | gameport->poll_timer.data = (unsigned long)gameport; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * Complete gameport port registration. | ||
542 | * Driver core will attempt to find appropriate driver for the port. | ||
543 | */ | ||
544 | static void gameport_add_port(struct gameport *gameport) | ||
545 | { | ||
546 | if (gameport->parent) | ||
547 | gameport->parent->child = gameport; | ||
548 | |||
549 | gameport->speed = gameport_measure_speed(gameport); | ||
550 | |||
551 | list_add_tail(&gameport->node, &gameport_list); | ||
552 | |||
553 | if (gameport->io) | ||
554 | printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n", | ||
555 | gameport->name, gameport->phys, gameport->io, gameport->speed); | ||
556 | else | ||
557 | printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n", | ||
558 | gameport->name, gameport->phys, gameport->speed); | ||
559 | |||
560 | device_add(&gameport->dev); | ||
561 | gameport->registered = 1; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * gameport_destroy_port() completes deregistration process and removes | ||
566 | * port from the system | ||
567 | */ | ||
568 | static void gameport_destroy_port(struct gameport *gameport) | ||
569 | { | ||
570 | struct gameport *child; | ||
571 | |||
572 | child = gameport_get_pending_child(gameport); | ||
573 | if (child) { | ||
574 | gameport_remove_pending_events(child); | ||
575 | put_device(&child->dev); | ||
576 | } | ||
577 | |||
578 | if (gameport->parent) { | ||
579 | gameport->parent->child = NULL; | ||
580 | gameport->parent = NULL; | ||
581 | } | ||
582 | |||
583 | if (gameport->registered) { | ||
584 | device_del(&gameport->dev); | ||
585 | list_del_init(&gameport->node); | ||
586 | gameport->registered = 0; | ||
587 | } | ||
588 | |||
589 | gameport_remove_pending_events(gameport); | ||
590 | put_device(&gameport->dev); | ||
591 | } | ||
592 | |||
593 | /* | ||
594 | * Reconnect gameport port and all its children (re-initialize attached devices) | ||
595 | */ | ||
596 | static void gameport_reconnect_port(struct gameport *gameport) | ||
597 | { | ||
598 | do { | ||
599 | if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) { | ||
600 | gameport_disconnect_port(gameport); | ||
601 | gameport_find_driver(gameport); | ||
602 | /* Ok, old children are now gone, we are done */ | ||
603 | break; | ||
604 | } | ||
605 | gameport = gameport->child; | ||
606 | } while (gameport); | ||
607 | } | ||
608 | |||
609 | /* | ||
610 | * gameport_disconnect_port() unbinds a port from its driver. As a side effect | ||
611 | * all child ports are unbound and destroyed. | ||
612 | */ | ||
613 | static void gameport_disconnect_port(struct gameport *gameport) | ||
614 | { | ||
615 | struct gameport *s, *parent; | ||
616 | |||
617 | if (gameport->child) { | ||
618 | /* | ||
619 | * Children ports should be disconnected and destroyed | ||
620 | * first, staring with the leaf one, since we don't want | ||
621 | * to do recursion | ||
622 | */ | ||
623 | for (s = gameport; s->child; s = s->child) | ||
624 | /* empty */; | ||
625 | |||
626 | do { | ||
627 | parent = s->parent; | ||
628 | |||
629 | gameport_release_driver(s); | ||
630 | gameport_destroy_port(s); | ||
631 | } while ((s = parent) != gameport); | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * Ok, no children left, now disconnect this port | ||
636 | */ | ||
637 | gameport_release_driver(gameport); | ||
638 | } | ||
639 | |||
640 | void gameport_rescan(struct gameport *gameport) | ||
641 | { | ||
642 | gameport_queue_event(gameport, NULL, GAMEPORT_RESCAN); | ||
643 | } | ||
644 | |||
645 | void gameport_reconnect(struct gameport *gameport) | ||
646 | { | ||
647 | gameport_queue_event(gameport, NULL, GAMEPORT_RECONNECT); | ||
648 | } | ||
649 | |||
650 | /* | ||
651 | * Submits register request to kgameportd for subsequent execution. | ||
652 | * Note that port registration is always asynchronous. | ||
653 | */ | ||
654 | void __gameport_register_port(struct gameport *gameport, struct module *owner) | ||
655 | { | ||
656 | gameport_init_port(gameport); | ||
657 | gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT); | ||
658 | } | ||
659 | |||
660 | /* | ||
661 | * Synchronously unregisters gameport port. | ||
662 | */ | ||
663 | void gameport_unregister_port(struct gameport *gameport) | ||
664 | { | ||
665 | down(&gameport_sem); | ||
666 | gameport_disconnect_port(gameport); | ||
667 | gameport_destroy_port(gameport); | ||
668 | up(&gameport_sem); | ||
669 | } | ||
670 | |||
671 | |||
672 | /* | ||
673 | * Gameport driver operations | ||
674 | */ | ||
675 | |||
676 | static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf) | ||
677 | { | ||
678 | struct gameport_driver *driver = to_gameport_driver(drv); | ||
679 | return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); | ||
680 | } | ||
681 | |||
682 | static struct driver_attribute gameport_driver_attrs[] = { | ||
683 | __ATTR(description, S_IRUGO, gameport_driver_show_description, NULL), | ||
684 | __ATTR_NULL | ||
685 | }; | ||
686 | |||
687 | static int gameport_driver_probe(struct device *dev) | ||
688 | { | ||
689 | struct gameport *gameport = to_gameport_port(dev); | ||
690 | struct gameport_driver *drv = to_gameport_driver(dev->driver); | ||
691 | |||
692 | drv->connect(gameport, drv); | ||
693 | return gameport->drv ? 0 : -ENODEV; | ||
694 | } | ||
695 | |||
696 | static int gameport_driver_remove(struct device *dev) | ||
697 | { | ||
698 | struct gameport *gameport = to_gameport_port(dev); | ||
699 | struct gameport_driver *drv = to_gameport_driver(dev->driver); | ||
700 | |||
701 | drv->disconnect(gameport); | ||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | void __gameport_register_driver(struct gameport_driver *drv, struct module *owner) | ||
706 | { | ||
707 | drv->driver.bus = &gameport_bus; | ||
708 | drv->driver.probe = gameport_driver_probe; | ||
709 | drv->driver.remove = gameport_driver_remove; | ||
710 | gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER); | ||
711 | } | ||
712 | |||
713 | void gameport_unregister_driver(struct gameport_driver *drv) | ||
714 | { | ||
715 | struct gameport *gameport; | ||
716 | |||
717 | down(&gameport_sem); | ||
718 | drv->ignore = 1; /* so gameport_find_driver ignores it */ | ||
719 | |||
720 | start_over: | ||
721 | list_for_each_entry(gameport, &gameport_list, node) { | ||
722 | if (gameport->drv == drv) { | ||
723 | gameport_disconnect_port(gameport); | ||
724 | gameport_find_driver(gameport); | ||
725 | /* we could've deleted some ports, restart */ | ||
726 | goto start_over; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | driver_unregister(&drv->driver); | ||
731 | up(&gameport_sem); | ||
732 | } | ||
733 | |||
734 | static int gameport_bus_match(struct device *dev, struct device_driver *drv) | ||
735 | { | ||
736 | struct gameport_driver *gameport_drv = to_gameport_driver(drv); | ||
737 | |||
738 | return !gameport_drv->ignore; | ||
739 | } | ||
740 | |||
741 | static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv) | ||
742 | { | ||
743 | down(&gameport->drv_sem); | ||
744 | gameport->drv = drv; | ||
745 | up(&gameport->drv_sem); | ||
746 | } | ||
747 | |||
748 | int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode) | ||
749 | { | ||
750 | |||
751 | if (gameport->open) { | ||
752 | if (gameport->open(gameport, mode)) { | ||
753 | return -1; | ||
754 | } | ||
755 | } else { | ||
756 | if (mode != GAMEPORT_MODE_RAW) | ||
757 | return -1; | ||
758 | } | ||
759 | |||
760 | gameport_set_drv(gameport, drv); | ||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | void gameport_close(struct gameport *gameport) | ||
765 | { | ||
766 | del_timer_sync(&gameport->poll_timer); | ||
767 | gameport->poll_handler = NULL; | ||
768 | gameport->poll_interval = 0; | ||
769 | gameport_set_drv(gameport, NULL); | ||
770 | if (gameport->close) | ||
771 | gameport->close(gameport); | ||
772 | } | ||
773 | |||
774 | static int __init gameport_init(void) | ||
775 | { | ||
776 | if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) { | ||
777 | printk(KERN_ERR "gameport: Failed to start kgameportd\n"); | ||
778 | return -1; | ||
779 | } | ||
780 | |||
781 | gameport_bus.dev_attrs = gameport_device_attrs; | ||
782 | gameport_bus.drv_attrs = gameport_driver_attrs; | ||
783 | gameport_bus.match = gameport_bus_match; | ||
784 | bus_register(&gameport_bus); | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static void __exit gameport_exit(void) | ||
790 | { | ||
791 | bus_unregister(&gameport_bus); | ||
792 | kill_proc(gameport_pid, SIGTERM, 1); | ||
793 | wait_for_completion(&gameport_exited); | ||
794 | } | ||
795 | |||
796 | module_init(gameport_init); | ||
797 | module_exit(gameport_exit); | ||
diff --git a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c new file mode 100644 index 000000000000..d65d81080257 --- /dev/null +++ b/drivers/input/gameport/lightning.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* | ||
2 | * $Id: lightning.c,v 1.20 2002/01/22 20:41:31 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1998-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * PDPI Lightning 4 gamecard 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 <asm/io.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/ioport.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/gameport.h> | ||
39 | #include <linux/slab.h> | ||
40 | |||
41 | #define L4_PORT 0x201 | ||
42 | #define L4_SELECT_ANALOG 0xa4 | ||
43 | #define L4_SELECT_DIGITAL 0xa5 | ||
44 | #define L4_SELECT_SECONDARY 0xa6 | ||
45 | #define L4_CMD_ID 0x80 | ||
46 | #define L4_CMD_GETCAL 0x92 | ||
47 | #define L4_CMD_SETCAL 0x93 | ||
48 | #define L4_ID 0x04 | ||
49 | #define L4_BUSY 0x01 | ||
50 | #define L4_TIMEOUT 80 /* 80 us */ | ||
51 | |||
52 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
53 | MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver"); | ||
54 | MODULE_LICENSE("GPL"); | ||
55 | |||
56 | struct l4 { | ||
57 | struct gameport *gameport; | ||
58 | unsigned char port; | ||
59 | }; | ||
60 | |||
61 | static struct l4 l4_ports[8]; | ||
62 | |||
63 | /* | ||
64 | * l4_wait_ready() waits for the L4 to become ready. | ||
65 | */ | ||
66 | |||
67 | static int l4_wait_ready(void) | ||
68 | { | ||
69 | unsigned int t = L4_TIMEOUT; | ||
70 | |||
71 | while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--; | ||
72 | return -(t <= 0); | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * l4_cooked_read() reads data from the Lightning 4. | ||
77 | */ | ||
78 | |||
79 | static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons) | ||
80 | { | ||
81 | struct l4 *l4 = gameport->port_data; | ||
82 | unsigned char status; | ||
83 | int i, result = -1; | ||
84 | |||
85 | outb(L4_SELECT_ANALOG, L4_PORT); | ||
86 | outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT); | ||
87 | |||
88 | if (inb(L4_PORT) & L4_BUSY) goto fail; | ||
89 | outb(l4->port & 3, L4_PORT); | ||
90 | |||
91 | if (l4_wait_ready()) goto fail; | ||
92 | status = inb(L4_PORT); | ||
93 | |||
94 | for (i = 0; i < 4; i++) | ||
95 | if (status & (1 << i)) { | ||
96 | if (l4_wait_ready()) goto fail; | ||
97 | axes[i] = inb(L4_PORT); | ||
98 | if (axes[i] > 252) axes[i] = -1; | ||
99 | } | ||
100 | |||
101 | if (status & 0x10) { | ||
102 | if (l4_wait_ready()) goto fail; | ||
103 | *buttons = inb(L4_PORT) & 0x0f; | ||
104 | } | ||
105 | |||
106 | result = 0; | ||
107 | |||
108 | fail: outb(L4_SELECT_ANALOG, L4_PORT); | ||
109 | return result; | ||
110 | } | ||
111 | |||
112 | static int l4_open(struct gameport *gameport, int mode) | ||
113 | { | ||
114 | struct l4 *l4 = gameport->port_data; | ||
115 | |||
116 | if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED) | ||
117 | return -1; | ||
118 | outb(L4_SELECT_ANALOG, L4_PORT); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * l4_getcal() reads the L4 with calibration values. | ||
124 | */ | ||
125 | |||
126 | static int l4_getcal(int port, int *cal) | ||
127 | { | ||
128 | int i, result = -1; | ||
129 | |||
130 | outb(L4_SELECT_ANALOG, L4_PORT); | ||
131 | outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT); | ||
132 | if (inb(L4_PORT) & L4_BUSY) | ||
133 | goto out; | ||
134 | |||
135 | outb(L4_CMD_GETCAL, L4_PORT); | ||
136 | if (l4_wait_ready()) | ||
137 | goto out; | ||
138 | |||
139 | if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) | ||
140 | goto out; | ||
141 | |||
142 | if (l4_wait_ready()) | ||
143 | goto out; | ||
144 | outb(port & 3, L4_PORT); | ||
145 | |||
146 | for (i = 0; i < 4; i++) { | ||
147 | if (l4_wait_ready()) | ||
148 | goto out; | ||
149 | cal[i] = inb(L4_PORT); | ||
150 | } | ||
151 | |||
152 | result = 0; | ||
153 | |||
154 | out: outb(L4_SELECT_ANALOG, L4_PORT); | ||
155 | return result; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * l4_setcal() programs the L4 with calibration values. | ||
160 | */ | ||
161 | |||
162 | static int l4_setcal(int port, int *cal) | ||
163 | { | ||
164 | int i, result = -1; | ||
165 | |||
166 | outb(L4_SELECT_ANALOG, L4_PORT); | ||
167 | outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT); | ||
168 | if (inb(L4_PORT) & L4_BUSY) | ||
169 | goto out; | ||
170 | |||
171 | outb(L4_CMD_SETCAL, L4_PORT); | ||
172 | if (l4_wait_ready()) | ||
173 | goto out; | ||
174 | |||
175 | if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) | ||
176 | goto out; | ||
177 | |||
178 | if (l4_wait_ready()) | ||
179 | goto out; | ||
180 | outb(port & 3, L4_PORT); | ||
181 | |||
182 | for (i = 0; i < 4; i++) { | ||
183 | if (l4_wait_ready()) | ||
184 | goto out; | ||
185 | outb(cal[i], L4_PORT); | ||
186 | } | ||
187 | |||
188 | result = 0; | ||
189 | |||
190 | out: outb(L4_SELECT_ANALOG, L4_PORT); | ||
191 | return result; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * l4_calibrate() calibrates the L4 for the attached device, so | ||
196 | * that the device's resistance fits into the L4's 8-bit range. | ||
197 | */ | ||
198 | |||
199 | static int l4_calibrate(struct gameport *gameport, int *axes, int *max) | ||
200 | { | ||
201 | int i, t; | ||
202 | int cal[4]; | ||
203 | struct l4 *l4 = gameport->port_data; | ||
204 | |||
205 | if (l4_getcal(l4->port, cal)) | ||
206 | return -1; | ||
207 | |||
208 | for (i = 0; i < 4; i++) { | ||
209 | t = (max[i] * cal[i]) / 200; | ||
210 | t = (t < 1) ? 1 : ((t > 255) ? 255 : t); | ||
211 | axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t; | ||
212 | axes[i] = (axes[i] > 252) ? 252 : axes[i]; | ||
213 | cal[i] = t; | ||
214 | } | ||
215 | |||
216 | if (l4_setcal(l4->port, cal)) | ||
217 | return -1; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int __init l4_create_ports(int card_no) | ||
223 | { | ||
224 | struct l4 *l4; | ||
225 | struct gameport *port; | ||
226 | int i, idx; | ||
227 | |||
228 | for (i = 0; i < 4; i++) { | ||
229 | |||
230 | idx = card_no * 4 + i; | ||
231 | l4 = &l4_ports[idx]; | ||
232 | |||
233 | if (!(l4->gameport = port = gameport_allocate_port())) { | ||
234 | printk(KERN_ERR "lightning: Memory allocation failed\n"); | ||
235 | while (--i >= 0) { | ||
236 | gameport_free_port(l4->gameport); | ||
237 | l4->gameport = NULL; | ||
238 | } | ||
239 | return -ENOMEM; | ||
240 | } | ||
241 | l4->port = idx; | ||
242 | |||
243 | port->port_data = l4; | ||
244 | port->open = l4_open; | ||
245 | port->cooked_read = l4_cooked_read; | ||
246 | port->calibrate = l4_calibrate; | ||
247 | |||
248 | gameport_set_name(port, "PDPI Lightning 4"); | ||
249 | gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx); | ||
250 | |||
251 | if (idx == 0) | ||
252 | port->io = L4_PORT; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int __init l4_add_card(int card_no) | ||
259 | { | ||
260 | int cal[4] = { 255, 255, 255, 255 }; | ||
261 | int i, rev, result; | ||
262 | struct l4 *l4; | ||
263 | |||
264 | outb(L4_SELECT_ANALOG, L4_PORT); | ||
265 | outb(L4_SELECT_DIGITAL + card_no, L4_PORT); | ||
266 | |||
267 | if (inb(L4_PORT) & L4_BUSY) | ||
268 | return -1; | ||
269 | outb(L4_CMD_ID, L4_PORT); | ||
270 | |||
271 | if (l4_wait_ready()) | ||
272 | return -1; | ||
273 | |||
274 | if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no) | ||
275 | return -1; | ||
276 | |||
277 | if (l4_wait_ready()) | ||
278 | return -1; | ||
279 | if (inb(L4_PORT) != L4_ID) | ||
280 | return -1; | ||
281 | |||
282 | if (l4_wait_ready()) | ||
283 | return -1; | ||
284 | rev = inb(L4_PORT); | ||
285 | |||
286 | if (!rev) | ||
287 | return -1; | ||
288 | |||
289 | result = l4_create_ports(card_no); | ||
290 | if (result) | ||
291 | return result; | ||
292 | |||
293 | printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n", | ||
294 | card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT); | ||
295 | |||
296 | for (i = 0; i < 4; i++) { | ||
297 | l4 = &l4_ports[card_no * 4 + i]; | ||
298 | |||
299 | if (rev > 0x28) /* on 2.9+ the setcal command works correctly */ | ||
300 | l4_setcal(l4->port, cal); | ||
301 | gameport_register_port(l4->gameport); | ||
302 | } | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int __init l4_init(void) | ||
308 | { | ||
309 | int i, cards = 0; | ||
310 | |||
311 | if (!request_region(L4_PORT, 1, "lightning")) | ||
312 | return -1; | ||
313 | |||
314 | for (i = 0; i < 2; i++) | ||
315 | if (l4_add_card(i) == 0) | ||
316 | cards++; | ||
317 | |||
318 | outb(L4_SELECT_ANALOG, L4_PORT); | ||
319 | |||
320 | if (!cards) { | ||
321 | release_region(L4_PORT, 1); | ||
322 | return -1; | ||
323 | } | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static void __exit l4_exit(void) | ||
329 | { | ||
330 | int i; | ||
331 | int cal[4] = { 59, 59, 59, 59 }; | ||
332 | |||
333 | for (i = 0; i < 8; i++) | ||
334 | if (l4_ports[i].gameport) { | ||
335 | l4_setcal(l4_ports[i].port, cal); | ||
336 | gameport_unregister_port(l4_ports[i].gameport); | ||
337 | } | ||
338 | |||
339 | outb(L4_SELECT_ANALOG, L4_PORT); | ||
340 | release_region(L4_PORT, 1); | ||
341 | } | ||
342 | |||
343 | module_init(l4_init); | ||
344 | module_exit(l4_exit); | ||
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c new file mode 100644 index 000000000000..7c5c6318eeb9 --- /dev/null +++ b/drivers/input/gameport/ns558.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | * $Id: ns558.c,v 1.43 2002/01/24 19:23:21 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | * Copyright (c) 1999 Brian Gerst | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * NS558 based standard IBM game port driver for Linux | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * Should you need to contact me, the author, you can do so either by | ||
28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
30 | */ | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/ioport.h> | ||
36 | #include <linux/config.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/gameport.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/pnp.h> | ||
42 | |||
43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
44 | MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver"); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | |||
47 | static int ns558_isa_portlist[] = { 0x201, 0x200, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209, | ||
48 | 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 }; | ||
49 | |||
50 | struct ns558 { | ||
51 | int type; | ||
52 | int io; | ||
53 | int size; | ||
54 | struct pnp_dev *dev; | ||
55 | struct gameport *gameport; | ||
56 | struct list_head node; | ||
57 | }; | ||
58 | |||
59 | static LIST_HEAD(ns558_list); | ||
60 | |||
61 | /* | ||
62 | * ns558_isa_probe() tries to find an isa gameport at the | ||
63 | * specified address, and also checks for mirrors. | ||
64 | * A joystick must be attached for this to work. | ||
65 | */ | ||
66 | |||
67 | static int ns558_isa_probe(int io) | ||
68 | { | ||
69 | int i, j, b; | ||
70 | unsigned char c, u, v; | ||
71 | struct ns558 *ns558; | ||
72 | struct gameport *port; | ||
73 | |||
74 | /* | ||
75 | * No one should be using this address. | ||
76 | */ | ||
77 | |||
78 | if (!request_region(io, 1, "ns558-isa")) | ||
79 | return -EBUSY; | ||
80 | |||
81 | /* | ||
82 | * We must not be able to write arbitrary values to the port. | ||
83 | * The lower two axis bits must be 1 after a write. | ||
84 | */ | ||
85 | |||
86 | c = inb(io); | ||
87 | outb(~c & ~3, io); | ||
88 | if (~(u = v = inb(io)) & 3) { | ||
89 | outb(c, io); | ||
90 | release_region(io, 1); | ||
91 | return -ENODEV; | ||
92 | } | ||
93 | /* | ||
94 | * After a trigger, there must be at least some bits changing. | ||
95 | */ | ||
96 | |||
97 | for (i = 0; i < 1000; i++) v &= inb(io); | ||
98 | |||
99 | if (u == v) { | ||
100 | outb(c, io); | ||
101 | release_region(io, 1); | ||
102 | return -ENODEV; | ||
103 | } | ||
104 | msleep(3); | ||
105 | /* | ||
106 | * After some time (4ms) the axes shouldn't change anymore. | ||
107 | */ | ||
108 | |||
109 | u = inb(io); | ||
110 | for (i = 0; i < 1000; i++) | ||
111 | if ((u ^ inb(io)) & 0xf) { | ||
112 | outb(c, io); | ||
113 | release_region(io, 1); | ||
114 | return -ENODEV; | ||
115 | } | ||
116 | /* | ||
117 | * And now find the number of mirrors of the port. | ||
118 | */ | ||
119 | |||
120 | for (i = 1; i < 5; i++) { | ||
121 | |||
122 | release_region(io & (-1 << (i - 1)), (1 << (i - 1))); | ||
123 | |||
124 | if (!request_region(io & (-1 << i), (1 << i), "ns558-isa")) | ||
125 | break; /* Don't disturb anyone */ | ||
126 | |||
127 | outb(0xff, io & (-1 << i)); | ||
128 | for (j = b = 0; j < 1000; j++) | ||
129 | if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++; | ||
130 | msleep(3); | ||
131 | |||
132 | if (b > 300) { /* We allow 30% difference */ | ||
133 | release_region(io & (-1 << i), (1 << i)); | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | i--; | ||
139 | |||
140 | if (i != 4) { | ||
141 | if (!request_region(io & (-1 << i), (1 << i), "ns558-isa")) | ||
142 | return -EBUSY; | ||
143 | } | ||
144 | |||
145 | ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL); | ||
146 | port = gameport_allocate_port(); | ||
147 | if (!ns558 || !port) { | ||
148 | printk(KERN_ERR "ns558: Memory allocation failed.\n"); | ||
149 | release_region(io & (-1 << i), (1 << i)); | ||
150 | kfree(ns558); | ||
151 | gameport_free_port(port); | ||
152 | return -ENOMEM; | ||
153 | } | ||
154 | |||
155 | memset(ns558, 0, sizeof(struct ns558)); | ||
156 | ns558->io = io; | ||
157 | ns558->size = 1 << i; | ||
158 | ns558->gameport = port; | ||
159 | |||
160 | port->io = io; | ||
161 | gameport_set_name(port, "NS558 ISA Gameport"); | ||
162 | gameport_set_phys(port, "isa%04x/gameport0", io & (-1 << i)); | ||
163 | |||
164 | gameport_register_port(port); | ||
165 | |||
166 | list_add(&ns558->node, &ns558_list); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | #ifdef CONFIG_PNP | ||
172 | |||
173 | static struct pnp_device_id pnp_devids[] = { | ||
174 | { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */ | ||
175 | { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */ | ||
176 | { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */ | ||
177 | { .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */ | ||
178 | { .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */ | ||
179 | { .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */ | ||
180 | { .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */ | ||
181 | { .id = "CSC0001", .driver_data = 0 }, /* CS4232 */ | ||
182 | { .id = "CSC000f", .driver_data = 0 }, /* CS4236 */ | ||
183 | { .id = "CSC0101", .driver_data = 0 }, /* CS4327 */ | ||
184 | { .id = "CTL7001", .driver_data = 0 }, /* SB16 */ | ||
185 | { .id = "CTL7002", .driver_data = 0 }, /* AWE64 */ | ||
186 | { .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */ | ||
187 | { .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */ | ||
188 | { .id = "ESS0001", .driver_data = 0 }, /* ES1869 */ | ||
189 | { .id = "ESS0005", .driver_data = 0 }, /* ES1878 */ | ||
190 | { .id = "ESS6880", .driver_data = 0 }, /* ES688 */ | ||
191 | { .id = "IBM0012", .driver_data = 0 }, /* CS4232 */ | ||
192 | { .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */ | ||
193 | { .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */ | ||
194 | { .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */ | ||
195 | { .id = "PNPb02f", .driver_data = 0 }, /* Generic */ | ||
196 | { .id = "", }, | ||
197 | }; | ||
198 | |||
199 | MODULE_DEVICE_TABLE(pnp, pnp_devids); | ||
200 | |||
201 | static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did) | ||
202 | { | ||
203 | int ioport, iolen; | ||
204 | struct ns558 *ns558; | ||
205 | struct gameport *port; | ||
206 | |||
207 | if (!pnp_port_valid(dev, 0)) { | ||
208 | printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n"); | ||
209 | return -ENODEV; | ||
210 | } | ||
211 | |||
212 | ioport = pnp_port_start(dev, 0); | ||
213 | iolen = pnp_port_len(dev, 0); | ||
214 | |||
215 | if (!request_region(ioport, iolen, "ns558-pnp")) | ||
216 | return -EBUSY; | ||
217 | |||
218 | ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL); | ||
219 | port = gameport_allocate_port(); | ||
220 | if (!ns558 || !port) { | ||
221 | printk(KERN_ERR "ns558: Memory allocation failed\n"); | ||
222 | kfree(ns558); | ||
223 | gameport_free_port(port); | ||
224 | return -ENOMEM; | ||
225 | } | ||
226 | |||
227 | ns558->io = ioport; | ||
228 | ns558->size = iolen; | ||
229 | ns558->dev = dev; | ||
230 | ns558->gameport = port; | ||
231 | |||
232 | gameport_set_name(port, "NS558 PnP Gameport"); | ||
233 | gameport_set_phys(port, "pnp%s/gameport0", dev->dev.bus_id); | ||
234 | port->dev.parent = &dev->dev; | ||
235 | port->io = ioport; | ||
236 | |||
237 | gameport_register_port(port); | ||
238 | |||
239 | list_add_tail(&ns558->node, &ns558_list); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static struct pnp_driver ns558_pnp_driver = { | ||
244 | .name = "ns558", | ||
245 | .id_table = pnp_devids, | ||
246 | .probe = ns558_pnp_probe, | ||
247 | }; | ||
248 | |||
249 | #else | ||
250 | |||
251 | static struct pnp_driver ns558_pnp_driver; | ||
252 | |||
253 | #endif | ||
254 | |||
255 | static int pnp_registered = 0; | ||
256 | |||
257 | static int __init ns558_init(void) | ||
258 | { | ||
259 | int i = 0; | ||
260 | |||
261 | /* | ||
262 | * Probe ISA ports first so that PnP gets to choose free port addresses | ||
263 | * not occupied by the ISA ports. | ||
264 | */ | ||
265 | |||
266 | while (ns558_isa_portlist[i]) | ||
267 | ns558_isa_probe(ns558_isa_portlist[i++]); | ||
268 | |||
269 | if (pnp_register_driver(&ns558_pnp_driver) >= 0) | ||
270 | pnp_registered = 1; | ||
271 | |||
272 | |||
273 | return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0; | ||
274 | } | ||
275 | |||
276 | static void __exit ns558_exit(void) | ||
277 | { | ||
278 | struct ns558 *ns558; | ||
279 | |||
280 | list_for_each_entry(ns558, &ns558_list, node) { | ||
281 | gameport_unregister_port(ns558->gameport); | ||
282 | release_region(ns558->io & ~(ns558->size - 1), ns558->size); | ||
283 | kfree(ns558); | ||
284 | } | ||
285 | |||
286 | if (pnp_registered) | ||
287 | pnp_unregister_driver(&ns558_pnp_driver); | ||
288 | } | ||
289 | |||
290 | module_init(ns558_init); | ||
291 | module_exit(ns558_exit); | ||
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c new file mode 100644 index 000000000000..36b0309c8bf6 --- /dev/null +++ b/drivers/input/gameport/vortex.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Raymond Ingles | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Trident 4DWave and Aureal Vortex gameport driver for Linux | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <asm/io.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/module.h> | ||
40 | #include <linux/pci.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/slab.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/gameport.h> | ||
45 | |||
46 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
47 | MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver"); | ||
48 | MODULE_LICENSE("GPL"); | ||
49 | |||
50 | #define VORTEX_GCR 0x0c /* Gameport control register */ | ||
51 | #define VORTEX_LEG 0x08 /* Legacy port location */ | ||
52 | #define VORTEX_AXD 0x10 /* Axes start */ | ||
53 | #define VORTEX_DATA_WAIT 20 /* 20 ms */ | ||
54 | |||
55 | struct vortex { | ||
56 | struct gameport *gameport; | ||
57 | struct pci_dev *dev; | ||
58 | unsigned char __iomem *base; | ||
59 | unsigned char __iomem *io; | ||
60 | }; | ||
61 | |||
62 | static unsigned char vortex_read(struct gameport *gameport) | ||
63 | { | ||
64 | struct vortex *vortex = gameport->port_data; | ||
65 | return readb(vortex->io + VORTEX_LEG); | ||
66 | } | ||
67 | |||
68 | static void vortex_trigger(struct gameport *gameport) | ||
69 | { | ||
70 | struct vortex *vortex = gameport->port_data; | ||
71 | writeb(0xff, vortex->io + VORTEX_LEG); | ||
72 | } | ||
73 | |||
74 | static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons) | ||
75 | { | ||
76 | struct vortex *vortex = gameport->port_data; | ||
77 | int i; | ||
78 | |||
79 | *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf; | ||
80 | |||
81 | for (i = 0; i < 4; i++) { | ||
82 | axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32)); | ||
83 | if (axes[i] == 0x1fff) axes[i] = -1; | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int vortex_open(struct gameport *gameport, int mode) | ||
90 | { | ||
91 | struct vortex *vortex = gameport->port_data; | ||
92 | |||
93 | switch (mode) { | ||
94 | case GAMEPORT_MODE_COOKED: | ||
95 | writeb(0x40, vortex->io + VORTEX_GCR); | ||
96 | msleep(VORTEX_DATA_WAIT); | ||
97 | return 0; | ||
98 | case GAMEPORT_MODE_RAW: | ||
99 | writeb(0x00, vortex->io + VORTEX_GCR); | ||
100 | return 0; | ||
101 | default: | ||
102 | return -1; | ||
103 | } | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
109 | { | ||
110 | struct vortex *vortex; | ||
111 | struct gameport *port; | ||
112 | int i; | ||
113 | |||
114 | vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL); | ||
115 | port = gameport_allocate_port(); | ||
116 | if (!vortex || !port) { | ||
117 | printk(KERN_ERR "vortex: Memory allocation failed.\n"); | ||
118 | kfree(vortex); | ||
119 | gameport_free_port(port); | ||
120 | return -ENOMEM; | ||
121 | } | ||
122 | |||
123 | for (i = 0; i < 6; i++) | ||
124 | if (~pci_resource_flags(dev, i) & IORESOURCE_IO) | ||
125 | break; | ||
126 | |||
127 | pci_enable_device(dev); | ||
128 | |||
129 | vortex->dev = dev; | ||
130 | vortex->gameport = port; | ||
131 | vortex->base = ioremap(pci_resource_start(vortex->dev, i), | ||
132 | pci_resource_len(vortex->dev, i)); | ||
133 | vortex->io = vortex->base + id->driver_data; | ||
134 | |||
135 | pci_set_drvdata(dev, vortex); | ||
136 | |||
137 | port->port_data = vortex; | ||
138 | port->fuzz = 64; | ||
139 | |||
140 | gameport_set_name(port, "AU88x0"); | ||
141 | gameport_set_phys(port, "pci%s/gameport0", pci_name(dev)); | ||
142 | port->dev.parent = &dev->dev; | ||
143 | port->read = vortex_read; | ||
144 | port->trigger = vortex_trigger; | ||
145 | port->cooked_read = vortex_cooked_read; | ||
146 | port->open = vortex_open; | ||
147 | |||
148 | gameport_register_port(port); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void __devexit vortex_remove(struct pci_dev *dev) | ||
154 | { | ||
155 | struct vortex *vortex = pci_get_drvdata(dev); | ||
156 | |||
157 | gameport_unregister_port(vortex->gameport); | ||
158 | iounmap(vortex->base); | ||
159 | kfree(vortex); | ||
160 | } | ||
161 | |||
162 | static struct pci_device_id vortex_id_table[] = { | ||
163 | { 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 }, | ||
164 | { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 }, | ||
165 | { 0 } | ||
166 | }; | ||
167 | |||
168 | static struct pci_driver vortex_driver = { | ||
169 | .name = "vortex_gameport", | ||
170 | .id_table = vortex_id_table, | ||
171 | .probe = vortex_probe, | ||
172 | .remove = __devexit_p(vortex_remove), | ||
173 | }; | ||
174 | |||
175 | static int __init vortex_init(void) | ||
176 | { | ||
177 | return pci_register_driver(&vortex_driver); | ||
178 | } | ||
179 | |||
180 | static void __exit vortex_exit(void) | ||
181 | { | ||
182 | pci_unregister_driver(&vortex_driver); | ||
183 | } | ||
184 | |||
185 | module_init(vortex_init); | ||
186 | module_exit(vortex_exit); | ||
diff --git a/drivers/input/input.c b/drivers/input/input.c new file mode 100644 index 000000000000..3385dd03abfc --- /dev/null +++ b/drivers/input/input.c | |||
@@ -0,0 +1,748 @@ | |||
1 | /* | ||
2 | * The input core | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 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 | #include <linux/init.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/smp_lock.h> | ||
16 | #include <linux/input.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/random.h> | ||
19 | #include <linux/major.h> | ||
20 | #include <linux/proc_fs.h> | ||
21 | #include <linux/kobject_uevent.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/poll.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/devfs_fs_kernel.h> | ||
26 | |||
27 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | ||
28 | MODULE_DESCRIPTION("Input core"); | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | |||
31 | EXPORT_SYMBOL(input_register_device); | ||
32 | EXPORT_SYMBOL(input_unregister_device); | ||
33 | EXPORT_SYMBOL(input_register_handler); | ||
34 | EXPORT_SYMBOL(input_unregister_handler); | ||
35 | EXPORT_SYMBOL(input_grab_device); | ||
36 | EXPORT_SYMBOL(input_release_device); | ||
37 | EXPORT_SYMBOL(input_open_device); | ||
38 | EXPORT_SYMBOL(input_close_device); | ||
39 | EXPORT_SYMBOL(input_accept_process); | ||
40 | EXPORT_SYMBOL(input_flush_device); | ||
41 | EXPORT_SYMBOL(input_event); | ||
42 | EXPORT_SYMBOL(input_class); | ||
43 | |||
44 | #define INPUT_DEVICES 256 | ||
45 | |||
46 | static LIST_HEAD(input_dev_list); | ||
47 | static LIST_HEAD(input_handler_list); | ||
48 | |||
49 | static struct input_handler *input_table[8]; | ||
50 | |||
51 | #ifdef CONFIG_PROC_FS | ||
52 | static struct proc_dir_entry *proc_bus_input_dir; | ||
53 | static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); | ||
54 | static int input_devices_state; | ||
55 | #endif | ||
56 | |||
57 | void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
58 | { | ||
59 | struct input_handle *handle; | ||
60 | |||
61 | if (type > EV_MAX || !test_bit(type, dev->evbit)) | ||
62 | return; | ||
63 | |||
64 | add_input_randomness(type, code, value); | ||
65 | |||
66 | switch (type) { | ||
67 | |||
68 | case EV_SYN: | ||
69 | switch (code) { | ||
70 | case SYN_CONFIG: | ||
71 | if (dev->event) dev->event(dev, type, code, value); | ||
72 | break; | ||
73 | |||
74 | case SYN_REPORT: | ||
75 | if (dev->sync) return; | ||
76 | dev->sync = 1; | ||
77 | break; | ||
78 | } | ||
79 | break; | ||
80 | |||
81 | case EV_KEY: | ||
82 | |||
83 | if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) | ||
84 | return; | ||
85 | |||
86 | if (value == 2) | ||
87 | break; | ||
88 | |||
89 | change_bit(code, dev->key); | ||
90 | |||
91 | if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) { | ||
92 | dev->repeat_key = code; | ||
93 | mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); | ||
94 | } | ||
95 | |||
96 | break; | ||
97 | |||
98 | case EV_ABS: | ||
99 | |||
100 | if (code > ABS_MAX || !test_bit(code, dev->absbit)) | ||
101 | return; | ||
102 | |||
103 | if (dev->absfuzz[code]) { | ||
104 | if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) && | ||
105 | (value < dev->abs[code] + (dev->absfuzz[code] >> 1))) | ||
106 | return; | ||
107 | |||
108 | if ((value > dev->abs[code] - dev->absfuzz[code]) && | ||
109 | (value < dev->abs[code] + dev->absfuzz[code])) | ||
110 | value = (dev->abs[code] * 3 + value) >> 2; | ||
111 | |||
112 | if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) && | ||
113 | (value < dev->abs[code] + (dev->absfuzz[code] << 1))) | ||
114 | value = (dev->abs[code] + value) >> 1; | ||
115 | } | ||
116 | |||
117 | if (dev->abs[code] == value) | ||
118 | return; | ||
119 | |||
120 | dev->abs[code] = value; | ||
121 | break; | ||
122 | |||
123 | case EV_REL: | ||
124 | |||
125 | if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0)) | ||
126 | return; | ||
127 | |||
128 | break; | ||
129 | |||
130 | case EV_MSC: | ||
131 | |||
132 | if (code > MSC_MAX || !test_bit(code, dev->mscbit)) | ||
133 | return; | ||
134 | |||
135 | if (dev->event) dev->event(dev, type, code, value); | ||
136 | |||
137 | break; | ||
138 | |||
139 | case EV_LED: | ||
140 | |||
141 | if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) | ||
142 | return; | ||
143 | |||
144 | change_bit(code, dev->led); | ||
145 | if (dev->event) dev->event(dev, type, code, value); | ||
146 | |||
147 | break; | ||
148 | |||
149 | case EV_SND: | ||
150 | |||
151 | if (code > SND_MAX || !test_bit(code, dev->sndbit)) | ||
152 | return; | ||
153 | |||
154 | if (dev->event) dev->event(dev, type, code, value); | ||
155 | |||
156 | break; | ||
157 | |||
158 | case EV_REP: | ||
159 | |||
160 | if (code > REP_MAX || value < 0 || dev->rep[code] == value) return; | ||
161 | |||
162 | dev->rep[code] = value; | ||
163 | if (dev->event) dev->event(dev, type, code, value); | ||
164 | |||
165 | break; | ||
166 | |||
167 | case EV_FF: | ||
168 | if (dev->event) dev->event(dev, type, code, value); | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | if (type != EV_SYN) | ||
173 | dev->sync = 0; | ||
174 | |||
175 | if (dev->grab) | ||
176 | dev->grab->handler->event(dev->grab, type, code, value); | ||
177 | else | ||
178 | list_for_each_entry(handle, &dev->h_list, d_node) | ||
179 | if (handle->open) | ||
180 | handle->handler->event(handle, type, code, value); | ||
181 | } | ||
182 | |||
183 | static void input_repeat_key(unsigned long data) | ||
184 | { | ||
185 | struct input_dev *dev = (void *) data; | ||
186 | |||
187 | if (!test_bit(dev->repeat_key, dev->key)) | ||
188 | return; | ||
189 | |||
190 | input_event(dev, EV_KEY, dev->repeat_key, 2); | ||
191 | input_sync(dev); | ||
192 | |||
193 | if (dev->rep[REP_PERIOD]) | ||
194 | mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD])); | ||
195 | } | ||
196 | |||
197 | int input_accept_process(struct input_handle *handle, struct file *file) | ||
198 | { | ||
199 | if (handle->dev->accept) | ||
200 | return handle->dev->accept(handle->dev, file); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | int input_grab_device(struct input_handle *handle) | ||
206 | { | ||
207 | if (handle->dev->grab) | ||
208 | return -EBUSY; | ||
209 | |||
210 | handle->dev->grab = handle; | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | void input_release_device(struct input_handle *handle) | ||
215 | { | ||
216 | if (handle->dev->grab == handle) | ||
217 | handle->dev->grab = NULL; | ||
218 | } | ||
219 | |||
220 | int input_open_device(struct input_handle *handle) | ||
221 | { | ||
222 | handle->open++; | ||
223 | if (handle->dev->open) | ||
224 | return handle->dev->open(handle->dev); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | int input_flush_device(struct input_handle* handle, struct file* file) | ||
229 | { | ||
230 | if (handle->dev->flush) | ||
231 | return handle->dev->flush(handle->dev, file); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | void input_close_device(struct input_handle *handle) | ||
237 | { | ||
238 | input_release_device(handle); | ||
239 | if (handle->dev->close) | ||
240 | handle->dev->close(handle->dev); | ||
241 | handle->open--; | ||
242 | } | ||
243 | |||
244 | static void input_link_handle(struct input_handle *handle) | ||
245 | { | ||
246 | list_add_tail(&handle->d_node, &handle->dev->h_list); | ||
247 | list_add_tail(&handle->h_node, &handle->handler->h_list); | ||
248 | } | ||
249 | |||
250 | #define MATCH_BIT(bit, max) \ | ||
251 | for (i = 0; i < NBITS(max); i++) \ | ||
252 | if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ | ||
253 | break; \ | ||
254 | if (i != NBITS(max)) \ | ||
255 | continue; | ||
256 | |||
257 | static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev) | ||
258 | { | ||
259 | int i; | ||
260 | |||
261 | for (; id->flags || id->driver_info; id++) { | ||
262 | |||
263 | if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) | ||
264 | if (id->id.bustype != dev->id.bustype) | ||
265 | continue; | ||
266 | |||
267 | if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) | ||
268 | if (id->id.vendor != dev->id.vendor) | ||
269 | continue; | ||
270 | |||
271 | if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) | ||
272 | if (id->id.product != dev->id.product) | ||
273 | continue; | ||
274 | |||
275 | if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) | ||
276 | if (id->id.version != dev->id.version) | ||
277 | continue; | ||
278 | |||
279 | MATCH_BIT(evbit, EV_MAX); | ||
280 | MATCH_BIT(keybit, KEY_MAX); | ||
281 | MATCH_BIT(relbit, REL_MAX); | ||
282 | MATCH_BIT(absbit, ABS_MAX); | ||
283 | MATCH_BIT(mscbit, MSC_MAX); | ||
284 | MATCH_BIT(ledbit, LED_MAX); | ||
285 | MATCH_BIT(sndbit, SND_MAX); | ||
286 | MATCH_BIT(ffbit, FF_MAX); | ||
287 | |||
288 | return id; | ||
289 | } | ||
290 | |||
291 | return NULL; | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Input hotplugging interface - loading event handlers based on | ||
296 | * device bitfields. | ||
297 | */ | ||
298 | |||
299 | #ifdef CONFIG_HOTPLUG | ||
300 | |||
301 | /* | ||
302 | * Input hotplugging invokes what /proc/sys/kernel/hotplug says | ||
303 | * (normally /sbin/hotplug) when input devices get added or removed. | ||
304 | * | ||
305 | * This invokes a user mode policy agent, typically helping to load driver | ||
306 | * or other modules, configure the device, and more. Drivers can provide | ||
307 | * a MODULE_DEVICE_TABLE to help with module loading subtasks. | ||
308 | * | ||
309 | */ | ||
310 | |||
311 | #define SPRINTF_BIT_A(bit, name, max) \ | ||
312 | do { \ | ||
313 | envp[i++] = scratch; \ | ||
314 | scratch += sprintf(scratch, name); \ | ||
315 | for (j = NBITS(max) - 1; j >= 0; j--) \ | ||
316 | if (dev->bit[j]) break; \ | ||
317 | for (; j >= 0; j--) \ | ||
318 | scratch += sprintf(scratch, "%lx ", dev->bit[j]); \ | ||
319 | scratch++; \ | ||
320 | } while (0) | ||
321 | |||
322 | #define SPRINTF_BIT_A2(bit, name, max, ev) \ | ||
323 | do { \ | ||
324 | if (test_bit(ev, dev->evbit)) \ | ||
325 | SPRINTF_BIT_A(bit, name, max); \ | ||
326 | } while (0) | ||
327 | |||
328 | static void input_call_hotplug(char *verb, struct input_dev *dev) | ||
329 | { | ||
330 | char *argv[3], **envp, *buf, *scratch; | ||
331 | int i = 0, j, value; | ||
332 | |||
333 | if (!hotplug_path[0]) { | ||
334 | printk(KERN_ERR "input.c: calling hotplug without a hotplug agent defined\n"); | ||
335 | return; | ||
336 | } | ||
337 | if (in_interrupt()) { | ||
338 | printk(KERN_ERR "input.c: calling hotplug from interrupt\n"); | ||
339 | return; | ||
340 | } | ||
341 | if (!current->fs->root) { | ||
342 | printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n"); | ||
343 | return; | ||
344 | } | ||
345 | if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) { | ||
346 | printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); | ||
347 | return; | ||
348 | } | ||
349 | if (!(buf = kmalloc(1024, GFP_KERNEL))) { | ||
350 | kfree (envp); | ||
351 | printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); | ||
352 | return; | ||
353 | } | ||
354 | |||
355 | argv[0] = hotplug_path; | ||
356 | argv[1] = "input"; | ||
357 | argv[2] = NULL; | ||
358 | |||
359 | envp[i++] = "HOME=/"; | ||
360 | envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | ||
361 | |||
362 | scratch = buf; | ||
363 | |||
364 | envp[i++] = scratch; | ||
365 | scratch += sprintf(scratch, "ACTION=%s", verb) + 1; | ||
366 | |||
367 | envp[i++] = scratch; | ||
368 | scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", | ||
369 | dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; | ||
370 | |||
371 | if (dev->name) { | ||
372 | envp[i++] = scratch; | ||
373 | scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; | ||
374 | } | ||
375 | |||
376 | if (dev->phys) { | ||
377 | envp[i++] = scratch; | ||
378 | scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; | ||
379 | } | ||
380 | |||
381 | SPRINTF_BIT_A(evbit, "EV=", EV_MAX); | ||
382 | SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY); | ||
383 | SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL); | ||
384 | SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS); | ||
385 | SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC); | ||
386 | SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED); | ||
387 | SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND); | ||
388 | SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF); | ||
389 | |||
390 | envp[i++] = NULL; | ||
391 | |||
392 | #ifdef INPUT_DEBUG | ||
393 | printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n", | ||
394 | argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); | ||
395 | #endif | ||
396 | |||
397 | value = call_usermodehelper(argv [0], argv, envp, 0); | ||
398 | |||
399 | kfree(buf); | ||
400 | kfree(envp); | ||
401 | |||
402 | #ifdef INPUT_DEBUG | ||
403 | if (value != 0) | ||
404 | printk(KERN_DEBUG "input.c: hotplug returned %d\n", value); | ||
405 | #endif | ||
406 | } | ||
407 | |||
408 | #endif | ||
409 | |||
410 | void input_register_device(struct input_dev *dev) | ||
411 | { | ||
412 | struct input_handle *handle; | ||
413 | struct input_handler *handler; | ||
414 | struct input_device_id *id; | ||
415 | |||
416 | set_bit(EV_SYN, dev->evbit); | ||
417 | |||
418 | /* | ||
419 | * If delay and period are pre-set by the driver, then autorepeating | ||
420 | * is handled by the driver itself and we don't do it in input.c. | ||
421 | */ | ||
422 | |||
423 | init_timer(&dev->timer); | ||
424 | if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { | ||
425 | dev->timer.data = (long) dev; | ||
426 | dev->timer.function = input_repeat_key; | ||
427 | dev->rep[REP_DELAY] = 250; | ||
428 | dev->rep[REP_PERIOD] = 33; | ||
429 | } | ||
430 | |||
431 | INIT_LIST_HEAD(&dev->h_list); | ||
432 | list_add_tail(&dev->node, &input_dev_list); | ||
433 | |||
434 | list_for_each_entry(handler, &input_handler_list, node) | ||
435 | if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) | ||
436 | if ((id = input_match_device(handler->id_table, dev))) | ||
437 | if ((handle = handler->connect(handler, dev, id))) | ||
438 | input_link_handle(handle); | ||
439 | |||
440 | #ifdef CONFIG_HOTPLUG | ||
441 | input_call_hotplug("add", dev); | ||
442 | #endif | ||
443 | |||
444 | #ifdef CONFIG_PROC_FS | ||
445 | input_devices_state++; | ||
446 | wake_up(&input_devices_poll_wait); | ||
447 | #endif | ||
448 | } | ||
449 | |||
450 | void input_unregister_device(struct input_dev *dev) | ||
451 | { | ||
452 | struct list_head * node, * next; | ||
453 | |||
454 | if (!dev) return; | ||
455 | |||
456 | del_timer_sync(&dev->timer); | ||
457 | |||
458 | list_for_each_safe(node, next, &dev->h_list) { | ||
459 | struct input_handle * handle = to_handle(node); | ||
460 | list_del_init(&handle->d_node); | ||
461 | list_del_init(&handle->h_node); | ||
462 | handle->handler->disconnect(handle); | ||
463 | } | ||
464 | |||
465 | #ifdef CONFIG_HOTPLUG | ||
466 | input_call_hotplug("remove", dev); | ||
467 | #endif | ||
468 | |||
469 | list_del_init(&dev->node); | ||
470 | |||
471 | #ifdef CONFIG_PROC_FS | ||
472 | input_devices_state++; | ||
473 | wake_up(&input_devices_poll_wait); | ||
474 | #endif | ||
475 | } | ||
476 | |||
477 | void input_register_handler(struct input_handler *handler) | ||
478 | { | ||
479 | struct input_dev *dev; | ||
480 | struct input_handle *handle; | ||
481 | struct input_device_id *id; | ||
482 | |||
483 | if (!handler) return; | ||
484 | |||
485 | INIT_LIST_HEAD(&handler->h_list); | ||
486 | |||
487 | if (handler->fops != NULL) | ||
488 | input_table[handler->minor >> 5] = handler; | ||
489 | |||
490 | list_add_tail(&handler->node, &input_handler_list); | ||
491 | |||
492 | list_for_each_entry(dev, &input_dev_list, node) | ||
493 | if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) | ||
494 | if ((id = input_match_device(handler->id_table, dev))) | ||
495 | if ((handle = handler->connect(handler, dev, id))) | ||
496 | input_link_handle(handle); | ||
497 | |||
498 | #ifdef CONFIG_PROC_FS | ||
499 | input_devices_state++; | ||
500 | wake_up(&input_devices_poll_wait); | ||
501 | #endif | ||
502 | } | ||
503 | |||
504 | void input_unregister_handler(struct input_handler *handler) | ||
505 | { | ||
506 | struct list_head * node, * next; | ||
507 | |||
508 | list_for_each_safe(node, next, &handler->h_list) { | ||
509 | struct input_handle * handle = to_handle_h(node); | ||
510 | list_del_init(&handle->h_node); | ||
511 | list_del_init(&handle->d_node); | ||
512 | handler->disconnect(handle); | ||
513 | } | ||
514 | |||
515 | list_del_init(&handler->node); | ||
516 | |||
517 | if (handler->fops != NULL) | ||
518 | input_table[handler->minor >> 5] = NULL; | ||
519 | |||
520 | #ifdef CONFIG_PROC_FS | ||
521 | input_devices_state++; | ||
522 | wake_up(&input_devices_poll_wait); | ||
523 | #endif | ||
524 | } | ||
525 | |||
526 | static int input_open_file(struct inode *inode, struct file *file) | ||
527 | { | ||
528 | struct input_handler *handler = input_table[iminor(inode) >> 5]; | ||
529 | struct file_operations *old_fops, *new_fops = NULL; | ||
530 | int err; | ||
531 | |||
532 | /* No load-on-demand here? */ | ||
533 | if (!handler || !(new_fops = fops_get(handler->fops))) | ||
534 | return -ENODEV; | ||
535 | |||
536 | /* | ||
537 | * That's _really_ odd. Usually NULL ->open means "nothing special", | ||
538 | * not "no device". Oh, well... | ||
539 | */ | ||
540 | if (!new_fops->open) { | ||
541 | fops_put(new_fops); | ||
542 | return -ENODEV; | ||
543 | } | ||
544 | old_fops = file->f_op; | ||
545 | file->f_op = new_fops; | ||
546 | |||
547 | err = new_fops->open(inode, file); | ||
548 | |||
549 | if (err) { | ||
550 | fops_put(file->f_op); | ||
551 | file->f_op = fops_get(old_fops); | ||
552 | } | ||
553 | fops_put(old_fops); | ||
554 | return err; | ||
555 | } | ||
556 | |||
557 | static struct file_operations input_fops = { | ||
558 | .owner = THIS_MODULE, | ||
559 | .open = input_open_file, | ||
560 | }; | ||
561 | |||
562 | #ifdef CONFIG_PROC_FS | ||
563 | |||
564 | #define SPRINTF_BIT_B(bit, name, max) \ | ||
565 | do { \ | ||
566 | len += sprintf(buf + len, "B: %s", name); \ | ||
567 | for (i = NBITS(max) - 1; i >= 0; i--) \ | ||
568 | if (dev->bit[i]) break; \ | ||
569 | for (; i >= 0; i--) \ | ||
570 | len += sprintf(buf + len, "%lx ", dev->bit[i]); \ | ||
571 | len += sprintf(buf + len, "\n"); \ | ||
572 | } while (0) | ||
573 | |||
574 | #define SPRINTF_BIT_B2(bit, name, max, ev) \ | ||
575 | do { \ | ||
576 | if (test_bit(ev, dev->evbit)) \ | ||
577 | SPRINTF_BIT_B(bit, name, max); \ | ||
578 | } while (0) | ||
579 | |||
580 | |||
581 | static unsigned int input_devices_poll(struct file *file, poll_table *wait) | ||
582 | { | ||
583 | int state = input_devices_state; | ||
584 | poll_wait(file, &input_devices_poll_wait, wait); | ||
585 | if (state != input_devices_state) | ||
586 | return POLLIN | POLLRDNORM; | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) | ||
591 | { | ||
592 | struct input_dev *dev; | ||
593 | struct input_handle *handle; | ||
594 | |||
595 | off_t at = 0; | ||
596 | int i, len, cnt = 0; | ||
597 | |||
598 | list_for_each_entry(dev, &input_dev_list, node) { | ||
599 | |||
600 | len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", | ||
601 | dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); | ||
602 | |||
603 | len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); | ||
604 | len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); | ||
605 | len += sprintf(buf + len, "H: Handlers="); | ||
606 | |||
607 | list_for_each_entry(handle, &dev->h_list, d_node) | ||
608 | len += sprintf(buf + len, "%s ", handle->name); | ||
609 | |||
610 | len += sprintf(buf + len, "\n"); | ||
611 | |||
612 | SPRINTF_BIT_B(evbit, "EV=", EV_MAX); | ||
613 | SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); | ||
614 | SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); | ||
615 | SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); | ||
616 | SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); | ||
617 | SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); | ||
618 | SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); | ||
619 | SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); | ||
620 | |||
621 | len += sprintf(buf + len, "\n"); | ||
622 | |||
623 | at += len; | ||
624 | |||
625 | if (at >= pos) { | ||
626 | if (!*start) { | ||
627 | *start = buf + (pos - (at - len)); | ||
628 | cnt = at - pos; | ||
629 | } else cnt += len; | ||
630 | buf += len; | ||
631 | if (cnt >= count) | ||
632 | break; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | if (&dev->node == &input_dev_list) | ||
637 | *eof = 1; | ||
638 | |||
639 | return (count > cnt) ? cnt : count; | ||
640 | } | ||
641 | |||
642 | static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) | ||
643 | { | ||
644 | struct input_handler *handler; | ||
645 | |||
646 | off_t at = 0; | ||
647 | int len = 0, cnt = 0; | ||
648 | int i = 0; | ||
649 | |||
650 | list_for_each_entry(handler, &input_handler_list, node) { | ||
651 | |||
652 | if (handler->fops) | ||
653 | len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", | ||
654 | i++, handler->name, handler->minor); | ||
655 | else | ||
656 | len = sprintf(buf, "N: Number=%d Name=%s\n", | ||
657 | i++, handler->name); | ||
658 | |||
659 | at += len; | ||
660 | |||
661 | if (at >= pos) { | ||
662 | if (!*start) { | ||
663 | *start = buf + (pos - (at - len)); | ||
664 | cnt = at - pos; | ||
665 | } else cnt += len; | ||
666 | buf += len; | ||
667 | if (cnt >= count) | ||
668 | break; | ||
669 | } | ||
670 | } | ||
671 | if (&handler->node == &input_handler_list) | ||
672 | *eof = 1; | ||
673 | |||
674 | return (count > cnt) ? cnt : count; | ||
675 | } | ||
676 | |||
677 | static int __init input_proc_init(void) | ||
678 | { | ||
679 | struct proc_dir_entry *entry; | ||
680 | |||
681 | proc_bus_input_dir = proc_mkdir("input", proc_bus); | ||
682 | if (proc_bus_input_dir == NULL) | ||
683 | return -ENOMEM; | ||
684 | proc_bus_input_dir->owner = THIS_MODULE; | ||
685 | entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); | ||
686 | if (entry == NULL) { | ||
687 | remove_proc_entry("input", proc_bus); | ||
688 | return -ENOMEM; | ||
689 | } | ||
690 | entry->owner = THIS_MODULE; | ||
691 | entry->proc_fops->poll = input_devices_poll; | ||
692 | entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); | ||
693 | if (entry == NULL) { | ||
694 | remove_proc_entry("devices", proc_bus_input_dir); | ||
695 | remove_proc_entry("input", proc_bus); | ||
696 | return -ENOMEM; | ||
697 | } | ||
698 | entry->owner = THIS_MODULE; | ||
699 | return 0; | ||
700 | } | ||
701 | #else /* !CONFIG_PROC_FS */ | ||
702 | static inline int input_proc_init(void) { return 0; } | ||
703 | #endif | ||
704 | |||
705 | struct class_simple *input_class; | ||
706 | |||
707 | static int __init input_init(void) | ||
708 | { | ||
709 | int retval = -ENOMEM; | ||
710 | |||
711 | input_class = class_simple_create(THIS_MODULE, "input"); | ||
712 | if (IS_ERR(input_class)) | ||
713 | return PTR_ERR(input_class); | ||
714 | input_proc_init(); | ||
715 | retval = register_chrdev(INPUT_MAJOR, "input", &input_fops); | ||
716 | if (retval) { | ||
717 | printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); | ||
718 | remove_proc_entry("devices", proc_bus_input_dir); | ||
719 | remove_proc_entry("handlers", proc_bus_input_dir); | ||
720 | remove_proc_entry("input", proc_bus); | ||
721 | class_simple_destroy(input_class); | ||
722 | return retval; | ||
723 | } | ||
724 | |||
725 | retval = devfs_mk_dir("input"); | ||
726 | if (retval) { | ||
727 | remove_proc_entry("devices", proc_bus_input_dir); | ||
728 | remove_proc_entry("handlers", proc_bus_input_dir); | ||
729 | remove_proc_entry("input", proc_bus); | ||
730 | unregister_chrdev(INPUT_MAJOR, "input"); | ||
731 | class_simple_destroy(input_class); | ||
732 | } | ||
733 | return retval; | ||
734 | } | ||
735 | |||
736 | static void __exit input_exit(void) | ||
737 | { | ||
738 | remove_proc_entry("devices", proc_bus_input_dir); | ||
739 | remove_proc_entry("handlers", proc_bus_input_dir); | ||
740 | remove_proc_entry("input", proc_bus); | ||
741 | |||
742 | devfs_remove("input"); | ||
743 | unregister_chrdev(INPUT_MAJOR, "input"); | ||
744 | class_simple_destroy(input_class); | ||
745 | } | ||
746 | |||
747 | subsys_initcall(input_init); | ||
748 | module_exit(input_exit); | ||
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c new file mode 100644 index 000000000000..7d7527f8b02d --- /dev/null +++ b/drivers/input/joydev.c | |||
@@ -0,0 +1,533 @@ | |||
1 | /* | ||
2 | * Joystick device driver for the input driver suite. | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * Copyright (c) 1999 Colin Van Dyke | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <asm/io.h> | ||
14 | #include <asm/system.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/joystick.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/major.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/miscdevice.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/poll.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/smp_lock.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/devfs_fs_kernel.h> | ||
30 | |||
31 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
32 | MODULE_DESCRIPTION("Joystick device interfaces"); | ||
33 | MODULE_SUPPORTED_DEVICE("input/js"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | #define JOYDEV_MINOR_BASE 0 | ||
37 | #define JOYDEV_MINORS 16 | ||
38 | #define JOYDEV_BUFFER_SIZE 64 | ||
39 | |||
40 | #define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) | ||
41 | |||
42 | struct joydev { | ||
43 | int exist; | ||
44 | int open; | ||
45 | int minor; | ||
46 | char name[16]; | ||
47 | struct input_handle handle; | ||
48 | wait_queue_head_t wait; | ||
49 | struct list_head list; | ||
50 | struct js_corr corr[ABS_MAX + 1]; | ||
51 | struct JS_DATA_SAVE_TYPE glue; | ||
52 | int nabs; | ||
53 | int nkey; | ||
54 | __u16 keymap[KEY_MAX - BTN_MISC + 1]; | ||
55 | __u16 keypam[KEY_MAX - BTN_MISC + 1]; | ||
56 | __u8 absmap[ABS_MAX + 1]; | ||
57 | __u8 abspam[ABS_MAX + 1]; | ||
58 | __s16 abs[ABS_MAX + 1]; | ||
59 | }; | ||
60 | |||
61 | struct joydev_list { | ||
62 | struct js_event buffer[JOYDEV_BUFFER_SIZE]; | ||
63 | int head; | ||
64 | int tail; | ||
65 | int startup; | ||
66 | struct fasync_struct *fasync; | ||
67 | struct joydev *joydev; | ||
68 | struct list_head node; | ||
69 | }; | ||
70 | |||
71 | static struct joydev *joydev_table[JOYDEV_MINORS]; | ||
72 | |||
73 | static int joydev_correct(int value, struct js_corr *corr) | ||
74 | { | ||
75 | switch (corr->type) { | ||
76 | case JS_CORR_NONE: | ||
77 | break; | ||
78 | case JS_CORR_BROKEN: | ||
79 | value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : | ||
80 | ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : | ||
81 | ((corr->coef[2] * (value - corr->coef[0])) >> 14); | ||
82 | break; | ||
83 | default: | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | if (value < -32767) return -32767; | ||
88 | if (value > 32767) return 32767; | ||
89 | |||
90 | return value; | ||
91 | } | ||
92 | |||
93 | static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | ||
94 | { | ||
95 | struct joydev *joydev = handle->private; | ||
96 | struct joydev_list *list; | ||
97 | struct js_event event; | ||
98 | |||
99 | switch (type) { | ||
100 | |||
101 | case EV_KEY: | ||
102 | if (code < BTN_MISC || value == 2) return; | ||
103 | event.type = JS_EVENT_BUTTON; | ||
104 | event.number = joydev->keymap[code - BTN_MISC]; | ||
105 | event.value = value; | ||
106 | break; | ||
107 | |||
108 | case EV_ABS: | ||
109 | event.type = JS_EVENT_AXIS; | ||
110 | event.number = joydev->absmap[code]; | ||
111 | event.value = joydev_correct(value, joydev->corr + event.number); | ||
112 | if (event.value == joydev->abs[event.number]) return; | ||
113 | joydev->abs[event.number] = event.value; | ||
114 | break; | ||
115 | |||
116 | default: | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | event.time = MSECS(jiffies); | ||
121 | |||
122 | list_for_each_entry(list, &joydev->list, node) { | ||
123 | |||
124 | memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); | ||
125 | |||
126 | if (list->startup == joydev->nabs + joydev->nkey) | ||
127 | if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) | ||
128 | list->startup = 0; | ||
129 | |||
130 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
131 | } | ||
132 | |||
133 | wake_up_interruptible(&joydev->wait); | ||
134 | } | ||
135 | |||
136 | static int joydev_fasync(int fd, struct file *file, int on) | ||
137 | { | ||
138 | int retval; | ||
139 | struct joydev_list *list = file->private_data; | ||
140 | retval = fasync_helper(fd, file, on, &list->fasync); | ||
141 | return retval < 0 ? retval : 0; | ||
142 | } | ||
143 | |||
144 | static void joydev_free(struct joydev *joydev) | ||
145 | { | ||
146 | joydev_table[joydev->minor] = NULL; | ||
147 | kfree(joydev); | ||
148 | } | ||
149 | |||
150 | static int joydev_release(struct inode * inode, struct file * file) | ||
151 | { | ||
152 | struct joydev_list *list = file->private_data; | ||
153 | |||
154 | joydev_fasync(-1, file, 0); | ||
155 | |||
156 | list_del(&list->node); | ||
157 | |||
158 | if (!--list->joydev->open) { | ||
159 | if (list->joydev->exist) | ||
160 | input_close_device(&list->joydev->handle); | ||
161 | else | ||
162 | joydev_free(list->joydev); | ||
163 | } | ||
164 | |||
165 | kfree(list); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int joydev_open(struct inode *inode, struct file *file) | ||
170 | { | ||
171 | struct joydev_list *list; | ||
172 | int i = iminor(inode) - JOYDEV_MINOR_BASE; | ||
173 | |||
174 | if (i >= JOYDEV_MINORS || !joydev_table[i]) | ||
175 | return -ENODEV; | ||
176 | |||
177 | if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) | ||
178 | return -ENOMEM; | ||
179 | memset(list, 0, sizeof(struct joydev_list)); | ||
180 | |||
181 | list->joydev = joydev_table[i]; | ||
182 | list_add_tail(&list->node, &joydev_table[i]->list); | ||
183 | file->private_data = list; | ||
184 | |||
185 | if (!list->joydev->open++) | ||
186 | if (list->joydev->exist) | ||
187 | input_open_device(&list->joydev->handle); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | ||
193 | { | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | ||
198 | { | ||
199 | struct joydev_list *list = file->private_data; | ||
200 | struct joydev *joydev = list->joydev; | ||
201 | struct input_dev *input = joydev->handle.dev; | ||
202 | int retval = 0; | ||
203 | |||
204 | if (!list->joydev->exist) | ||
205 | return -ENODEV; | ||
206 | |||
207 | if (count < sizeof(struct js_event)) | ||
208 | return -EINVAL; | ||
209 | |||
210 | if (count == sizeof(struct JS_DATA_TYPE)) { | ||
211 | |||
212 | struct JS_DATA_TYPE data; | ||
213 | int i; | ||
214 | |||
215 | for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) | ||
216 | data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; | ||
217 | data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; | ||
218 | data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; | ||
219 | |||
220 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) | ||
221 | return -EFAULT; | ||
222 | |||
223 | list->startup = 0; | ||
224 | list->tail = list->head; | ||
225 | |||
226 | return sizeof(struct JS_DATA_TYPE); | ||
227 | } | ||
228 | |||
229 | if (list->startup == joydev->nabs + joydev->nkey | ||
230 | && list->head == list->tail && (file->f_flags & O_NONBLOCK)) | ||
231 | return -EAGAIN; | ||
232 | |||
233 | retval = wait_event_interruptible(list->joydev->wait, | ||
234 | !list->joydev->exist || | ||
235 | list->startup < joydev->nabs + joydev->nkey || | ||
236 | list->head != list->tail); | ||
237 | |||
238 | if (retval) | ||
239 | return retval; | ||
240 | |||
241 | if (!list->joydev->exist) | ||
242 | return -ENODEV; | ||
243 | |||
244 | while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { | ||
245 | |||
246 | struct js_event event; | ||
247 | |||
248 | event.time = MSECS(jiffies); | ||
249 | |||
250 | if (list->startup < joydev->nkey) { | ||
251 | event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; | ||
252 | event.number = list->startup; | ||
253 | event.value = !!test_bit(joydev->keypam[event.number], input->key); | ||
254 | } else { | ||
255 | event.type = JS_EVENT_AXIS | JS_EVENT_INIT; | ||
256 | event.number = list->startup - joydev->nkey; | ||
257 | event.value = joydev->abs[event.number]; | ||
258 | } | ||
259 | |||
260 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) | ||
261 | return -EFAULT; | ||
262 | |||
263 | list->startup++; | ||
264 | retval += sizeof(struct js_event); | ||
265 | } | ||
266 | |||
267 | while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { | ||
268 | |||
269 | if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) | ||
270 | return -EFAULT; | ||
271 | |||
272 | list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); | ||
273 | retval += sizeof(struct js_event); | ||
274 | } | ||
275 | |||
276 | return retval; | ||
277 | } | ||
278 | |||
279 | /* No kernel lock - fine */ | ||
280 | static unsigned int joydev_poll(struct file *file, poll_table *wait) | ||
281 | { | ||
282 | struct joydev_list *list = file->private_data; | ||
283 | poll_wait(file, &list->joydev->wait, wait); | ||
284 | return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? | ||
285 | (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); | ||
286 | } | ||
287 | |||
288 | static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
289 | { | ||
290 | struct joydev_list *list = file->private_data; | ||
291 | struct joydev *joydev = list->joydev; | ||
292 | struct input_dev *dev = joydev->handle.dev; | ||
293 | void __user *argp = (void __user *)arg; | ||
294 | int i, j; | ||
295 | |||
296 | if (!joydev->exist) return -ENODEV; | ||
297 | |||
298 | switch (cmd) { | ||
299 | |||
300 | case JS_SET_CAL: | ||
301 | return copy_from_user(&joydev->glue.JS_CORR, argp, | ||
302 | sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; | ||
303 | case JS_GET_CAL: | ||
304 | return copy_to_user(argp, &joydev->glue.JS_CORR, | ||
305 | sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; | ||
306 | case JS_SET_TIMEOUT: | ||
307 | return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg); | ||
308 | case JS_GET_TIMEOUT: | ||
309 | return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg); | ||
310 | case JS_SET_TIMELIMIT: | ||
311 | return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); | ||
312 | case JS_GET_TIMELIMIT: | ||
313 | return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); | ||
314 | case JS_SET_ALL: | ||
315 | return copy_from_user(&joydev->glue, argp, | ||
316 | sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; | ||
317 | case JS_GET_ALL: | ||
318 | return copy_to_user(argp, &joydev->glue, | ||
319 | sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; | ||
320 | |||
321 | case JSIOCGVERSION: | ||
322 | return put_user(JS_VERSION, (__u32 __user *) arg); | ||
323 | case JSIOCGAXES: | ||
324 | return put_user(joydev->nabs, (__u8 __user *) arg); | ||
325 | case JSIOCGBUTTONS: | ||
326 | return put_user(joydev->nkey, (__u8 __user *) arg); | ||
327 | case JSIOCSCORR: | ||
328 | if (copy_from_user(joydev->corr, argp, | ||
329 | sizeof(struct js_corr) * joydev->nabs)) | ||
330 | return -EFAULT; | ||
331 | for (i = 0; i < joydev->nabs; i++) { | ||
332 | j = joydev->abspam[i]; | ||
333 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | ||
334 | } | ||
335 | return 0; | ||
336 | case JSIOCGCORR: | ||
337 | return copy_to_user(argp, joydev->corr, | ||
338 | sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; | ||
339 | case JSIOCSAXMAP: | ||
340 | if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) | ||
341 | return -EFAULT; | ||
342 | for (i = 0; i < joydev->nabs; i++) { | ||
343 | if (joydev->abspam[i] > ABS_MAX) return -EINVAL; | ||
344 | joydev->absmap[joydev->abspam[i]] = i; | ||
345 | } | ||
346 | return 0; | ||
347 | case JSIOCGAXMAP: | ||
348 | return copy_to_user(argp, joydev->abspam, | ||
349 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; | ||
350 | case JSIOCSBTNMAP: | ||
351 | if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) | ||
352 | return -EFAULT; | ||
353 | for (i = 0; i < joydev->nkey; i++) { | ||
354 | if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL; | ||
355 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; | ||
356 | } | ||
357 | return 0; | ||
358 | case JSIOCGBTNMAP: | ||
359 | return copy_to_user(argp, joydev->keypam, | ||
360 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; | ||
361 | default: | ||
362 | if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { | ||
363 | int len; | ||
364 | if (!dev->name) return 0; | ||
365 | len = strlen(dev->name) + 1; | ||
366 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
367 | if (copy_to_user(argp, dev->name, len)) return -EFAULT; | ||
368 | return len; | ||
369 | } | ||
370 | } | ||
371 | return -EINVAL; | ||
372 | } | ||
373 | |||
374 | static struct file_operations joydev_fops = { | ||
375 | .owner = THIS_MODULE, | ||
376 | .read = joydev_read, | ||
377 | .write = joydev_write, | ||
378 | .poll = joydev_poll, | ||
379 | .open = joydev_open, | ||
380 | .release = joydev_release, | ||
381 | .ioctl = joydev_ioctl, | ||
382 | .fasync = joydev_fasync, | ||
383 | }; | ||
384 | |||
385 | static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | ||
386 | { | ||
387 | struct joydev *joydev; | ||
388 | int i, j, t, minor; | ||
389 | |||
390 | for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); | ||
391 | if (minor == JOYDEV_MINORS) { | ||
392 | printk(KERN_ERR "joydev: no more free joydev devices\n"); | ||
393 | return NULL; | ||
394 | } | ||
395 | |||
396 | if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) | ||
397 | return NULL; | ||
398 | memset(joydev, 0, sizeof(struct joydev)); | ||
399 | |||
400 | INIT_LIST_HEAD(&joydev->list); | ||
401 | init_waitqueue_head(&joydev->wait); | ||
402 | |||
403 | joydev->minor = minor; | ||
404 | joydev->exist = 1; | ||
405 | joydev->handle.dev = dev; | ||
406 | joydev->handle.name = joydev->name; | ||
407 | joydev->handle.handler = handler; | ||
408 | joydev->handle.private = joydev; | ||
409 | sprintf(joydev->name, "js%d", minor); | ||
410 | |||
411 | for (i = 0; i < ABS_MAX + 1; i++) | ||
412 | if (test_bit(i, dev->absbit)) { | ||
413 | joydev->absmap[i] = joydev->nabs; | ||
414 | joydev->abspam[joydev->nabs] = i; | ||
415 | joydev->nabs++; | ||
416 | } | ||
417 | |||
418 | for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++) | ||
419 | if (test_bit(i + BTN_MISC, dev->keybit)) { | ||
420 | joydev->keymap[i] = joydev->nkey; | ||
421 | joydev->keypam[joydev->nkey] = i + BTN_MISC; | ||
422 | joydev->nkey++; | ||
423 | } | ||
424 | |||
425 | for (i = 0; i < BTN_JOYSTICK - BTN_MISC + 1; i++) | ||
426 | if (test_bit(i + BTN_MISC, dev->keybit)) { | ||
427 | joydev->keymap[i] = joydev->nkey; | ||
428 | joydev->keypam[joydev->nkey] = i + BTN_MISC; | ||
429 | joydev->nkey++; | ||
430 | } | ||
431 | |||
432 | for (i = 0; i < joydev->nabs; i++) { | ||
433 | j = joydev->abspam[i]; | ||
434 | if (dev->absmax[j] == dev->absmin[j]) { | ||
435 | joydev->corr[i].type = JS_CORR_NONE; | ||
436 | joydev->abs[i] = dev->abs[j]; | ||
437 | continue; | ||
438 | } | ||
439 | joydev->corr[i].type = JS_CORR_BROKEN; | ||
440 | joydev->corr[i].prec = dev->absfuzz[j]; | ||
441 | joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; | ||
442 | joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; | ||
443 | if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]))) | ||
444 | continue; | ||
445 | joydev->corr[i].coef[2] = (1 << 29) / t; | ||
446 | joydev->corr[i].coef[3] = (1 << 29) / t; | ||
447 | |||
448 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | ||
449 | } | ||
450 | |||
451 | joydev_table[minor] = joydev; | ||
452 | |||
453 | devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), | ||
454 | S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor); | ||
455 | class_simple_device_add(input_class, | ||
456 | MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), | ||
457 | dev->dev, "js%d", minor); | ||
458 | |||
459 | return &joydev->handle; | ||
460 | } | ||
461 | |||
462 | static void joydev_disconnect(struct input_handle *handle) | ||
463 | { | ||
464 | struct joydev *joydev = handle->private; | ||
465 | struct joydev_list *list; | ||
466 | |||
467 | class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); | ||
468 | devfs_remove("input/js%d", joydev->minor); | ||
469 | joydev->exist = 0; | ||
470 | |||
471 | if (joydev->open) { | ||
472 | input_close_device(handle); | ||
473 | wake_up_interruptible(&joydev->wait); | ||
474 | list_for_each_entry(list, &joydev->list, node) | ||
475 | kill_fasync(&list->fasync, SIGIO, POLL_HUP); | ||
476 | } else | ||
477 | joydev_free(joydev); | ||
478 | } | ||
479 | |||
480 | static struct input_device_id joydev_blacklist[] = { | ||
481 | { | ||
482 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
483 | .evbit = { BIT(EV_KEY) }, | ||
484 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | ||
485 | }, /* Avoid itouchpads, touchscreens and tablets */ | ||
486 | { }, /* Terminating entry */ | ||
487 | }; | ||
488 | |||
489 | static struct input_device_id joydev_ids[] = { | ||
490 | { | ||
491 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
492 | .evbit = { BIT(EV_ABS) }, | ||
493 | .absbit = { BIT(ABS_X) }, | ||
494 | }, | ||
495 | { | ||
496 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
497 | .evbit = { BIT(EV_ABS) }, | ||
498 | .absbit = { BIT(ABS_WHEEL) }, | ||
499 | }, | ||
500 | { | ||
501 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
502 | .evbit = { BIT(EV_ABS) }, | ||
503 | .absbit = { BIT(ABS_THROTTLE) }, | ||
504 | }, | ||
505 | { }, /* Terminating entry */ | ||
506 | }; | ||
507 | |||
508 | MODULE_DEVICE_TABLE(input, joydev_ids); | ||
509 | |||
510 | static struct input_handler joydev_handler = { | ||
511 | .event = joydev_event, | ||
512 | .connect = joydev_connect, | ||
513 | .disconnect = joydev_disconnect, | ||
514 | .fops = &joydev_fops, | ||
515 | .minor = JOYDEV_MINOR_BASE, | ||
516 | .name = "joydev", | ||
517 | .id_table = joydev_ids, | ||
518 | .blacklist = joydev_blacklist, | ||
519 | }; | ||
520 | |||
521 | static int __init joydev_init(void) | ||
522 | { | ||
523 | input_register_handler(&joydev_handler); | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static void __exit joydev_exit(void) | ||
528 | { | ||
529 | input_unregister_handler(&joydev_handler); | ||
530 | } | ||
531 | |||
532 | module_init(joydev_init); | ||
533 | module_exit(joydev_exit); | ||
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig new file mode 100644 index 000000000000..67519ef0ef95 --- /dev/null +++ b/drivers/input/joystick/Kconfig | |||
@@ -0,0 +1,256 @@ | |||
1 | # | ||
2 | # Joystick driver configuration | ||
3 | # | ||
4 | menuconfig INPUT_JOYSTICK | ||
5 | bool "Joysticks" | ||
6 | help | ||
7 | If you have a joystick, 6dof controller, gamepad, steering wheel, | ||
8 | weapon control system or something like that you can say Y here | ||
9 | and the list of supported devices will be displayed. This option | ||
10 | doesn't affect the kernel. | ||
11 | |||
12 | Please read the file <file:Documentation/input/joystick.txt> which | ||
13 | contains more information. | ||
14 | |||
15 | if INPUT_JOYSTICK | ||
16 | |||
17 | config JOYSTICK_ANALOG | ||
18 | tristate "Classic PC analog joysticks and gamepads" | ||
19 | select GAMEPORT | ||
20 | ---help--- | ||
21 | Say Y here if you have a joystick that connects to the PC | ||
22 | gameport. In addition to the usual PC analog joystick, this driver | ||
23 | supports many extensions, including joysticks with throttle control, | ||
24 | with rudders, additional hats and buttons compatible with CH | ||
25 | Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or | ||
26 | Saitek Cyborg joysticks. | ||
27 | |||
28 | Please read the file <file:Documentation/input/joystick.txt> which | ||
29 | contains more information. | ||
30 | |||
31 | To compile this driver as a module, choose M here: the | ||
32 | module will be called analog. | ||
33 | |||
34 | config JOYSTICK_A3D | ||
35 | tristate "Assasin 3D and MadCatz Panther devices" | ||
36 | select GAMEPORT | ||
37 | help | ||
38 | Say Y here if you have an FPGaming or MadCatz controller using the | ||
39 | A3D protocol over the PC gameport. | ||
40 | |||
41 | To compile this driver as a module, choose M here: the | ||
42 | module will be called a3d. | ||
43 | |||
44 | config JOYSTICK_ADI | ||
45 | tristate "Logitech ADI digital joysticks and gamepads" | ||
46 | select GAMEPORT | ||
47 | help | ||
48 | Say Y here if you have a Logitech controller using the ADI | ||
49 | protocol over the PC gameport. | ||
50 | |||
51 | To compile this driver as a module, choose M here: the | ||
52 | module will be called adi. | ||
53 | |||
54 | config JOYSTICK_COBRA | ||
55 | tristate "Creative Labs Blaster Cobra gamepad" | ||
56 | select GAMEPORT | ||
57 | help | ||
58 | Say Y here if you have a Creative Labs Blaster Cobra gamepad. | ||
59 | |||
60 | To compile this driver as a module, choose M here: the | ||
61 | module will be called cobra. | ||
62 | |||
63 | config JOYSTICK_GF2K | ||
64 | tristate "Genius Flight2000 Digital joysticks and gamepads" | ||
65 | select GAMEPORT | ||
66 | help | ||
67 | Say Y here if you have a Genius Flight2000 or MaxFighter digitally | ||
68 | communicating joystick or gamepad. | ||
69 | |||
70 | To compile this driver as a module, choose M here: the | ||
71 | module will be called gf2k. | ||
72 | |||
73 | config JOYSTICK_GRIP | ||
74 | tristate "Gravis GrIP joysticks and gamepads" | ||
75 | select GAMEPORT | ||
76 | help | ||
77 | Say Y here if you have a Gravis controller using the GrIP protocol | ||
78 | over the PC gameport. | ||
79 | |||
80 | To compile this driver as a module, choose M here: the | ||
81 | module will be called grip. | ||
82 | |||
83 | config JOYSTICK_GRIP_MP | ||
84 | tristate "Gravis GrIP MultiPort" | ||
85 | select GAMEPORT | ||
86 | help | ||
87 | Say Y here if you have the original Gravis GrIP MultiPort, a hub | ||
88 | that connects to the gameport and you connect gamepads to it. | ||
89 | |||
90 | To compile this driver as a module, choose M here: the | ||
91 | module will be called grip_mp. | ||
92 | |||
93 | config JOYSTICK_GUILLEMOT | ||
94 | tristate "Guillemot joysticks and gamepads" | ||
95 | select GAMEPORT | ||
96 | help | ||
97 | Say Y here if you have a Guillemot joystick using a digital | ||
98 | protocol over the PC gameport. | ||
99 | |||
100 | To compile this driver as a module, choose M here: the | ||
101 | module will be called guillemot. | ||
102 | |||
103 | config JOYSTICK_INTERACT | ||
104 | tristate "InterAct digital joysticks and gamepads" | ||
105 | select GAMEPORT | ||
106 | help | ||
107 | Say Y here if you have an InterAct gameport or joystick | ||
108 | communicating digitally over the gameport. | ||
109 | |||
110 | To compile this driver as a module, choose M here: the | ||
111 | module will be called interact. | ||
112 | |||
113 | config JOYSTICK_SIDEWINDER | ||
114 | tristate "Microsoft SideWinder digital joysticks and gamepads" | ||
115 | select GAMEPORT | ||
116 | help | ||
117 | Say Y here if you have a Microsoft controller using the Digital | ||
118 | Overdrive protocol over PC gameport. | ||
119 | |||
120 | To compile this driver as a module, choose M here: the | ||
121 | module will be called sidewinder. | ||
122 | |||
123 | config JOYSTICK_TMDC | ||
124 | tristate "ThrustMaster DirectConnect joysticks and gamepads" | ||
125 | select GAMEPORT | ||
126 | help | ||
127 | Say Y here if you have a ThrustMaster controller using the | ||
128 | DirectConnect (BSP) protocol over the PC gameport. | ||
129 | |||
130 | To compile this driver as a module, choose M here: the | ||
131 | module will be called tmdc. | ||
132 | |||
133 | source "drivers/input/joystick/iforce/Kconfig" | ||
134 | |||
135 | config JOYSTICK_WARRIOR | ||
136 | tristate "Logitech WingMan Warrior joystick" | ||
137 | select SERIO | ||
138 | help | ||
139 | Say Y here if you have a Logitech WingMan Warrior joystick connected | ||
140 | to your computer's serial port. | ||
141 | |||
142 | To compile this driver as a module, choose M here: the | ||
143 | module will be called warrior. | ||
144 | |||
145 | config JOYSTICK_MAGELLAN | ||
146 | tristate "LogiCad3d Magellan/SpaceMouse 6dof controllers" | ||
147 | select SERIO | ||
148 | help | ||
149 | Say Y here if you have a Magellan or Space Mouse 6DOF controller | ||
150 | connected to your computer's serial port. | ||
151 | |||
152 | To compile this driver as a module, choose M here: the | ||
153 | module will be called magellan. | ||
154 | |||
155 | config JOYSTICK_SPACEORB | ||
156 | tristate "SpaceTec SpaceOrb/Avenger 6dof controllers" | ||
157 | select SERIO | ||
158 | help | ||
159 | Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF | ||
160 | controller connected to your computer's serial port. | ||
161 | |||
162 | To compile this driver as a module, choose M here: the | ||
163 | module will be called spaceorb. | ||
164 | |||
165 | config JOYSTICK_SPACEBALL | ||
166 | tristate "SpaceTec SpaceBall 6dof controllers" | ||
167 | select SERIO | ||
168 | help | ||
169 | Say Y here if you have a SpaceTec SpaceBall 2003/3003/4000 FLX | ||
170 | controller connected to your computer's serial port. For the | ||
171 | SpaceBall 4000 USB model, use the USB HID driver. | ||
172 | |||
173 | To compile this driver as a module, choose M here: the | ||
174 | module will be called spaceball. | ||
175 | |||
176 | config JOYSTICK_STINGER | ||
177 | tristate "Gravis Stinger gamepad" | ||
178 | select SERIO | ||
179 | help | ||
180 | Say Y here if you have a Gravis Stinger connected to one of your | ||
181 | serial ports. | ||
182 | |||
183 | To compile this driver as a module, choose M here: the | ||
184 | module will be called stinger. | ||
185 | |||
186 | config JOYSTICK_TWIDJOY | ||
187 | tristate "Twiddler as a joystick" | ||
188 | select SERIO | ||
189 | help | ||
190 | Say Y here if you have a Handykey Twiddler connected to your | ||
191 | computer's serial port and want to use it as a joystick. | ||
192 | |||
193 | To compile this driver as a module, choose M here: the | ||
194 | module will be called twidjoy. | ||
195 | |||
196 | config JOYSTICK_DB9 | ||
197 | tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads" | ||
198 | depends on PARPORT | ||
199 | ---help--- | ||
200 | Say Y here if you have a Sega Master System gamepad, Sega Genesis | ||
201 | gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, | ||
202 | Commodore, Amstrad CPC joystick connected to your parallel port. | ||
203 | For more information on how to use the driver please read | ||
204 | <file:Documentation/input/joystick-parport.txt>. | ||
205 | |||
206 | To compile this driver as a module, choose M here: the | ||
207 | module will be called db9. | ||
208 | |||
209 | config JOYSTICK_GAMECON | ||
210 | tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads" | ||
211 | depends on PARPORT | ||
212 | ---help--- | ||
213 | Say Y here if you have a Nintendo Entertainment System gamepad, | ||
214 | Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad, | ||
215 | Sony PlayStation gamepad or a Multisystem -- Atari, Amiga, | ||
216 | Commodore, Amstrad CPC joystick connected to your parallel port. | ||
217 | For more information on how to use the driver please read | ||
218 | <file:Documentation/input/joystick-parport.txt>. | ||
219 | |||
220 | To compile this driver as a module, choose M here: the | ||
221 | module will be called gamecon. | ||
222 | |||
223 | config JOYSTICK_TURBOGRAFX | ||
224 | tristate "Multisystem joysticks via TurboGraFX device" | ||
225 | depends on PARPORT | ||
226 | help | ||
227 | Say Y here if you have the TurboGraFX interface by Steffen Schwenke, | ||
228 | and want to use it with Multisystem -- Atari, Amiga, Commodore, | ||
229 | Amstrad CPC joystick. For more information on how to use the driver | ||
230 | please read <file:Documentation/input/joystick-parport.txt>. | ||
231 | |||
232 | To compile this driver as a module, choose M here: the | ||
233 | module will be called turbografx. | ||
234 | |||
235 | config JOYSTICK_AMIGA | ||
236 | tristate "Amiga joysticks" | ||
237 | depends on AMIGA | ||
238 | help | ||
239 | Say Y here if you have an Amiga with a digital joystick connected | ||
240 | to it. | ||
241 | |||
242 | To compile this driver as a module, choose M here: the | ||
243 | module will be called amijoy. | ||
244 | |||
245 | config JOYSTICK_JOYDUMP | ||
246 | tristate "Gameport data dumper" | ||
247 | select GAMEPORT | ||
248 | help | ||
249 | Say Y here if you want to dump data from your joystick into the system | ||
250 | log for debugging purposes. Say N if you are making a production | ||
251 | configuration or aren't sure. | ||
252 | |||
253 | To compile this driver as a module, choose M here: the | ||
254 | module will be called joydump. | ||
255 | |||
256 | endif | ||
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile new file mode 100644 index 000000000000..5231f6ff75b8 --- /dev/null +++ b/drivers/input/joystick/Makefile | |||
@@ -0,0 +1,30 @@ | |||
1 | # | ||
2 | # Makefile for the input core drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_JOYSTICK_A3D) += a3d.o | ||
8 | obj-$(CONFIG_JOYSTICK_ADI) += adi.o | ||
9 | obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o | ||
10 | obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o | ||
11 | obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o | ||
12 | obj-$(CONFIG_JOYSTICK_DB9) += db9.o | ||
13 | obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o | ||
14 | obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o | ||
15 | obj-$(CONFIG_JOYSTICK_GRIP) += grip.o | ||
16 | obj-$(CONFIG_JOYSTICK_GRIP_MP) += grip_mp.o | ||
17 | obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o | ||
18 | obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o | ||
19 | obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o | ||
20 | obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o | ||
21 | obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o | ||
22 | obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o | ||
23 | obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o | ||
24 | obj-$(CONFIG_JOYSTICK_STINGER) += stinger.o | ||
25 | obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o | ||
26 | obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o | ||
27 | obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o | ||
28 | obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o | ||
29 | |||
30 | obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/ | ||
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c new file mode 100644 index 000000000000..ad39fe4bf35f --- /dev/null +++ b/drivers/input/joystick/a3d.c | |||
@@ -0,0 +1,417 @@ | |||
1 | /* | ||
2 | * $Id: a3d.c,v 1.21 2002/01/22 20:11:50 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1998-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * FP-Gaming Assasin 3D joystick 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/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/gameport.h> | ||
36 | #include <linux/input.h> | ||
37 | |||
38 | #define DRIVER_DESC "FP-Gaming Assasin 3D joystick driver" | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | #define A3D_MAX_START 600 /* 600 us */ | ||
45 | #define A3D_MAX_STROBE 80 /* 80 us */ | ||
46 | #define A3D_MAX_LENGTH 40 /* 40*3 bits */ | ||
47 | |||
48 | #define A3D_MODE_A3D 1 /* Assassin 3D */ | ||
49 | #define A3D_MODE_PAN 2 /* Panther */ | ||
50 | #define A3D_MODE_OEM 3 /* Panther OEM version */ | ||
51 | #define A3D_MODE_PXL 4 /* Panther XL */ | ||
52 | |||
53 | static char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther", | ||
54 | "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" }; | ||
55 | |||
56 | struct a3d { | ||
57 | struct gameport *gameport; | ||
58 | struct gameport *adc; | ||
59 | struct input_dev dev; | ||
60 | int axes[4]; | ||
61 | int buttons; | ||
62 | int mode; | ||
63 | int length; | ||
64 | int reads; | ||
65 | int bads; | ||
66 | char phys[32]; | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | * a3d_read_packet() reads an Assassin 3D packet. | ||
71 | */ | ||
72 | |||
73 | static int a3d_read_packet(struct gameport *gameport, int length, char *data) | ||
74 | { | ||
75 | unsigned long flags; | ||
76 | unsigned char u, v; | ||
77 | unsigned int t, s; | ||
78 | int i; | ||
79 | |||
80 | i = 0; | ||
81 | t = gameport_time(gameport, A3D_MAX_START); | ||
82 | s = gameport_time(gameport, A3D_MAX_STROBE); | ||
83 | |||
84 | local_irq_save(flags); | ||
85 | gameport_trigger(gameport); | ||
86 | v = gameport_read(gameport); | ||
87 | |||
88 | while (t > 0 && i < length) { | ||
89 | t--; | ||
90 | u = v; v = gameport_read(gameport); | ||
91 | if (~v & u & 0x10) { | ||
92 | data[i++] = v >> 5; | ||
93 | t = s; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | local_irq_restore(flags); | ||
98 | |||
99 | return i; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * a3d_csum() computes checksum of triplet packet | ||
104 | */ | ||
105 | |||
106 | static int a3d_csum(char *data, int count) | ||
107 | { | ||
108 | int i, csum = 0; | ||
109 | |||
110 | for (i = 0; i < count - 2; i++) | ||
111 | csum += data[i]; | ||
112 | return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]); | ||
113 | } | ||
114 | |||
115 | static void a3d_read(struct a3d *a3d, unsigned char *data) | ||
116 | { | ||
117 | struct input_dev *dev = &a3d->dev; | ||
118 | |||
119 | switch (a3d->mode) { | ||
120 | |||
121 | case A3D_MODE_A3D: | ||
122 | case A3D_MODE_OEM: | ||
123 | case A3D_MODE_PAN: | ||
124 | |||
125 | input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7)); | ||
126 | input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7)); | ||
127 | |||
128 | input_report_key(dev, BTN_RIGHT, data[2] & 1); | ||
129 | input_report_key(dev, BTN_LEFT, data[3] & 2); | ||
130 | input_report_key(dev, BTN_MIDDLE, data[3] & 4); | ||
131 | |||
132 | input_sync(dev); | ||
133 | |||
134 | a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; | ||
135 | a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; | ||
136 | a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; | ||
137 | a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128; | ||
138 | |||
139 | a3d->buttons = ((data[3] << 3) | data[4]) & 0xf; | ||
140 | |||
141 | break; | ||
142 | |||
143 | case A3D_MODE_PXL: | ||
144 | |||
145 | input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7)); | ||
146 | input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7)); | ||
147 | |||
148 | input_report_key(dev, BTN_RIGHT, data[2] & 1); | ||
149 | input_report_key(dev, BTN_LEFT, data[3] & 2); | ||
150 | input_report_key(dev, BTN_MIDDLE, data[3] & 4); | ||
151 | input_report_key(dev, BTN_SIDE, data[7] & 2); | ||
152 | input_report_key(dev, BTN_EXTRA, data[7] & 4); | ||
153 | |||
154 | input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128); | ||
155 | input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128); | ||
156 | input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128); | ||
157 | input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128); | ||
158 | |||
159 | input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1)); | ||
160 | input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1)); | ||
161 | input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1)); | ||
162 | input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1)); | ||
163 | |||
164 | input_report_key(dev, BTN_TRIGGER, data[8] & 1); | ||
165 | input_report_key(dev, BTN_THUMB, data[8] & 2); | ||
166 | input_report_key(dev, BTN_TOP, data[8] & 4); | ||
167 | input_report_key(dev, BTN_PINKIE, data[7] & 1); | ||
168 | |||
169 | input_sync(dev); | ||
170 | |||
171 | break; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | |||
176 | /* | ||
177 | * a3d_poll() reads and analyzes A3D joystick data. | ||
178 | */ | ||
179 | |||
180 | static void a3d_poll(struct gameport *gameport) | ||
181 | { | ||
182 | struct a3d *a3d = gameport_get_drvdata(gameport); | ||
183 | unsigned char data[A3D_MAX_LENGTH]; | ||
184 | |||
185 | a3d->reads++; | ||
186 | if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length || | ||
187 | data[0] != a3d->mode || a3d_csum(data, a3d->length)) | ||
188 | a3d->bads++; | ||
189 | else | ||
190 | a3d_read(a3d, data); | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * a3d_adc_cooked_read() copies the acis and button data to the | ||
195 | * callers arrays. It could do the read itself, but the caller could | ||
196 | * call this more than 50 times a second, which would use too much CPU. | ||
197 | */ | ||
198 | |||
199 | static int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons) | ||
200 | { | ||
201 | struct a3d *a3d = gameport->port_data; | ||
202 | int i; | ||
203 | |||
204 | for (i = 0; i < 4; i++) | ||
205 | axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1; | ||
206 | *buttons = a3d->buttons; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * a3d_adc_open() is the gameport open routine. It refuses to serve | ||
212 | * any but cooked data. | ||
213 | */ | ||
214 | |||
215 | static int a3d_adc_open(struct gameport *gameport, int mode) | ||
216 | { | ||
217 | struct a3d *a3d = gameport->port_data; | ||
218 | |||
219 | if (mode != GAMEPORT_MODE_COOKED) | ||
220 | return -1; | ||
221 | |||
222 | gameport_start_polling(a3d->gameport); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * a3d_adc_close() is a callback from the input close routine. | ||
228 | */ | ||
229 | |||
230 | static void a3d_adc_close(struct gameport *gameport) | ||
231 | { | ||
232 | struct a3d *a3d = gameport->port_data; | ||
233 | |||
234 | gameport_stop_polling(a3d->gameport); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * a3d_open() is a callback from the input open routine. | ||
239 | */ | ||
240 | |||
241 | static int a3d_open(struct input_dev *dev) | ||
242 | { | ||
243 | struct a3d *a3d = dev->private; | ||
244 | |||
245 | gameport_start_polling(a3d->gameport); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * a3d_close() is a callback from the input close routine. | ||
251 | */ | ||
252 | |||
253 | static void a3d_close(struct input_dev *dev) | ||
254 | { | ||
255 | struct a3d *a3d = dev->private; | ||
256 | |||
257 | gameport_stop_polling(a3d->gameport); | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * a3d_connect() probes for A3D joysticks. | ||
262 | */ | ||
263 | |||
264 | static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
265 | { | ||
266 | struct a3d *a3d; | ||
267 | struct gameport *adc; | ||
268 | unsigned char data[A3D_MAX_LENGTH]; | ||
269 | int i; | ||
270 | int err; | ||
271 | |||
272 | if (!(a3d = kcalloc(1, sizeof(struct a3d), GFP_KERNEL))) | ||
273 | return -ENOMEM; | ||
274 | |||
275 | a3d->gameport = gameport; | ||
276 | |||
277 | gameport_set_drvdata(gameport, a3d); | ||
278 | |||
279 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
280 | if (err) | ||
281 | goto fail1; | ||
282 | |||
283 | i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data); | ||
284 | |||
285 | if (!i || a3d_csum(data, i)) { | ||
286 | err = -ENODEV; | ||
287 | goto fail2; | ||
288 | } | ||
289 | |||
290 | a3d->mode = data[0]; | ||
291 | |||
292 | if (!a3d->mode || a3d->mode > 5) { | ||
293 | printk(KERN_WARNING "a3d.c: Unknown A3D device detected " | ||
294 | "(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode); | ||
295 | err = -ENODEV; | ||
296 | goto fail2; | ||
297 | } | ||
298 | |||
299 | gameport_set_poll_handler(gameport, a3d_poll); | ||
300 | gameport_set_poll_interval(gameport, 20); | ||
301 | |||
302 | sprintf(a3d->phys, "%s/input0", gameport->phys); | ||
303 | |||
304 | if (a3d->mode == A3D_MODE_PXL) { | ||
305 | |||
306 | int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER }; | ||
307 | |||
308 | a3d->length = 33; | ||
309 | |||
310 | init_input_dev(&a3d->dev); | ||
311 | |||
312 | a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); | ||
313 | a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y); | ||
314 | a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER) | ||
315 | | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y); | ||
316 | |||
317 | a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | ||
318 | | BIT(BTN_SIDE) | BIT(BTN_EXTRA); | ||
319 | |||
320 | a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE); | ||
321 | |||
322 | a3d_read(a3d, data); | ||
323 | |||
324 | for (i = 0; i < 4; i++) { | ||
325 | if (i < 2) | ||
326 | input_set_abs_params(&a3d->dev, axes[i], 48, a3d->dev.abs[axes[i]] * 2 - 48, 0, 8); | ||
327 | else | ||
328 | input_set_abs_params(&a3d->dev, axes[i], 2, 253, 0, 0); | ||
329 | input_set_abs_params(&a3d->dev, ABS_HAT0X + i, -1, 1, 0, 0); | ||
330 | } | ||
331 | |||
332 | } else { | ||
333 | a3d->length = 29; | ||
334 | |||
335 | init_input_dev(&a3d->dev); | ||
336 | |||
337 | a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL); | ||
338 | a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y); | ||
339 | a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE); | ||
340 | |||
341 | a3d_read(a3d, data); | ||
342 | |||
343 | if (!(a3d->adc = adc = gameport_allocate_port())) | ||
344 | printk(KERN_ERR "a3d: Not enough memory for ADC port\n"); | ||
345 | else { | ||
346 | adc->port_data = a3d; | ||
347 | adc->open = a3d_adc_open; | ||
348 | adc->close = a3d_adc_close; | ||
349 | adc->cooked_read = a3d_adc_cooked_read; | ||
350 | adc->fuzz = 1; | ||
351 | |||
352 | gameport_set_name(adc, a3d_names[a3d->mode]); | ||
353 | gameport_set_phys(adc, "%s/gameport0", gameport->phys); | ||
354 | adc->dev.parent = &gameport->dev; | ||
355 | |||
356 | gameport_register_port(adc); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | a3d->dev.private = a3d; | ||
361 | a3d->dev.open = a3d_open; | ||
362 | a3d->dev.close = a3d_close; | ||
363 | |||
364 | a3d->dev.name = a3d_names[a3d->mode]; | ||
365 | a3d->dev.phys = a3d->phys; | ||
366 | a3d->dev.id.bustype = BUS_GAMEPORT; | ||
367 | a3d->dev.id.vendor = GAMEPORT_ID_VENDOR_MADCATZ; | ||
368 | a3d->dev.id.product = a3d->mode; | ||
369 | a3d->dev.id.version = 0x0100; | ||
370 | |||
371 | input_register_device(&a3d->dev); | ||
372 | printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys); | ||
373 | |||
374 | return 0; | ||
375 | |||
376 | fail2: gameport_close(gameport); | ||
377 | fail1: gameport_set_drvdata(gameport, NULL); | ||
378 | kfree(a3d); | ||
379 | return err; | ||
380 | } | ||
381 | |||
382 | static void a3d_disconnect(struct gameport *gameport) | ||
383 | { | ||
384 | struct a3d *a3d = gameport_get_drvdata(gameport); | ||
385 | |||
386 | input_unregister_device(&a3d->dev); | ||
387 | if (a3d->adc) { | ||
388 | gameport_unregister_port(a3d->adc); | ||
389 | a3d->adc = NULL; | ||
390 | } | ||
391 | gameport_close(gameport); | ||
392 | gameport_set_drvdata(gameport, NULL); | ||
393 | kfree(a3d); | ||
394 | } | ||
395 | |||
396 | static struct gameport_driver a3d_drv = { | ||
397 | .driver = { | ||
398 | .name = "adc", | ||
399 | }, | ||
400 | .description = DRIVER_DESC, | ||
401 | .connect = a3d_connect, | ||
402 | .disconnect = a3d_disconnect, | ||
403 | }; | ||
404 | |||
405 | static int __init a3d_init(void) | ||
406 | { | ||
407 | gameport_register_driver(&a3d_drv); | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static void __exit a3d_exit(void) | ||
412 | { | ||
413 | gameport_unregister_driver(&a3d_drv); | ||
414 | } | ||
415 | |||
416 | module_init(a3d_init); | ||
417 | module_exit(a3d_exit); | ||
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c new file mode 100644 index 000000000000..83f6dafc1716 --- /dev/null +++ b/drivers/input/joystick/adi.c | |||
@@ -0,0 +1,560 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1998-2005 Vojtech Pavlik | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * Logitech ADI joystick family driver for Linux | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Should you need to contact me, the author, you can do so either by | ||
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
27 | */ | ||
28 | |||
29 | #include <linux/delay.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/input.h> | ||
35 | #include <linux/gameport.h> | ||
36 | #include <linux/init.h> | ||
37 | |||
38 | #define DRIVER_DESC "Logitech ADI joystick family driver" | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | /* | ||
45 | * Times, array sizes, flags, ids. | ||
46 | */ | ||
47 | |||
48 | #define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */ | ||
49 | #define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */ | ||
50 | #define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */ | ||
51 | #define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */ | ||
52 | |||
53 | #define ADI_MAX_LENGTH 256 | ||
54 | #define ADI_MIN_LENGTH 8 | ||
55 | #define ADI_MIN_LEN_LENGTH 10 | ||
56 | #define ADI_MIN_ID_LENGTH 66 | ||
57 | #define ADI_MAX_NAME_LENGTH 48 | ||
58 | #define ADI_MAX_CNAME_LENGTH 16 | ||
59 | #define ADI_MAX_PHYS_LENGTH 64 | ||
60 | |||
61 | #define ADI_FLAG_HAT 0x04 | ||
62 | #define ADI_FLAG_10BIT 0x08 | ||
63 | |||
64 | #define ADI_ID_TPD 0x01 | ||
65 | #define ADI_ID_WGP 0x06 | ||
66 | #define ADI_ID_WGPE 0x08 | ||
67 | #define ADI_ID_MAX 0x0a | ||
68 | |||
69 | /* | ||
70 | * Names, buttons, axes ... | ||
71 | */ | ||
72 | |||
73 | static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", | ||
74 | "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", | ||
75 | "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", | ||
76 | "WingMan GamePad USB", "Unknown Device %#x" }; | ||
77 | |||
78 | static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y }; | ||
79 | static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; | ||
80 | static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y }; | ||
81 | static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; | ||
82 | static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; | ||
83 | |||
84 | static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }; | ||
85 | static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA }; | ||
86 | static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 }; | ||
87 | static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; | ||
88 | |||
89 | static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs, | ||
90 | adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs }; | ||
91 | |||
92 | static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key, | ||
93 | adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key }; | ||
94 | |||
95 | /* | ||
96 | * Hat to axis conversion arrays. | ||
97 | */ | ||
98 | |||
99 | static struct { | ||
100 | int x; | ||
101 | int y; | ||
102 | } adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | ||
103 | |||
104 | /* | ||
105 | * Per-port information. | ||
106 | */ | ||
107 | |||
108 | struct adi { | ||
109 | struct input_dev dev; | ||
110 | int length; | ||
111 | int ret; | ||
112 | int idx; | ||
113 | unsigned char id; | ||
114 | char buttons; | ||
115 | char axes10; | ||
116 | char axes8; | ||
117 | signed char pad; | ||
118 | char hats; | ||
119 | char *abs; | ||
120 | short *key; | ||
121 | char name[ADI_MAX_NAME_LENGTH]; | ||
122 | char cname[ADI_MAX_CNAME_LENGTH]; | ||
123 | char phys[ADI_MAX_PHYS_LENGTH]; | ||
124 | unsigned char data[ADI_MAX_LENGTH]; | ||
125 | }; | ||
126 | |||
127 | struct adi_port { | ||
128 | struct gameport *gameport; | ||
129 | struct adi adi[2]; | ||
130 | int bad; | ||
131 | int reads; | ||
132 | }; | ||
133 | |||
134 | /* | ||
135 | * adi_read_packet() reads a Logitech ADI packet. | ||
136 | */ | ||
137 | |||
138 | static void adi_read_packet(struct adi_port *port) | ||
139 | { | ||
140 | struct adi *adi = port->adi; | ||
141 | struct gameport *gameport = port->gameport; | ||
142 | unsigned char u, v, w, x, z; | ||
143 | int t[2], s[2], i; | ||
144 | unsigned long flags; | ||
145 | |||
146 | for (i = 0; i < 2; i++) { | ||
147 | adi[i].ret = -1; | ||
148 | t[i] = gameport_time(gameport, ADI_MAX_START); | ||
149 | s[i] = 0; | ||
150 | } | ||
151 | |||
152 | local_irq_save(flags); | ||
153 | |||
154 | gameport_trigger(gameport); | ||
155 | v = z = gameport_read(gameport); | ||
156 | |||
157 | do { | ||
158 | u = v; | ||
159 | w = u ^ (v = x = gameport_read(gameport)); | ||
160 | for (i = 0; i < 2; i++, w >>= 2, x >>= 2) { | ||
161 | t[i]--; | ||
162 | if ((w & 0x30) && s[i]) { | ||
163 | if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) { | ||
164 | adi[i].data[++adi[i].ret] = w; | ||
165 | t[i] = gameport_time(gameport, ADI_MAX_STROBE); | ||
166 | } else t[i] = 0; | ||
167 | } else if (!(x & 0x30)) s[i] = 1; | ||
168 | } | ||
169 | } while (t[0] > 0 || t[1] > 0); | ||
170 | |||
171 | local_irq_restore(flags); | ||
172 | |||
173 | return; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * adi_move_bits() detects a possible 2-stream mode, and moves | ||
178 | * the bits accordingly. | ||
179 | */ | ||
180 | |||
181 | static void adi_move_bits(struct adi_port *port, int length) | ||
182 | { | ||
183 | int i; | ||
184 | struct adi *adi = port->adi; | ||
185 | |||
186 | adi[0].idx = adi[1].idx = 0; | ||
187 | |||
188 | if (adi[0].ret <= 0 || adi[1].ret <= 0) return; | ||
189 | if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return; | ||
190 | |||
191 | for (i = 1; i <= adi[1].ret; i++) | ||
192 | adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i]; | ||
193 | |||
194 | adi[0].ret += adi[1].ret; | ||
195 | adi[1].ret = -1; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * adi_get_bits() gathers bits from the data packet. | ||
200 | */ | ||
201 | |||
202 | static inline int adi_get_bits(struct adi *adi, int count) | ||
203 | { | ||
204 | int bits = 0; | ||
205 | int i; | ||
206 | if ((adi->idx += count) > adi->ret) return 0; | ||
207 | for (i = 0; i < count; i++) | ||
208 | bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; | ||
209 | return bits; | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * adi_decode() decodes Logitech joystick data into input events. | ||
214 | */ | ||
215 | |||
216 | static int adi_decode(struct adi *adi) | ||
217 | { | ||
218 | struct input_dev *dev = &adi->dev; | ||
219 | char *abs = adi->abs; | ||
220 | short *key = adi->key; | ||
221 | int i, t; | ||
222 | |||
223 | if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4))) | ||
224 | return -1; | ||
225 | |||
226 | for (i = 0; i < adi->axes10; i++) | ||
227 | input_report_abs(dev, *abs++, adi_get_bits(adi, 10)); | ||
228 | |||
229 | for (i = 0; i < adi->axes8; i++) | ||
230 | input_report_abs(dev, *abs++, adi_get_bits(adi, 8)); | ||
231 | |||
232 | for (i = 0; i < adi->buttons && i < 63; i++) { | ||
233 | if (i == adi->pad) { | ||
234 | t = adi_get_bits(adi, 4); | ||
235 | input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1)); | ||
236 | input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1)); | ||
237 | } | ||
238 | input_report_key(dev, *key++, adi_get_bits(adi, 1)); | ||
239 | } | ||
240 | |||
241 | for (i = 0; i < adi->hats; i++) { | ||
242 | if ((t = adi_get_bits(adi, 4)) > 8) t = 0; | ||
243 | input_report_abs(dev, *abs++, adi_hat_to_axis[t].x); | ||
244 | input_report_abs(dev, *abs++, adi_hat_to_axis[t].y); | ||
245 | } | ||
246 | |||
247 | for (i = 63; i < adi->buttons; i++) | ||
248 | input_report_key(dev, *key++, adi_get_bits(adi, 1)); | ||
249 | |||
250 | input_sync(dev); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * adi_read() reads the data packet and decodes it. | ||
257 | */ | ||
258 | |||
259 | static int adi_read(struct adi_port *port) | ||
260 | { | ||
261 | int i; | ||
262 | int result = 0; | ||
263 | |||
264 | adi_read_packet(port); | ||
265 | adi_move_bits(port, port->adi[0].length); | ||
266 | |||
267 | for (i = 0; i < 2; i++) | ||
268 | if (port->adi[i].length) | ||
269 | result |= adi_decode(port->adi + i); | ||
270 | |||
271 | return result; | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * adi_poll() repeatedly polls the Logitech joysticks. | ||
276 | */ | ||
277 | |||
278 | static void adi_poll(struct gameport *gameport) | ||
279 | { | ||
280 | struct adi_port *port = gameport_get_drvdata(gameport); | ||
281 | |||
282 | port->bad -= adi_read(port); | ||
283 | port->reads++; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * adi_open() is a callback from the input open routine. | ||
288 | */ | ||
289 | |||
290 | static int adi_open(struct input_dev *dev) | ||
291 | { | ||
292 | struct adi_port *port = dev->private; | ||
293 | |||
294 | gameport_start_polling(port->gameport); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * adi_close() is a callback from the input close routine. | ||
300 | */ | ||
301 | |||
302 | static void adi_close(struct input_dev *dev) | ||
303 | { | ||
304 | struct adi_port *port = dev->private; | ||
305 | |||
306 | gameport_stop_polling(port->gameport); | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * adi_init_digital() sends a trigger & delay sequence | ||
311 | * to reset and initialize a Logitech joystick into digital mode. | ||
312 | */ | ||
313 | |||
314 | static void adi_init_digital(struct gameport *gameport) | ||
315 | { | ||
316 | int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 }; | ||
317 | int i; | ||
318 | |||
319 | for (i = 0; seq[i]; i++) { | ||
320 | gameport_trigger(gameport); | ||
321 | if (seq[i] > 0) msleep(seq[i]); | ||
322 | if (seq[i] < 0) { | ||
323 | mdelay(-seq[i]); | ||
324 | udelay(-seq[i]*14); /* It looks like mdelay() is off by approx 1.4% */ | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | static void adi_id_decode(struct adi *adi, struct adi_port *port) | ||
330 | { | ||
331 | int i, t; | ||
332 | |||
333 | if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */ | ||
334 | return; | ||
335 | |||
336 | if (adi->ret < (t = adi_get_bits(adi, 10))) { | ||
337 | printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); | ||
338 | return; | ||
339 | } | ||
340 | |||
341 | adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4); | ||
342 | |||
343 | if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++; | ||
344 | |||
345 | adi->length = adi_get_bits(adi, 10); | ||
346 | |||
347 | if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) { | ||
348 | printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length); | ||
349 | adi->length = 0; | ||
350 | return; | ||
351 | } | ||
352 | |||
353 | adi->axes8 = adi_get_bits(adi, 4); | ||
354 | adi->buttons = adi_get_bits(adi, 6); | ||
355 | |||
356 | if (adi_get_bits(adi, 6) != 8 && adi->hats) { | ||
357 | printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n"); | ||
358 | adi->length = 0; | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | adi->buttons += adi_get_bits(adi, 6); | ||
363 | adi->hats += adi_get_bits(adi, 4); | ||
364 | |||
365 | i = adi_get_bits(adi, 4); | ||
366 | |||
367 | if (t & ADI_FLAG_10BIT) { | ||
368 | adi->axes10 = adi->axes8 - i; | ||
369 | adi->axes8 = i; | ||
370 | } | ||
371 | |||
372 | t = adi_get_bits(adi, 4); | ||
373 | |||
374 | for (i = 0; i < t; i++) | ||
375 | adi->cname[i] = adi_get_bits(adi, 8); | ||
376 | adi->cname[i] = 0; | ||
377 | |||
378 | t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4; | ||
379 | if (adi->length != t && adi->length != t + (t & 1)) { | ||
380 | printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length); | ||
381 | adi->length = 0; | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | switch (adi->id) { | ||
386 | case ADI_ID_TPD: | ||
387 | adi->pad = 4; | ||
388 | adi->buttons -= 4; | ||
389 | break; | ||
390 | case ADI_ID_WGP: | ||
391 | adi->pad = 0; | ||
392 | adi->buttons -= 4; | ||
393 | break; | ||
394 | default: | ||
395 | adi->pad = -1; | ||
396 | break; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | static void adi_init_input(struct adi *adi, struct adi_port *port, int half) | ||
401 | { | ||
402 | int i, t; | ||
403 | char buf[ADI_MAX_NAME_LENGTH]; | ||
404 | |||
405 | if (!adi->length) return; | ||
406 | |||
407 | init_input_dev(&adi->dev); | ||
408 | |||
409 | t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX; | ||
410 | |||
411 | snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id); | ||
412 | snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s", buf); | ||
413 | snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half); | ||
414 | |||
415 | adi->abs = adi_abs[t]; | ||
416 | adi->key = adi_key[t]; | ||
417 | |||
418 | adi->dev.open = adi_open; | ||
419 | adi->dev.close = adi_close; | ||
420 | |||
421 | adi->dev.name = adi->name; | ||
422 | adi->dev.phys = adi->phys; | ||
423 | adi->dev.id.bustype = BUS_GAMEPORT; | ||
424 | adi->dev.id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; | ||
425 | adi->dev.id.product = adi->id; | ||
426 | adi->dev.id.version = 0x0100; | ||
427 | |||
428 | adi->dev.private = port; | ||
429 | adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
430 | |||
431 | for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) | ||
432 | set_bit(adi->abs[i], adi->dev.absbit); | ||
433 | |||
434 | for (i = 0; i < adi->buttons; i++) | ||
435 | set_bit(adi->key[i], adi->dev.keybit); | ||
436 | } | ||
437 | |||
438 | static void adi_init_center(struct adi *adi) | ||
439 | { | ||
440 | int i, t, x; | ||
441 | |||
442 | if (!adi->length) | ||
443 | return; | ||
444 | |||
445 | for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { | ||
446 | |||
447 | t = adi->abs[i]; | ||
448 | x = adi->dev.abs[t]; | ||
449 | |||
450 | if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) | ||
451 | x = i < adi->axes10 ? 512 : 128; | ||
452 | |||
453 | if (i < adi->axes10) | ||
454 | input_set_abs_params(&adi->dev, t, 64, x * 2 - 64, 2, 16); | ||
455 | else if (i < adi->axes10 + adi->axes8) | ||
456 | input_set_abs_params(&adi->dev, t, 48, x * 2 - 48, 1, 16); | ||
457 | else | ||
458 | input_set_abs_params(&adi->dev, t, -1, 1, 0, 0); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * adi_connect() probes for Logitech ADI joysticks. | ||
464 | */ | ||
465 | |||
466 | static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
467 | { | ||
468 | struct adi_port *port; | ||
469 | int i; | ||
470 | int err; | ||
471 | |||
472 | if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL))) | ||
473 | return -ENOMEM; | ||
474 | |||
475 | port->gameport = gameport; | ||
476 | |||
477 | gameport_set_drvdata(gameport, port); | ||
478 | |||
479 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
480 | if (err) { | ||
481 | kfree(port); | ||
482 | return err; | ||
483 | } | ||
484 | |||
485 | adi_init_digital(gameport); | ||
486 | adi_read_packet(port); | ||
487 | |||
488 | if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH) | ||
489 | adi_move_bits(port, adi_get_bits(port->adi, 10)); | ||
490 | |||
491 | for (i = 0; i < 2; i++) { | ||
492 | adi_id_decode(port->adi + i, port); | ||
493 | adi_init_input(port->adi + i, port, i); | ||
494 | } | ||
495 | |||
496 | if (!port->adi[0].length && !port->adi[1].length) { | ||
497 | gameport_close(gameport); | ||
498 | kfree(port); | ||
499 | return -ENODEV; | ||
500 | } | ||
501 | |||
502 | gameport_set_poll_handler(gameport, adi_poll); | ||
503 | gameport_set_poll_interval(gameport, 20); | ||
504 | |||
505 | msleep(ADI_INIT_DELAY); | ||
506 | if (adi_read(port)) { | ||
507 | msleep(ADI_DATA_DELAY); | ||
508 | adi_read(port); | ||
509 | } | ||
510 | |||
511 | for (i = 0; i < 2; i++) | ||
512 | if (port->adi[i].length > 0) { | ||
513 | adi_init_center(port->adi + i); | ||
514 | input_register_device(&port->adi[i].dev); | ||
515 | printk(KERN_INFO "input: %s [%s] on %s\n", | ||
516 | port->adi[i].name, port->adi[i].cname, gameport->phys); | ||
517 | } | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static void adi_disconnect(struct gameport *gameport) | ||
523 | { | ||
524 | int i; | ||
525 | struct adi_port *port = gameport_get_drvdata(gameport); | ||
526 | |||
527 | for (i = 0; i < 2; i++) | ||
528 | if (port->adi[i].length > 0) | ||
529 | input_unregister_device(&port->adi[i].dev); | ||
530 | gameport_close(gameport); | ||
531 | gameport_set_drvdata(gameport, NULL); | ||
532 | kfree(port); | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * The gameport device structure. | ||
537 | */ | ||
538 | |||
539 | static struct gameport_driver adi_drv = { | ||
540 | .driver = { | ||
541 | .name = "adi", | ||
542 | }, | ||
543 | .description = DRIVER_DESC, | ||
544 | .connect = adi_connect, | ||
545 | .disconnect = adi_disconnect, | ||
546 | }; | ||
547 | |||
548 | static int __init adi_init(void) | ||
549 | { | ||
550 | gameport_register_driver(&adi_drv); | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static void __exit adi_exit(void) | ||
555 | { | ||
556 | gameport_unregister_driver(&adi_drv); | ||
557 | } | ||
558 | |||
559 | module_init(adi_init); | ||
560 | module_exit(adi_exit); | ||
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c new file mode 100644 index 000000000000..cf36ca9b92f3 --- /dev/null +++ b/drivers/input/joystick/amijoy.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * $Id: amijoy.c,v 1.13 2002/01/22 20:26:32 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1998-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Driver for Amiga joysticks for Linux/m68k | ||
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/types.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/input.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | |||
40 | #include <asm/system.h> | ||
41 | #include <asm/amigahw.h> | ||
42 | #include <asm/amigaints.h> | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
45 | MODULE_DESCRIPTION("Driver for Amiga joysticks"); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | static int amijoy[2] = { 0, 1 }; | ||
49 | module_param_array_named(map, amijoy, uint, NULL, 0); | ||
50 | MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)"); | ||
51 | |||
52 | __obsolete_setup("amijoy="); | ||
53 | |||
54 | static int amijoy_used[2] = { 0, 0 }; | ||
55 | static struct input_dev amijoy_dev[2]; | ||
56 | static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; | ||
57 | |||
58 | static char *amijoy_name = "Amiga joystick"; | ||
59 | |||
60 | static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) | ||
61 | { | ||
62 | int i, data = 0, button = 0; | ||
63 | |||
64 | for (i = 0; i < 2; i++) | ||
65 | if (amijoy[i]) { | ||
66 | |||
67 | switch (i) { | ||
68 | case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break; | ||
69 | case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break; | ||
70 | } | ||
71 | |||
72 | input_regs(amijoy_dev + i, fp); | ||
73 | |||
74 | input_report_key(amijoy_dev + i, BTN_TRIGGER, button); | ||
75 | |||
76 | input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); | ||
77 | data = ~(data ^ (data << 1)); | ||
78 | input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); | ||
79 | |||
80 | input_sync(amijoy_dev + i); | ||
81 | } | ||
82 | return IRQ_HANDLED; | ||
83 | } | ||
84 | |||
85 | static int amijoy_open(struct input_dev *dev) | ||
86 | { | ||
87 | int *used = dev->private; | ||
88 | |||
89 | if ((*used)++) | ||
90 | return 0; | ||
91 | |||
92 | if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) { | ||
93 | (*used)--; | ||
94 | printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB); | ||
95 | return -EBUSY; | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static void amijoy_close(struct input_dev *dev) | ||
102 | { | ||
103 | int *used = dev->private; | ||
104 | |||
105 | if (!--(*used)) | ||
106 | free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); | ||
107 | } | ||
108 | |||
109 | static int __init amijoy_init(void) | ||
110 | { | ||
111 | int i, j; | ||
112 | |||
113 | for (i = 0; i < 2; i++) | ||
114 | if (amijoy[i]) { | ||
115 | if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2, | ||
116 | "amijoy [Denise]")) { | ||
117 | if (i == 1 && amijoy[0]) { | ||
118 | input_unregister_device(amijoy_dev); | ||
119 | release_mem_region(CUSTOM_PHYSADDR+10, 2); | ||
120 | } | ||
121 | return -EBUSY; | ||
122 | } | ||
123 | |||
124 | amijoy_dev[i].open = amijoy_open; | ||
125 | amijoy_dev[i].close = amijoy_close; | ||
126 | amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
127 | amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | ||
128 | amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
129 | for (j = 0; j < 2; j++) { | ||
130 | amijoy_dev[i].absmin[ABS_X + j] = -1; | ||
131 | amijoy_dev[i].absmax[ABS_X + j] = 1; | ||
132 | } | ||
133 | |||
134 | amijoy_dev[i].name = amijoy_name; | ||
135 | amijoy_dev[i].phys = amijoy_phys[i]; | ||
136 | amijoy_dev[i].id.bustype = BUS_AMIGA; | ||
137 | amijoy_dev[i].id.vendor = 0x0001; | ||
138 | amijoy_dev[i].id.product = 0x0003; | ||
139 | amijoy_dev[i].id.version = 0x0100; | ||
140 | |||
141 | amijoy_dev[i].private = amijoy_used + i; | ||
142 | |||
143 | input_register_device(amijoy_dev + i); | ||
144 | printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i); | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static void __exit amijoy_exit(void) | ||
150 | { | ||
151 | int i; | ||
152 | |||
153 | for (i = 0; i < 2; i++) | ||
154 | if (amijoy[i]) { | ||
155 | input_unregister_device(amijoy_dev + i); | ||
156 | release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | module_init(amijoy_init); | ||
161 | module_exit(amijoy_exit); | ||
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c new file mode 100644 index 000000000000..504b7d550567 --- /dev/null +++ b/drivers/input/joystick/analog.c | |||
@@ -0,0 +1,772 @@ | |||
1 | /* | ||
2 | * $Id: analog.c,v 1.68 2002/01/22 20:18:32 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1996-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Analog joystick and gamepad 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/config.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/bitops.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/input.h> | ||
40 | #include <linux/gameport.h> | ||
41 | #include <asm/timex.h> | ||
42 | |||
43 | #define DRIVER_DESC "Analog joystick and gamepad driver" | ||
44 | |||
45 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
46 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | |||
49 | /* | ||
50 | * Option parsing. | ||
51 | */ | ||
52 | |||
53 | #define ANALOG_PORTS 16 | ||
54 | |||
55 | static char *js[ANALOG_PORTS]; | ||
56 | static int js_nargs; | ||
57 | static int analog_options[ANALOG_PORTS]; | ||
58 | module_param_array_named(map, js, charp, &js_nargs, 0); | ||
59 | MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities"); | ||
60 | |||
61 | __obsolete_setup("js="); | ||
62 | |||
63 | /* | ||
64 | * Times, feature definitions. | ||
65 | */ | ||
66 | |||
67 | #define ANALOG_RUDDER 0x00004 | ||
68 | #define ANALOG_THROTTLE 0x00008 | ||
69 | #define ANALOG_AXES_STD 0x0000f | ||
70 | #define ANALOG_BTNS_STD 0x000f0 | ||
71 | |||
72 | #define ANALOG_BTNS_CHF 0x00100 | ||
73 | #define ANALOG_HAT1_CHF 0x00200 | ||
74 | #define ANALOG_HAT2_CHF 0x00400 | ||
75 | #define ANALOG_HAT_FCS 0x00800 | ||
76 | #define ANALOG_HATS_ALL 0x00e00 | ||
77 | #define ANALOG_BTN_TL 0x01000 | ||
78 | #define ANALOG_BTN_TR 0x02000 | ||
79 | #define ANALOG_BTN_TL2 0x04000 | ||
80 | #define ANALOG_BTN_TR2 0x08000 | ||
81 | #define ANALOG_BTNS_TLR 0x03000 | ||
82 | #define ANALOG_BTNS_TLR2 0x0c000 | ||
83 | #define ANALOG_BTNS_GAMEPAD 0x0f000 | ||
84 | |||
85 | #define ANALOG_HBTN_CHF 0x10000 | ||
86 | #define ANALOG_ANY_CHF 0x10700 | ||
87 | #define ANALOG_SAITEK 0x20000 | ||
88 | #define ANALOG_EXTENSIONS 0x7ff00 | ||
89 | #define ANALOG_GAMEPAD 0x80000 | ||
90 | |||
91 | #define ANALOG_MAX_TIME 3 /* 3 ms */ | ||
92 | #define ANALOG_LOOP_TIME 2000 /* 2 * loop */ | ||
93 | #define ANALOG_SAITEK_DELAY 200 /* 200 us */ | ||
94 | #define ANALOG_SAITEK_TIME 2000 /* 2000 us */ | ||
95 | #define ANALOG_AXIS_TIME 2 /* 2 * refresh */ | ||
96 | #define ANALOG_INIT_RETRIES 8 /* 8 times */ | ||
97 | #define ANALOG_FUZZ_BITS 2 /* 2 bit more */ | ||
98 | #define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */ | ||
99 | |||
100 | #define ANALOG_MAX_NAME_LENGTH 128 | ||
101 | #define ANALOG_MAX_PHYS_LENGTH 32 | ||
102 | |||
103 | static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE }; | ||
104 | static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; | ||
105 | static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR }; | ||
106 | static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS }; | ||
107 | static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE }; | ||
108 | static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, | ||
109 | BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 }; | ||
110 | |||
111 | static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 }; | ||
112 | |||
113 | struct analog { | ||
114 | struct input_dev dev; | ||
115 | int mask; | ||
116 | short *buttons; | ||
117 | char name[ANALOG_MAX_NAME_LENGTH]; | ||
118 | char phys[ANALOG_MAX_PHYS_LENGTH]; | ||
119 | }; | ||
120 | |||
121 | struct analog_port { | ||
122 | struct gameport *gameport; | ||
123 | struct analog analog[2]; | ||
124 | unsigned char mask; | ||
125 | char saitek; | ||
126 | char cooked; | ||
127 | int bads; | ||
128 | int reads; | ||
129 | int speed; | ||
130 | int loop; | ||
131 | int fuzz; | ||
132 | int axes[4]; | ||
133 | int buttons; | ||
134 | int initial[4]; | ||
135 | int axtime; | ||
136 | }; | ||
137 | |||
138 | /* | ||
139 | * Time macros. | ||
140 | */ | ||
141 | |||
142 | #ifdef __i386__ | ||
143 | #define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0) | ||
144 | #define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0))) | ||
145 | #define TIME_NAME (cpu_has_tsc?"TSC":"PIT") | ||
146 | static unsigned int get_time_pit(void) | ||
147 | { | ||
148 | extern spinlock_t i8253_lock; | ||
149 | unsigned long flags; | ||
150 | unsigned int count; | ||
151 | |||
152 | spin_lock_irqsave(&i8253_lock, flags); | ||
153 | outb_p(0x00, 0x43); | ||
154 | count = inb_p(0x40); | ||
155 | count |= inb_p(0x40) << 8; | ||
156 | spin_unlock_irqrestore(&i8253_lock, flags); | ||
157 | |||
158 | return count; | ||
159 | } | ||
160 | #elif defined(__x86_64__) | ||
161 | #define GET_TIME(x) rdtscl(x) | ||
162 | #define DELTA(x,y) ((y)-(x)) | ||
163 | #define TIME_NAME "TSC" | ||
164 | #elif defined(__alpha__) | ||
165 | #define GET_TIME(x) do { x = get_cycles(); } while (0) | ||
166 | #define DELTA(x,y) ((y)-(x)) | ||
167 | #define TIME_NAME "PCC" | ||
168 | #else | ||
169 | #define FAKE_TIME | ||
170 | static unsigned long analog_faketime = 0; | ||
171 | #define GET_TIME(x) do { x = analog_faketime++; } while(0) | ||
172 | #define DELTA(x,y) ((y)-(x)) | ||
173 | #define TIME_NAME "Unreliable" | ||
174 | #warning Precise timer not defined for this architecture. | ||
175 | #endif | ||
176 | |||
177 | /* | ||
178 | * analog_decode() decodes analog joystick data and reports input events. | ||
179 | */ | ||
180 | |||
181 | static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons) | ||
182 | { | ||
183 | struct input_dev *dev = &analog->dev; | ||
184 | int i, j; | ||
185 | |||
186 | if (analog->mask & ANALOG_HAT_FCS) | ||
187 | for (i = 0; i < 4; i++) | ||
188 | if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) { | ||
189 | buttons |= 1 << (i + 14); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | for (i = j = 0; i < 6; i++) | ||
194 | if (analog->mask & (0x10 << i)) | ||
195 | input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1); | ||
196 | |||
197 | if (analog->mask & ANALOG_HBTN_CHF) | ||
198 | for (i = 0; i < 4; i++) | ||
199 | input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1); | ||
200 | |||
201 | if (analog->mask & ANALOG_BTN_TL) | ||
202 | input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1)); | ||
203 | if (analog->mask & ANALOG_BTN_TR) | ||
204 | input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1)); | ||
205 | if (analog->mask & ANALOG_BTN_TL2) | ||
206 | input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1))); | ||
207 | if (analog->mask & ANALOG_BTN_TR2) | ||
208 | input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1))); | ||
209 | |||
210 | for (i = j = 0; i < 4; i++) | ||
211 | if (analog->mask & (1 << i)) | ||
212 | input_report_abs(dev, analog_axes[j++], axes[i]); | ||
213 | |||
214 | for (i = j = 0; i < 3; i++) | ||
215 | if (analog->mask & analog_exts[i]) { | ||
216 | input_report_abs(dev, analog_hats[j++], | ||
217 | ((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1)); | ||
218 | input_report_abs(dev, analog_hats[j++], | ||
219 | ((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1)); | ||
220 | } | ||
221 | |||
222 | input_sync(dev); | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * analog_cooked_read() reads analog joystick data. | ||
227 | */ | ||
228 | |||
229 | static int analog_cooked_read(struct analog_port *port) | ||
230 | { | ||
231 | struct gameport *gameport = port->gameport; | ||
232 | unsigned int time[4], start, loop, now, loopout, timeout; | ||
233 | unsigned char data[4], this, last; | ||
234 | unsigned long flags; | ||
235 | int i, j; | ||
236 | |||
237 | loopout = (ANALOG_LOOP_TIME * port->loop) / 1000; | ||
238 | timeout = ANALOG_MAX_TIME * port->speed; | ||
239 | |||
240 | local_irq_save(flags); | ||
241 | gameport_trigger(gameport); | ||
242 | GET_TIME(now); | ||
243 | local_irq_restore(flags); | ||
244 | |||
245 | start = now; | ||
246 | this = port->mask; | ||
247 | i = 0; | ||
248 | |||
249 | do { | ||
250 | loop = now; | ||
251 | last = this; | ||
252 | |||
253 | local_irq_disable(); | ||
254 | this = gameport_read(gameport) & port->mask; | ||
255 | GET_TIME(now); | ||
256 | local_irq_restore(flags); | ||
257 | |||
258 | if ((last ^ this) && (DELTA(loop, now) < loopout)) { | ||
259 | data[i] = last ^ this; | ||
260 | time[i] = now; | ||
261 | i++; | ||
262 | } | ||
263 | |||
264 | } while (this && (i < 4) && (DELTA(start, now) < timeout)); | ||
265 | |||
266 | this <<= 4; | ||
267 | |||
268 | for (--i; i >= 0; i--) { | ||
269 | this |= data[i]; | ||
270 | for (j = 0; j < 4; j++) | ||
271 | if (data[i] & (1 << j)) | ||
272 | port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; | ||
273 | } | ||
274 | |||
275 | return -(this != port->mask); | ||
276 | } | ||
277 | |||
278 | static int analog_button_read(struct analog_port *port, char saitek, char chf) | ||
279 | { | ||
280 | unsigned char u; | ||
281 | int t = 1, i = 0; | ||
282 | int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME); | ||
283 | |||
284 | u = gameport_read(port->gameport); | ||
285 | |||
286 | if (!chf) { | ||
287 | port->buttons = (~u >> 4) & 0xf; | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | port->buttons = 0; | ||
292 | |||
293 | while ((~u & 0xf0) && (i < 16) && t) { | ||
294 | port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf]; | ||
295 | if (!saitek) return 0; | ||
296 | udelay(ANALOG_SAITEK_DELAY); | ||
297 | t = strobe; | ||
298 | gameport_trigger(port->gameport); | ||
299 | while (((u = gameport_read(port->gameport)) & port->mask) && t) t--; | ||
300 | i++; | ||
301 | } | ||
302 | |||
303 | return -(!t || (i == 16)); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * analog_poll() repeatedly polls the Analog joysticks. | ||
308 | */ | ||
309 | |||
310 | static void analog_poll(struct gameport *gameport) | ||
311 | { | ||
312 | struct analog_port *port = gameport_get_drvdata(gameport); | ||
313 | int i; | ||
314 | |||
315 | char saitek = !!(port->analog[0].mask & ANALOG_SAITEK); | ||
316 | char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF); | ||
317 | |||
318 | if (port->cooked) { | ||
319 | port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons); | ||
320 | if (chf) | ||
321 | port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0; | ||
322 | port->reads++; | ||
323 | } else { | ||
324 | if (!port->axtime--) { | ||
325 | port->bads -= analog_cooked_read(port); | ||
326 | port->bads -= analog_button_read(port, saitek, chf); | ||
327 | port->reads++; | ||
328 | port->axtime = ANALOG_AXIS_TIME - 1; | ||
329 | } else { | ||
330 | if (!saitek) | ||
331 | analog_button_read(port, saitek, chf); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | for (i = 0; i < 2; i++) | ||
336 | if (port->analog[i].mask) | ||
337 | analog_decode(port->analog + i, port->axes, port->initial, port->buttons); | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * analog_open() is a callback from the input open routine. | ||
342 | */ | ||
343 | |||
344 | static int analog_open(struct input_dev *dev) | ||
345 | { | ||
346 | struct analog_port *port = dev->private; | ||
347 | |||
348 | gameport_start_polling(port->gameport); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * analog_close() is a callback from the input close routine. | ||
354 | */ | ||
355 | |||
356 | static void analog_close(struct input_dev *dev) | ||
357 | { | ||
358 | struct analog_port *port = dev->private; | ||
359 | |||
360 | gameport_stop_polling(port->gameport); | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * analog_calibrate_timer() calibrates the timer and computes loop | ||
365 | * and timeout values for a joystick port. | ||
366 | */ | ||
367 | |||
368 | static void analog_calibrate_timer(struct analog_port *port) | ||
369 | { | ||
370 | struct gameport *gameport = port->gameport; | ||
371 | unsigned int i, t, tx, t1, t2, t3; | ||
372 | unsigned long flags; | ||
373 | |||
374 | local_irq_save(flags); | ||
375 | GET_TIME(t1); | ||
376 | #ifdef FAKE_TIME | ||
377 | analog_faketime += 830; | ||
378 | #endif | ||
379 | mdelay(1); | ||
380 | GET_TIME(t2); | ||
381 | GET_TIME(t3); | ||
382 | local_irq_restore(flags); | ||
383 | |||
384 | port->speed = DELTA(t1, t2) - DELTA(t2, t3); | ||
385 | |||
386 | tx = ~0; | ||
387 | |||
388 | for (i = 0; i < 50; i++) { | ||
389 | local_irq_save(flags); | ||
390 | GET_TIME(t1); | ||
391 | for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); } | ||
392 | GET_TIME(t3); | ||
393 | local_irq_restore(flags); | ||
394 | udelay(i); | ||
395 | t = DELTA(t1, t2) - DELTA(t2, t3); | ||
396 | if (t < tx) tx = t; | ||
397 | } | ||
398 | |||
399 | port->loop = tx / 50; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * analog_name() constructs a name for an analog joystick. | ||
404 | */ | ||
405 | |||
406 | static void analog_name(struct analog *analog) | ||
407 | { | ||
408 | sprintf(analog->name, "Analog %d-axis %d-button", | ||
409 | hweight8(analog->mask & ANALOG_AXES_STD), | ||
410 | hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 + | ||
411 | hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4); | ||
412 | |||
413 | if (analog->mask & ANALOG_HATS_ALL) | ||
414 | sprintf(analog->name, "%s %d-hat", | ||
415 | analog->name, hweight16(analog->mask & ANALOG_HATS_ALL)); | ||
416 | |||
417 | if (analog->mask & ANALOG_HAT_FCS) | ||
418 | strcat(analog->name, " FCS"); | ||
419 | if (analog->mask & ANALOG_ANY_CHF) | ||
420 | strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF"); | ||
421 | |||
422 | strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick"); | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * analog_init_device() | ||
427 | */ | ||
428 | |||
429 | static void analog_init_device(struct analog_port *port, struct analog *analog, int index) | ||
430 | { | ||
431 | int i, j, t, v, w, x, y, z; | ||
432 | |||
433 | analog_name(analog); | ||
434 | sprintf(analog->phys, "%s/input%d", port->gameport->phys, index); | ||
435 | analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; | ||
436 | |||
437 | init_input_dev(&analog->dev); | ||
438 | |||
439 | analog->dev.name = analog->name; | ||
440 | analog->dev.phys = analog->phys; | ||
441 | analog->dev.id.bustype = BUS_GAMEPORT; | ||
442 | analog->dev.id.vendor = GAMEPORT_ID_VENDOR_ANALOG; | ||
443 | analog->dev.id.product = analog->mask >> 4; | ||
444 | analog->dev.id.version = 0x0100; | ||
445 | |||
446 | analog->dev.open = analog_open; | ||
447 | analog->dev.close = analog_close; | ||
448 | analog->dev.private = port; | ||
449 | analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
450 | |||
451 | for (i = j = 0; i < 4; i++) | ||
452 | if (analog->mask & (1 << i)) { | ||
453 | |||
454 | t = analog_axes[j]; | ||
455 | x = port->axes[i]; | ||
456 | y = (port->axes[0] + port->axes[1]) >> 1; | ||
457 | z = y - port->axes[i]; | ||
458 | z = z > 0 ? z : -z; | ||
459 | v = (x >> 3); | ||
460 | w = (x >> 3); | ||
461 | |||
462 | set_bit(t, analog->dev.absbit); | ||
463 | |||
464 | if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3))) | ||
465 | x = y; | ||
466 | |||
467 | if (analog->mask & ANALOG_SAITEK) { | ||
468 | if (i == 2) x = port->axes[i]; | ||
469 | v = x - (x >> 2); | ||
470 | w = (x >> 4); | ||
471 | } | ||
472 | |||
473 | analog->dev.absmax[t] = (x << 1) - v; | ||
474 | analog->dev.absmin[t] = v; | ||
475 | analog->dev.absfuzz[t] = port->fuzz; | ||
476 | analog->dev.absflat[t] = w; | ||
477 | |||
478 | j++; | ||
479 | } | ||
480 | |||
481 | for (i = j = 0; i < 3; i++) | ||
482 | if (analog->mask & analog_exts[i]) | ||
483 | for (x = 0; x < 2; x++) { | ||
484 | t = analog_hats[j++]; | ||
485 | set_bit(t, analog->dev.absbit); | ||
486 | analog->dev.absmax[t] = 1; | ||
487 | analog->dev.absmin[t] = -1; | ||
488 | } | ||
489 | |||
490 | for (i = j = 0; i < 4; i++) | ||
491 | if (analog->mask & (0x10 << i)) | ||
492 | set_bit(analog->buttons[j++], analog->dev.keybit); | ||
493 | |||
494 | if (analog->mask & ANALOG_BTNS_CHF) | ||
495 | for (i = 0; i < 2; i++) | ||
496 | set_bit(analog->buttons[j++], analog->dev.keybit); | ||
497 | |||
498 | if (analog->mask & ANALOG_HBTN_CHF) | ||
499 | for (i = 0; i < 4; i++) | ||
500 | set_bit(analog->buttons[j++], analog->dev.keybit); | ||
501 | |||
502 | for (i = 0; i < 4; i++) | ||
503 | if (analog->mask & (ANALOG_BTN_TL << i)) | ||
504 | set_bit(analog_pads[i], analog->dev.keybit); | ||
505 | |||
506 | analog_decode(analog, port->axes, port->initial, port->buttons); | ||
507 | |||
508 | input_register_device(&analog->dev); | ||
509 | |||
510 | printk(KERN_INFO "input: %s at %s", analog->name, port->gameport->phys); | ||
511 | |||
512 | if (port->cooked) | ||
513 | printk(" [ADC port]\n"); | ||
514 | else | ||
515 | printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME, | ||
516 | port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed, | ||
517 | port->speed > 10000 ? "M" : "k", | ||
518 | port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000) | ||
519 | : (port->loop * 1000000) / port->speed); | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * analog_init_devices() sets up device-specific values and registers the input devices. | ||
524 | */ | ||
525 | |||
526 | static int analog_init_masks(struct analog_port *port) | ||
527 | { | ||
528 | int i; | ||
529 | struct analog *analog = port->analog; | ||
530 | int max[4]; | ||
531 | |||
532 | if (!port->mask) | ||
533 | return -1; | ||
534 | |||
535 | if ((port->mask & 3) != 3 && port->mask != 0xc) { | ||
536 | printk(KERN_WARNING "analog.c: Unknown joystick device found " | ||
537 | "(data=%#x, %s), probably not analog joystick.\n", | ||
538 | port->mask, port->gameport->phys); | ||
539 | return -1; | ||
540 | } | ||
541 | |||
542 | |||
543 | i = analog_options[0]; /* FIXME !!! - need to specify options for different ports */ | ||
544 | |||
545 | analog[0].mask = i & 0xfffff; | ||
546 | |||
547 | analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD) | ||
548 | | port->mask | ((port->mask << 8) & ANALOG_HAT_FCS) | ||
549 | | ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2); | ||
550 | |||
551 | analog[0].mask &= ~(ANALOG_HAT2_CHF) | ||
552 | | ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF); | ||
553 | |||
554 | analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2) | ||
555 | | ((~analog[0].mask & ANALOG_HAT_FCS) >> 8) | ||
556 | | ((~analog[0].mask & ANALOG_HAT_FCS) << 2) | ||
557 | | ((~analog[0].mask & ANALOG_HAT_FCS) << 4); | ||
558 | |||
559 | analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER) | ||
560 | | (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10) | ||
561 | & ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12)); | ||
562 | |||
563 | analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000); | ||
564 | |||
565 | analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD | ||
566 | : (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD); | ||
567 | |||
568 | if (port->cooked) { | ||
569 | |||
570 | for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1; | ||
571 | |||
572 | if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1; | ||
573 | if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1; | ||
574 | if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1; | ||
575 | if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1; | ||
576 | if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1; | ||
577 | |||
578 | gameport_calibrate(port->gameport, port->axes, max); | ||
579 | } | ||
580 | |||
581 | for (i = 0; i < 4; i++) | ||
582 | port->initial[i] = port->axes[i]; | ||
583 | |||
584 | return -!(analog[0].mask || analog[1].mask); | ||
585 | } | ||
586 | |||
587 | static int analog_init_port(struct gameport *gameport, struct gameport_driver *drv, struct analog_port *port) | ||
588 | { | ||
589 | int i, t, u, v; | ||
590 | |||
591 | port->gameport = gameport; | ||
592 | |||
593 | gameport_set_drvdata(gameport, port); | ||
594 | |||
595 | if (!gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) { | ||
596 | |||
597 | analog_calibrate_timer(port); | ||
598 | |||
599 | gameport_trigger(gameport); | ||
600 | t = gameport_read(gameport); | ||
601 | msleep(ANALOG_MAX_TIME); | ||
602 | port->mask = (gameport_read(gameport) ^ t) & t & 0xf; | ||
603 | port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS; | ||
604 | |||
605 | for (i = 0; i < ANALOG_INIT_RETRIES; i++) { | ||
606 | if (!analog_cooked_read(port)) | ||
607 | break; | ||
608 | msleep(ANALOG_MAX_TIME); | ||
609 | } | ||
610 | |||
611 | u = v = 0; | ||
612 | |||
613 | msleep(ANALOG_MAX_TIME); | ||
614 | t = gameport_time(gameport, ANALOG_MAX_TIME * 1000); | ||
615 | gameport_trigger(gameport); | ||
616 | while ((gameport_read(port->gameport) & port->mask) && (u < t)) | ||
617 | u++; | ||
618 | udelay(ANALOG_SAITEK_DELAY); | ||
619 | t = gameport_time(gameport, ANALOG_SAITEK_TIME); | ||
620 | gameport_trigger(gameport); | ||
621 | while ((gameport_read(port->gameport) & port->mask) && (v < t)) | ||
622 | v++; | ||
623 | |||
624 | if (v < (u >> 1)) { /* FIXME - more than one port */ | ||
625 | analog_options[0] |= /* FIXME - more than one port */ | ||
626 | ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF; | ||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | gameport_close(gameport); | ||
631 | } | ||
632 | |||
633 | if (!gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) { | ||
634 | |||
635 | for (i = 0; i < ANALOG_INIT_RETRIES; i++) | ||
636 | if (!gameport_cooked_read(gameport, port->axes, &port->buttons)) | ||
637 | break; | ||
638 | for (i = 0; i < 4; i++) | ||
639 | if (port->axes[i] != -1) | ||
640 | port->mask |= 1 << i; | ||
641 | |||
642 | port->fuzz = gameport->fuzz; | ||
643 | port->cooked = 1; | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | return gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
648 | } | ||
649 | |||
650 | static int analog_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
651 | { | ||
652 | struct analog_port *port; | ||
653 | int i; | ||
654 | int err; | ||
655 | |||
656 | if (!(port = kcalloc(1, sizeof(struct analog_port), GFP_KERNEL))) | ||
657 | return - ENOMEM; | ||
658 | |||
659 | err = analog_init_port(gameport, drv, port); | ||
660 | if (err) { | ||
661 | kfree(port); | ||
662 | return err; | ||
663 | } | ||
664 | |||
665 | err = analog_init_masks(port); | ||
666 | if (err) { | ||
667 | gameport_close(gameport); | ||
668 | gameport_set_drvdata(gameport, NULL); | ||
669 | kfree(port); | ||
670 | return err; | ||
671 | } | ||
672 | |||
673 | gameport_set_poll_handler(gameport, analog_poll); | ||
674 | gameport_set_poll_interval(gameport, 10); | ||
675 | |||
676 | for (i = 0; i < 2; i++) | ||
677 | if (port->analog[i].mask) | ||
678 | analog_init_device(port, port->analog + i, i); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static void analog_disconnect(struct gameport *gameport) | ||
684 | { | ||
685 | int i; | ||
686 | struct analog_port *port = gameport_get_drvdata(gameport); | ||
687 | |||
688 | for (i = 0; i < 2; i++) | ||
689 | if (port->analog[i].mask) | ||
690 | input_unregister_device(&port->analog[i].dev); | ||
691 | gameport_close(gameport); | ||
692 | gameport_set_drvdata(gameport, NULL); | ||
693 | printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n", | ||
694 | port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0, | ||
695 | port->gameport->phys); | ||
696 | kfree(port); | ||
697 | } | ||
698 | |||
699 | struct analog_types { | ||
700 | char *name; | ||
701 | int value; | ||
702 | }; | ||
703 | |||
704 | static struct analog_types analog_types[] = { | ||
705 | { "none", 0x00000000 }, | ||
706 | { "auto", 0x000000ff }, | ||
707 | { "2btn", 0x0000003f }, | ||
708 | { "y-joy", 0x0cc00033 }, | ||
709 | { "y-pad", 0x8cc80033 }, | ||
710 | { "fcs", 0x000008f7 }, | ||
711 | { "chf", 0x000002ff }, | ||
712 | { "fullchf", 0x000007ff }, | ||
713 | { "gamepad", 0x000830f3 }, | ||
714 | { "gamepad8", 0x0008f0f3 }, | ||
715 | { NULL, 0 } | ||
716 | }; | ||
717 | |||
718 | static void analog_parse_options(void) | ||
719 | { | ||
720 | int i, j; | ||
721 | char *end; | ||
722 | |||
723 | for (i = 0; i < js_nargs; i++) { | ||
724 | |||
725 | for (j = 0; analog_types[j].name; j++) | ||
726 | if (!strcmp(analog_types[j].name, js[i])) { | ||
727 | analog_options[i] = analog_types[j].value; | ||
728 | break; | ||
729 | } | ||
730 | if (analog_types[j].name) continue; | ||
731 | |||
732 | analog_options[i] = simple_strtoul(js[i], &end, 0); | ||
733 | if (end != js[i]) continue; | ||
734 | |||
735 | analog_options[i] = 0xff; | ||
736 | if (!strlen(js[i])) continue; | ||
737 | |||
738 | printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]); | ||
739 | } | ||
740 | |||
741 | for (; i < ANALOG_PORTS; i++) | ||
742 | analog_options[i] = 0xff; | ||
743 | } | ||
744 | |||
745 | /* | ||
746 | * The gameport device structure. | ||
747 | */ | ||
748 | |||
749 | static struct gameport_driver analog_drv = { | ||
750 | .driver = { | ||
751 | .name = "analog", | ||
752 | }, | ||
753 | .description = DRIVER_DESC, | ||
754 | .connect = analog_connect, | ||
755 | .disconnect = analog_disconnect, | ||
756 | }; | ||
757 | |||
758 | static int __init analog_init(void) | ||
759 | { | ||
760 | analog_parse_options(); | ||
761 | gameport_register_driver(&analog_drv); | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | static void __exit analog_exit(void) | ||
767 | { | ||
768 | gameport_unregister_driver(&analog_drv); | ||
769 | } | ||
770 | |||
771 | module_init(analog_init); | ||
772 | module_exit(analog_exit); | ||
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c new file mode 100644 index 000000000000..a6002205328f --- /dev/null +++ b/drivers/input/joystick/cobra.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * $Id: cobra.c,v 1.19 2002/01/22 20:26:52 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Creative Labs Blaster GamePad Cobra 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/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/gameport.h> | ||
36 | #include <linux/input.h> | ||
37 | |||
38 | #define DRIVER_DESC "Creative Labs Blaster GamePad Cobra driver" | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | #define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ | ||
45 | #define COBRA_LENGTH 36 | ||
46 | |||
47 | static char* cobra_name = "Creative Labs Blaster GamePad Cobra"; | ||
48 | |||
49 | static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 }; | ||
50 | |||
51 | struct cobra { | ||
52 | struct gameport *gameport; | ||
53 | struct input_dev dev[2]; | ||
54 | int reads; | ||
55 | int bads; | ||
56 | unsigned char exists; | ||
57 | char phys[2][32]; | ||
58 | }; | ||
59 | |||
60 | static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data) | ||
61 | { | ||
62 | unsigned long flags; | ||
63 | unsigned char u, v, w; | ||
64 | __u64 buf[2]; | ||
65 | int r[2], t[2]; | ||
66 | int i, j, ret; | ||
67 | |||
68 | int strobe = gameport_time(gameport, COBRA_MAX_STROBE); | ||
69 | |||
70 | for (i = 0; i < 2; i++) { | ||
71 | r[i] = buf[i] = 0; | ||
72 | t[i] = COBRA_MAX_STROBE; | ||
73 | } | ||
74 | |||
75 | local_irq_save(flags); | ||
76 | |||
77 | u = gameport_read(gameport); | ||
78 | |||
79 | do { | ||
80 | t[0]--; t[1]--; | ||
81 | v = gameport_read(gameport); | ||
82 | for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2) | ||
83 | if (w & 0x30) { | ||
84 | if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) { | ||
85 | buf[i] |= (__u64)((w >> 5) & 1) << r[i]++; | ||
86 | t[i] = strobe; | ||
87 | u = v; | ||
88 | } else t[i] = 0; | ||
89 | } | ||
90 | } while (t[0] > 0 || t[1] > 0); | ||
91 | |||
92 | local_irq_restore(flags); | ||
93 | |||
94 | ret = 0; | ||
95 | |||
96 | for (i = 0; i < 2; i++) { | ||
97 | |||
98 | if (r[i] != COBRA_LENGTH) continue; | ||
99 | |||
100 | for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++) | ||
101 | buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1)); | ||
102 | |||
103 | if (j < COBRA_LENGTH) ret |= (1 << i); | ||
104 | |||
105 | data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0) | ||
106 | | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000) | ||
107 | | ((buf[i] >> 11) & 0x1f00000); | ||
108 | |||
109 | } | ||
110 | |||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | static void cobra_poll(struct gameport *gameport) | ||
115 | { | ||
116 | struct cobra *cobra = gameport_get_drvdata(gameport); | ||
117 | struct input_dev *dev; | ||
118 | unsigned int data[2]; | ||
119 | int i, j, r; | ||
120 | |||
121 | cobra->reads++; | ||
122 | |||
123 | if ((r = cobra_read_packet(gameport, data)) != cobra->exists) { | ||
124 | cobra->bads++; | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | for (i = 0; i < 2; i++) | ||
129 | if (cobra->exists & r & (1 << i)) { | ||
130 | |||
131 | dev = cobra->dev + i; | ||
132 | |||
133 | input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1)); | ||
134 | input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); | ||
135 | |||
136 | for (j = 0; cobra_btn[j]; j++) | ||
137 | input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j)); | ||
138 | |||
139 | input_sync(dev); | ||
140 | |||
141 | } | ||
142 | } | ||
143 | |||
144 | static int cobra_open(struct input_dev *dev) | ||
145 | { | ||
146 | struct cobra *cobra = dev->private; | ||
147 | |||
148 | gameport_start_polling(cobra->gameport); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static void cobra_close(struct input_dev *dev) | ||
153 | { | ||
154 | struct cobra *cobra = dev->private; | ||
155 | |||
156 | gameport_stop_polling(cobra->gameport); | ||
157 | } | ||
158 | |||
159 | static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
160 | { | ||
161 | struct cobra *cobra; | ||
162 | unsigned int data[2]; | ||
163 | int i, j; | ||
164 | int err; | ||
165 | |||
166 | if (!(cobra = kcalloc(1, sizeof(struct cobra), GFP_KERNEL))) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | cobra->gameport = gameport; | ||
170 | |||
171 | gameport_set_drvdata(gameport, cobra); | ||
172 | |||
173 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
174 | if (err) | ||
175 | goto fail1; | ||
176 | |||
177 | cobra->exists = cobra_read_packet(gameport, data); | ||
178 | |||
179 | for (i = 0; i < 2; i++) | ||
180 | if ((cobra->exists >> i) & data[i] & 1) { | ||
181 | printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d" | ||
182 | " Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7); | ||
183 | cobra->exists &= ~(1 << i); | ||
184 | } | ||
185 | |||
186 | if (!cobra->exists) { | ||
187 | err = -ENODEV; | ||
188 | goto fail2; | ||
189 | } | ||
190 | |||
191 | gameport_set_poll_handler(gameport, cobra_poll); | ||
192 | gameport_set_poll_interval(gameport, 20); | ||
193 | |||
194 | for (i = 0; i < 2; i++) | ||
195 | if ((cobra->exists >> i) & 1) { | ||
196 | |||
197 | sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i); | ||
198 | |||
199 | cobra->dev[i].private = cobra; | ||
200 | cobra->dev[i].open = cobra_open; | ||
201 | cobra->dev[i].close = cobra_close; | ||
202 | |||
203 | cobra->dev[i].name = cobra_name; | ||
204 | cobra->dev[i].phys = cobra->phys[i]; | ||
205 | cobra->dev[i].id.bustype = BUS_GAMEPORT; | ||
206 | cobra->dev[i].id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; | ||
207 | cobra->dev[i].id.product = 0x0008; | ||
208 | cobra->dev[i].id.version = 0x0100; | ||
209 | |||
210 | cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
211 | |||
212 | input_set_abs_params(&cobra->dev[i], ABS_X, -1, 1, 0, 0); | ||
213 | input_set_abs_params(&cobra->dev[i], ABS_Y, -1, 1, 0, 0); | ||
214 | |||
215 | for (j = 0; cobra_btn[j]; j++) | ||
216 | set_bit(cobra_btn[j], cobra->dev[i].keybit); | ||
217 | |||
218 | input_register_device(&cobra->dev[i]); | ||
219 | printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys); | ||
220 | } | ||
221 | |||
222 | return 0; | ||
223 | |||
224 | fail2: gameport_close(gameport); | ||
225 | fail1: gameport_set_drvdata(gameport, NULL); | ||
226 | kfree(cobra); | ||
227 | return err; | ||
228 | } | ||
229 | |||
230 | static void cobra_disconnect(struct gameport *gameport) | ||
231 | { | ||
232 | struct cobra *cobra = gameport_get_drvdata(gameport); | ||
233 | int i; | ||
234 | |||
235 | for (i = 0; i < 2; i++) | ||
236 | if ((cobra->exists >> i) & 1) | ||
237 | input_unregister_device(cobra->dev + i); | ||
238 | gameport_close(gameport); | ||
239 | gameport_set_drvdata(gameport, NULL); | ||
240 | kfree(cobra); | ||
241 | } | ||
242 | |||
243 | static struct gameport_driver cobra_drv = { | ||
244 | .driver = { | ||
245 | .name = "cobra", | ||
246 | }, | ||
247 | .description = DRIVER_DESC, | ||
248 | .connect = cobra_connect, | ||
249 | .disconnect = cobra_disconnect, | ||
250 | }; | ||
251 | |||
252 | static int __init cobra_init(void) | ||
253 | { | ||
254 | gameport_register_driver(&cobra_drv); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static void __exit cobra_exit(void) | ||
259 | { | ||
260 | gameport_unregister_driver(&cobra_drv); | ||
261 | } | ||
262 | |||
263 | module_init(cobra_init); | ||
264 | module_exit(cobra_exit); | ||
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c new file mode 100644 index 000000000000..cfdd3acf06a1 --- /dev/null +++ b/drivers/input/joystick/db9.c | |||
@@ -0,0 +1,647 @@ | |||
1 | /* | ||
2 | * $Id: db9.c,v 1.13 2002/04/07 20:13:37 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Andree Borrmann Mats Sjövall | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/moduleparam.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/parport.h> | ||
40 | #include <linux/input.h> | ||
41 | |||
42 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
43 | MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | static int db9[] __initdata = { -1, 0 }; | ||
47 | static int db9_nargs __initdata = 0; | ||
48 | module_param_array_named(dev, db9, int, &db9_nargs, 0); | ||
49 | MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)"); | ||
50 | |||
51 | static int db9_2[] __initdata = { -1, 0 }; | ||
52 | static int db9_nargs_2 __initdata = 0; | ||
53 | module_param_array_named(dev2, db9_2, int, &db9_nargs_2, 0); | ||
54 | MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)"); | ||
55 | |||
56 | static int db9_3[] __initdata = { -1, 0 }; | ||
57 | static int db9_nargs_3 __initdata = 0; | ||
58 | module_param_array_named(dev3, db9_3, int, &db9_nargs_3, 0); | ||
59 | MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)"); | ||
60 | |||
61 | __obsolete_setup("db9="); | ||
62 | __obsolete_setup("db9_2="); | ||
63 | __obsolete_setup("db9_3="); | ||
64 | |||
65 | #define DB9_MULTI_STICK 0x01 | ||
66 | #define DB9_MULTI2_STICK 0x02 | ||
67 | #define DB9_GENESIS_PAD 0x03 | ||
68 | #define DB9_GENESIS5_PAD 0x05 | ||
69 | #define DB9_GENESIS6_PAD 0x06 | ||
70 | #define DB9_SATURN_PAD 0x07 | ||
71 | #define DB9_MULTI_0802 0x08 | ||
72 | #define DB9_MULTI_0802_2 0x09 | ||
73 | #define DB9_CD32_PAD 0x0A | ||
74 | #define DB9_SATURN_DPP 0x0B | ||
75 | #define DB9_SATURN_DPP_2 0x0C | ||
76 | #define DB9_MAX_PAD 0x0D | ||
77 | |||
78 | #define DB9_UP 0x01 | ||
79 | #define DB9_DOWN 0x02 | ||
80 | #define DB9_LEFT 0x04 | ||
81 | #define DB9_RIGHT 0x08 | ||
82 | #define DB9_FIRE1 0x10 | ||
83 | #define DB9_FIRE2 0x20 | ||
84 | #define DB9_FIRE3 0x40 | ||
85 | #define DB9_FIRE4 0x80 | ||
86 | |||
87 | #define DB9_NORMAL 0x0a | ||
88 | #define DB9_NOSELECT 0x08 | ||
89 | |||
90 | #define DB9_MAX_DEVICES 2 | ||
91 | |||
92 | #define DB9_GENESIS6_DELAY 14 | ||
93 | #define DB9_REFRESH_TIME HZ/100 | ||
94 | |||
95 | struct db9 { | ||
96 | struct input_dev dev[DB9_MAX_DEVICES]; | ||
97 | struct timer_list timer; | ||
98 | struct pardevice *pd; | ||
99 | int mode; | ||
100 | int used; | ||
101 | char phys[2][32]; | ||
102 | }; | ||
103 | |||
104 | static struct db9 *db9_base[3]; | ||
105 | |||
106 | static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB }; | ||
107 | static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE }; | ||
108 | static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; | ||
109 | |||
110 | static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 9, 1, 1, 7, 9, 9 }; | ||
111 | static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, | ||
112 | db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn, | ||
113 | db9_cd32_btn, db9_cd32_btn }; | ||
114 | static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", | ||
115 | NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", | ||
116 | "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad", "Saturn dpp", "Saturn dpp dual" }; | ||
117 | |||
118 | static const int db9_max_pads[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 6, 1, 2, 1, 6, 12 }; | ||
119 | static const int db9_num_axis[DB9_MAX_PAD] = { 0, 2, 2, 2, 0, 2, 2, 7, 2, 2, 2 ,7, 7 }; | ||
120 | static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; | ||
121 | static const int db9_bidirectional[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 }; | ||
122 | static const int db9_reverse[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 }; | ||
123 | |||
124 | /* | ||
125 | * Saturn controllers | ||
126 | */ | ||
127 | #define DB9_SATURN_DELAY 300 | ||
128 | static const int db9_saturn_byte[] = { 1, 1, 1, 2, 2, 2, 2, 2, 1 }; | ||
129 | static const unsigned char db9_saturn_mask[] = { 0x04, 0x01, 0x02, 0x40, 0x20, 0x10, 0x08, 0x80, 0x08 }; | ||
130 | |||
131 | /* | ||
132 | * db9_saturn_write_sub() writes 2 bit data. | ||
133 | */ | ||
134 | static void db9_saturn_write_sub(struct parport *port, int type, unsigned char data, int powered, int pwr_sub) | ||
135 | { | ||
136 | unsigned char c; | ||
137 | |||
138 | switch (type) { | ||
139 | case 1: /* DPP1 */ | ||
140 | c = 0x80 | 0x30 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | data; | ||
141 | parport_write_data(port, c); | ||
142 | break; | ||
143 | case 2: /* DPP2 */ | ||
144 | c = 0x40 | data << 4 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | 0x03; | ||
145 | parport_write_data(port, c); | ||
146 | break; | ||
147 | case 0: /* DB9 */ | ||
148 | c = ((((data & 2) ? 2 : 0) | ((data & 1) ? 4 : 0)) ^ 0x02) | !powered; | ||
149 | parport_write_control(port, c); | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * gc_saturn_read_sub() reads 4 bit data. | ||
156 | */ | ||
157 | static unsigned char db9_saturn_read_sub(struct parport *port, int type) | ||
158 | { | ||
159 | unsigned char data; | ||
160 | |||
161 | if (type) { | ||
162 | /* DPP */ | ||
163 | data = parport_read_status(port) ^ 0x80; | ||
164 | return (data & 0x80 ? 1 : 0) | (data & 0x40 ? 2 : 0) | ||
165 | | (data & 0x20 ? 4 : 0) | (data & 0x10 ? 8 : 0); | ||
166 | } else { | ||
167 | /* DB9 */ | ||
168 | data = parport_read_data(port) & 0x0f; | ||
169 | return (data & 0x8 ? 1 : 0) | (data & 0x4 ? 2 : 0) | ||
170 | | (data & 0x2 ? 4 : 0) | (data & 0x1 ? 8 : 0); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * db9_saturn_read_analog() sends clock and reads 8 bit data. | ||
176 | */ | ||
177 | static unsigned char db9_saturn_read_analog(struct parport *port, int type, int powered) | ||
178 | { | ||
179 | unsigned char data; | ||
180 | |||
181 | db9_saturn_write_sub(port, type, 0, powered, 0); | ||
182 | udelay(DB9_SATURN_DELAY); | ||
183 | data = db9_saturn_read_sub(port, type) << 4; | ||
184 | db9_saturn_write_sub(port, type, 2, powered, 0); | ||
185 | udelay(DB9_SATURN_DELAY); | ||
186 | data |= db9_saturn_read_sub(port, type); | ||
187 | return data; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * db9_saturn_read_packet() reads whole saturn packet at connector | ||
192 | * and returns device identifier code. | ||
193 | */ | ||
194 | static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered) | ||
195 | { | ||
196 | int i, j; | ||
197 | unsigned char tmp; | ||
198 | |||
199 | db9_saturn_write_sub(port, type, 3, powered, 0); | ||
200 | data[0] = db9_saturn_read_sub(port, type); | ||
201 | switch (data[0] & 0x0f) { | ||
202 | case 0xf: | ||
203 | /* 1111 no pad */ | ||
204 | return data[0] = 0xff; | ||
205 | case 0x4: case 0x4 | 0x8: | ||
206 | /* ?100 : digital controller */ | ||
207 | db9_saturn_write_sub(port, type, 0, powered, 1); | ||
208 | data[2] = db9_saturn_read_sub(port, type) << 4; | ||
209 | db9_saturn_write_sub(port, type, 2, powered, 1); | ||
210 | data[1] = db9_saturn_read_sub(port, type) << 4; | ||
211 | db9_saturn_write_sub(port, type, 1, powered, 1); | ||
212 | data[1] |= db9_saturn_read_sub(port, type); | ||
213 | db9_saturn_write_sub(port, type, 3, powered, 1); | ||
214 | /* data[2] |= db9_saturn_read_sub(port, type); */ | ||
215 | data[2] |= data[0]; | ||
216 | return data[0] = 0x02; | ||
217 | case 0x1: | ||
218 | /* 0001 : analog controller or multitap */ | ||
219 | db9_saturn_write_sub(port, type, 2, powered, 0); | ||
220 | udelay(DB9_SATURN_DELAY); | ||
221 | data[0] = db9_saturn_read_analog(port, type, powered); | ||
222 | if (data[0] != 0x41) { | ||
223 | /* read analog controller */ | ||
224 | for (i = 0; i < (data[0] & 0x0f); i++) | ||
225 | data[i + 1] = db9_saturn_read_analog(port, type, powered); | ||
226 | db9_saturn_write_sub(port, type, 3, powered, 0); | ||
227 | return data[0]; | ||
228 | } else { | ||
229 | /* read multitap */ | ||
230 | if (db9_saturn_read_analog(port, type, powered) != 0x60) | ||
231 | return data[0] = 0xff; | ||
232 | for (i = 0; i < 60; i += 10) { | ||
233 | data[i] = db9_saturn_read_analog(port, type, powered); | ||
234 | if (data[i] != 0xff) | ||
235 | /* read each pad */ | ||
236 | for (j = 0; j < (data[i] & 0x0f); j++) | ||
237 | data[i + j + 1] = db9_saturn_read_analog(port, type, powered); | ||
238 | } | ||
239 | db9_saturn_write_sub(port, type, 3, powered, 0); | ||
240 | return 0x41; | ||
241 | } | ||
242 | case 0x0: | ||
243 | /* 0000 : mouse */ | ||
244 | db9_saturn_write_sub(port, type, 2, powered, 0); | ||
245 | udelay(DB9_SATURN_DELAY); | ||
246 | tmp = db9_saturn_read_analog(port, type, powered); | ||
247 | if (tmp == 0xff) { | ||
248 | for (i = 0; i < 3; i++) | ||
249 | data[i + 1] = db9_saturn_read_analog(port, type, powered); | ||
250 | db9_saturn_write_sub(port, type, 3, powered, 0); | ||
251 | return data[0] = 0xe3; | ||
252 | } | ||
253 | default: | ||
254 | return data[0]; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * db9_saturn_report() analyzes packet and reports. | ||
260 | */ | ||
261 | static int db9_saturn_report(unsigned char id, unsigned char data[60], struct input_dev *dev, int n, int max_pads) | ||
262 | { | ||
263 | int tmp, i, j; | ||
264 | |||
265 | tmp = (id == 0x41) ? 60 : 10; | ||
266 | for (j = 0; (j < tmp) && (n < max_pads); j += 10, n++) { | ||
267 | switch (data[j]) { | ||
268 | case 0x16: /* multi controller (analog 4 axis) */ | ||
269 | input_report_abs(dev + n, db9_abs[5], data[j + 6]); | ||
270 | case 0x15: /* mission stick (analog 3 axis) */ | ||
271 | input_report_abs(dev + n, db9_abs[3], data[j + 4]); | ||
272 | input_report_abs(dev + n, db9_abs[4], data[j + 5]); | ||
273 | case 0x13: /* racing controller (analog 1 axis) */ | ||
274 | input_report_abs(dev + n, db9_abs[2], data[j + 3]); | ||
275 | case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */ | ||
276 | case 0x02: /* digital pad (digital 2 axis + buttons) */ | ||
277 | input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64)); | ||
278 | input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16)); | ||
279 | for (i = 0; i < 9; i++) | ||
280 | input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]); | ||
281 | break; | ||
282 | case 0x19: /* mission stick x2 (analog 6 axis + buttons) */ | ||
283 | input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64)); | ||
284 | input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16)); | ||
285 | for (i = 0; i < 9; i++) | ||
286 | input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]); | ||
287 | input_report_abs(dev + n, db9_abs[2], data[j + 3]); | ||
288 | input_report_abs(dev + n, db9_abs[3], data[j + 4]); | ||
289 | input_report_abs(dev + n, db9_abs[4], data[j + 5]); | ||
290 | /* | ||
291 | input_report_abs(dev + n, db9_abs[8], (data[j + 6] & 128 ? 0 : 1) - (data[j + 6] & 64 ? 0 : 1)); | ||
292 | input_report_abs(dev + n, db9_abs[9], (data[j + 6] & 32 ? 0 : 1) - (data[j + 6] & 16 ? 0 : 1)); | ||
293 | */ | ||
294 | input_report_abs(dev + n, db9_abs[6], data[j + 7]); | ||
295 | input_report_abs(dev + n, db9_abs[7], data[j + 8]); | ||
296 | input_report_abs(dev + n, db9_abs[5], data[j + 9]); | ||
297 | break; | ||
298 | case 0xd3: /* sankyo ff (analog 1 axis + stop btn) */ | ||
299 | input_report_key(dev + n, BTN_A, data[j + 3] & 0x80); | ||
300 | input_report_abs(dev + n, db9_abs[2], data[j + 3] & 0x7f); | ||
301 | break; | ||
302 | case 0xe3: /* shuttle mouse (analog 2 axis + buttons. signed value) */ | ||
303 | input_report_key(dev + n, BTN_START, data[j + 1] & 0x08); | ||
304 | input_report_key(dev + n, BTN_A, data[j + 1] & 0x04); | ||
305 | input_report_key(dev + n, BTN_C, data[j + 1] & 0x02); | ||
306 | input_report_key(dev + n, BTN_B, data[j + 1] & 0x01); | ||
307 | input_report_abs(dev + n, db9_abs[2], data[j + 2] ^ 0x80); | ||
308 | input_report_abs(dev + n, db9_abs[3], (0xff-(data[j + 3] ^ 0x80))+1); /* */ | ||
309 | break; | ||
310 | case 0xff: | ||
311 | default: /* no pad */ | ||
312 | input_report_abs(dev + n, db9_abs[0], 0); | ||
313 | input_report_abs(dev + n, db9_abs[1], 0); | ||
314 | for (i = 0; i < 9; i++) | ||
315 | input_report_key(dev + n, db9_cd32_btn[i], 0); | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | return n; | ||
320 | } | ||
321 | |||
322 | static int db9_saturn(int mode, struct parport *port, struct input_dev *dev) | ||
323 | { | ||
324 | unsigned char id, data[60]; | ||
325 | int type, n, max_pads; | ||
326 | int tmp, i; | ||
327 | |||
328 | switch (mode) { | ||
329 | case DB9_SATURN_PAD: | ||
330 | type = 0; | ||
331 | n = 1; | ||
332 | break; | ||
333 | case DB9_SATURN_DPP: | ||
334 | type = 1; | ||
335 | n = 1; | ||
336 | break; | ||
337 | case DB9_SATURN_DPP_2: | ||
338 | type = 1; | ||
339 | n = 2; | ||
340 | break; | ||
341 | default: | ||
342 | return -1; | ||
343 | } | ||
344 | max_pads = min(db9_max_pads[mode], DB9_MAX_DEVICES); | ||
345 | for (tmp = 0, i = 0; i < n; i++) { | ||
346 | id = db9_saturn_read_packet(port, data, type + i, 1); | ||
347 | tmp = db9_saturn_report(id, data, dev, tmp, max_pads); | ||
348 | } | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void db9_timer(unsigned long private) | ||
353 | { | ||
354 | struct db9 *db9 = (void *) private; | ||
355 | struct parport *port = db9->pd->port; | ||
356 | struct input_dev *dev = db9->dev; | ||
357 | int data, i; | ||
358 | |||
359 | switch(db9->mode) { | ||
360 | case DB9_MULTI_0802_2: | ||
361 | |||
362 | data = parport_read_data(port) >> 3; | ||
363 | |||
364 | input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
365 | input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
366 | input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1); | ||
367 | |||
368 | case DB9_MULTI_0802: | ||
369 | |||
370 | data = parport_read_status(port) >> 3; | ||
371 | |||
372 | input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
373 | input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
374 | input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1); | ||
375 | break; | ||
376 | |||
377 | case DB9_MULTI_STICK: | ||
378 | |||
379 | data = parport_read_data(port); | ||
380 | |||
381 | input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
382 | input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
383 | input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1); | ||
384 | break; | ||
385 | |||
386 | case DB9_MULTI2_STICK: | ||
387 | |||
388 | data = parport_read_data(port); | ||
389 | |||
390 | input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
391 | input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
392 | input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1); | ||
393 | input_report_key(dev, BTN_THUMB, ~data & DB9_FIRE2); | ||
394 | break; | ||
395 | |||
396 | case DB9_GENESIS_PAD: | ||
397 | |||
398 | parport_write_control(port, DB9_NOSELECT); | ||
399 | data = parport_read_data(port); | ||
400 | |||
401 | input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
402 | input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
403 | input_report_key(dev, BTN_B, ~data & DB9_FIRE1); | ||
404 | input_report_key(dev, BTN_C, ~data & DB9_FIRE2); | ||
405 | |||
406 | parport_write_control(port, DB9_NORMAL); | ||
407 | data=parport_read_data(port); | ||
408 | |||
409 | input_report_key(dev, BTN_A, ~data & DB9_FIRE1); | ||
410 | input_report_key(dev, BTN_START, ~data & DB9_FIRE2); | ||
411 | break; | ||
412 | |||
413 | case DB9_GENESIS5_PAD: | ||
414 | |||
415 | parport_write_control(port, DB9_NOSELECT); | ||
416 | data=parport_read_data(port); | ||
417 | |||
418 | input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
419 | input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
420 | input_report_key(dev, BTN_B, ~data & DB9_FIRE1); | ||
421 | input_report_key(dev, BTN_C, ~data & DB9_FIRE2); | ||
422 | |||
423 | parport_write_control(port, DB9_NORMAL); | ||
424 | data=parport_read_data(port); | ||
425 | |||
426 | input_report_key(dev, BTN_A, ~data & DB9_FIRE1); | ||
427 | input_report_key(dev, BTN_X, ~data & DB9_FIRE2); | ||
428 | input_report_key(dev, BTN_Y, ~data & DB9_LEFT); | ||
429 | input_report_key(dev, BTN_START, ~data & DB9_RIGHT); | ||
430 | break; | ||
431 | |||
432 | case DB9_GENESIS6_PAD: | ||
433 | |||
434 | parport_write_control(port, DB9_NOSELECT); /* 1 */ | ||
435 | udelay(DB9_GENESIS6_DELAY); | ||
436 | data=parport_read_data(port); | ||
437 | |||
438 | input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
439 | input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
440 | input_report_key(dev, BTN_B, ~data & DB9_FIRE1); | ||
441 | input_report_key(dev, BTN_C, ~data & DB9_FIRE2); | ||
442 | |||
443 | parport_write_control(port, DB9_NORMAL); | ||
444 | udelay(DB9_GENESIS6_DELAY); | ||
445 | data=parport_read_data(port); | ||
446 | |||
447 | input_report_key(dev, BTN_A, ~data & DB9_FIRE1); | ||
448 | input_report_key(dev, BTN_START, ~data & DB9_FIRE2); | ||
449 | |||
450 | parport_write_control(port, DB9_NOSELECT); /* 2 */ | ||
451 | udelay(DB9_GENESIS6_DELAY); | ||
452 | parport_write_control(port, DB9_NORMAL); | ||
453 | udelay(DB9_GENESIS6_DELAY); | ||
454 | parport_write_control(port, DB9_NOSELECT); /* 3 */ | ||
455 | udelay(DB9_GENESIS6_DELAY); | ||
456 | data=parport_read_data(port); | ||
457 | |||
458 | input_report_key(dev, BTN_X, ~data & DB9_LEFT); | ||
459 | input_report_key(dev, BTN_Y, ~data & DB9_DOWN); | ||
460 | input_report_key(dev, BTN_Z, ~data & DB9_UP); | ||
461 | input_report_key(dev, BTN_MODE, ~data & DB9_RIGHT); | ||
462 | |||
463 | parport_write_control(port, DB9_NORMAL); | ||
464 | udelay(DB9_GENESIS6_DELAY); | ||
465 | parport_write_control(port, DB9_NOSELECT); /* 4 */ | ||
466 | udelay(DB9_GENESIS6_DELAY); | ||
467 | parport_write_control(port, DB9_NORMAL); | ||
468 | break; | ||
469 | |||
470 | case DB9_SATURN_PAD: | ||
471 | case DB9_SATURN_DPP: | ||
472 | case DB9_SATURN_DPP_2: | ||
473 | |||
474 | db9_saturn(db9->mode, port, dev); | ||
475 | break; | ||
476 | |||
477 | case DB9_CD32_PAD: | ||
478 | |||
479 | data=parport_read_data(port); | ||
480 | |||
481 | input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); | ||
482 | input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); | ||
483 | |||
484 | parport_write_control(port, 0x0a); | ||
485 | |||
486 | for (i = 0; i < 7; i++) { | ||
487 | data = parport_read_data(port); | ||
488 | parport_write_control(port, 0x02); | ||
489 | parport_write_control(port, 0x0a); | ||
490 | input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2); | ||
491 | } | ||
492 | |||
493 | parport_write_control(port, 0x00); | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | input_sync(dev); | ||
498 | |||
499 | mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); | ||
500 | } | ||
501 | |||
502 | static int db9_open(struct input_dev *dev) | ||
503 | { | ||
504 | struct db9 *db9 = dev->private; | ||
505 | struct parport *port = db9->pd->port; | ||
506 | |||
507 | if (!db9->used++) { | ||
508 | parport_claim(db9->pd); | ||
509 | parport_write_data(port, 0xff); | ||
510 | if (db9_reverse[db9->mode]) { | ||
511 | parport_data_reverse(port); | ||
512 | parport_write_control(port, DB9_NORMAL); | ||
513 | } | ||
514 | mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); | ||
515 | } | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static void db9_close(struct input_dev *dev) | ||
521 | { | ||
522 | struct db9 *db9 = dev->private; | ||
523 | struct parport *port = db9->pd->port; | ||
524 | |||
525 | if (!--db9->used) { | ||
526 | del_timer(&db9->timer); | ||
527 | parport_write_control(port, 0x00); | ||
528 | parport_data_forward(port); | ||
529 | parport_release(db9->pd); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | static struct db9 __init *db9_probe(int *config, int nargs) | ||
534 | { | ||
535 | struct db9 *db9; | ||
536 | struct parport *pp; | ||
537 | int i, j; | ||
538 | |||
539 | if (config[0] < 0) | ||
540 | return NULL; | ||
541 | |||
542 | if (nargs < 2) { | ||
543 | printk(KERN_ERR "db9.c: Device type must be specified.\n"); | ||
544 | return NULL; | ||
545 | } | ||
546 | |||
547 | if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) { | ||
548 | printk(KERN_ERR "db9.c: bad config\n"); | ||
549 | return NULL; | ||
550 | } | ||
551 | |||
552 | pp = parport_find_number(config[0]); | ||
553 | if (!pp) { | ||
554 | printk(KERN_ERR "db9.c: no such parport\n"); | ||
555 | return NULL; | ||
556 | } | ||
557 | |||
558 | if (db9_bidirectional[config[1]]) { | ||
559 | if (!(pp->modes & PARPORT_MODE_TRISTATE)) { | ||
560 | printk(KERN_ERR "db9.c: specified parport is not bidirectional\n"); | ||
561 | parport_put_port(pp); | ||
562 | return NULL; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) { | ||
567 | parport_put_port(pp); | ||
568 | return NULL; | ||
569 | } | ||
570 | memset(db9, 0, sizeof(struct db9)); | ||
571 | |||
572 | db9->mode = config[1]; | ||
573 | init_timer(&db9->timer); | ||
574 | db9->timer.data = (long) db9; | ||
575 | db9->timer.function = db9_timer; | ||
576 | |||
577 | db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); | ||
578 | parport_put_port(pp); | ||
579 | |||
580 | if (!db9->pd) { | ||
581 | printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n"); | ||
582 | kfree(db9); | ||
583 | return NULL; | ||
584 | } | ||
585 | |||
586 | for (i = 0; i < (min(db9_max_pads[db9->mode], DB9_MAX_DEVICES)); i++) { | ||
587 | |||
588 | sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i); | ||
589 | |||
590 | db9->dev[i].private = db9; | ||
591 | db9->dev[i].open = db9_open; | ||
592 | db9->dev[i].close = db9_close; | ||
593 | |||
594 | db9->dev[i].name = db9_name[db9->mode]; | ||
595 | db9->dev[i].phys = db9->phys[i]; | ||
596 | db9->dev[i].id.bustype = BUS_PARPORT; | ||
597 | db9->dev[i].id.vendor = 0x0002; | ||
598 | db9->dev[i].id.product = config[1]; | ||
599 | db9->dev[i].id.version = 0x0100; | ||
600 | |||
601 | db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
602 | for (j = 0; j < db9_buttons[db9->mode]; j++) | ||
603 | set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); | ||
604 | for (j = 0; j < db9_num_axis[db9->mode]; j++) { | ||
605 | set_bit(db9_abs[j], db9->dev[i].absbit); | ||
606 | if (j < 2) { | ||
607 | db9->dev[i].absmin[db9_abs[j]] = -1; | ||
608 | db9->dev[i].absmax[db9_abs[j]] = 1; | ||
609 | } else { | ||
610 | db9->dev[i].absmin[db9_abs[j]] = 1; | ||
611 | db9->dev[i].absmax[db9_abs[j]] = 255; | ||
612 | db9->dev[i].absflat[db9_abs[j]] = 0; | ||
613 | } | ||
614 | } | ||
615 | input_register_device(db9->dev + i); | ||
616 | printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name); | ||
617 | } | ||
618 | |||
619 | return db9; | ||
620 | } | ||
621 | |||
622 | static int __init db9_init(void) | ||
623 | { | ||
624 | db9_base[0] = db9_probe(db9, db9_nargs); | ||
625 | db9_base[1] = db9_probe(db9_2, db9_nargs_2); | ||
626 | db9_base[2] = db9_probe(db9_3, db9_nargs_3); | ||
627 | |||
628 | if (db9_base[0] || db9_base[1] || db9_base[2]) | ||
629 | return 0; | ||
630 | |||
631 | return -ENODEV; | ||
632 | } | ||
633 | |||
634 | static void __exit db9_exit(void) | ||
635 | { | ||
636 | int i, j; | ||
637 | |||
638 | for (i = 0; i < 3; i++) | ||
639 | if (db9_base[i]) { | ||
640 | for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++) | ||
641 | input_unregister_device(db9_base[i]->dev + j); | ||
642 | parport_unregister_device(db9_base[i]->pd); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | module_init(db9_init); | ||
647 | module_exit(db9_exit); | ||
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c new file mode 100644 index 000000000000..8732f52bdd08 --- /dev/null +++ b/drivers/input/joystick/gamecon.c | |||
@@ -0,0 +1,697 @@ | |||
1 | /* | ||
2 | * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz> | ||
5 | * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org> | ||
6 | * | ||
7 | * Based on the work of: | ||
8 | * Andree Borrmann John Dahlstrom | ||
9 | * David Kuder Nathan Hand | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * Should you need to contact me, the author, you can do so either by | ||
28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
30 | */ | ||
31 | |||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/parport.h> | ||
38 | #include <linux/input.h> | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; | ||
45 | static int gc_nargs __initdata = 0; | ||
46 | module_param_array_named(map, gc, int, &gc_nargs, 0); | ||
47 | MODULE_PARM_DESC(map, "Describers first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)"); | ||
48 | |||
49 | static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; | ||
50 | static int gc_nargs_2 __initdata = 0; | ||
51 | module_param_array_named(map2, gc_2, int, &gc_nargs_2, 0); | ||
52 | MODULE_PARM_DESC(map2, "Describers second set of devices"); | ||
53 | |||
54 | static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; | ||
55 | static int gc_nargs_3 __initdata = 0; | ||
56 | module_param_array_named(map3, gc_3, int, &gc_nargs_3, 0); | ||
57 | MODULE_PARM_DESC(map3, "Describers third set of devices"); | ||
58 | |||
59 | __obsolete_setup("gc="); | ||
60 | __obsolete_setup("gc_2="); | ||
61 | __obsolete_setup("gc_3="); | ||
62 | |||
63 | /* see also gs_psx_delay parameter in PSX support section */ | ||
64 | |||
65 | #define GC_SNES 1 | ||
66 | #define GC_NES 2 | ||
67 | #define GC_NES4 3 | ||
68 | #define GC_MULTI 4 | ||
69 | #define GC_MULTI2 5 | ||
70 | #define GC_N64 6 | ||
71 | #define GC_PSX 7 | ||
72 | #define GC_DDR 8 | ||
73 | |||
74 | #define GC_MAX 8 | ||
75 | |||
76 | #define GC_REFRESH_TIME HZ/100 | ||
77 | |||
78 | struct gc { | ||
79 | struct pardevice *pd; | ||
80 | struct input_dev dev[5]; | ||
81 | struct timer_list timer; | ||
82 | unsigned char pads[GC_MAX + 1]; | ||
83 | int used; | ||
84 | char phys[5][32]; | ||
85 | }; | ||
86 | |||
87 | static struct gc *gc_base[3]; | ||
88 | |||
89 | static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; | ||
90 | |||
91 | static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", | ||
92 | "Multisystem 2-button joystick", "N64 controller", "PSX controller", | ||
93 | "PSX DDR controller" }; | ||
94 | /* | ||
95 | * N64 support. | ||
96 | */ | ||
97 | |||
98 | static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 }; | ||
99 | static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START }; | ||
100 | |||
101 | #define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */ | ||
102 | #define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */ | ||
103 | #define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */ | ||
104 | #define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */ | ||
105 | #define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */ | ||
106 | /* GC_N64_DWS > 24 is known to fail */ | ||
107 | #define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */ | ||
108 | #define GC_N64_POWER_R 0xfd /* power during read */ | ||
109 | #define GC_N64_OUT 0x1d /* output bits to the 4 pads */ | ||
110 | /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */ | ||
111 | /* in GC_N64_OUT is pulled low on the output port (by any routine) for more */ | ||
112 | /* than 123 us */ | ||
113 | #define GC_N64_CLOCK 0x02 /* clock bits for read */ | ||
114 | |||
115 | /* | ||
116 | * gc_n64_read_packet() reads an N64 packet. | ||
117 | * Each pad uses one bit per byte. So all pads connected to this port are read in parallel. | ||
118 | */ | ||
119 | |||
120 | static void gc_n64_read_packet(struct gc *gc, unsigned char *data) | ||
121 | { | ||
122 | int i; | ||
123 | unsigned long flags; | ||
124 | |||
125 | /* | ||
126 | * Request the pad to transmit data | ||
127 | */ | ||
128 | |||
129 | local_irq_save(flags); | ||
130 | for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) { | ||
131 | parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0)); | ||
132 | udelay(GC_N64_DWS); | ||
133 | } | ||
134 | local_irq_restore(flags); | ||
135 | |||
136 | /* | ||
137 | * Wait for the pad response to be loaded into the 33-bit register of the adapter | ||
138 | */ | ||
139 | |||
140 | udelay(GC_N64_DELAY); | ||
141 | |||
142 | /* | ||
143 | * Grab data (ignoring the last bit, which is a stop bit) | ||
144 | */ | ||
145 | |||
146 | for (i = 0; i < GC_N64_LENGTH; i++) { | ||
147 | parport_write_data(gc->pd->port, GC_N64_POWER_R); | ||
148 | data[i] = parport_read_status(gc->pd->port); | ||
149 | parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * We must wait 200 ms here for the controller to reinitialize before the next read request. | ||
154 | * No worries as long as gc_read is polled less frequently than this. | ||
155 | */ | ||
156 | |||
157 | } | ||
158 | |||
159 | /* | ||
160 | * NES/SNES support. | ||
161 | */ | ||
162 | |||
163 | #define GC_NES_DELAY 6 /* Delay between bits - 6us */ | ||
164 | #define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */ | ||
165 | #define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */ | ||
166 | |||
167 | #define GC_NES_POWER 0xfc | ||
168 | #define GC_NES_CLOCK 0x01 | ||
169 | #define GC_NES_LATCH 0x02 | ||
170 | |||
171 | static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 }; | ||
172 | static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 }; | ||
173 | static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR }; | ||
174 | |||
175 | /* | ||
176 | * gc_nes_read_packet() reads a NES/SNES packet. | ||
177 | * Each pad uses one bit per byte. So all pads connected to | ||
178 | * this port are read in parallel. | ||
179 | */ | ||
180 | |||
181 | static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH); | ||
186 | udelay(GC_NES_DELAY * 2); | ||
187 | parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK); | ||
188 | |||
189 | for (i = 0; i < length; i++) { | ||
190 | udelay(GC_NES_DELAY); | ||
191 | parport_write_data(gc->pd->port, GC_NES_POWER); | ||
192 | data[i] = parport_read_status(gc->pd->port) ^ 0x7f; | ||
193 | udelay(GC_NES_DELAY); | ||
194 | parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Multisystem joystick support | ||
200 | */ | ||
201 | |||
202 | #define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */ | ||
203 | #define GC_MULTI2_LENGTH 6 /* One more bit for one more button */ | ||
204 | |||
205 | /* | ||
206 | * gc_multi_read_packet() reads a Multisystem joystick packet. | ||
207 | */ | ||
208 | |||
209 | static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) | ||
210 | { | ||
211 | int i; | ||
212 | |||
213 | for (i = 0; i < length; i++) { | ||
214 | parport_write_data(gc->pd->port, ~(1 << i)); | ||
215 | data[i] = parport_read_status(gc->pd->port) ^ 0x7f; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * PSX support | ||
221 | * | ||
222 | * See documentation at: | ||
223 | * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt | ||
224 | * http://www.gamesx.com/controldata/psxcont/psxcont.htm | ||
225 | * ftp://milano.usal.es/pablo/ | ||
226 | * | ||
227 | */ | ||
228 | |||
229 | #define GC_PSX_DELAY 25 /* 25 usec */ | ||
230 | #define GC_PSX_LENGTH 8 /* talk to the controller in bits */ | ||
231 | #define GC_PSX_BYTES 6 /* the maximum number of bytes to read off the controller */ | ||
232 | |||
233 | #define GC_PSX_MOUSE 1 /* Mouse */ | ||
234 | #define GC_PSX_NEGCON 2 /* NegCon */ | ||
235 | #define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */ | ||
236 | #define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */ | ||
237 | #define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ | ||
238 | |||
239 | #define GC_PSX_CLOCK 0x04 /* Pin 4 */ | ||
240 | #define GC_PSX_COMMAND 0x01 /* Pin 2 */ | ||
241 | #define GC_PSX_POWER 0xf8 /* Pins 5-9 */ | ||
242 | #define GC_PSX_SELECT 0x02 /* Pin 3 */ | ||
243 | |||
244 | #define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */ | ||
245 | #define GC_PSX_LEN(x) (((x) & 0xf) << 1) /* Low nibble is length in bytes/2 */ | ||
246 | |||
247 | static int gc_psx_delay = GC_PSX_DELAY; | ||
248 | module_param_named(psx_delay, gc_psx_delay, uint, 0); | ||
249 | MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)"); | ||
250 | |||
251 | __obsolete_setup("gc_psx_delay="); | ||
252 | |||
253 | static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; | ||
254 | static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, | ||
255 | BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; | ||
256 | static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 }; | ||
257 | |||
258 | /* | ||
259 | * gc_psx_command() writes 8bit command and reads 8bit data from | ||
260 | * the psx pad. | ||
261 | */ | ||
262 | |||
263 | static void gc_psx_command(struct gc *gc, int b, unsigned char data[5]) | ||
264 | { | ||
265 | int i, j, cmd, read; | ||
266 | for (i = 0; i < 5; i++) | ||
267 | data[i] = 0; | ||
268 | |||
269 | for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) { | ||
270 | cmd = (b & 1) ? GC_PSX_COMMAND : 0; | ||
271 | parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); | ||
272 | udelay(gc_psx_delay); | ||
273 | read = parport_read_status(gc->pd->port) ^ 0x80; | ||
274 | for (j = 0; j < 5; j++) | ||
275 | data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0; | ||
276 | parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); | ||
277 | udelay(gc_psx_delay); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * gc_psx_read_packet() reads a whole psx packet and returns | ||
283 | * device identifier code. | ||
284 | */ | ||
285 | |||
286 | static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_BYTES], unsigned char id[5]) | ||
287 | { | ||
288 | int i, j, max_len = 0; | ||
289 | unsigned long flags; | ||
290 | unsigned char data2[5]; | ||
291 | |||
292 | parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ | ||
293 | udelay(gc_psx_delay); | ||
294 | parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ | ||
295 | udelay(gc_psx_delay); | ||
296 | |||
297 | local_irq_save(flags); | ||
298 | |||
299 | gc_psx_command(gc, 0x01, data2); /* Access pad */ | ||
300 | gc_psx_command(gc, 0x42, id); /* Get device ids */ | ||
301 | gc_psx_command(gc, 0, data2); /* Dump status */ | ||
302 | |||
303 | for (i =0; i < 5; i++) /* Find the longest pad */ | ||
304 | if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) | ||
305 | && (GC_PSX_LEN(id[i]) > max_len) | ||
306 | && (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES)) | ||
307 | max_len = GC_PSX_LEN(id[i]); | ||
308 | |||
309 | for (i = 0; i < max_len; i++) { /* Read in all the data */ | ||
310 | gc_psx_command(gc, 0, data2); | ||
311 | for (j = 0; j < 5; j++) | ||
312 | data[j][i] = data2[j]; | ||
313 | } | ||
314 | |||
315 | local_irq_restore(flags); | ||
316 | |||
317 | parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); | ||
318 | |||
319 | for(i = 0; i < 5; i++) /* Set id's to the real value */ | ||
320 | id[i] = GC_PSX_ID(id[i]); | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * gc_timer() reads and analyzes console pads data. | ||
325 | */ | ||
326 | |||
327 | #define GC_MAX_LENGTH GC_N64_LENGTH | ||
328 | |||
329 | static void gc_timer(unsigned long private) | ||
330 | { | ||
331 | struct gc *gc = (void *) private; | ||
332 | struct input_dev *dev = gc->dev; | ||
333 | unsigned char data[GC_MAX_LENGTH]; | ||
334 | unsigned char data_psx[5][GC_PSX_BYTES]; | ||
335 | int i, j, s; | ||
336 | |||
337 | /* | ||
338 | * N64 pads - must be read first, any read confuses them for 200 us | ||
339 | */ | ||
340 | |||
341 | if (gc->pads[GC_N64]) { | ||
342 | |||
343 | gc_n64_read_packet(gc, data); | ||
344 | |||
345 | for (i = 0; i < 5; i++) { | ||
346 | |||
347 | s = gc_status_bit[i]; | ||
348 | |||
349 | if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) { | ||
350 | |||
351 | signed char axes[2]; | ||
352 | axes[0] = axes[1] = 0; | ||
353 | |||
354 | for (j = 0; j < 8; j++) { | ||
355 | if (data[23 - j] & s) axes[0] |= 1 << j; | ||
356 | if (data[31 - j] & s) axes[1] |= 1 << j; | ||
357 | } | ||
358 | |||
359 | input_report_abs(dev + i, ABS_X, axes[0]); | ||
360 | input_report_abs(dev + i, ABS_Y, -axes[1]); | ||
361 | |||
362 | input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7])); | ||
363 | input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5])); | ||
364 | |||
365 | for (j = 0; j < 10; j++) | ||
366 | input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]); | ||
367 | |||
368 | input_sync(dev + i); | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * NES and SNES pads | ||
375 | */ | ||
376 | |||
377 | if (gc->pads[GC_NES] || gc->pads[GC_SNES]) { | ||
378 | |||
379 | gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data); | ||
380 | |||
381 | for (i = 0; i < 5; i++) { | ||
382 | |||
383 | s = gc_status_bit[i]; | ||
384 | |||
385 | if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { | ||
386 | input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7])); | ||
387 | input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5])); | ||
388 | } | ||
389 | |||
390 | if (s & gc->pads[GC_NES]) | ||
391 | for (j = 0; j < 4; j++) | ||
392 | input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]); | ||
393 | |||
394 | if (s & gc->pads[GC_SNES]) | ||
395 | for (j = 0; j < 8; j++) | ||
396 | input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]); | ||
397 | |||
398 | input_sync(dev + i); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Multi and Multi2 joysticks | ||
404 | */ | ||
405 | |||
406 | if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) { | ||
407 | |||
408 | gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data); | ||
409 | |||
410 | for (i = 0; i < 5; i++) { | ||
411 | |||
412 | s = gc_status_bit[i]; | ||
413 | |||
414 | if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { | ||
415 | input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3])); | ||
416 | input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1])); | ||
417 | input_report_key(dev + i, BTN_TRIGGER, s & data[4]); | ||
418 | } | ||
419 | |||
420 | if (s & gc->pads[GC_MULTI2]) | ||
421 | input_report_key(dev + i, BTN_THUMB, s & data[5]); | ||
422 | |||
423 | input_sync(dev + i); | ||
424 | } | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * PSX controllers | ||
429 | */ | ||
430 | |||
431 | if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) { | ||
432 | |||
433 | gc_psx_read_packet(gc, data_psx, data); | ||
434 | |||
435 | for (i = 0; i < 5; i++) { | ||
436 | switch (data[i]) { | ||
437 | |||
438 | case GC_PSX_RUMBLE: | ||
439 | |||
440 | input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04); | ||
441 | input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02); | ||
442 | |||
443 | case GC_PSX_NEGCON: | ||
444 | case GC_PSX_ANALOG: | ||
445 | |||
446 | if(gc->pads[GC_DDR] & gc_status_bit[i]) { | ||
447 | for(j = 0; j < 4; j++) | ||
448 | input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); | ||
449 | } else { | ||
450 | for (j = 0; j < 4; j++) | ||
451 | input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]); | ||
452 | |||
453 | input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); | ||
454 | input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); | ||
455 | } | ||
456 | |||
457 | for (j = 0; j < 8; j++) | ||
458 | input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); | ||
459 | |||
460 | input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); | ||
461 | input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); | ||
462 | |||
463 | input_sync(dev + i); | ||
464 | |||
465 | break; | ||
466 | |||
467 | case GC_PSX_NORMAL: | ||
468 | if(gc->pads[GC_DDR] & gc_status_bit[i]) { | ||
469 | for(j = 0; j < 4; j++) | ||
470 | input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); | ||
471 | } else { | ||
472 | input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); | ||
473 | input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); | ||
474 | |||
475 | /* for some reason if the extra axes are left unset they drift */ | ||
476 | /* for (j = 0; j < 4; j++) | ||
477 | input_report_abs(dev + i, gc_psx_abs[j+2], 128); | ||
478 | * This needs to be debugged properly, | ||
479 | * maybe fuzz processing needs to be done in input_sync() | ||
480 | * --vojtech | ||
481 | */ | ||
482 | } | ||
483 | |||
484 | for (j = 0; j < 8; j++) | ||
485 | input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); | ||
486 | |||
487 | input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); | ||
488 | input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); | ||
489 | |||
490 | input_sync(dev + i); | ||
491 | |||
492 | break; | ||
493 | |||
494 | case 0: /* not a pad, ignore */ | ||
495 | break; | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); | ||
501 | } | ||
502 | |||
503 | static int gc_open(struct input_dev *dev) | ||
504 | { | ||
505 | struct gc *gc = dev->private; | ||
506 | if (!gc->used++) { | ||
507 | parport_claim(gc->pd); | ||
508 | parport_write_control(gc->pd->port, 0x04); | ||
509 | mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); | ||
510 | } | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static void gc_close(struct input_dev *dev) | ||
515 | { | ||
516 | struct gc *gc = dev->private; | ||
517 | if (!--gc->used) { | ||
518 | del_timer(&gc->timer); | ||
519 | parport_write_control(gc->pd->port, 0x00); | ||
520 | parport_release(gc->pd); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | static struct gc __init *gc_probe(int *config, int nargs) | ||
525 | { | ||
526 | struct gc *gc; | ||
527 | struct parport *pp; | ||
528 | int i, j; | ||
529 | |||
530 | if (config[0] < 0) | ||
531 | return NULL; | ||
532 | |||
533 | if (nargs < 2) { | ||
534 | printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); | ||
535 | return NULL; | ||
536 | } | ||
537 | |||
538 | pp = parport_find_number(config[0]); | ||
539 | |||
540 | if (!pp) { | ||
541 | printk(KERN_ERR "gamecon.c: no such parport\n"); | ||
542 | return NULL; | ||
543 | } | ||
544 | |||
545 | if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) { | ||
546 | parport_put_port(pp); | ||
547 | return NULL; | ||
548 | } | ||
549 | memset(gc, 0, sizeof(struct gc)); | ||
550 | |||
551 | gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); | ||
552 | |||
553 | parport_put_port(pp); | ||
554 | |||
555 | if (!gc->pd) { | ||
556 | printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n"); | ||
557 | kfree(gc); | ||
558 | return NULL; | ||
559 | } | ||
560 | |||
561 | parport_claim(gc->pd); | ||
562 | |||
563 | init_timer(&gc->timer); | ||
564 | gc->timer.data = (long) gc; | ||
565 | gc->timer.function = gc_timer; | ||
566 | |||
567 | for (i = 0; i < nargs - 1; i++) { | ||
568 | |||
569 | if (!config[i + 1]) | ||
570 | continue; | ||
571 | |||
572 | if (config[i + 1] < 1 || config[i + 1] > GC_MAX) { | ||
573 | printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]); | ||
574 | continue; | ||
575 | } | ||
576 | |||
577 | gc->dev[i].private = gc; | ||
578 | gc->dev[i].open = gc_open; | ||
579 | gc->dev[i].close = gc_close; | ||
580 | |||
581 | gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
582 | |||
583 | for (j = 0; j < 2; j++) { | ||
584 | set_bit(ABS_X + j, gc->dev[i].absbit); | ||
585 | gc->dev[i].absmin[ABS_X + j] = -1; | ||
586 | gc->dev[i].absmax[ABS_X + j] = 1; | ||
587 | } | ||
588 | |||
589 | gc->pads[0] |= gc_status_bit[i]; | ||
590 | gc->pads[config[i + 1]] |= gc_status_bit[i]; | ||
591 | |||
592 | switch(config[i + 1]) { | ||
593 | |||
594 | case GC_N64: | ||
595 | for (j = 0; j < 10; j++) | ||
596 | set_bit(gc_n64_btn[j], gc->dev[i].keybit); | ||
597 | |||
598 | for (j = 0; j < 2; j++) { | ||
599 | set_bit(ABS_X + j, gc->dev[i].absbit); | ||
600 | gc->dev[i].absmin[ABS_X + j] = -127; | ||
601 | gc->dev[i].absmax[ABS_X + j] = 126; | ||
602 | gc->dev[i].absflat[ABS_X + j] = 2; | ||
603 | set_bit(ABS_HAT0X + j, gc->dev[i].absbit); | ||
604 | gc->dev[i].absmin[ABS_HAT0X + j] = -1; | ||
605 | gc->dev[i].absmax[ABS_HAT0X + j] = 1; | ||
606 | } | ||
607 | |||
608 | break; | ||
609 | |||
610 | case GC_SNES: | ||
611 | for (j = 4; j < 8; j++) | ||
612 | set_bit(gc_snes_btn[j], gc->dev[i].keybit); | ||
613 | case GC_NES: | ||
614 | for (j = 0; j < 4; j++) | ||
615 | set_bit(gc_snes_btn[j], gc->dev[i].keybit); | ||
616 | break; | ||
617 | |||
618 | case GC_MULTI2: | ||
619 | set_bit(BTN_THUMB, gc->dev[i].keybit); | ||
620 | case GC_MULTI: | ||
621 | set_bit(BTN_TRIGGER, gc->dev[i].keybit); | ||
622 | break; | ||
623 | |||
624 | case GC_PSX: | ||
625 | case GC_DDR: | ||
626 | if(config[i + 1] == GC_DDR) { | ||
627 | for (j = 0; j < 4; j++) | ||
628 | set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit); | ||
629 | } else { | ||
630 | for (j = 0; j < 6; j++) { | ||
631 | set_bit(gc_psx_abs[j], gc->dev[i].absbit); | ||
632 | gc->dev[i].absmin[gc_psx_abs[j]] = 4; | ||
633 | gc->dev[i].absmax[gc_psx_abs[j]] = 252; | ||
634 | gc->dev[i].absflat[gc_psx_abs[j]] = 2; | ||
635 | } | ||
636 | } | ||
637 | |||
638 | for (j = 0; j < 12; j++) | ||
639 | set_bit(gc_psx_btn[j], gc->dev[i].keybit); | ||
640 | |||
641 | break; | ||
642 | } | ||
643 | |||
644 | sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); | ||
645 | |||
646 | gc->dev[i].name = gc_names[config[i + 1]]; | ||
647 | gc->dev[i].phys = gc->phys[i]; | ||
648 | gc->dev[i].id.bustype = BUS_PARPORT; | ||
649 | gc->dev[i].id.vendor = 0x0001; | ||
650 | gc->dev[i].id.product = config[i + 1]; | ||
651 | gc->dev[i].id.version = 0x0100; | ||
652 | } | ||
653 | |||
654 | parport_release(gc->pd); | ||
655 | |||
656 | if (!gc->pads[0]) { | ||
657 | parport_unregister_device(gc->pd); | ||
658 | kfree(gc); | ||
659 | return NULL; | ||
660 | } | ||
661 | |||
662 | for (i = 0; i < 5; i++) | ||
663 | if (gc->pads[0] & gc_status_bit[i]) { | ||
664 | input_register_device(gc->dev + i); | ||
665 | printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name); | ||
666 | } | ||
667 | |||
668 | return gc; | ||
669 | } | ||
670 | |||
671 | static int __init gc_init(void) | ||
672 | { | ||
673 | gc_base[0] = gc_probe(gc, gc_nargs); | ||
674 | gc_base[1] = gc_probe(gc_2, gc_nargs_2); | ||
675 | gc_base[2] = gc_probe(gc_3, gc_nargs_3); | ||
676 | |||
677 | if (gc_base[0] || gc_base[1] || gc_base[2]) | ||
678 | return 0; | ||
679 | |||
680 | return -ENODEV; | ||
681 | } | ||
682 | |||
683 | static void __exit gc_exit(void) | ||
684 | { | ||
685 | int i, j; | ||
686 | |||
687 | for (i = 0; i < 3; i++) | ||
688 | if (gc_base[i]) { | ||
689 | for (j = 0; j < 5; j++) | ||
690 | if (gc_base[i]->pads[0] & gc_status_bit[j]) | ||
691 | input_unregister_device(gc_base[i]->dev + j); | ||
692 | parport_unregister_device(gc_base[i]->pd); | ||
693 | } | ||
694 | } | ||
695 | |||
696 | module_init(gc_init); | ||
697 | module_exit(gc_exit); | ||
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c new file mode 100644 index 000000000000..ad13f09a4e71 --- /dev/null +++ b/drivers/input/joystick/gf2k.c | |||
@@ -0,0 +1,380 @@ | |||
1 | /* | ||
2 | * $Id: gf2k.c,v 1.19 2002/01/22 20:27:43 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1998-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Genius Flight 2000 joystick 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/delay.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/input.h> | ||
37 | #include <linux/gameport.h> | ||
38 | |||
39 | #define DRIVER_DESC "Genius Flight 2000 joystick driver" | ||
40 | |||
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
42 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | #define GF2K_START 400 /* The time we wait for the first bit [400 us] */ | ||
46 | #define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */ | ||
47 | #define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */ | ||
48 | #define GF2K_LENGTH 80 /* Max number of triplets in a packet */ | ||
49 | |||
50 | /* | ||
51 | * Genius joystick ids ... | ||
52 | */ | ||
53 | |||
54 | #define GF2K_ID_G09 1 | ||
55 | #define GF2K_ID_F30D 2 | ||
56 | #define GF2K_ID_F30 3 | ||
57 | #define GF2K_ID_F31D 4 | ||
58 | #define GF2K_ID_F305 5 | ||
59 | #define GF2K_ID_F23P 6 | ||
60 | #define GF2K_ID_F31 7 | ||
61 | #define GF2K_ID_MAX 7 | ||
62 | |||
63 | static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 }; | ||
64 | static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | ||
65 | |||
66 | static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D", | ||
67 | "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"}; | ||
68 | static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 }; | ||
69 | static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 }; | ||
70 | static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 }; | ||
71 | static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 }; | ||
72 | static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 }; | ||
73 | |||
74 | static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE }; | ||
75 | static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }; | ||
76 | static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT }; | ||
77 | |||
78 | |||
79 | static short gf2k_seq_reset[] = { 240, 340, 0 }; | ||
80 | static short gf2k_seq_digital[] = { 590, 320, 860, 0 }; | ||
81 | |||
82 | struct gf2k { | ||
83 | struct gameport *gameport; | ||
84 | struct input_dev dev; | ||
85 | int reads; | ||
86 | int bads; | ||
87 | unsigned char id; | ||
88 | unsigned char length; | ||
89 | char phys[32]; | ||
90 | }; | ||
91 | |||
92 | /* | ||
93 | * gf2k_read_packet() reads a Genius Flight2000 packet. | ||
94 | */ | ||
95 | |||
96 | static int gf2k_read_packet(struct gameport *gameport, int length, char *data) | ||
97 | { | ||
98 | unsigned char u, v; | ||
99 | int i; | ||
100 | unsigned int t, p; | ||
101 | unsigned long flags; | ||
102 | |||
103 | t = gameport_time(gameport, GF2K_START); | ||
104 | p = gameport_time(gameport, GF2K_STROBE); | ||
105 | |||
106 | i = 0; | ||
107 | |||
108 | local_irq_save(flags); | ||
109 | |||
110 | gameport_trigger(gameport); | ||
111 | v = gameport_read(gameport); | ||
112 | |||
113 | while (t > 0 && i < length) { | ||
114 | t--; u = v; | ||
115 | v = gameport_read(gameport); | ||
116 | if (v & ~u & 0x10) { | ||
117 | data[i++] = v >> 5; | ||
118 | t = p; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | local_irq_restore(flags); | ||
123 | |||
124 | return i; | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * gf2k_trigger_seq() initializes a Genius Flight2000 joystick | ||
129 | * into digital mode. | ||
130 | */ | ||
131 | |||
132 | static void gf2k_trigger_seq(struct gameport *gameport, short *seq) | ||
133 | { | ||
134 | |||
135 | unsigned long flags; | ||
136 | int i, t; | ||
137 | |||
138 | local_irq_save(flags); | ||
139 | |||
140 | i = 0; | ||
141 | do { | ||
142 | gameport_trigger(gameport); | ||
143 | t = gameport_time(gameport, GF2K_TIMEOUT * 1000); | ||
144 | while ((gameport_read(gameport) & 1) && t) t--; | ||
145 | udelay(seq[i]); | ||
146 | } while (seq[++i]); | ||
147 | |||
148 | gameport_trigger(gameport); | ||
149 | |||
150 | local_irq_restore(flags); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * js_sw_get_bits() composes bits from the triplet buffer into a __u64. | ||
155 | * Parameter 'pos' is bit number inside packet where to start at, 'num' is number | ||
156 | * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits | ||
157 | * is number of bits per triplet. | ||
158 | */ | ||
159 | |||
160 | #define GB(p,n,s) gf2k_get_bits(data, p, n, s) | ||
161 | |||
162 | static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift) | ||
163 | { | ||
164 | __u64 data = 0; | ||
165 | int i; | ||
166 | |||
167 | for (i = 0; i < num / 3 + 2; i++) | ||
168 | data |= buf[pos / 3 + i] << (i * 3); | ||
169 | data >>= pos % 3; | ||
170 | data &= (1 << num) - 1; | ||
171 | data <<= shift; | ||
172 | |||
173 | return data; | ||
174 | } | ||
175 | |||
176 | static void gf2k_read(struct gf2k *gf2k, unsigned char *data) | ||
177 | { | ||
178 | struct input_dev *dev = &gf2k->dev; | ||
179 | int i, t; | ||
180 | |||
181 | for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++) | ||
182 | input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9)); | ||
183 | |||
184 | for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++) | ||
185 | input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9)); | ||
186 | |||
187 | t = GB(40,4,0); | ||
188 | |||
189 | for (i = 0; i < gf2k_hats[gf2k->id]; i++) | ||
190 | input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]); | ||
191 | |||
192 | t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10); | ||
193 | |||
194 | for (i = 0; i < gf2k_joys[gf2k->id]; i++) | ||
195 | input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1); | ||
196 | |||
197 | for (i = 0; i < gf2k_pads[gf2k->id]; i++) | ||
198 | input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1); | ||
199 | |||
200 | input_sync(dev); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * gf2k_poll() reads and analyzes Genius joystick data. | ||
205 | */ | ||
206 | |||
207 | static void gf2k_poll(struct gameport *gameport) | ||
208 | { | ||
209 | struct gf2k *gf2k = gameport_get_drvdata(gameport); | ||
210 | unsigned char data[GF2K_LENGTH]; | ||
211 | |||
212 | gf2k->reads++; | ||
213 | |||
214 | if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) | ||
215 | gf2k->bads++; | ||
216 | else | ||
217 | gf2k_read(gf2k, data); | ||
218 | } | ||
219 | |||
220 | static int gf2k_open(struct input_dev *dev) | ||
221 | { | ||
222 | struct gf2k *gf2k = dev->private; | ||
223 | |||
224 | gameport_start_polling(gf2k->gameport); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static void gf2k_close(struct input_dev *dev) | ||
229 | { | ||
230 | struct gf2k *gf2k = dev->private; | ||
231 | |||
232 | gameport_stop_polling(gf2k->gameport); | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * gf2k_connect() probes for Genius id joysticks. | ||
237 | */ | ||
238 | |||
239 | static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
240 | { | ||
241 | struct gf2k *gf2k; | ||
242 | unsigned char data[GF2K_LENGTH]; | ||
243 | int i, err; | ||
244 | |||
245 | if (!(gf2k = kcalloc(1, sizeof(struct gf2k), GFP_KERNEL))) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | gf2k->gameport = gameport; | ||
249 | |||
250 | gameport_set_drvdata(gameport, gf2k); | ||
251 | |||
252 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
253 | if (err) | ||
254 | goto fail1; | ||
255 | |||
256 | gf2k_trigger_seq(gameport, gf2k_seq_reset); | ||
257 | |||
258 | msleep(GF2K_TIMEOUT); | ||
259 | |||
260 | gf2k_trigger_seq(gameport, gf2k_seq_digital); | ||
261 | |||
262 | msleep(GF2K_TIMEOUT); | ||
263 | |||
264 | if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12) { | ||
265 | err = -ENODEV; | ||
266 | goto fail2; | ||
267 | } | ||
268 | |||
269 | if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5))) { | ||
270 | err = -ENODEV; | ||
271 | goto fail2; | ||
272 | } | ||
273 | |||
274 | #ifdef RESET_WORKS | ||
275 | if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) || | ||
276 | (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) { | ||
277 | err = -ENODEV; | ||
278 | goto fail2; | ||
279 | } | ||
280 | #else | ||
281 | gf2k->id = 6; | ||
282 | #endif | ||
283 | |||
284 | if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) { | ||
285 | printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n", | ||
286 | gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]); | ||
287 | err = -ENODEV; | ||
288 | goto fail2; | ||
289 | } | ||
290 | |||
291 | gameport_set_poll_handler(gameport, gf2k_poll); | ||
292 | gameport_set_poll_interval(gameport, 20); | ||
293 | |||
294 | sprintf(gf2k->phys, "%s/input0", gameport->phys); | ||
295 | |||
296 | gf2k->length = gf2k_lens[gf2k->id]; | ||
297 | |||
298 | init_input_dev(&gf2k->dev); | ||
299 | |||
300 | gf2k->dev.private = gf2k; | ||
301 | gf2k->dev.open = gf2k_open; | ||
302 | gf2k->dev.close = gf2k_close; | ||
303 | gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
304 | |||
305 | gf2k->dev.name = gf2k_names[gf2k->id]; | ||
306 | gf2k->dev.phys = gf2k->phys; | ||
307 | gf2k->dev.id.bustype = BUS_GAMEPORT; | ||
308 | gf2k->dev.id.vendor = GAMEPORT_ID_VENDOR_GENIUS; | ||
309 | gf2k->dev.id.product = gf2k->id; | ||
310 | gf2k->dev.id.version = 0x0100; | ||
311 | |||
312 | for (i = 0; i < gf2k_axes[gf2k->id]; i++) | ||
313 | set_bit(gf2k_abs[i], gf2k->dev.absbit); | ||
314 | |||
315 | for (i = 0; i < gf2k_hats[gf2k->id]; i++) { | ||
316 | set_bit(ABS_HAT0X + i, gf2k->dev.absbit); | ||
317 | gf2k->dev.absmin[ABS_HAT0X + i] = -1; | ||
318 | gf2k->dev.absmax[ABS_HAT0X + i] = 1; | ||
319 | } | ||
320 | |||
321 | for (i = 0; i < gf2k_joys[gf2k->id]; i++) | ||
322 | set_bit(gf2k_btn_joy[i], gf2k->dev.keybit); | ||
323 | |||
324 | for (i = 0; i < gf2k_pads[gf2k->id]; i++) | ||
325 | set_bit(gf2k_btn_pad[i], gf2k->dev.keybit); | ||
326 | |||
327 | gf2k_read_packet(gameport, gf2k->length, data); | ||
328 | gf2k_read(gf2k, data); | ||
329 | |||
330 | for (i = 0; i < gf2k_axes[gf2k->id]; i++) { | ||
331 | gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 : | ||
332 | gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; | ||
333 | gf2k->dev.absmin[gf2k_abs[i]] = 32; | ||
334 | gf2k->dev.absfuzz[gf2k_abs[i]] = 8; | ||
335 | gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; | ||
336 | } | ||
337 | |||
338 | input_register_device(&gf2k->dev); | ||
339 | printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys); | ||
340 | |||
341 | return 0; | ||
342 | |||
343 | fail2: gameport_close(gameport); | ||
344 | fail1: gameport_set_drvdata(gameport, NULL); | ||
345 | kfree(gf2k); | ||
346 | return err; | ||
347 | } | ||
348 | |||
349 | static void gf2k_disconnect(struct gameport *gameport) | ||
350 | { | ||
351 | struct gf2k *gf2k = gameport_get_drvdata(gameport); | ||
352 | |||
353 | input_unregister_device(&gf2k->dev); | ||
354 | gameport_close(gameport); | ||
355 | gameport_set_drvdata(gameport, NULL); | ||
356 | kfree(gf2k); | ||
357 | } | ||
358 | |||
359 | static struct gameport_driver gf2k_drv = { | ||
360 | .driver = { | ||
361 | .name = "gf2k", | ||
362 | }, | ||
363 | .description = DRIVER_DESC, | ||
364 | .connect = gf2k_connect, | ||
365 | .disconnect = gf2k_disconnect, | ||
366 | }; | ||
367 | |||
368 | static int __init gf2k_init(void) | ||
369 | { | ||
370 | gameport_register_driver(&gf2k_drv); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static void __exit gf2k_exit(void) | ||
375 | { | ||
376 | gameport_unregister_driver(&gf2k_drv); | ||
377 | } | ||
378 | |||
379 | module_init(gf2k_init); | ||
380 | module_exit(gf2k_exit); | ||
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c new file mode 100644 index 000000000000..d1500d2562d6 --- /dev/null +++ b/drivers/input/joystick/grip.c | |||
@@ -0,0 +1,422 @@ | |||
1 | /* | ||
2 | * $Id: grip.c,v 1.21 2002/01/22 20:27:57 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1998-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Gravis/Kensington GrIP protocol joystick and gamepad 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/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/gameport.h> | ||
36 | #include <linux/input.h> | ||
37 | |||
38 | #define DRIVER_DESC "Gravis GrIP protocol joystick driver" | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | #define GRIP_MODE_GPP 1 | ||
45 | #define GRIP_MODE_BD 2 | ||
46 | #define GRIP_MODE_XT 3 | ||
47 | #define GRIP_MODE_DC 4 | ||
48 | |||
49 | #define GRIP_LENGTH_GPP 24 | ||
50 | #define GRIP_STROBE_GPP 200 /* 200 us */ | ||
51 | #define GRIP_LENGTH_XT 4 | ||
52 | #define GRIP_STROBE_XT 64 /* 64 us */ | ||
53 | #define GRIP_MAX_CHUNKS_XT 10 | ||
54 | #define GRIP_MAX_BITS_XT 30 | ||
55 | |||
56 | struct grip { | ||
57 | struct gameport *gameport; | ||
58 | struct input_dev dev[2]; | ||
59 | unsigned char mode[2]; | ||
60 | int reads; | ||
61 | int bads; | ||
62 | char phys[2][32]; | ||
63 | }; | ||
64 | |||
65 | static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 }; | ||
66 | static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 }; | ||
67 | static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 }; | ||
68 | static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 }; | ||
69 | |||
70 | static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 }; | ||
71 | static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | ||
72 | static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 }; | ||
73 | static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | ||
74 | |||
75 | static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital", | ||
76 | "Gravis Xterminator Digital", "Gravis Xterminator DualControl" }; | ||
77 | static int *grip_abs[] = { NULL, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc }; | ||
78 | static int *grip_btn[] = { NULL, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc }; | ||
79 | static char grip_anx[] = { 0, 0, 3, 5, 5 }; | ||
80 | static char grip_cen[] = { 0, 0, 2, 2, 4 }; | ||
81 | |||
82 | /* | ||
83 | * grip_gpp_read_packet() reads a Gravis GamePad Pro packet. | ||
84 | */ | ||
85 | |||
86 | static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data) | ||
87 | { | ||
88 | unsigned long flags; | ||
89 | unsigned char u, v; | ||
90 | unsigned int t; | ||
91 | int i; | ||
92 | |||
93 | int strobe = gameport_time(gameport, GRIP_STROBE_GPP); | ||
94 | |||
95 | data[0] = 0; | ||
96 | t = strobe; | ||
97 | i = 0; | ||
98 | |||
99 | local_irq_save(flags); | ||
100 | |||
101 | v = gameport_read(gameport) >> shift; | ||
102 | |||
103 | do { | ||
104 | t--; | ||
105 | u = v; v = (gameport_read(gameport) >> shift) & 3; | ||
106 | if (~v & u & 1) { | ||
107 | data[0] |= (v >> 1) << i++; | ||
108 | t = strobe; | ||
109 | } | ||
110 | } while (i < GRIP_LENGTH_GPP && t > 0); | ||
111 | |||
112 | local_irq_restore(flags); | ||
113 | |||
114 | if (i < GRIP_LENGTH_GPP) return -1; | ||
115 | |||
116 | for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++) | ||
117 | data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1); | ||
118 | |||
119 | return -(i == GRIP_LENGTH_GPP); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * grip_xt_read_packet() reads a Gravis Xterminator packet. | ||
124 | */ | ||
125 | |||
126 | static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data) | ||
127 | { | ||
128 | unsigned int i, j, buf, crc; | ||
129 | unsigned char u, v, w; | ||
130 | unsigned long flags; | ||
131 | unsigned int t; | ||
132 | char status; | ||
133 | |||
134 | int strobe = gameport_time(gameport, GRIP_STROBE_XT); | ||
135 | |||
136 | data[0] = data[1] = data[2] = data[3] = 0; | ||
137 | status = buf = i = j = 0; | ||
138 | t = strobe; | ||
139 | |||
140 | local_irq_save(flags); | ||
141 | |||
142 | v = w = (gameport_read(gameport) >> shift) & 3; | ||
143 | |||
144 | do { | ||
145 | t--; | ||
146 | u = (gameport_read(gameport) >> shift) & 3; | ||
147 | |||
148 | if (u ^ v) { | ||
149 | |||
150 | if ((u ^ v) & 1) { | ||
151 | buf = (buf << 1) | (u >> 1); | ||
152 | t = strobe; | ||
153 | i++; | ||
154 | } else | ||
155 | |||
156 | if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) { | ||
157 | if (i == 20) { | ||
158 | crc = buf ^ (buf >> 7) ^ (buf >> 14); | ||
159 | if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) { | ||
160 | data[buf >> 18] = buf >> 4; | ||
161 | status |= 1 << (buf >> 18); | ||
162 | } | ||
163 | j++; | ||
164 | } | ||
165 | t = strobe; | ||
166 | buf = 0; | ||
167 | i = 0; | ||
168 | } | ||
169 | w = v; | ||
170 | v = u; | ||
171 | } | ||
172 | |||
173 | } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0); | ||
174 | |||
175 | local_irq_restore(flags); | ||
176 | |||
177 | return -(status != 0xf); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * grip_timer() repeatedly polls the joysticks and generates events. | ||
182 | */ | ||
183 | |||
184 | static void grip_poll(struct gameport *gameport) | ||
185 | { | ||
186 | struct grip *grip = gameport_get_drvdata(gameport); | ||
187 | unsigned int data[GRIP_LENGTH_XT]; | ||
188 | struct input_dev *dev; | ||
189 | int i, j; | ||
190 | |||
191 | for (i = 0; i < 2; i++) { | ||
192 | |||
193 | dev = grip->dev + i; | ||
194 | grip->reads++; | ||
195 | |||
196 | switch (grip->mode[i]) { | ||
197 | |||
198 | case GRIP_MODE_GPP: | ||
199 | |||
200 | if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) { | ||
201 | grip->bads++; | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1)); | ||
206 | input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1)); | ||
207 | |||
208 | for (j = 0; j < 12; j++) | ||
209 | if (grip_btn_gpp[j]) | ||
210 | input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1); | ||
211 | |||
212 | break; | ||
213 | |||
214 | case GRIP_MODE_BD: | ||
215 | |||
216 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { | ||
217 | grip->bads++; | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); | ||
222 | input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); | ||
223 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); | ||
224 | |||
225 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); | ||
226 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); | ||
227 | |||
228 | for (j = 0; j < 5; j++) | ||
229 | input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1); | ||
230 | |||
231 | break; | ||
232 | |||
233 | case GRIP_MODE_XT: | ||
234 | |||
235 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { | ||
236 | grip->bads++; | ||
237 | break; | ||
238 | } | ||
239 | |||
240 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); | ||
241 | input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); | ||
242 | input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f); | ||
243 | input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f); | ||
244 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); | ||
245 | |||
246 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); | ||
247 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); | ||
248 | input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1)); | ||
249 | input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1)); | ||
250 | |||
251 | for (j = 0; j < 11; j++) | ||
252 | input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1); | ||
253 | break; | ||
254 | |||
255 | case GRIP_MODE_DC: | ||
256 | |||
257 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { | ||
258 | grip->bads++; | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); | ||
263 | input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f); | ||
264 | input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f); | ||
265 | input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f); | ||
266 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); | ||
267 | |||
268 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); | ||
269 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); | ||
270 | |||
271 | for (j = 0; j < 9; j++) | ||
272 | input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1); | ||
273 | break; | ||
274 | |||
275 | |||
276 | } | ||
277 | |||
278 | input_sync(dev); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static int grip_open(struct input_dev *dev) | ||
283 | { | ||
284 | struct grip *grip = dev->private; | ||
285 | |||
286 | gameport_start_polling(grip->gameport); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void grip_close(struct input_dev *dev) | ||
291 | { | ||
292 | struct grip *grip = dev->private; | ||
293 | |||
294 | gameport_stop_polling(grip->gameport); | ||
295 | } | ||
296 | |||
297 | static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
298 | { | ||
299 | struct grip *grip; | ||
300 | unsigned int data[GRIP_LENGTH_XT]; | ||
301 | int i, j, t; | ||
302 | int err; | ||
303 | |||
304 | if (!(grip = kcalloc(1, sizeof(struct grip), GFP_KERNEL))) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | grip->gameport = gameport; | ||
308 | |||
309 | gameport_set_drvdata(gameport, grip); | ||
310 | |||
311 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
312 | if (err) | ||
313 | goto fail1; | ||
314 | |||
315 | for (i = 0; i < 2; i++) { | ||
316 | if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) { | ||
317 | grip->mode[i] = GRIP_MODE_GPP; | ||
318 | continue; | ||
319 | } | ||
320 | if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) { | ||
321 | if (!(data[3] & 7)) { | ||
322 | grip->mode[i] = GRIP_MODE_BD; | ||
323 | continue; | ||
324 | } | ||
325 | if (!(data[2] & 0xf0)) { | ||
326 | grip->mode[i] = GRIP_MODE_XT; | ||
327 | continue; | ||
328 | } | ||
329 | grip->mode[i] = GRIP_MODE_DC; | ||
330 | continue; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | if (!grip->mode[0] && !grip->mode[1]) { | ||
335 | err = -ENODEV; | ||
336 | goto fail2; | ||
337 | } | ||
338 | |||
339 | gameport_set_poll_handler(gameport, grip_poll); | ||
340 | gameport_set_poll_interval(gameport, 20); | ||
341 | |||
342 | for (i = 0; i < 2; i++) | ||
343 | if (grip->mode[i]) { | ||
344 | |||
345 | sprintf(grip->phys[i], "%s/input%d", gameport->phys, i); | ||
346 | |||
347 | grip->dev[i].private = grip; | ||
348 | |||
349 | grip->dev[i].open = grip_open; | ||
350 | grip->dev[i].close = grip_close; | ||
351 | |||
352 | grip->dev[i].name = grip_name[grip->mode[i]]; | ||
353 | grip->dev[i].phys = grip->phys[i]; | ||
354 | grip->dev[i].id.bustype = BUS_GAMEPORT; | ||
355 | grip->dev[i].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; | ||
356 | grip->dev[i].id.product = grip->mode[i]; | ||
357 | grip->dev[i].id.version = 0x0100; | ||
358 | |||
359 | grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
360 | |||
361 | for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { | ||
362 | |||
363 | if (j < grip_cen[grip->mode[i]]) | ||
364 | input_set_abs_params(&grip->dev[i], t, 14, 52, 1, 2); | ||
365 | else if (j < grip_anx[grip->mode[i]]) | ||
366 | input_set_abs_params(&grip->dev[i], t, 3, 57, 1, 0); | ||
367 | else | ||
368 | input_set_abs_params(&grip->dev[i], t, -1, 1, 0, 0); | ||
369 | } | ||
370 | |||
371 | for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) | ||
372 | if (t > 0) | ||
373 | set_bit(t, grip->dev[i].keybit); | ||
374 | |||
375 | printk(KERN_INFO "input: %s on %s\n", | ||
376 | grip_name[grip->mode[i]], gameport->phys); | ||
377 | input_register_device(grip->dev + i); | ||
378 | } | ||
379 | |||
380 | return 0; | ||
381 | |||
382 | fail2: gameport_close(gameport); | ||
383 | fail1: gameport_set_drvdata(gameport, NULL); | ||
384 | kfree(grip); | ||
385 | return err; | ||
386 | } | ||
387 | |||
388 | static void grip_disconnect(struct gameport *gameport) | ||
389 | { | ||
390 | struct grip *grip = gameport_get_drvdata(gameport); | ||
391 | int i; | ||
392 | |||
393 | for (i = 0; i < 2; i++) | ||
394 | if (grip->mode[i]) | ||
395 | input_unregister_device(grip->dev + i); | ||
396 | gameport_close(gameport); | ||
397 | gameport_set_drvdata(gameport, NULL); | ||
398 | kfree(grip); | ||
399 | } | ||
400 | |||
401 | static struct gameport_driver grip_drv = { | ||
402 | .driver = { | ||
403 | .name = "grip", | ||
404 | }, | ||
405 | .description = DRIVER_DESC, | ||
406 | .connect = grip_connect, | ||
407 | .disconnect = grip_disconnect, | ||
408 | }; | ||
409 | |||
410 | static int __init grip_init(void) | ||
411 | { | ||
412 | gameport_register_driver(&grip_drv); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static void __exit grip_exit(void) | ||
417 | { | ||
418 | gameport_unregister_driver(&grip_drv); | ||
419 | } | ||
420 | |||
421 | module_init(grip_init); | ||
422 | module_exit(grip_exit); | ||
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c new file mode 100644 index 000000000000..42e5005d621f --- /dev/null +++ b/drivers/input/joystick/grip_mp.c | |||
@@ -0,0 +1,677 @@ | |||
1 | /* | ||
2 | * $Id: grip_mp.c,v 1.9 2002/07/20 19:28:45 bonnland Exp $ | ||
3 | * | ||
4 | * Driver for the Gravis Grip Multiport, a gamepad "hub" that | ||
5 | * connects up to four 9-pin digital gamepads/joysticks. | ||
6 | * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. | ||
7 | * | ||
8 | * Thanks to Chris Gassib for helpful advice. | ||
9 | * | ||
10 | * Copyright (c) 2002 Brian Bonnlander, Bill Soudan | ||
11 | * Copyright (c) 1998-2000 Vojtech Pavlik | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/gameport.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/proc_fs.h> | ||
22 | |||
23 | #define DRIVER_DESC "Gravis Grip Multiport driver" | ||
24 | |||
25 | MODULE_AUTHOR("Brian Bonnlander"); | ||
26 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
27 | MODULE_LICENSE("GPL"); | ||
28 | |||
29 | #ifdef GRIP_DEBUG | ||
30 | #define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) | ||
31 | #else | ||
32 | #define dbg(format, arg...) do {} while (0) | ||
33 | #endif | ||
34 | |||
35 | /* | ||
36 | * Grip multiport state | ||
37 | */ | ||
38 | |||
39 | struct grip_mp { | ||
40 | struct gameport *gameport; | ||
41 | struct input_dev dev[4]; | ||
42 | int mode[4]; | ||
43 | int registered[4]; | ||
44 | int reads; | ||
45 | int bads; | ||
46 | |||
47 | /* individual gamepad states */ | ||
48 | int buttons[4]; | ||
49 | int xaxes[4]; | ||
50 | int yaxes[4]; | ||
51 | int dirty[4]; /* has the state been updated? */ | ||
52 | }; | ||
53 | |||
54 | /* | ||
55 | * Multiport packet interpretation | ||
56 | */ | ||
57 | |||
58 | #define PACKET_FULL 0x80000000 /* packet is full */ | ||
59 | #define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */ | ||
60 | #define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */ | ||
61 | #define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */ | ||
62 | #define PACKET_MP_DONE 0x02000000 /* multiport done sending */ | ||
63 | |||
64 | /* | ||
65 | * Packet status code interpretation | ||
66 | */ | ||
67 | |||
68 | #define IO_GOT_PACKET 0x0100 /* Got a packet */ | ||
69 | #define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */ | ||
70 | #define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */ | ||
71 | #define IO_DONE 0x1000 /* Multiport is done sending packets */ | ||
72 | #define IO_RETRY 0x4000 /* Try again later to get packet */ | ||
73 | #define IO_RESET 0x8000 /* Force multiport to resend all packets */ | ||
74 | |||
75 | /* | ||
76 | * Gamepad configuration data. Other 9-pin digital joystick devices | ||
77 | * may work with the multiport, so this may not be an exhaustive list! | ||
78 | * Commodore 64 joystick remains untested. | ||
79 | */ | ||
80 | |||
81 | #define GRIP_INIT_DELAY 2000 /* 2 ms */ | ||
82 | |||
83 | #define GRIP_MODE_NONE 0 | ||
84 | #define GRIP_MODE_RESET 1 | ||
85 | #define GRIP_MODE_GP 2 | ||
86 | #define GRIP_MODE_C64 3 | ||
87 | |||
88 | static int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; | ||
89 | static int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; | ||
90 | |||
91 | static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; | ||
92 | static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; | ||
93 | |||
94 | static int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; | ||
95 | static int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; | ||
96 | |||
97 | static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; | ||
98 | |||
99 | static const int init_seq[] = { | ||
100 | 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, | ||
101 | 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, | ||
102 | 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, | ||
103 | 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 }; | ||
104 | |||
105 | /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ | ||
106 | |||
107 | static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; | ||
108 | |||
109 | static void register_slot(int i, struct grip_mp *grip); | ||
110 | |||
111 | /* | ||
112 | * Returns whether an odd or even number of bits are on in pkt. | ||
113 | */ | ||
114 | |||
115 | static int bit_parity(u32 pkt) | ||
116 | { | ||
117 | int x = pkt ^ (pkt >> 16); | ||
118 | x ^= x >> 8; | ||
119 | x ^= x >> 4; | ||
120 | x ^= x >> 2; | ||
121 | x ^= x >> 1; | ||
122 | return x & 1; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Poll gameport; return true if all bits set in 'onbits' are on and | ||
127 | * all bits set in 'offbits' are off. | ||
128 | */ | ||
129 | |||
130 | static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data) | ||
131 | { | ||
132 | int i, nloops; | ||
133 | |||
134 | nloops = gameport_time(gp, u_sec); | ||
135 | for (i = 0; i < nloops; i++) { | ||
136 | *data = gameport_read(gp); | ||
137 | if ((*data & onbits) == onbits && | ||
138 | (~(*data) & offbits) == offbits) | ||
139 | return 1; | ||
140 | } | ||
141 | dbg("gameport timed out after %d microseconds.\n", u_sec); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Gets a 28-bit packet from the multiport. | ||
147 | * | ||
148 | * After getting a packet successfully, commands encoded by sendcode may | ||
149 | * be sent to the multiport. | ||
150 | * | ||
151 | * The multiport clock value is reflected in gameport bit B4. | ||
152 | * | ||
153 | * Returns a packet status code indicating whether packet is valid, the transfer | ||
154 | * mode, and any error conditions. | ||
155 | * | ||
156 | * sendflags: current I/O status | ||
157 | * sendcode: data to send to the multiport if sendflags is nonzero | ||
158 | */ | ||
159 | |||
160 | static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) | ||
161 | { | ||
162 | u8 raw_data; /* raw data from gameport */ | ||
163 | u8 data_mask; /* packet data bits from raw_data */ | ||
164 | u32 pkt; /* packet temporary storage */ | ||
165 | int bits_per_read; /* num packet bits per gameport read */ | ||
166 | int portvals = 0; /* used for port value sanity check */ | ||
167 | int i; | ||
168 | |||
169 | /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */ | ||
170 | |||
171 | *packet = 0; | ||
172 | raw_data = gameport_read(gameport); | ||
173 | if (raw_data & 1) | ||
174 | return IO_RETRY; | ||
175 | |||
176 | for (i = 0; i < 64; i++) { | ||
177 | raw_data = gameport_read(gameport); | ||
178 | portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */ | ||
179 | } | ||
180 | |||
181 | if (portvals == 1) { /* B4, B5 off */ | ||
182 | raw_data = gameport_read(gameport); | ||
183 | portvals = raw_data & 0xf0; | ||
184 | |||
185 | if (raw_data & 0x31) | ||
186 | return IO_RESET; | ||
187 | gameport_trigger(gameport); | ||
188 | |||
189 | if (!poll_until(0x10, 0, 308, gameport, &raw_data)) | ||
190 | return IO_RESET; | ||
191 | } else | ||
192 | return IO_RETRY; | ||
193 | |||
194 | /* Determine packet transfer mode and prepare for packet construction. */ | ||
195 | |||
196 | if (raw_data & 0x20) { /* 3 data bits/read */ | ||
197 | portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */ | ||
198 | |||
199 | if (portvals != 0xb) | ||
200 | return 0; | ||
201 | data_mask = 7; | ||
202 | bits_per_read = 3; | ||
203 | pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28; | ||
204 | } else { /* 1 data bit/read */ | ||
205 | data_mask = 1; | ||
206 | bits_per_read = 1; | ||
207 | pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28; | ||
208 | } | ||
209 | |||
210 | /* Construct a packet. Final data bits must be zero. */ | ||
211 | |||
212 | while (1) { | ||
213 | if (!poll_until(0, 0x10, 77, gameport, &raw_data)) | ||
214 | return IO_RESET; | ||
215 | raw_data = (raw_data >> 5) & data_mask; | ||
216 | |||
217 | if (pkt & PACKET_FULL) | ||
218 | break; | ||
219 | pkt = (pkt << bits_per_read) | raw_data; | ||
220 | |||
221 | if (!poll_until(0x10, 0, 77, gameport, &raw_data)) | ||
222 | return IO_RESET; | ||
223 | } | ||
224 | |||
225 | if (raw_data) | ||
226 | return IO_RESET; | ||
227 | |||
228 | /* If 3 bits/read used, drop from 30 bits to 28. */ | ||
229 | |||
230 | if (bits_per_read == 3) { | ||
231 | pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff); | ||
232 | pkt = (pkt >> 2) | 0xf0000000; | ||
233 | } | ||
234 | |||
235 | if (bit_parity(pkt) == 1) | ||
236 | return IO_RESET; | ||
237 | |||
238 | /* Acknowledge packet receipt */ | ||
239 | |||
240 | if (!poll_until(0x30, 0, 77, gameport, &raw_data)) | ||
241 | return IO_RESET; | ||
242 | |||
243 | raw_data = gameport_read(gameport); | ||
244 | |||
245 | if (raw_data & 1) | ||
246 | return IO_RESET; | ||
247 | |||
248 | gameport_trigger(gameport); | ||
249 | |||
250 | if (!poll_until(0, 0x20, 77, gameport, &raw_data)) | ||
251 | return IO_RESET; | ||
252 | |||
253 | /* Return if we just wanted the packet or multiport wants to send more */ | ||
254 | |||
255 | *packet = pkt; | ||
256 | if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE))) | ||
257 | return IO_GOT_PACKET; | ||
258 | |||
259 | if (pkt & PACKET_MP_MORE) | ||
260 | return IO_GOT_PACKET | IO_RETRY; | ||
261 | |||
262 | /* Multiport is done sending packets and is ready to receive data */ | ||
263 | |||
264 | if (!poll_until(0x20, 0, 77, gameport, &raw_data)) | ||
265 | return IO_GOT_PACKET | IO_RESET; | ||
266 | |||
267 | raw_data = gameport_read(gameport); | ||
268 | if (raw_data & 1) | ||
269 | return IO_GOT_PACKET | IO_RESET; | ||
270 | |||
271 | /* Trigger gameport based on bits in sendcode */ | ||
272 | |||
273 | gameport_trigger(gameport); | ||
274 | do { | ||
275 | if (!poll_until(0x20, 0x10, 116, gameport, &raw_data)) | ||
276 | return IO_GOT_PACKET | IO_RESET; | ||
277 | |||
278 | if (!poll_until(0x30, 0, 193, gameport, &raw_data)) | ||
279 | return IO_GOT_PACKET | IO_RESET; | ||
280 | |||
281 | if (raw_data & 1) | ||
282 | return IO_GOT_PACKET | IO_RESET; | ||
283 | |||
284 | if (sendcode & 1) | ||
285 | gameport_trigger(gameport); | ||
286 | |||
287 | sendcode >>= 1; | ||
288 | } while (sendcode); | ||
289 | |||
290 | return IO_GOT_PACKET | IO_MODE_FAST; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Disables and restores interrupts for mp_io(), which does the actual I/O. | ||
295 | */ | ||
296 | |||
297 | static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) | ||
298 | { | ||
299 | int status; | ||
300 | unsigned long flags; | ||
301 | |||
302 | local_irq_save(flags); | ||
303 | status = mp_io(gameport, sendflags, sendcode, packet); | ||
304 | local_irq_restore(flags); | ||
305 | |||
306 | return status; | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * Puts multiport into digital mode. Multiport LED turns green. | ||
311 | * | ||
312 | * Returns true if a valid digital packet was received, false otherwise. | ||
313 | */ | ||
314 | |||
315 | static int dig_mode_start(struct gameport *gameport, u32 *packet) | ||
316 | { | ||
317 | int i, seq_len = sizeof(init_seq)/sizeof(int); | ||
318 | int flags, tries = 0, bads = 0; | ||
319 | |||
320 | for (i = 0; i < seq_len; i++) { /* Send magic sequence */ | ||
321 | if (init_seq[i]) | ||
322 | gameport_trigger(gameport); | ||
323 | udelay(GRIP_INIT_DELAY); | ||
324 | } | ||
325 | |||
326 | for (i = 0; i < 16; i++) /* Wait for multiport to settle */ | ||
327 | udelay(GRIP_INIT_DELAY); | ||
328 | |||
329 | while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */ | ||
330 | |||
331 | flags = multiport_io(gameport, IO_RESET, 0x27, packet); | ||
332 | |||
333 | if (flags & IO_MODE_FAST) | ||
334 | return 1; | ||
335 | |||
336 | if (flags & IO_RETRY) | ||
337 | tries++; | ||
338 | else | ||
339 | bads++; | ||
340 | } | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * Packet structure: B0-B15 => gamepad state | ||
346 | * B16-B20 => gamepad device type | ||
347 | * B21-B24 => multiport slot index (1-4) | ||
348 | * | ||
349 | * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist. | ||
350 | * | ||
351 | * Returns the packet status. | ||
352 | */ | ||
353 | |||
354 | static int get_and_decode_packet(struct grip_mp *grip, int flags) | ||
355 | { | ||
356 | u32 packet; | ||
357 | int joytype = 0; | ||
358 | int slot = 0; | ||
359 | |||
360 | /* Get a packet and check for validity */ | ||
361 | |||
362 | flags &= IO_RESET | IO_RETRY; | ||
363 | flags = multiport_io(grip->gameport, flags, 0, &packet); | ||
364 | grip->reads++; | ||
365 | |||
366 | if (packet & PACKET_MP_DONE) | ||
367 | flags |= IO_DONE; | ||
368 | |||
369 | if (flags && !(flags & IO_GOT_PACKET)) { | ||
370 | grip->bads++; | ||
371 | return flags; | ||
372 | } | ||
373 | |||
374 | /* Ignore non-gamepad packets, e.g. multiport hardware version */ | ||
375 | |||
376 | slot = ((packet >> 21) & 0xf) - 1; | ||
377 | if ((slot < 0) || (slot > 3)) | ||
378 | return flags; | ||
379 | |||
380 | /* | ||
381 | * Handle "reset" packets, which occur at startup, and when gamepads | ||
382 | * are removed or plugged in. May contain configuration of a new gamepad. | ||
383 | */ | ||
384 | |||
385 | joytype = (packet >> 16) & 0x1f; | ||
386 | if (!joytype) { | ||
387 | |||
388 | if (grip->registered[slot]) { | ||
389 | printk(KERN_INFO "grip_mp: removing %s, slot %d\n", | ||
390 | grip_name[grip->mode[slot]], slot); | ||
391 | input_unregister_device(grip->dev + slot); | ||
392 | grip->registered[slot] = 0; | ||
393 | } | ||
394 | dbg("Reset: grip multiport slot %d\n", slot); | ||
395 | grip->mode[slot] = GRIP_MODE_RESET; | ||
396 | flags |= IO_SLOT_CHANGE; | ||
397 | return flags; | ||
398 | } | ||
399 | |||
400 | /* Interpret a grip pad packet */ | ||
401 | |||
402 | if (joytype == 0x1f) { | ||
403 | |||
404 | int dir = (packet >> 8) & 0xf; /* eight way directional value */ | ||
405 | grip->buttons[slot] = (~packet) & 0xff; | ||
406 | grip->yaxes[slot] = ((axis_map[dir] >> 2) & 3) - 1; | ||
407 | grip->xaxes[slot] = (axis_map[dir] & 3) - 1; | ||
408 | grip->dirty[slot] = 1; | ||
409 | |||
410 | if (grip->mode[slot] == GRIP_MODE_RESET) | ||
411 | flags |= IO_SLOT_CHANGE; | ||
412 | |||
413 | grip->mode[slot] = GRIP_MODE_GP; | ||
414 | |||
415 | if (!grip->registered[slot]) { | ||
416 | dbg("New Grip pad in multiport slot %d.\n", slot); | ||
417 | register_slot(slot, grip); | ||
418 | } | ||
419 | return flags; | ||
420 | } | ||
421 | |||
422 | /* Handle non-grip device codes. For now, just print diagnostics. */ | ||
423 | |||
424 | { | ||
425 | static int strange_code = 0; | ||
426 | if (strange_code != joytype) { | ||
427 | printk(KERN_INFO "Possible non-grip pad/joystick detected.\n"); | ||
428 | printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet); | ||
429 | strange_code = joytype; | ||
430 | } | ||
431 | } | ||
432 | return flags; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * Returns true if all multiport slot states appear valid. | ||
437 | */ | ||
438 | |||
439 | static int slots_valid(struct grip_mp *grip) | ||
440 | { | ||
441 | int flags, slot, invalid = 0, active = 0; | ||
442 | |||
443 | flags = get_and_decode_packet(grip, 0); | ||
444 | if (!(flags & IO_GOT_PACKET)) | ||
445 | return 0; | ||
446 | |||
447 | for (slot = 0; slot < 4; slot++) { | ||
448 | if (grip->mode[slot] == GRIP_MODE_RESET) | ||
449 | invalid = 1; | ||
450 | if (grip->mode[slot] != GRIP_MODE_NONE) | ||
451 | active = 1; | ||
452 | } | ||
453 | |||
454 | /* Return true if no active slot but multiport sent all its data */ | ||
455 | if (!active) | ||
456 | return (flags & IO_DONE) ? 1 : 0; | ||
457 | |||
458 | /* Return false if invalid device code received */ | ||
459 | return invalid ? 0 : 1; | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Returns whether the multiport was placed into digital mode and | ||
464 | * able to communicate its state successfully. | ||
465 | */ | ||
466 | |||
467 | static int multiport_init(struct grip_mp *grip) | ||
468 | { | ||
469 | int dig_mode, initialized = 0, tries = 0; | ||
470 | u32 packet; | ||
471 | |||
472 | dig_mode = dig_mode_start(grip->gameport, &packet); | ||
473 | while (!dig_mode && tries < 4) { | ||
474 | dig_mode = dig_mode_start(grip->gameport, &packet); | ||
475 | tries++; | ||
476 | } | ||
477 | |||
478 | if (dig_mode) | ||
479 | dbg("multiport_init(): digital mode activated.\n"); | ||
480 | else { | ||
481 | dbg("multiport_init(): unable to activate digital mode.\n"); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | /* Get packets, store multiport state, and check state's validity */ | ||
486 | for (tries = 0; tries < 4096; tries++) { | ||
487 | if ( slots_valid(grip) ) { | ||
488 | initialized = 1; | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | dbg("multiport_init(): initialized == %d\n", initialized); | ||
493 | return initialized; | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * Reports joystick state to the linux input layer. | ||
498 | */ | ||
499 | |||
500 | static void report_slot(struct grip_mp *grip, int slot) | ||
501 | { | ||
502 | struct input_dev *dev = &(grip->dev[slot]); | ||
503 | int i, buttons = grip->buttons[slot]; | ||
504 | |||
505 | /* Store button states with linux input driver */ | ||
506 | |||
507 | for (i = 0; i < 8; i++) | ||
508 | input_report_key(dev, grip_btn_gp[i], (buttons >> i) & 1); | ||
509 | |||
510 | /* Store axis states with linux driver */ | ||
511 | |||
512 | input_report_abs(dev, ABS_X, grip->xaxes[slot]); | ||
513 | input_report_abs(dev, ABS_Y, grip->yaxes[slot]); | ||
514 | |||
515 | /* Tell the receiver of the events to process them */ | ||
516 | |||
517 | input_sync(dev); | ||
518 | |||
519 | grip->dirty[slot] = 0; | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Get the multiport state. | ||
524 | */ | ||
525 | |||
526 | static void grip_poll(struct gameport *gameport) | ||
527 | { | ||
528 | struct grip_mp *grip = gameport_get_drvdata(gameport); | ||
529 | int i, npkts, flags; | ||
530 | |||
531 | for (npkts = 0; npkts < 4; npkts++) { | ||
532 | flags = IO_RETRY; | ||
533 | for (i = 0; i < 32; i++) { | ||
534 | flags = get_and_decode_packet(grip, flags); | ||
535 | if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY)) | ||
536 | break; | ||
537 | } | ||
538 | if (flags & IO_DONE) | ||
539 | break; | ||
540 | } | ||
541 | |||
542 | for (i = 0; i < 4; i++) | ||
543 | if (grip->dirty[i]) | ||
544 | report_slot(grip, i); | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Called when a joystick device file is opened | ||
549 | */ | ||
550 | |||
551 | static int grip_open(struct input_dev *dev) | ||
552 | { | ||
553 | struct grip_mp *grip = dev->private; | ||
554 | |||
555 | gameport_start_polling(grip->gameport); | ||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * Called when a joystick device file is closed | ||
561 | */ | ||
562 | |||
563 | static void grip_close(struct input_dev *dev) | ||
564 | { | ||
565 | struct grip_mp *grip = dev->private; | ||
566 | |||
567 | gameport_start_polling(grip->gameport); | ||
568 | } | ||
569 | |||
570 | /* | ||
571 | * Tell the linux input layer about a newly plugged-in gamepad. | ||
572 | */ | ||
573 | |||
574 | static void register_slot(int slot, struct grip_mp *grip) | ||
575 | { | ||
576 | int j, t; | ||
577 | |||
578 | grip->dev[slot].private = grip; | ||
579 | grip->dev[slot].open = grip_open; | ||
580 | grip->dev[slot].close = grip_close; | ||
581 | grip->dev[slot].name = grip_name[grip->mode[slot]]; | ||
582 | grip->dev[slot].id.bustype = BUS_GAMEPORT; | ||
583 | grip->dev[slot].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; | ||
584 | grip->dev[slot].id.product = 0x0100 + grip->mode[slot]; | ||
585 | grip->dev[slot].id.version = 0x0100; | ||
586 | grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
587 | |||
588 | for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) | ||
589 | input_set_abs_params(&grip->dev[slot], t, -1, 1, 0, 0); | ||
590 | |||
591 | for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++) | ||
592 | if (t > 0) | ||
593 | set_bit(t, grip->dev[slot].keybit); | ||
594 | |||
595 | input_register_device(grip->dev + slot); | ||
596 | grip->registered[slot] = 1; | ||
597 | |||
598 | if (grip->dirty[slot]) /* report initial state, if any */ | ||
599 | report_slot(grip, slot); | ||
600 | |||
601 | printk(KERN_INFO "grip_mp: added %s, slot %d\n", | ||
602 | grip_name[grip->mode[slot]], slot); | ||
603 | } | ||
604 | |||
605 | static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
606 | { | ||
607 | struct grip_mp *grip; | ||
608 | int err; | ||
609 | |||
610 | if (!(grip = kcalloc(1, sizeof(struct grip_mp), GFP_KERNEL))) | ||
611 | return -ENOMEM; | ||
612 | |||
613 | grip->gameport = gameport; | ||
614 | |||
615 | gameport_set_drvdata(gameport, grip); | ||
616 | |||
617 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
618 | if (err) | ||
619 | goto fail1; | ||
620 | |||
621 | gameport_set_poll_handler(gameport, grip_poll); | ||
622 | gameport_set_poll_interval(gameport, 20); | ||
623 | |||
624 | if (!multiport_init(grip)) { | ||
625 | err = -ENODEV; | ||
626 | goto fail2; | ||
627 | } | ||
628 | |||
629 | if (!grip->mode[0] && !grip->mode[1] && !grip->mode[2] && !grip->mode[3]) { | ||
630 | /* nothing plugged in */ | ||
631 | err = -ENODEV; | ||
632 | goto fail2; | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | |||
637 | fail2: gameport_close(gameport); | ||
638 | fail1: gameport_set_drvdata(gameport, NULL); | ||
639 | kfree(grip); | ||
640 | return err; | ||
641 | } | ||
642 | |||
643 | static void grip_disconnect(struct gameport *gameport) | ||
644 | { | ||
645 | struct grip_mp *grip = gameport_get_drvdata(gameport); | ||
646 | int i; | ||
647 | |||
648 | for (i = 0; i < 4; i++) | ||
649 | if (grip->registered[i]) | ||
650 | input_unregister_device(grip->dev + i); | ||
651 | gameport_close(gameport); | ||
652 | gameport_set_drvdata(gameport, NULL); | ||
653 | kfree(grip); | ||
654 | } | ||
655 | |||
656 | static struct gameport_driver grip_drv = { | ||
657 | .driver = { | ||
658 | .name = "grip_mp", | ||
659 | }, | ||
660 | .description = DRIVER_DESC, | ||
661 | .connect = grip_connect, | ||
662 | .disconnect = grip_disconnect, | ||
663 | }; | ||
664 | |||
665 | static int __init grip_init(void) | ||
666 | { | ||
667 | gameport_register_driver(&grip_drv); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static void __exit grip_exit(void) | ||
672 | { | ||
673 | gameport_unregister_driver(&grip_drv); | ||
674 | } | ||
675 | |||
676 | module_init(grip_init); | ||
677 | module_exit(grip_exit); | ||
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c new file mode 100644 index 000000000000..f93da7bc082d --- /dev/null +++ b/drivers/input/joystick/guillemot.c | |||
@@ -0,0 +1,289 @@ | |||
1 | /* | ||
2 | * $Id: guillemot.c,v 1.10 2002/01/22 20:28:12 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Guillemot Digital Interface Protocol 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/kernel.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/gameport.h> | ||
37 | #include <linux/input.h> | ||
38 | |||
39 | #define DRIVER_DESC "Guillemot Digital joystick driver" | ||
40 | |||
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
42 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | #define GUILLEMOT_MAX_START 600 /* 600 us */ | ||
46 | #define GUILLEMOT_MAX_STROBE 60 /* 60 us */ | ||
47 | #define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */ | ||
48 | |||
49 | static short guillemot_abs_pad[] = | ||
50 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 }; | ||
51 | |||
52 | static short guillemot_btn_pad[] = | ||
53 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 }; | ||
54 | |||
55 | static struct { | ||
56 | int x; | ||
57 | int y; | ||
58 | } guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | ||
59 | |||
60 | struct guillemot_type { | ||
61 | unsigned char id; | ||
62 | short *abs; | ||
63 | short *btn; | ||
64 | int hat; | ||
65 | char *name; | ||
66 | }; | ||
67 | |||
68 | struct guillemot { | ||
69 | struct gameport *gameport; | ||
70 | struct input_dev dev; | ||
71 | int bads; | ||
72 | int reads; | ||
73 | struct guillemot_type *type; | ||
74 | unsigned char length; | ||
75 | char phys[32]; | ||
76 | }; | ||
77 | |||
78 | static struct guillemot_type guillemot_type[] = { | ||
79 | { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" }, | ||
80 | { 0 }}; | ||
81 | |||
82 | /* | ||
83 | * guillemot_read_packet() reads Guillemot joystick data. | ||
84 | */ | ||
85 | |||
86 | static int guillemot_read_packet(struct gameport *gameport, u8 *data) | ||
87 | { | ||
88 | unsigned long flags; | ||
89 | unsigned char u, v; | ||
90 | unsigned int t, s; | ||
91 | int i; | ||
92 | |||
93 | for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++) | ||
94 | data[i] = 0; | ||
95 | |||
96 | i = 0; | ||
97 | t = gameport_time(gameport, GUILLEMOT_MAX_START); | ||
98 | s = gameport_time(gameport, GUILLEMOT_MAX_STROBE); | ||
99 | |||
100 | local_irq_save(flags); | ||
101 | gameport_trigger(gameport); | ||
102 | v = gameport_read(gameport); | ||
103 | |||
104 | while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) { | ||
105 | t--; | ||
106 | u = v; v = gameport_read(gameport); | ||
107 | if (v & ~u & 0x10) { | ||
108 | data[i >> 3] |= ((v >> 5) & 1) << (i & 7); | ||
109 | i++; | ||
110 | t = s; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | local_irq_restore(flags); | ||
115 | |||
116 | return i; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * guillemot_poll() reads and analyzes Guillemot joystick data. | ||
121 | */ | ||
122 | |||
123 | static void guillemot_poll(struct gameport *gameport) | ||
124 | { | ||
125 | struct guillemot *guillemot = gameport_get_drvdata(gameport); | ||
126 | struct input_dev *dev = &guillemot->dev; | ||
127 | u8 data[GUILLEMOT_MAX_LENGTH]; | ||
128 | int i; | ||
129 | |||
130 | guillemot->reads++; | ||
131 | |||
132 | if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 || | ||
133 | data[0] != 0x55 || data[16] != 0xaa) { | ||
134 | guillemot->bads++; | ||
135 | } else { | ||
136 | |||
137 | for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++) | ||
138 | input_report_abs(dev, guillemot->type->abs[i], data[i + 5]); | ||
139 | |||
140 | if (guillemot->type->hat) { | ||
141 | input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x); | ||
142 | input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y); | ||
143 | } | ||
144 | |||
145 | for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++) | ||
146 | input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1); | ||
147 | } | ||
148 | |||
149 | input_sync(dev); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * guillemot_open() is a callback from the input open routine. | ||
154 | */ | ||
155 | |||
156 | static int guillemot_open(struct input_dev *dev) | ||
157 | { | ||
158 | struct guillemot *guillemot = dev->private; | ||
159 | |||
160 | gameport_start_polling(guillemot->gameport); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * guillemot_close() is a callback from the input close routine. | ||
166 | */ | ||
167 | |||
168 | static void guillemot_close(struct input_dev *dev) | ||
169 | { | ||
170 | struct guillemot *guillemot = dev->private; | ||
171 | |||
172 | gameport_stop_polling(guillemot->gameport); | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * guillemot_connect() probes for Guillemot joysticks. | ||
177 | */ | ||
178 | |||
179 | static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
180 | { | ||
181 | struct guillemot *guillemot; | ||
182 | u8 data[GUILLEMOT_MAX_LENGTH]; | ||
183 | int i, t; | ||
184 | int err; | ||
185 | |||
186 | if (!(guillemot = kcalloc(1, sizeof(struct guillemot), GFP_KERNEL))) | ||
187 | return -ENOMEM; | ||
188 | |||
189 | guillemot->gameport = gameport; | ||
190 | |||
191 | gameport_set_drvdata(gameport, guillemot); | ||
192 | |||
193 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
194 | if (err) | ||
195 | goto fail1; | ||
196 | |||
197 | i = guillemot_read_packet(gameport, data); | ||
198 | |||
199 | if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) { | ||
200 | err = -ENODEV; | ||
201 | goto fail2; | ||
202 | } | ||
203 | |||
204 | for (i = 0; guillemot_type[i].name; i++) | ||
205 | if (guillemot_type[i].id == data[11]) | ||
206 | break; | ||
207 | |||
208 | if (!guillemot_type[i].name) { | ||
209 | printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n", | ||
210 | gameport->phys, data[12], data[13], data[11], data[14], data[15]); | ||
211 | err = -ENODEV; | ||
212 | goto fail2; | ||
213 | } | ||
214 | |||
215 | gameport_set_poll_handler(gameport, guillemot_poll); | ||
216 | gameport_set_poll_interval(gameport, 20); | ||
217 | |||
218 | sprintf(guillemot->phys, "%s/input0", gameport->phys); | ||
219 | |||
220 | guillemot->type = guillemot_type + i; | ||
221 | |||
222 | guillemot->dev.private = guillemot; | ||
223 | guillemot->dev.open = guillemot_open; | ||
224 | guillemot->dev.close = guillemot_close; | ||
225 | |||
226 | guillemot->dev.name = guillemot_type[i].name; | ||
227 | guillemot->dev.phys = guillemot->phys; | ||
228 | guillemot->dev.id.bustype = BUS_GAMEPORT; | ||
229 | guillemot->dev.id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; | ||
230 | guillemot->dev.id.product = guillemot_type[i].id; | ||
231 | guillemot->dev.id.version = (int)data[14] << 8 | data[15]; | ||
232 | |||
233 | guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
234 | |||
235 | for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) | ||
236 | input_set_abs_params(&guillemot->dev, t, 0, 255, 0, 0); | ||
237 | |||
238 | if (guillemot->type->hat) { | ||
239 | input_set_abs_params(&guillemot->dev, ABS_HAT0X, -1, 1, 0, 0); | ||
240 | input_set_abs_params(&guillemot->dev, ABS_HAT0Y, -1, 1, 0, 0); | ||
241 | } | ||
242 | |||
243 | for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) | ||
244 | set_bit(t, guillemot->dev.keybit); | ||
245 | |||
246 | input_register_device(&guillemot->dev); | ||
247 | printk(KERN_INFO "input: %s ver %d.%02d on %s\n", | ||
248 | guillemot->type->name, data[14], data[15], gameport->phys); | ||
249 | |||
250 | return 0; | ||
251 | |||
252 | fail2: gameport_close(gameport); | ||
253 | fail1: gameport_set_drvdata(gameport, NULL); | ||
254 | kfree(guillemot); | ||
255 | return err; | ||
256 | } | ||
257 | |||
258 | static void guillemot_disconnect(struct gameport *gameport) | ||
259 | { | ||
260 | struct guillemot *guillemot = gameport_get_drvdata(gameport); | ||
261 | |||
262 | printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); | ||
263 | input_unregister_device(&guillemot->dev); | ||
264 | gameport_close(gameport); | ||
265 | kfree(guillemot); | ||
266 | } | ||
267 | |||
268 | static struct gameport_driver guillemot_drv = { | ||
269 | .driver = { | ||
270 | .name = "guillemot", | ||
271 | }, | ||
272 | .description = DRIVER_DESC, | ||
273 | .connect = guillemot_connect, | ||
274 | .disconnect = guillemot_disconnect, | ||
275 | }; | ||
276 | |||
277 | static int __init guillemot_init(void) | ||
278 | { | ||
279 | gameport_register_driver(&guillemot_drv); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static void __exit guillemot_exit(void) | ||
284 | { | ||
285 | gameport_unregister_driver(&guillemot_drv); | ||
286 | } | ||
287 | |||
288 | module_init(guillemot_init); | ||
289 | module_exit(guillemot_exit); | ||
diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig new file mode 100644 index 000000000000..8fde22a021b3 --- /dev/null +++ b/drivers/input/joystick/iforce/Kconfig | |||
@@ -0,0 +1,32 @@ | |||
1 | # | ||
2 | # I-Force driver configuration | ||
3 | # | ||
4 | config JOYSTICK_IFORCE | ||
5 | tristate "I-Force devices" | ||
6 | depends on INPUT && INPUT_JOYSTICK | ||
7 | help | ||
8 | Say Y here if you have an I-Force joystick or steering wheel | ||
9 | |||
10 | You also must choose at least one of the two options below. | ||
11 | |||
12 | To compile this driver as a module, choose M here: the | ||
13 | module will be called iforce. | ||
14 | |||
15 | config JOYSTICK_IFORCE_USB | ||
16 | bool "I-Force USB joysticks and wheels" | ||
17 | depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB | ||
18 | help | ||
19 | Say Y here if you have an I-Force joystick or steering wheel | ||
20 | connected to your USB port. | ||
21 | |||
22 | config JOYSTICK_IFORCE_232 | ||
23 | bool "I-Force Serial joysticks and wheels" | ||
24 | depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO | ||
25 | help | ||
26 | Say Y here if you have an I-Force joystick or steering wheel | ||
27 | connected to your serial (COM) port. | ||
28 | |||
29 | You will need an additional utility called inputattach, see | ||
30 | <file:Documentation/input/joystick.txt> | ||
31 | and <file:Documentation/input/ff.txt>. | ||
32 | |||
diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile new file mode 100644 index 000000000000..17ae42bf9ffd --- /dev/null +++ b/drivers/input/joystick/iforce/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # | ||
2 | # Makefile for the I-Force driver | ||
3 | # | ||
4 | # By Johann Deneux <deneux@ifrance.com> | ||
5 | # | ||
6 | |||
7 | # Goal definition | ||
8 | iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o | ||
9 | |||
10 | obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o | ||
11 | |||
12 | ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) | ||
13 | iforce-objs += iforce-serio.o | ||
14 | endif | ||
15 | |||
16 | ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) | ||
17 | iforce-objs += iforce-usb.o | ||
18 | endif | ||
19 | |||
20 | EXTRA_CFLAGS = -Werror-implicit-function-declaration | ||
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c new file mode 100644 index 000000000000..4678b6dab43b --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-ff.c | |||
@@ -0,0 +1,543 @@ | |||
1 | /* | ||
2 | * $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | * Should you need to contact me, the author, you can do so either by | ||
26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | /* | ||
33 | * Set the magnitude of a constant force effect | ||
34 | * Return error code | ||
35 | * | ||
36 | * Note: caller must ensure exclusive access to device | ||
37 | */ | ||
38 | |||
39 | static int make_magnitude_modifier(struct iforce* iforce, | ||
40 | struct resource* mod_chunk, int no_alloc, __s16 level) | ||
41 | { | ||
42 | unsigned char data[3]; | ||
43 | |||
44 | if (!no_alloc) { | ||
45 | down(&iforce->mem_mutex); | ||
46 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, | ||
47 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
48 | NULL, NULL)) { | ||
49 | up(&iforce->mem_mutex); | ||
50 | return -ENOMEM; | ||
51 | } | ||
52 | up(&iforce->mem_mutex); | ||
53 | } | ||
54 | |||
55 | data[0] = LO(mod_chunk->start); | ||
56 | data[1] = HI(mod_chunk->start); | ||
57 | data[2] = HIFIX80(level); | ||
58 | |||
59 | iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); | ||
60 | |||
61 | iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Upload the component of an effect dealing with the period, phase and magnitude | ||
67 | */ | ||
68 | |||
69 | static int make_period_modifier(struct iforce* iforce, | ||
70 | struct resource* mod_chunk, int no_alloc, | ||
71 | __s16 magnitude, __s16 offset, u16 period, u16 phase) | ||
72 | { | ||
73 | unsigned char data[7]; | ||
74 | |||
75 | period = TIME_SCALE(period); | ||
76 | |||
77 | if (!no_alloc) { | ||
78 | down(&iforce->mem_mutex); | ||
79 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, | ||
80 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
81 | NULL, NULL)) { | ||
82 | up(&iforce->mem_mutex); | ||
83 | return -ENOMEM; | ||
84 | } | ||
85 | up(&iforce->mem_mutex); | ||
86 | } | ||
87 | |||
88 | data[0] = LO(mod_chunk->start); | ||
89 | data[1] = HI(mod_chunk->start); | ||
90 | |||
91 | data[2] = HIFIX80(magnitude); | ||
92 | data[3] = HIFIX80(offset); | ||
93 | data[4] = HI(phase); | ||
94 | |||
95 | data[5] = LO(period); | ||
96 | data[6] = HI(period); | ||
97 | |||
98 | iforce_send_packet(iforce, FF_CMD_PERIOD, data); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Uploads the part of an effect setting the envelope of the force | ||
105 | */ | ||
106 | |||
107 | static int make_envelope_modifier(struct iforce* iforce, | ||
108 | struct resource* mod_chunk, int no_alloc, | ||
109 | u16 attack_duration, __s16 initial_level, | ||
110 | u16 fade_duration, __s16 final_level) | ||
111 | { | ||
112 | unsigned char data[8]; | ||
113 | |||
114 | attack_duration = TIME_SCALE(attack_duration); | ||
115 | fade_duration = TIME_SCALE(fade_duration); | ||
116 | |||
117 | if (!no_alloc) { | ||
118 | down(&iforce->mem_mutex); | ||
119 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, | ||
120 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
121 | NULL, NULL)) { | ||
122 | up(&iforce->mem_mutex); | ||
123 | return -ENOMEM; | ||
124 | } | ||
125 | up(&iforce->mem_mutex); | ||
126 | } | ||
127 | |||
128 | data[0] = LO(mod_chunk->start); | ||
129 | data[1] = HI(mod_chunk->start); | ||
130 | |||
131 | data[2] = LO(attack_duration); | ||
132 | data[3] = HI(attack_duration); | ||
133 | data[4] = HI(initial_level); | ||
134 | |||
135 | data[5] = LO(fade_duration); | ||
136 | data[6] = HI(fade_duration); | ||
137 | data[7] = HI(final_level); | ||
138 | |||
139 | iforce_send_packet(iforce, FF_CMD_ENVELOPE, data); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Component of spring, friction, inertia... effects | ||
146 | */ | ||
147 | |||
148 | static int make_condition_modifier(struct iforce* iforce, | ||
149 | struct resource* mod_chunk, int no_alloc, | ||
150 | __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) | ||
151 | { | ||
152 | unsigned char data[10]; | ||
153 | |||
154 | if (!no_alloc) { | ||
155 | down(&iforce->mem_mutex); | ||
156 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, | ||
157 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
158 | NULL, NULL)) { | ||
159 | up(&iforce->mem_mutex); | ||
160 | return -ENOMEM; | ||
161 | } | ||
162 | up(&iforce->mem_mutex); | ||
163 | } | ||
164 | |||
165 | data[0] = LO(mod_chunk->start); | ||
166 | data[1] = HI(mod_chunk->start); | ||
167 | |||
168 | data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ | ||
169 | data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ | ||
170 | |||
171 | center = (500*center)>>15; | ||
172 | data[4] = LO(center); | ||
173 | data[5] = HI(center); | ||
174 | |||
175 | db = (1000*db)>>16; | ||
176 | data[6] = LO(db); | ||
177 | data[7] = HI(db); | ||
178 | |||
179 | data[8] = (100*rsat)>>16; | ||
180 | data[9] = (100*lsat)>>16; | ||
181 | |||
182 | iforce_send_packet(iforce, FF_CMD_CONDITION, data); | ||
183 | iforce_dump_packet("condition", FF_CMD_CONDITION, data); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static unsigned char find_button(struct iforce *iforce, signed short button) | ||
189 | { | ||
190 | int i; | ||
191 | for (i = 1; iforce->type->btn[i] >= 0; i++) | ||
192 | if (iforce->type->btn[i] == button) | ||
193 | return i + 1; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Analyse the changes in an effect, and tell if we need to send an condition | ||
199 | * parameter packet | ||
200 | */ | ||
201 | static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) | ||
202 | { | ||
203 | int id = new->id; | ||
204 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
205 | int ret=0; | ||
206 | int i; | ||
207 | |||
208 | if (new->type != FF_SPRING && new->type != FF_FRICTION) { | ||
209 | printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); | ||
210 | return FALSE; | ||
211 | } | ||
212 | |||
213 | for(i=0; i<2; i++) { | ||
214 | ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation | ||
215 | || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation | ||
216 | || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff | ||
217 | || old->u.condition[i].left_coeff != new->u.condition[i].left_coeff | ||
218 | || old->u.condition[i].deadband != new->u.condition[i].deadband | ||
219 | || old->u.condition[i].center != new->u.condition[i].center; | ||
220 | } | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Analyse the changes in an effect, and tell if we need to send a magnitude | ||
226 | * parameter packet | ||
227 | */ | ||
228 | static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) | ||
229 | { | ||
230 | int id = effect->id; | ||
231 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
232 | |||
233 | if (effect->type != FF_CONSTANT) { | ||
234 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | ||
235 | return FALSE; | ||
236 | } | ||
237 | |||
238 | return (old->u.constant.level != effect->u.constant.level); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * Analyse the changes in an effect, and tell if we need to send an envelope | ||
243 | * parameter packet | ||
244 | */ | ||
245 | static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect) | ||
246 | { | ||
247 | int id = effect->id; | ||
248 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
249 | |||
250 | switch (effect->type) { | ||
251 | case FF_CONSTANT: | ||
252 | if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length | ||
253 | || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level | ||
254 | || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length | ||
255 | || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) | ||
256 | return TRUE; | ||
257 | break; | ||
258 | |||
259 | case FF_PERIODIC: | ||
260 | if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length | ||
261 | || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level | ||
262 | || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length | ||
263 | || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) | ||
264 | return TRUE; | ||
265 | break; | ||
266 | |||
267 | default: | ||
268 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | ||
269 | } | ||
270 | |||
271 | return FALSE; | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * Analyse the changes in an effect, and tell if we need to send a periodic | ||
276 | * parameter effect | ||
277 | */ | ||
278 | static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) | ||
279 | { | ||
280 | int id = new->id; | ||
281 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
282 | |||
283 | if (new->type != FF_PERIODIC) { | ||
284 | printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); | ||
285 | return FALSE; | ||
286 | } | ||
287 | |||
288 | return (old->u.periodic.period != new->u.periodic.period | ||
289 | || old->u.periodic.magnitude != new->u.periodic.magnitude | ||
290 | || old->u.periodic.offset != new->u.periodic.offset | ||
291 | || old->u.periodic.phase != new->u.periodic.phase); | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Analyse the changes in an effect, and tell if we need to send an effect | ||
296 | * packet | ||
297 | */ | ||
298 | static int need_core(struct iforce* iforce, struct ff_effect* new) | ||
299 | { | ||
300 | int id = new->id; | ||
301 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
302 | |||
303 | if (old->direction != new->direction | ||
304 | || old->trigger.button != new->trigger.button | ||
305 | || old->trigger.interval != new->trigger.interval | ||
306 | || old->replay.length != new->replay.length | ||
307 | || old->replay.delay != new->replay.delay) | ||
308 | return TRUE; | ||
309 | |||
310 | return FALSE; | ||
311 | } | ||
312 | /* | ||
313 | * Send the part common to all effects to the device | ||
314 | */ | ||
315 | static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, | ||
316 | u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, | ||
317 | u16 interval, u16 direction) | ||
318 | { | ||
319 | unsigned char data[14]; | ||
320 | |||
321 | duration = TIME_SCALE(duration); | ||
322 | delay = TIME_SCALE(delay); | ||
323 | interval = TIME_SCALE(interval); | ||
324 | |||
325 | data[0] = LO(id); | ||
326 | data[1] = effect_type; | ||
327 | data[2] = LO(axes) | find_button(iforce, button); | ||
328 | |||
329 | data[3] = LO(duration); | ||
330 | data[4] = HI(duration); | ||
331 | |||
332 | data[5] = HI(direction); | ||
333 | |||
334 | data[6] = LO(interval); | ||
335 | data[7] = HI(interval); | ||
336 | |||
337 | data[8] = LO(mod_id1); | ||
338 | data[9] = HI(mod_id1); | ||
339 | data[10] = LO(mod_id2); | ||
340 | data[11] = HI(mod_id2); | ||
341 | |||
342 | data[12] = LO(delay); | ||
343 | data[13] = HI(delay); | ||
344 | |||
345 | /* Stop effect */ | ||
346 | /* iforce_control_playback(iforce, id, 0);*/ | ||
347 | |||
348 | iforce_send_packet(iforce, FF_CMD_EFFECT, data); | ||
349 | |||
350 | /* If needed, restart effect */ | ||
351 | if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { | ||
352 | /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ | ||
353 | iforce_control_playback(iforce, id, 1); | ||
354 | } | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * Upload a periodic effect to the device | ||
361 | * See also iforce_upload_constant. | ||
362 | */ | ||
363 | int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) | ||
364 | { | ||
365 | u8 wave_code; | ||
366 | int core_id = effect->id; | ||
367 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | ||
368 | struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | ||
369 | struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | ||
370 | int param1_err = 1; | ||
371 | int param2_err = 1; | ||
372 | int core_err = 0; | ||
373 | |||
374 | if (!is_update || need_period_modifier(iforce, effect)) { | ||
375 | param1_err = make_period_modifier(iforce, mod1_chunk, | ||
376 | is_update, | ||
377 | effect->u.periodic.magnitude, effect->u.periodic.offset, | ||
378 | effect->u.periodic.period, effect->u.periodic.phase); | ||
379 | if (param1_err) return param1_err; | ||
380 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | ||
381 | } | ||
382 | |||
383 | if (!is_update || need_envelope_modifier(iforce, effect)) { | ||
384 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | ||
385 | is_update, | ||
386 | effect->u.periodic.envelope.attack_length, | ||
387 | effect->u.periodic.envelope.attack_level, | ||
388 | effect->u.periodic.envelope.fade_length, | ||
389 | effect->u.periodic.envelope.fade_level); | ||
390 | if (param2_err) return param2_err; | ||
391 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | ||
392 | } | ||
393 | |||
394 | switch (effect->u.periodic.waveform) { | ||
395 | case FF_SQUARE: wave_code = 0x20; break; | ||
396 | case FF_TRIANGLE: wave_code = 0x21; break; | ||
397 | case FF_SINE: wave_code = 0x22; break; | ||
398 | case FF_SAW_UP: wave_code = 0x23; break; | ||
399 | case FF_SAW_DOWN: wave_code = 0x24; break; | ||
400 | default: wave_code = 0x20; break; | ||
401 | } | ||
402 | |||
403 | if (!is_update || need_core(iforce, effect)) { | ||
404 | core_err = make_core(iforce, effect->id, | ||
405 | mod1_chunk->start, | ||
406 | mod2_chunk->start, | ||
407 | wave_code, | ||
408 | 0x20, | ||
409 | effect->replay.length, | ||
410 | effect->replay.delay, | ||
411 | effect->trigger.button, | ||
412 | effect->trigger.interval, | ||
413 | effect->direction); | ||
414 | } | ||
415 | |||
416 | /* If one of the parameter creation failed, we already returned an | ||
417 | * error code. | ||
418 | * If the core creation failed, we return its error code. | ||
419 | * Else: if one parameter at least was created, we return 0 | ||
420 | * else we return 1; | ||
421 | */ | ||
422 | return core_err < 0 ? core_err : (param1_err && param2_err); | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Upload a constant force effect | ||
427 | * Return value: | ||
428 | * <0 Error code | ||
429 | * 0 Ok, effect created or updated | ||
430 | * 1 effect did not change since last upload, and no packet was therefore sent | ||
431 | */ | ||
432 | int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) | ||
433 | { | ||
434 | int core_id = effect->id; | ||
435 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | ||
436 | struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | ||
437 | struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | ||
438 | int param1_err = 1; | ||
439 | int param2_err = 1; | ||
440 | int core_err = 0; | ||
441 | |||
442 | if (!is_update || need_magnitude_modifier(iforce, effect)) { | ||
443 | param1_err = make_magnitude_modifier(iforce, mod1_chunk, | ||
444 | is_update, | ||
445 | effect->u.constant.level); | ||
446 | if (param1_err) return param1_err; | ||
447 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | ||
448 | } | ||
449 | |||
450 | if (!is_update || need_envelope_modifier(iforce, effect)) { | ||
451 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | ||
452 | is_update, | ||
453 | effect->u.constant.envelope.attack_length, | ||
454 | effect->u.constant.envelope.attack_level, | ||
455 | effect->u.constant.envelope.fade_length, | ||
456 | effect->u.constant.envelope.fade_level); | ||
457 | if (param2_err) return param2_err; | ||
458 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | ||
459 | } | ||
460 | |||
461 | if (!is_update || need_core(iforce, effect)) { | ||
462 | core_err = make_core(iforce, effect->id, | ||
463 | mod1_chunk->start, | ||
464 | mod2_chunk->start, | ||
465 | 0x00, | ||
466 | 0x20, | ||
467 | effect->replay.length, | ||
468 | effect->replay.delay, | ||
469 | effect->trigger.button, | ||
470 | effect->trigger.interval, | ||
471 | effect->direction); | ||
472 | } | ||
473 | |||
474 | /* If one of the parameter creation failed, we already returned an | ||
475 | * error code. | ||
476 | * If the core creation failed, we return its error code. | ||
477 | * Else: if one parameter at least was created, we return 0 | ||
478 | * else we return 1; | ||
479 | */ | ||
480 | return core_err < 0 ? core_err : (param1_err && param2_err); | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * Upload an condition effect. Those are for example friction, inertia, springs... | ||
485 | */ | ||
486 | int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update) | ||
487 | { | ||
488 | int core_id = effect->id; | ||
489 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | ||
490 | struct resource* mod1_chunk = &(core_effect->mod1_chunk); | ||
491 | struct resource* mod2_chunk = &(core_effect->mod2_chunk); | ||
492 | u8 type; | ||
493 | int param_err = 1; | ||
494 | int core_err = 0; | ||
495 | |||
496 | switch (effect->type) { | ||
497 | case FF_SPRING: type = 0x40; break; | ||
498 | case FF_DAMPER: type = 0x41; break; | ||
499 | default: return -1; | ||
500 | } | ||
501 | |||
502 | if (!is_update || need_condition_modifier(iforce, effect)) { | ||
503 | param_err = make_condition_modifier(iforce, mod1_chunk, | ||
504 | is_update, | ||
505 | effect->u.condition[0].right_saturation, | ||
506 | effect->u.condition[0].left_saturation, | ||
507 | effect->u.condition[0].right_coeff, | ||
508 | effect->u.condition[0].left_coeff, | ||
509 | effect->u.condition[0].deadband, | ||
510 | effect->u.condition[0].center); | ||
511 | if (param_err) return param_err; | ||
512 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | ||
513 | |||
514 | param_err = make_condition_modifier(iforce, mod2_chunk, | ||
515 | is_update, | ||
516 | effect->u.condition[1].right_saturation, | ||
517 | effect->u.condition[1].left_saturation, | ||
518 | effect->u.condition[1].right_coeff, | ||
519 | effect->u.condition[1].left_coeff, | ||
520 | effect->u.condition[1].deadband, | ||
521 | effect->u.condition[1].center); | ||
522 | if (param_err) return param_err; | ||
523 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | ||
524 | |||
525 | } | ||
526 | |||
527 | if (!is_update || need_core(iforce, effect)) { | ||
528 | core_err = make_core(iforce, effect->id, | ||
529 | mod1_chunk->start, mod2_chunk->start, | ||
530 | type, 0xc0, | ||
531 | effect->replay.length, effect->replay.delay, | ||
532 | effect->trigger.button, effect->trigger.interval, | ||
533 | effect->direction); | ||
534 | } | ||
535 | |||
536 | /* If the parameter creation failed, we already returned an | ||
537 | * error code. | ||
538 | * If the core creation failed, we return its error code. | ||
539 | * Else: if a parameter was created, we return 0 | ||
540 | * else we return 1; | ||
541 | */ | ||
542 | return core_err < 0 ? core_err : param_err; | ||
543 | } | ||
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c new file mode 100644 index 000000000000..028f3513629a --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-main.c | |||
@@ -0,0 +1,557 @@ | |||
1 | /* | ||
2 | * $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | * Should you need to contact me, the author, you can do so either by | ||
26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>"); | ||
33 | MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static signed short btn_joystick[] = | ||
37 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | ||
38 | BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; | ||
39 | |||
40 | static signed short btn_avb_pegasus[] = | ||
41 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | ||
42 | BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; | ||
43 | |||
44 | static signed short btn_wheel[] = | ||
45 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | ||
46 | BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; | ||
47 | |||
48 | static signed short btn_avb_tw[] = | ||
49 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, | ||
50 | BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; | ||
51 | |||
52 | static signed short btn_avb_wheel[] = | ||
53 | { BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3, | ||
54 | BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 }; | ||
55 | |||
56 | static signed short abs_joystick[] = | ||
57 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | ||
58 | |||
59 | static signed short abs_avb_pegasus[] = | ||
60 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, | ||
61 | ABS_HAT1X, ABS_HAT1Y, -1 }; | ||
62 | |||
63 | static signed short abs_wheel[] = | ||
64 | { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; | ||
65 | |||
66 | static signed short ff_iforce[] = | ||
67 | { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_DAMPER, | ||
68 | FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, | ||
69 | FF_AUTOCENTER, -1 }; | ||
70 | |||
71 | static struct iforce_device iforce_device[] = { | ||
72 | { 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce }, | ||
73 | { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, | ||
74 | { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, | ||
75 | { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_avb_pegasus, abs_avb_pegasus, ff_iforce }, | ||
76 | { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_avb_wheel, abs_wheel, ff_iforce }, | ||
77 | { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, //? | ||
78 | { 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? | ||
79 | { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? | ||
80 | { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? | ||
81 | { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } | ||
82 | }; | ||
83 | |||
84 | |||
85 | |||
86 | static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
87 | { | ||
88 | struct iforce* iforce = (struct iforce*)(dev->private); | ||
89 | unsigned char data[3]; | ||
90 | |||
91 | if (type != EV_FF) | ||
92 | return -1; | ||
93 | |||
94 | switch (code) { | ||
95 | |||
96 | case FF_GAIN: | ||
97 | |||
98 | data[0] = value >> 9; | ||
99 | iforce_send_packet(iforce, FF_CMD_GAIN, data); | ||
100 | |||
101 | return 0; | ||
102 | |||
103 | case FF_AUTOCENTER: | ||
104 | |||
105 | data[0] = 0x03; | ||
106 | data[1] = value >> 9; | ||
107 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | ||
108 | |||
109 | data[0] = 0x04; | ||
110 | data[1] = 0x01; | ||
111 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | ||
112 | |||
113 | return 0; | ||
114 | |||
115 | default: /* Play or stop an effect */ | ||
116 | |||
117 | if (!CHECK_OWNERSHIP(code, iforce)) { | ||
118 | return -1; | ||
119 | } | ||
120 | if (value > 0) { | ||
121 | set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
122 | } | ||
123 | else { | ||
124 | clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
125 | } | ||
126 | |||
127 | iforce_control_playback(iforce, code, value); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Function called when an ioctl is performed on the event dev entry. | ||
136 | * It uploads an effect to the device | ||
137 | */ | ||
138 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | ||
139 | { | ||
140 | struct iforce* iforce = (struct iforce*)(dev->private); | ||
141 | int id; | ||
142 | int ret; | ||
143 | int is_update; | ||
144 | |||
145 | /* Check this effect type is supported by this device */ | ||
146 | if (!test_bit(effect->type, iforce->dev.ffbit)) | ||
147 | return -EINVAL; | ||
148 | |||
149 | /* | ||
150 | * If we want to create a new effect, get a free id | ||
151 | */ | ||
152 | if (effect->id == -1) { | ||
153 | |||
154 | for (id=0; id < FF_EFFECTS_MAX; ++id) | ||
155 | if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; | ||
156 | |||
157 | if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | effect->id = id; | ||
161 | iforce->core_effects[id].owner = current->pid; | ||
162 | iforce->core_effects[id].flags[0] = (1<<FF_CORE_IS_USED); /* Only IS_USED bit must be set */ | ||
163 | |||
164 | is_update = FALSE; | ||
165 | } | ||
166 | else { | ||
167 | /* We want to update an effect */ | ||
168 | if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES; | ||
169 | |||
170 | /* Parameter type cannot be updated */ | ||
171 | if (effect->type != iforce->core_effects[effect->id].effect.type) | ||
172 | return -EINVAL; | ||
173 | |||
174 | /* Check the effect is not already being updated */ | ||
175 | if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { | ||
176 | return -EAGAIN; | ||
177 | } | ||
178 | |||
179 | is_update = TRUE; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Upload the effect | ||
184 | */ | ||
185 | switch (effect->type) { | ||
186 | |||
187 | case FF_PERIODIC: | ||
188 | ret = iforce_upload_periodic(iforce, effect, is_update); | ||
189 | break; | ||
190 | |||
191 | case FF_CONSTANT: | ||
192 | ret = iforce_upload_constant(iforce, effect, is_update); | ||
193 | break; | ||
194 | |||
195 | case FF_SPRING: | ||
196 | case FF_DAMPER: | ||
197 | ret = iforce_upload_condition(iforce, effect, is_update); | ||
198 | break; | ||
199 | |||
200 | default: | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | if (ret == 0) { | ||
204 | /* A packet was sent, forbid new updates until we are notified | ||
205 | * that the packet was updated | ||
206 | */ | ||
207 | set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); | ||
208 | } | ||
209 | iforce->core_effects[effect->id].effect = *effect; | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Erases an effect: it frees the effect id and mark as unused the memory | ||
215 | * allocated for the parameters | ||
216 | */ | ||
217 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) | ||
218 | { | ||
219 | struct iforce* iforce = (struct iforce*)(dev->private); | ||
220 | int err = 0; | ||
221 | struct iforce_core_effect* core_effect; | ||
222 | |||
223 | /* Check who is trying to erase this effect */ | ||
224 | if (iforce->core_effects[effect_id].owner != current->pid) { | ||
225 | printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner); | ||
226 | return -EACCES; | ||
227 | } | ||
228 | |||
229 | if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) | ||
230 | return -EINVAL; | ||
231 | |||
232 | core_effect = iforce->core_effects + effect_id; | ||
233 | |||
234 | if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) | ||
235 | err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); | ||
236 | |||
237 | if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) | ||
238 | err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); | ||
239 | |||
240 | /*TODO: remember to change that if more FF_MOD* bits are added */ | ||
241 | core_effect->flags[0] = 0; | ||
242 | |||
243 | return err; | ||
244 | } | ||
245 | |||
246 | static int iforce_open(struct input_dev *dev) | ||
247 | { | ||
248 | struct iforce *iforce = dev->private; | ||
249 | |||
250 | switch (iforce->bus) { | ||
251 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
252 | case IFORCE_USB: | ||
253 | iforce->irq->dev = iforce->usbdev; | ||
254 | if (usb_submit_urb(iforce->irq, GFP_KERNEL)) | ||
255 | return -EIO; | ||
256 | break; | ||
257 | #endif | ||
258 | } | ||
259 | |||
260 | /* Enable force feedback */ | ||
261 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int iforce_flush(struct input_dev *dev, struct file *file) | ||
267 | { | ||
268 | struct iforce *iforce = dev->private; | ||
269 | int i; | ||
270 | |||
271 | /* Erase all effects this process owns */ | ||
272 | for (i=0; i<dev->ff_effects_max; ++i) { | ||
273 | |||
274 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | ||
275 | current->pid == iforce->core_effects[i].owner) { | ||
276 | |||
277 | /* Stop effect */ | ||
278 | input_report_ff(dev, i, 0); | ||
279 | |||
280 | /* Free ressources assigned to effect */ | ||
281 | if (iforce_erase_effect(dev, i)) { | ||
282 | printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void iforce_release(struct input_dev *dev) | ||
291 | { | ||
292 | struct iforce *iforce = dev->private; | ||
293 | int i; | ||
294 | |||
295 | /* Check: no effect should be present in memory */ | ||
296 | for (i=0; i<dev->ff_effects_max; ++i) { | ||
297 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) | ||
298 | break; | ||
299 | } | ||
300 | if (i<dev->ff_effects_max) { | ||
301 | printk(KERN_WARNING "iforce_release: Device still owns effects\n"); | ||
302 | } | ||
303 | |||
304 | /* Disable force feedback playback */ | ||
305 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); | ||
306 | |||
307 | switch (iforce->bus) { | ||
308 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
309 | case IFORCE_USB: | ||
310 | usb_unlink_urb(iforce->irq); | ||
311 | |||
312 | /* The device was unplugged before the file | ||
313 | * was released */ | ||
314 | if (iforce->usbdev == NULL) { | ||
315 | iforce_delete_device(iforce); | ||
316 | kfree(iforce); | ||
317 | } | ||
318 | break; | ||
319 | #endif | ||
320 | } | ||
321 | } | ||
322 | |||
323 | void iforce_delete_device(struct iforce *iforce) | ||
324 | { | ||
325 | switch (iforce->bus) { | ||
326 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
327 | case IFORCE_USB: | ||
328 | iforce_usb_delete(iforce); | ||
329 | break; | ||
330 | #endif | ||
331 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
332 | case IFORCE_232: | ||
333 | //TODO: Wait for the last packets to be sent | ||
334 | break; | ||
335 | #endif | ||
336 | } | ||
337 | } | ||
338 | |||
339 | int iforce_init_device(struct iforce *iforce) | ||
340 | { | ||
341 | unsigned char c[] = "CEOV"; | ||
342 | int i; | ||
343 | |||
344 | init_waitqueue_head(&iforce->wait); | ||
345 | spin_lock_init(&iforce->xmit_lock); | ||
346 | init_MUTEX(&iforce->mem_mutex); | ||
347 | iforce->xmit.buf = iforce->xmit_data; | ||
348 | |||
349 | iforce->dev.ff_effects_max = 10; | ||
350 | |||
351 | /* | ||
352 | * Input device fields. | ||
353 | */ | ||
354 | |||
355 | switch (iforce->bus) { | ||
356 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
357 | case IFORCE_USB: | ||
358 | iforce->dev.id.bustype = BUS_USB; | ||
359 | iforce->dev.dev = &iforce->usbdev->dev; | ||
360 | break; | ||
361 | #endif | ||
362 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
363 | case IFORCE_232: | ||
364 | iforce->dev.id.bustype = BUS_RS232; | ||
365 | iforce->dev.dev = &iforce->serio->dev; | ||
366 | break; | ||
367 | #endif | ||
368 | } | ||
369 | |||
370 | iforce->dev.private = iforce; | ||
371 | iforce->dev.name = "Unknown I-Force device"; | ||
372 | iforce->dev.open = iforce_open; | ||
373 | iforce->dev.close = iforce_release; | ||
374 | iforce->dev.flush = iforce_flush; | ||
375 | iforce->dev.event = iforce_input_event; | ||
376 | iforce->dev.upload_effect = iforce_upload_effect; | ||
377 | iforce->dev.erase_effect = iforce_erase_effect; | ||
378 | |||
379 | /* | ||
380 | * On-device memory allocation. | ||
381 | */ | ||
382 | |||
383 | iforce->device_memory.name = "I-Force device effect memory"; | ||
384 | iforce->device_memory.start = 0; | ||
385 | iforce->device_memory.end = 200; | ||
386 | iforce->device_memory.flags = IORESOURCE_MEM; | ||
387 | iforce->device_memory.parent = NULL; | ||
388 | iforce->device_memory.child = NULL; | ||
389 | iforce->device_memory.sibling = NULL; | ||
390 | |||
391 | /* | ||
392 | * Wait until device ready - until it sends its first response. | ||
393 | */ | ||
394 | |||
395 | for (i = 0; i < 20; i++) | ||
396 | if (!iforce_get_id_packet(iforce, "O")) | ||
397 | break; | ||
398 | |||
399 | if (i == 20) { /* 5 seconds */ | ||
400 | printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n"); | ||
401 | return -1; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Get device info. | ||
406 | */ | ||
407 | |||
408 | if (!iforce_get_id_packet(iforce, "M")) | ||
409 | iforce->dev.id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; | ||
410 | else | ||
411 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); | ||
412 | |||
413 | if (!iforce_get_id_packet(iforce, "P")) | ||
414 | iforce->dev.id.product = (iforce->edata[2] << 8) | iforce->edata[1]; | ||
415 | else | ||
416 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); | ||
417 | |||
418 | if (!iforce_get_id_packet(iforce, "B")) | ||
419 | iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; | ||
420 | else | ||
421 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); | ||
422 | |||
423 | if (!iforce_get_id_packet(iforce, "N")) | ||
424 | iforce->dev.ff_effects_max = iforce->edata[1]; | ||
425 | else | ||
426 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); | ||
427 | |||
428 | /* Check if the device can store more effects than the driver can really handle */ | ||
429 | if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { | ||
430 | printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", | ||
431 | iforce->dev.ff_effects_max, FF_EFFECTS_MAX); | ||
432 | iforce->dev.ff_effects_max = FF_EFFECTS_MAX; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * Display additional info. | ||
437 | */ | ||
438 | |||
439 | for (i = 0; c[i]; i++) | ||
440 | if (!iforce_get_id_packet(iforce, c + i)) | ||
441 | iforce_dump_packet("info", iforce->ecmd, iforce->edata); | ||
442 | |||
443 | /* | ||
444 | * Disable spring, enable force feedback. | ||
445 | * FIXME: We should use iforce_set_autocenter() et al here. | ||
446 | */ | ||
447 | |||
448 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); | ||
449 | |||
450 | /* | ||
451 | * Find appropriate device entry | ||
452 | */ | ||
453 | |||
454 | for (i = 0; iforce_device[i].idvendor; i++) | ||
455 | if (iforce_device[i].idvendor == iforce->dev.id.vendor && | ||
456 | iforce_device[i].idproduct == iforce->dev.id.product) | ||
457 | break; | ||
458 | |||
459 | iforce->type = iforce_device + i; | ||
460 | iforce->dev.name = iforce->type->name; | ||
461 | |||
462 | /* | ||
463 | * Set input device bitfields and ranges. | ||
464 | */ | ||
465 | |||
466 | iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); | ||
467 | |||
468 | for (i = 0; iforce->type->btn[i] >= 0; i++) { | ||
469 | signed short t = iforce->type->btn[i]; | ||
470 | set_bit(t, iforce->dev.keybit); | ||
471 | } | ||
472 | set_bit(BTN_DEAD, iforce->dev.keybit); | ||
473 | |||
474 | for (i = 0; iforce->type->abs[i] >= 0; i++) { | ||
475 | |||
476 | signed short t = iforce->type->abs[i]; | ||
477 | set_bit(t, iforce->dev.absbit); | ||
478 | |||
479 | switch (t) { | ||
480 | |||
481 | case ABS_X: | ||
482 | case ABS_Y: | ||
483 | case ABS_WHEEL: | ||
484 | |||
485 | iforce->dev.absmax[t] = 1920; | ||
486 | iforce->dev.absmin[t] = -1920; | ||
487 | iforce->dev.absflat[t] = 128; | ||
488 | iforce->dev.absfuzz[t] = 16; | ||
489 | |||
490 | set_bit(t, iforce->dev.ffbit); | ||
491 | break; | ||
492 | |||
493 | case ABS_THROTTLE: | ||
494 | case ABS_GAS: | ||
495 | case ABS_BRAKE: | ||
496 | |||
497 | iforce->dev.absmax[t] = 255; | ||
498 | iforce->dev.absmin[t] = 0; | ||
499 | break; | ||
500 | |||
501 | case ABS_RUDDER: | ||
502 | |||
503 | iforce->dev.absmax[t] = 127; | ||
504 | iforce->dev.absmin[t] = -128; | ||
505 | break; | ||
506 | |||
507 | case ABS_HAT0X: | ||
508 | case ABS_HAT0Y: | ||
509 | case ABS_HAT1X: | ||
510 | case ABS_HAT1Y: | ||
511 | iforce->dev.absmax[t] = 1; | ||
512 | iforce->dev.absmin[t] = -1; | ||
513 | break; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | for (i = 0; iforce->type->ff[i] >= 0; i++) | ||
518 | set_bit(iforce->type->ff[i], iforce->dev.ffbit); | ||
519 | |||
520 | /* | ||
521 | * Register input device. | ||
522 | */ | ||
523 | |||
524 | input_register_device(&iforce->dev); | ||
525 | |||
526 | printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open); | ||
527 | |||
528 | printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n", | ||
529 | iforce->dev.name, iforce->dev.ff_effects_max, | ||
530 | iforce->device_memory.end); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int __init iforce_init(void) | ||
536 | { | ||
537 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
538 | usb_register(&iforce_usb_driver); | ||
539 | #endif | ||
540 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
541 | serio_register_driver(&iforce_serio_drv); | ||
542 | #endif | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static void __exit iforce_exit(void) | ||
547 | { | ||
548 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
549 | usb_deregister(&iforce_usb_driver); | ||
550 | #endif | ||
551 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
552 | serio_unregister_driver(&iforce_serio_drv); | ||
553 | #endif | ||
554 | } | ||
555 | |||
556 | module_init(iforce_init); | ||
557 | module_exit(iforce_exit); | ||
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c new file mode 100644 index 000000000000..58728ebaaf80 --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-packets.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | * Should you need to contact me, the author, you can do so either by | ||
26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | static struct { | ||
33 | __s32 x; | ||
34 | __s32 y; | ||
35 | } iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | ||
36 | |||
37 | |||
38 | void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) | ||
39 | { | ||
40 | int i; | ||
41 | |||
42 | printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); | ||
43 | for (i = 0; i < LO(cmd); i++) | ||
44 | printk("%02x ", data[i]); | ||
45 | printk(")\n"); | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Send a packet of bytes to the device | ||
50 | */ | ||
51 | int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) | ||
52 | { | ||
53 | /* Copy data to buffer */ | ||
54 | int n = LO(cmd); | ||
55 | int c; | ||
56 | int empty; | ||
57 | int head, tail; | ||
58 | unsigned long flags; | ||
59 | |||
60 | /* | ||
61 | * Update head and tail of xmit buffer | ||
62 | */ | ||
63 | spin_lock_irqsave(&iforce->xmit_lock, flags); | ||
64 | |||
65 | head = iforce->xmit.head; | ||
66 | tail = iforce->xmit.tail; | ||
67 | |||
68 | if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { | ||
69 | printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); | ||
70 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | empty = head == tail; | ||
75 | XMIT_INC(iforce->xmit.head, n+2); | ||
76 | |||
77 | /* | ||
78 | * Store packet in xmit buffer | ||
79 | */ | ||
80 | iforce->xmit.buf[head] = HI(cmd); | ||
81 | XMIT_INC(head, 1); | ||
82 | iforce->xmit.buf[head] = LO(cmd); | ||
83 | XMIT_INC(head, 1); | ||
84 | |||
85 | c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); | ||
86 | if (n < c) c=n; | ||
87 | |||
88 | memcpy(&iforce->xmit.buf[head], | ||
89 | data, | ||
90 | c); | ||
91 | if (n != c) { | ||
92 | memcpy(&iforce->xmit.buf[0], | ||
93 | data + c, | ||
94 | n - c); | ||
95 | } | ||
96 | XMIT_INC(head, n); | ||
97 | |||
98 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
99 | /* | ||
100 | * If necessary, start the transmission | ||
101 | */ | ||
102 | switch (iforce->bus) { | ||
103 | |||
104 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
105 | case IFORCE_232: | ||
106 | if (empty) | ||
107 | iforce_serial_xmit(iforce); | ||
108 | break; | ||
109 | #endif | ||
110 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
111 | case IFORCE_USB: | ||
112 | |||
113 | if (iforce->usbdev && empty && | ||
114 | !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { | ||
115 | |||
116 | iforce_usb_xmit(iforce); | ||
117 | } | ||
118 | break; | ||
119 | #endif | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* Start or stop an effect */ | ||
125 | int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) | ||
126 | { | ||
127 | unsigned char data[3]; | ||
128 | |||
129 | printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); | ||
130 | |||
131 | data[0] = LO(id); | ||
132 | data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; | ||
133 | data[2] = LO(value); | ||
134 | return iforce_send_packet(iforce, FF_CMD_PLAY, data); | ||
135 | } | ||
136 | |||
137 | /* Mark an effect that was being updated as ready. That means it can be updated | ||
138 | * again */ | ||
139 | static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) | ||
140 | { | ||
141 | int i; | ||
142 | for (i=0; i<iforce->dev.ff_effects_max; ++i) { | ||
143 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | ||
144 | (iforce->core_effects[i].mod1_chunk.start == addr || | ||
145 | iforce->core_effects[i].mod2_chunk.start == addr)) { | ||
146 | clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags); | ||
147 | return 0; | ||
148 | } | ||
149 | } | ||
150 | printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); | ||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs) | ||
155 | { | ||
156 | struct input_dev *dev = &iforce->dev; | ||
157 | int i; | ||
158 | static int being_used = 0; | ||
159 | |||
160 | if (being_used) | ||
161 | printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); | ||
162 | being_used++; | ||
163 | |||
164 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
165 | if (HI(iforce->expect_packet) == HI(cmd)) { | ||
166 | iforce->expect_packet = 0; | ||
167 | iforce->ecmd = cmd; | ||
168 | memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); | ||
169 | wake_up(&iforce->wait); | ||
170 | } | ||
171 | #endif | ||
172 | |||
173 | if (!iforce->type) { | ||
174 | being_used--; | ||
175 | return; | ||
176 | } | ||
177 | |||
178 | switch (HI(cmd)) { | ||
179 | |||
180 | case 0x01: /* joystick position data */ | ||
181 | case 0x03: /* wheel position data */ | ||
182 | |||
183 | input_regs(dev, regs); | ||
184 | |||
185 | if (HI(cmd) == 1) { | ||
186 | input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); | ||
187 | input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); | ||
188 | input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); | ||
189 | if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) | ||
190 | input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); | ||
191 | } else { | ||
192 | input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); | ||
193 | input_report_abs(dev, ABS_GAS, 255 - data[2]); | ||
194 | input_report_abs(dev, ABS_BRAKE, 255 - data[3]); | ||
195 | } | ||
196 | |||
197 | input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); | ||
198 | input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); | ||
199 | |||
200 | for (i = 0; iforce->type->btn[i] >= 0; i++) | ||
201 | input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); | ||
202 | |||
203 | /* If there are untouched bits left, interpret them as the second hat */ | ||
204 | if (i <= 8) { | ||
205 | int btns = data[6]; | ||
206 | if (test_bit(ABS_HAT1X, dev->absbit)) { | ||
207 | if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1); | ||
208 | else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1); | ||
209 | else input_report_abs(dev, ABS_HAT1X, 0); | ||
210 | } | ||
211 | if (test_bit(ABS_HAT1Y, dev->absbit)) { | ||
212 | if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1); | ||
213 | else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1); | ||
214 | else input_report_abs(dev, ABS_HAT1Y, 0); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | input_sync(dev); | ||
219 | |||
220 | break; | ||
221 | |||
222 | case 0x02: /* status report */ | ||
223 | input_regs(dev, regs); | ||
224 | input_report_key(dev, BTN_DEAD, data[0] & 0x02); | ||
225 | input_sync(dev); | ||
226 | |||
227 | /* Check if an effect was just started or stopped */ | ||
228 | i = data[1] & 0x7f; | ||
229 | if (data[1] & 0x80) { | ||
230 | if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | ||
231 | /* Report play event */ | ||
232 | input_report_ff_status(dev, i, FF_STATUS_PLAYING); | ||
233 | } | ||
234 | } | ||
235 | else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | ||
236 | /* Report stop event */ | ||
237 | input_report_ff_status(dev, i, FF_STATUS_STOPPED); | ||
238 | } | ||
239 | if (LO(cmd) > 3) { | ||
240 | int j; | ||
241 | for (j=3; j<LO(cmd); j+=2) { | ||
242 | mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); | ||
243 | } | ||
244 | } | ||
245 | break; | ||
246 | } | ||
247 | being_used--; | ||
248 | } | ||
249 | |||
250 | int iforce_get_id_packet(struct iforce *iforce, char *packet) | ||
251 | { | ||
252 | DECLARE_WAITQUEUE(wait, current); | ||
253 | int timeout = HZ; /* 1 second */ | ||
254 | |||
255 | switch (iforce->bus) { | ||
256 | |||
257 | case IFORCE_USB: | ||
258 | |||
259 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
260 | iforce->cr.bRequest = packet[0]; | ||
261 | iforce->ctrl->dev = iforce->usbdev; | ||
262 | |||
263 | set_current_state(TASK_INTERRUPTIBLE); | ||
264 | add_wait_queue(&iforce->wait, &wait); | ||
265 | |||
266 | if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) { | ||
267 | set_current_state(TASK_RUNNING); | ||
268 | remove_wait_queue(&iforce->wait, &wait); | ||
269 | return -1; | ||
270 | } | ||
271 | |||
272 | while (timeout && iforce->ctrl->status == -EINPROGRESS) | ||
273 | timeout = schedule_timeout(timeout); | ||
274 | |||
275 | set_current_state(TASK_RUNNING); | ||
276 | remove_wait_queue(&iforce->wait, &wait); | ||
277 | |||
278 | if (!timeout) { | ||
279 | usb_unlink_urb(iforce->ctrl); | ||
280 | return -1; | ||
281 | } | ||
282 | #else | ||
283 | printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n"); | ||
284 | #endif | ||
285 | break; | ||
286 | |||
287 | case IFORCE_232: | ||
288 | |||
289 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
290 | iforce->expect_packet = FF_CMD_QUERY; | ||
291 | iforce_send_packet(iforce, FF_CMD_QUERY, packet); | ||
292 | |||
293 | set_current_state(TASK_INTERRUPTIBLE); | ||
294 | add_wait_queue(&iforce->wait, &wait); | ||
295 | |||
296 | while (timeout && iforce->expect_packet) | ||
297 | timeout = schedule_timeout(timeout); | ||
298 | |||
299 | set_current_state(TASK_RUNNING); | ||
300 | remove_wait_queue(&iforce->wait, &wait); | ||
301 | |||
302 | if (!timeout) { | ||
303 | iforce->expect_packet = 0; | ||
304 | return -1; | ||
305 | } | ||
306 | #else | ||
307 | printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n"); | ||
308 | #endif | ||
309 | break; | ||
310 | |||
311 | default: | ||
312 | printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n", | ||
313 | iforce->bus); | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | return -(iforce->edata[0] != packet[0]); | ||
318 | } | ||
319 | |||
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c new file mode 100644 index 000000000000..11f51905cba7 --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-serio.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | * Should you need to contact me, the author, you can do so either by | ||
26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | void iforce_serial_xmit(struct iforce *iforce) | ||
33 | { | ||
34 | unsigned char cs; | ||
35 | int i; | ||
36 | unsigned long flags; | ||
37 | |||
38 | if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { | ||
39 | set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | spin_lock_irqsave(&iforce->xmit_lock, flags); | ||
44 | |||
45 | again: | ||
46 | if (iforce->xmit.head == iforce->xmit.tail) { | ||
47 | clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | ||
48 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
49 | return; | ||
50 | } | ||
51 | |||
52 | cs = 0x2b; | ||
53 | |||
54 | serio_write(iforce->serio, 0x2b); | ||
55 | |||
56 | serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); | ||
57 | cs ^= iforce->xmit.buf[iforce->xmit.tail]; | ||
58 | XMIT_INC(iforce->xmit.tail, 1); | ||
59 | |||
60 | for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { | ||
61 | serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); | ||
62 | cs ^= iforce->xmit.buf[iforce->xmit.tail]; | ||
63 | XMIT_INC(iforce->xmit.tail, 1); | ||
64 | } | ||
65 | |||
66 | serio_write(iforce->serio, cs); | ||
67 | |||
68 | if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) | ||
69 | goto again; | ||
70 | |||
71 | clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | ||
72 | |||
73 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
74 | } | ||
75 | |||
76 | static void iforce_serio_write_wakeup(struct serio *serio) | ||
77 | { | ||
78 | struct iforce *iforce = serio_get_drvdata(serio); | ||
79 | |||
80 | iforce_serial_xmit(iforce); | ||
81 | } | ||
82 | |||
83 | static irqreturn_t iforce_serio_irq(struct serio *serio, | ||
84 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
85 | { | ||
86 | struct iforce *iforce = serio_get_drvdata(serio); | ||
87 | |||
88 | if (!iforce->pkt) { | ||
89 | if (data == 0x2b) | ||
90 | iforce->pkt = 1; | ||
91 | goto out; | ||
92 | } | ||
93 | |||
94 | if (!iforce->id) { | ||
95 | if (data > 3 && data != 0xff) | ||
96 | iforce->pkt = 0; | ||
97 | else | ||
98 | iforce->id = data; | ||
99 | goto out; | ||
100 | } | ||
101 | |||
102 | if (!iforce->len) { | ||
103 | if (data > IFORCE_MAX_LENGTH) { | ||
104 | iforce->pkt = 0; | ||
105 | iforce->id = 0; | ||
106 | } else { | ||
107 | iforce->len = data; | ||
108 | } | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | if (iforce->idx < iforce->len) { | ||
113 | iforce->csum += iforce->data[iforce->idx++] = data; | ||
114 | goto out; | ||
115 | } | ||
116 | |||
117 | if (iforce->idx == iforce->len) { | ||
118 | iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data, regs); | ||
119 | iforce->pkt = 0; | ||
120 | iforce->id = 0; | ||
121 | iforce->len = 0; | ||
122 | iforce->idx = 0; | ||
123 | iforce->csum = 0; | ||
124 | } | ||
125 | out: | ||
126 | return IRQ_HANDLED; | ||
127 | } | ||
128 | |||
129 | static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) | ||
130 | { | ||
131 | struct iforce *iforce; | ||
132 | int err; | ||
133 | |||
134 | if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) | ||
135 | return -ENOMEM; | ||
136 | |||
137 | memset(iforce, 0, sizeof(struct iforce)); | ||
138 | |||
139 | iforce->bus = IFORCE_232; | ||
140 | iforce->serio = serio; | ||
141 | |||
142 | serio_set_drvdata(serio, iforce); | ||
143 | |||
144 | err = serio_open(serio, drv); | ||
145 | if (err) { | ||
146 | serio_set_drvdata(serio, NULL); | ||
147 | kfree(iforce); | ||
148 | return err; | ||
149 | } | ||
150 | |||
151 | if (iforce_init_device(iforce)) { | ||
152 | serio_close(serio); | ||
153 | serio_set_drvdata(serio, NULL); | ||
154 | kfree(iforce); | ||
155 | return -ENODEV; | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void iforce_serio_disconnect(struct serio *serio) | ||
162 | { | ||
163 | struct iforce *iforce = serio_get_drvdata(serio); | ||
164 | |||
165 | input_unregister_device(&iforce->dev); | ||
166 | serio_close(serio); | ||
167 | serio_set_drvdata(serio, NULL); | ||
168 | kfree(iforce); | ||
169 | } | ||
170 | |||
171 | static struct serio_device_id iforce_serio_ids[] = { | ||
172 | { | ||
173 | .type = SERIO_RS232, | ||
174 | .proto = SERIO_IFORCE, | ||
175 | .id = SERIO_ANY, | ||
176 | .extra = SERIO_ANY, | ||
177 | }, | ||
178 | { 0 } | ||
179 | }; | ||
180 | |||
181 | MODULE_DEVICE_TABLE(serio, iforce_serio_ids); | ||
182 | |||
183 | struct serio_driver iforce_serio_drv = { | ||
184 | .driver = { | ||
185 | .name = "iforce", | ||
186 | }, | ||
187 | .description = "RS232 I-Force joysticks and wheels driver", | ||
188 | .id_table = iforce_serio_ids, | ||
189 | .write_wakeup = iforce_serio_write_wakeup, | ||
190 | .interrupt = iforce_serio_irq, | ||
191 | .connect = iforce_serio_connect, | ||
192 | .disconnect = iforce_serio_disconnect, | ||
193 | }; | ||
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c new file mode 100644 index 000000000000..617c0b0e5a39 --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-usb.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | * Should you need to contact me, the author, you can do so either by | ||
26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | void iforce_usb_xmit(struct iforce *iforce) | ||
33 | { | ||
34 | int n, c; | ||
35 | unsigned long flags; | ||
36 | |||
37 | spin_lock_irqsave(&iforce->xmit_lock, flags); | ||
38 | |||
39 | if (iforce->xmit.head == iforce->xmit.tail) { | ||
40 | clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | ||
41 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; | ||
46 | XMIT_INC(iforce->xmit.tail, 1); | ||
47 | n = iforce->xmit.buf[iforce->xmit.tail]; | ||
48 | XMIT_INC(iforce->xmit.tail, 1); | ||
49 | |||
50 | iforce->out->transfer_buffer_length = n + 1; | ||
51 | iforce->out->dev = iforce->usbdev; | ||
52 | |||
53 | /* Copy rest of data then */ | ||
54 | c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); | ||
55 | if (n < c) c=n; | ||
56 | |||
57 | memcpy(iforce->out->transfer_buffer + 1, | ||
58 | &iforce->xmit.buf[iforce->xmit.tail], | ||
59 | c); | ||
60 | if (n != c) { | ||
61 | memcpy(iforce->out->transfer_buffer + 1 + c, | ||
62 | &iforce->xmit.buf[0], | ||
63 | n-c); | ||
64 | } | ||
65 | XMIT_INC(iforce->xmit.tail, n); | ||
66 | |||
67 | if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) { | ||
68 | printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); | ||
69 | } | ||
70 | |||
71 | /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. | ||
72 | * As long as the urb completion handler is not called, the transmiting | ||
73 | * is considered to be running */ | ||
74 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
75 | } | ||
76 | |||
77 | static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs) | ||
78 | { | ||
79 | struct iforce *iforce = urb->context; | ||
80 | int status; | ||
81 | |||
82 | switch (urb->status) { | ||
83 | case 0: | ||
84 | /* success */ | ||
85 | break; | ||
86 | case -ECONNRESET: | ||
87 | case -ENOENT: | ||
88 | case -ESHUTDOWN: | ||
89 | /* this urb is terminated, clean up */ | ||
90 | dbg("%s - urb shutting down with status: %d", | ||
91 | __FUNCTION__, urb->status); | ||
92 | return; | ||
93 | default: | ||
94 | dbg("%s - urb has status of: %d", __FUNCTION__, urb->status); | ||
95 | goto exit; | ||
96 | } | ||
97 | |||
98 | iforce_process_packet(iforce, | ||
99 | (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs); | ||
100 | |||
101 | exit: | ||
102 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
103 | if (status) | ||
104 | err ("%s - usb_submit_urb failed with result %d", | ||
105 | __FUNCTION__, status); | ||
106 | } | ||
107 | |||
108 | static void iforce_usb_out(struct urb *urb, struct pt_regs *regs) | ||
109 | { | ||
110 | struct iforce *iforce = urb->context; | ||
111 | |||
112 | if (urb->status) { | ||
113 | printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | iforce_usb_xmit(iforce); | ||
118 | |||
119 | wake_up(&iforce->wait); | ||
120 | } | ||
121 | |||
122 | static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs) | ||
123 | { | ||
124 | struct iforce *iforce = urb->context; | ||
125 | if (urb->status) return; | ||
126 | iforce->ecmd = 0xff00 | urb->actual_length; | ||
127 | wake_up(&iforce->wait); | ||
128 | } | ||
129 | |||
130 | static int iforce_usb_probe(struct usb_interface *intf, | ||
131 | const struct usb_device_id *id) | ||
132 | { | ||
133 | struct usb_device *dev = interface_to_usbdev(intf); | ||
134 | struct usb_host_interface *interface; | ||
135 | struct usb_endpoint_descriptor *epirq, *epout; | ||
136 | struct iforce *iforce; | ||
137 | |||
138 | interface = intf->cur_altsetting; | ||
139 | |||
140 | epirq = &interface->endpoint[0].desc; | ||
141 | epout = &interface->endpoint[1].desc; | ||
142 | |||
143 | if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) | ||
144 | goto fail; | ||
145 | |||
146 | memset(iforce, 0, sizeof(struct iforce)); | ||
147 | |||
148 | if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) { | ||
149 | goto fail; | ||
150 | } | ||
151 | |||
152 | if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) { | ||
153 | goto fail; | ||
154 | } | ||
155 | |||
156 | if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) { | ||
157 | goto fail; | ||
158 | } | ||
159 | |||
160 | iforce->bus = IFORCE_USB; | ||
161 | iforce->usbdev = dev; | ||
162 | |||
163 | iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; | ||
164 | iforce->cr.wIndex = 0; | ||
165 | iforce->cr.wLength = 16; | ||
166 | |||
167 | usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), | ||
168 | iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); | ||
169 | |||
170 | usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), | ||
171 | iforce + 1, 32, iforce_usb_out, iforce); | ||
172 | |||
173 | usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), | ||
174 | (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); | ||
175 | |||
176 | if (iforce_init_device(iforce)) goto fail; | ||
177 | |||
178 | usb_set_intfdata(intf, iforce); | ||
179 | return 0; | ||
180 | |||
181 | fail: | ||
182 | if (iforce) { | ||
183 | if (iforce->irq) usb_free_urb(iforce->irq); | ||
184 | if (iforce->out) usb_free_urb(iforce->out); | ||
185 | if (iforce->ctrl) usb_free_urb(iforce->ctrl); | ||
186 | kfree(iforce); | ||
187 | } | ||
188 | |||
189 | return -ENODEV; | ||
190 | } | ||
191 | |||
192 | /* Called by iforce_delete() */ | ||
193 | void iforce_usb_delete(struct iforce* iforce) | ||
194 | { | ||
195 | usb_unlink_urb(iforce->irq); | ||
196 | /* Is it ok to unlink those ? */ | ||
197 | usb_unlink_urb(iforce->out); | ||
198 | usb_unlink_urb(iforce->ctrl); | ||
199 | |||
200 | usb_free_urb(iforce->irq); | ||
201 | usb_free_urb(iforce->out); | ||
202 | usb_free_urb(iforce->ctrl); | ||
203 | } | ||
204 | |||
205 | static void iforce_usb_disconnect(struct usb_interface *intf) | ||
206 | { | ||
207 | struct iforce *iforce = usb_get_intfdata(intf); | ||
208 | int open = 0; /* FIXME! iforce->dev.handle->open; */ | ||
209 | |||
210 | usb_set_intfdata(intf, NULL); | ||
211 | if (iforce) { | ||
212 | iforce->usbdev = NULL; | ||
213 | input_unregister_device(&iforce->dev); | ||
214 | |||
215 | if (!open) { | ||
216 | iforce_delete_device(iforce); | ||
217 | kfree(iforce); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static struct usb_device_id iforce_usb_ids [] = { | ||
223 | { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */ | ||
224 | { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ | ||
225 | { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ | ||
226 | { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ | ||
227 | { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ | ||
228 | { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ | ||
229 | { USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */ | ||
230 | { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ | ||
231 | { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ | ||
232 | { } /* Terminating entry */ | ||
233 | }; | ||
234 | |||
235 | MODULE_DEVICE_TABLE (usb, iforce_usb_ids); | ||
236 | |||
237 | struct usb_driver iforce_usb_driver = { | ||
238 | .owner = THIS_MODULE, | ||
239 | .name = "iforce", | ||
240 | .probe = iforce_usb_probe, | ||
241 | .disconnect = iforce_usb_disconnect, | ||
242 | .id_table = iforce_usb_ids, | ||
243 | }; | ||
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h new file mode 100644 index 000000000000..bce247bc300b --- /dev/null +++ b/drivers/input/joystick/iforce/iforce.h | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | * Should you need to contact me, the author, you can do so either by | ||
26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/input.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/usb.h> | ||
37 | #include <linux/serio.h> | ||
38 | #include <linux/config.h> | ||
39 | #include <linux/circ_buf.h> | ||
40 | #include <asm/semaphore.h> | ||
41 | |||
42 | /* This module provides arbitrary resource management routines. | ||
43 | * I use it to manage the device's memory. | ||
44 | * Despite the name of this module, I am *not* going to access the ioports. | ||
45 | */ | ||
46 | #include <linux/ioport.h> | ||
47 | |||
48 | #define IFORCE_MAX_LENGTH 16 | ||
49 | |||
50 | /* iforce::bus */ | ||
51 | #define IFORCE_232 1 | ||
52 | #define IFORCE_USB 2 | ||
53 | |||
54 | #define FALSE 0 | ||
55 | #define TRUE 1 | ||
56 | |||
57 | #define FF_EFFECTS_MAX 32 | ||
58 | |||
59 | /* Each force feedback effect is made of one core effect, which can be | ||
60 | * associated to at most to effect modifiers | ||
61 | */ | ||
62 | #define FF_MOD1_IS_USED 0 | ||
63 | #define FF_MOD2_IS_USED 1 | ||
64 | #define FF_CORE_IS_USED 2 | ||
65 | #define FF_CORE_IS_PLAYED 3 /* Effect is currently being played */ | ||
66 | #define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ | ||
67 | #define FF_CORE_UPDATE 5 /* Effect is being updated */ | ||
68 | #define FF_MODCORE_MAX 5 | ||
69 | |||
70 | #define CHECK_OWNERSHIP(i, iforce) \ | ||
71 | ((i) < FF_EFFECTS_MAX && i >= 0 && \ | ||
72 | test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ | ||
73 | (current->pid == 0 || \ | ||
74 | (iforce)->core_effects[(i)].owner == current->pid)) | ||
75 | |||
76 | struct iforce_core_effect { | ||
77 | /* Information about where modifiers are stored in the device's memory */ | ||
78 | struct resource mod1_chunk; | ||
79 | struct resource mod2_chunk; | ||
80 | unsigned long flags[NBITS(FF_MODCORE_MAX)]; | ||
81 | pid_t owner; | ||
82 | /* Used to keep track of parameters of an effect. They are needed | ||
83 | * to know what parts of an effect changed in an update operation. | ||
84 | * We try to send only parameter packets if possible, as sending | ||
85 | * effect parameter requires the effect to be stoped and restarted | ||
86 | */ | ||
87 | struct ff_effect effect; | ||
88 | }; | ||
89 | |||
90 | #define FF_CMD_EFFECT 0x010e | ||
91 | #define FF_CMD_ENVELOPE 0x0208 | ||
92 | #define FF_CMD_MAGNITUDE 0x0303 | ||
93 | #define FF_CMD_PERIOD 0x0407 | ||
94 | #define FF_CMD_CONDITION 0x050a | ||
95 | |||
96 | #define FF_CMD_AUTOCENTER 0x4002 | ||
97 | #define FF_CMD_PLAY 0x4103 | ||
98 | #define FF_CMD_ENABLE 0x4201 | ||
99 | #define FF_CMD_GAIN 0x4301 | ||
100 | |||
101 | #define FF_CMD_QUERY 0xff01 | ||
102 | |||
103 | /* Buffer for async write */ | ||
104 | #define XMIT_SIZE 256 | ||
105 | #define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 | ||
106 | /* iforce::xmit_flags */ | ||
107 | #define IFORCE_XMIT_RUNNING 0 | ||
108 | #define IFORCE_XMIT_AGAIN 1 | ||
109 | |||
110 | struct iforce_device { | ||
111 | u16 idvendor; | ||
112 | u16 idproduct; | ||
113 | char *name; | ||
114 | signed short *btn; | ||
115 | signed short *abs; | ||
116 | signed short *ff; | ||
117 | }; | ||
118 | |||
119 | struct iforce { | ||
120 | struct input_dev dev; /* Input device interface */ | ||
121 | struct iforce_device *type; | ||
122 | int bus; | ||
123 | |||
124 | unsigned char data[IFORCE_MAX_LENGTH]; | ||
125 | unsigned char edata[IFORCE_MAX_LENGTH]; | ||
126 | u16 ecmd; | ||
127 | u16 expect_packet; | ||
128 | |||
129 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
130 | struct serio *serio; /* RS232 transfer */ | ||
131 | int idx, pkt, len, id; | ||
132 | unsigned char csum; | ||
133 | #endif | ||
134 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
135 | struct usb_device *usbdev; /* USB transfer */ | ||
136 | struct urb *irq, *out, *ctrl; | ||
137 | struct usb_ctrlrequest cr; | ||
138 | #endif | ||
139 | spinlock_t xmit_lock; | ||
140 | /* Buffer used for asynchronous sending of bytes to the device */ | ||
141 | struct circ_buf xmit; | ||
142 | unsigned char xmit_data[XMIT_SIZE]; | ||
143 | long xmit_flags[1]; | ||
144 | |||
145 | /* Force Feedback */ | ||
146 | wait_queue_head_t wait; | ||
147 | struct resource device_memory; | ||
148 | struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; | ||
149 | struct semaphore mem_mutex; | ||
150 | }; | ||
151 | |||
152 | /* Get hi and low bytes of a 16-bits int */ | ||
153 | #define HI(a) ((unsigned char)((a) >> 8)) | ||
154 | #define LO(a) ((unsigned char)((a) & 0xff)) | ||
155 | |||
156 | /* For many parameters, it seems that 0x80 is a special value that should | ||
157 | * be avoided. Instead, we replace this value by 0x7f | ||
158 | */ | ||
159 | #define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) | ||
160 | |||
161 | /* Encode a time value */ | ||
162 | #define TIME_SCALE(a) (a) | ||
163 | |||
164 | |||
165 | /* Public functions */ | ||
166 | /* iforce-serio.c */ | ||
167 | void iforce_serial_xmit(struct iforce *iforce); | ||
168 | |||
169 | /* iforce-usb.c */ | ||
170 | void iforce_usb_xmit(struct iforce *iforce); | ||
171 | void iforce_usb_delete(struct iforce *iforce); | ||
172 | |||
173 | /* iforce-main.c */ | ||
174 | int iforce_init_device(struct iforce *iforce); | ||
175 | void iforce_delete_device(struct iforce *iforce); | ||
176 | |||
177 | /* iforce-packets.c */ | ||
178 | int iforce_control_playback(struct iforce*, u16 id, unsigned int); | ||
179 | void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs); | ||
180 | int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); | ||
181 | void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; | ||
182 | int iforce_get_id_packet(struct iforce *iforce, char *packet); | ||
183 | |||
184 | /* iforce-ff.c */ | ||
185 | int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); | ||
186 | int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); | ||
187 | int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); | ||
188 | |||
189 | /* Public variables */ | ||
190 | extern struct serio_driver iforce_serio_drv; | ||
191 | extern struct usb_driver iforce_usb_driver; | ||
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c new file mode 100644 index 000000000000..9d3f8c38cb09 --- /dev/null +++ b/drivers/input/joystick/interact.c | |||
@@ -0,0 +1,322 @@ | |||
1 | /* | ||
2 | * $Id: interact.c,v 1.16 2002/01/22 20:28:25 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Toby Deshane | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * InterAct digital gamepad/joystick driver for Linux | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/gameport.h> | ||
40 | #include <linux/input.h> | ||
41 | |||
42 | #define DRIVER_DESC "InterAct digital joystick driver" | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
45 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | #define INTERACT_MAX_START 600 /* 400 us */ | ||
49 | #define INTERACT_MAX_STROBE 60 /* 40 us */ | ||
50 | #define INTERACT_MAX_LENGTH 32 /* 32 bits */ | ||
51 | |||
52 | #define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */ | ||
53 | #define INTERACT_TYPE_PP8D 1 /* ProPad 8 */ | ||
54 | |||
55 | struct interact { | ||
56 | struct gameport *gameport; | ||
57 | struct input_dev dev; | ||
58 | int bads; | ||
59 | int reads; | ||
60 | unsigned char type; | ||
61 | unsigned char length; | ||
62 | char phys[32]; | ||
63 | }; | ||
64 | |||
65 | static short interact_abs_hhfx[] = | ||
66 | { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 }; | ||
67 | static short interact_abs_pp8d[] = | ||
68 | { ABS_X, ABS_Y, -1 }; | ||
69 | |||
70 | static short interact_btn_hhfx[] = | ||
71 | { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 }; | ||
72 | static short interact_btn_pp8d[] = | ||
73 | { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 }; | ||
74 | |||
75 | struct interact_type { | ||
76 | int id; | ||
77 | short *abs; | ||
78 | short *btn; | ||
79 | char *name; | ||
80 | unsigned char length; | ||
81 | unsigned char b8; | ||
82 | }; | ||
83 | |||
84 | static struct interact_type interact_type[] = { | ||
85 | { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 }, | ||
86 | { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 }, | ||
87 | { 0 }}; | ||
88 | |||
89 | /* | ||
90 | * interact_read_packet() reads and InterAct joystick data. | ||
91 | */ | ||
92 | |||
93 | static int interact_read_packet(struct gameport *gameport, int length, u32 *data) | ||
94 | { | ||
95 | unsigned long flags; | ||
96 | unsigned char u, v; | ||
97 | unsigned int t, s; | ||
98 | int i; | ||
99 | |||
100 | i = 0; | ||
101 | data[0] = data[1] = data[2] = 0; | ||
102 | t = gameport_time(gameport, INTERACT_MAX_START); | ||
103 | s = gameport_time(gameport, INTERACT_MAX_STROBE); | ||
104 | |||
105 | local_irq_save(flags); | ||
106 | gameport_trigger(gameport); | ||
107 | v = gameport_read(gameport); | ||
108 | |||
109 | while (t > 0 && i < length) { | ||
110 | t--; | ||
111 | u = v; v = gameport_read(gameport); | ||
112 | if (v & ~u & 0x40) { | ||
113 | data[0] = (data[0] << 1) | ((v >> 4) & 1); | ||
114 | data[1] = (data[1] << 1) | ((v >> 5) & 1); | ||
115 | data[2] = (data[2] << 1) | ((v >> 7) & 1); | ||
116 | i++; | ||
117 | t = s; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | local_irq_restore(flags); | ||
122 | |||
123 | return i; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * interact_poll() reads and analyzes InterAct joystick data. | ||
128 | */ | ||
129 | |||
130 | static void interact_poll(struct gameport *gameport) | ||
131 | { | ||
132 | struct interact *interact = gameport_get_drvdata(gameport); | ||
133 | struct input_dev *dev = &interact->dev; | ||
134 | u32 data[3]; | ||
135 | int i; | ||
136 | |||
137 | interact->reads++; | ||
138 | |||
139 | if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) { | ||
140 | interact->bads++; | ||
141 | } else { | ||
142 | |||
143 | for (i = 0; i < 3; i++) | ||
144 | data[i] <<= INTERACT_MAX_LENGTH - interact->length; | ||
145 | |||
146 | switch (interact->type) { | ||
147 | |||
148 | case INTERACT_TYPE_HHFX: | ||
149 | |||
150 | for (i = 0; i < 4; i++) | ||
151 | input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); | ||
152 | |||
153 | for (i = 0; i < 2; i++) | ||
154 | input_report_abs(dev, ABS_HAT0Y - i, | ||
155 | ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); | ||
156 | |||
157 | for (i = 0; i < 8; i++) | ||
158 | input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); | ||
159 | |||
160 | for (i = 0; i < 4; i++) | ||
161 | input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); | ||
162 | |||
163 | break; | ||
164 | |||
165 | case INTERACT_TYPE_PP8D: | ||
166 | |||
167 | for (i = 0; i < 2; i++) | ||
168 | input_report_abs(dev, interact_abs_pp8d[i], | ||
169 | ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); | ||
170 | |||
171 | for (i = 0; i < 8; i++) | ||
172 | input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); | ||
173 | |||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | input_sync(dev); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * interact_open() is a callback from the input open routine. | ||
183 | */ | ||
184 | |||
185 | static int interact_open(struct input_dev *dev) | ||
186 | { | ||
187 | struct interact *interact = dev->private; | ||
188 | |||
189 | gameport_start_polling(interact->gameport); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * interact_close() is a callback from the input close routine. | ||
195 | */ | ||
196 | |||
197 | static void interact_close(struct input_dev *dev) | ||
198 | { | ||
199 | struct interact *interact = dev->private; | ||
200 | |||
201 | gameport_stop_polling(interact->gameport); | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * interact_connect() probes for InterAct joysticks. | ||
206 | */ | ||
207 | |||
208 | static int interact_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
209 | { | ||
210 | struct interact *interact; | ||
211 | __u32 data[3]; | ||
212 | int i, t; | ||
213 | int err; | ||
214 | |||
215 | if (!(interact = kcalloc(1, sizeof(struct interact), GFP_KERNEL))) | ||
216 | return -ENOMEM; | ||
217 | |||
218 | interact->gameport = gameport; | ||
219 | |||
220 | gameport_set_drvdata(gameport, interact); | ||
221 | |||
222 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
223 | if (err) | ||
224 | goto fail1; | ||
225 | |||
226 | i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data); | ||
227 | |||
228 | if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) { | ||
229 | err = -ENODEV; | ||
230 | goto fail2; | ||
231 | } | ||
232 | |||
233 | for (i = 0; interact_type[i].length; i++) | ||
234 | if (interact_type[i].id == (data[2] >> 16)) | ||
235 | break; | ||
236 | |||
237 | if (!interact_type[i].length) { | ||
238 | printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n", | ||
239 | gameport->phys, i, data[0], data[1], data[2]); | ||
240 | err = -ENODEV; | ||
241 | goto fail2; | ||
242 | } | ||
243 | |||
244 | gameport_set_poll_handler(gameport, interact_poll); | ||
245 | gameport_set_poll_interval(gameport, 20); | ||
246 | |||
247 | sprintf(interact->phys, "%s/input0", gameport->phys); | ||
248 | |||
249 | interact->type = i; | ||
250 | interact->length = interact_type[i].length; | ||
251 | |||
252 | interact->dev.private = interact; | ||
253 | interact->dev.open = interact_open; | ||
254 | interact->dev.close = interact_close; | ||
255 | |||
256 | interact->dev.name = interact_type[i].name; | ||
257 | interact->dev.phys = interact->phys; | ||
258 | interact->dev.id.bustype = BUS_GAMEPORT; | ||
259 | interact->dev.id.vendor = GAMEPORT_ID_VENDOR_INTERACT; | ||
260 | interact->dev.id.product = interact_type[i].id; | ||
261 | interact->dev.id.version = 0x0100; | ||
262 | |||
263 | interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
264 | |||
265 | for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { | ||
266 | set_bit(t, interact->dev.absbit); | ||
267 | if (i < interact_type[interact->type].b8) { | ||
268 | interact->dev.absmin[t] = 0; | ||
269 | interact->dev.absmax[t] = 255; | ||
270 | } else { | ||
271 | interact->dev.absmin[t] = -1; | ||
272 | interact->dev.absmax[t] = 1; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++) | ||
277 | set_bit(t, interact->dev.keybit); | ||
278 | |||
279 | input_register_device(&interact->dev); | ||
280 | printk(KERN_INFO "input: %s on %s\n", | ||
281 | interact_type[interact->type].name, gameport->phys); | ||
282 | |||
283 | return 0; | ||
284 | |||
285 | fail2: gameport_close(gameport); | ||
286 | fail1: gameport_set_drvdata(gameport, NULL); | ||
287 | kfree(interact); | ||
288 | return err; | ||
289 | } | ||
290 | |||
291 | static void interact_disconnect(struct gameport *gameport) | ||
292 | { | ||
293 | struct interact *interact = gameport_get_drvdata(gameport); | ||
294 | |||
295 | input_unregister_device(&interact->dev); | ||
296 | gameport_close(gameport); | ||
297 | gameport_set_drvdata(gameport, NULL); | ||
298 | kfree(interact); | ||
299 | } | ||
300 | |||
301 | static struct gameport_driver interact_drv = { | ||
302 | .driver = { | ||
303 | .name = "interact", | ||
304 | }, | ||
305 | .description = DRIVER_DESC, | ||
306 | .connect = interact_connect, | ||
307 | .disconnect = interact_disconnect, | ||
308 | }; | ||
309 | |||
310 | static int __init interact_init(void) | ||
311 | { | ||
312 | gameport_register_driver(&interact_drv); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static void __exit interact_exit(void) | ||
317 | { | ||
318 | gameport_unregister_driver(&interact_drv); | ||
319 | } | ||
320 | |||
321 | module_init(interact_init); | ||
322 | module_exit(interact_exit); | ||
diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c new file mode 100644 index 000000000000..4234ccaf9146 --- /dev/null +++ b/drivers/input/joystick/joydump.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * $Id: joydump.c,v 1.1 2002/01/23 06:56:16 jsimmons Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1996-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This is just a very simple driver that can dump the data | ||
9 | * out of the joystick port into the syslog ... | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * Should you need to contact me, the author, you can do so either by | ||
28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
30 | */ | ||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/gameport.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/init.h> | ||
37 | |||
38 | #define DRIVER_DESC "Gameport data dumper module" | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | #define BUF_SIZE 256 | ||
45 | |||
46 | struct joydump { | ||
47 | unsigned int time; | ||
48 | unsigned char data; | ||
49 | }; | ||
50 | |||
51 | static int joydump_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
52 | { | ||
53 | struct joydump *buf; /* all entries */ | ||
54 | struct joydump *dump, *prev; /* one entry each */ | ||
55 | int axes[4], buttons; | ||
56 | int i, j, t, timeout; | ||
57 | unsigned long flags; | ||
58 | unsigned char u; | ||
59 | |||
60 | printk(KERN_INFO "joydump: ,------------------ START ----------------.\n"); | ||
61 | printk(KERN_INFO "joydump: | Dumping: %30s |\n", gameport->phys); | ||
62 | printk(KERN_INFO "joydump: | Speed: %28d kHz |\n", gameport->speed); | ||
63 | |||
64 | if (gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) { | ||
65 | |||
66 | printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n"); | ||
67 | |||
68 | if (gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) { | ||
69 | |||
70 | printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n"); | ||
71 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); | ||
72 | return -ENODEV; | ||
73 | } | ||
74 | |||
75 | gameport_cooked_read(gameport, axes, &buttons); | ||
76 | |||
77 | for (i = 0; i < 4; i++) | ||
78 | printk(KERN_INFO "joydump: | Axis %d: %4d. |\n", i, axes[i]); | ||
79 | printk(KERN_INFO "joydump: | Buttons %02x. |\n", buttons); | ||
80 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); | ||
81 | } | ||
82 | |||
83 | timeout = gameport_time(gameport, 10000); /* 10 ms */ | ||
84 | |||
85 | buf = kmalloc(BUF_SIZE * sizeof(struct joydump), GFP_KERNEL); | ||
86 | if (!buf) { | ||
87 | printk(KERN_INFO "joydump: no memory for testing\n"); | ||
88 | goto jd_end; | ||
89 | } | ||
90 | dump = buf; | ||
91 | t = 0; | ||
92 | i = 1; | ||
93 | |||
94 | local_irq_save(flags); | ||
95 | |||
96 | u = gameport_read(gameport); | ||
97 | |||
98 | dump->data = u; | ||
99 | dump->time = t; | ||
100 | dump++; | ||
101 | |||
102 | gameport_trigger(gameport); | ||
103 | |||
104 | while (i < BUF_SIZE && t < timeout) { | ||
105 | |||
106 | dump->data = gameport_read(gameport); | ||
107 | |||
108 | if (dump->data ^ u) { | ||
109 | u = dump->data; | ||
110 | dump->time = t; | ||
111 | i++; | ||
112 | dump++; | ||
113 | } | ||
114 | t++; | ||
115 | } | ||
116 | |||
117 | local_irq_restore(flags); | ||
118 | |||
119 | /* | ||
120 | * Dump data. | ||
121 | */ | ||
122 | |||
123 | t = i; | ||
124 | dump = buf; | ||
125 | prev = dump; | ||
126 | |||
127 | printk(KERN_INFO "joydump: >------------------ DATA -----------------<\n"); | ||
128 | printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", 0, 0); | ||
129 | for (j = 7; j >= 0; j--) | ||
130 | printk("%d", (dump->data >> j) & 1); | ||
131 | printk(" |\n"); | ||
132 | dump++; | ||
133 | |||
134 | for (i = 1; i < t; i++, dump++, prev++) { | ||
135 | printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", | ||
136 | i, dump->time - prev->time); | ||
137 | for (j = 7; j >= 0; j--) | ||
138 | printk("%d", (dump->data >> j) & 1); | ||
139 | printk(" |\n"); | ||
140 | } | ||
141 | kfree(buf); | ||
142 | |||
143 | jd_end: | ||
144 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static void joydump_disconnect(struct gameport *gameport) | ||
150 | { | ||
151 | gameport_close(gameport); | ||
152 | } | ||
153 | |||
154 | static struct gameport_driver joydump_drv = { | ||
155 | .driver = { | ||
156 | .name = "joydump", | ||
157 | }, | ||
158 | .description = DRIVER_DESC, | ||
159 | .connect = joydump_connect, | ||
160 | .disconnect = joydump_disconnect, | ||
161 | }; | ||
162 | |||
163 | static int __init joydump_init(void) | ||
164 | { | ||
165 | gameport_register_driver(&joydump_drv); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static void __exit joydump_exit(void) | ||
170 | { | ||
171 | gameport_unregister_driver(&joydump_drv); | ||
172 | } | ||
173 | |||
174 | module_init(joydump_init); | ||
175 | module_exit(joydump_exit); | ||
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c new file mode 100644 index 000000000000..1ba503627242 --- /dev/null +++ b/drivers/input/joystick/magellan.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * $Id: magellan.c,v 1.16 2002/01/22 20:28:39 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Magellan and Space Mouse 6dof controller 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/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/input.h> | ||
35 | #include <linux/serio.h> | ||
36 | #include <linux/init.h> | ||
37 | |||
38 | #define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver" | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | /* | ||
45 | * Definitions & global arrays. | ||
46 | */ | ||
47 | |||
48 | #define MAGELLAN_MAX_LENGTH 32 | ||
49 | |||
50 | static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; | ||
51 | static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; | ||
52 | static char *magellan_name = "LogiCad3D Magellan / SpaceMouse"; | ||
53 | |||
54 | /* | ||
55 | * Per-Magellan data. | ||
56 | */ | ||
57 | |||
58 | struct magellan { | ||
59 | struct input_dev dev; | ||
60 | int idx; | ||
61 | unsigned char data[MAGELLAN_MAX_LENGTH]; | ||
62 | char phys[32]; | ||
63 | }; | ||
64 | |||
65 | /* | ||
66 | * magellan_crunch_nibbles() verifies that the bytes sent from the Magellan | ||
67 | * have correct upper nibbles for the lower ones, if not, the packet will | ||
68 | * be thrown away. It also strips these upper halves to simplify further | ||
69 | * processing. | ||
70 | */ | ||
71 | |||
72 | static int magellan_crunch_nibbles(unsigned char *data, int count) | ||
73 | { | ||
74 | static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?"; | ||
75 | |||
76 | do { | ||
77 | if (data[count] == nibbles[data[count] & 0xf]) | ||
78 | data[count] = data[count] & 0xf; | ||
79 | else | ||
80 | return -1; | ||
81 | } while (--count); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static void magellan_process_packet(struct magellan* magellan, struct pt_regs *regs) | ||
87 | { | ||
88 | struct input_dev *dev = &magellan->dev; | ||
89 | unsigned char *data = magellan->data; | ||
90 | int i, t; | ||
91 | |||
92 | if (!magellan->idx) return; | ||
93 | |||
94 | input_regs(dev, regs); | ||
95 | |||
96 | switch (magellan->data[0]) { | ||
97 | |||
98 | case 'd': /* Axis data */ | ||
99 | if (magellan->idx != 25) return; | ||
100 | if (magellan_crunch_nibbles(data, 24)) return; | ||
101 | for (i = 0; i < 6; i++) | ||
102 | input_report_abs(dev, magellan_axes[i], | ||
103 | (data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 | | ||
104 | data[(i << 2) + 3] << 4 | data[(i << 2) + 4]) - 32768); | ||
105 | break; | ||
106 | |||
107 | case 'k': /* Button data */ | ||
108 | if (magellan->idx != 4) return; | ||
109 | if (magellan_crunch_nibbles(data, 3)) return; | ||
110 | t = (data[1] << 1) | (data[2] << 5) | data[3]; | ||
111 | for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1); | ||
112 | break; | ||
113 | } | ||
114 | |||
115 | input_sync(dev); | ||
116 | } | ||
117 | |||
118 | static irqreturn_t magellan_interrupt(struct serio *serio, | ||
119 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
120 | { | ||
121 | struct magellan* magellan = serio_get_drvdata(serio); | ||
122 | |||
123 | if (data == '\r') { | ||
124 | magellan_process_packet(magellan, regs); | ||
125 | magellan->idx = 0; | ||
126 | } else { | ||
127 | if (magellan->idx < MAGELLAN_MAX_LENGTH) | ||
128 | magellan->data[magellan->idx++] = data; | ||
129 | } | ||
130 | return IRQ_HANDLED; | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * magellan_disconnect() is the opposite of magellan_connect() | ||
135 | */ | ||
136 | |||
137 | static void magellan_disconnect(struct serio *serio) | ||
138 | { | ||
139 | struct magellan* magellan = serio_get_drvdata(serio); | ||
140 | |||
141 | input_unregister_device(&magellan->dev); | ||
142 | serio_close(serio); | ||
143 | serio_set_drvdata(serio, NULL); | ||
144 | kfree(magellan); | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * magellan_connect() is the routine that is called when someone adds a | ||
149 | * new serio device that supports Magellan protocol and registers it as | ||
150 | * an input device. | ||
151 | */ | ||
152 | |||
153 | static int magellan_connect(struct serio *serio, struct serio_driver *drv) | ||
154 | { | ||
155 | struct magellan *magellan; | ||
156 | int i, t; | ||
157 | int err; | ||
158 | |||
159 | if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL))) | ||
160 | return -ENOMEM; | ||
161 | |||
162 | memset(magellan, 0, sizeof(struct magellan)); | ||
163 | |||
164 | magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
165 | |||
166 | for (i = 0; i < 9; i++) | ||
167 | set_bit(magellan_buttons[i], magellan->dev.keybit); | ||
168 | |||
169 | for (i = 0; i < 6; i++) { | ||
170 | t = magellan_axes[i]; | ||
171 | set_bit(t, magellan->dev.absbit); | ||
172 | magellan->dev.absmin[t] = -360; | ||
173 | magellan->dev.absmax[t] = 360; | ||
174 | } | ||
175 | |||
176 | sprintf(magellan->phys, "%s/input0", serio->phys); | ||
177 | |||
178 | init_input_dev(&magellan->dev); | ||
179 | magellan->dev.private = magellan; | ||
180 | magellan->dev.name = magellan_name; | ||
181 | magellan->dev.phys = magellan->phys; | ||
182 | magellan->dev.id.bustype = BUS_RS232; | ||
183 | magellan->dev.id.vendor = SERIO_MAGELLAN; | ||
184 | magellan->dev.id.product = 0x0001; | ||
185 | magellan->dev.id.version = 0x0100; | ||
186 | magellan->dev.dev = &serio->dev; | ||
187 | |||
188 | serio_set_drvdata(serio, magellan); | ||
189 | |||
190 | err = serio_open(serio, drv); | ||
191 | if (err) { | ||
192 | serio_set_drvdata(serio, NULL); | ||
193 | kfree(magellan); | ||
194 | return err; | ||
195 | } | ||
196 | |||
197 | input_register_device(&magellan->dev); | ||
198 | |||
199 | printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * The serio driver structure. | ||
206 | */ | ||
207 | |||
208 | static struct serio_device_id magellan_serio_ids[] = { | ||
209 | { | ||
210 | .type = SERIO_RS232, | ||
211 | .proto = SERIO_MAGELLAN, | ||
212 | .id = SERIO_ANY, | ||
213 | .extra = SERIO_ANY, | ||
214 | }, | ||
215 | { 0 } | ||
216 | }; | ||
217 | |||
218 | MODULE_DEVICE_TABLE(serio, magellan_serio_ids); | ||
219 | |||
220 | static struct serio_driver magellan_drv = { | ||
221 | .driver = { | ||
222 | .name = "magellan", | ||
223 | }, | ||
224 | .description = DRIVER_DESC, | ||
225 | .id_table = magellan_serio_ids, | ||
226 | .interrupt = magellan_interrupt, | ||
227 | .connect = magellan_connect, | ||
228 | .disconnect = magellan_disconnect, | ||
229 | }; | ||
230 | |||
231 | /* | ||
232 | * The functions for inserting/removing us as a module. | ||
233 | */ | ||
234 | |||
235 | static int __init magellan_init(void) | ||
236 | { | ||
237 | serio_register_driver(&magellan_drv); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static void __exit magellan_exit(void) | ||
242 | { | ||
243 | serio_unregister_driver(&magellan_drv); | ||
244 | } | ||
245 | |||
246 | module_init(magellan_init); | ||
247 | module_exit(magellan_exit); | ||
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c new file mode 100644 index 000000000000..47144a7ed9e7 --- /dev/null +++ b/drivers/input/joystick/sidewinder.c | |||
@@ -0,0 +1,807 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1998-2005 Vojtech Pavlik | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * Microsoft SideWinder joystick family driver for Linux | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Should you need to contact me, the author, you can do so either by | ||
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
27 | */ | ||
28 | |||
29 | #include <linux/delay.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/input.h> | ||
35 | #include <linux/gameport.h> | ||
36 | |||
37 | #define DRIVER_DESC "Microsoft SideWinder joystick family driver" | ||
38 | |||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
40 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | /* | ||
44 | * These are really magic values. Changing them can make a problem go away, | ||
45 | * as well as break everything. | ||
46 | */ | ||
47 | |||
48 | #undef SW_DEBUG | ||
49 | #undef SW_DEBUG_DATA | ||
50 | |||
51 | #define SW_START 600 /* The time we wait for the first bit [600 us] */ | ||
52 | #define SW_STROBE 60 /* Max time per bit [60 us] */ | ||
53 | #define SW_TIMEOUT 6 /* Wait for everything to settle [6 ms] */ | ||
54 | #define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */ | ||
55 | #define SW_END 8 /* Number of bits before end of packet to kick */ | ||
56 | #define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */ | ||
57 | #define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */ | ||
58 | #define SW_OK 64 /* Number of packet read successes to switch optimization back on */ | ||
59 | #define SW_LENGTH 512 /* Max number of bits in a packet */ | ||
60 | |||
61 | #ifdef SW_DEBUG | ||
62 | #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg) | ||
63 | #else | ||
64 | #define dbg(format, arg...) do {} while (0) | ||
65 | #endif | ||
66 | |||
67 | /* | ||
68 | * SideWinder joystick types ... | ||
69 | */ | ||
70 | |||
71 | #define SW_ID_3DP 0 | ||
72 | #define SW_ID_GP 1 | ||
73 | #define SW_ID_PP 2 | ||
74 | #define SW_ID_FFP 3 | ||
75 | #define SW_ID_FSP 4 | ||
76 | #define SW_ID_FFW 5 | ||
77 | |||
78 | /* | ||
79 | * Names, buttons, axes ... | ||
80 | */ | ||
81 | |||
82 | static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro", | ||
83 | "Force Feedback Wheel" }; | ||
84 | |||
85 | static char sw_abs[][7] = { | ||
86 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | ||
87 | { ABS_X, ABS_Y }, | ||
88 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | ||
89 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | ||
90 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | ||
91 | { ABS_RX, ABS_RUDDER, ABS_THROTTLE }}; | ||
92 | |||
93 | static char sw_bit[][7] = { | ||
94 | { 10, 10, 9, 10, 1, 1 }, | ||
95 | { 1, 1 }, | ||
96 | { 10, 10, 6, 7, 1, 1 }, | ||
97 | { 10, 10, 6, 7, 1, 1 }, | ||
98 | { 10, 10, 6, 1, 1 }, | ||
99 | { 10, 7, 7, 1, 1 }}; | ||
100 | |||
101 | static short sw_btn[][12] = { | ||
102 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE }, | ||
103 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE }, | ||
104 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, | ||
105 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, | ||
106 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }, | ||
107 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }}; | ||
108 | |||
109 | static struct { | ||
110 | int x; | ||
111 | int y; | ||
112 | } sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | ||
113 | |||
114 | struct sw { | ||
115 | struct gameport *gameport; | ||
116 | struct input_dev dev[4]; | ||
117 | char name[64]; | ||
118 | char phys[4][32]; | ||
119 | int length; | ||
120 | int type; | ||
121 | int bits; | ||
122 | int number; | ||
123 | int fail; | ||
124 | int ok; | ||
125 | int reads; | ||
126 | int bads; | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * sw_read_packet() is a function which reads either a data packet, or an | ||
131 | * identification packet from a SideWinder joystick. The protocol is very, | ||
132 | * very, very braindamaged. Microsoft patented it in US patent #5628686. | ||
133 | */ | ||
134 | |||
135 | static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id) | ||
136 | { | ||
137 | unsigned long flags; | ||
138 | int timeout, bitout, sched, i, kick, start, strobe; | ||
139 | unsigned char pending, u, v; | ||
140 | |||
141 | i = -id; /* Don't care about data, only want ID */ | ||
142 | timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 0; /* Set up global timeout for ID packet */ | ||
143 | kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */ | ||
144 | start = gameport_time(gameport, SW_START); | ||
145 | strobe = gameport_time(gameport, SW_STROBE); | ||
146 | bitout = start; | ||
147 | pending = 0; | ||
148 | sched = 0; | ||
149 | |||
150 | local_irq_save(flags); /* Quiet, please */ | ||
151 | |||
152 | gameport_trigger(gameport); /* Trigger */ | ||
153 | v = gameport_read(gameport); | ||
154 | |||
155 | do { | ||
156 | bitout--; | ||
157 | u = v; | ||
158 | v = gameport_read(gameport); | ||
159 | } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */ | ||
160 | |||
161 | if (bitout > 0) | ||
162 | bitout = strobe; /* Extend time if not timed out */ | ||
163 | |||
164 | while ((timeout > 0 || bitout > 0) && (i < length)) { | ||
165 | |||
166 | timeout--; | ||
167 | bitout--; /* Decrement timers */ | ||
168 | sched--; | ||
169 | |||
170 | u = v; | ||
171 | v = gameport_read(gameport); | ||
172 | |||
173 | if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */ | ||
174 | if (i >= 0) /* Want this data */ | ||
175 | buf[i] = v >> 5; /* Store it */ | ||
176 | i++; /* Advance index */ | ||
177 | bitout = strobe; /* Extend timeout for next bit */ | ||
178 | } | ||
179 | |||
180 | if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */ | ||
181 | sched = kick; /* Schedule second trigger */ | ||
182 | kick = 0; /* Don't schedule next time on falling edge */ | ||
183 | pending = 1; /* Mark schedule */ | ||
184 | } | ||
185 | |||
186 | if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */ | ||
187 | gameport_trigger(gameport); /* Trigger */ | ||
188 | bitout = start; /* Long bit timeout */ | ||
189 | pending = 0; /* Unmark schedule */ | ||
190 | timeout = 0; /* Switch from global to bit timeouts */ | ||
191 | } | ||
192 | } | ||
193 | |||
194 | local_irq_restore(flags); /* Done - relax */ | ||
195 | |||
196 | #ifdef SW_DEBUG_DATA | ||
197 | { | ||
198 | int j; | ||
199 | printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i); | ||
200 | for (j = 0; j < i; j++) printk("%d", buf[j]); | ||
201 | printk("]\n"); | ||
202 | } | ||
203 | #endif | ||
204 | |||
205 | return i; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64. | ||
210 | * Parameter 'pos' is bit number inside packet where to start at, 'num' is number | ||
211 | * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits | ||
212 | * is number of bits per triplet. | ||
213 | */ | ||
214 | |||
215 | #define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits) | ||
216 | |||
217 | static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits) | ||
218 | { | ||
219 | __u64 data = 0; | ||
220 | int tri = pos % bits; /* Start position */ | ||
221 | int i = pos / bits; | ||
222 | int bit = 0; | ||
223 | |||
224 | while (num--) { | ||
225 | data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */ | ||
226 | if (tri == bits) { | ||
227 | i++; /* Next triplet */ | ||
228 | tri = 0; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | return data; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * sw_init_digital() initializes a SideWinder 3D Pro joystick | ||
237 | * into digital mode. | ||
238 | */ | ||
239 | |||
240 | static void sw_init_digital(struct gameport *gameport) | ||
241 | { | ||
242 | int seq[] = { 140, 140+725, 140+300, 0 }; | ||
243 | unsigned long flags; | ||
244 | int i, t; | ||
245 | |||
246 | local_irq_save(flags); | ||
247 | |||
248 | i = 0; | ||
249 | do { | ||
250 | gameport_trigger(gameport); /* Trigger */ | ||
251 | t = gameport_time(gameport, SW_TIMEOUT * 1000); | ||
252 | while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */ | ||
253 | udelay(seq[i]); /* Delay magic time */ | ||
254 | } while (seq[++i]); | ||
255 | |||
256 | gameport_trigger(gameport); /* Last trigger */ | ||
257 | |||
258 | local_irq_restore(flags); | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * sw_parity() computes parity of __u64 | ||
263 | */ | ||
264 | |||
265 | static int sw_parity(__u64 t) | ||
266 | { | ||
267 | int x = t ^ (t >> 32); | ||
268 | |||
269 | x ^= x >> 16; | ||
270 | x ^= x >> 8; | ||
271 | x ^= x >> 4; | ||
272 | x ^= x >> 2; | ||
273 | x ^= x >> 1; | ||
274 | return x & 1; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * sw_ccheck() checks synchronization bits and computes checksum of nibbles. | ||
279 | */ | ||
280 | |||
281 | static int sw_check(__u64 t) | ||
282 | { | ||
283 | unsigned char sum = 0; | ||
284 | |||
285 | if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */ | ||
286 | return -1; | ||
287 | |||
288 | while (t) { /* Sum */ | ||
289 | sum += t & 0xf; | ||
290 | t >>= 4; | ||
291 | } | ||
292 | |||
293 | return sum & 0xf; | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * sw_parse() analyzes SideWinder joystick data, and writes the results into | ||
298 | * the axes and buttons arrays. | ||
299 | */ | ||
300 | |||
301 | static int sw_parse(unsigned char *buf, struct sw *sw) | ||
302 | { | ||
303 | int hat, i, j; | ||
304 | struct input_dev *dev = sw->dev; | ||
305 | |||
306 | switch (sw->type) { | ||
307 | |||
308 | case SW_ID_3DP: | ||
309 | |||
310 | if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) | ||
311 | return -1; | ||
312 | |||
313 | input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7)); | ||
314 | input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7)); | ||
315 | input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7)); | ||
316 | input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7)); | ||
317 | |||
318 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); | ||
319 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); | ||
320 | |||
321 | for (j = 0; j < 7; j++) | ||
322 | input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1)); | ||
323 | |||
324 | input_report_key(dev, BTN_BASE4, !GB(38,1)); | ||
325 | input_report_key(dev, BTN_BASE5, !GB(37,1)); | ||
326 | |||
327 | input_sync(dev); | ||
328 | |||
329 | return 0; | ||
330 | |||
331 | case SW_ID_GP: | ||
332 | |||
333 | for (i = 0; i < sw->number; i ++) { | ||
334 | |||
335 | if (sw_parity(GB(i*15,15))) | ||
336 | return -1; | ||
337 | |||
338 | input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); | ||
339 | input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); | ||
340 | |||
341 | for (j = 0; j < 10; j++) | ||
342 | input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); | ||
343 | |||
344 | input_sync(dev + i); | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | |||
349 | case SW_ID_PP: | ||
350 | case SW_ID_FFP: | ||
351 | |||
352 | if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) | ||
353 | return -1; | ||
354 | |||
355 | input_report_abs(dev, ABS_X, GB( 9,10)); | ||
356 | input_report_abs(dev, ABS_Y, GB(19,10)); | ||
357 | input_report_abs(dev, ABS_RZ, GB(36, 6)); | ||
358 | input_report_abs(dev, ABS_THROTTLE, GB(29, 7)); | ||
359 | |||
360 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); | ||
361 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); | ||
362 | |||
363 | for (j = 0; j < 9; j++) | ||
364 | input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1)); | ||
365 | |||
366 | input_sync(dev); | ||
367 | |||
368 | return 0; | ||
369 | |||
370 | case SW_ID_FSP: | ||
371 | |||
372 | if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) | ||
373 | return -1; | ||
374 | |||
375 | input_report_abs(dev, ABS_X, GB( 0,10)); | ||
376 | input_report_abs(dev, ABS_Y, GB(16,10)); | ||
377 | input_report_abs(dev, ABS_THROTTLE, GB(32, 6)); | ||
378 | |||
379 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); | ||
380 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); | ||
381 | |||
382 | for (j = 0; j < 6; j++) | ||
383 | input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1)); | ||
384 | |||
385 | input_report_key(dev, BTN_TR, !GB(26,1)); | ||
386 | input_report_key(dev, BTN_START, !GB(27,1)); | ||
387 | input_report_key(dev, BTN_MODE, !GB(38,1)); | ||
388 | input_report_key(dev, BTN_SELECT, !GB(39,1)); | ||
389 | |||
390 | input_sync(dev); | ||
391 | |||
392 | return 0; | ||
393 | |||
394 | case SW_ID_FFW: | ||
395 | |||
396 | if (!sw_parity(GB(0,33))) | ||
397 | return -1; | ||
398 | |||
399 | input_report_abs(dev, ABS_RX, GB( 0,10)); | ||
400 | input_report_abs(dev, ABS_RUDDER, GB(10, 6)); | ||
401 | input_report_abs(dev, ABS_THROTTLE, GB(16, 6)); | ||
402 | |||
403 | for (j = 0; j < 8; j++) | ||
404 | input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1)); | ||
405 | |||
406 | input_sync(dev); | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | return -1; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * sw_read() reads SideWinder joystick data, and reinitializes | ||
416 | * the joystick in case of persistent problems. This is the function that is | ||
417 | * called from the generic code to poll the joystick. | ||
418 | */ | ||
419 | |||
420 | static int sw_read(struct sw *sw) | ||
421 | { | ||
422 | unsigned char buf[SW_LENGTH]; | ||
423 | int i; | ||
424 | |||
425 | i = sw_read_packet(sw->gameport, buf, sw->length, 0); | ||
426 | |||
427 | if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */ | ||
428 | |||
429 | if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */ | ||
430 | printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s" | ||
431 | " - going to reinitialize.\n", sw->gameport->phys); | ||
432 | sw->fail = SW_FAIL; /* Reinitialize */ | ||
433 | i = 128; /* Bogus value */ | ||
434 | } | ||
435 | |||
436 | if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */ | ||
437 | i = 66; /* Everything is fine */ | ||
438 | |||
439 | if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */ | ||
440 | i = 66; /* Everything is fine */ | ||
441 | |||
442 | if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */ | ||
443 | memmove(buf, buf + i - 22, 22); /* Move data */ | ||
444 | i = 66; /* Carry on */ | ||
445 | } | ||
446 | } | ||
447 | |||
448 | if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */ | ||
449 | |||
450 | sw->fail = 0; | ||
451 | sw->ok++; | ||
452 | |||
453 | if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */ | ||
454 | && sw->ok > SW_OK) { | ||
455 | |||
456 | printk(KERN_INFO "sidewinder.c: No more trouble on %s" | ||
457 | " - enabling optimization again.\n", sw->gameport->phys); | ||
458 | sw->length = 22; | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | sw->ok = 0; | ||
465 | sw->fail++; | ||
466 | |||
467 | if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */ | ||
468 | |||
469 | printk(KERN_INFO "sidewinder.c: Many bit errors on %s" | ||
470 | " - disabling optimization.\n", sw->gameport->phys); | ||
471 | sw->length = 66; | ||
472 | } | ||
473 | |||
474 | if (sw->fail < SW_FAIL) | ||
475 | return -1; /* Not enough, don't reinitialize yet */ | ||
476 | |||
477 | printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s" | ||
478 | " - reinitializing joystick.\n", sw->gameport->phys); | ||
479 | |||
480 | if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */ | ||
481 | mdelay(3 * SW_TIMEOUT); | ||
482 | sw_init_digital(sw->gameport); | ||
483 | } | ||
484 | |||
485 | mdelay(SW_TIMEOUT); | ||
486 | i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */ | ||
487 | mdelay(SW_TIMEOUT); | ||
488 | sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */ | ||
489 | |||
490 | sw->fail = SW_FAIL; | ||
491 | |||
492 | return -1; | ||
493 | } | ||
494 | |||
495 | static void sw_poll(struct gameport *gameport) | ||
496 | { | ||
497 | struct sw *sw = gameport_get_drvdata(gameport); | ||
498 | |||
499 | sw->reads++; | ||
500 | if (sw_read(sw)) | ||
501 | sw->bads++; | ||
502 | } | ||
503 | |||
504 | static int sw_open(struct input_dev *dev) | ||
505 | { | ||
506 | struct sw *sw = dev->private; | ||
507 | |||
508 | gameport_start_polling(sw->gameport); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static void sw_close(struct input_dev *dev) | ||
513 | { | ||
514 | struct sw *sw = dev->private; | ||
515 | |||
516 | gameport_stop_polling(sw->gameport); | ||
517 | } | ||
518 | |||
519 | /* | ||
520 | * sw_print_packet() prints the contents of a SideWinder packet. | ||
521 | */ | ||
522 | |||
523 | static void sw_print_packet(char *name, int length, unsigned char *buf, char bits) | ||
524 | { | ||
525 | int i; | ||
526 | |||
527 | printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length); | ||
528 | for (i = (((length + 3) >> 2) - 1); i >= 0; i--) | ||
529 | printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits)); | ||
530 | printk("]\n"); | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * sw_3dp_id() translates the 3DP id into a human legible string. | ||
535 | * Unfortunately I don't know how to do this for the other SW types. | ||
536 | */ | ||
537 | |||
538 | static void sw_3dp_id(unsigned char *buf, char *comment) | ||
539 | { | ||
540 | int i; | ||
541 | char pnp[8], rev[9]; | ||
542 | |||
543 | for (i = 0; i < 7; i++) /* ASCII PnP ID */ | ||
544 | pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1); | ||
545 | |||
546 | for (i = 0; i < 8; i++) /* ASCII firmware revision */ | ||
547 | rev[i] = sw_get_bits(buf, 88+8*i, 8, 1); | ||
548 | |||
549 | pnp[7] = rev[8] = 0; | ||
550 | |||
551 | sprintf(comment, " [PnP %d.%02d id %s rev %s]", | ||
552 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */ | ||
553 | sw_get_bits(buf, 16, 6, 1)) / 100, | ||
554 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | | ||
555 | sw_get_bits(buf, 16, 6, 1)) % 100, | ||
556 | pnp, rev); | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * sw_guess_mode() checks the upper two button bits for toggling - | ||
561 | * indication of that the joystick is in 3-bit mode. This is documented | ||
562 | * behavior for 3DP ID packet, and for example the FSP does this in | ||
563 | * normal packets instead. Fun ... | ||
564 | */ | ||
565 | |||
566 | static int sw_guess_mode(unsigned char *buf, int len) | ||
567 | { | ||
568 | int i; | ||
569 | unsigned char xor = 0; | ||
570 | |||
571 | for (i = 1; i < len; i++) | ||
572 | xor |= (buf[i - 1] ^ buf[i]) & 6; | ||
573 | |||
574 | return !!xor * 2 + 1; | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * sw_connect() probes for SideWinder type joysticks. | ||
579 | */ | ||
580 | |||
581 | static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
582 | { | ||
583 | struct sw *sw; | ||
584 | int i, j, k, l; | ||
585 | int err; | ||
586 | unsigned char *buf = NULL; /* [SW_LENGTH] */ | ||
587 | unsigned char *idbuf = NULL; /* [SW_LENGTH] */ | ||
588 | unsigned char m = 1; | ||
589 | char comment[40]; | ||
590 | |||
591 | comment[0] = 0; | ||
592 | |||
593 | sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL); | ||
594 | buf = kmalloc(SW_LENGTH, GFP_KERNEL); | ||
595 | idbuf = kmalloc(SW_LENGTH, GFP_KERNEL); | ||
596 | if (!sw || !buf || !idbuf) { | ||
597 | err = -ENOMEM; | ||
598 | goto fail1; | ||
599 | } | ||
600 | |||
601 | sw->gameport = gameport; | ||
602 | |||
603 | gameport_set_drvdata(gameport, sw); | ||
604 | |||
605 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
606 | if (err) | ||
607 | goto fail1; | ||
608 | |||
609 | dbg("Init 0: Opened %s, io %#x, speed %d", | ||
610 | gameport->phys, gameport->io, gameport->speed); | ||
611 | |||
612 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */ | ||
613 | msleep(SW_TIMEOUT); | ||
614 | dbg("Init 1: Mode %d. Length %d.", m , i); | ||
615 | |||
616 | if (!i) { /* No data. 3d Pro analog mode? */ | ||
617 | sw_init_digital(gameport); /* Switch to digital */ | ||
618 | msleep(SW_TIMEOUT); | ||
619 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ | ||
620 | msleep(SW_TIMEOUT); | ||
621 | dbg("Init 1b: Length %d.", i); | ||
622 | if (!i) { /* No data -> FAIL */ | ||
623 | err = -ENODEV; | ||
624 | goto fail2; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */ | ||
629 | m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */ | ||
630 | dbg("Init 2: Mode %d. ID Length %d.", m, j); | ||
631 | |||
632 | if (j <= 0) { /* Read ID failed. Happens in 1-bit mode on PP */ | ||
633 | msleep(SW_TIMEOUT); | ||
634 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ | ||
635 | m |= sw_guess_mode(buf, i); | ||
636 | dbg("Init 2b: Mode %d. Length %d.", m, i); | ||
637 | if (!i) { | ||
638 | err = -ENODEV; | ||
639 | goto fail2; | ||
640 | } | ||
641 | msleep(SW_TIMEOUT); | ||
642 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */ | ||
643 | dbg("Init 2c: ID Length %d.", j); | ||
644 | } | ||
645 | |||
646 | sw->type = -1; | ||
647 | k = SW_FAIL; /* Try SW_FAIL times */ | ||
648 | l = 0; | ||
649 | |||
650 | do { | ||
651 | k--; | ||
652 | msleep(SW_TIMEOUT); | ||
653 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */ | ||
654 | dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k); | ||
655 | |||
656 | if (i > l) { /* Longer? As we can only lose bits, it makes */ | ||
657 | /* no sense to try detection for a packet shorter */ | ||
658 | l = i; /* than the previous one */ | ||
659 | |||
660 | sw->number = 1; | ||
661 | sw->gameport = gameport; | ||
662 | sw->length = i; | ||
663 | sw->bits = m; | ||
664 | |||
665 | dbg("Init 3a: Case %d.\n", i * m); | ||
666 | |||
667 | switch (i * m) { | ||
668 | case 60: | ||
669 | sw->number++; | ||
670 | case 45: /* Ambiguous packet length */ | ||
671 | if (j <= 40) { /* ID length less or eq 40 -> FSP */ | ||
672 | case 43: | ||
673 | sw->type = SW_ID_FSP; | ||
674 | break; | ||
675 | } | ||
676 | sw->number++; | ||
677 | case 30: | ||
678 | sw->number++; | ||
679 | case 15: | ||
680 | sw->type = SW_ID_GP; | ||
681 | break; | ||
682 | case 33: | ||
683 | case 31: | ||
684 | sw->type = SW_ID_FFW; | ||
685 | break; | ||
686 | case 48: /* Ambiguous */ | ||
687 | if (j == 14) { /* ID length 14*3 -> FFP */ | ||
688 | sw->type = SW_ID_FFP; | ||
689 | sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on"); | ||
690 | } else | ||
691 | sw->type = SW_ID_PP; | ||
692 | break; | ||
693 | case 66: | ||
694 | sw->bits = 3; | ||
695 | case 198: | ||
696 | sw->length = 22; | ||
697 | case 64: | ||
698 | sw->type = SW_ID_3DP; | ||
699 | if (j == 160) sw_3dp_id(idbuf, comment); | ||
700 | break; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | } while (k && sw->type == -1); | ||
705 | |||
706 | if (sw->type == -1) { | ||
707 | printk(KERN_WARNING "sidewinder.c: unknown joystick device detected " | ||
708 | "on %s, contact <vojtech@ucw.cz>\n", gameport->phys); | ||
709 | sw_print_packet("ID", j * 3, idbuf, 3); | ||
710 | sw_print_packet("Data", i * m, buf, m); | ||
711 | err = -ENODEV; | ||
712 | goto fail2; | ||
713 | } | ||
714 | |||
715 | #ifdef SW_DEBUG | ||
716 | sw_print_packet("ID", j * 3, idbuf, 3); | ||
717 | sw_print_packet("Data", i * m, buf, m); | ||
718 | #endif | ||
719 | |||
720 | gameport_set_poll_handler(gameport, sw_poll); | ||
721 | gameport_set_poll_interval(gameport, 20); | ||
722 | |||
723 | k = i; | ||
724 | l = j; | ||
725 | |||
726 | for (i = 0; i < sw->number; i++) { | ||
727 | int bits, code; | ||
728 | |||
729 | sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]); | ||
730 | sprintf(sw->phys[i], "%s/input%d", gameport->phys, i); | ||
731 | |||
732 | sw->dev[i].private = sw; | ||
733 | |||
734 | sw->dev[i].open = sw_open; | ||
735 | sw->dev[i].close = sw_close; | ||
736 | |||
737 | sw->dev[i].name = sw->name; | ||
738 | sw->dev[i].phys = sw->phys[i]; | ||
739 | sw->dev[i].id.bustype = BUS_GAMEPORT; | ||
740 | sw->dev[i].id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; | ||
741 | sw->dev[i].id.product = sw->type; | ||
742 | sw->dev[i].id.version = 0x0100; | ||
743 | |||
744 | sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
745 | |||
746 | for (j = 0; (bits = sw_bit[sw->type][j]); j++) { | ||
747 | code = sw_abs[sw->type][j]; | ||
748 | set_bit(code, sw->dev[i].absbit); | ||
749 | sw->dev[i].absmax[code] = (1 << bits) - 1; | ||
750 | sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0; | ||
751 | sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; | ||
752 | if (code != ABS_THROTTLE) | ||
753 | sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; | ||
754 | } | ||
755 | |||
756 | for (j = 0; (code = sw_btn[sw->type][j]); j++) | ||
757 | set_bit(code, sw->dev[i].keybit); | ||
758 | |||
759 | input_register_device(sw->dev + i); | ||
760 | printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n", | ||
761 | sw->name, comment, gameport->phys, m, l, k); | ||
762 | } | ||
763 | |||
764 | return 0; | ||
765 | |||
766 | fail2: gameport_close(gameport); | ||
767 | fail1: gameport_set_drvdata(gameport, NULL); | ||
768 | kfree(sw); | ||
769 | kfree(buf); | ||
770 | kfree(idbuf); | ||
771 | return err; | ||
772 | } | ||
773 | |||
774 | static void sw_disconnect(struct gameport *gameport) | ||
775 | { | ||
776 | struct sw *sw = gameport_get_drvdata(gameport); | ||
777 | int i; | ||
778 | |||
779 | for (i = 0; i < sw->number; i++) | ||
780 | input_unregister_device(sw->dev + i); | ||
781 | gameport_close(gameport); | ||
782 | gameport_set_drvdata(gameport, NULL); | ||
783 | kfree(sw); | ||
784 | } | ||
785 | |||
786 | static struct gameport_driver sw_drv = { | ||
787 | .driver = { | ||
788 | .name = "sidewinder", | ||
789 | }, | ||
790 | .description = DRIVER_DESC, | ||
791 | .connect = sw_connect, | ||
792 | .disconnect = sw_disconnect, | ||
793 | }; | ||
794 | |||
795 | static int __init sw_init(void) | ||
796 | { | ||
797 | gameport_register_driver(&sw_drv); | ||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | static void __exit sw_exit(void) | ||
802 | { | ||
803 | gameport_unregister_driver(&sw_drv); | ||
804 | } | ||
805 | |||
806 | module_init(sw_init); | ||
807 | module_exit(sw_exit); | ||
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c new file mode 100644 index 000000000000..ec0a2a64d49c --- /dev/null +++ b/drivers/input/joystick/spaceball.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * $Id: spaceball.c,v 1.17 2002/01/22 20:29:03 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * David Thompson | ||
8 | * Joseph Krahn | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * SpaceTec SpaceBall 2003/3003/4000 FLX driver for Linux | ||
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 either by | ||
31 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
32 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/input.h> | ||
40 | #include <linux/serio.h> | ||
41 | |||
42 | #define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver" | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
45 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | /* | ||
49 | * Constants. | ||
50 | */ | ||
51 | |||
52 | #define SPACEBALL_MAX_LENGTH 128 | ||
53 | #define SPACEBALL_MAX_ID 8 | ||
54 | |||
55 | #define SPACEBALL_1003 1 | ||
56 | #define SPACEBALL_2003B 3 | ||
57 | #define SPACEBALL_2003C 4 | ||
58 | #define SPACEBALL_3003C 7 | ||
59 | #define SPACEBALL_4000FLX 8 | ||
60 | #define SPACEBALL_4000FLX_L 9 | ||
61 | |||
62 | static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; | ||
63 | static char *spaceball_names[] = { | ||
64 | "?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", | ||
65 | "SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", | ||
66 | "SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" }; | ||
67 | |||
68 | /* | ||
69 | * Per-Ball data. | ||
70 | */ | ||
71 | |||
72 | struct spaceball { | ||
73 | struct input_dev dev; | ||
74 | struct serio *serio; | ||
75 | int idx; | ||
76 | int escape; | ||
77 | unsigned char data[SPACEBALL_MAX_LENGTH]; | ||
78 | char phys[32]; | ||
79 | }; | ||
80 | |||
81 | /* | ||
82 | * spaceball_process_packet() decodes packets the driver receives from the | ||
83 | * SpaceBall. | ||
84 | */ | ||
85 | |||
86 | static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs *regs) | ||
87 | { | ||
88 | struct input_dev *dev = &spaceball->dev; | ||
89 | unsigned char *data = spaceball->data; | ||
90 | int i; | ||
91 | |||
92 | if (spaceball->idx < 2) return; | ||
93 | |||
94 | input_regs(dev, regs); | ||
95 | |||
96 | switch (spaceball->data[0]) { | ||
97 | |||
98 | case 'D': /* Ball data */ | ||
99 | if (spaceball->idx != 15) return; | ||
100 | for (i = 0; i < 6; i++) | ||
101 | input_report_abs(dev, spaceball_axes[i], | ||
102 | (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2])); | ||
103 | break; | ||
104 | |||
105 | case 'K': /* Button data */ | ||
106 | if (spaceball->idx != 3) return; | ||
107 | input_report_key(dev, BTN_1, (data[2] & 0x01) || (data[2] & 0x20)); | ||
108 | input_report_key(dev, BTN_2, data[2] & 0x02); | ||
109 | input_report_key(dev, BTN_3, data[2] & 0x04); | ||
110 | input_report_key(dev, BTN_4, data[2] & 0x08); | ||
111 | input_report_key(dev, BTN_5, data[1] & 0x01); | ||
112 | input_report_key(dev, BTN_6, data[1] & 0x02); | ||
113 | input_report_key(dev, BTN_7, data[1] & 0x04); | ||
114 | input_report_key(dev, BTN_8, data[1] & 0x10); | ||
115 | break; | ||
116 | |||
117 | case '.': /* Advanced button data */ | ||
118 | if (spaceball->idx != 3) return; | ||
119 | input_report_key(dev, BTN_1, data[2] & 0x01); | ||
120 | input_report_key(dev, BTN_2, data[2] & 0x02); | ||
121 | input_report_key(dev, BTN_3, data[2] & 0x04); | ||
122 | input_report_key(dev, BTN_4, data[2] & 0x08); | ||
123 | input_report_key(dev, BTN_5, data[2] & 0x10); | ||
124 | input_report_key(dev, BTN_6, data[2] & 0x20); | ||
125 | input_report_key(dev, BTN_7, data[2] & 0x80); | ||
126 | input_report_key(dev, BTN_8, data[1] & 0x01); | ||
127 | input_report_key(dev, BTN_9, data[1] & 0x02); | ||
128 | input_report_key(dev, BTN_A, data[1] & 0x04); | ||
129 | input_report_key(dev, BTN_B, data[1] & 0x08); | ||
130 | input_report_key(dev, BTN_C, data[1] & 0x10); | ||
131 | input_report_key(dev, BTN_MODE, data[1] & 0x20); | ||
132 | break; | ||
133 | |||
134 | case 'E': /* Device error */ | ||
135 | spaceball->data[spaceball->idx - 1] = 0; | ||
136 | printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1); | ||
137 | break; | ||
138 | |||
139 | case '?': /* Bad command packet */ | ||
140 | spaceball->data[spaceball->idx - 1] = 0; | ||
141 | printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1); | ||
142 | break; | ||
143 | } | ||
144 | |||
145 | input_sync(dev); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, | ||
150 | * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which | ||
151 | * can occur in the axis values. | ||
152 | */ | ||
153 | |||
154 | static irqreturn_t spaceball_interrupt(struct serio *serio, | ||
155 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
156 | { | ||
157 | struct spaceball *spaceball = serio_get_drvdata(serio); | ||
158 | |||
159 | switch (data) { | ||
160 | case 0xd: | ||
161 | spaceball_process_packet(spaceball, regs); | ||
162 | spaceball->idx = 0; | ||
163 | spaceball->escape = 0; | ||
164 | break; | ||
165 | case '^': | ||
166 | if (!spaceball->escape) { | ||
167 | spaceball->escape = 1; | ||
168 | break; | ||
169 | } | ||
170 | spaceball->escape = 0; | ||
171 | case 'M': | ||
172 | case 'Q': | ||
173 | case 'S': | ||
174 | if (spaceball->escape) { | ||
175 | spaceball->escape = 0; | ||
176 | data &= 0x1f; | ||
177 | } | ||
178 | default: | ||
179 | if (spaceball->escape) | ||
180 | spaceball->escape = 0; | ||
181 | if (spaceball->idx < SPACEBALL_MAX_LENGTH) | ||
182 | spaceball->data[spaceball->idx++] = data; | ||
183 | break; | ||
184 | } | ||
185 | return IRQ_HANDLED; | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * spaceball_disconnect() is the opposite of spaceball_connect() | ||
190 | */ | ||
191 | |||
192 | static void spaceball_disconnect(struct serio *serio) | ||
193 | { | ||
194 | struct spaceball* spaceball = serio_get_drvdata(serio); | ||
195 | |||
196 | input_unregister_device(&spaceball->dev); | ||
197 | serio_close(serio); | ||
198 | serio_set_drvdata(serio, NULL); | ||
199 | kfree(spaceball); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * spaceball_connect() is the routine that is called when someone adds a | ||
204 | * new serio device that supports Spaceball protocol and registers it as | ||
205 | * an input device. | ||
206 | */ | ||
207 | |||
208 | static int spaceball_connect(struct serio *serio, struct serio_driver *drv) | ||
209 | { | ||
210 | struct spaceball *spaceball; | ||
211 | int i, t, id; | ||
212 | int err; | ||
213 | |||
214 | if ((id = serio->id.id) > SPACEBALL_MAX_ID) | ||
215 | return -ENODEV; | ||
216 | |||
217 | if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL))) | ||
218 | return - ENOMEM; | ||
219 | |||
220 | memset(spaceball, 0, sizeof(struct spaceball)); | ||
221 | |||
222 | spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
223 | |||
224 | switch (id) { | ||
225 | case SPACEBALL_4000FLX: | ||
226 | case SPACEBALL_4000FLX_L: | ||
227 | spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9); | ||
228 | spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); | ||
229 | default: | ||
230 | spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | ||
231 | | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8); | ||
232 | case SPACEBALL_3003C: | ||
233 | spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); | ||
234 | } | ||
235 | |||
236 | for (i = 0; i < 6; i++) { | ||
237 | t = spaceball_axes[i]; | ||
238 | set_bit(t, spaceball->dev.absbit); | ||
239 | spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600; | ||
240 | spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600; | ||
241 | spaceball->dev.absflat[t] = i < 3 ? 40 : 8; | ||
242 | spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2; | ||
243 | } | ||
244 | |||
245 | spaceball->serio = serio; | ||
246 | spaceball->dev.private = spaceball; | ||
247 | |||
248 | sprintf(spaceball->phys, "%s/input0", serio->phys); | ||
249 | |||
250 | init_input_dev(&spaceball->dev); | ||
251 | spaceball->dev.name = spaceball_names[id]; | ||
252 | spaceball->dev.phys = spaceball->phys; | ||
253 | spaceball->dev.id.bustype = BUS_RS232; | ||
254 | spaceball->dev.id.vendor = SERIO_SPACEBALL; | ||
255 | spaceball->dev.id.product = id; | ||
256 | spaceball->dev.id.version = 0x0100; | ||
257 | spaceball->dev.dev = &serio->dev; | ||
258 | |||
259 | serio_set_drvdata(serio, spaceball); | ||
260 | |||
261 | err = serio_open(serio, drv); | ||
262 | if (err) { | ||
263 | serio_set_drvdata(serio, NULL); | ||
264 | kfree(spaceball); | ||
265 | return err; | ||
266 | } | ||
267 | |||
268 | input_register_device(&spaceball->dev); | ||
269 | |||
270 | printk(KERN_INFO "input: %s on serio%s\n", | ||
271 | spaceball_names[id], serio->phys); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * The serio driver structure. | ||
278 | */ | ||
279 | |||
280 | static struct serio_device_id spaceball_serio_ids[] = { | ||
281 | { | ||
282 | .type = SERIO_RS232, | ||
283 | .proto = SERIO_SPACEBALL, | ||
284 | .id = SERIO_ANY, | ||
285 | .extra = SERIO_ANY, | ||
286 | }, | ||
287 | { 0 } | ||
288 | }; | ||
289 | |||
290 | MODULE_DEVICE_TABLE(serio, spaceball_serio_ids); | ||
291 | |||
292 | static struct serio_driver spaceball_drv = { | ||
293 | .driver = { | ||
294 | .name = "spaceball", | ||
295 | }, | ||
296 | .description = DRIVER_DESC, | ||
297 | .id_table = spaceball_serio_ids, | ||
298 | .interrupt = spaceball_interrupt, | ||
299 | .connect = spaceball_connect, | ||
300 | .disconnect = spaceball_disconnect, | ||
301 | }; | ||
302 | |||
303 | /* | ||
304 | * The functions for inserting/removing us as a module. | ||
305 | */ | ||
306 | |||
307 | static int __init spaceball_init(void) | ||
308 | { | ||
309 | serio_register_driver(&spaceball_drv); | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static void __exit spaceball_exit(void) | ||
314 | { | ||
315 | serio_unregister_driver(&spaceball_drv); | ||
316 | } | ||
317 | |||
318 | module_init(spaceball_init); | ||
319 | module_exit(spaceball_exit); | ||
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c new file mode 100644 index 000000000000..c76cf8ff29c0 --- /dev/null +++ b/drivers/input/joystick/spaceorb.c | |||
@@ -0,0 +1,263 @@ | |||
1 | /* | ||
2 | * $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * David Thompson | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/input.h> | ||
39 | #include <linux/serio.h> | ||
40 | |||
41 | #define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver" | ||
42 | |||
43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
44 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | |||
47 | /* | ||
48 | * Constants. | ||
49 | */ | ||
50 | |||
51 | #define SPACEORB_MAX_LENGTH 64 | ||
52 | |||
53 | static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A }; | ||
54 | static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; | ||
55 | static char *spaceorb_name = "SpaceTec SpaceOrb 360 / Avenger"; | ||
56 | |||
57 | /* | ||
58 | * Per-Orb data. | ||
59 | */ | ||
60 | |||
61 | struct spaceorb { | ||
62 | struct input_dev dev; | ||
63 | struct serio *serio; | ||
64 | int idx; | ||
65 | unsigned char data[SPACEORB_MAX_LENGTH]; | ||
66 | char phys[32]; | ||
67 | }; | ||
68 | |||
69 | static unsigned char spaceorb_xor[] = "SpaceWare"; | ||
70 | |||
71 | static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout", | ||
72 | "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; | ||
73 | |||
74 | /* | ||
75 | * spaceorb_process_packet() decodes packets the driver receives from the | ||
76 | * SpaceOrb. | ||
77 | */ | ||
78 | |||
79 | static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *regs) | ||
80 | { | ||
81 | struct input_dev *dev = &spaceorb->dev; | ||
82 | unsigned char *data = spaceorb->data; | ||
83 | unsigned char c = 0; | ||
84 | int axes[6]; | ||
85 | int i; | ||
86 | |||
87 | if (spaceorb->idx < 2) return; | ||
88 | for (i = 0; i < spaceorb->idx; i++) c ^= data[i]; | ||
89 | if (c) return; | ||
90 | |||
91 | input_regs(dev, regs); | ||
92 | |||
93 | switch (data[0]) { | ||
94 | |||
95 | case 'R': /* Reset packet */ | ||
96 | spaceorb->data[spaceorb->idx - 1] = 0; | ||
97 | for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); | ||
98 | printk(KERN_INFO "input: %s [%s] on %s\n", | ||
99 | spaceorb_name, spaceorb->data + i, spaceorb->serio->phys); | ||
100 | break; | ||
101 | |||
102 | case 'D': /* Ball + button data */ | ||
103 | if (spaceorb->idx != 12) return; | ||
104 | for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; | ||
105 | axes[0] = ( data[2] << 3) | (data[ 3] >> 4); | ||
106 | axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1); | ||
107 | axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5); | ||
108 | axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2); | ||
109 | axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6); | ||
110 | axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3); | ||
111 | for (i = 0; i < 6; i++) | ||
112 | input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0)); | ||
113 | for (i = 0; i < 6; i++) | ||
114 | input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1); | ||
115 | break; | ||
116 | |||
117 | case 'K': /* Button data */ | ||
118 | if (spaceorb->idx != 5) return; | ||
119 | for (i = 0; i < 7; i++) | ||
120 | input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1); | ||
121 | |||
122 | break; | ||
123 | |||
124 | case 'E': /* Error packet */ | ||
125 | if (spaceorb->idx != 4) return; | ||
126 | printk(KERN_ERR "joy-spaceorb: Device error. [ "); | ||
127 | for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]); | ||
128 | printk("]\n"); | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | input_sync(dev); | ||
133 | } | ||
134 | |||
135 | static irqreturn_t spaceorb_interrupt(struct serio *serio, | ||
136 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
137 | { | ||
138 | struct spaceorb* spaceorb = serio_get_drvdata(serio); | ||
139 | |||
140 | if (~data & 0x80) { | ||
141 | if (spaceorb->idx) spaceorb_process_packet(spaceorb, regs); | ||
142 | spaceorb->idx = 0; | ||
143 | } | ||
144 | if (spaceorb->idx < SPACEORB_MAX_LENGTH) | ||
145 | spaceorb->data[spaceorb->idx++] = data & 0x7f; | ||
146 | return IRQ_HANDLED; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * spaceorb_disconnect() is the opposite of spaceorb_connect() | ||
151 | */ | ||
152 | |||
153 | static void spaceorb_disconnect(struct serio *serio) | ||
154 | { | ||
155 | struct spaceorb* spaceorb = serio_get_drvdata(serio); | ||
156 | |||
157 | input_unregister_device(&spaceorb->dev); | ||
158 | serio_close(serio); | ||
159 | serio_set_drvdata(serio, NULL); | ||
160 | kfree(spaceorb); | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * spaceorb_connect() is the routine that is called when someone adds a | ||
165 | * new serio device that supports SpaceOrb/Avenger protocol and registers | ||
166 | * it as an input device. | ||
167 | */ | ||
168 | |||
169 | static int spaceorb_connect(struct serio *serio, struct serio_driver *drv) | ||
170 | { | ||
171 | struct spaceorb *spaceorb; | ||
172 | int i, t; | ||
173 | int err; | ||
174 | |||
175 | if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL))) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | memset(spaceorb, 0, sizeof(struct spaceorb)); | ||
179 | |||
180 | spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
181 | |||
182 | for (i = 0; i < 6; i++) | ||
183 | set_bit(spaceorb_buttons[i], spaceorb->dev.keybit); | ||
184 | |||
185 | for (i = 0; i < 6; i++) { | ||
186 | t = spaceorb_axes[i]; | ||
187 | set_bit(t, spaceorb->dev.absbit); | ||
188 | spaceorb->dev.absmin[t] = -508; | ||
189 | spaceorb->dev.absmax[t] = 508; | ||
190 | } | ||
191 | |||
192 | spaceorb->serio = serio; | ||
193 | spaceorb->dev.private = spaceorb; | ||
194 | |||
195 | sprintf(spaceorb->phys, "%s/input0", serio->phys); | ||
196 | |||
197 | init_input_dev(&spaceorb->dev); | ||
198 | spaceorb->dev.name = spaceorb_name; | ||
199 | spaceorb->dev.phys = spaceorb->phys; | ||
200 | spaceorb->dev.id.bustype = BUS_RS232; | ||
201 | spaceorb->dev.id.vendor = SERIO_SPACEORB; | ||
202 | spaceorb->dev.id.product = 0x0001; | ||
203 | spaceorb->dev.id.version = 0x0100; | ||
204 | spaceorb->dev.dev = &serio->dev; | ||
205 | |||
206 | serio_set_drvdata(serio, spaceorb); | ||
207 | |||
208 | err = serio_open(serio, drv); | ||
209 | if (err) { | ||
210 | serio_set_drvdata(serio, NULL); | ||
211 | kfree(spaceorb); | ||
212 | return err; | ||
213 | } | ||
214 | |||
215 | input_register_device(&spaceorb->dev); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * The serio driver structure. | ||
222 | */ | ||
223 | |||
224 | static struct serio_device_id spaceorb_serio_ids[] = { | ||
225 | { | ||
226 | .type = SERIO_RS232, | ||
227 | .proto = SERIO_SPACEORB, | ||
228 | .id = SERIO_ANY, | ||
229 | .extra = SERIO_ANY, | ||
230 | }, | ||
231 | { 0 } | ||
232 | }; | ||
233 | |||
234 | MODULE_DEVICE_TABLE(serio, spaceorb_serio_ids); | ||
235 | |||
236 | static struct serio_driver spaceorb_drv = { | ||
237 | .driver = { | ||
238 | .name = "spaceorb", | ||
239 | }, | ||
240 | .description = DRIVER_DESC, | ||
241 | .id_table = spaceorb_serio_ids, | ||
242 | .interrupt = spaceorb_interrupt, | ||
243 | .connect = spaceorb_connect, | ||
244 | .disconnect = spaceorb_disconnect, | ||
245 | }; | ||
246 | |||
247 | /* | ||
248 | * The functions for inserting/removing us as a module. | ||
249 | */ | ||
250 | |||
251 | static int __init spaceorb_init(void) | ||
252 | { | ||
253 | serio_register_driver(&spaceorb_drv); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static void __exit spaceorb_exit(void) | ||
258 | { | ||
259 | serio_unregister_driver(&spaceorb_drv); | ||
260 | } | ||
261 | |||
262 | module_init(spaceorb_init); | ||
263 | module_exit(spaceorb_exit); | ||
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c new file mode 100644 index 000000000000..6f6e6753d590 --- /dev/null +++ b/drivers/input/joystick/stinger.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * $Id: stinger.c,v 1.10 2002/01/22 20:29:31 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * Copyright (c) 2000 Mark Fletcher | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Gravis Stinger gamepad driver for Linux | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free warftware; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * Should you need to contact me, the author, you can do so either by | ||
28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
30 | */ | ||
31 | |||
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 "Gravis Stinger gamepad driver" | ||
40 | |||
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
42 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | /* | ||
46 | * Constants. | ||
47 | */ | ||
48 | |||
49 | #define STINGER_MAX_LENGTH 8 | ||
50 | |||
51 | static char *stinger_name = "Gravis Stinger"; | ||
52 | |||
53 | /* | ||
54 | * Per-Stinger data. | ||
55 | */ | ||
56 | |||
57 | struct stinger { | ||
58 | struct input_dev dev; | ||
59 | int idx; | ||
60 | unsigned char data[STINGER_MAX_LENGTH]; | ||
61 | char phys[32]; | ||
62 | }; | ||
63 | |||
64 | /* | ||
65 | * stinger_process_packet() decodes packets the driver receives from the | ||
66 | * Stinger. It updates the data accordingly. | ||
67 | */ | ||
68 | |||
69 | static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs) | ||
70 | { | ||
71 | struct input_dev *dev = &stinger->dev; | ||
72 | unsigned char *data = stinger->data; | ||
73 | |||
74 | if (!stinger->idx) return; | ||
75 | |||
76 | input_regs(dev, regs); | ||
77 | |||
78 | input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5)); | ||
79 | input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4)); | ||
80 | input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3)); | ||
81 | input_report_key(dev, BTN_X, ((data[0] & 0x04) >> 2)); | ||
82 | input_report_key(dev, BTN_Y, ((data[3] & 0x20) >> 5)); | ||
83 | input_report_key(dev, BTN_Z, ((data[3] & 0x10) >> 4)); | ||
84 | input_report_key(dev, BTN_TL, ((data[3] & 0x08) >> 3)); | ||
85 | input_report_key(dev, BTN_TR, ((data[3] & 0x04) >> 2)); | ||
86 | input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1)); | ||
87 | input_report_key(dev, BTN_START, (data[3] & 0x01)); | ||
88 | |||
89 | input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6)); | ||
90 | input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F)); | ||
91 | |||
92 | input_sync(dev); | ||
93 | |||
94 | return; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * stinger_interrupt() is called by the low level driver when characters | ||
99 | * are ready for us. We then buffer them for further processing, or call the | ||
100 | * packet processing routine. | ||
101 | */ | ||
102 | |||
103 | static irqreturn_t stinger_interrupt(struct serio *serio, | ||
104 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
105 | { | ||
106 | struct stinger *stinger = serio_get_drvdata(serio); | ||
107 | |||
108 | /* All Stinger packets are 4 bytes */ | ||
109 | |||
110 | if (stinger->idx < STINGER_MAX_LENGTH) | ||
111 | stinger->data[stinger->idx++] = data; | ||
112 | |||
113 | if (stinger->idx == 4) { | ||
114 | stinger_process_packet(stinger, regs); | ||
115 | stinger->idx = 0; | ||
116 | } | ||
117 | |||
118 | return IRQ_HANDLED; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * stinger_disconnect() is the opposite of stinger_connect() | ||
123 | */ | ||
124 | |||
125 | static void stinger_disconnect(struct serio *serio) | ||
126 | { | ||
127 | struct stinger *stinger = serio_get_drvdata(serio); | ||
128 | |||
129 | input_unregister_device(&stinger->dev); | ||
130 | serio_close(serio); | ||
131 | serio_set_drvdata(serio, NULL); | ||
132 | kfree(stinger); | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * stinger_connect() is the routine that is called when someone adds a | ||
137 | * new serio device that supports Stinger protocol and registers it as | ||
138 | * an input device. | ||
139 | */ | ||
140 | |||
141 | static int stinger_connect(struct serio *serio, struct serio_driver *drv) | ||
142 | { | ||
143 | struct stinger *stinger; | ||
144 | int i; | ||
145 | int err; | ||
146 | |||
147 | if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL))) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | memset(stinger, 0, sizeof(struct stinger)); | ||
151 | |||
152 | stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
153 | stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \ | ||
154 | BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \ | ||
155 | BIT(BTN_START) | BIT(BTN_SELECT); | ||
156 | stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | ||
157 | |||
158 | sprintf(stinger->phys, "%s/serio0", serio->phys); | ||
159 | |||
160 | init_input_dev(&stinger->dev); | ||
161 | stinger->dev.name = stinger_name; | ||
162 | stinger->dev.phys = stinger->phys; | ||
163 | stinger->dev.id.bustype = BUS_RS232; | ||
164 | stinger->dev.id.vendor = SERIO_STINGER; | ||
165 | stinger->dev.id.product = 0x0001; | ||
166 | stinger->dev.id.version = 0x0100; | ||
167 | stinger->dev.dev = &serio->dev; | ||
168 | |||
169 | for (i = 0; i < 2; i++) { | ||
170 | stinger->dev.absmax[ABS_X+i] = 64; | ||
171 | stinger->dev.absmin[ABS_X+i] = -64; | ||
172 | stinger->dev.absflat[ABS_X+i] = 4; | ||
173 | } | ||
174 | |||
175 | stinger->dev.private = stinger; | ||
176 | |||
177 | serio_set_drvdata(serio, stinger); | ||
178 | |||
179 | err = serio_open(serio, drv); | ||
180 | if (err) { | ||
181 | serio_set_drvdata(serio, NULL); | ||
182 | kfree(stinger); | ||
183 | return err; | ||
184 | } | ||
185 | |||
186 | input_register_device(&stinger->dev); | ||
187 | |||
188 | printk(KERN_INFO "input: %s on %s\n", stinger_name, serio->phys); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * The serio driver structure. | ||
195 | */ | ||
196 | |||
197 | static struct serio_device_id stinger_serio_ids[] = { | ||
198 | { | ||
199 | .type = SERIO_RS232, | ||
200 | .proto = SERIO_STINGER, | ||
201 | .id = SERIO_ANY, | ||
202 | .extra = SERIO_ANY, | ||
203 | }, | ||
204 | { 0 } | ||
205 | }; | ||
206 | |||
207 | MODULE_DEVICE_TABLE(serio, stinger_serio_ids); | ||
208 | |||
209 | static struct serio_driver stinger_drv = { | ||
210 | .driver = { | ||
211 | .name = "stinger", | ||
212 | }, | ||
213 | .description = DRIVER_DESC, | ||
214 | .id_table = stinger_serio_ids, | ||
215 | .interrupt = stinger_interrupt, | ||
216 | .connect = stinger_connect, | ||
217 | .disconnect = stinger_disconnect, | ||
218 | }; | ||
219 | |||
220 | /* | ||
221 | * The functions for inserting/removing us as a module. | ||
222 | */ | ||
223 | |||
224 | static int __init stinger_init(void) | ||
225 | { | ||
226 | serio_register_driver(&stinger_drv); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static void __exit stinger_exit(void) | ||
231 | { | ||
232 | serio_unregister_driver(&stinger_drv); | ||
233 | } | ||
234 | |||
235 | module_init(stinger_init); | ||
236 | module_exit(stinger_exit); | ||
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c new file mode 100644 index 000000000000..aaee52ceb920 --- /dev/null +++ b/drivers/input/joystick/tmdc.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * $Id: tmdc.c,v 1.31 2002/01/22 20:29:52 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1998-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Trystan Larey-Williams | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * ThrustMaster DirectConnect (BSP) joystick family driver for Linux | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/delay.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/gameport.h> | ||
40 | #include <linux/input.h> | ||
41 | |||
42 | #define DRIVER_DESC "ThrustMaster DirectConnect joystick driver" | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
45 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | #define TMDC_MAX_START 600 /* 600 us */ | ||
49 | #define TMDC_MAX_STROBE 60 /* 60 us */ | ||
50 | #define TMDC_MAX_LENGTH 13 | ||
51 | |||
52 | #define TMDC_MODE_M3DI 1 | ||
53 | #define TMDC_MODE_3DRP 3 | ||
54 | #define TMDC_MODE_AT 4 | ||
55 | #define TMDC_MODE_FM 8 | ||
56 | #define TMDC_MODE_FGP 163 | ||
57 | |||
58 | #define TMDC_BYTE_ID 10 | ||
59 | #define TMDC_BYTE_REV 11 | ||
60 | #define TMDC_BYTE_DEF 12 | ||
61 | |||
62 | #define TMDC_ABS 7 | ||
63 | #define TMDC_ABS_HAT 4 | ||
64 | #define TMDC_BTN 16 | ||
65 | |||
66 | static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; | ||
67 | static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; | ||
68 | |||
69 | static signed char tmdc_abs[TMDC_ABS] = | ||
70 | { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; | ||
71 | static signed char tmdc_abs_hat[TMDC_ABS_HAT] = | ||
72 | { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; | ||
73 | static signed char tmdc_abs_at[TMDC_ABS] = | ||
74 | { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; | ||
75 | static signed char tmdc_abs_fm[TMDC_ABS] = | ||
76 | { ABS_RX, ABS_RY, ABS_X, ABS_Y }; | ||
77 | |||
78 | static short tmdc_btn_pad[TMDC_BTN] = | ||
79 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; | ||
80 | static short tmdc_btn_joy[TMDC_BTN] = | ||
81 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, | ||
82 | BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; | ||
83 | static short tmdc_btn_fm[TMDC_BTN] = | ||
84 | { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; | ||
85 | static short tmdc_btn_at[TMDC_BTN] = | ||
86 | { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, | ||
87 | BTN_BASE3, BTN_BASE2, BTN_BASE }; | ||
88 | |||
89 | static struct { | ||
90 | int x; | ||
91 | int y; | ||
92 | } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; | ||
93 | |||
94 | struct tmdc { | ||
95 | struct gameport *gameport; | ||
96 | struct input_dev dev[2]; | ||
97 | char name[2][64]; | ||
98 | char phys[2][32]; | ||
99 | int mode[2]; | ||
100 | signed char *abs[2]; | ||
101 | short *btn[2]; | ||
102 | unsigned char absc[2]; | ||
103 | unsigned char btnc[2][4]; | ||
104 | unsigned char btno[2][4]; | ||
105 | int reads; | ||
106 | int bads; | ||
107 | unsigned char exists; | ||
108 | }; | ||
109 | |||
110 | /* | ||
111 | * tmdc_read_packet() reads a ThrustMaster packet. | ||
112 | */ | ||
113 | |||
114 | static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH]) | ||
115 | { | ||
116 | unsigned char u, v, w, x; | ||
117 | unsigned long flags; | ||
118 | int i[2], j[2], t[2], p, k; | ||
119 | |||
120 | p = gameport_time(gameport, TMDC_MAX_STROBE); | ||
121 | |||
122 | for (k = 0; k < 2; k++) { | ||
123 | t[k] = gameport_time(gameport, TMDC_MAX_START); | ||
124 | i[k] = j[k] = 0; | ||
125 | } | ||
126 | |||
127 | local_irq_save(flags); | ||
128 | gameport_trigger(gameport); | ||
129 | |||
130 | w = gameport_read(gameport) >> 4; | ||
131 | |||
132 | do { | ||
133 | x = w; | ||
134 | w = gameport_read(gameport) >> 4; | ||
135 | |||
136 | for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) { | ||
137 | if (~v & u & 2) { | ||
138 | if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue; | ||
139 | t[k] = p; | ||
140 | if (j[k] == 0) { /* Start bit */ | ||
141 | if (~v & 1) t[k] = 0; | ||
142 | data[k][i[k]] = 0; j[k]++; continue; | ||
143 | } | ||
144 | if (j[k] == 9) { /* Stop bit */ | ||
145 | if (v & 1) t[k] = 0; | ||
146 | j[k] = 0; i[k]++; continue; | ||
147 | } | ||
148 | data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */ | ||
149 | } | ||
150 | t[k]--; | ||
151 | } | ||
152 | } while (t[0] > 0 || t[1] > 0); | ||
153 | |||
154 | local_irq_restore(flags); | ||
155 | |||
156 | return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * tmdc_poll() reads and analyzes ThrustMaster joystick data. | ||
161 | */ | ||
162 | |||
163 | static void tmdc_poll(struct gameport *gameport) | ||
164 | { | ||
165 | unsigned char data[2][TMDC_MAX_LENGTH]; | ||
166 | struct tmdc *tmdc = gameport_get_drvdata(gameport); | ||
167 | struct input_dev *dev; | ||
168 | unsigned char r, bad = 0; | ||
169 | int i, j, k, l; | ||
170 | |||
171 | tmdc->reads++; | ||
172 | |||
173 | if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) | ||
174 | bad = 1; | ||
175 | else | ||
176 | |||
177 | for (j = 0; j < 2; j++) | ||
178 | if (r & (1 << j) & tmdc->exists) { | ||
179 | |||
180 | if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) { | ||
181 | bad = 1; | ||
182 | continue; | ||
183 | } | ||
184 | |||
185 | dev = tmdc->dev + j; | ||
186 | |||
187 | for (i = 0; i < tmdc->absc[j]; i++) { | ||
188 | if (tmdc->abs[j][i] < 0) continue; | ||
189 | input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]); | ||
190 | } | ||
191 | |||
192 | switch (tmdc->mode[j]) { | ||
193 | |||
194 | case TMDC_MODE_M3DI: | ||
195 | |||
196 | i = tmdc_byte_d[0]; | ||
197 | input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1)); | ||
198 | input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1)); | ||
199 | break; | ||
200 | |||
201 | case TMDC_MODE_AT: | ||
202 | |||
203 | i = tmdc_byte_a[3]; | ||
204 | input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x); | ||
205 | input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y); | ||
206 | break; | ||
207 | |||
208 | } | ||
209 | |||
210 | for (k = l = 0; k < 4; k++) { | ||
211 | for (i = 0; i < tmdc->btnc[j][k]; i++) | ||
212 | input_report_key(dev, tmdc->btn[j][i + l], | ||
213 | ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1)); | ||
214 | l += tmdc->btnc[j][k]; | ||
215 | } | ||
216 | |||
217 | input_sync(dev); | ||
218 | } | ||
219 | |||
220 | tmdc->bads += bad; | ||
221 | } | ||
222 | |||
223 | static int tmdc_open(struct input_dev *dev) | ||
224 | { | ||
225 | struct tmdc *tmdc = dev->private; | ||
226 | |||
227 | gameport_start_polling(tmdc->gameport); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static void tmdc_close(struct input_dev *dev) | ||
232 | { | ||
233 | struct tmdc *tmdc = dev->private; | ||
234 | |||
235 | gameport_stop_polling(tmdc->gameport); | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * tmdc_probe() probes for ThrustMaster type joysticks. | ||
240 | */ | ||
241 | |||
242 | static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) | ||
243 | { | ||
244 | static struct models { | ||
245 | unsigned char id; | ||
246 | char *name; | ||
247 | char abs; | ||
248 | char hats; | ||
249 | char btnc[4]; | ||
250 | char btno[4]; | ||
251 | signed char *axes; | ||
252 | short *buttons; | ||
253 | } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, | ||
254 | { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, | ||
255 | { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, | ||
256 | { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, | ||
257 | { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, | ||
258 | { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }}; | ||
259 | |||
260 | unsigned char data[2][TMDC_MAX_LENGTH]; | ||
261 | struct tmdc *tmdc; | ||
262 | int i, j, k, l, m; | ||
263 | int err; | ||
264 | |||
265 | if (!(tmdc = kcalloc(1, sizeof(struct tmdc), GFP_KERNEL))) | ||
266 | return -ENOMEM; | ||
267 | |||
268 | tmdc->gameport = gameport; | ||
269 | |||
270 | gameport_set_drvdata(gameport, tmdc); | ||
271 | |||
272 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | ||
273 | if (err) | ||
274 | goto fail1; | ||
275 | |||
276 | if (!(tmdc->exists = tmdc_read_packet(gameport, data))) { | ||
277 | err = -ENODEV; | ||
278 | goto fail2; | ||
279 | } | ||
280 | |||
281 | gameport_set_poll_handler(gameport, tmdc_poll); | ||
282 | gameport_set_poll_interval(gameport, 20); | ||
283 | |||
284 | for (j = 0; j < 2; j++) | ||
285 | if (tmdc->exists & (1 << j)) { | ||
286 | |||
287 | tmdc->mode[j] = data[j][TMDC_BYTE_ID]; | ||
288 | |||
289 | for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++); | ||
290 | |||
291 | tmdc->abs[j] = models[m].axes; | ||
292 | tmdc->btn[j] = models[m].buttons; | ||
293 | |||
294 | if (!models[m].id) { | ||
295 | models[m].abs = data[j][TMDC_BYTE_DEF] >> 4; | ||
296 | for (k = 0; k < 4; k++) | ||
297 | models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0; | ||
298 | } | ||
299 | |||
300 | tmdc->absc[j] = models[m].abs; | ||
301 | for (k = 0; k < 4; k++) { | ||
302 | tmdc->btnc[j][k] = models[m].btnc[k]; | ||
303 | tmdc->btno[j][k] = models[m].btno[k]; | ||
304 | } | ||
305 | |||
306 | sprintf(tmdc->name[j], models[m].name, models[m].abs, | ||
307 | (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]); | ||
308 | |||
309 | sprintf(tmdc->phys[j], "%s/input%d", gameport->phys, j); | ||
310 | |||
311 | tmdc->dev[j].private = tmdc; | ||
312 | tmdc->dev[j].open = tmdc_open; | ||
313 | tmdc->dev[j].close = tmdc_close; | ||
314 | |||
315 | tmdc->dev[j].name = tmdc->name[j]; | ||
316 | tmdc->dev[j].phys = tmdc->phys[j]; | ||
317 | tmdc->dev[j].id.bustype = BUS_GAMEPORT; | ||
318 | tmdc->dev[j].id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; | ||
319 | tmdc->dev[j].id.product = models[m].id; | ||
320 | tmdc->dev[j].id.version = 0x0100; | ||
321 | |||
322 | tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
323 | |||
324 | for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) | ||
325 | if (tmdc->abs[j][i] >= 0) | ||
326 | input_set_abs_params(&tmdc->dev[j], tmdc->abs[j][i], 8, 248, 2, 4); | ||
327 | |||
328 | for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) | ||
329 | input_set_abs_params(&tmdc->dev[j], tmdc_abs_hat[i], -1, 1, 0, 0); | ||
330 | |||
331 | |||
332 | for (k = l = 0; k < 4; k++) { | ||
333 | for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++) | ||
334 | set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit); | ||
335 | l += models[m].btnc[k]; | ||
336 | } | ||
337 | |||
338 | input_register_device(tmdc->dev + j); | ||
339 | printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys); | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | |||
344 | fail2: gameport_close(gameport); | ||
345 | fail1: gameport_set_drvdata(gameport, NULL); | ||
346 | kfree(tmdc); | ||
347 | return err; | ||
348 | } | ||
349 | |||
350 | static void tmdc_disconnect(struct gameport *gameport) | ||
351 | { | ||
352 | struct tmdc *tmdc = gameport_get_drvdata(gameport); | ||
353 | int i; | ||
354 | |||
355 | for (i = 0; i < 2; i++) | ||
356 | if (tmdc->exists & (1 << i)) | ||
357 | input_unregister_device(tmdc->dev + i); | ||
358 | gameport_close(gameport); | ||
359 | gameport_set_drvdata(gameport, NULL); | ||
360 | kfree(tmdc); | ||
361 | } | ||
362 | |||
363 | static struct gameport_driver tmdc_drv = { | ||
364 | .driver = { | ||
365 | .name = "tmdc", | ||
366 | }, | ||
367 | .description = DRIVER_DESC, | ||
368 | .connect = tmdc_connect, | ||
369 | .disconnect = tmdc_disconnect, | ||
370 | }; | ||
371 | |||
372 | static int __init tmdc_init(void) | ||
373 | { | ||
374 | gameport_register_driver(&tmdc_drv); | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static void __exit tmdc_exit(void) | ||
379 | { | ||
380 | gameport_unregister_driver(&tmdc_drv); | ||
381 | } | ||
382 | |||
383 | module_init(tmdc_init); | ||
384 | module_exit(tmdc_exit); | ||
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c new file mode 100644 index 000000000000..dd88b9cb49fa --- /dev/null +++ b/drivers/input/joystick/turbografx.c | |||
@@ -0,0 +1,258 @@ | |||
1 | /* | ||
2 | * $Id: turbografx.c,v 1.14 2002/01/22 20:30:39 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1998-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Steffen Schwenke | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * TurboGraFX parallel port interface driver for Linux. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/parport.h> | ||
36 | #include <linux/input.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/moduleparam.h> | ||
39 | #include <linux/init.h> | ||
40 | |||
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
42 | MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; | ||
46 | static int tgfx_nargs __initdata = 0; | ||
47 | module_param_array_named(map, tgfx, int, &tgfx_nargs, 0); | ||
48 | MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>"); | ||
49 | |||
50 | static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; | ||
51 | static int tgfx_nargs_2 __initdata = 0; | ||
52 | module_param_array_named(map2, tgfx_2, int, &tgfx_nargs_2, 0); | ||
53 | MODULE_PARM_DESC(map2, "Describes second set of devices"); | ||
54 | |||
55 | static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; | ||
56 | static int tgfx_nargs_3 __initdata = 0; | ||
57 | module_param_array_named(map3, tgfx_3, int, &tgfx_nargs_3, 0); | ||
58 | MODULE_PARM_DESC(map3, "Describes third set of devices"); | ||
59 | |||
60 | __obsolete_setup("tgfx="); | ||
61 | __obsolete_setup("tgfx_2="); | ||
62 | __obsolete_setup("tgfx_3="); | ||
63 | |||
64 | #define TGFX_REFRESH_TIME HZ/100 /* 10 ms */ | ||
65 | |||
66 | #define TGFX_TRIGGER 0x08 | ||
67 | #define TGFX_UP 0x10 | ||
68 | #define TGFX_DOWN 0x20 | ||
69 | #define TGFX_LEFT 0x40 | ||
70 | #define TGFX_RIGHT 0x80 | ||
71 | |||
72 | #define TGFX_THUMB 0x02 | ||
73 | #define TGFX_THUMB2 0x04 | ||
74 | #define TGFX_TOP 0x01 | ||
75 | #define TGFX_TOP2 0x08 | ||
76 | |||
77 | static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; | ||
78 | static char *tgfx_name = "TurboGraFX Multisystem joystick"; | ||
79 | |||
80 | static struct tgfx { | ||
81 | struct pardevice *pd; | ||
82 | struct timer_list timer; | ||
83 | struct input_dev dev[7]; | ||
84 | char phys[7][32]; | ||
85 | int sticks; | ||
86 | int used; | ||
87 | } *tgfx_base[3]; | ||
88 | |||
89 | /* | ||
90 | * tgfx_timer() reads and analyzes TurboGraFX joystick data. | ||
91 | */ | ||
92 | |||
93 | static void tgfx_timer(unsigned long private) | ||
94 | { | ||
95 | struct tgfx *tgfx = (void *) private; | ||
96 | struct input_dev *dev; | ||
97 | int data1, data2, i; | ||
98 | |||
99 | for (i = 0; i < 7; i++) | ||
100 | if (tgfx->sticks & (1 << i)) { | ||
101 | |||
102 | dev = tgfx->dev + i; | ||
103 | |||
104 | parport_write_data(tgfx->pd->port, ~(1 << i)); | ||
105 | data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; | ||
106 | data2 = parport_read_control(tgfx->pd->port) ^ 0x04; /* CAVEAT parport */ | ||
107 | |||
108 | input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT)); | ||
109 | input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP )); | ||
110 | |||
111 | input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER)); | ||
112 | input_report_key(dev, BTN_THUMB, (data2 & TGFX_THUMB )); | ||
113 | input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 )); | ||
114 | input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP )); | ||
115 | input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 )); | ||
116 | |||
117 | input_sync(dev); | ||
118 | } | ||
119 | |||
120 | mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); | ||
121 | } | ||
122 | |||
123 | static int tgfx_open(struct input_dev *dev) | ||
124 | { | ||
125 | struct tgfx *tgfx = dev->private; | ||
126 | if (!tgfx->used++) { | ||
127 | parport_claim(tgfx->pd); | ||
128 | parport_write_control(tgfx->pd->port, 0x04); | ||
129 | mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); | ||
130 | } | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static void tgfx_close(struct input_dev *dev) | ||
135 | { | ||
136 | struct tgfx *tgfx = dev->private; | ||
137 | if (!--tgfx->used) { | ||
138 | del_timer(&tgfx->timer); | ||
139 | parport_write_control(tgfx->pd->port, 0x00); | ||
140 | parport_release(tgfx->pd); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * tgfx_probe() probes for tg gamepads. | ||
146 | */ | ||
147 | |||
148 | static struct tgfx __init *tgfx_probe(int *config, int nargs) | ||
149 | { | ||
150 | struct tgfx *tgfx; | ||
151 | struct parport *pp; | ||
152 | int i, j; | ||
153 | |||
154 | if (config[0] < 0) | ||
155 | return NULL; | ||
156 | |||
157 | if (nargs < 2) { | ||
158 | printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | pp = parport_find_number(config[0]); | ||
163 | |||
164 | if (!pp) { | ||
165 | printk(KERN_ERR "turbografx.c: no such parport\n"); | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) { | ||
170 | parport_put_port(pp); | ||
171 | return NULL; | ||
172 | } | ||
173 | memset(tgfx, 0, sizeof(struct tgfx)); | ||
174 | |||
175 | tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); | ||
176 | |||
177 | parport_put_port(pp); | ||
178 | |||
179 | if (!tgfx->pd) { | ||
180 | printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); | ||
181 | kfree(tgfx); | ||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | init_timer(&tgfx->timer); | ||
186 | tgfx->timer.data = (long) tgfx; | ||
187 | tgfx->timer.function = tgfx_timer; | ||
188 | |||
189 | tgfx->sticks = 0; | ||
190 | |||
191 | for (i = 0; i < nargs - 1; i++) | ||
192 | if (config[i+1] > 0 && config[i+1] < 6) { | ||
193 | |||
194 | tgfx->sticks |= (1 << i); | ||
195 | |||
196 | tgfx->dev[i].private = tgfx; | ||
197 | tgfx->dev[i].open = tgfx_open; | ||
198 | tgfx->dev[i].close = tgfx_close; | ||
199 | |||
200 | sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name); | ||
201 | |||
202 | tgfx->dev[i].name = tgfx_name; | ||
203 | tgfx->dev[i].phys = tgfx->phys[i]; | ||
204 | tgfx->dev[i].id.bustype = BUS_PARPORT; | ||
205 | tgfx->dev[i].id.vendor = 0x0003; | ||
206 | tgfx->dev[i].id.product = config[i+1]; | ||
207 | tgfx->dev[i].id.version = 0x0100; | ||
208 | |||
209 | tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
210 | tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | ||
211 | |||
212 | for (j = 0; j < config[i+1]; j++) | ||
213 | set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); | ||
214 | |||
215 | tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; | ||
216 | tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; | ||
217 | |||
218 | input_register_device(tgfx->dev + i); | ||
219 | printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", | ||
220 | config[i+1], tgfx->pd->port->name); | ||
221 | } | ||
222 | |||
223 | if (!tgfx->sticks) { | ||
224 | parport_unregister_device(tgfx->pd); | ||
225 | kfree(tgfx); | ||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | return tgfx; | ||
230 | } | ||
231 | |||
232 | static int __init tgfx_init(void) | ||
233 | { | ||
234 | tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs); | ||
235 | tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2); | ||
236 | tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3); | ||
237 | |||
238 | if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) | ||
239 | return 0; | ||
240 | |||
241 | return -ENODEV; | ||
242 | } | ||
243 | |||
244 | static void __exit tgfx_exit(void) | ||
245 | { | ||
246 | int i, j; | ||
247 | |||
248 | for (i = 0; i < 3; i++) | ||
249 | if (tgfx_base[i]) { | ||
250 | for (j = 0; j < 7; j++) | ||
251 | if (tgfx_base[i]->sticks & (1 << j)) | ||
252 | input_unregister_device(tgfx_base[i]->dev + j); | ||
253 | parport_unregister_device(tgfx_base[i]->pd); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | module_init(tgfx_init); | ||
258 | module_exit(tgfx_exit); | ||
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c new file mode 100644 index 000000000000..0379bc166525 --- /dev/null +++ b/drivers/input/joystick/twidjoy.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * $Id: twidjoy.c,v 1.5 2002/01/22 20:31:53 vojtech Exp $ | ||
3 | * | ||
4 | * derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp" | ||
5 | * | ||
6 | * Copyright (c) 2001 Arndt Schoenewald | ||
7 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
8 | * Copyright (c) 2000 Mark Fletcher | ||
9 | * | ||
10 | * Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Driver to use Handykey's Twiddler (the first edition, i.e. the one with | ||
15 | * the RS232 interface) as a joystick under Linux | ||
16 | * | ||
17 | * The Twiddler is a one-handed chording keyboard featuring twelve buttons on | ||
18 | * the front, six buttons on the top, and a built-in tilt sensor. The buttons | ||
19 | * on the front, which are grouped as four rows of three buttons, are pressed | ||
20 | * by the four fingers (this implies only one button per row can be held down | ||
21 | * at the same time) and the buttons on the top are for the thumb. The tilt | ||
22 | * sensor delivers X and Y axis data depending on how the Twiddler is held. | ||
23 | * Additional information can be found at http://www.handykey.com. | ||
24 | * | ||
25 | * This driver does not use the Twiddler for its intended purpose, i.e. as | ||
26 | * a chording keyboard, but as a joystick: pressing and releasing a button | ||
27 | * immediately sends a corresponding button event, and tilting it generates | ||
28 | * corresponding ABS_X and ABS_Y events. This turns the Twiddler into a game | ||
29 | * controller with amazing 18 buttons :-) | ||
30 | * | ||
31 | * Note: The Twiddler2 (the successor of the Twiddler that connects directly | ||
32 | * to the PS/2 keyboard and mouse ports) is NOT supported by this driver! | ||
33 | * | ||
34 | * For questions or feedback regarding this driver module please contact: | ||
35 | * Arndt Schoenewald <arndt@quelltext.com> | ||
36 | */ | ||
37 | |||
38 | /* | ||
39 | * This program is free software; you can redistribute it and/or modify | ||
40 | * it under the terms of the GNU General Public License as published by | ||
41 | * the Free Software Foundation; either version 2 of the License, or | ||
42 | * (at your option) any later version. | ||
43 | * | ||
44 | * This program is distributed in the hope that it will be useful, | ||
45 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
46 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
47 | * GNU General Public License for more details. | ||
48 | * | ||
49 | * You should have received a copy of the GNU General Public License | ||
50 | * along with this program; if not, write to the Free Software | ||
51 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
52 | */ | ||
53 | |||
54 | #include <linux/kernel.h> | ||
55 | #include <linux/module.h> | ||
56 | #include <linux/slab.h> | ||
57 | #include <linux/input.h> | ||
58 | #include <linux/serio.h> | ||
59 | #include <linux/init.h> | ||
60 | |||
61 | #define DRIVER_DESC "Handykey Twiddler keyboard as a joystick driver" | ||
62 | |||
63 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
64 | MODULE_LICENSE("GPL"); | ||
65 | |||
66 | /* | ||
67 | * Constants. | ||
68 | */ | ||
69 | |||
70 | #define TWIDJOY_MAX_LENGTH 5 | ||
71 | |||
72 | static char *twidjoy_name = "Handykey Twiddler"; | ||
73 | |||
74 | static struct twidjoy_button_spec { | ||
75 | int bitshift; | ||
76 | int bitmask; | ||
77 | int buttons[3]; | ||
78 | } | ||
79 | twidjoy_buttons[] = { | ||
80 | { 0, 3, { BTN_A, BTN_B, BTN_C } }, | ||
81 | { 2, 3, { BTN_X, BTN_Y, BTN_Z } }, | ||
82 | { 4, 3, { BTN_TL, BTN_TR, BTN_TR2 } }, | ||
83 | { 6, 3, { BTN_SELECT, BTN_START, BTN_MODE } }, | ||
84 | { 8, 1, { BTN_BASE5 } }, | ||
85 | { 9, 1, { BTN_BASE } }, | ||
86 | { 10, 1, { BTN_BASE3 } }, | ||
87 | { 11, 1, { BTN_BASE4 } }, | ||
88 | { 12, 1, { BTN_BASE2 } }, | ||
89 | { 13, 1, { BTN_BASE6 } }, | ||
90 | { 0, 0, { 0 } } | ||
91 | }; | ||
92 | |||
93 | /* | ||
94 | * Per-Twiddler data. | ||
95 | */ | ||
96 | |||
97 | struct twidjoy { | ||
98 | struct input_dev dev; | ||
99 | int idx; | ||
100 | unsigned char data[TWIDJOY_MAX_LENGTH]; | ||
101 | char phys[32]; | ||
102 | }; | ||
103 | |||
104 | /* | ||
105 | * twidjoy_process_packet() decodes packets the driver receives from the | ||
106 | * Twiddler. It updates the data accordingly. | ||
107 | */ | ||
108 | |||
109 | static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs) | ||
110 | { | ||
111 | if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { | ||
112 | struct input_dev *dev = &twidjoy->dev; | ||
113 | unsigned char *data = twidjoy->data; | ||
114 | struct twidjoy_button_spec *bp; | ||
115 | int button_bits, abs_x, abs_y; | ||
116 | |||
117 | button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); | ||
118 | |||
119 | input_regs(dev, regs); | ||
120 | |||
121 | for (bp = twidjoy_buttons; bp->bitmask; bp++) { | ||
122 | int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; | ||
123 | int i; | ||
124 | |||
125 | for (i = 0; i < bp->bitmask; i++) | ||
126 | input_report_key(dev, bp->buttons[i], i+1 == value); | ||
127 | } | ||
128 | |||
129 | abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); | ||
130 | if (data[4] & 0x08) abs_x -= 256; | ||
131 | |||
132 | abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); | ||
133 | if (data[3] & 0x02) abs_y -= 256; | ||
134 | |||
135 | input_report_abs(dev, ABS_X, -abs_x); | ||
136 | input_report_abs(dev, ABS_Y, +abs_y); | ||
137 | |||
138 | input_sync(dev); | ||
139 | } | ||
140 | |||
141 | return; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * twidjoy_interrupt() is called by the low level driver when characters | ||
146 | * are ready for us. We then buffer them for further processing, or call the | ||
147 | * packet processing routine. | ||
148 | */ | ||
149 | |||
150 | static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
151 | { | ||
152 | struct twidjoy *twidjoy = serio_get_drvdata(serio); | ||
153 | |||
154 | /* All Twiddler packets are 5 bytes. The fact that the first byte | ||
155 | * has a MSB of 0 and all other bytes have a MSB of 1 can be used | ||
156 | * to check and regain sync. */ | ||
157 | |||
158 | if ((data & 0x80) == 0) | ||
159 | twidjoy->idx = 0; /* this byte starts a new packet */ | ||
160 | else if (twidjoy->idx == 0) | ||
161 | return IRQ_HANDLED; /* wrong MSB -- ignore this byte */ | ||
162 | |||
163 | if (twidjoy->idx < TWIDJOY_MAX_LENGTH) | ||
164 | twidjoy->data[twidjoy->idx++] = data; | ||
165 | |||
166 | if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { | ||
167 | twidjoy_process_packet(twidjoy, regs); | ||
168 | twidjoy->idx = 0; | ||
169 | } | ||
170 | |||
171 | return IRQ_HANDLED; | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * twidjoy_disconnect() is the opposite of twidjoy_connect() | ||
176 | */ | ||
177 | |||
178 | static void twidjoy_disconnect(struct serio *serio) | ||
179 | { | ||
180 | struct twidjoy *twidjoy = serio_get_drvdata(serio); | ||
181 | |||
182 | input_unregister_device(&twidjoy->dev); | ||
183 | serio_close(serio); | ||
184 | serio_set_drvdata(serio, NULL); | ||
185 | kfree(twidjoy); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * twidjoy_connect() is the routine that is called when someone adds a | ||
190 | * new serio device. It looks for the Twiddler, and if found, registers | ||
191 | * it as an input device. | ||
192 | */ | ||
193 | |||
194 | static int twidjoy_connect(struct serio *serio, struct serio_driver *drv) | ||
195 | { | ||
196 | struct twidjoy_button_spec *bp; | ||
197 | struct twidjoy *twidjoy; | ||
198 | int i; | ||
199 | int err; | ||
200 | |||
201 | if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL))) | ||
202 | return -ENOMEM; | ||
203 | |||
204 | memset(twidjoy, 0, sizeof(struct twidjoy)); | ||
205 | |||
206 | sprintf(twidjoy->phys, "%s/input0", serio->phys); | ||
207 | |||
208 | init_input_dev(&twidjoy->dev); | ||
209 | twidjoy->dev.name = twidjoy_name; | ||
210 | twidjoy->dev.phys = twidjoy->phys; | ||
211 | twidjoy->dev.id.bustype = BUS_RS232; | ||
212 | twidjoy->dev.id.vendor = SERIO_TWIDJOY; | ||
213 | twidjoy->dev.id.product = 0x0001; | ||
214 | twidjoy->dev.id.version = 0x0100; | ||
215 | twidjoy->dev.dev = &serio->dev; | ||
216 | |||
217 | twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
218 | |||
219 | for (bp = twidjoy_buttons; bp->bitmask; bp++) { | ||
220 | for (i = 0; i < bp->bitmask; i++) | ||
221 | set_bit(bp->buttons[i], twidjoy->dev.keybit); | ||
222 | } | ||
223 | |||
224 | twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | ||
225 | |||
226 | for (i = 0; i < 2; i++) { | ||
227 | twidjoy->dev.absmax[ABS_X+i] = 50; | ||
228 | twidjoy->dev.absmin[ABS_X+i] = -50; | ||
229 | |||
230 | /* TODO: arndt 20010708: Are these values appropriate? */ | ||
231 | twidjoy->dev.absfuzz[ABS_X+i] = 4; | ||
232 | twidjoy->dev.absflat[ABS_X+i] = 4; | ||
233 | } | ||
234 | |||
235 | twidjoy->dev.private = twidjoy; | ||
236 | |||
237 | serio_set_drvdata(serio, twidjoy); | ||
238 | |||
239 | err = serio_open(serio, drv); | ||
240 | if (err) { | ||
241 | serio_set_drvdata(serio, NULL); | ||
242 | kfree(twidjoy); | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | input_register_device(&twidjoy->dev); | ||
247 | |||
248 | printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys); | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * The serio driver structure. | ||
255 | */ | ||
256 | |||
257 | static struct serio_device_id twidjoy_serio_ids[] = { | ||
258 | { | ||
259 | .type = SERIO_RS232, | ||
260 | .proto = SERIO_TWIDJOY, | ||
261 | .id = SERIO_ANY, | ||
262 | .extra = SERIO_ANY, | ||
263 | }, | ||
264 | { 0 } | ||
265 | }; | ||
266 | |||
267 | MODULE_DEVICE_TABLE(serio, twidjoy_serio_ids); | ||
268 | |||
269 | static struct serio_driver twidjoy_drv = { | ||
270 | .driver = { | ||
271 | .name = "twidjoy", | ||
272 | }, | ||
273 | .description = DRIVER_DESC, | ||
274 | .id_table = twidjoy_serio_ids, | ||
275 | .interrupt = twidjoy_interrupt, | ||
276 | .connect = twidjoy_connect, | ||
277 | .disconnect = twidjoy_disconnect, | ||
278 | }; | ||
279 | |||
280 | /* | ||
281 | * The functions for inserting/removing us as a module. | ||
282 | */ | ||
283 | |||
284 | int __init twidjoy_init(void) | ||
285 | { | ||
286 | serio_register_driver(&twidjoy_drv); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | void __exit twidjoy_exit(void) | ||
291 | { | ||
292 | serio_unregister_driver(&twidjoy_drv); | ||
293 | } | ||
294 | |||
295 | module_init(twidjoy_init); | ||
296 | module_exit(twidjoy_exit); | ||
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c new file mode 100644 index 000000000000..6976a219504c --- /dev/null +++ b/drivers/input/joystick/warrior.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * $Id: warrior.c,v 1.14 2002/01/22 20:32:10 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Logitech WingMan Warrior joystick driver for Linux | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * This program is free warftware; 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/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/input.h> | ||
35 | #include <linux/serio.h> | ||
36 | #include <linux/init.h> | ||
37 | |||
38 | #define DRIVER_DESC "Logitech WingMan Warrior joystick driver" | ||
39 | |||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | /* | ||
45 | * Constants. | ||
46 | */ | ||
47 | |||
48 | #define WARRIOR_MAX_LENGTH 16 | ||
49 | static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; | ||
50 | static char *warrior_name = "Logitech WingMan Warrior"; | ||
51 | |||
52 | /* | ||
53 | * Per-Warrior data. | ||
54 | */ | ||
55 | |||
56 | struct warrior { | ||
57 | struct input_dev dev; | ||
58 | int idx, len; | ||
59 | unsigned char data[WARRIOR_MAX_LENGTH]; | ||
60 | char phys[32]; | ||
61 | }; | ||
62 | |||
63 | /* | ||
64 | * warrior_process_packet() decodes packets the driver receives from the | ||
65 | * Warrior. It updates the data accordingly. | ||
66 | */ | ||
67 | |||
68 | static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs) | ||
69 | { | ||
70 | struct input_dev *dev = &warrior->dev; | ||
71 | unsigned char *data = warrior->data; | ||
72 | |||
73 | if (!warrior->idx) return; | ||
74 | |||
75 | input_regs(dev, regs); | ||
76 | |||
77 | switch ((data[0] >> 4) & 7) { | ||
78 | case 1: /* Button data */ | ||
79 | input_report_key(dev, BTN_TRIGGER, data[3] & 1); | ||
80 | input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1); | ||
81 | input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1); | ||
82 | input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1); | ||
83 | break; | ||
84 | case 3: /* XY-axis info->data */ | ||
85 | input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5))); | ||
86 | input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); | ||
87 | break; | ||
88 | case 5: /* Throttle, spinner, hat info->data */ | ||
89 | input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); | ||
90 | input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0)); | ||
91 | input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0)); | ||
92 | input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5)); | ||
93 | break; | ||
94 | } | ||
95 | input_sync(dev); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * warrior_interrupt() is called by the low level driver when characters | ||
100 | * are ready for us. We then buffer them for further processing, or call the | ||
101 | * packet processing routine. | ||
102 | */ | ||
103 | |||
104 | static irqreturn_t warrior_interrupt(struct serio *serio, | ||
105 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
106 | { | ||
107 | struct warrior *warrior = serio_get_drvdata(serio); | ||
108 | |||
109 | if (data & 0x80) { | ||
110 | if (warrior->idx) warrior_process_packet(warrior, regs); | ||
111 | warrior->idx = 0; | ||
112 | warrior->len = warrior_lengths[(data >> 4) & 7]; | ||
113 | } | ||
114 | |||
115 | if (warrior->idx < warrior->len) | ||
116 | warrior->data[warrior->idx++] = data; | ||
117 | |||
118 | if (warrior->idx == warrior->len) { | ||
119 | if (warrior->idx) warrior_process_packet(warrior, regs); | ||
120 | warrior->idx = 0; | ||
121 | warrior->len = 0; | ||
122 | } | ||
123 | return IRQ_HANDLED; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * warrior_disconnect() is the opposite of warrior_connect() | ||
128 | */ | ||
129 | |||
130 | static void warrior_disconnect(struct serio *serio) | ||
131 | { | ||
132 | struct warrior *warrior = serio_get_drvdata(serio); | ||
133 | |||
134 | input_unregister_device(&warrior->dev); | ||
135 | serio_close(serio); | ||
136 | serio_set_drvdata(serio, NULL); | ||
137 | kfree(warrior); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * warrior_connect() is the routine that is called when someone adds a | ||
142 | * new serio device. It looks for the Warrior, and if found, registers | ||
143 | * it as an input device. | ||
144 | */ | ||
145 | |||
146 | static int warrior_connect(struct serio *serio, struct serio_driver *drv) | ||
147 | { | ||
148 | struct warrior *warrior; | ||
149 | int i; | ||
150 | int err; | ||
151 | |||
152 | if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL))) | ||
153 | return -ENOMEM; | ||
154 | |||
155 | memset(warrior, 0, sizeof(struct warrior)); | ||
156 | |||
157 | warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); | ||
158 | warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); | ||
159 | warrior->dev.relbit[0] = BIT(REL_DIAL); | ||
160 | warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); | ||
161 | |||
162 | sprintf(warrior->phys, "%s/input0", serio->phys); | ||
163 | |||
164 | init_input_dev(&warrior->dev); | ||
165 | warrior->dev.name = warrior_name; | ||
166 | warrior->dev.phys = warrior->phys; | ||
167 | warrior->dev.id.bustype = BUS_RS232; | ||
168 | warrior->dev.id.vendor = SERIO_WARRIOR; | ||
169 | warrior->dev.id.product = 0x0001; | ||
170 | warrior->dev.id.version = 0x0100; | ||
171 | warrior->dev.dev = &serio->dev; | ||
172 | |||
173 | for (i = 0; i < 2; i++) { | ||
174 | warrior->dev.absmax[ABS_X+i] = -64; | ||
175 | warrior->dev.absmin[ABS_X+i] = 64; | ||
176 | warrior->dev.absflat[ABS_X+i] = 8; | ||
177 | } | ||
178 | |||
179 | warrior->dev.absmax[ABS_THROTTLE] = -112; | ||
180 | warrior->dev.absmin[ABS_THROTTLE] = 112; | ||
181 | |||
182 | for (i = 0; i < 2; i++) { | ||
183 | warrior->dev.absmax[ABS_HAT0X+i] = -1; | ||
184 | warrior->dev.absmin[ABS_HAT0X+i] = 1; | ||
185 | } | ||
186 | |||
187 | warrior->dev.private = warrior; | ||
188 | |||
189 | serio_set_drvdata(serio, warrior); | ||
190 | |||
191 | err = serio_open(serio, drv); | ||
192 | if (err) { | ||
193 | serio_set_drvdata(serio, NULL); | ||
194 | kfree(warrior); | ||
195 | return err; | ||
196 | } | ||
197 | |||
198 | input_register_device(&warrior->dev); | ||
199 | |||
200 | printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * The serio driver structure. | ||
207 | */ | ||
208 | |||
209 | static struct serio_device_id warrior_serio_ids[] = { | ||
210 | { | ||
211 | .type = SERIO_RS232, | ||
212 | .proto = SERIO_WARRIOR, | ||
213 | .id = SERIO_ANY, | ||
214 | .extra = SERIO_ANY, | ||
215 | }, | ||
216 | { 0 } | ||
217 | }; | ||
218 | |||
219 | MODULE_DEVICE_TABLE(serio, warrior_serio_ids); | ||
220 | |||
221 | static struct serio_driver warrior_drv = { | ||
222 | .driver = { | ||
223 | .name = "warrior", | ||
224 | }, | ||
225 | .description = DRIVER_DESC, | ||
226 | .id_table = warrior_serio_ids, | ||
227 | .interrupt = warrior_interrupt, | ||
228 | .connect = warrior_connect, | ||
229 | .disconnect = warrior_disconnect, | ||
230 | }; | ||
231 | |||
232 | /* | ||
233 | * The functions for inserting/removing us as a module. | ||
234 | */ | ||
235 | |||
236 | static int __init warrior_init(void) | ||
237 | { | ||
238 | serio_register_driver(&warrior_drv); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void __exit warrior_exit(void) | ||
243 | { | ||
244 | serio_unregister_driver(&warrior_drv); | ||
245 | } | ||
246 | |||
247 | module_init(warrior_init); | ||
248 | module_exit(warrior_exit); | ||
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig new file mode 100644 index 000000000000..e55dee390775 --- /dev/null +++ b/drivers/input/keyboard/Kconfig | |||
@@ -0,0 +1,185 @@ | |||
1 | # | ||
2 | # Input core configuration | ||
3 | # | ||
4 | menuconfig INPUT_KEYBOARD | ||
5 | bool "Keyboards" if EMBEDDED || !X86 | ||
6 | default y | ||
7 | help | ||
8 | Say Y here, and a list of supported keyboards will be displayed. | ||
9 | This option doesn't affect the kernel. | ||
10 | |||
11 | If unsure, say Y. | ||
12 | |||
13 | if INPUT_KEYBOARD | ||
14 | |||
15 | config KEYBOARD_ATKBD | ||
16 | tristate "AT keyboard" if !PC | ||
17 | default y | ||
18 | select SERIO | ||
19 | select SERIO_LIBPS2 | ||
20 | select SERIO_I8042 if PC | ||
21 | select SERIO_GSCPS2 if GSC | ||
22 | help | ||
23 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually | ||
24 | you'll need this, unless you have a different type keyboard (USB, ADB | ||
25 | or other). This also works for AT and PS/2 keyboards connected over a | ||
26 | PS/2 to serial converter. | ||
27 | |||
28 | If unsure, say Y. | ||
29 | |||
30 | To compile this driver as a module, choose M here: the | ||
31 | module will be called atkbd. | ||
32 | |||
33 | config KEYBOARD_ATKBD_HP_KEYCODES | ||
34 | bool "Use HP keyboard scancodes" | ||
35 | depends on PARISC && KEYBOARD_ATKBD | ||
36 | default y | ||
37 | help | ||
38 | Say Y here if you have a PA-RISC machine and want to use an AT or | ||
39 | PS/2 keyboard, and your keyboard uses keycodes that are specific to | ||
40 | PA-RISC keyboards. | ||
41 | |||
42 | Say N if you use a standard keyboard. | ||
43 | |||
44 | config KEYBOARD_ATKBD_RDI_KEYCODES | ||
45 | bool "Use PrecisionBook keyboard scancodes" | ||
46 | depends on KEYBOARD_ATKBD_HP_KEYCODES | ||
47 | default n | ||
48 | help | ||
49 | If you have an RDI PrecisionBook, say Y here if you want to use its | ||
50 | built-in keyboard (as opposed to an external keyboard). | ||
51 | |||
52 | The PrecisionBook has five keys that conflict with those used by most | ||
53 | AT and PS/2 keyboards. These are as follows: | ||
54 | |||
55 | PrecisionBook Standard AT or PS/2 | ||
56 | |||
57 | F1 F12 | ||
58 | Left Ctrl Left Alt | ||
59 | Caps Lock Left Ctrl | ||
60 | Right Ctrl Caps Lock | ||
61 | Left 102nd key (the key to the right of Left Shift) | ||
62 | |||
63 | If you say N here, and use the PrecisionBook keyboard, then each key | ||
64 | in the left-hand column will be interpreted as the corresponding key | ||
65 | in the right-hand column. | ||
66 | |||
67 | If you say Y here, and use an external keyboard, then each key in the | ||
68 | right-hand column will be interpreted as the key shown in the | ||
69 | left-hand column. | ||
70 | |||
71 | config KEYBOARD_SUNKBD | ||
72 | tristate "Sun Type 4 and Type 5 keyboard" | ||
73 | select SERIO | ||
74 | help | ||
75 | Say Y here if you want to use a Sun Type 4 or Type 5 keyboard, | ||
76 | connected either to the Sun keyboard connector or to an serial | ||
77 | (RS-232) port via a simple adapter. | ||
78 | |||
79 | To compile this driver as a module, choose M here: the | ||
80 | module will be called sunkbd. | ||
81 | |||
82 | config KEYBOARD_LKKBD | ||
83 | tristate "DECstation/VAXstation LK201/LK401 keyboard" | ||
84 | select SERIO | ||
85 | help | ||
86 | Say Y here if you want to use a LK201 or LK401 style serial | ||
87 | keyboard. This keyboard is also useable on PCs if you attach | ||
88 | it with the inputattach program. The connector pinout is | ||
89 | described within lkkbd.c. | ||
90 | |||
91 | To compile this driver as a module, choose M here: the | ||
92 | module will be called lkkbd. | ||
93 | |||
94 | config KEYBOARD_LOCOMO | ||
95 | tristate "LoCoMo Keyboard Support" | ||
96 | depends on SHARP_LOCOMO | ||
97 | help | ||
98 | Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA | ||
99 | |||
100 | To compile this driver as a module, choose M here: the | ||
101 | module will be called locomokbd. | ||
102 | |||
103 | config KEYBOARD_XTKBD | ||
104 | tristate "XT keyboard" | ||
105 | select SERIO | ||
106 | help | ||
107 | Say Y here if you want to use the old IBM PC/XT keyboard (or | ||
108 | compatible) on your system. This is only possible with a | ||
109 | parallel port keyboard adapter, you cannot connect it to the | ||
110 | keyboard port on a PC that runs Linux. | ||
111 | |||
112 | To compile this driver as a module, choose M here: the | ||
113 | module will be called xtkbd. | ||
114 | |||
115 | config KEYBOARD_NEWTON | ||
116 | tristate "Newton keyboard" | ||
117 | select SERIO | ||
118 | help | ||
119 | Say Y here if you have a Newton keyboard on a serial port. | ||
120 | |||
121 | To compile this driver as a module, choose M here: the | ||
122 | module will be called newtonkbd. | ||
123 | |||
124 | config KEYBOARD_CORGI | ||
125 | tristate "Corgi keyboard" | ||
126 | depends on PXA_SHARPSL | ||
127 | default y | ||
128 | help | ||
129 | Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx | ||
130 | series of PDAs. | ||
131 | |||
132 | To compile this driver as a module, choose M here: the | ||
133 | module will be called corgikbd. | ||
134 | |||
135 | config KEYBOARD_MAPLE | ||
136 | tristate "Maple bus keyboard" | ||
137 | depends on SH_DREAMCAST && MAPLE | ||
138 | help | ||
139 | Say Y here if you have a DreamCast console running Linux and have | ||
140 | a keyboard attached to its Maple bus. | ||
141 | |||
142 | To compile this driver as a module, choose M here: the | ||
143 | module will be called maple_keyb. | ||
144 | |||
145 | config KEYBOARD_AMIGA | ||
146 | tristate "Amiga keyboard" | ||
147 | depends on AMIGA | ||
148 | help | ||
149 | Say Y here if you are running Linux on any AMIGA and have a keyboard | ||
150 | attached. | ||
151 | |||
152 | To compile this driver as a module, choose M here: the | ||
153 | module will be called amikbd. | ||
154 | |||
155 | config KEYBOARD_HIL_OLD | ||
156 | tristate "HP HIL keyboard support (simple driver)" | ||
157 | depends on GSC | ||
158 | default y | ||
159 | help | ||
160 | The "Human Interface Loop" is a older, 8-channel USB-like | ||
161 | controller used in several Hewlett Packard models. This driver | ||
162 | was adapted from the one written for m68k/hp300, and implements | ||
163 | support for a keyboard attached to the HIL port, but not for | ||
164 | any other types of HIL input devices like mice or tablets. | ||
165 | However, it has been thoroughly tested and is stable. | ||
166 | |||
167 | If you want full HIL support including support for multiple | ||
168 | keyboards, mices and tablets, you have to enable the | ||
169 | "HP System Device Controller i8042 Support" in the input/serio | ||
170 | submenu. | ||
171 | |||
172 | config KEYBOARD_HIL | ||
173 | tristate "HP HIL keyboard support" | ||
174 | depends on GSC | ||
175 | default y | ||
176 | select HP_SDC | ||
177 | select HIL_MLC | ||
178 | select SERIO | ||
179 | help | ||
180 | The "Human Interface Loop" is a older, 8-channel USB-like | ||
181 | controller used in several Hewlett Packard models. | ||
182 | This driver implements support for HIL-keyboards attached | ||
183 | to your machine, so normally you should say Y here. | ||
184 | |||
185 | endif | ||
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile new file mode 100644 index 000000000000..b02eeceea3c3 --- /dev/null +++ b/drivers/input/keyboard/Makefile | |||
@@ -0,0 +1,19 @@ | |||
1 | # | ||
2 | # Makefile for the input core drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o | ||
8 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o | ||
9 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o | ||
10 | obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o | ||
11 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | ||
12 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o | ||
13 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o | ||
14 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o | ||
15 | obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o | ||
16 | obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o | ||
17 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o | ||
18 | obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o | ||
19 | |||
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c new file mode 100644 index 000000000000..4e8e8ea214ab --- /dev/null +++ b/drivers/input/keyboard/amikbd.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Hamish Macdonald | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Amiga keyboard driver for Linux/m68k | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/input.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | |||
40 | #include <asm/amigaints.h> | ||
41 | #include <asm/amigahw.h> | ||
42 | #include <asm/irq.h> | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
45 | MODULE_DESCRIPTION("Amiga keyboard driver"); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | static unsigned char amikbd_keycode[0x78] = { | ||
49 | [0] = KEY_GRAVE, | ||
50 | [1] = KEY_1, | ||
51 | [2] = KEY_2, | ||
52 | [3] = KEY_3, | ||
53 | [4] = KEY_4, | ||
54 | [5] = KEY_5, | ||
55 | [6] = KEY_6, | ||
56 | [7] = KEY_7, | ||
57 | [8] = KEY_8, | ||
58 | [9] = KEY_9, | ||
59 | [10] = KEY_0, | ||
60 | [11] = KEY_MINUS, | ||
61 | [12] = KEY_EQUAL, | ||
62 | [13] = KEY_BACKSLASH, | ||
63 | [15] = KEY_KP0, | ||
64 | [16] = KEY_Q, | ||
65 | [17] = KEY_W, | ||
66 | [18] = KEY_E, | ||
67 | [19] = KEY_R, | ||
68 | [20] = KEY_T, | ||
69 | [21] = KEY_Y, | ||
70 | [22] = KEY_U, | ||
71 | [23] = KEY_I, | ||
72 | [24] = KEY_O, | ||
73 | [25] = KEY_P, | ||
74 | [26] = KEY_LEFTBRACE, | ||
75 | [27] = KEY_RIGHTBRACE, | ||
76 | [29] = KEY_KP1, | ||
77 | [30] = KEY_KP2, | ||
78 | [31] = KEY_KP3, | ||
79 | [32] = KEY_A, | ||
80 | [33] = KEY_S, | ||
81 | [34] = KEY_D, | ||
82 | [35] = KEY_F, | ||
83 | [36] = KEY_G, | ||
84 | [37] = KEY_H, | ||
85 | [38] = KEY_J, | ||
86 | [39] = KEY_K, | ||
87 | [40] = KEY_L, | ||
88 | [41] = KEY_SEMICOLON, | ||
89 | [42] = KEY_APOSTROPHE, | ||
90 | [43] = KEY_BACKSLASH, | ||
91 | [45] = KEY_KP4, | ||
92 | [46] = KEY_KP5, | ||
93 | [47] = KEY_KP6, | ||
94 | [48] = KEY_102ND, | ||
95 | [49] = KEY_Z, | ||
96 | [50] = KEY_X, | ||
97 | [51] = KEY_C, | ||
98 | [52] = KEY_V, | ||
99 | [53] = KEY_B, | ||
100 | [54] = KEY_N, | ||
101 | [55] = KEY_M, | ||
102 | [56] = KEY_COMMA, | ||
103 | [57] = KEY_DOT, | ||
104 | [58] = KEY_SLASH, | ||
105 | [60] = KEY_KPDOT, | ||
106 | [61] = KEY_KP7, | ||
107 | [62] = KEY_KP8, | ||
108 | [63] = KEY_KP9, | ||
109 | [64] = KEY_SPACE, | ||
110 | [65] = KEY_BACKSPACE, | ||
111 | [66] = KEY_TAB, | ||
112 | [67] = KEY_KPENTER, | ||
113 | [68] = KEY_ENTER, | ||
114 | [69] = KEY_ESC, | ||
115 | [70] = KEY_DELETE, | ||
116 | [74] = KEY_KPMINUS, | ||
117 | [76] = KEY_UP, | ||
118 | [77] = KEY_DOWN, | ||
119 | [78] = KEY_RIGHT, | ||
120 | [79] = KEY_LEFT, | ||
121 | [80] = KEY_F1, | ||
122 | [81] = KEY_F2, | ||
123 | [82] = KEY_F3, | ||
124 | [83] = KEY_F4, | ||
125 | [84] = KEY_F5, | ||
126 | [85] = KEY_F6, | ||
127 | [86] = KEY_F7, | ||
128 | [87] = KEY_F8, | ||
129 | [88] = KEY_F9, | ||
130 | [89] = KEY_F10, | ||
131 | [90] = KEY_KPLEFTPAREN, | ||
132 | [91] = KEY_KPRIGHTPAREN, | ||
133 | [92] = KEY_KPSLASH, | ||
134 | [93] = KEY_KPASTERISK, | ||
135 | [94] = KEY_KPPLUS, | ||
136 | [95] = KEY_HELP, | ||
137 | [96] = KEY_LEFTSHIFT, | ||
138 | [97] = KEY_RIGHTSHIFT, | ||
139 | [98] = KEY_CAPSLOCK, | ||
140 | [99] = KEY_LEFTCTRL, | ||
141 | [100] = KEY_LEFTALT, | ||
142 | [101] = KEY_RIGHTALT, | ||
143 | [102] = KEY_LEFTMETA, | ||
144 | [103] = KEY_RIGHTMETA | ||
145 | }; | ||
146 | |||
147 | static const char *amikbd_messages[8] = { | ||
148 | [0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n", | ||
149 | [1] = KERN_WARNING "amikbd: keyboard lost sync\n", | ||
150 | [2] = KERN_WARNING "amikbd: keyboard buffer overflow\n", | ||
151 | [3] = KERN_WARNING "amikbd: keyboard controller failure\n", | ||
152 | [4] = KERN_ERR "amikbd: keyboard selftest failure\n", | ||
153 | [5] = KERN_INFO "amikbd: initiate power-up key stream\n", | ||
154 | [6] = KERN_INFO "amikbd: terminate power-up key stream\n", | ||
155 | [7] = KERN_WARNING "amikbd: keyboard interrupt\n" | ||
156 | }; | ||
157 | |||
158 | static struct input_dev amikbd_dev; | ||
159 | |||
160 | static char *amikbd_name = "Amiga keyboard"; | ||
161 | static char *amikbd_phys = "amikbd/input0"; | ||
162 | |||
163 | static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) | ||
164 | { | ||
165 | unsigned char scancode, down; | ||
166 | |||
167 | scancode = ~ciaa.sdr; /* get and invert scancode (keyboard is active low) */ | ||
168 | ciaa.cra |= 0x40; /* switch SP pin to output for handshake */ | ||
169 | udelay(85); /* wait until 85 us have expired */ | ||
170 | ciaa.cra &= ~0x40; /* switch CIA serial port to input mode */ | ||
171 | |||
172 | down = !(scancode & 1); /* lowest bit is release bit */ | ||
173 | scancode >>= 1; | ||
174 | |||
175 | if (scancode < 0x78) { /* scancodes < 0x78 are keys */ | ||
176 | |||
177 | scancode = amikbd_keycode[scancode]; | ||
178 | |||
179 | input_regs(&amikbd_dev, fp); | ||
180 | |||
181 | if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */ | ||
182 | input_report_key(&amikbd_dev, scancode, 1); | ||
183 | input_report_key(&amikbd_dev, scancode, 0); | ||
184 | input_sync(&amikbd_dev); | ||
185 | } else { | ||
186 | input_report_key(&amikbd_dev, scancode, down); | ||
187 | input_sync(&amikbd_dev); | ||
188 | } | ||
189 | } else /* scancodes >= 0x78 are error codes */ | ||
190 | printk(amikbd_messages[scancode - 0x78]); | ||
191 | |||
192 | return IRQ_HANDLED; | ||
193 | } | ||
194 | |||
195 | static int __init amikbd_init(void) | ||
196 | { | ||
197 | int i; | ||
198 | |||
199 | if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) | ||
200 | return -EIO; | ||
201 | |||
202 | if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) | ||
203 | return -EBUSY; | ||
204 | |||
205 | init_input_dev(&amikbd_dev); | ||
206 | |||
207 | amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
208 | amikbd_dev.keycode = amikbd_keycode; | ||
209 | amikbd_dev.keycodesize = sizeof(unsigned char); | ||
210 | amikbd_dev.keycodemax = ARRAY_SIZE(amikbd_keycode); | ||
211 | |||
212 | for (i = 0; i < 0x78; i++) | ||
213 | if (amikbd_keycode[i]) | ||
214 | set_bit(amikbd_keycode[i], amikbd_dev.keybit); | ||
215 | |||
216 | ciaa.cra &= ~0x41; /* serial data in, turn off TA */ | ||
217 | request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt); | ||
218 | |||
219 | amikbd_dev.name = amikbd_name; | ||
220 | amikbd_dev.phys = amikbd_phys; | ||
221 | amikbd_dev.id.bustype = BUS_AMIGA; | ||
222 | amikbd_dev.id.vendor = 0x0001; | ||
223 | amikbd_dev.id.product = 0x0001; | ||
224 | amikbd_dev.id.version = 0x0100; | ||
225 | |||
226 | input_register_device(&amikbd_dev); | ||
227 | |||
228 | printk(KERN_INFO "input: %s\n", amikbd_name); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static void __exit amikbd_exit(void) | ||
234 | { | ||
235 | input_unregister_device(&amikbd_dev); | ||
236 | free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt); | ||
237 | release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100); | ||
238 | } | ||
239 | |||
240 | module_init(amikbd_init); | ||
241 | module_exit(amikbd_exit); | ||
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c new file mode 100644 index 000000000000..f7304f0ce542 --- /dev/null +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -0,0 +1,1148 @@ | |||
1 | /* | ||
2 | * AT and PS/2 keyboard driver | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 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 standard AT keyboards and PS/2 keyboards in | ||
15 | * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb | ||
16 | * input-only controllers and AT keyboards connected over a one way RS232 | ||
17 | * converter. | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/input.h> | ||
27 | #include <linux/serio.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/libps2.h> | ||
30 | |||
31 | #define DRIVER_DESC "AT and PS/2 keyboard driver" | ||
32 | |||
33 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | ||
34 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | static int atkbd_set = 2; | ||
38 | module_param_named(set, atkbd_set, int, 0); | ||
39 | MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); | ||
40 | |||
41 | #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) | ||
42 | static int atkbd_reset; | ||
43 | #else | ||
44 | static int atkbd_reset = 1; | ||
45 | #endif | ||
46 | module_param_named(reset, atkbd_reset, bool, 0); | ||
47 | MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); | ||
48 | |||
49 | static int atkbd_softrepeat; | ||
50 | module_param_named(softrepeat, atkbd_softrepeat, bool, 0); | ||
51 | MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); | ||
52 | |||
53 | static int atkbd_softraw = 1; | ||
54 | module_param_named(softraw, atkbd_softraw, bool, 0); | ||
55 | MODULE_PARM_DESC(softraw, "Use software generated rawmode"); | ||
56 | |||
57 | static int atkbd_scroll = 1; | ||
58 | module_param_named(scroll, atkbd_scroll, bool, 0); | ||
59 | MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); | ||
60 | |||
61 | static int atkbd_extra; | ||
62 | module_param_named(extra, atkbd_extra, bool, 0); | ||
63 | MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); | ||
64 | |||
65 | __obsolete_setup("atkbd_set="); | ||
66 | __obsolete_setup("atkbd_reset"); | ||
67 | __obsolete_setup("atkbd_softrepeat="); | ||
68 | |||
69 | /* | ||
70 | * Scancode to keycode tables. These are just the default setting, and | ||
71 | * are loadable via an userland utility. | ||
72 | */ | ||
73 | |||
74 | static unsigned char atkbd_set2_keycode[512] = { | ||
75 | |||
76 | #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES | ||
77 | |||
78 | /* XXX: need a more general approach */ | ||
79 | |||
80 | #include "hpps2atkbd.h" /* include the keyboard scancodes */ | ||
81 | |||
82 | #else | ||
83 | 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, | ||
84 | 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, | ||
85 | 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, | ||
86 | 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, | ||
87 | 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, | ||
88 | 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85, | ||
89 | 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, | ||
90 | 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, | ||
91 | |||
92 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
93 | 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, | ||
94 | 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, | ||
95 | 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142, | ||
96 | 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, | ||
97 | 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, | ||
98 | 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, | ||
99 | 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, | ||
100 | |||
101 | 0, 0, 0, 65, 99, | ||
102 | #endif | ||
103 | }; | ||
104 | |||
105 | static unsigned char atkbd_set3_keycode[512] = { | ||
106 | |||
107 | 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, | ||
108 | 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, | ||
109 | 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, | ||
110 | 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66, | ||
111 | 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68, | ||
112 | 113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70, | ||
113 | 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, | ||
114 | 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183, | ||
115 | |||
116 | 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0, | ||
117 | 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168, | ||
118 | 148,149,147,140 | ||
119 | }; | ||
120 | |||
121 | static unsigned char atkbd_unxlate_table[128] = { | ||
122 | 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, | ||
123 | 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, | ||
124 | 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, | ||
125 | 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, | ||
126 | 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, | ||
127 | 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, | ||
128 | 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, | ||
129 | 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 | ||
130 | }; | ||
131 | |||
132 | #define ATKBD_CMD_SETLEDS 0x10ed | ||
133 | #define ATKBD_CMD_GSCANSET 0x11f0 | ||
134 | #define ATKBD_CMD_SSCANSET 0x10f0 | ||
135 | #define ATKBD_CMD_GETID 0x02f2 | ||
136 | #define ATKBD_CMD_SETREP 0x10f3 | ||
137 | #define ATKBD_CMD_ENABLE 0x00f4 | ||
138 | #define ATKBD_CMD_RESET_DIS 0x00f5 | ||
139 | #define ATKBD_CMD_SETALL_MBR 0x00fa | ||
140 | #define ATKBD_CMD_RESET_BAT 0x02ff | ||
141 | #define ATKBD_CMD_RESEND 0x00fe | ||
142 | #define ATKBD_CMD_EX_ENABLE 0x10ea | ||
143 | #define ATKBD_CMD_EX_SETLEDS 0x20eb | ||
144 | #define ATKBD_CMD_OK_GETID 0x02e8 | ||
145 | |||
146 | #define ATKBD_RET_ACK 0xfa | ||
147 | #define ATKBD_RET_NAK 0xfe | ||
148 | #define ATKBD_RET_BAT 0xaa | ||
149 | #define ATKBD_RET_EMUL0 0xe0 | ||
150 | #define ATKBD_RET_EMUL1 0xe1 | ||
151 | #define ATKBD_RET_RELEASE 0xf0 | ||
152 | #define ATKBD_RET_HANGUEL 0xf1 | ||
153 | #define ATKBD_RET_HANJA 0xf2 | ||
154 | #define ATKBD_RET_ERR 0xff | ||
155 | |||
156 | #define ATKBD_KEY_UNKNOWN 0 | ||
157 | #define ATKBD_KEY_NULL 255 | ||
158 | |||
159 | #define ATKBD_SCR_1 254 | ||
160 | #define ATKBD_SCR_2 253 | ||
161 | #define ATKBD_SCR_4 252 | ||
162 | #define ATKBD_SCR_8 251 | ||
163 | #define ATKBD_SCR_CLICK 250 | ||
164 | #define ATKBD_SCR_LEFT 249 | ||
165 | #define ATKBD_SCR_RIGHT 248 | ||
166 | |||
167 | #define ATKBD_SPECIAL 248 | ||
168 | |||
169 | static struct { | ||
170 | unsigned char keycode; | ||
171 | unsigned char set2; | ||
172 | } atkbd_scroll_keys[] = { | ||
173 | { ATKBD_SCR_1, 0xc5 }, | ||
174 | { ATKBD_SCR_2, 0xa9 }, | ||
175 | { ATKBD_SCR_4, 0xb6 }, | ||
176 | { ATKBD_SCR_8, 0xa7 }, | ||
177 | { ATKBD_SCR_CLICK, 0xe0 }, | ||
178 | { ATKBD_SCR_LEFT, 0xcb }, | ||
179 | { ATKBD_SCR_RIGHT, 0xd2 }, | ||
180 | }; | ||
181 | |||
182 | /* | ||
183 | * The atkbd control structure | ||
184 | */ | ||
185 | |||
186 | struct atkbd { | ||
187 | |||
188 | struct ps2dev ps2dev; | ||
189 | |||
190 | /* Written only during init */ | ||
191 | char name[64]; | ||
192 | char phys[32]; | ||
193 | struct input_dev dev; | ||
194 | |||
195 | unsigned short id; | ||
196 | unsigned char keycode[512]; | ||
197 | unsigned char set; | ||
198 | unsigned char translated; | ||
199 | unsigned char extra; | ||
200 | unsigned char write; | ||
201 | unsigned char softrepeat; | ||
202 | unsigned char softraw; | ||
203 | unsigned char scroll; | ||
204 | unsigned char enabled; | ||
205 | |||
206 | /* Accessed only from interrupt */ | ||
207 | unsigned char emul; | ||
208 | unsigned char resend; | ||
209 | unsigned char release; | ||
210 | unsigned char bat_xl; | ||
211 | unsigned int last; | ||
212 | unsigned long time; | ||
213 | }; | ||
214 | |||
215 | static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, | ||
216 | ssize_t (*handler)(struct atkbd *, char *)); | ||
217 | static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, | ||
218 | ssize_t (*handler)(struct atkbd *, const char *, size_t)); | ||
219 | #define ATKBD_DEFINE_ATTR(_name) \ | ||
220 | static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ | ||
221 | static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ | ||
222 | static ssize_t atkbd_do_show_##_name(struct device *d, char *b) \ | ||
223 | { \ | ||
224 | return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ | ||
225 | } \ | ||
226 | static ssize_t atkbd_do_set_##_name(struct device *d, const char *b, size_t s) \ | ||
227 | { \ | ||
228 | return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ | ||
229 | } \ | ||
230 | static struct device_attribute atkbd_attr_##_name = \ | ||
231 | __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); | ||
232 | |||
233 | ATKBD_DEFINE_ATTR(extra); | ||
234 | ATKBD_DEFINE_ATTR(scroll); | ||
235 | ATKBD_DEFINE_ATTR(set); | ||
236 | ATKBD_DEFINE_ATTR(softrepeat); | ||
237 | ATKBD_DEFINE_ATTR(softraw); | ||
238 | |||
239 | |||
240 | static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) | ||
241 | { | ||
242 | input_regs(dev, regs); | ||
243 | if (value == 3) { | ||
244 | input_report_key(dev, code, 1); | ||
245 | input_sync(dev); | ||
246 | input_report_key(dev, code, 0); | ||
247 | } else | ||
248 | input_event(dev, EV_KEY, code, value); | ||
249 | input_sync(dev); | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * atkbd_interrupt(). Here takes place processing of data received from | ||
254 | * the keyboard into events. | ||
255 | */ | ||
256 | |||
257 | static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, | ||
258 | unsigned int flags, struct pt_regs *regs) | ||
259 | { | ||
260 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
261 | unsigned int code = data; | ||
262 | int scroll = 0, hscroll = 0, click = -1; | ||
263 | int value; | ||
264 | |||
265 | #ifdef ATKBD_DEBUG | ||
266 | printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); | ||
267 | #endif | ||
268 | |||
269 | #if !defined(__i386__) && !defined (__x86_64__) | ||
270 | if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { | ||
271 | printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags); | ||
272 | serio_write(serio, ATKBD_CMD_RESEND); | ||
273 | atkbd->resend = 1; | ||
274 | goto out; | ||
275 | } | ||
276 | |||
277 | if (!flags && data == ATKBD_RET_ACK) | ||
278 | atkbd->resend = 0; | ||
279 | #endif | ||
280 | |||
281 | if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK)) | ||
282 | if (ps2_handle_ack(&atkbd->ps2dev, data)) | ||
283 | goto out; | ||
284 | |||
285 | if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD)) | ||
286 | if (ps2_handle_response(&atkbd->ps2dev, data)) | ||
287 | goto out; | ||
288 | |||
289 | if (!atkbd->enabled) | ||
290 | goto out; | ||
291 | |||
292 | input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); | ||
293 | |||
294 | if (atkbd->translated) { | ||
295 | |||
296 | if (atkbd->emul || | ||
297 | !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 || | ||
298 | code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA || | ||
299 | code == ATKBD_RET_ERR || | ||
300 | (code == ATKBD_RET_BAT && !atkbd->bat_xl))) { | ||
301 | atkbd->release = code >> 7; | ||
302 | code &= 0x7f; | ||
303 | } | ||
304 | |||
305 | if (!atkbd->emul && | ||
306 | (code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) | ||
307 | atkbd->bat_xl = !atkbd->release; | ||
308 | } | ||
309 | |||
310 | switch (code) { | ||
311 | case ATKBD_RET_BAT: | ||
312 | atkbd->enabled = 0; | ||
313 | serio_rescan(atkbd->ps2dev.serio); | ||
314 | goto out; | ||
315 | case ATKBD_RET_EMUL0: | ||
316 | atkbd->emul = 1; | ||
317 | goto out; | ||
318 | case ATKBD_RET_EMUL1: | ||
319 | atkbd->emul = 2; | ||
320 | goto out; | ||
321 | case ATKBD_RET_RELEASE: | ||
322 | atkbd->release = 1; | ||
323 | goto out; | ||
324 | case ATKBD_RET_HANGUEL: | ||
325 | atkbd_report_key(&atkbd->dev, regs, KEY_HANGUEL, 3); | ||
326 | goto out; | ||
327 | case ATKBD_RET_HANJA: | ||
328 | atkbd_report_key(&atkbd->dev, regs, KEY_HANJA, 3); | ||
329 | goto out; | ||
330 | case ATKBD_RET_ERR: | ||
331 | printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | if (atkbd->set != 3) | ||
336 | code = (code & 0x7f) | ((code & 0x80) << 1); | ||
337 | if (atkbd->emul) { | ||
338 | if (--atkbd->emul) | ||
339 | goto out; | ||
340 | code |= (atkbd->set != 3) ? 0x80 : 0x100; | ||
341 | } | ||
342 | |||
343 | if (atkbd->keycode[code] != ATKBD_KEY_NULL) | ||
344 | input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); | ||
345 | |||
346 | switch (atkbd->keycode[code]) { | ||
347 | case ATKBD_KEY_NULL: | ||
348 | break; | ||
349 | case ATKBD_KEY_UNKNOWN: | ||
350 | if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { | ||
351 | printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " | ||
352 | "like XFree86, might be trying access hardware directly.\n", | ||
353 | data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); | ||
354 | } else { | ||
355 | printk(KERN_WARNING "atkbd.c: Unknown key %s " | ||
356 | "(%s set %d, code %#x on %s).\n", | ||
357 | atkbd->release ? "released" : "pressed", | ||
358 | atkbd->translated ? "translated" : "raw", | ||
359 | atkbd->set, code, serio->phys); | ||
360 | printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' " | ||
361 | "to make it known.\n", | ||
362 | code & 0x80 ? "e0" : "", code & 0x7f); | ||
363 | } | ||
364 | input_sync(&atkbd->dev); | ||
365 | break; | ||
366 | case ATKBD_SCR_1: | ||
367 | scroll = 1 - atkbd->release * 2; | ||
368 | break; | ||
369 | case ATKBD_SCR_2: | ||
370 | scroll = 2 - atkbd->release * 4; | ||
371 | break; | ||
372 | case ATKBD_SCR_4: | ||
373 | scroll = 4 - atkbd->release * 8; | ||
374 | break; | ||
375 | case ATKBD_SCR_8: | ||
376 | scroll = 8 - atkbd->release * 16; | ||
377 | break; | ||
378 | case ATKBD_SCR_CLICK: | ||
379 | click = !atkbd->release; | ||
380 | break; | ||
381 | case ATKBD_SCR_LEFT: | ||
382 | hscroll = -1; | ||
383 | break; | ||
384 | case ATKBD_SCR_RIGHT: | ||
385 | hscroll = 1; | ||
386 | break; | ||
387 | default: | ||
388 | value = atkbd->release ? 0 : | ||
389 | (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); | ||
390 | |||
391 | switch (value) { /* Workaround Toshiba laptop multiple keypress */ | ||
392 | case 0: | ||
393 | atkbd->last = 0; | ||
394 | break; | ||
395 | case 1: | ||
396 | atkbd->last = code; | ||
397 | atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev.rep[REP_DELAY]) / 2; | ||
398 | break; | ||
399 | case 2: | ||
400 | if (!time_after(jiffies, atkbd->time) && atkbd->last == code) | ||
401 | value = 1; | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); | ||
406 | } | ||
407 | |||
408 | if (atkbd->scroll) { | ||
409 | input_regs(&atkbd->dev, regs); | ||
410 | if (click != -1) | ||
411 | input_report_key(&atkbd->dev, BTN_MIDDLE, click); | ||
412 | input_report_rel(&atkbd->dev, REL_WHEEL, scroll); | ||
413 | input_report_rel(&atkbd->dev, REL_HWHEEL, hscroll); | ||
414 | input_sync(&atkbd->dev); | ||
415 | } | ||
416 | |||
417 | atkbd->release = 0; | ||
418 | out: | ||
419 | return IRQ_HANDLED; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Event callback from the input module. Events that change the state of | ||
424 | * the hardware are processed here. | ||
425 | */ | ||
426 | |||
427 | static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
428 | { | ||
429 | struct atkbd *atkbd = dev->private; | ||
430 | const short period[32] = | ||
431 | { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, | ||
432 | 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 }; | ||
433 | const short delay[4] = | ||
434 | { 250, 500, 750, 1000 }; | ||
435 | unsigned char param[2]; | ||
436 | int i, j; | ||
437 | |||
438 | if (!atkbd->write) | ||
439 | return -1; | ||
440 | |||
441 | switch (type) { | ||
442 | |||
443 | case EV_LED: | ||
444 | |||
445 | param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | ||
446 | | (test_bit(LED_NUML, dev->led) ? 2 : 0) | ||
447 | | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); | ||
448 | ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS); | ||
449 | |||
450 | if (atkbd->extra) { | ||
451 | param[0] = 0; | ||
452 | param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) | ||
453 | | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) | ||
454 | | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | ||
455 | | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | ||
456 | | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); | ||
457 | ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS); | ||
458 | } | ||
459 | |||
460 | return 0; | ||
461 | |||
462 | |||
463 | case EV_REP: | ||
464 | |||
465 | if (atkbd->softrepeat) return 0; | ||
466 | |||
467 | i = j = 0; | ||
468 | while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++; | ||
469 | while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++; | ||
470 | dev->rep[REP_PERIOD] = period[i]; | ||
471 | dev->rep[REP_DELAY] = delay[j]; | ||
472 | param[0] = i | (j << 5); | ||
473 | ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | return -1; | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * atkbd_enable() signals that interrupt handler is allowed to | ||
483 | * generate input events. | ||
484 | */ | ||
485 | |||
486 | static inline void atkbd_enable(struct atkbd *atkbd) | ||
487 | { | ||
488 | serio_pause_rx(atkbd->ps2dev.serio); | ||
489 | atkbd->enabled = 1; | ||
490 | serio_continue_rx(atkbd->ps2dev.serio); | ||
491 | } | ||
492 | |||
493 | /* | ||
494 | * atkbd_disable() tells input handler that all incoming data except | ||
495 | * for ACKs and command response should be dropped. | ||
496 | */ | ||
497 | |||
498 | static inline void atkbd_disable(struct atkbd *atkbd) | ||
499 | { | ||
500 | serio_pause_rx(atkbd->ps2dev.serio); | ||
501 | atkbd->enabled = 0; | ||
502 | serio_continue_rx(atkbd->ps2dev.serio); | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * atkbd_probe() probes for an AT keyboard on a serio port. | ||
507 | */ | ||
508 | |||
509 | static int atkbd_probe(struct atkbd *atkbd) | ||
510 | { | ||
511 | struct ps2dev *ps2dev = &atkbd->ps2dev; | ||
512 | unsigned char param[2]; | ||
513 | |||
514 | /* | ||
515 | * Some systems, where the bit-twiddling when testing the io-lines of the | ||
516 | * controller may confuse the keyboard need a full reset of the keyboard. On | ||
517 | * these systems the BIOS also usually doesn't do it for us. | ||
518 | */ | ||
519 | |||
520 | if (atkbd_reset) | ||
521 | if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT)) | ||
522 | printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys); | ||
523 | |||
524 | /* | ||
525 | * Then we check the keyboard ID. We should get 0xab83 under normal conditions. | ||
526 | * Some keyboards report different values, but the first byte is always 0xab or | ||
527 | * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this | ||
528 | * should make sure we don't try to set the LEDs on it. | ||
529 | */ | ||
530 | |||
531 | param[0] = param[1] = 0xa5; /* initialize with invalid values */ | ||
532 | if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { | ||
533 | |||
534 | /* | ||
535 | * If the get ID command failed, we check if we can at least set the LEDs on | ||
536 | * the keyboard. This should work on every keyboard out there. It also turns | ||
537 | * the LEDs off, which we want anyway. | ||
538 | */ | ||
539 | param[0] = 0; | ||
540 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
541 | return -1; | ||
542 | atkbd->id = 0xabba; | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */ | ||
547 | param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */ | ||
548 | param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */ | ||
549 | return -1; | ||
550 | |||
551 | atkbd->id = (param[0] << 8) | param[1]; | ||
552 | |||
553 | if (atkbd->id == 0xaca1 && atkbd->translated) { | ||
554 | printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n"); | ||
555 | printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n"); | ||
556 | return -1; | ||
557 | } | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | /* | ||
563 | * atkbd_select_set checks if a keyboard has a working Set 3 support, and | ||
564 | * sets it into that. Unfortunately there are keyboards that can be switched | ||
565 | * to Set 3, but don't work well in that (BTC Multimedia ...) | ||
566 | */ | ||
567 | |||
568 | static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra) | ||
569 | { | ||
570 | struct ps2dev *ps2dev = &atkbd->ps2dev; | ||
571 | unsigned char param[2]; | ||
572 | |||
573 | atkbd->extra = 0; | ||
574 | /* | ||
575 | * For known special keyboards we can go ahead and set the correct set. | ||
576 | * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and | ||
577 | * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards. | ||
578 | */ | ||
579 | |||
580 | if (atkbd->translated) | ||
581 | return 2; | ||
582 | |||
583 | if (atkbd->id == 0xaca1) { | ||
584 | param[0] = 3; | ||
585 | ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET); | ||
586 | return 3; | ||
587 | } | ||
588 | |||
589 | if (allow_extra) { | ||
590 | param[0] = 0x71; | ||
591 | if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) { | ||
592 | atkbd->extra = 1; | ||
593 | return 2; | ||
594 | } | ||
595 | } | ||
596 | |||
597 | if (target_set != 3) | ||
598 | return 2; | ||
599 | |||
600 | if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) { | ||
601 | atkbd->id = param[0] << 8 | param[1]; | ||
602 | return 2; | ||
603 | } | ||
604 | |||
605 | param[0] = 3; | ||
606 | if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) | ||
607 | return 2; | ||
608 | |||
609 | param[0] = 0; | ||
610 | if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET)) | ||
611 | return 2; | ||
612 | |||
613 | if (param[0] != 3) { | ||
614 | param[0] = 2; | ||
615 | if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) | ||
616 | return 2; | ||
617 | } | ||
618 | |||
619 | ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR); | ||
620 | |||
621 | return 3; | ||
622 | } | ||
623 | |||
624 | static int atkbd_activate(struct atkbd *atkbd) | ||
625 | { | ||
626 | struct ps2dev *ps2dev = &atkbd->ps2dev; | ||
627 | unsigned char param[1]; | ||
628 | |||
629 | /* | ||
630 | * Set the LEDs to a defined state. | ||
631 | */ | ||
632 | |||
633 | param[0] = 0; | ||
634 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
635 | return -1; | ||
636 | |||
637 | /* | ||
638 | * Set autorepeat to fastest possible. | ||
639 | */ | ||
640 | |||
641 | param[0] = 0; | ||
642 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP)) | ||
643 | return -1; | ||
644 | |||
645 | /* | ||
646 | * Enable the keyboard to receive keystrokes. | ||
647 | */ | ||
648 | |||
649 | if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { | ||
650 | printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n", | ||
651 | ps2dev->serio->phys); | ||
652 | return -1; | ||
653 | } | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a | ||
660 | * reboot. | ||
661 | */ | ||
662 | |||
663 | static void atkbd_cleanup(struct serio *serio) | ||
664 | { | ||
665 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
666 | ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT); | ||
667 | } | ||
668 | |||
669 | |||
670 | /* | ||
671 | * atkbd_disconnect() closes and frees. | ||
672 | */ | ||
673 | |||
674 | static void atkbd_disconnect(struct serio *serio) | ||
675 | { | ||
676 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
677 | |||
678 | atkbd_disable(atkbd); | ||
679 | |||
680 | /* make sure we don't have a command in flight */ | ||
681 | synchronize_kernel(); | ||
682 | flush_scheduled_work(); | ||
683 | |||
684 | device_remove_file(&serio->dev, &atkbd_attr_extra); | ||
685 | device_remove_file(&serio->dev, &atkbd_attr_scroll); | ||
686 | device_remove_file(&serio->dev, &atkbd_attr_set); | ||
687 | device_remove_file(&serio->dev, &atkbd_attr_softrepeat); | ||
688 | device_remove_file(&serio->dev, &atkbd_attr_softraw); | ||
689 | |||
690 | input_unregister_device(&atkbd->dev); | ||
691 | serio_close(serio); | ||
692 | serio_set_drvdata(serio, NULL); | ||
693 | kfree(atkbd); | ||
694 | } | ||
695 | |||
696 | |||
697 | /* | ||
698 | * atkbd_set_device_attrs() initializes keyboard's keycode table | ||
699 | * according to the selected scancode set | ||
700 | */ | ||
701 | |||
702 | static void atkbd_set_keycode_table(struct atkbd *atkbd) | ||
703 | { | ||
704 | int i, j; | ||
705 | |||
706 | memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); | ||
707 | |||
708 | if (atkbd->translated) { | ||
709 | for (i = 0; i < 128; i++) { | ||
710 | atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; | ||
711 | atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; | ||
712 | if (atkbd->scroll) | ||
713 | for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++) | ||
714 | if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2) | ||
715 | atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode; | ||
716 | } | ||
717 | } else if (atkbd->set == 3) { | ||
718 | memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); | ||
719 | } else { | ||
720 | memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); | ||
721 | |||
722 | if (atkbd->scroll) | ||
723 | for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) | ||
724 | atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | /* | ||
729 | * atkbd_set_device_attrs() sets up keyboard's input device structure | ||
730 | */ | ||
731 | |||
732 | static void atkbd_set_device_attrs(struct atkbd *atkbd) | ||
733 | { | ||
734 | int i; | ||
735 | |||
736 | memset(&atkbd->dev, 0, sizeof(struct input_dev)); | ||
737 | |||
738 | init_input_dev(&atkbd->dev); | ||
739 | |||
740 | atkbd->dev.name = atkbd->name; | ||
741 | atkbd->dev.phys = atkbd->phys; | ||
742 | atkbd->dev.id.bustype = BUS_I8042; | ||
743 | atkbd->dev.id.vendor = 0x0001; | ||
744 | atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set; | ||
745 | atkbd->dev.id.version = atkbd->id; | ||
746 | atkbd->dev.event = atkbd_event; | ||
747 | atkbd->dev.private = atkbd; | ||
748 | atkbd->dev.dev = &atkbd->ps2dev.serio->dev; | ||
749 | |||
750 | atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); | ||
751 | |||
752 | if (atkbd->write) { | ||
753 | atkbd->dev.evbit[0] |= BIT(EV_LED); | ||
754 | atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); | ||
755 | } | ||
756 | |||
757 | if (atkbd->extra) | ||
758 | atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | | ||
759 | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); | ||
760 | |||
761 | if (!atkbd->softrepeat) { | ||
762 | atkbd->dev.rep[REP_DELAY] = 250; | ||
763 | atkbd->dev.rep[REP_PERIOD] = 33; | ||
764 | } | ||
765 | |||
766 | atkbd->dev.mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); | ||
767 | |||
768 | if (atkbd->scroll) { | ||
769 | atkbd->dev.evbit[0] |= BIT(EV_REL); | ||
770 | atkbd->dev.relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL); | ||
771 | set_bit(BTN_MIDDLE, atkbd->dev.keybit); | ||
772 | } | ||
773 | |||
774 | atkbd->dev.keycode = atkbd->keycode; | ||
775 | atkbd->dev.keycodesize = sizeof(unsigned char); | ||
776 | atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode); | ||
777 | |||
778 | for (i = 0; i < 512; i++) | ||
779 | if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) | ||
780 | set_bit(atkbd->keycode[i], atkbd->dev.keybit); | ||
781 | } | ||
782 | |||
783 | /* | ||
784 | * atkbd_connect() is called when the serio module finds an interface | ||
785 | * that isn't handled yet by an appropriate device driver. We check if | ||
786 | * there is an AT keyboard out there and if yes, we register ourselves | ||
787 | * to the input module. | ||
788 | */ | ||
789 | |||
790 | static int atkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
791 | { | ||
792 | struct atkbd *atkbd; | ||
793 | int err; | ||
794 | |||
795 | if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) | ||
796 | return - ENOMEM; | ||
797 | |||
798 | memset(atkbd, 0, sizeof(struct atkbd)); | ||
799 | |||
800 | ps2_init(&atkbd->ps2dev, serio); | ||
801 | |||
802 | switch (serio->id.type) { | ||
803 | |||
804 | case SERIO_8042_XL: | ||
805 | atkbd->translated = 1; | ||
806 | case SERIO_8042: | ||
807 | if (serio->write) | ||
808 | atkbd->write = 1; | ||
809 | break; | ||
810 | } | ||
811 | |||
812 | atkbd->softraw = atkbd_softraw; | ||
813 | atkbd->softrepeat = atkbd_softrepeat; | ||
814 | atkbd->scroll = atkbd_scroll; | ||
815 | |||
816 | if (!atkbd->write) | ||
817 | atkbd->softrepeat = 1; | ||
818 | |||
819 | if (atkbd->softrepeat) | ||
820 | atkbd->softraw = 1; | ||
821 | |||
822 | serio_set_drvdata(serio, atkbd); | ||
823 | |||
824 | err = serio_open(serio, drv); | ||
825 | if (err) { | ||
826 | serio_set_drvdata(serio, NULL); | ||
827 | kfree(atkbd); | ||
828 | return err; | ||
829 | } | ||
830 | |||
831 | if (atkbd->write) { | ||
832 | |||
833 | if (atkbd_probe(atkbd)) { | ||
834 | serio_close(serio); | ||
835 | serio_set_drvdata(serio, NULL); | ||
836 | kfree(atkbd); | ||
837 | return -ENODEV; | ||
838 | } | ||
839 | |||
840 | atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); | ||
841 | atkbd_activate(atkbd); | ||
842 | |||
843 | } else { | ||
844 | atkbd->set = 2; | ||
845 | atkbd->id = 0xab00; | ||
846 | } | ||
847 | |||
848 | if (atkbd->extra) | ||
849 | sprintf(atkbd->name, "AT Set 2 Extra keyboard"); | ||
850 | else | ||
851 | sprintf(atkbd->name, "AT %s Set %d keyboard", | ||
852 | atkbd->translated ? "Translated" : "Raw", atkbd->set); | ||
853 | |||
854 | sprintf(atkbd->phys, "%s/input0", serio->phys); | ||
855 | |||
856 | atkbd_set_keycode_table(atkbd); | ||
857 | atkbd_set_device_attrs(atkbd); | ||
858 | |||
859 | input_register_device(&atkbd->dev); | ||
860 | |||
861 | device_create_file(&serio->dev, &atkbd_attr_extra); | ||
862 | device_create_file(&serio->dev, &atkbd_attr_scroll); | ||
863 | device_create_file(&serio->dev, &atkbd_attr_set); | ||
864 | device_create_file(&serio->dev, &atkbd_attr_softrepeat); | ||
865 | device_create_file(&serio->dev, &atkbd_attr_softraw); | ||
866 | |||
867 | atkbd_enable(atkbd); | ||
868 | |||
869 | printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | /* | ||
875 | * atkbd_reconnect() tries to restore keyboard into a sane state and is | ||
876 | * most likely called on resume. | ||
877 | */ | ||
878 | |||
879 | static int atkbd_reconnect(struct serio *serio) | ||
880 | { | ||
881 | struct atkbd *atkbd = serio_get_drvdata(serio); | ||
882 | struct serio_driver *drv = serio->drv; | ||
883 | unsigned char param[1]; | ||
884 | |||
885 | if (!atkbd || !drv) { | ||
886 | printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); | ||
887 | return -1; | ||
888 | } | ||
889 | |||
890 | atkbd_disable(atkbd); | ||
891 | |||
892 | if (atkbd->write) { | ||
893 | param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) | ||
894 | | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) | ||
895 | | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0); | ||
896 | |||
897 | if (atkbd_probe(atkbd)) | ||
898 | return -1; | ||
899 | if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) | ||
900 | return -1; | ||
901 | |||
902 | atkbd_activate(atkbd); | ||
903 | |||
904 | if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
905 | return -1; | ||
906 | } | ||
907 | |||
908 | atkbd_enable(atkbd); | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | static struct serio_device_id atkbd_serio_ids[] = { | ||
914 | { | ||
915 | .type = SERIO_8042, | ||
916 | .proto = SERIO_ANY, | ||
917 | .id = SERIO_ANY, | ||
918 | .extra = SERIO_ANY, | ||
919 | }, | ||
920 | { | ||
921 | .type = SERIO_8042_XL, | ||
922 | .proto = SERIO_ANY, | ||
923 | .id = SERIO_ANY, | ||
924 | .extra = SERIO_ANY, | ||
925 | }, | ||
926 | { | ||
927 | .type = SERIO_RS232, | ||
928 | .proto = SERIO_PS2SER, | ||
929 | .id = SERIO_ANY, | ||
930 | .extra = SERIO_ANY, | ||
931 | }, | ||
932 | { 0 } | ||
933 | }; | ||
934 | |||
935 | MODULE_DEVICE_TABLE(serio, atkbd_serio_ids); | ||
936 | |||
937 | static struct serio_driver atkbd_drv = { | ||
938 | .driver = { | ||
939 | .name = "atkbd", | ||
940 | }, | ||
941 | .description = DRIVER_DESC, | ||
942 | .id_table = atkbd_serio_ids, | ||
943 | .interrupt = atkbd_interrupt, | ||
944 | .connect = atkbd_connect, | ||
945 | .reconnect = atkbd_reconnect, | ||
946 | .disconnect = atkbd_disconnect, | ||
947 | .cleanup = atkbd_cleanup, | ||
948 | }; | ||
949 | |||
950 | static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, | ||
951 | ssize_t (*handler)(struct atkbd *, char *)) | ||
952 | { | ||
953 | struct serio *serio = to_serio_port(dev); | ||
954 | int retval; | ||
955 | |||
956 | retval = serio_pin_driver(serio); | ||
957 | if (retval) | ||
958 | return retval; | ||
959 | |||
960 | if (serio->drv != &atkbd_drv) { | ||
961 | retval = -ENODEV; | ||
962 | goto out; | ||
963 | } | ||
964 | |||
965 | retval = handler((struct atkbd *)serio_get_drvdata(serio), buf); | ||
966 | |||
967 | out: | ||
968 | serio_unpin_driver(serio); | ||
969 | return retval; | ||
970 | } | ||
971 | |||
972 | static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, | ||
973 | ssize_t (*handler)(struct atkbd *, const char *, size_t)) | ||
974 | { | ||
975 | struct serio *serio = to_serio_port(dev); | ||
976 | struct atkbd *atkbd; | ||
977 | int retval; | ||
978 | |||
979 | retval = serio_pin_driver(serio); | ||
980 | if (retval) | ||
981 | return retval; | ||
982 | |||
983 | if (serio->drv != &atkbd_drv) { | ||
984 | retval = -ENODEV; | ||
985 | goto out; | ||
986 | } | ||
987 | |||
988 | atkbd = serio_get_drvdata(serio); | ||
989 | atkbd_disable(atkbd); | ||
990 | retval = handler(atkbd, buf, count); | ||
991 | atkbd_enable(atkbd); | ||
992 | |||
993 | out: | ||
994 | serio_unpin_driver(serio); | ||
995 | return retval; | ||
996 | } | ||
997 | |||
998 | static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) | ||
999 | { | ||
1000 | return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0); | ||
1001 | } | ||
1002 | |||
1003 | static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) | ||
1004 | { | ||
1005 | unsigned long value; | ||
1006 | char *rest; | ||
1007 | |||
1008 | if (!atkbd->write) | ||
1009 | return -EIO; | ||
1010 | |||
1011 | value = simple_strtoul(buf, &rest, 10); | ||
1012 | if (*rest || value > 1) | ||
1013 | return -EINVAL; | ||
1014 | |||
1015 | if (atkbd->extra != value) { | ||
1016 | /* unregister device as it's properties will change */ | ||
1017 | input_unregister_device(&atkbd->dev); | ||
1018 | atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); | ||
1019 | atkbd_activate(atkbd); | ||
1020 | atkbd_set_device_attrs(atkbd); | ||
1021 | input_register_device(&atkbd->dev); | ||
1022 | } | ||
1023 | return count; | ||
1024 | } | ||
1025 | |||
1026 | static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) | ||
1027 | { | ||
1028 | return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); | ||
1029 | } | ||
1030 | |||
1031 | static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) | ||
1032 | { | ||
1033 | unsigned long value; | ||
1034 | char *rest; | ||
1035 | |||
1036 | value = simple_strtoul(buf, &rest, 10); | ||
1037 | if (*rest || value > 1) | ||
1038 | return -EINVAL; | ||
1039 | |||
1040 | if (atkbd->scroll != value) { | ||
1041 | /* unregister device as it's properties will change */ | ||
1042 | input_unregister_device(&atkbd->dev); | ||
1043 | atkbd->scroll = value; | ||
1044 | atkbd_set_keycode_table(atkbd); | ||
1045 | atkbd_set_device_attrs(atkbd); | ||
1046 | input_register_device(&atkbd->dev); | ||
1047 | } | ||
1048 | return count; | ||
1049 | } | ||
1050 | |||
1051 | static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) | ||
1052 | { | ||
1053 | return sprintf(buf, "%d\n", atkbd->set); | ||
1054 | } | ||
1055 | |||
1056 | static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) | ||
1057 | { | ||
1058 | unsigned long value; | ||
1059 | char *rest; | ||
1060 | |||
1061 | if (!atkbd->write) | ||
1062 | return -EIO; | ||
1063 | |||
1064 | value = simple_strtoul(buf, &rest, 10); | ||
1065 | if (*rest || (value != 2 && value != 3)) | ||
1066 | return -EINVAL; | ||
1067 | |||
1068 | if (atkbd->set != value) { | ||
1069 | /* unregister device as it's properties will change */ | ||
1070 | input_unregister_device(&atkbd->dev); | ||
1071 | atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); | ||
1072 | atkbd_activate(atkbd); | ||
1073 | atkbd_set_keycode_table(atkbd); | ||
1074 | atkbd_set_device_attrs(atkbd); | ||
1075 | input_register_device(&atkbd->dev); | ||
1076 | } | ||
1077 | return count; | ||
1078 | } | ||
1079 | |||
1080 | static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) | ||
1081 | { | ||
1082 | return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0); | ||
1083 | } | ||
1084 | |||
1085 | static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) | ||
1086 | { | ||
1087 | unsigned long value; | ||
1088 | char *rest; | ||
1089 | |||
1090 | if (!atkbd->write) | ||
1091 | return -EIO; | ||
1092 | |||
1093 | value = simple_strtoul(buf, &rest, 10); | ||
1094 | if (*rest || value > 1) | ||
1095 | return -EINVAL; | ||
1096 | |||
1097 | if (atkbd->softrepeat != value) { | ||
1098 | /* unregister device as it's properties will change */ | ||
1099 | input_unregister_device(&atkbd->dev); | ||
1100 | atkbd->softrepeat = value; | ||
1101 | if (atkbd->softrepeat) | ||
1102 | atkbd->softraw = 1; | ||
1103 | atkbd_set_device_attrs(atkbd); | ||
1104 | input_register_device(&atkbd->dev); | ||
1105 | } | ||
1106 | |||
1107 | return count; | ||
1108 | } | ||
1109 | |||
1110 | |||
1111 | static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) | ||
1112 | { | ||
1113 | return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0); | ||
1114 | } | ||
1115 | |||
1116 | static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) | ||
1117 | { | ||
1118 | unsigned long value; | ||
1119 | char *rest; | ||
1120 | |||
1121 | value = simple_strtoul(buf, &rest, 10); | ||
1122 | if (*rest || value > 1) | ||
1123 | return -EINVAL; | ||
1124 | |||
1125 | if (atkbd->softraw != value) { | ||
1126 | /* unregister device as it's properties will change */ | ||
1127 | input_unregister_device(&atkbd->dev); | ||
1128 | atkbd->softraw = value; | ||
1129 | atkbd_set_device_attrs(atkbd); | ||
1130 | input_register_device(&atkbd->dev); | ||
1131 | } | ||
1132 | return count; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | static int __init atkbd_init(void) | ||
1137 | { | ||
1138 | serio_register_driver(&atkbd_drv); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static void __exit atkbd_exit(void) | ||
1143 | { | ||
1144 | serio_unregister_driver(&atkbd_drv); | ||
1145 | } | ||
1146 | |||
1147 | module_init(atkbd_init); | ||
1148 | module_exit(atkbd_exit); | ||
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c new file mode 100644 index 000000000000..0f1220a0ceb5 --- /dev/null +++ b/drivers/input/keyboard/corgikbd.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * Keyboard driver for Sharp Corgi models (SL-C7xx) | ||
3 | * | ||
4 | * Copyright (c) 2004-2005 Richard Purdie | ||
5 | * | ||
6 | * Based on xtkbd.c/locomkbd.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/input.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <asm/irq.h> | ||
22 | |||
23 | #include <asm/arch/corgi.h> | ||
24 | #include <asm/arch/hardware.h> | ||
25 | #include <asm/arch/pxa-regs.h> | ||
26 | #include <asm/hardware/scoop.h> | ||
27 | |||
28 | #define KB_ROWS 8 | ||
29 | #define KB_COLS 12 | ||
30 | #define KB_ROWMASK(r) (1 << (r)) | ||
31 | #define SCANCODE(r,c) ( ((r)<<4) + (c) + 1 ) | ||
32 | /* zero code, 124 scancodes + 3 hinge combinations */ | ||
33 | #define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 ) | ||
34 | #define SCAN_INTERVAL (HZ/10) | ||
35 | #define CORGIKBD_PRESSED 1 | ||
36 | |||
37 | #define HINGE_SCAN_INTERVAL (HZ/4) | ||
38 | |||
39 | #define CORGI_KEY_CALENDER KEY_F1 | ||
40 | #define CORGI_KEY_ADDRESS KEY_F2 | ||
41 | #define CORGI_KEY_FN KEY_F3 | ||
42 | #define CORGI_KEY_OFF KEY_SUSPEND | ||
43 | #define CORGI_KEY_EXOK KEY_F5 | ||
44 | #define CORGI_KEY_EXCANCEL KEY_F6 | ||
45 | #define CORGI_KEY_EXJOGDOWN KEY_F7 | ||
46 | #define CORGI_KEY_EXJOGUP KEY_F8 | ||
47 | #define CORGI_KEY_JAP1 KEY_LEFTCTRL | ||
48 | #define CORGI_KEY_JAP2 KEY_LEFTALT | ||
49 | #define CORGI_KEY_OK KEY_F11 | ||
50 | #define CORGI_KEY_MENU KEY_F12 | ||
51 | #define CORGI_HINGE_0 KEY_KP0 | ||
52 | #define CORGI_HINGE_1 KEY_KP1 | ||
53 | #define CORGI_HINGE_2 KEY_KP2 | ||
54 | |||
55 | static unsigned char corgikbd_keycode[NR_SCANCODES] = { | ||
56 | 0, /* 0 */ | ||
57 | 0, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, 0, 0, 0, 0, 0, 0, 0, /* 1-16 */ | ||
58 | 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, 0, 0, 0, 0, 0, 0, 0, /* 17-32 */ | ||
59 | KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */ | ||
60 | CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */ | ||
61 | CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, /* 65-80 */ | ||
62 | KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */ | ||
63 | KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */ | ||
64 | CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0, /* 113-124 */ | ||
65 | CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2 /* 125-127 */ | ||
66 | }; | ||
67 | |||
68 | |||
69 | struct corgikbd { | ||
70 | unsigned char keycode[ARRAY_SIZE(corgikbd_keycode)]; | ||
71 | struct input_dev input; | ||
72 | char phys[32]; | ||
73 | |||
74 | unsigned char state[ARRAY_SIZE(corgikbd_keycode)]; | ||
75 | spinlock_t lock; | ||
76 | |||
77 | struct timer_list timer; | ||
78 | struct timer_list htimer; | ||
79 | }; | ||
80 | |||
81 | static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data) | ||
82 | { | ||
83 | if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) { | ||
84 | corgikbd_data->state[scancode] |= CORGIKBD_PRESSED; | ||
85 | input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1); | ||
86 | if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF) | ||
87 | input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); | ||
88 | } else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) { | ||
89 | corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED; | ||
90 | input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | #define KB_DISCHARGE_DELAY 10 | ||
95 | #define KB_ACTIVATE_DELAY 10 | ||
96 | |||
97 | /* Helper functions for reading the keyboard matrix | ||
98 | * Note: We should really be using pxa_gpio_mode to alter GPDR but it | ||
99 | * requires a function call per GPIO bit which is excessive | ||
100 | * when we need to access 12 bits at once multiple times. | ||
101 | * These functions must be called within local_irq_save()/local_irq_restore() | ||
102 | * or similar. | ||
103 | */ | ||
104 | static inline void corgikbd_discharge_all(void) | ||
105 | { | ||
106 | // STROBE All HiZ | ||
107 | GPCR2 = CORGI_GPIO_ALL_STROBE_BIT; | ||
108 | GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT; | ||
109 | } | ||
110 | |||
111 | static inline void corgikbd_activate_all(void) | ||
112 | { | ||
113 | // STROBE ALL -> High | ||
114 | GPSR2 = CORGI_GPIO_ALL_STROBE_BIT; | ||
115 | GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT; | ||
116 | |||
117 | udelay(KB_DISCHARGE_DELAY); | ||
118 | |||
119 | // Clear any interrupts we may have triggered when altering the GPIO lines | ||
120 | GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT; | ||
121 | GEDR2 = CORGI_GPIO_LOW_SENSE_BIT; | ||
122 | } | ||
123 | |||
124 | static inline void corgikbd_activate_col(int col) | ||
125 | { | ||
126 | // STROBE col -> High, not col -> HiZ | ||
127 | GPSR2 = CORGI_GPIO_STROBE_BIT(col); | ||
128 | GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col); | ||
129 | } | ||
130 | |||
131 | static inline void corgikbd_reset_col(int col) | ||
132 | { | ||
133 | // STROBE col -> Low | ||
134 | GPCR2 = CORGI_GPIO_STROBE_BIT(col); | ||
135 | // STROBE col -> out, not col -> HiZ | ||
136 | GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col); | ||
137 | } | ||
138 | |||
139 | #define GET_ROWS_STATUS(c) (((GPLR1 & CORGI_GPIO_HIGH_SENSE_BIT) >> CORGI_GPIO_HIGH_SENSE_RSHIFT) | ((GPLR2 & CORGI_GPIO_LOW_SENSE_BIT) << CORGI_GPIO_LOW_SENSE_LSHIFT)) | ||
140 | |||
141 | /* | ||
142 | * The corgi keyboard only generates interrupts when a key is pressed. | ||
143 | * When a key is pressed, we enable a timer which then scans the | ||
144 | * keyboard to detect when the key is released. | ||
145 | */ | ||
146 | |||
147 | /* Scan the hardware keyboard and push any changes up through the input layer */ | ||
148 | static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs) | ||
149 | { | ||
150 | unsigned int row, col, rowd, scancode; | ||
151 | unsigned long flags; | ||
152 | unsigned int num_pressed; | ||
153 | |||
154 | spin_lock_irqsave(&corgikbd_data->lock, flags); | ||
155 | |||
156 | if (regs) | ||
157 | input_regs(&corgikbd_data->input, regs); | ||
158 | |||
159 | num_pressed = 0; | ||
160 | for (col = 0; col < KB_COLS; col++) { | ||
161 | /* | ||
162 | * Discharge the output driver capacitatance | ||
163 | * in the keyboard matrix. (Yes it is significant..) | ||
164 | */ | ||
165 | |||
166 | corgikbd_discharge_all(); | ||
167 | udelay(KB_DISCHARGE_DELAY); | ||
168 | |||
169 | corgikbd_activate_col(col); | ||
170 | udelay(KB_ACTIVATE_DELAY); | ||
171 | |||
172 | rowd = GET_ROWS_STATUS(col); | ||
173 | for (row = 0; row < KB_ROWS; row++) { | ||
174 | scancode = SCANCODE(row, col); | ||
175 | handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data); | ||
176 | if (rowd & KB_ROWMASK(row)) | ||
177 | num_pressed++; | ||
178 | } | ||
179 | corgikbd_reset_col(col); | ||
180 | } | ||
181 | |||
182 | corgikbd_activate_all(); | ||
183 | |||
184 | input_sync(&corgikbd_data->input); | ||
185 | |||
186 | /* if any keys are pressed, enable the timer */ | ||
187 | if (num_pressed) | ||
188 | mod_timer(&corgikbd_data->timer, jiffies + SCAN_INTERVAL); | ||
189 | |||
190 | spin_unlock_irqrestore(&corgikbd_data->lock, flags); | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * corgi keyboard interrupt handler. | ||
195 | */ | ||
196 | static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
197 | { | ||
198 | struct corgikbd *corgikbd_data = dev_id; | ||
199 | |||
200 | if (!timer_pending(&corgikbd_data->timer)) { | ||
201 | /** wait chattering delay **/ | ||
202 | udelay(20); | ||
203 | corgikbd_scankeyboard(corgikbd_data, regs); | ||
204 | } | ||
205 | |||
206 | return IRQ_HANDLED; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * corgi timer checking for released keys | ||
211 | */ | ||
212 | static void corgikbd_timer_callback(unsigned long data) | ||
213 | { | ||
214 | struct corgikbd *corgikbd_data = (struct corgikbd *) data; | ||
215 | corgikbd_scankeyboard(corgikbd_data, NULL); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * The hinge switches generate no interrupt so they need to be | ||
220 | * monitored by a timer. | ||
221 | * | ||
222 | * When we detect changes, we debounce it and then pass the three | ||
223 | * positions the system can take as keypresses to the input system. | ||
224 | */ | ||
225 | |||
226 | #define HINGE_STABLE_COUNT 2 | ||
227 | static int sharpsl_hinge_state; | ||
228 | static int hinge_count; | ||
229 | |||
230 | static void corgikbd_hinge_timer(unsigned long data) | ||
231 | { | ||
232 | struct corgikbd *corgikbd_data = (struct corgikbd *) data; | ||
233 | unsigned long gprr; | ||
234 | unsigned long flags; | ||
235 | |||
236 | gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB); | ||
237 | if (gprr != sharpsl_hinge_state) { | ||
238 | hinge_count = 0; | ||
239 | sharpsl_hinge_state = gprr; | ||
240 | } else if (hinge_count < HINGE_STABLE_COUNT) { | ||
241 | hinge_count++; | ||
242 | if (hinge_count >= HINGE_STABLE_COUNT) { | ||
243 | spin_lock_irqsave(&corgikbd_data->lock, flags); | ||
244 | |||
245 | handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */ | ||
246 | handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */ | ||
247 | handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed */ | ||
248 | input_sync(&corgikbd_data->input); | ||
249 | |||
250 | spin_unlock_irqrestore(&corgikbd_data->lock, flags); | ||
251 | } | ||
252 | } | ||
253 | mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL); | ||
254 | } | ||
255 | |||
256 | static int __init corgikbd_probe(struct device *dev) | ||
257 | { | ||
258 | int i; | ||
259 | struct corgikbd *corgikbd; | ||
260 | |||
261 | corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL); | ||
262 | if (!corgikbd) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | dev_set_drvdata(dev,corgikbd); | ||
266 | strcpy(corgikbd->phys, "corgikbd/input0"); | ||
267 | |||
268 | spin_lock_init(corgikbd->lock); | ||
269 | |||
270 | /* Init Keyboard rescan timer */ | ||
271 | init_timer(&corgikbd->timer); | ||
272 | corgikbd->timer.function = corgikbd_timer_callback; | ||
273 | corgikbd->timer.data = (unsigned long) corgikbd; | ||
274 | |||
275 | /* Init Hinge Timer */ | ||
276 | init_timer(&corgikbd->htimer); | ||
277 | corgikbd->htimer.function = corgikbd_hinge_timer; | ||
278 | corgikbd->htimer.data = (unsigned long) corgikbd; | ||
279 | |||
280 | init_input_dev(&corgikbd->input); | ||
281 | corgikbd->input.private = corgikbd; | ||
282 | corgikbd->input.name = "Corgi Keyboard"; | ||
283 | corgikbd->input.dev = dev; | ||
284 | corgikbd->input.phys = corgikbd->phys; | ||
285 | corgikbd->input.id.bustype = BUS_HOST; | ||
286 | corgikbd->input.id.vendor = 0x0001; | ||
287 | corgikbd->input.id.product = 0x0001; | ||
288 | corgikbd->input.id.version = 0x0100; | ||
289 | corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR); | ||
290 | corgikbd->input.keycode = corgikbd->keycode; | ||
291 | corgikbd->input.keycodesize = sizeof(unsigned char); | ||
292 | corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode); | ||
293 | |||
294 | memcpy(corgikbd->keycode, corgikbd_keycode, sizeof(corgikbd->keycode)); | ||
295 | for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++) | ||
296 | set_bit(corgikbd->keycode[i], corgikbd->input.keybit); | ||
297 | clear_bit(0, corgikbd->input.keybit); | ||
298 | |||
299 | input_register_device(&corgikbd->input); | ||
300 | mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL); | ||
301 | |||
302 | /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ | ||
303 | for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) { | ||
304 | pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN); | ||
305 | if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt, | ||
306 | SA_INTERRUPT, "corgikbd", corgikbd)) | ||
307 | printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i); | ||
308 | else | ||
309 | set_irq_type(CORGI_IRQ_GPIO_KEY_SENSE(i),IRQT_RISING); | ||
310 | } | ||
311 | |||
312 | /* Set Strobe lines as outputs - set high */ | ||
313 | for (i = 0; i < CORGI_KEY_STROBE_NUM; i++) | ||
314 | pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH); | ||
315 | |||
316 | printk(KERN_INFO "input: Corgi Keyboard Registered\n"); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int corgikbd_remove(struct device *dev) | ||
322 | { | ||
323 | int i; | ||
324 | struct corgikbd *corgikbd = dev_get_drvdata(dev); | ||
325 | |||
326 | for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) | ||
327 | free_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd); | ||
328 | |||
329 | del_timer_sync(&corgikbd->htimer); | ||
330 | del_timer_sync(&corgikbd->timer); | ||
331 | |||
332 | input_unregister_device(&corgikbd->input); | ||
333 | |||
334 | kfree(corgikbd); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static struct device_driver corgikbd_driver = { | ||
340 | .name = "corgi-keyboard", | ||
341 | .bus = &platform_bus_type, | ||
342 | .probe = corgikbd_probe, | ||
343 | .remove = corgikbd_remove, | ||
344 | }; | ||
345 | |||
346 | static int __devinit corgikbd_init(void) | ||
347 | { | ||
348 | return driver_register(&corgikbd_driver); | ||
349 | } | ||
350 | |||
351 | static void __exit corgikbd_exit(void) | ||
352 | { | ||
353 | driver_unregister(&corgikbd_driver); | ||
354 | } | ||
355 | |||
356 | module_init(corgikbd_init); | ||
357 | module_exit(corgikbd_exit); | ||
358 | |||
359 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); | ||
360 | MODULE_DESCRIPTION("Corgi Keyboard Driver"); | ||
361 | MODULE_LICENSE("GPLv2"); | ||
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c new file mode 100644 index 000000000000..ef78bffed5e7 --- /dev/null +++ b/drivers/input/keyboard/hil_kbd.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * Generic linux-input device driver for keyboard devices | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/hil.h> | ||
35 | #include <linux/input.h> | ||
36 | #include <linux/serio.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/pci_ids.h> | ||
42 | |||
43 | #define PREFIX "HIL KEYB: " | ||
44 | #define HIL_GENERIC_NAME "HIL keyboard" | ||
45 | |||
46 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
47 | MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); | ||
48 | MODULE_LICENSE("Dual BSD/GPL"); | ||
49 | |||
50 | #define HIL_KBD_MAX_LENGTH 16 | ||
51 | |||
52 | #define HIL_KBD_SET1_UPBIT 0x01 | ||
53 | #define HIL_KBD_SET1_SHIFT 1 | ||
54 | static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] = | ||
55 | { HIL_KEYCODES_SET1 }; | ||
56 | |||
57 | #define HIL_KBD_SET2_UPBIT 0x01 | ||
58 | #define HIL_KBD_SET2_SHIFT 1 | ||
59 | /* Set2 is user defined */ | ||
60 | |||
61 | #define HIL_KBD_SET3_UPBIT 0x80 | ||
62 | #define HIL_KBD_SET3_SHIFT 0 | ||
63 | static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] = | ||
64 | { HIL_KEYCODES_SET3 }; | ||
65 | |||
66 | static char hil_language[][16] = { HIL_LOCALE_MAP }; | ||
67 | |||
68 | struct hil_kbd { | ||
69 | struct input_dev dev; | ||
70 | struct serio *serio; | ||
71 | |||
72 | /* Input buffer and index for packets from HIL bus. */ | ||
73 | hil_packet data[HIL_KBD_MAX_LENGTH]; | ||
74 | int idx4; /* four counts per packet */ | ||
75 | |||
76 | /* Raw device info records from HIL bus, see hil.h for fields. */ | ||
77 | char idd[HIL_KBD_MAX_LENGTH]; /* DID byte and IDD record */ | ||
78 | char rsc[HIL_KBD_MAX_LENGTH]; /* RSC record */ | ||
79 | char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */ | ||
80 | char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */ | ||
81 | |||
82 | /* Something to sleep around with. */ | ||
83 | struct semaphore sem; | ||
84 | }; | ||
85 | |||
86 | /* Process a complete packet after transfer from the HIL */ | ||
87 | static void hil_kbd_process_record(struct hil_kbd *kbd) | ||
88 | { | ||
89 | struct input_dev *dev = &kbd->dev; | ||
90 | hil_packet *data = kbd->data; | ||
91 | hil_packet p; | ||
92 | int idx, i, cnt; | ||
93 | |||
94 | idx = kbd->idx4/4; | ||
95 | p = data[idx - 1]; | ||
96 | |||
97 | if ((p & ~HIL_CMDCT_POL) == | ||
98 | (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report; | ||
99 | if ((p & ~HIL_CMDCT_RPL) == | ||
100 | (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report; | ||
101 | |||
102 | /* Not a poll response. See if we are loading config records. */ | ||
103 | switch (p & HIL_PKT_DATA_MASK) { | ||
104 | case HIL_CMD_IDD: | ||
105 | for (i = 0; i < idx; i++) | ||
106 | kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
107 | for (; i < HIL_KBD_MAX_LENGTH; i++) | ||
108 | kbd->idd[i] = 0; | ||
109 | break; | ||
110 | case HIL_CMD_RSC: | ||
111 | for (i = 0; i < idx; i++) | ||
112 | kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
113 | for (; i < HIL_KBD_MAX_LENGTH; i++) | ||
114 | kbd->rsc[i] = 0; | ||
115 | break; | ||
116 | case HIL_CMD_EXD: | ||
117 | for (i = 0; i < idx; i++) | ||
118 | kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
119 | for (; i < HIL_KBD_MAX_LENGTH; i++) | ||
120 | kbd->exd[i] = 0; | ||
121 | break; | ||
122 | case HIL_CMD_RNM: | ||
123 | for (i = 0; i < idx; i++) | ||
124 | kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK; | ||
125 | for (; i < HIL_KBD_MAX_LENGTH + 1; i++) | ||
126 | kbd->rnm[i] = '\0'; | ||
127 | break; | ||
128 | default: | ||
129 | /* These occur when device isn't present */ | ||
130 | if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; | ||
131 | /* Anything else we'd like to know about. */ | ||
132 | printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); | ||
133 | break; | ||
134 | } | ||
135 | goto out; | ||
136 | |||
137 | report: | ||
138 | cnt = 1; | ||
139 | switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { | ||
140 | case HIL_POL_CHARTYPE_NONE: | ||
141 | break; | ||
142 | case HIL_POL_CHARTYPE_ASCII: | ||
143 | while (cnt < idx - 1) | ||
144 | input_report_key(dev, kbd->data[cnt++] & 0x7f, 1); | ||
145 | break; | ||
146 | case HIL_POL_CHARTYPE_RSVD1: | ||
147 | case HIL_POL_CHARTYPE_RSVD2: | ||
148 | case HIL_POL_CHARTYPE_BINARY: | ||
149 | while (cnt < idx - 1) | ||
150 | input_report_key(dev, kbd->data[cnt++], 1); | ||
151 | break; | ||
152 | case HIL_POL_CHARTYPE_SET1: | ||
153 | while (cnt < idx - 1) { | ||
154 | unsigned int key; | ||
155 | int up; | ||
156 | key = kbd->data[cnt++]; | ||
157 | up = key & HIL_KBD_SET1_UPBIT; | ||
158 | key &= (~HIL_KBD_SET1_UPBIT & 0xff); | ||
159 | key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT]; | ||
160 | if (key != KEY_RESERVED) | ||
161 | input_report_key(dev, key, !up); | ||
162 | } | ||
163 | break; | ||
164 | case HIL_POL_CHARTYPE_SET2: | ||
165 | while (cnt < idx - 1) { | ||
166 | unsigned int key; | ||
167 | int up; | ||
168 | key = kbd->data[cnt++]; | ||
169 | up = key & HIL_KBD_SET2_UPBIT; | ||
170 | key &= (~HIL_KBD_SET1_UPBIT & 0xff); | ||
171 | key = key >> HIL_KBD_SET2_SHIFT; | ||
172 | if (key != KEY_RESERVED) | ||
173 | input_report_key(dev, key, !up); | ||
174 | } | ||
175 | break; | ||
176 | case HIL_POL_CHARTYPE_SET3: | ||
177 | while (cnt < idx - 1) { | ||
178 | unsigned int key; | ||
179 | int up; | ||
180 | key = kbd->data[cnt++]; | ||
181 | up = key & HIL_KBD_SET3_UPBIT; | ||
182 | key &= (~HIL_KBD_SET1_UPBIT & 0xff); | ||
183 | key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT]; | ||
184 | if (key != KEY_RESERVED) | ||
185 | input_report_key(dev, key, !up); | ||
186 | } | ||
187 | break; | ||
188 | } | ||
189 | out: | ||
190 | kbd->idx4 = 0; | ||
191 | up(&kbd->sem); | ||
192 | } | ||
193 | |||
194 | static void hil_kbd_process_err(struct hil_kbd *kbd) { | ||
195 | printk(KERN_WARNING PREFIX "errored HIL packet\n"); | ||
196 | kbd->idx4 = 0; | ||
197 | up(&kbd->sem); | ||
198 | } | ||
199 | |||
200 | static irqreturn_t hil_kbd_interrupt(struct serio *serio, | ||
201 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
202 | { | ||
203 | struct hil_kbd *kbd; | ||
204 | hil_packet packet; | ||
205 | int idx; | ||
206 | |||
207 | kbd = (struct hil_kbd *)serio->private; | ||
208 | if (kbd == NULL) { | ||
209 | BUG(); | ||
210 | return IRQ_HANDLED; | ||
211 | } | ||
212 | |||
213 | if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) { | ||
214 | hil_kbd_process_err(kbd); | ||
215 | return IRQ_HANDLED; | ||
216 | } | ||
217 | idx = kbd->idx4/4; | ||
218 | if (!(kbd->idx4 % 4)) kbd->data[idx] = 0; | ||
219 | packet = kbd->data[idx]; | ||
220 | packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8); | ||
221 | kbd->data[idx] = packet; | ||
222 | |||
223 | /* Records of N 4-byte hil_packets must terminate with a command. */ | ||
224 | if ((++(kbd->idx4)) % 4) return IRQ_HANDLED; | ||
225 | if ((packet & 0xffff0000) != HIL_ERR_INT) { | ||
226 | hil_kbd_process_err(kbd); | ||
227 | return IRQ_HANDLED; | ||
228 | } | ||
229 | if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd); | ||
230 | return IRQ_HANDLED; | ||
231 | } | ||
232 | |||
233 | static void hil_kbd_disconnect(struct serio *serio) | ||
234 | { | ||
235 | struct hil_kbd *kbd; | ||
236 | |||
237 | kbd = (struct hil_kbd *)serio->private; | ||
238 | if (kbd == NULL) { | ||
239 | BUG(); | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | input_unregister_device(&kbd->dev); | ||
244 | serio_close(serio); | ||
245 | kfree(kbd); | ||
246 | } | ||
247 | |||
248 | static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) | ||
249 | { | ||
250 | struct hil_kbd *kbd; | ||
251 | uint8_t did, *idd; | ||
252 | int i; | ||
253 | |||
254 | if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; | ||
255 | |||
256 | if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return; | ||
257 | memset(kbd, 0, sizeof(struct hil_kbd)); | ||
258 | |||
259 | if (serio_open(serio, drv)) goto bail0; | ||
260 | |||
261 | serio->private = kbd; | ||
262 | kbd->serio = serio; | ||
263 | kbd->dev.private = kbd; | ||
264 | |||
265 | init_MUTEX_LOCKED(&(kbd->sem)); | ||
266 | |||
267 | /* Get device info. MLC driver supplies devid/status/etc. */ | ||
268 | serio->write(serio, 0); | ||
269 | serio->write(serio, 0); | ||
270 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
271 | serio->write(serio, HIL_CMD_IDD); | ||
272 | down(&(kbd->sem)); | ||
273 | |||
274 | serio->write(serio, 0); | ||
275 | serio->write(serio, 0); | ||
276 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
277 | serio->write(serio, HIL_CMD_RSC); | ||
278 | down(&(kbd->sem)); | ||
279 | |||
280 | serio->write(serio, 0); | ||
281 | serio->write(serio, 0); | ||
282 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
283 | serio->write(serio, HIL_CMD_RNM); | ||
284 | down(&(kbd->sem)); | ||
285 | |||
286 | serio->write(serio, 0); | ||
287 | serio->write(serio, 0); | ||
288 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
289 | serio->write(serio, HIL_CMD_EXD); | ||
290 | down(&(kbd->sem)); | ||
291 | |||
292 | up(&(kbd->sem)); | ||
293 | |||
294 | did = kbd->idd[0]; | ||
295 | idd = kbd->idd + 1; | ||
296 | switch (did & HIL_IDD_DID_TYPE_MASK) { | ||
297 | case HIL_IDD_DID_TYPE_KB_INTEGRAL: | ||
298 | case HIL_IDD_DID_TYPE_KB_ITF: | ||
299 | case HIL_IDD_DID_TYPE_KB_RSVD: | ||
300 | case HIL_IDD_DID_TYPE_CHAR: | ||
301 | printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", | ||
302 | did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); | ||
303 | break; | ||
304 | default: | ||
305 | goto bail1; | ||
306 | } | ||
307 | |||
308 | if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { | ||
309 | printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); | ||
310 | goto bail1; | ||
311 | } | ||
312 | |||
313 | |||
314 | kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
315 | kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); | ||
316 | kbd->dev.keycodemax = HIL_KEYCODES_SET1_TBLSIZE; | ||
317 | kbd->dev.keycodesize = sizeof(hil_kbd_set1[0]); | ||
318 | kbd->dev.keycode = hil_kbd_set1; | ||
319 | kbd->dev.name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; | ||
320 | kbd->dev.phys = "hpkbd/input0"; /* XXX */ | ||
321 | |||
322 | kbd->dev.id.bustype = BUS_HIL; | ||
323 | kbd->dev.id.vendor = PCI_VENDOR_ID_HP; | ||
324 | kbd->dev.id.product = 0x0001; /* TODO: get from kbd->rsc */ | ||
325 | kbd->dev.id.version = 0x0100; /* TODO: get from kbd->rsc */ | ||
326 | kbd->dev.dev = &serio->dev; | ||
327 | |||
328 | for (i = 0; i < 128; i++) { | ||
329 | set_bit(hil_kbd_set1[i], kbd->dev.keybit); | ||
330 | set_bit(hil_kbd_set3[i], kbd->dev.keybit); | ||
331 | } | ||
332 | clear_bit(0, kbd->dev.keybit); | ||
333 | |||
334 | input_register_device(&kbd->dev); | ||
335 | printk(KERN_INFO "input: %s, ID: %d\n", | ||
336 | kbd->dev.name, did); | ||
337 | |||
338 | serio->write(serio, 0); | ||
339 | serio->write(serio, 0); | ||
340 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
341 | serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ | ||
342 | down(&(kbd->sem)); | ||
343 | up(&(kbd->sem)); | ||
344 | |||
345 | return; | ||
346 | bail1: | ||
347 | serio_close(serio); | ||
348 | bail0: | ||
349 | kfree(kbd); | ||
350 | } | ||
351 | |||
352 | |||
353 | struct serio_driver hil_kbd_serio_drv = { | ||
354 | .driver = { | ||
355 | .name = "hil_kbd", | ||
356 | }, | ||
357 | .description = "HP HIL keyboard driver", | ||
358 | .connect = hil_kbd_connect, | ||
359 | .disconnect = hil_kbd_disconnect, | ||
360 | .interrupt = hil_kbd_interrupt | ||
361 | }; | ||
362 | |||
363 | static int __init hil_kbd_init(void) | ||
364 | { | ||
365 | serio_register_driver(&hil_kbd_serio_drv); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static void __exit hil_kbd_exit(void) | ||
370 | { | ||
371 | serio_unregister_driver(&hil_kbd_serio_drv); | ||
372 | } | ||
373 | |||
374 | module_init(hil_kbd_init); | ||
375 | module_exit(hil_kbd_exit); | ||
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c new file mode 100644 index 000000000000..eecb77db0847 --- /dev/null +++ b/drivers/input/keyboard/hilkbd.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * linux/drivers/hil/hilkbd.c | ||
3 | * | ||
4 | * Copyright (C) 1998 Philip Blundell <philb@gnu.org> | ||
5 | * Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai> | ||
6 | * Copyright (C) 1999-2003 Helge Deller <deller@gmx.de> | ||
7 | * | ||
8 | * Very basic HP Human Interface Loop (HIL) driver. | ||
9 | * This driver handles the keyboard on HP300 (m68k) and on some | ||
10 | * HP700 (parisc) series machines. | ||
11 | * | ||
12 | * | ||
13 | * This file is subject to the terms and conditions of the GNU General Public | ||
14 | * License version 2. See the file COPYING in the main directory of this | ||
15 | * archive for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/pci_ids.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/hil.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | |||
29 | |||
30 | MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller"); | ||
31 | MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)"); | ||
32 | MODULE_LICENSE("GPL v2"); | ||
33 | |||
34 | |||
35 | #if defined(CONFIG_PARISC) | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/hardware.h> | ||
39 | #include <asm/parisc-device.h> | ||
40 | static unsigned long hil_base; /* HPA for the HIL device */ | ||
41 | static unsigned int hil_irq; | ||
42 | #define HILBASE hil_base /* HPPA (parisc) port address */ | ||
43 | #define HIL_DATA 0x800 | ||
44 | #define HIL_CMD 0x801 | ||
45 | #define HIL_IRQ hil_irq | ||
46 | #define hil_readb(p) gsc_readb(p) | ||
47 | #define hil_writeb(v,p) gsc_writeb((v),(p)) | ||
48 | |||
49 | #elif defined(CONFIG_HP300) | ||
50 | |||
51 | #define HILBASE 0xf0428000 /* HP300 (m86k) port address */ | ||
52 | #define HIL_DATA 0x1 | ||
53 | #define HIL_CMD 0x3 | ||
54 | #define HIL_IRQ 2 | ||
55 | #define hil_readb(p) readb(p) | ||
56 | #define hil_writeb(v,p) writeb((v),(p)) | ||
57 | |||
58 | #else | ||
59 | #error "HIL is not supported on this platform" | ||
60 | #endif | ||
61 | |||
62 | |||
63 | |||
64 | /* HIL helper functions */ | ||
65 | |||
66 | #define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY) | ||
67 | #define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY) | ||
68 | #define hil_status() (hil_readb(HILBASE + HIL_CMD)) | ||
69 | #define hil_command(x) do { hil_writeb((x), HILBASE + HIL_CMD); } while (0) | ||
70 | #define hil_read_data() (hil_readb(HILBASE + HIL_DATA)) | ||
71 | #define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0) | ||
72 | |||
73 | /* HIL constants */ | ||
74 | |||
75 | #define HIL_BUSY 0x02 | ||
76 | #define HIL_DATA_RDY 0x01 | ||
77 | |||
78 | #define HIL_SETARD 0xA0 /* set auto-repeat delay */ | ||
79 | #define HIL_SETARR 0xA2 /* set auto-repeat rate */ | ||
80 | #define HIL_SETTONE 0xA3 /* set tone generator */ | ||
81 | #define HIL_CNMT 0xB2 /* clear nmi */ | ||
82 | #define HIL_INTON 0x5C /* Turn on interrupts. */ | ||
83 | #define HIL_INTOFF 0x5D /* Turn off interrupts. */ | ||
84 | |||
85 | #define HIL_READKBDSADR 0xF9 | ||
86 | #define HIL_WRITEKBDSADR 0xE9 | ||
87 | |||
88 | static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = | ||
89 | { HIL_KEYCODES_SET1 }; | ||
90 | |||
91 | /* HIL structure */ | ||
92 | static struct { | ||
93 | struct input_dev dev; | ||
94 | |||
95 | unsigned int curdev; | ||
96 | |||
97 | unsigned char s; | ||
98 | unsigned char c; | ||
99 | int valid; | ||
100 | |||
101 | unsigned char data[16]; | ||
102 | unsigned int ptr; | ||
103 | spinlock_t lock; | ||
104 | |||
105 | void *dev_id; /* native bus device */ | ||
106 | } hil_dev; | ||
107 | |||
108 | |||
109 | static void poll_finished(void) | ||
110 | { | ||
111 | int down; | ||
112 | int key; | ||
113 | unsigned char scode; | ||
114 | |||
115 | switch (hil_dev.data[0]) { | ||
116 | case 0x40: | ||
117 | down = (hil_dev.data[1] & 1) == 0; | ||
118 | scode = hil_dev.data[1] >> 1; | ||
119 | key = hphilkeyb_keycode[scode]; | ||
120 | input_report_key(&hil_dev.dev, key, down); | ||
121 | break; | ||
122 | } | ||
123 | hil_dev.curdev = 0; | ||
124 | } | ||
125 | |||
126 | static inline void handle_status(unsigned char s, unsigned char c) | ||
127 | { | ||
128 | if (c & 0x8) { | ||
129 | /* End of block */ | ||
130 | if (c & 0x10) | ||
131 | poll_finished(); | ||
132 | } else { | ||
133 | if (c & 0x10) { | ||
134 | if (hil_dev.curdev) | ||
135 | poll_finished(); /* just in case */ | ||
136 | hil_dev.curdev = c & 7; | ||
137 | hil_dev.ptr = 0; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static inline void handle_data(unsigned char s, unsigned char c) | ||
143 | { | ||
144 | if (hil_dev.curdev) { | ||
145 | hil_dev.data[hil_dev.ptr++] = c; | ||
146 | hil_dev.ptr &= 15; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | |||
151 | /* | ||
152 | * Handle HIL interrupts. | ||
153 | */ | ||
154 | static irqreturn_t hil_interrupt(int irq, void *handle, struct pt_regs *regs) | ||
155 | { | ||
156 | unsigned char s, c; | ||
157 | |||
158 | s = hil_status(); | ||
159 | c = hil_read_data(); | ||
160 | |||
161 | switch (s >> 4) { | ||
162 | case 0x5: | ||
163 | handle_status(s, c); | ||
164 | break; | ||
165 | case 0x6: | ||
166 | handle_data(s, c); | ||
167 | break; | ||
168 | case 0x4: | ||
169 | hil_dev.s = s; | ||
170 | hil_dev.c = c; | ||
171 | mb(); | ||
172 | hil_dev.valid = 1; | ||
173 | break; | ||
174 | } | ||
175 | return IRQ_HANDLED; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Send a command to the HIL | ||
180 | */ | ||
181 | |||
182 | static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) | ||
183 | { | ||
184 | unsigned long flags; | ||
185 | |||
186 | spin_lock_irqsave(&hil_dev.lock, flags); | ||
187 | while (hil_busy()) | ||
188 | /* wait */; | ||
189 | hil_command(cmd); | ||
190 | while (len--) { | ||
191 | while (hil_busy()) | ||
192 | /* wait */; | ||
193 | hil_write_data(*(data++)); | ||
194 | } | ||
195 | spin_unlock_irqrestore(&hil_dev.lock, flags); | ||
196 | } | ||
197 | |||
198 | |||
199 | /* | ||
200 | * Initialise HIL. | ||
201 | */ | ||
202 | |||
203 | static int __init | ||
204 | hil_keyb_init(void) | ||
205 | { | ||
206 | unsigned char c; | ||
207 | unsigned int i, kbid; | ||
208 | wait_queue_head_t hil_wait; | ||
209 | |||
210 | if (hil_dev.dev.id.bustype) { | ||
211 | return -ENODEV; /* already initialized */ | ||
212 | } | ||
213 | |||
214 | #if defined(CONFIG_HP300) | ||
215 | if (!hwreg_present((void *)(HILBASE + HIL_DATA))) | ||
216 | return -ENODEV; | ||
217 | |||
218 | request_region(HILBASE+HIL_DATA, 2, "hil"); | ||
219 | #endif | ||
220 | |||
221 | request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); | ||
222 | |||
223 | /* Turn on interrupts */ | ||
224 | hil_do(HIL_INTON, NULL, 0); | ||
225 | |||
226 | /* Look for keyboards */ | ||
227 | hil_dev.valid = 0; /* clear any pending data */ | ||
228 | hil_do(HIL_READKBDSADR, NULL, 0); | ||
229 | |||
230 | init_waitqueue_head(&hil_wait); | ||
231 | wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ); | ||
232 | if (!hil_dev.valid) { | ||
233 | printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n"); | ||
234 | } | ||
235 | |||
236 | c = hil_dev.c; | ||
237 | hil_dev.valid = 0; | ||
238 | if (c == 0) { | ||
239 | kbid = -1; | ||
240 | printk(KERN_WARNING "HIL: no keyboard present.\n"); | ||
241 | } else { | ||
242 | kbid = ffz(~c); | ||
243 | /* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */ | ||
244 | } | ||
245 | |||
246 | /* set it to raw mode */ | ||
247 | c = 0; | ||
248 | hil_do(HIL_WRITEKBDSADR, &c, 1); | ||
249 | |||
250 | init_input_dev(&hil_dev.dev); | ||
251 | |||
252 | for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) | ||
253 | if (hphilkeyb_keycode[i] != KEY_RESERVED) | ||
254 | set_bit(hphilkeyb_keycode[i], hil_dev.dev.keybit); | ||
255 | |||
256 | hil_dev.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
257 | hil_dev.dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); | ||
258 | hil_dev.dev.keycodemax = HIL_KEYCODES_SET1_TBLSIZE; | ||
259 | hil_dev.dev.keycodesize = sizeof(hphilkeyb_keycode[0]); | ||
260 | hil_dev.dev.keycode = hphilkeyb_keycode; | ||
261 | hil_dev.dev.name = "HIL keyboard"; | ||
262 | hil_dev.dev.phys = "hpkbd/input0"; | ||
263 | |||
264 | hil_dev.dev.id.bustype = BUS_HIL; | ||
265 | hil_dev.dev.id.vendor = PCI_VENDOR_ID_HP; | ||
266 | hil_dev.dev.id.product = 0x0001; | ||
267 | hil_dev.dev.id.version = 0x0010; | ||
268 | |||
269 | input_register_device(&hil_dev.dev); | ||
270 | printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n", | ||
271 | hil_dev.dev.name, kbid, HILBASE, HIL_IRQ); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | #if defined(CONFIG_PARISC) | ||
277 | static int __init | ||
278 | hil_init_chip(struct parisc_device *dev) | ||
279 | { | ||
280 | if (!dev->irq) { | ||
281 | printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa); | ||
282 | return -ENODEV; | ||
283 | } | ||
284 | |||
285 | hil_base = dev->hpa; | ||
286 | hil_irq = dev->irq; | ||
287 | hil_dev.dev_id = dev; | ||
288 | |||
289 | printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq); | ||
290 | |||
291 | return hil_keyb_init(); | ||
292 | } | ||
293 | |||
294 | static struct parisc_device_id hil_tbl[] = { | ||
295 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 }, | ||
296 | { 0, } | ||
297 | }; | ||
298 | |||
299 | MODULE_DEVICE_TABLE(parisc, hil_tbl); | ||
300 | |||
301 | static struct parisc_driver hil_driver = { | ||
302 | .name = "HIL", | ||
303 | .id_table = hil_tbl, | ||
304 | .probe = hil_init_chip, | ||
305 | }; | ||
306 | #endif /* CONFIG_PARISC */ | ||
307 | |||
308 | |||
309 | |||
310 | |||
311 | |||
312 | static int __init hil_init(void) | ||
313 | { | ||
314 | #if defined(CONFIG_PARISC) | ||
315 | return register_parisc_driver(&hil_driver); | ||
316 | #else | ||
317 | return hil_keyb_init(); | ||
318 | #endif | ||
319 | } | ||
320 | |||
321 | |||
322 | static void __exit hil_exit(void) | ||
323 | { | ||
324 | if (HIL_IRQ) { | ||
325 | disable_irq(HIL_IRQ); | ||
326 | free_irq(HIL_IRQ, hil_dev.dev_id); | ||
327 | } | ||
328 | |||
329 | /* Turn off interrupts */ | ||
330 | hil_do(HIL_INTOFF, NULL, 0); | ||
331 | |||
332 | input_unregister_device(&hil_dev.dev); | ||
333 | |||
334 | #if defined(CONFIG_PARISC) | ||
335 | unregister_parisc_driver(&hil_driver); | ||
336 | #else | ||
337 | release_region(HILBASE+HIL_DATA, 2); | ||
338 | #endif | ||
339 | } | ||
340 | |||
341 | module_init(hil_init); | ||
342 | module_exit(hil_exit); | ||
343 | |||
diff --git a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h new file mode 100644 index 000000000000..dc33f6945222 --- /dev/null +++ b/drivers/input/keyboard/hpps2atkbd.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * drivers/input/keyboard/hpps2atkbd.h | ||
3 | * | ||
4 | * Copyright (c) 2004 Helge Deller <deller@gmx.de> | ||
5 | * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr> | ||
6 | * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org> | ||
7 | * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr> | ||
8 | * | ||
9 | * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | /* Is the keyboard an RDI PrecisionBook? */ | ||
18 | #ifndef CONFIG_KEYBOARD_ATKBD_RDI_KEYCODES | ||
19 | # define CONFLICT(x,y) x | ||
20 | #else | ||
21 | # define CONFLICT(x,y) y | ||
22 | #endif | ||
23 | |||
24 | /* sadly RDI (Tadpole) decided to ship a different keyboard layout | ||
25 | than HP for their PS/2 laptop keyboard which leads to conflicting | ||
26 | keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook. | ||
27 | HP: RDI: */ | ||
28 | #define C_07 CONFLICT( KEY_F12, KEY_F1 ) | ||
29 | #define C_11 CONFLICT( KEY_LEFTALT, KEY_LEFTCTRL ) | ||
30 | #define C_14 CONFLICT( KEY_LEFTCTRL, KEY_CAPSLOCK ) | ||
31 | #define C_58 CONFLICT( KEY_CAPSLOCK, KEY_RIGHTCTRL ) | ||
32 | #define C_61 CONFLICT( KEY_102ND, KEY_LEFT ) | ||
33 | |||
34 | /* Raw SET 2 scancode table */ | ||
35 | |||
36 | /* 00 */ KEY_RESERVED, KEY_F9, KEY_RESERVED, KEY_F5, KEY_F3, KEY_F1, KEY_F2, C_07, | ||
37 | /* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2, | ||
38 | /* 10 */ KEY_RESERVED, C_11, KEY_LEFTSHIFT, KEY_RESERVED, C_14, KEY_Q, KEY_1, KEY_F3, | ||
39 | /* 18 */ KEY_RESERVED, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4, | ||
40 | /* 20 */ KEY_RESERVED, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5, | ||
41 | /* 28 */ KEY_RESERVED, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6, | ||
42 | /* 30 */ KEY_RESERVED, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7, | ||
43 | /* 38 */ KEY_RESERVED, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8, | ||
44 | /* 40 */ KEY_RESERVED, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9, | ||
45 | /* 48 */ KEY_RESERVED, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10, | ||
46 | /* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_APOSTROPHE,KEY_RESERVED, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ, | ||
47 | /* 58 */ C_58, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK, | ||
48 | /* 60 */ KEY_DOWN, C_61, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT, | ||
49 | /* 68 */ KEY_RESERVED, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP, | ||
50 | /* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, | ||
51 | /* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_102ND, | ||
52 | /* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
53 | /* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
54 | /* 90 */ KEY_RESERVED, KEY_RIGHTALT, 255, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
55 | /* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_CAPSLOCK, KEY_RESERVED, KEY_LEFTMETA, | ||
56 | /* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTMETA, | ||
57 | /* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_COMPOSE, | ||
58 | /* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
59 | /* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
60 | /* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
61 | /* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPSLASH, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
62 | /* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
63 | /* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPENTER, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
64 | /* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
65 | /* e8 */ KEY_RESERVED, KEY_END, KEY_RESERVED, KEY_LEFT, KEY_HOME, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
66 | /* f0 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_RESERVED, KEY_RIGHT, KEY_UP, KEY_RESERVED, KEY_PAUSE, | ||
67 | /* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_PAGEDOWN, KEY_RESERVED, KEY_SYSRQ, KEY_PAGEUP, KEY_RESERVED, KEY_RESERVED, | ||
68 | |||
69 | /* These are offset for escaped keycodes: */ | ||
70 | |||
71 | /* 00 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_F7, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
72 | /* 08 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
73 | /* 10 */ KEY_RESERVED, KEY_RIGHTALT, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
74 | /* 18 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
75 | /* 20 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
76 | /* 28 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
77 | /* 30 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
78 | /* 38 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
79 | /* 40 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
80 | /* 48 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
81 | /* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
82 | /* 58 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
83 | /* 60 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
84 | /* 68 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
85 | /* 70 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
86 | /* 78 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
87 | /* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
88 | /* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
89 | /* 90 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
90 | /* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
91 | /* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
92 | /* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
93 | /* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
94 | /* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
95 | /* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
96 | /* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
97 | /* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
98 | /* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
99 | /* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
100 | /* e8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
101 | /* f0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
102 | /* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED | ||
103 | |||
104 | #undef CONFLICT | ||
105 | #undef C_07 | ||
106 | #undef C_11 | ||
107 | #undef C_14 | ||
108 | #undef C_58 | ||
109 | #undef C_61 | ||
110 | |||
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c new file mode 100644 index 000000000000..2694ff2b5beb --- /dev/null +++ b/drivers/input/keyboard/lkkbd.c | |||
@@ -0,0 +1,752 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de> | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * LK keyboard driver for Linux, based on sunkbd.c (C) by Vojtech Pavlik | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * DEC LK201 and LK401 keyboard driver for Linux (primary for DECstations | ||
11 | * and VAXstations, but can also be used on any standard RS232 with an | ||
12 | * adaptor). | ||
13 | * | ||
14 | * DISCLAIMER: This works for _me_. If you break anything by using the | ||
15 | * information given below, I will _not_ be liable! | ||
16 | * | ||
17 | * RJ10 pinout: To DE9: Or DB25: | ||
18 | * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) | ||
19 | * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND) | ||
20 | * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD) | ||
21 | * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!! | ||
22 | * | ||
23 | * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For | ||
24 | * RJ10, it's like this: | ||
25 | * | ||
26 | * __=__ Hold the plug in front of you, cable downwards, | ||
27 | * /___/| nose is hidden behind the plug. Now, pin 1 is at | ||
28 | * |1234|| the left side, pin 4 at the right and 2 and 3 are | ||
29 | * |IIII|| in between, of course:) | ||
30 | * | || | ||
31 | * |____|/ | ||
32 | * || So the adaptor consists of three connected cables | ||
33 | * || for data transmission (RxD and TxD) and signal ground. | ||
34 | * Additionally, you have to get +12V from somewhere. | ||
35 | * Most easily, you'll get that from a floppy or HDD power connector. | ||
36 | * It's the yellow cable there (black is ground and red is +5V). | ||
37 | * | ||
38 | * The keyboard and all the commands it understands are documented in | ||
39 | * "VCB02 Video Subsystem - Technical Manual", EK-104AA-TM-001. This | ||
40 | * document is LK201 specific, but LK401 is mostly compatible. It comes | ||
41 | * up in LK201 mode and doesn't report any of the additional keys it | ||
42 | * has. These need to be switched on with the LK_CMD_ENABLE_LK401 | ||
43 | * command. You'll find this document (scanned .pdf file) on MANX, | ||
44 | * a search engine specific to DEC documentation. Try | ||
45 | * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1 | ||
46 | */ | ||
47 | |||
48 | /* | ||
49 | * This program is free software; you can redistribute it and/or modify | ||
50 | * it under the terms of the GNU General Public License as published by | ||
51 | * the Free Software Foundation; either version 2 of the License, or | ||
52 | * (at your option) any later version. | ||
53 | * | ||
54 | * This program is distributed in the hope that it will be useful, | ||
55 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
56 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
57 | * GNU General Public License for more details. | ||
58 | * | ||
59 | * You should have received a copy of the GNU General Public License | ||
60 | * along with this program; if not, write to the Free Software | ||
61 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
62 | * | ||
63 | * Should you need to contact me, the author, you can do so either by | ||
64 | * email or by paper mail: | ||
65 | * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.), | ||
66 | * Germany. | ||
67 | */ | ||
68 | |||
69 | #include <linux/delay.h> | ||
70 | #include <linux/slab.h> | ||
71 | #include <linux/module.h> | ||
72 | #include <linux/moduleparam.h> | ||
73 | #include <linux/interrupt.h> | ||
74 | #include <linux/init.h> | ||
75 | #include <linux/input.h> | ||
76 | #include <linux/serio.h> | ||
77 | #include <linux/workqueue.h> | ||
78 | |||
79 | #define DRIVER_DESC "LK keyboard driver" | ||
80 | |||
81 | MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); | ||
82 | MODULE_DESCRIPTION (DRIVER_DESC); | ||
83 | MODULE_LICENSE ("GPL"); | ||
84 | |||
85 | /* | ||
86 | * Known parameters: | ||
87 | * bell_volume | ||
88 | * keyclick_volume | ||
89 | * ctrlclick_volume | ||
90 | * | ||
91 | * Please notice that there's not yet an API to set these at runtime. | ||
92 | */ | ||
93 | static int bell_volume = 100; /* % */ | ||
94 | module_param (bell_volume, int, 0); | ||
95 | MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%"); | ||
96 | |||
97 | static int keyclick_volume = 100; /* % */ | ||
98 | module_param (keyclick_volume, int, 0); | ||
99 | MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%"); | ||
100 | |||
101 | static int ctrlclick_volume = 100; /* % */ | ||
102 | module_param (ctrlclick_volume, int, 0); | ||
103 | MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); | ||
104 | |||
105 | static int lk201_compose_is_alt = 0; | ||
106 | module_param (lk201_compose_is_alt, int, 0); | ||
107 | MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " | ||
108 | "will act as an Alt key"); | ||
109 | |||
110 | |||
111 | |||
112 | #undef LKKBD_DEBUG | ||
113 | #ifdef LKKBD_DEBUG | ||
114 | #define DBG(x...) printk (x) | ||
115 | #else | ||
116 | #define DBG(x...) do {} while (0) | ||
117 | #endif | ||
118 | |||
119 | /* LED control */ | ||
120 | #define LK_LED_WAIT 0x81 | ||
121 | #define LK_LED_COMPOSE 0x82 | ||
122 | #define LK_LED_SHIFTLOCK 0x84 | ||
123 | #define LK_LED_SCROLLLOCK 0x88 | ||
124 | #define LK_CMD_LED_ON 0x13 | ||
125 | #define LK_CMD_LED_OFF 0x11 | ||
126 | |||
127 | /* Mode control */ | ||
128 | #define LK_MODE_DOWN 0x80 | ||
129 | #define LK_MODE_AUTODOWN 0x82 | ||
130 | #define LK_MODE_UPDOWN 0x86 | ||
131 | #define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3)) | ||
132 | |||
133 | /* Misc commands */ | ||
134 | #define LK_CMD_ENABLE_KEYCLICK 0x1b | ||
135 | #define LK_CMD_DISABLE_KEYCLICK 0x99 | ||
136 | #define LK_CMD_DISABLE_BELL 0xa1 | ||
137 | #define LK_CMD_SOUND_BELL 0xa7 | ||
138 | #define LK_CMD_ENABLE_BELL 0x23 | ||
139 | #define LK_CMD_DISABLE_CTRCLICK 0xb9 | ||
140 | #define LK_CMD_ENABLE_CTRCLICK 0xbb | ||
141 | #define LK_CMD_SET_DEFAULTS 0xd3 | ||
142 | #define LK_CMD_POWERCYCLE_RESET 0xfd | ||
143 | #define LK_CMD_ENABLE_LK401 0xe9 | ||
144 | #define LK_CMD_REQUEST_ID 0xab | ||
145 | |||
146 | /* Misc responses from keyboard */ | ||
147 | #define LK_STUCK_KEY 0x3d | ||
148 | #define LK_SELFTEST_FAILED 0x3e | ||
149 | #define LK_ALL_KEYS_UP 0xb3 | ||
150 | #define LK_METRONOME 0xb4 | ||
151 | #define LK_OUTPUT_ERROR 0xb5 | ||
152 | #define LK_INPUT_ERROR 0xb6 | ||
153 | #define LK_KBD_LOCKED 0xb7 | ||
154 | #define LK_KBD_TEST_MODE_ACK 0xb8 | ||
155 | #define LK_PREFIX_KEY_DOWN 0xb9 | ||
156 | #define LK_MODE_CHANGE_ACK 0xba | ||
157 | #define LK_RESPONSE_RESERVED 0xbb | ||
158 | |||
159 | #define LK_NUM_KEYCODES 256 | ||
160 | #define LK_NUM_IGNORE_BYTES 6 | ||
161 | typedef u_int16_t lk_keycode_t; | ||
162 | |||
163 | |||
164 | |||
165 | static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { | ||
166 | [0x56] = KEY_F1, | ||
167 | [0x57] = KEY_F2, | ||
168 | [0x58] = KEY_F3, | ||
169 | [0x59] = KEY_F4, | ||
170 | [0x5a] = KEY_F5, | ||
171 | [0x64] = KEY_F6, | ||
172 | [0x65] = KEY_F7, | ||
173 | [0x66] = KEY_F8, | ||
174 | [0x67] = KEY_F9, | ||
175 | [0x68] = KEY_F10, | ||
176 | [0x71] = KEY_F11, | ||
177 | [0x72] = KEY_F12, | ||
178 | [0x73] = KEY_F13, | ||
179 | [0x74] = KEY_F14, | ||
180 | [0x7c] = KEY_F15, | ||
181 | [0x7d] = KEY_F16, | ||
182 | [0x80] = KEY_F17, | ||
183 | [0x81] = KEY_F18, | ||
184 | [0x82] = KEY_F19, | ||
185 | [0x83] = KEY_F20, | ||
186 | [0x8a] = KEY_FIND, | ||
187 | [0x8b] = KEY_INSERT, | ||
188 | [0x8c] = KEY_DELETE, | ||
189 | [0x8d] = KEY_SELECT, | ||
190 | [0x8e] = KEY_PAGEUP, | ||
191 | [0x8f] = KEY_PAGEDOWN, | ||
192 | [0x92] = KEY_KP0, | ||
193 | [0x94] = KEY_KPDOT, | ||
194 | [0x95] = KEY_KPENTER, | ||
195 | [0x96] = KEY_KP1, | ||
196 | [0x97] = KEY_KP2, | ||
197 | [0x98] = KEY_KP3, | ||
198 | [0x99] = KEY_KP4, | ||
199 | [0x9a] = KEY_KP5, | ||
200 | [0x9b] = KEY_KP6, | ||
201 | [0x9c] = KEY_KPCOMMA, | ||
202 | [0x9d] = KEY_KP7, | ||
203 | [0x9e] = KEY_KP8, | ||
204 | [0x9f] = KEY_KP9, | ||
205 | [0xa0] = KEY_KPMINUS, | ||
206 | [0xa1] = KEY_PROG1, | ||
207 | [0xa2] = KEY_PROG2, | ||
208 | [0xa3] = KEY_PROG3, | ||
209 | [0xa4] = KEY_PROG4, | ||
210 | [0xa7] = KEY_LEFT, | ||
211 | [0xa8] = KEY_RIGHT, | ||
212 | [0xa9] = KEY_DOWN, | ||
213 | [0xaa] = KEY_UP, | ||
214 | [0xab] = KEY_RIGHTSHIFT, | ||
215 | [0xac] = KEY_LEFTALT, | ||
216 | [0xad] = KEY_COMPOSE, /* Right Compose, that is. */ | ||
217 | [0xae] = KEY_LEFTSHIFT, /* Same as KEY_RIGHTSHIFT on LK201 */ | ||
218 | [0xaf] = KEY_LEFTCTRL, | ||
219 | [0xb0] = KEY_CAPSLOCK, | ||
220 | [0xb1] = KEY_COMPOSE, /* Left Compose, that is. */ | ||
221 | [0xb2] = KEY_RIGHTALT, | ||
222 | [0xbc] = KEY_BACKSPACE, | ||
223 | [0xbd] = KEY_ENTER, | ||
224 | [0xbe] = KEY_TAB, | ||
225 | [0xbf] = KEY_ESC, | ||
226 | [0xc0] = KEY_1, | ||
227 | [0xc1] = KEY_Q, | ||
228 | [0xc2] = KEY_A, | ||
229 | [0xc3] = KEY_Z, | ||
230 | [0xc5] = KEY_2, | ||
231 | [0xc6] = KEY_W, | ||
232 | [0xc7] = KEY_S, | ||
233 | [0xc8] = KEY_X, | ||
234 | [0xc9] = KEY_102ND, | ||
235 | [0xcb] = KEY_3, | ||
236 | [0xcc] = KEY_E, | ||
237 | [0xcd] = KEY_D, | ||
238 | [0xce] = KEY_C, | ||
239 | [0xd0] = KEY_4, | ||
240 | [0xd1] = KEY_R, | ||
241 | [0xd2] = KEY_F, | ||
242 | [0xd3] = KEY_V, | ||
243 | [0xd4] = KEY_SPACE, | ||
244 | [0xd6] = KEY_5, | ||
245 | [0xd7] = KEY_T, | ||
246 | [0xd8] = KEY_G, | ||
247 | [0xd9] = KEY_B, | ||
248 | [0xdb] = KEY_6, | ||
249 | [0xdc] = KEY_Y, | ||
250 | [0xdd] = KEY_H, | ||
251 | [0xde] = KEY_N, | ||
252 | [0xe0] = KEY_7, | ||
253 | [0xe1] = KEY_U, | ||
254 | [0xe2] = KEY_J, | ||
255 | [0xe3] = KEY_M, | ||
256 | [0xe5] = KEY_8, | ||
257 | [0xe6] = KEY_I, | ||
258 | [0xe7] = KEY_K, | ||
259 | [0xe8] = KEY_COMMA, | ||
260 | [0xea] = KEY_9, | ||
261 | [0xeb] = KEY_O, | ||
262 | [0xec] = KEY_L, | ||
263 | [0xed] = KEY_DOT, | ||
264 | [0xef] = KEY_0, | ||
265 | [0xf0] = KEY_P, | ||
266 | [0xf2] = KEY_SEMICOLON, | ||
267 | [0xf3] = KEY_SLASH, | ||
268 | [0xf5] = KEY_EQUAL, | ||
269 | [0xf6] = KEY_RIGHTBRACE, | ||
270 | [0xf7] = KEY_BACKSLASH, | ||
271 | [0xf9] = KEY_MINUS, | ||
272 | [0xfa] = KEY_LEFTBRACE, | ||
273 | [0xfb] = KEY_APOSTROPHE, | ||
274 | }; | ||
275 | |||
276 | #define CHECK_LED(LED, BITS) do { \ | ||
277 | if (test_bit (LED, lk->dev.led)) \ | ||
278 | leds_on |= BITS; \ | ||
279 | else \ | ||
280 | leds_off |= BITS; \ | ||
281 | } while (0) | ||
282 | |||
283 | /* | ||
284 | * Per-keyboard data | ||
285 | */ | ||
286 | struct lkkbd { | ||
287 | lk_keycode_t keycode[LK_NUM_KEYCODES]; | ||
288 | int ignore_bytes; | ||
289 | unsigned char id[LK_NUM_IGNORE_BYTES]; | ||
290 | struct input_dev dev; | ||
291 | struct serio *serio; | ||
292 | struct work_struct tq; | ||
293 | char name[64]; | ||
294 | char phys[32]; | ||
295 | char type; | ||
296 | int bell_volume; | ||
297 | int keyclick_volume; | ||
298 | int ctrlclick_volume; | ||
299 | }; | ||
300 | |||
301 | /* | ||
302 | * Calculate volume parameter byte for a given volume. | ||
303 | */ | ||
304 | static unsigned char | ||
305 | volume_to_hw (int volume_percent) | ||
306 | { | ||
307 | unsigned char ret = 0; | ||
308 | |||
309 | if (volume_percent < 0) | ||
310 | volume_percent = 0; | ||
311 | if (volume_percent > 100) | ||
312 | volume_percent = 100; | ||
313 | |||
314 | if (volume_percent >= 0) | ||
315 | ret = 7; | ||
316 | if (volume_percent >= 13) /* 12.5 */ | ||
317 | ret = 6; | ||
318 | if (volume_percent >= 25) | ||
319 | ret = 5; | ||
320 | if (volume_percent >= 38) /* 37.5 */ | ||
321 | ret = 4; | ||
322 | if (volume_percent >= 50) | ||
323 | ret = 3; | ||
324 | if (volume_percent >= 63) /* 62.5 */ | ||
325 | ret = 2; /* This is the default volume */ | ||
326 | if (volume_percent >= 75) | ||
327 | ret = 1; | ||
328 | if (volume_percent >= 88) /* 87.5 */ | ||
329 | ret = 0; | ||
330 | |||
331 | ret |= 0x80; | ||
332 | |||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | static void | ||
337 | lkkbd_detection_done (struct lkkbd *lk) | ||
338 | { | ||
339 | int i; | ||
340 | |||
341 | /* | ||
342 | * Reset setting for Compose key. Let Compose be KEY_COMPOSE. | ||
343 | */ | ||
344 | lk->keycode[0xb1] = KEY_COMPOSE; | ||
345 | |||
346 | /* | ||
347 | * Print keyboard name and modify Compose=Alt on user's request. | ||
348 | */ | ||
349 | switch (lk->id[4]) { | ||
350 | case 1: | ||
351 | sprintf (lk->name, "DEC LK201 keyboard"); | ||
352 | |||
353 | if (lk201_compose_is_alt) | ||
354 | lk->keycode[0xb1] = KEY_LEFTALT; | ||
355 | break; | ||
356 | |||
357 | case 2: | ||
358 | sprintf (lk->name, "DEC LK401 keyboard"); | ||
359 | break; | ||
360 | |||
361 | default: | ||
362 | sprintf (lk->name, "Unknown DEC keyboard"); | ||
363 | printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " | ||
364 | "please report to Jan-Benedict Glaw " | ||
365 | "<jbglaw@lug-owl.de>\n", lk->phys); | ||
366 | printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); | ||
367 | for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) | ||
368 | printk (" 0x%02x", lk->id[i]); | ||
369 | printk ("\n"); | ||
370 | break; | ||
371 | } | ||
372 | printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", | ||
373 | lk->phys, lk->name); | ||
374 | |||
375 | /* | ||
376 | * Report errors during keyboard boot-up. | ||
377 | */ | ||
378 | switch (lk->id[2]) { | ||
379 | case 0x00: | ||
380 | /* All okay */ | ||
381 | break; | ||
382 | |||
383 | case LK_STUCK_KEY: | ||
384 | printk (KERN_ERR "lkkbd: Stuck key on keyboard at " | ||
385 | "%s\n", lk->phys); | ||
386 | break; | ||
387 | |||
388 | case LK_SELFTEST_FAILED: | ||
389 | printk (KERN_ERR "lkkbd: Selftest failed on keyboard " | ||
390 | "at %s, keyboard may not work " | ||
391 | "properly\n", lk->phys); | ||
392 | break; | ||
393 | |||
394 | default: | ||
395 | printk (KERN_ERR "lkkbd: Unknown error %02x on " | ||
396 | "keyboard at %s\n", lk->id[2], | ||
397 | lk->phys); | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Try to hint user if there's a stuck key. | ||
403 | */ | ||
404 | if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) | ||
405 | printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " | ||
406 | "is 0x%04x\n", lk->id[3], | ||
407 | lk->keycode[lk->id[3]]); | ||
408 | |||
409 | return; | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * lkkbd_interrupt() is called by the low level driver when a character | ||
414 | * is received. | ||
415 | */ | ||
416 | static irqreturn_t | ||
417 | lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, | ||
418 | struct pt_regs *regs) | ||
419 | { | ||
420 | struct lkkbd *lk = serio_get_drvdata (serio); | ||
421 | int i; | ||
422 | |||
423 | DBG (KERN_INFO "Got byte 0x%02x\n", data); | ||
424 | |||
425 | if (lk->ignore_bytes > 0) { | ||
426 | DBG (KERN_INFO "Ignoring a byte on %s\n", | ||
427 | lk->name); | ||
428 | lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; | ||
429 | |||
430 | if (lk->ignore_bytes == 0) | ||
431 | lkkbd_detection_done (lk); | ||
432 | |||
433 | return IRQ_HANDLED; | ||
434 | } | ||
435 | |||
436 | switch (data) { | ||
437 | case LK_ALL_KEYS_UP: | ||
438 | input_regs (&lk->dev, regs); | ||
439 | for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) | ||
440 | if (lk->keycode[i] != KEY_RESERVED) | ||
441 | input_report_key (&lk->dev, lk->keycode[i], 0); | ||
442 | input_sync (&lk->dev); | ||
443 | break; | ||
444 | case LK_METRONOME: | ||
445 | DBG (KERN_INFO "Got LK_METRONOME and don't " | ||
446 | "know how to handle...\n"); | ||
447 | break; | ||
448 | case LK_OUTPUT_ERROR: | ||
449 | DBG (KERN_INFO "Got LK_OUTPUT_ERROR and don't " | ||
450 | "know how to handle...\n"); | ||
451 | break; | ||
452 | case LK_INPUT_ERROR: | ||
453 | DBG (KERN_INFO "Got LK_INPUT_ERROR and don't " | ||
454 | "know how to handle...\n"); | ||
455 | break; | ||
456 | case LK_KBD_LOCKED: | ||
457 | DBG (KERN_INFO "Got LK_KBD_LOCKED and don't " | ||
458 | "know how to handle...\n"); | ||
459 | break; | ||
460 | case LK_KBD_TEST_MODE_ACK: | ||
461 | DBG (KERN_INFO "Got LK_KBD_TEST_MODE_ACK and don't " | ||
462 | "know how to handle...\n"); | ||
463 | break; | ||
464 | case LK_PREFIX_KEY_DOWN: | ||
465 | DBG (KERN_INFO "Got LK_PREFIX_KEY_DOWN and don't " | ||
466 | "know how to handle...\n"); | ||
467 | break; | ||
468 | case LK_MODE_CHANGE_ACK: | ||
469 | DBG (KERN_INFO "Got LK_MODE_CHANGE_ACK and ignored " | ||
470 | "it properly...\n"); | ||
471 | break; | ||
472 | case LK_RESPONSE_RESERVED: | ||
473 | DBG (KERN_INFO "Got LK_RESPONSE_RESERVED and don't " | ||
474 | "know how to handle...\n"); | ||
475 | break; | ||
476 | case 0x01: | ||
477 | DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); | ||
478 | lk->ignore_bytes = LK_NUM_IGNORE_BYTES; | ||
479 | lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; | ||
480 | schedule_work (&lk->tq); | ||
481 | break; | ||
482 | |||
483 | default: | ||
484 | if (lk->keycode[data] != KEY_RESERVED) { | ||
485 | input_regs (&lk->dev, regs); | ||
486 | if (!test_bit (lk->keycode[data], lk->dev.key)) | ||
487 | input_report_key (&lk->dev, lk->keycode[data], 1); | ||
488 | else | ||
489 | input_report_key (&lk->dev, lk->keycode[data], 0); | ||
490 | input_sync (&lk->dev); | ||
491 | } else | ||
492 | printk (KERN_WARNING "%s: Unknown key with " | ||
493 | "scancode 0x%02x on %s.\n", | ||
494 | __FILE__, data, lk->name); | ||
495 | } | ||
496 | |||
497 | return IRQ_HANDLED; | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * lkkbd_event() handles events from the input module. | ||
502 | */ | ||
503 | static int | ||
504 | lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, | ||
505 | int value) | ||
506 | { | ||
507 | struct lkkbd *lk = dev->private; | ||
508 | unsigned char leds_on = 0; | ||
509 | unsigned char leds_off = 0; | ||
510 | |||
511 | switch (type) { | ||
512 | case EV_LED: | ||
513 | CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); | ||
514 | CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); | ||
515 | CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); | ||
516 | CHECK_LED (LED_SLEEP, LK_LED_WAIT); | ||
517 | if (leds_on != 0) { | ||
518 | lk->serio->write (lk->serio, LK_CMD_LED_ON); | ||
519 | lk->serio->write (lk->serio, leds_on); | ||
520 | } | ||
521 | if (leds_off != 0) { | ||
522 | lk->serio->write (lk->serio, LK_CMD_LED_OFF); | ||
523 | lk->serio->write (lk->serio, leds_off); | ||
524 | } | ||
525 | return 0; | ||
526 | |||
527 | case EV_SND: | ||
528 | switch (code) { | ||
529 | case SND_CLICK: | ||
530 | if (value == 0) { | ||
531 | DBG ("%s: Deactivating key clicks\n", __FUNCTION__); | ||
532 | lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); | ||
533 | lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); | ||
534 | } else { | ||
535 | DBG ("%s: Activating key clicks\n", __FUNCTION__); | ||
536 | lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); | ||
537 | lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); | ||
538 | lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); | ||
539 | lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); | ||
540 | } | ||
541 | return 0; | ||
542 | |||
543 | case SND_BELL: | ||
544 | if (value != 0) | ||
545 | lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | break; | ||
550 | |||
551 | default: | ||
552 | printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", | ||
553 | __FUNCTION__, type, code, value); | ||
554 | } | ||
555 | |||
556 | return -1; | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * lkkbd_reinit() sets leds and beeps to a state the computer remembers they | ||
561 | * were in. | ||
562 | */ | ||
563 | static void | ||
564 | lkkbd_reinit (void *data) | ||
565 | { | ||
566 | struct lkkbd *lk = data; | ||
567 | int division; | ||
568 | unsigned char leds_on = 0; | ||
569 | unsigned char leds_off = 0; | ||
570 | |||
571 | /* Ask for ID */ | ||
572 | lk->serio->write (lk->serio, LK_CMD_REQUEST_ID); | ||
573 | |||
574 | /* Reset parameters */ | ||
575 | lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); | ||
576 | |||
577 | /* Set LEDs */ | ||
578 | CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); | ||
579 | CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); | ||
580 | CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); | ||
581 | CHECK_LED (LED_SLEEP, LK_LED_WAIT); | ||
582 | if (leds_on != 0) { | ||
583 | lk->serio->write (lk->serio, LK_CMD_LED_ON); | ||
584 | lk->serio->write (lk->serio, leds_on); | ||
585 | } | ||
586 | if (leds_off != 0) { | ||
587 | lk->serio->write (lk->serio, LK_CMD_LED_OFF); | ||
588 | lk->serio->write (lk->serio, leds_off); | ||
589 | } | ||
590 | |||
591 | /* | ||
592 | * Try to activate extended LK401 mode. This command will | ||
593 | * only work with a LK401 keyboard and grants access to | ||
594 | * LAlt, RAlt, RCompose and RShift. | ||
595 | */ | ||
596 | lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401); | ||
597 | |||
598 | /* Set all keys to UPDOWN mode */ | ||
599 | for (division = 1; division <= 14; division++) | ||
600 | lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, | ||
601 | division)); | ||
602 | |||
603 | /* Enable bell and set volume */ | ||
604 | lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL); | ||
605 | lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); | ||
606 | |||
607 | /* Enable/disable keyclick (and possibly set volume) */ | ||
608 | if (test_bit (SND_CLICK, lk->dev.snd)) { | ||
609 | lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); | ||
610 | lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); | ||
611 | lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); | ||
612 | lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); | ||
613 | } else { | ||
614 | lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); | ||
615 | lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); | ||
616 | } | ||
617 | |||
618 | /* Sound the bell if needed */ | ||
619 | if (test_bit (SND_BELL, lk->dev.snd)) | ||
620 | lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. | ||
625 | */ | ||
626 | static int | ||
627 | lkkbd_connect (struct serio *serio, struct serio_driver *drv) | ||
628 | { | ||
629 | struct lkkbd *lk; | ||
630 | int i; | ||
631 | int err; | ||
632 | |||
633 | if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) | ||
634 | return -ENOMEM; | ||
635 | |||
636 | memset (lk, 0, sizeof (struct lkkbd)); | ||
637 | |||
638 | init_input_dev (&lk->dev); | ||
639 | set_bit (EV_KEY, lk->dev.evbit); | ||
640 | set_bit (EV_LED, lk->dev.evbit); | ||
641 | set_bit (EV_SND, lk->dev.evbit); | ||
642 | set_bit (EV_REP, lk->dev.evbit); | ||
643 | set_bit (LED_CAPSL, lk->dev.ledbit); | ||
644 | set_bit (LED_SLEEP, lk->dev.ledbit); | ||
645 | set_bit (LED_COMPOSE, lk->dev.ledbit); | ||
646 | set_bit (LED_SCROLLL, lk->dev.ledbit); | ||
647 | set_bit (SND_BELL, lk->dev.sndbit); | ||
648 | set_bit (SND_CLICK, lk->dev.sndbit); | ||
649 | |||
650 | lk->serio = serio; | ||
651 | |||
652 | INIT_WORK (&lk->tq, lkkbd_reinit, lk); | ||
653 | |||
654 | lk->bell_volume = bell_volume; | ||
655 | lk->keyclick_volume = keyclick_volume; | ||
656 | lk->ctrlclick_volume = ctrlclick_volume; | ||
657 | |||
658 | lk->dev.keycode = lk->keycode; | ||
659 | lk->dev.keycodesize = sizeof (lk_keycode_t); | ||
660 | lk->dev.keycodemax = LK_NUM_KEYCODES; | ||
661 | |||
662 | lk->dev.event = lkkbd_event; | ||
663 | lk->dev.private = lk; | ||
664 | |||
665 | serio_set_drvdata (serio, lk); | ||
666 | |||
667 | err = serio_open (serio, drv); | ||
668 | if (err) { | ||
669 | serio_set_drvdata (serio, NULL); | ||
670 | kfree (lk); | ||
671 | return err; | ||
672 | } | ||
673 | |||
674 | sprintf (lk->name, "DEC LK keyboard"); | ||
675 | sprintf (lk->phys, "%s/input0", serio->phys); | ||
676 | |||
677 | memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); | ||
678 | for (i = 0; i < LK_NUM_KEYCODES; i++) | ||
679 | set_bit (lk->keycode[i], lk->dev.keybit); | ||
680 | |||
681 | lk->dev.name = lk->name; | ||
682 | lk->dev.phys = lk->phys; | ||
683 | lk->dev.id.bustype = BUS_RS232; | ||
684 | lk->dev.id.vendor = SERIO_LKKBD; | ||
685 | lk->dev.id.product = 0; | ||
686 | lk->dev.id.version = 0x0100; | ||
687 | lk->dev.dev = &serio->dev; | ||
688 | |||
689 | input_register_device (&lk->dev); | ||
690 | |||
691 | printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys); | ||
692 | lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /* | ||
698 | * lkkbd_disconnect() unregisters and closes behind us. | ||
699 | */ | ||
700 | static void | ||
701 | lkkbd_disconnect (struct serio *serio) | ||
702 | { | ||
703 | struct lkkbd *lk = serio_get_drvdata (serio); | ||
704 | |||
705 | input_unregister_device (&lk->dev); | ||
706 | serio_close (serio); | ||
707 | serio_set_drvdata (serio, NULL); | ||
708 | kfree (lk); | ||
709 | } | ||
710 | |||
711 | static struct serio_device_id lkkbd_serio_ids[] = { | ||
712 | { | ||
713 | .type = SERIO_RS232, | ||
714 | .proto = SERIO_LKKBD, | ||
715 | .id = SERIO_ANY, | ||
716 | .extra = SERIO_ANY, | ||
717 | }, | ||
718 | { 0 } | ||
719 | }; | ||
720 | |||
721 | MODULE_DEVICE_TABLE(serio, lkkbd_serio_ids); | ||
722 | |||
723 | static struct serio_driver lkkbd_drv = { | ||
724 | .driver = { | ||
725 | .name = "lkkbd", | ||
726 | }, | ||
727 | .description = DRIVER_DESC, | ||
728 | .id_table = lkkbd_serio_ids, | ||
729 | .connect = lkkbd_connect, | ||
730 | .disconnect = lkkbd_disconnect, | ||
731 | .interrupt = lkkbd_interrupt, | ||
732 | }; | ||
733 | |||
734 | /* | ||
735 | * The functions for insering/removing us as a module. | ||
736 | */ | ||
737 | static int __init | ||
738 | lkkbd_init (void) | ||
739 | { | ||
740 | serio_register_driver(&lkkbd_drv); | ||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | static void __exit | ||
745 | lkkbd_exit (void) | ||
746 | { | ||
747 | serio_unregister_driver(&lkkbd_drv); | ||
748 | } | ||
749 | |||
750 | module_init (lkkbd_init); | ||
751 | module_exit (lkkbd_exit); | ||
752 | |||
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c new file mode 100644 index 000000000000..d3e9dd6a13cd --- /dev/null +++ b/drivers/input/keyboard/locomokbd.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 John Lenz | ||
3 | * | ||
4 | * Based on from xtkbd.c | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * LoCoMo keyboard driver for Linux/ARM | ||
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 | */ | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/input.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/device.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/ioport.h> | ||
37 | |||
38 | #include <asm/hardware/locomo.h> | ||
39 | #include <asm/irq.h> | ||
40 | |||
41 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); | ||
42 | MODULE_DESCRIPTION("LoCoMo keyboard driver"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | #define LOCOMOKBD_NUMKEYS 128 | ||
46 | |||
47 | #define KEY_ACTIVITY KEY_F16 | ||
48 | #define KEY_CONTACT KEY_F18 | ||
49 | #define KEY_CENTER KEY_F15 | ||
50 | |||
51 | static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { | ||
52 | 0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */ | ||
53 | 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT, /* 10 - 19 */ | ||
54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */ | ||
55 | 0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0, /* 30 - 39 */ | ||
56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT, /* 40 - 49 */ | ||
57 | KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T, /* 50 - 59 */ | ||
58 | KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0, /* 60 - 69 */ | ||
59 | KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0, /* 70 - 79 */ | ||
60 | 0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J, /* 80 - 89 */ | ||
61 | KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0, /* 90 - 99 */ | ||
62 | 0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A, /* 100 - 109 */ | ||
63 | KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0, /* 110 - 119 */ | ||
64 | KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */ | ||
65 | }; | ||
66 | |||
67 | #define KB_ROWS 16 | ||
68 | #define KB_COLS 8 | ||
69 | #define KB_ROWMASK(r) (1 << (r)) | ||
70 | #define SCANCODE(c,r) ( ((c)<<4) + (r) + 1 ) | ||
71 | #define NR_SCANCODES 128 | ||
72 | |||
73 | #define KB_DELAY 8 | ||
74 | #define SCAN_INTERVAL (HZ/10) | ||
75 | #define LOCOMOKBD_PRESSED 1 | ||
76 | |||
77 | struct locomokbd { | ||
78 | unsigned char keycode[LOCOMOKBD_NUMKEYS]; | ||
79 | struct input_dev input; | ||
80 | char phys[32]; | ||
81 | |||
82 | struct locomo_dev *ldev; | ||
83 | unsigned long base; | ||
84 | spinlock_t lock; | ||
85 | |||
86 | struct timer_list timer; | ||
87 | }; | ||
88 | |||
89 | /* helper functions for reading the keyboard matrix */ | ||
90 | static inline void locomokbd_charge_all(unsigned long membase) | ||
91 | { | ||
92 | locomo_writel(0x00FF, membase + LOCOMO_KSC); | ||
93 | } | ||
94 | |||
95 | static inline void locomokbd_activate_all(unsigned long membase) | ||
96 | { | ||
97 | unsigned long r; | ||
98 | |||
99 | locomo_writel(0, membase + LOCOMO_KSC); | ||
100 | r = locomo_readl(membase + LOCOMO_KIC); | ||
101 | r &= 0xFEFF; | ||
102 | locomo_writel(r, membase + LOCOMO_KIC); | ||
103 | } | ||
104 | |||
105 | static inline void locomokbd_activate_col(unsigned long membase, int col) | ||
106 | { | ||
107 | unsigned short nset; | ||
108 | unsigned short nbset; | ||
109 | |||
110 | nset = 0xFF & ~(1 << col); | ||
111 | nbset = (nset << 8) + nset; | ||
112 | locomo_writel(nbset, membase + LOCOMO_KSC); | ||
113 | } | ||
114 | |||
115 | static inline void locomokbd_reset_col(unsigned long membase, int col) | ||
116 | { | ||
117 | unsigned short nbset; | ||
118 | |||
119 | nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF; | ||
120 | locomo_writel(nbset, membase + LOCOMO_KSC); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * The LoCoMo keyboard only generates interrupts when a key is pressed. | ||
125 | * So when a key is pressed, we enable a timer. This timer scans the | ||
126 | * keyboard, and this is how we detect when the key is released. | ||
127 | */ | ||
128 | |||
129 | /* Scan the hardware keyboard and push any changes up through the input layer */ | ||
130 | static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs) | ||
131 | { | ||
132 | unsigned int row, col, rowd, scancode; | ||
133 | unsigned long flags; | ||
134 | unsigned int num_pressed; | ||
135 | unsigned long membase = locomokbd->base; | ||
136 | |||
137 | spin_lock_irqsave(&locomokbd->lock, flags); | ||
138 | |||
139 | if (regs) | ||
140 | input_regs(&locomokbd->input, regs); | ||
141 | |||
142 | locomokbd_charge_all(membase); | ||
143 | |||
144 | num_pressed = 0; | ||
145 | for (col = 0; col < KB_COLS; col++) { | ||
146 | |||
147 | locomokbd_activate_col(membase, col); | ||
148 | udelay(KB_DELAY); | ||
149 | |||
150 | rowd = ~locomo_readl(membase + LOCOMO_KIB); | ||
151 | for (row = 0; row < KB_ROWS; row++ ) { | ||
152 | scancode = SCANCODE(col, row); | ||
153 | if (rowd & KB_ROWMASK(row)) { | ||
154 | num_pressed += 1; | ||
155 | input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 1); | ||
156 | } else { | ||
157 | input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 0); | ||
158 | } | ||
159 | } | ||
160 | locomokbd_reset_col(membase, col); | ||
161 | } | ||
162 | locomokbd_activate_all(membase); | ||
163 | |||
164 | input_sync(&locomokbd->input); | ||
165 | |||
166 | /* if any keys are pressed, enable the timer */ | ||
167 | if (num_pressed) | ||
168 | mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL); | ||
169 | |||
170 | spin_unlock_irqrestore(&locomokbd->lock, flags); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * LoCoMo keyboard interrupt handler. | ||
175 | */ | ||
176 | static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
177 | { | ||
178 | struct locomokbd *locomokbd = dev_id; | ||
179 | /** wait chattering delay **/ | ||
180 | udelay(100); | ||
181 | |||
182 | locomokbd_scankeyboard(locomokbd, regs); | ||
183 | |||
184 | return IRQ_HANDLED; | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * LoCoMo timer checking for released keys | ||
189 | */ | ||
190 | static void locomokbd_timer_callback(unsigned long data) | ||
191 | { | ||
192 | struct locomokbd *locomokbd = (struct locomokbd *) data; | ||
193 | locomokbd_scankeyboard(locomokbd, NULL); | ||
194 | } | ||
195 | |||
196 | static int locomokbd_probe(struct locomo_dev *dev) | ||
197 | { | ||
198 | struct locomokbd *locomokbd; | ||
199 | int i, ret; | ||
200 | |||
201 | locomokbd = kmalloc(sizeof(struct locomokbd), GFP_KERNEL); | ||
202 | if (!locomokbd) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | memset(locomokbd, 0, sizeof(struct locomokbd)); | ||
206 | |||
207 | /* try and claim memory region */ | ||
208 | if (!request_mem_region((unsigned long) dev->mapbase, | ||
209 | dev->length, | ||
210 | LOCOMO_DRIVER_NAME(dev))) { | ||
211 | ret = -EBUSY; | ||
212 | printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n"); | ||
213 | goto free; | ||
214 | } | ||
215 | |||
216 | locomokbd->ldev = dev; | ||
217 | locomo_set_drvdata(dev, locomokbd); | ||
218 | |||
219 | locomokbd->base = (unsigned long) dev->mapbase; | ||
220 | |||
221 | spin_lock_init(&locomokbd->lock); | ||
222 | |||
223 | init_timer(&locomokbd->timer); | ||
224 | locomokbd->timer.function = locomokbd_timer_callback; | ||
225 | locomokbd->timer.data = (unsigned long) locomokbd; | ||
226 | |||
227 | locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
228 | |||
229 | init_input_dev(&locomokbd->input); | ||
230 | locomokbd->input.keycode = locomokbd->keycode; | ||
231 | locomokbd->input.keycodesize = sizeof(unsigned char); | ||
232 | locomokbd->input.keycodemax = ARRAY_SIZE(locomokbd_keycode); | ||
233 | locomokbd->input.private = locomokbd; | ||
234 | |||
235 | memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode)); | ||
236 | for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) | ||
237 | set_bit(locomokbd->keycode[i], locomokbd->input.keybit); | ||
238 | clear_bit(0, locomokbd->input.keybit); | ||
239 | |||
240 | strcpy(locomokbd->phys, "locomokbd/input0"); | ||
241 | |||
242 | locomokbd->input.name = "LoCoMo keyboard"; | ||
243 | locomokbd->input.phys = locomokbd->phys; | ||
244 | locomokbd->input.id.bustype = BUS_XTKBD; | ||
245 | locomokbd->input.id.vendor = 0x0001; | ||
246 | locomokbd->input.id.product = 0x0001; | ||
247 | locomokbd->input.id.version = 0x0100; | ||
248 | |||
249 | /* attempt to get the interrupt */ | ||
250 | ret = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd); | ||
251 | if (ret) { | ||
252 | printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n"); | ||
253 | goto out; | ||
254 | } | ||
255 | |||
256 | input_register_device(&locomokbd->input); | ||
257 | |||
258 | printk(KERN_INFO "input: LoCoMo keyboard on locomokbd\n"); | ||
259 | |||
260 | return 0; | ||
261 | |||
262 | out: | ||
263 | release_mem_region((unsigned long) dev->mapbase, dev->length); | ||
264 | locomo_set_drvdata(dev, NULL); | ||
265 | free: | ||
266 | kfree(locomokbd); | ||
267 | |||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | static int locomokbd_remove(struct locomo_dev *dev) | ||
272 | { | ||
273 | struct locomokbd *locomokbd = locomo_get_drvdata(dev); | ||
274 | |||
275 | free_irq(dev->irq[0], locomokbd); | ||
276 | |||
277 | del_timer_sync(&locomokbd->timer); | ||
278 | |||
279 | input_unregister_device(&locomokbd->input); | ||
280 | locomo_set_drvdata(dev, NULL); | ||
281 | |||
282 | release_mem_region((unsigned long) dev->mapbase, dev->length); | ||
283 | |||
284 | kfree(locomokbd); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static struct locomo_driver keyboard_driver = { | ||
290 | .drv = { | ||
291 | .name = "locomokbd" | ||
292 | }, | ||
293 | .devid = LOCOMO_DEVID_KEYBOARD, | ||
294 | .probe = locomokbd_probe, | ||
295 | .remove = locomokbd_remove, | ||
296 | }; | ||
297 | |||
298 | static int __init locomokbd_init(void) | ||
299 | { | ||
300 | return locomo_driver_register(&keyboard_driver); | ||
301 | } | ||
302 | |||
303 | static void __exit locomokbd_exit(void) | ||
304 | { | ||
305 | locomo_driver_unregister(&keyboard_driver); | ||
306 | } | ||
307 | |||
308 | module_init(locomokbd_init); | ||
309 | module_exit(locomokbd_exit); | ||
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c new file mode 100644 index 000000000000..859ed771ee0a --- /dev/null +++ b/drivers/input/keyboard/maple_keyb.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $ | ||
3 | * SEGA Dreamcast keyboard driver | ||
4 | * Based on drivers/usb/usbkbd.c | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/slab.h> | ||
9 | #include <linux/input.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/timer.h> | ||
13 | #include <linux/maple.h> | ||
14 | |||
15 | MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>"); | ||
16 | MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); | ||
17 | MODULE_LICENSE("GPL"); | ||
18 | |||
19 | static unsigned char dc_kbd_keycode[256] = { | ||
20 | 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, | ||
21 | 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, | ||
22 | 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, | ||
23 | 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, | ||
24 | 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, | ||
25 | 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, | ||
26 | 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, | ||
27 | 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, | ||
28 | 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, | ||
29 | 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
33 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
34 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, | ||
35 | 150,158,159,128,136,177,178,176,142,152,173,140 | ||
36 | }; | ||
37 | |||
38 | |||
39 | struct dc_kbd { | ||
40 | struct input_dev dev; | ||
41 | unsigned char new[8]; | ||
42 | unsigned char old[8]; | ||
43 | int open; | ||
44 | }; | ||
45 | |||
46 | |||
47 | static void dc_scan_kbd(struct dc_kbd *kbd) | ||
48 | { | ||
49 | int i; | ||
50 | struct input_dev *dev = &kbd->dev; | ||
51 | |||
52 | for(i=0; i<8; i++) | ||
53 | input_report_key(dev, | ||
54 | dc_kbd_keycode[i+224], | ||
55 | (kbd->new[0]>>i)&1); | ||
56 | |||
57 | for(i=2; i<8; i++) { | ||
58 | |||
59 | if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) { | ||
60 | if(dc_kbd_keycode[kbd->old[i]]) | ||
61 | input_report_key(dev, | ||
62 | dc_kbd_keycode[kbd->old[i]], | ||
63 | 0); | ||
64 | else | ||
65 | printk("Unknown key (scancode %#x) released.", | ||
66 | kbd->old[i]); | ||
67 | } | ||
68 | |||
69 | if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) { | ||
70 | if(dc_kbd_keycode[kbd->new[i]]) | ||
71 | input_report_key(dev, | ||
72 | dc_kbd_keycode[kbd->new[i]], | ||
73 | 1); | ||
74 | else | ||
75 | printk("Unknown key (scancode %#x) pressed.", | ||
76 | kbd->new[i]); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | input_sync(dev); | ||
81 | |||
82 | memcpy(kbd->old, kbd->new, 8); | ||
83 | } | ||
84 | |||
85 | |||
86 | static void dc_kbd_callback(struct mapleq *mq) | ||
87 | { | ||
88 | struct maple_device *mapledev = mq->dev; | ||
89 | struct dc_kbd *kbd = mapledev->private_data; | ||
90 | unsigned long *buf = mq->recvbuf; | ||
91 | |||
92 | if (buf[1] == mapledev->function) { | ||
93 | memcpy(kbd->new, buf+2, 8); | ||
94 | dc_scan_kbd(kbd); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | |||
99 | static int dc_kbd_open(struct input_dev *dev) | ||
100 | { | ||
101 | struct dc_kbd *kbd = dev->private; | ||
102 | kbd->open++; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | |||
107 | static void dc_kbd_close(struct input_dev *dev) | ||
108 | { | ||
109 | struct dc_kbd *kbd = dev->private; | ||
110 | kbd->open--; | ||
111 | } | ||
112 | |||
113 | |||
114 | static int dc_kbd_connect(struct maple_device *dev) | ||
115 | { | ||
116 | int i; | ||
117 | unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); | ||
118 | struct dc_kbd *kbd; | ||
119 | |||
120 | if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) | ||
121 | return -1; | ||
122 | memset(kbd, 0, sizeof(struct dc_kbd)); | ||
123 | |||
124 | dev->private_data = kbd; | ||
125 | |||
126 | kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
127 | |||
128 | init_input_dev(&kbd->dev); | ||
129 | |||
130 | for (i=0; i<255; i++) | ||
131 | set_bit(dc_kbd_keycode[i], kbd->dev.keybit); | ||
132 | |||
133 | clear_bit(0, kbd->dev.keybit); | ||
134 | |||
135 | kbd->dev.private = kbd; | ||
136 | kbd->dev.open = dc_kbd_open; | ||
137 | kbd->dev.close = dc_kbd_close; | ||
138 | kbd->dev.event = NULL; | ||
139 | |||
140 | kbd->dev.name = dev->product_name; | ||
141 | kbd->dev.id.bustype = BUS_MAPLE; | ||
142 | |||
143 | input_register_device(&kbd->dev); | ||
144 | |||
145 | maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); | ||
146 | |||
147 | printk(KERN_INFO "input: keyboard(0x%lx): %s\n", data, kbd->dev.name); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | |||
153 | static void dc_kbd_disconnect(struct maple_device *dev) | ||
154 | { | ||
155 | struct dc_kbd *kbd = dev->private_data; | ||
156 | |||
157 | input_unregister_device(&kbd->dev); | ||
158 | kfree(kbd); | ||
159 | } | ||
160 | |||
161 | |||
162 | static struct maple_driver dc_kbd_driver = { | ||
163 | .function = MAPLE_FUNC_KEYBOARD, | ||
164 | .name = "Dreamcast keyboard", | ||
165 | .connect = dc_kbd_connect, | ||
166 | .disconnect = dc_kbd_disconnect, | ||
167 | }; | ||
168 | |||
169 | |||
170 | static int __init dc_kbd_init(void) | ||
171 | { | ||
172 | maple_register_driver(&dc_kbd_driver); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | |||
177 | static void __exit dc_kbd_exit(void) | ||
178 | { | ||
179 | maple_unregister_driver(&dc_kbd_driver); | ||
180 | } | ||
181 | |||
182 | |||
183 | module_init(dc_kbd_init); | ||
184 | module_exit(dc_kbd_exit); | ||
185 | |||
186 | /* | ||
187 | * Local variables: | ||
188 | * c-basic-offset: 8 | ||
189 | * End: | ||
190 | */ | ||
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c new file mode 100644 index 000000000000..2e8ce1613eec --- /dev/null +++ b/drivers/input/keyboard/newtonkbd.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000 Justin Cormack | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * Newton keyboard driver for Linux | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Should you need to contact me, the author, you can do so either by | ||
25 | * e-mail - mail your message to <j.cormack@doc.ic.ac.uk>, or by paper mail: | ||
26 | * Justin Cormack, 68 Dartmouth Park Road, London NW5 1SN, UK. | ||
27 | */ | ||
28 | |||
29 | #include <linux/slab.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/input.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/serio.h> | ||
34 | |||
35 | #define DRIVER_DESC "Newton keyboard driver" | ||
36 | |||
37 | MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>"); | ||
38 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | #define NKBD_KEY 0x7f | ||
42 | #define NKBD_PRESS 0x80 | ||
43 | |||
44 | static unsigned char nkbd_keycode[128] = { | ||
45 | KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X, | ||
46 | KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R, | ||
47 | KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5, | ||
48 | KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O, | ||
49 | KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE, | ||
50 | KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT, | ||
51 | KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, 0, 0, 0, KEY_LEFTMETA, | ||
52 | KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, 0, 0, 0, | ||
53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
57 | KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0 | ||
58 | }; | ||
59 | |||
60 | static char *nkbd_name = "Newton Keyboard"; | ||
61 | |||
62 | struct nkbd { | ||
63 | unsigned char keycode[128]; | ||
64 | struct input_dev dev; | ||
65 | struct serio *serio; | ||
66 | char phys[32]; | ||
67 | }; | ||
68 | |||
69 | static irqreturn_t nkbd_interrupt(struct serio *serio, | ||
70 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
71 | { | ||
72 | struct nkbd *nkbd = serio_get_drvdata(serio); | ||
73 | |||
74 | /* invalid scan codes are probably the init sequence, so we ignore them */ | ||
75 | if (nkbd->keycode[data & NKBD_KEY]) { | ||
76 | input_regs(&nkbd->dev, regs); | ||
77 | input_report_key(&nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS); | ||
78 | input_sync(&nkbd->dev); | ||
79 | } | ||
80 | |||
81 | else if (data == 0xe7) /* end of init sequence */ | ||
82 | printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); | ||
83 | return IRQ_HANDLED; | ||
84 | |||
85 | } | ||
86 | |||
87 | static int nkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
88 | { | ||
89 | struct nkbd *nkbd; | ||
90 | int i; | ||
91 | int err; | ||
92 | |||
93 | if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL))) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | memset(nkbd, 0, sizeof(struct nkbd)); | ||
97 | |||
98 | nkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
99 | |||
100 | nkbd->serio = serio; | ||
101 | |||
102 | init_input_dev(&nkbd->dev); | ||
103 | nkbd->dev.keycode = nkbd->keycode; | ||
104 | nkbd->dev.keycodesize = sizeof(unsigned char); | ||
105 | nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode); | ||
106 | nkbd->dev.private = nkbd; | ||
107 | |||
108 | serio_set_drvdata(serio, nkbd); | ||
109 | |||
110 | err = serio_open(serio, drv); | ||
111 | if (err) { | ||
112 | serio_set_drvdata(serio, NULL); | ||
113 | kfree(nkbd); | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); | ||
118 | for (i = 0; i < 128; i++) | ||
119 | set_bit(nkbd->keycode[i], nkbd->dev.keybit); | ||
120 | clear_bit(0, nkbd->dev.keybit); | ||
121 | |||
122 | sprintf(nkbd->phys, "%s/input0", serio->phys); | ||
123 | |||
124 | nkbd->dev.name = nkbd_name; | ||
125 | nkbd->dev.phys = nkbd->phys; | ||
126 | nkbd->dev.id.bustype = BUS_RS232; | ||
127 | nkbd->dev.id.vendor = SERIO_NEWTON; | ||
128 | nkbd->dev.id.product = 0x0001; | ||
129 | nkbd->dev.id.version = 0x0100; | ||
130 | nkbd->dev.dev = &serio->dev; | ||
131 | |||
132 | input_register_device(&nkbd->dev); | ||
133 | |||
134 | printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static void nkbd_disconnect(struct serio *serio) | ||
140 | { | ||
141 | struct nkbd *nkbd = serio_get_drvdata(serio); | ||
142 | |||
143 | input_unregister_device(&nkbd->dev); | ||
144 | serio_close(serio); | ||
145 | serio_set_drvdata(serio, NULL); | ||
146 | kfree(nkbd); | ||
147 | } | ||
148 | |||
149 | static struct serio_device_id nkbd_serio_ids[] = { | ||
150 | { | ||
151 | .type = SERIO_RS232, | ||
152 | .proto = SERIO_NEWTON, | ||
153 | .id = SERIO_ANY, | ||
154 | .extra = SERIO_ANY, | ||
155 | }, | ||
156 | { 0 } | ||
157 | }; | ||
158 | |||
159 | MODULE_DEVICE_TABLE(serio, nkbd_serio_ids); | ||
160 | |||
161 | static struct serio_driver nkbd_drv = { | ||
162 | .driver = { | ||
163 | .name = "newtonkbd", | ||
164 | }, | ||
165 | .description = DRIVER_DESC, | ||
166 | .id_table = nkbd_serio_ids, | ||
167 | .interrupt = nkbd_interrupt, | ||
168 | .connect = nkbd_connect, | ||
169 | .disconnect = nkbd_disconnect, | ||
170 | }; | ||
171 | |||
172 | static int __init nkbd_init(void) | ||
173 | { | ||
174 | serio_register_driver(&nkbd_drv); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static void __exit nkbd_exit(void) | ||
179 | { | ||
180 | serio_unregister_driver(&nkbd_drv); | ||
181 | } | ||
182 | |||
183 | module_init(nkbd_init); | ||
184 | module_exit(nkbd_exit); | ||
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c new file mode 100644 index 000000000000..596964ceb96d --- /dev/null +++ b/drivers/input/keyboard/sunkbd.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Sun keyboard 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/delay.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/input.h> | ||
37 | #include <linux/serio.h> | ||
38 | #include <linux/workqueue.h> | ||
39 | |||
40 | #define DRIVER_DESC "Sun keyboard driver" | ||
41 | |||
42 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
43 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | static unsigned char sunkbd_keycode[128] = { | ||
47 | 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, | ||
48 | 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, | ||
49 | 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, | ||
50 | 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, | ||
51 | 26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32, | ||
52 | 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136, | ||
53 | 104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101, | ||
54 | 79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78 | ||
55 | }; | ||
56 | |||
57 | #define SUNKBD_CMD_RESET 0x1 | ||
58 | #define SUNKBD_CMD_BELLON 0x2 | ||
59 | #define SUNKBD_CMD_BELLOFF 0x3 | ||
60 | #define SUNKBD_CMD_CLICK 0xa | ||
61 | #define SUNKBD_CMD_NOCLICK 0xb | ||
62 | #define SUNKBD_CMD_SETLED 0xe | ||
63 | #define SUNKBD_CMD_LAYOUT 0xf | ||
64 | |||
65 | #define SUNKBD_RET_RESET 0xff | ||
66 | #define SUNKBD_RET_ALLUP 0x7f | ||
67 | #define SUNKBD_RET_LAYOUT 0xfe | ||
68 | |||
69 | #define SUNKBD_LAYOUT_5_MASK 0x20 | ||
70 | #define SUNKBD_RELEASE 0x80 | ||
71 | #define SUNKBD_KEY 0x7f | ||
72 | |||
73 | /* | ||
74 | * Per-keyboard data. | ||
75 | */ | ||
76 | |||
77 | struct sunkbd { | ||
78 | unsigned char keycode[128]; | ||
79 | struct input_dev dev; | ||
80 | struct serio *serio; | ||
81 | struct work_struct tq; | ||
82 | wait_queue_head_t wait; | ||
83 | char name[64]; | ||
84 | char phys[32]; | ||
85 | char type; | ||
86 | volatile s8 reset; | ||
87 | volatile s8 layout; | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * sunkbd_interrupt() is called by the low level driver when a character | ||
92 | * is received. | ||
93 | */ | ||
94 | |||
95 | static irqreturn_t sunkbd_interrupt(struct serio *serio, | ||
96 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
97 | { | ||
98 | struct sunkbd* sunkbd = serio_get_drvdata(serio); | ||
99 | |||
100 | if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ | ||
101 | sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ | ||
102 | wake_up_interruptible(&sunkbd->wait); | ||
103 | goto out; | ||
104 | } | ||
105 | |||
106 | if (sunkbd->layout == -1) { | ||
107 | sunkbd->layout = data; | ||
108 | wake_up_interruptible(&sunkbd->wait); | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | switch (data) { | ||
113 | |||
114 | case SUNKBD_RET_RESET: | ||
115 | schedule_work(&sunkbd->tq); | ||
116 | sunkbd->reset = -1; | ||
117 | break; | ||
118 | |||
119 | case SUNKBD_RET_LAYOUT: | ||
120 | sunkbd->layout = -1; | ||
121 | break; | ||
122 | |||
123 | case SUNKBD_RET_ALLUP: /* All keys released */ | ||
124 | break; | ||
125 | |||
126 | default: | ||
127 | if (sunkbd->keycode[data & SUNKBD_KEY]) { | ||
128 | input_regs(&sunkbd->dev, regs); | ||
129 | input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); | ||
130 | input_sync(&sunkbd->dev); | ||
131 | } else { | ||
132 | printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", | ||
133 | data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); | ||
134 | } | ||
135 | } | ||
136 | out: | ||
137 | return IRQ_HANDLED; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * sunkbd_event() handles events from the input module. | ||
142 | */ | ||
143 | |||
144 | static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
145 | { | ||
146 | struct sunkbd *sunkbd = dev->private; | ||
147 | |||
148 | switch (type) { | ||
149 | |||
150 | case EV_LED: | ||
151 | |||
152 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); | ||
153 | sunkbd->serio->write(sunkbd->serio, | ||
154 | (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | | ||
155 | (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); | ||
156 | return 0; | ||
157 | |||
158 | case EV_SND: | ||
159 | |||
160 | switch (code) { | ||
161 | |||
162 | case SND_CLICK: | ||
163 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); | ||
164 | return 0; | ||
165 | |||
166 | case SND_BELL: | ||
167 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | break; | ||
172 | } | ||
173 | |||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * sunkbd_initialize() checks for a Sun keyboard attached, and determines | ||
179 | * its type. | ||
180 | */ | ||
181 | |||
182 | static int sunkbd_initialize(struct sunkbd *sunkbd) | ||
183 | { | ||
184 | sunkbd->reset = -2; | ||
185 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); | ||
186 | wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); | ||
187 | if (sunkbd->reset <0) | ||
188 | return -1; | ||
189 | |||
190 | sunkbd->type = sunkbd->reset; | ||
191 | |||
192 | if (sunkbd->type == 4) { /* Type 4 keyboard */ | ||
193 | sunkbd->layout = -2; | ||
194 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); | ||
195 | wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); | ||
196 | if (sunkbd->layout < 0) return -1; | ||
197 | if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * sunkbd_reinit() sets leds and beeps to a state the computer remembers they | ||
205 | * were in. | ||
206 | */ | ||
207 | |||
208 | static void sunkbd_reinit(void *data) | ||
209 | { | ||
210 | struct sunkbd *sunkbd = data; | ||
211 | |||
212 | wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); | ||
213 | |||
214 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); | ||
215 | sunkbd->serio->write(sunkbd->serio, | ||
216 | (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | | ||
217 | (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); | ||
218 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); | ||
219 | sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. | ||
224 | */ | ||
225 | |||
226 | static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
227 | { | ||
228 | struct sunkbd *sunkbd; | ||
229 | int i; | ||
230 | int err; | ||
231 | |||
232 | if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) | ||
233 | return -ENOMEM; | ||
234 | |||
235 | memset(sunkbd, 0, sizeof(struct sunkbd)); | ||
236 | |||
237 | init_input_dev(&sunkbd->dev); | ||
238 | init_waitqueue_head(&sunkbd->wait); | ||
239 | |||
240 | sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); | ||
241 | sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); | ||
242 | sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); | ||
243 | |||
244 | sunkbd->serio = serio; | ||
245 | |||
246 | INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd); | ||
247 | |||
248 | sunkbd->dev.keycode = sunkbd->keycode; | ||
249 | sunkbd->dev.keycodesize = sizeof(unsigned char); | ||
250 | sunkbd->dev.keycodemax = ARRAY_SIZE(sunkbd_keycode); | ||
251 | |||
252 | sunkbd->dev.event = sunkbd_event; | ||
253 | sunkbd->dev.private = sunkbd; | ||
254 | |||
255 | serio_set_drvdata(serio, sunkbd); | ||
256 | |||
257 | err = serio_open(serio, drv); | ||
258 | if (err) { | ||
259 | serio_set_drvdata(serio, NULL); | ||
260 | kfree(sunkbd); | ||
261 | return err; | ||
262 | } | ||
263 | |||
264 | if (sunkbd_initialize(sunkbd) < 0) { | ||
265 | serio_close(serio); | ||
266 | serio_set_drvdata(serio, NULL); | ||
267 | kfree(sunkbd); | ||
268 | return -ENODEV; | ||
269 | } | ||
270 | |||
271 | sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); | ||
272 | |||
273 | memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); | ||
274 | for (i = 0; i < 128; i++) | ||
275 | set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); | ||
276 | clear_bit(0, sunkbd->dev.keybit); | ||
277 | |||
278 | sprintf(sunkbd->phys, "%s/input0", serio->phys); | ||
279 | |||
280 | sunkbd->dev.name = sunkbd->name; | ||
281 | sunkbd->dev.phys = sunkbd->phys; | ||
282 | sunkbd->dev.id.bustype = BUS_RS232; | ||
283 | sunkbd->dev.id.vendor = SERIO_SUNKBD; | ||
284 | sunkbd->dev.id.product = sunkbd->type; | ||
285 | sunkbd->dev.id.version = 0x0100; | ||
286 | sunkbd->dev.dev = &serio->dev; | ||
287 | |||
288 | input_register_device(&sunkbd->dev); | ||
289 | |||
290 | printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * sunkbd_disconnect() unregisters and closes behind us. | ||
297 | */ | ||
298 | |||
299 | static void sunkbd_disconnect(struct serio *serio) | ||
300 | { | ||
301 | struct sunkbd *sunkbd = serio_get_drvdata(serio); | ||
302 | input_unregister_device(&sunkbd->dev); | ||
303 | serio_close(serio); | ||
304 | serio_set_drvdata(serio, NULL); | ||
305 | kfree(sunkbd); | ||
306 | } | ||
307 | |||
308 | static struct serio_device_id sunkbd_serio_ids[] = { | ||
309 | { | ||
310 | .type = SERIO_RS232, | ||
311 | .proto = SERIO_SUNKBD, | ||
312 | .id = SERIO_ANY, | ||
313 | .extra = SERIO_ANY, | ||
314 | }, | ||
315 | { | ||
316 | .type = SERIO_RS232, | ||
317 | .proto = SERIO_UNKNOWN, /* sunkbd does probe */ | ||
318 | .id = SERIO_ANY, | ||
319 | .extra = SERIO_ANY, | ||
320 | }, | ||
321 | { 0 } | ||
322 | }; | ||
323 | |||
324 | MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids); | ||
325 | |||
326 | static struct serio_driver sunkbd_drv = { | ||
327 | .driver = { | ||
328 | .name = "sunkbd", | ||
329 | }, | ||
330 | .description = DRIVER_DESC, | ||
331 | .id_table = sunkbd_serio_ids, | ||
332 | .interrupt = sunkbd_interrupt, | ||
333 | .connect = sunkbd_connect, | ||
334 | .disconnect = sunkbd_disconnect, | ||
335 | }; | ||
336 | |||
337 | /* | ||
338 | * The functions for insering/removing us as a module. | ||
339 | */ | ||
340 | |||
341 | static int __init sunkbd_init(void) | ||
342 | { | ||
343 | serio_register_driver(&sunkbd_drv); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void __exit sunkbd_exit(void) | ||
348 | { | ||
349 | serio_unregister_driver(&sunkbd_drv); | ||
350 | } | ||
351 | |||
352 | module_init(sunkbd_init); | ||
353 | module_exit(sunkbd_exit); | ||
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c new file mode 100644 index 000000000000..19eaec7789d1 --- /dev/null +++ b/drivers/input/keyboard/xtkbd.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * XT keyboard 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/slab.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/input.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/serio.h> | ||
36 | |||
37 | #define DRIVER_DESC "XT keyboard driver" | ||
38 | |||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
40 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | #define XTKBD_EMUL0 0xe0 | ||
44 | #define XTKBD_EMUL1 0xe1 | ||
45 | #define XTKBD_KEY 0x7f | ||
46 | #define XTKBD_RELEASE 0x80 | ||
47 | |||
48 | static unsigned char xtkbd_keycode[256] = { | ||
49 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
50 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
51 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, | ||
52 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, | ||
53 | 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, | ||
54 | 80, 81, 82, 83, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 0, 0, | ||
55 | 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0,110,111,103,108,105, | ||
56 | 106 | ||
57 | }; | ||
58 | |||
59 | static char *xtkbd_name = "XT Keyboard"; | ||
60 | |||
61 | struct xtkbd { | ||
62 | unsigned char keycode[256]; | ||
63 | struct input_dev dev; | ||
64 | struct serio *serio; | ||
65 | char phys[32]; | ||
66 | }; | ||
67 | |||
68 | static irqreturn_t xtkbd_interrupt(struct serio *serio, | ||
69 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
70 | { | ||
71 | struct xtkbd *xtkbd = serio_get_drvdata(serio); | ||
72 | |||
73 | switch (data) { | ||
74 | case XTKBD_EMUL0: | ||
75 | case XTKBD_EMUL1: | ||
76 | break; | ||
77 | default: | ||
78 | |||
79 | if (xtkbd->keycode[data & XTKBD_KEY]) { | ||
80 | input_regs(&xtkbd->dev, regs); | ||
81 | input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); | ||
82 | input_sync(&xtkbd->dev); | ||
83 | } else { | ||
84 | printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", | ||
85 | data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); | ||
86 | } | ||
87 | } | ||
88 | return IRQ_HANDLED; | ||
89 | } | ||
90 | |||
91 | static int xtkbd_connect(struct serio *serio, struct serio_driver *drv) | ||
92 | { | ||
93 | struct xtkbd *xtkbd; | ||
94 | int i; | ||
95 | int err; | ||
96 | |||
97 | if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL))) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | memset(xtkbd, 0, sizeof(struct xtkbd)); | ||
101 | |||
102 | xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
103 | |||
104 | xtkbd->serio = serio; | ||
105 | |||
106 | init_input_dev(&xtkbd->dev); | ||
107 | xtkbd->dev.keycode = xtkbd->keycode; | ||
108 | xtkbd->dev.keycodesize = sizeof(unsigned char); | ||
109 | xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode); | ||
110 | xtkbd->dev.private = xtkbd; | ||
111 | |||
112 | serio_set_drvdata(serio, xtkbd); | ||
113 | |||
114 | err = serio_open(serio, drv); | ||
115 | if (err) { | ||
116 | serio_set_drvdata(serio, NULL); | ||
117 | kfree(xtkbd); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); | ||
122 | for (i = 0; i < 255; i++) | ||
123 | set_bit(xtkbd->keycode[i], xtkbd->dev.keybit); | ||
124 | clear_bit(0, xtkbd->dev.keybit); | ||
125 | |||
126 | sprintf(xtkbd->phys, "%s/input0", serio->phys); | ||
127 | |||
128 | xtkbd->dev.name = xtkbd_name; | ||
129 | xtkbd->dev.phys = xtkbd->phys; | ||
130 | xtkbd->dev.id.bustype = BUS_XTKBD; | ||
131 | xtkbd->dev.id.vendor = 0x0001; | ||
132 | xtkbd->dev.id.product = 0x0001; | ||
133 | xtkbd->dev.id.version = 0x0100; | ||
134 | xtkbd->dev.dev = &serio->dev; | ||
135 | |||
136 | input_register_device(&xtkbd->dev); | ||
137 | |||
138 | printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void xtkbd_disconnect(struct serio *serio) | ||
144 | { | ||
145 | struct xtkbd *xtkbd = serio_get_drvdata(serio); | ||
146 | |||
147 | input_unregister_device(&xtkbd->dev); | ||
148 | serio_close(serio); | ||
149 | serio_set_drvdata(serio, NULL); | ||
150 | kfree(xtkbd); | ||
151 | } | ||
152 | |||
153 | static struct serio_device_id xtkbd_serio_ids[] = { | ||
154 | { | ||
155 | .type = SERIO_XT, | ||
156 | .proto = SERIO_ANY, | ||
157 | .id = SERIO_ANY, | ||
158 | .extra = SERIO_ANY, | ||
159 | }, | ||
160 | { 0 } | ||
161 | }; | ||
162 | |||
163 | MODULE_DEVICE_TABLE(serio, xtkbd_serio_ids); | ||
164 | |||
165 | static struct serio_driver xtkbd_drv = { | ||
166 | .driver = { | ||
167 | .name = "xtkbd", | ||
168 | }, | ||
169 | .description = DRIVER_DESC, | ||
170 | .id_table = xtkbd_serio_ids, | ||
171 | .interrupt = xtkbd_interrupt, | ||
172 | .connect = xtkbd_connect, | ||
173 | .disconnect = xtkbd_disconnect, | ||
174 | }; | ||
175 | |||
176 | static int __init xtkbd_init(void) | ||
177 | { | ||
178 | serio_register_driver(&xtkbd_drv); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static void __exit xtkbd_exit(void) | ||
183 | { | ||
184 | serio_unregister_driver(&xtkbd_drv); | ||
185 | } | ||
186 | |||
187 | module_init(xtkbd_init); | ||
188 | module_exit(xtkbd_exit); | ||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig new file mode 100644 index 000000000000..bb934e6d9636 --- /dev/null +++ b/drivers/input/misc/Kconfig | |||
@@ -0,0 +1,60 @@ | |||
1 | # | ||
2 | # Input misc drivers configuration | ||
3 | # | ||
4 | menuconfig INPUT_MISC | ||
5 | bool "Miscellaneous devices" | ||
6 | help | ||
7 | Say Y here, and a list of miscellaneous input drivers will be displayed. | ||
8 | Everything that didn't fit into the other categories is here. This option | ||
9 | doesn't affect the kernel. | ||
10 | |||
11 | If unsure, say Y. | ||
12 | |||
13 | if INPUT_MISC | ||
14 | |||
15 | config INPUT_PCSPKR | ||
16 | tristate "PC Speaker support" | ||
17 | depends on ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES | ||
18 | help | ||
19 | Say Y here if you want the standard PC Speaker to be used for | ||
20 | bells and whistles. | ||
21 | |||
22 | If unsure, say Y. | ||
23 | |||
24 | To compile this driver as a module, choose M here: the | ||
25 | module will be called pcspkr. | ||
26 | |||
27 | config INPUT_SPARCSPKR | ||
28 | tristate "SPARC Speaker support" | ||
29 | depends on PCI && (SPARC32 || SPARC64) | ||
30 | help | ||
31 | Say Y here if you want the standard Speaker on Sparc PCI systems | ||
32 | to be used for bells and whistles. | ||
33 | |||
34 | If unsure, say Y. | ||
35 | |||
36 | To compile this driver as a module, choose M here: the | ||
37 | module will be called sparcspkr. | ||
38 | |||
39 | config INPUT_M68K_BEEP | ||
40 | tristate "M68k Beeper support" | ||
41 | depends on M68K | ||
42 | |||
43 | config INPUT_UINPUT | ||
44 | tristate "User level driver support" | ||
45 | help | ||
46 | Say Y here if you want to support user level drivers for input | ||
47 | subsystem accessible under char device 10:223 - /dev/input/uinput. | ||
48 | |||
49 | To compile this driver as a module, choose M here: the | ||
50 | module will be called uinput. | ||
51 | |||
52 | config HP_SDC_RTC | ||
53 | tristate "HP SDC Real Time Clock" | ||
54 | depends on GSC | ||
55 | select HP_SDC | ||
56 | help | ||
57 | Say Y here if you want to support the built-in real time clock | ||
58 | of the HP SDC controller. | ||
59 | |||
60 | endif | ||
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile new file mode 100644 index 000000000000..f8d01c69f349 --- /dev/null +++ b/drivers/input/misc/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Makefile for the input misc drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | ||
8 | obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o | ||
9 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | ||
10 | obj-$(CONFIG_INPUT_98SPKR) += 98spkr.o | ||
11 | obj-$(CONFIG_INPUT_UINPUT) += uinput.o | ||
12 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | ||
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c new file mode 100644 index 000000000000..1cd7657f7e42 --- /dev/null +++ b/drivers/input/misc/hp_sdc_rtc.c | |||
@@ -0,0 +1,724 @@ | |||
1 | /* | ||
2 | * HP i8042 SDC + MSM-58321 BBRTC driver. | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * System Device Controller Microprocessor Firmware Theory of Operation | ||
31 | * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 | ||
32 | * efirtc.c by Stephane Eranian/Hewlett Packard | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/hp_sdc.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/time.h> | ||
42 | #include <linux/miscdevice.h> | ||
43 | #include <linux/proc_fs.h> | ||
44 | #include <linux/poll.h> | ||
45 | #include <linux/rtc.h> | ||
46 | |||
47 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
48 | MODULE_DESCRIPTION("HP i8042 SDC + MSM-58321 RTC Driver"); | ||
49 | MODULE_LICENSE("Dual BSD/GPL"); | ||
50 | |||
51 | #define RTC_VERSION "1.10d" | ||
52 | |||
53 | static unsigned long epoch = 2000; | ||
54 | |||
55 | static struct semaphore i8042tregs; | ||
56 | |||
57 | static hp_sdc_irqhook hp_sdc_rtc_isr; | ||
58 | |||
59 | static struct fasync_struct *hp_sdc_rtc_async_queue; | ||
60 | |||
61 | static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait); | ||
62 | |||
63 | static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin); | ||
64 | |||
65 | static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, | ||
66 | size_t count, loff_t *ppos); | ||
67 | |||
68 | static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, | ||
69 | unsigned int cmd, unsigned long arg); | ||
70 | |||
71 | static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait); | ||
72 | |||
73 | static int hp_sdc_rtc_open(struct inode *inode, struct file *file); | ||
74 | static int hp_sdc_rtc_release(struct inode *inode, struct file *file); | ||
75 | static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on); | ||
76 | |||
77 | static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off, | ||
78 | int count, int *eof, void *data); | ||
79 | |||
80 | static void hp_sdc_rtc_isr (int irq, void *dev_id, | ||
81 | uint8_t status, uint8_t data) | ||
82 | { | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm) | ||
87 | { | ||
88 | struct semaphore tsem; | ||
89 | hp_sdc_transaction t; | ||
90 | uint8_t tseq[91]; | ||
91 | int i; | ||
92 | |||
93 | i = 0; | ||
94 | while (i < 91) { | ||
95 | tseq[i++] = HP_SDC_ACT_DATAREG | | ||
96 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN; | ||
97 | tseq[i++] = 0x01; /* write i8042[0x70] */ | ||
98 | tseq[i] = i / 7; /* BBRTC reg address */ | ||
99 | i++; | ||
100 | tseq[i++] = HP_SDC_CMD_DO_RTCR; /* Trigger command */ | ||
101 | tseq[i++] = 2; /* expect 1 stat/dat pair back. */ | ||
102 | i++; i++; /* buffer for stat/dat pair */ | ||
103 | } | ||
104 | tseq[84] |= HP_SDC_ACT_SEMAPHORE; | ||
105 | t.endidx = 91; | ||
106 | t.seq = tseq; | ||
107 | t.act.semaphore = &tsem; | ||
108 | init_MUTEX_LOCKED(&tsem); | ||
109 | |||
110 | if (hp_sdc_enqueue_transaction(&t)) return -1; | ||
111 | |||
112 | down_interruptible(&tsem); /* Put ourselves to sleep for results. */ | ||
113 | |||
114 | /* Check for nonpresence of BBRTC */ | ||
115 | if (!((tseq[83] | tseq[90] | tseq[69] | tseq[76] | | ||
116 | tseq[55] | tseq[62] | tseq[34] | tseq[41] | | ||
117 | tseq[20] | tseq[27] | tseq[6] | tseq[13]) & 0x0f)) | ||
118 | return -1; | ||
119 | |||
120 | memset(rtctm, 0, sizeof(struct rtc_time)); | ||
121 | rtctm->tm_year = (tseq[83] & 0x0f) + (tseq[90] & 0x0f) * 10; | ||
122 | rtctm->tm_mon = (tseq[69] & 0x0f) + (tseq[76] & 0x0f) * 10; | ||
123 | rtctm->tm_mday = (tseq[55] & 0x0f) + (tseq[62] & 0x0f) * 10; | ||
124 | rtctm->tm_wday = (tseq[48] & 0x0f); | ||
125 | rtctm->tm_hour = (tseq[34] & 0x0f) + (tseq[41] & 0x0f) * 10; | ||
126 | rtctm->tm_min = (tseq[20] & 0x0f) + (tseq[27] & 0x0f) * 10; | ||
127 | rtctm->tm_sec = (tseq[6] & 0x0f) + (tseq[13] & 0x0f) * 10; | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int hp_sdc_rtc_read_bbrtc (struct rtc_time *rtctm) | ||
133 | { | ||
134 | struct rtc_time tm, tm_last; | ||
135 | int i = 0; | ||
136 | |||
137 | /* MSM-58321 has no read latch, so must read twice and compare. */ | ||
138 | |||
139 | if (hp_sdc_rtc_do_read_bbrtc(&tm_last)) return -1; | ||
140 | if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1; | ||
141 | |||
142 | while (memcmp(&tm, &tm_last, sizeof(struct rtc_time))) { | ||
143 | if (i++ > 4) return -1; | ||
144 | memcpy(&tm_last, &tm, sizeof(struct rtc_time)); | ||
145 | if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1; | ||
146 | } | ||
147 | |||
148 | memcpy(rtctm, &tm, sizeof(struct rtc_time)); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | |||
154 | static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg) | ||
155 | { | ||
156 | hp_sdc_transaction t; | ||
157 | uint8_t tseq[26] = { | ||
158 | HP_SDC_ACT_PRECMD | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, | ||
159 | 0, | ||
160 | HP_SDC_CMD_READ_T1, 2, 0, 0, | ||
161 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, | ||
162 | HP_SDC_CMD_READ_T2, 2, 0, 0, | ||
163 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, | ||
164 | HP_SDC_CMD_READ_T3, 2, 0, 0, | ||
165 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, | ||
166 | HP_SDC_CMD_READ_T4, 2, 0, 0, | ||
167 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, | ||
168 | HP_SDC_CMD_READ_T5, 2, 0, 0 | ||
169 | }; | ||
170 | |||
171 | t.endidx = numreg * 5; | ||
172 | |||
173 | tseq[1] = loadcmd; | ||
174 | tseq[t.endidx - 4] |= HP_SDC_ACT_SEMAPHORE; /* numreg assumed > 1 */ | ||
175 | |||
176 | t.seq = tseq; | ||
177 | t.act.semaphore = &i8042tregs; | ||
178 | |||
179 | down_interruptible(&i8042tregs); /* Sleep if output regs in use. */ | ||
180 | |||
181 | if (hp_sdc_enqueue_transaction(&t)) return -1; | ||
182 | |||
183 | down_interruptible(&i8042tregs); /* Sleep until results come back. */ | ||
184 | up(&i8042tregs); | ||
185 | |||
186 | return (tseq[5] | | ||
187 | ((uint64_t)(tseq[10]) << 8) | ((uint64_t)(tseq[15]) << 16) | | ||
188 | ((uint64_t)(tseq[20]) << 24) | ((uint64_t)(tseq[25]) << 32)); | ||
189 | } | ||
190 | |||
191 | |||
192 | /* Read the i8042 real-time clock */ | ||
193 | static inline int hp_sdc_rtc_read_rt(struct timeval *res) { | ||
194 | int64_t raw; | ||
195 | uint32_t tenms; | ||
196 | unsigned int days; | ||
197 | |||
198 | raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_RT, 5); | ||
199 | if (raw < 0) return -1; | ||
200 | |||
201 | tenms = (uint32_t)raw & 0xffffff; | ||
202 | days = (unsigned int)(raw >> 24) & 0xffff; | ||
203 | |||
204 | res->tv_usec = (suseconds_t)(tenms % 100) * 10000; | ||
205 | res->tv_sec = (time_t)(tenms / 100) + days * 86400; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | |||
211 | /* Read the i8042 fast handshake timer */ | ||
212 | static inline int hp_sdc_rtc_read_fhs(struct timeval *res) { | ||
213 | uint64_t raw; | ||
214 | unsigned int tenms; | ||
215 | |||
216 | raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2); | ||
217 | if (raw < 0) return -1; | ||
218 | |||
219 | tenms = (unsigned int)raw & 0xffff; | ||
220 | |||
221 | res->tv_usec = (suseconds_t)(tenms % 100) * 10000; | ||
222 | res->tv_sec = (time_t)(tenms / 100); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | |||
228 | /* Read the i8042 match timer (a.k.a. alarm) */ | ||
229 | static inline int hp_sdc_rtc_read_mt(struct timeval *res) { | ||
230 | int64_t raw; | ||
231 | uint32_t tenms; | ||
232 | |||
233 | raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_MT, 3); | ||
234 | if (raw < 0) return -1; | ||
235 | |||
236 | tenms = (uint32_t)raw & 0xffffff; | ||
237 | |||
238 | res->tv_usec = (suseconds_t)(tenms % 100) * 10000; | ||
239 | res->tv_sec = (time_t)(tenms / 100); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | |||
245 | /* Read the i8042 delay timer */ | ||
246 | static inline int hp_sdc_rtc_read_dt(struct timeval *res) { | ||
247 | int64_t raw; | ||
248 | uint32_t tenms; | ||
249 | |||
250 | raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_DT, 3); | ||
251 | if (raw < 0) return -1; | ||
252 | |||
253 | tenms = (uint32_t)raw & 0xffffff; | ||
254 | |||
255 | res->tv_usec = (suseconds_t)(tenms % 100) * 10000; | ||
256 | res->tv_sec = (time_t)(tenms / 100); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | |||
262 | /* Read the i8042 cycle timer (a.k.a. periodic) */ | ||
263 | static inline int hp_sdc_rtc_read_ct(struct timeval *res) { | ||
264 | int64_t raw; | ||
265 | uint32_t tenms; | ||
266 | |||
267 | raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_CT, 3); | ||
268 | if (raw < 0) return -1; | ||
269 | |||
270 | tenms = (uint32_t)raw & 0xffffff; | ||
271 | |||
272 | res->tv_usec = (suseconds_t)(tenms % 100) * 10000; | ||
273 | res->tv_sec = (time_t)(tenms / 100); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | |||
279 | /* Set the i8042 real-time clock */ | ||
280 | static int hp_sdc_rtc_set_rt (struct timeval *setto) | ||
281 | { | ||
282 | uint32_t tenms; | ||
283 | unsigned int days; | ||
284 | hp_sdc_transaction t; | ||
285 | uint8_t tseq[11] = { | ||
286 | HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, | ||
287 | HP_SDC_CMD_SET_RTMS, 3, 0, 0, 0, | ||
288 | HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, | ||
289 | HP_SDC_CMD_SET_RTD, 2, 0, 0 | ||
290 | }; | ||
291 | |||
292 | t.endidx = 10; | ||
293 | |||
294 | if (0xffff < setto->tv_sec / 86400) return -1; | ||
295 | days = setto->tv_sec / 86400; | ||
296 | if (0xffff < setto->tv_usec / 1000000 / 86400) return -1; | ||
297 | days += ((setto->tv_sec % 86400) + setto->tv_usec / 1000000) / 86400; | ||
298 | if (days > 0xffff) return -1; | ||
299 | |||
300 | if (0xffffff < setto->tv_sec) return -1; | ||
301 | tenms = setto->tv_sec * 100; | ||
302 | if (0xffffff < setto->tv_usec / 10000) return -1; | ||
303 | tenms += setto->tv_usec / 10000; | ||
304 | if (tenms > 0xffffff) return -1; | ||
305 | |||
306 | tseq[3] = (uint8_t)(tenms & 0xff); | ||
307 | tseq[4] = (uint8_t)((tenms >> 8) & 0xff); | ||
308 | tseq[5] = (uint8_t)((tenms >> 16) & 0xff); | ||
309 | |||
310 | tseq[9] = (uint8_t)(days & 0xff); | ||
311 | tseq[10] = (uint8_t)((days >> 8) & 0xff); | ||
312 | |||
313 | t.seq = tseq; | ||
314 | |||
315 | if (hp_sdc_enqueue_transaction(&t)) return -1; | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | /* Set the i8042 fast handshake timer */ | ||
320 | static int hp_sdc_rtc_set_fhs (struct timeval *setto) | ||
321 | { | ||
322 | uint32_t tenms; | ||
323 | hp_sdc_transaction t; | ||
324 | uint8_t tseq[5] = { | ||
325 | HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, | ||
326 | HP_SDC_CMD_SET_FHS, 2, 0, 0 | ||
327 | }; | ||
328 | |||
329 | t.endidx = 4; | ||
330 | |||
331 | if (0xffff < setto->tv_sec) return -1; | ||
332 | tenms = setto->tv_sec * 100; | ||
333 | if (0xffff < setto->tv_usec / 10000) return -1; | ||
334 | tenms += setto->tv_usec / 10000; | ||
335 | if (tenms > 0xffff) return -1; | ||
336 | |||
337 | tseq[3] = (uint8_t)(tenms & 0xff); | ||
338 | tseq[4] = (uint8_t)((tenms >> 8) & 0xff); | ||
339 | |||
340 | t.seq = tseq; | ||
341 | |||
342 | if (hp_sdc_enqueue_transaction(&t)) return -1; | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | |||
347 | /* Set the i8042 match timer (a.k.a. alarm) */ | ||
348 | #define hp_sdc_rtc_set_mt (setto) \ | ||
349 | hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_MT) | ||
350 | |||
351 | /* Set the i8042 delay timer */ | ||
352 | #define hp_sdc_rtc_set_dt (setto) \ | ||
353 | hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_DT) | ||
354 | |||
355 | /* Set the i8042 cycle timer (a.k.a. periodic) */ | ||
356 | #define hp_sdc_rtc_set_ct (setto) \ | ||
357 | hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_CT) | ||
358 | |||
359 | /* Set one of the i8042 3-byte wide timers */ | ||
360 | static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd) | ||
361 | { | ||
362 | uint32_t tenms; | ||
363 | hp_sdc_transaction t; | ||
364 | uint8_t tseq[6] = { | ||
365 | HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, | ||
366 | 0, 3, 0, 0, 0 | ||
367 | }; | ||
368 | |||
369 | t.endidx = 6; | ||
370 | |||
371 | if (0xffffff < setto->tv_sec) return -1; | ||
372 | tenms = setto->tv_sec * 100; | ||
373 | if (0xffffff < setto->tv_usec / 10000) return -1; | ||
374 | tenms += setto->tv_usec / 10000; | ||
375 | if (tenms > 0xffffff) return -1; | ||
376 | |||
377 | tseq[1] = setcmd; | ||
378 | tseq[3] = (uint8_t)(tenms & 0xff); | ||
379 | tseq[4] = (uint8_t)((tenms >> 8) & 0xff); | ||
380 | tseq[5] = (uint8_t)((tenms >> 16) & 0xff); | ||
381 | |||
382 | t.seq = tseq; | ||
383 | |||
384 | if (hp_sdc_enqueue_transaction(&t)) { | ||
385 | return -1; | ||
386 | } | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin) | ||
391 | { | ||
392 | return -ESPIPE; | ||
393 | } | ||
394 | |||
395 | static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, | ||
396 | size_t count, loff_t *ppos) { | ||
397 | ssize_t retval; | ||
398 | |||
399 | if (count < sizeof(unsigned long)) | ||
400 | return -EINVAL; | ||
401 | |||
402 | retval = put_user(68, (unsigned long *)buf); | ||
403 | return retval; | ||
404 | } | ||
405 | |||
406 | static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait) | ||
407 | { | ||
408 | unsigned long l; | ||
409 | |||
410 | l = 0; | ||
411 | if (l != 0) | ||
412 | return POLLIN | POLLRDNORM; | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static int hp_sdc_rtc_open(struct inode *inode, struct file *file) | ||
417 | { | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int hp_sdc_rtc_release(struct inode *inode, struct file *file) | ||
422 | { | ||
423 | /* Turn off interrupts? */ | ||
424 | |||
425 | if (file->f_flags & FASYNC) { | ||
426 | hp_sdc_rtc_fasync (-1, file, 0); | ||
427 | } | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on) | ||
433 | { | ||
434 | return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue); | ||
435 | } | ||
436 | |||
437 | static int hp_sdc_rtc_proc_output (char *buf) | ||
438 | { | ||
439 | #define YN(bit) ("no") | ||
440 | #define NY(bit) ("yes") | ||
441 | char *p; | ||
442 | struct rtc_time tm; | ||
443 | struct timeval tv; | ||
444 | |||
445 | memset(&tm, 0, sizeof(struct rtc_time)); | ||
446 | |||
447 | p = buf; | ||
448 | |||
449 | if (hp_sdc_rtc_read_bbrtc(&tm)) { | ||
450 | p += sprintf(p, "BBRTC\t\t: READ FAILED!\n"); | ||
451 | } else { | ||
452 | p += sprintf(p, | ||
453 | "rtc_time\t: %02d:%02d:%02d\n" | ||
454 | "rtc_date\t: %04d-%02d-%02d\n" | ||
455 | "rtc_epoch\t: %04lu\n", | ||
456 | tm.tm_hour, tm.tm_min, tm.tm_sec, | ||
457 | tm.tm_year + 1900, tm.tm_mon + 1, | ||
458 | tm.tm_mday, epoch); | ||
459 | } | ||
460 | |||
461 | if (hp_sdc_rtc_read_rt(&tv)) { | ||
462 | p += sprintf(p, "i8042 rtc\t: READ FAILED!\n"); | ||
463 | } else { | ||
464 | p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n", | ||
465 | tv.tv_sec, tv.tv_usec/1000); | ||
466 | } | ||
467 | |||
468 | if (hp_sdc_rtc_read_fhs(&tv)) { | ||
469 | p += sprintf(p, "handshake\t: READ FAILED!\n"); | ||
470 | } else { | ||
471 | p += sprintf(p, "handshake\t: %ld.%02d seconds\n", | ||
472 | tv.tv_sec, tv.tv_usec/1000); | ||
473 | } | ||
474 | |||
475 | if (hp_sdc_rtc_read_mt(&tv)) { | ||
476 | p += sprintf(p, "alarm\t\t: READ FAILED!\n"); | ||
477 | } else { | ||
478 | p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n", | ||
479 | tv.tv_sec, tv.tv_usec/1000); | ||
480 | } | ||
481 | |||
482 | if (hp_sdc_rtc_read_dt(&tv)) { | ||
483 | p += sprintf(p, "delay\t\t: READ FAILED!\n"); | ||
484 | } else { | ||
485 | p += sprintf(p, "delay\t\t: %ld.%02d seconds\n", | ||
486 | tv.tv_sec, tv.tv_usec/1000); | ||
487 | } | ||
488 | |||
489 | if (hp_sdc_rtc_read_ct(&tv)) { | ||
490 | p += sprintf(p, "periodic\t: READ FAILED!\n"); | ||
491 | } else { | ||
492 | p += sprintf(p, "periodic\t: %ld.%02d seconds\n", | ||
493 | tv.tv_sec, tv.tv_usec/1000); | ||
494 | } | ||
495 | |||
496 | p += sprintf(p, | ||
497 | "DST_enable\t: %s\n" | ||
498 | "BCD\t\t: %s\n" | ||
499 | "24hr\t\t: %s\n" | ||
500 | "square_wave\t: %s\n" | ||
501 | "alarm_IRQ\t: %s\n" | ||
502 | "update_IRQ\t: %s\n" | ||
503 | "periodic_IRQ\t: %s\n" | ||
504 | "periodic_freq\t: %ld\n" | ||
505 | "batt_status\t: %s\n", | ||
506 | YN(RTC_DST_EN), | ||
507 | NY(RTC_DM_BINARY), | ||
508 | YN(RTC_24H), | ||
509 | YN(RTC_SQWE), | ||
510 | YN(RTC_AIE), | ||
511 | YN(RTC_UIE), | ||
512 | YN(RTC_PIE), | ||
513 | 1UL, | ||
514 | 1 ? "okay" : "dead"); | ||
515 | |||
516 | return p - buf; | ||
517 | #undef YN | ||
518 | #undef NY | ||
519 | } | ||
520 | |||
521 | static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off, | ||
522 | int count, int *eof, void *data) | ||
523 | { | ||
524 | int len = hp_sdc_rtc_proc_output (page); | ||
525 | if (len <= off+count) *eof = 1; | ||
526 | *start = page + off; | ||
527 | len -= off; | ||
528 | if (len>count) len = count; | ||
529 | if (len<0) len = 0; | ||
530 | return len; | ||
531 | } | ||
532 | |||
533 | static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, | ||
534 | unsigned int cmd, unsigned long arg) | ||
535 | { | ||
536 | #if 1 | ||
537 | return -EINVAL; | ||
538 | #else | ||
539 | |||
540 | struct rtc_time wtime; | ||
541 | struct timeval ttime; | ||
542 | int use_wtime = 0; | ||
543 | |||
544 | /* This needs major work. */ | ||
545 | |||
546 | switch (cmd) { | ||
547 | |||
548 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ | ||
549 | case RTC_AIE_ON: /* Allow alarm interrupts. */ | ||
550 | case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ | ||
551 | case RTC_PIE_ON: /* Allow periodic ints */ | ||
552 | case RTC_UIE_ON: /* Allow ints for RTC updates. */ | ||
553 | case RTC_UIE_OFF: /* Allow ints for RTC updates. */ | ||
554 | { | ||
555 | /* We cannot mask individual user timers and we | ||
556 | cannot tell them apart when they occur, so it | ||
557 | would be disingenuous to succeed these IOCTLs */ | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | case RTC_ALM_READ: /* Read the present alarm time */ | ||
561 | { | ||
562 | if (hp_sdc_rtc_read_mt(&ttime)) return -EFAULT; | ||
563 | if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT; | ||
564 | |||
565 | wtime.tm_hour = ttime.tv_sec / 3600; ttime.tv_sec %= 3600; | ||
566 | wtime.tm_min = ttime.tv_sec / 60; ttime.tv_sec %= 60; | ||
567 | wtime.tm_sec = ttime.tv_sec; | ||
568 | |||
569 | break; | ||
570 | } | ||
571 | case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ | ||
572 | { | ||
573 | return put_user(hp_sdc_rtc_freq, (unsigned long *)arg); | ||
574 | } | ||
575 | case RTC_IRQP_SET: /* Set periodic IRQ rate. */ | ||
576 | { | ||
577 | /* | ||
578 | * The max we can do is 100Hz. | ||
579 | */ | ||
580 | |||
581 | if ((arg < 1) || (arg > 100)) return -EINVAL; | ||
582 | ttime.tv_sec = 0; | ||
583 | ttime.tv_usec = 1000000 / arg; | ||
584 | if (hp_sdc_rtc_set_ct(&ttime)) return -EFAULT; | ||
585 | hp_sdc_rtc_freq = arg; | ||
586 | return 0; | ||
587 | } | ||
588 | case RTC_ALM_SET: /* Store a time into the alarm */ | ||
589 | { | ||
590 | /* | ||
591 | * This expects a struct hp_sdc_rtc_time. Writing 0xff means | ||
592 | * "don't care" or "match all" for PC timers. The HP SDC | ||
593 | * does not support that perk, but it could be emulated fairly | ||
594 | * easily. Only the tm_hour, tm_min and tm_sec are used. | ||
595 | * We could do it with 10ms accuracy with the HP SDC, if the | ||
596 | * rtc interface left us a way to do that. | ||
597 | */ | ||
598 | struct hp_sdc_rtc_time alm_tm; | ||
599 | |||
600 | if (copy_from_user(&alm_tm, (struct hp_sdc_rtc_time*)arg, | ||
601 | sizeof(struct hp_sdc_rtc_time))) | ||
602 | return -EFAULT; | ||
603 | |||
604 | if (alm_tm.tm_hour > 23) return -EINVAL; | ||
605 | if (alm_tm.tm_min > 59) return -EINVAL; | ||
606 | if (alm_tm.tm_sec > 59) return -EINVAL; | ||
607 | |||
608 | ttime.sec = alm_tm.tm_hour * 3600 + | ||
609 | alm_tm.tm_min * 60 + alm_tm.tm_sec; | ||
610 | ttime.usec = 0; | ||
611 | if (hp_sdc_rtc_set_mt(&ttime)) return -EFAULT; | ||
612 | return 0; | ||
613 | } | ||
614 | case RTC_RD_TIME: /* Read the time/date from RTC */ | ||
615 | { | ||
616 | if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT; | ||
617 | break; | ||
618 | } | ||
619 | case RTC_SET_TIME: /* Set the RTC */ | ||
620 | { | ||
621 | struct rtc_time hp_sdc_rtc_tm; | ||
622 | unsigned char mon, day, hrs, min, sec, leap_yr; | ||
623 | unsigned int yrs; | ||
624 | |||
625 | if (!capable(CAP_SYS_TIME)) | ||
626 | return -EACCES; | ||
627 | if (copy_from_user(&hp_sdc_rtc_tm, (struct rtc_time *)arg, | ||
628 | sizeof(struct rtc_time))) | ||
629 | return -EFAULT; | ||
630 | |||
631 | yrs = hp_sdc_rtc_tm.tm_year + 1900; | ||
632 | mon = hp_sdc_rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | ||
633 | day = hp_sdc_rtc_tm.tm_mday; | ||
634 | hrs = hp_sdc_rtc_tm.tm_hour; | ||
635 | min = hp_sdc_rtc_tm.tm_min; | ||
636 | sec = hp_sdc_rtc_tm.tm_sec; | ||
637 | |||
638 | if (yrs < 1970) | ||
639 | return -EINVAL; | ||
640 | |||
641 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | ||
642 | |||
643 | if ((mon > 12) || (day == 0)) | ||
644 | return -EINVAL; | ||
645 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | ||
646 | return -EINVAL; | ||
647 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | ||
648 | return -EINVAL; | ||
649 | |||
650 | if ((yrs -= eH) > 255) /* They are unsigned */ | ||
651 | return -EINVAL; | ||
652 | |||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | case RTC_EPOCH_READ: /* Read the epoch. */ | ||
657 | { | ||
658 | return put_user (epoch, (unsigned long *)arg); | ||
659 | } | ||
660 | case RTC_EPOCH_SET: /* Set the epoch. */ | ||
661 | { | ||
662 | /* | ||
663 | * There were no RTC clocks before 1900. | ||
664 | */ | ||
665 | if (arg < 1900) | ||
666 | return -EINVAL; | ||
667 | if (!capable(CAP_SYS_TIME)) | ||
668 | return -EACCES; | ||
669 | |||
670 | epoch = arg; | ||
671 | return 0; | ||
672 | } | ||
673 | default: | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; | ||
677 | #endif | ||
678 | } | ||
679 | |||
680 | static struct file_operations hp_sdc_rtc_fops = { | ||
681 | .owner = THIS_MODULE, | ||
682 | .llseek = hp_sdc_rtc_llseek, | ||
683 | .read = hp_sdc_rtc_read, | ||
684 | .poll = hp_sdc_rtc_poll, | ||
685 | .ioctl = hp_sdc_rtc_ioctl, | ||
686 | .open = hp_sdc_rtc_open, | ||
687 | .release = hp_sdc_rtc_release, | ||
688 | .fasync = hp_sdc_rtc_fasync, | ||
689 | }; | ||
690 | |||
691 | static struct miscdevice hp_sdc_rtc_dev = { | ||
692 | .minor = RTC_MINOR, | ||
693 | .name = "rtc_HIL", | ||
694 | .fops = &hp_sdc_rtc_fops | ||
695 | }; | ||
696 | |||
697 | static int __init hp_sdc_rtc_init(void) | ||
698 | { | ||
699 | int ret; | ||
700 | |||
701 | init_MUTEX(&i8042tregs); | ||
702 | |||
703 | if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) | ||
704 | return ret; | ||
705 | misc_register(&hp_sdc_rtc_dev); | ||
706 | create_proc_read_entry ("driver/rtc", 0, 0, | ||
707 | hp_sdc_rtc_read_proc, NULL); | ||
708 | |||
709 | printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " | ||
710 | "(RTC v " RTC_VERSION ")\n"); | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static void __exit hp_sdc_rtc_exit(void) | ||
716 | { | ||
717 | remove_proc_entry ("driver/rtc", NULL); | ||
718 | misc_deregister(&hp_sdc_rtc_dev); | ||
719 | hp_sdc_release_timer_irq(hp_sdc_rtc_isr); | ||
720 | printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n"); | ||
721 | } | ||
722 | |||
723 | module_init(hp_sdc_rtc_init); | ||
724 | module_exit(hp_sdc_rtc_exit); | ||
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c new file mode 100644 index 000000000000..64abdd98d482 --- /dev/null +++ b/drivers/input/misc/m68kspkr.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * m68k beeper driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002 Richard Zidlicky | ||
5 | * Copyright (c) 2002 Vojtech Pavlik | ||
6 | * Copyright (c) 1992 Orest Zborowski | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License version 2 as published by | ||
13 | * the Free Software Foundation | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <asm/machdep.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | MODULE_AUTHOR("Richard Zidlicky <rz@linux-m68k.org>"); | ||
24 | MODULE_DESCRIPTION("m68k beeper driver"); | ||
25 | MODULE_LICENSE("GPL"); | ||
26 | |||
27 | static char m68kspkr_name[] = "m68k beeper"; | ||
28 | static char m68kspkr_phys[] = "m68k/generic"; | ||
29 | static struct input_dev m68kspkr_dev; | ||
30 | |||
31 | static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
32 | { | ||
33 | unsigned int count = 0; | ||
34 | |||
35 | if (type != EV_SND) | ||
36 | return -1; | ||
37 | |||
38 | switch (code) { | ||
39 | case SND_BELL: if (value) value = 1000; | ||
40 | case SND_TONE: break; | ||
41 | default: return -1; | ||
42 | } | ||
43 | |||
44 | if (value > 20 && value < 32767) | ||
45 | count = 1193182 / value; | ||
46 | |||
47 | mach_beep(count, -1); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int __init m68kspkr_init(void) | ||
53 | { | ||
54 | if (!mach_beep){ | ||
55 | printk("%s: no lowlevel beep support\n", m68kspkr_name); | ||
56 | return -1; | ||
57 | } | ||
58 | |||
59 | m68kspkr_dev.evbit[0] = BIT(EV_SND); | ||
60 | m68kspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); | ||
61 | m68kspkr_dev.event = m68kspkr_event; | ||
62 | |||
63 | m68kspkr_dev.name = m68kspkr_name; | ||
64 | m68kspkr_dev.phys = m68kspkr_phys; | ||
65 | m68kspkr_dev.id.bustype = BUS_HOST; | ||
66 | m68kspkr_dev.id.vendor = 0x001f; | ||
67 | m68kspkr_dev.id.product = 0x0001; | ||
68 | m68kspkr_dev.id.version = 0x0100; | ||
69 | |||
70 | input_register_device(&m68kspkr_dev); | ||
71 | |||
72 | printk(KERN_INFO "input: %s\n", m68kspkr_name); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void __exit m68kspkr_exit(void) | ||
78 | { | ||
79 | input_unregister_device(&m68kspkr_dev); | ||
80 | } | ||
81 | |||
82 | module_init(m68kspkr_init); | ||
83 | module_exit(m68kspkr_exit); | ||
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c new file mode 100644 index 000000000000..3013194f462b --- /dev/null +++ b/drivers/input/misc/pcspkr.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * PC Speaker beeper driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002 Vojtech Pavlik | ||
5 | * Copyright (c) 1992 Orest Zborowski | ||
6 | * | ||
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 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <asm/8253pit.h> | ||
20 | #include <asm/io.h> | ||
21 | |||
22 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
23 | MODULE_DESCRIPTION("PC Speaker beeper driver"); | ||
24 | MODULE_LICENSE("GPL"); | ||
25 | |||
26 | static char pcspkr_name[] = "PC Speaker"; | ||
27 | static char pcspkr_phys[] = "isa0061/input0"; | ||
28 | static struct input_dev pcspkr_dev; | ||
29 | |||
30 | static DEFINE_SPINLOCK(i8253_beep_lock); | ||
31 | |||
32 | static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
33 | { | ||
34 | unsigned int count = 0; | ||
35 | unsigned long flags; | ||
36 | |||
37 | if (type != EV_SND) | ||
38 | return -1; | ||
39 | |||
40 | switch (code) { | ||
41 | case SND_BELL: if (value) value = 1000; | ||
42 | case SND_TONE: break; | ||
43 | default: return -1; | ||
44 | } | ||
45 | |||
46 | if (value > 20 && value < 32767) | ||
47 | count = PIT_TICK_RATE / value; | ||
48 | |||
49 | spin_lock_irqsave(&i8253_beep_lock, flags); | ||
50 | |||
51 | if (count) { | ||
52 | /* enable counter 2 */ | ||
53 | outb_p(inb_p(0x61) | 3, 0x61); | ||
54 | /* set command for counter 2, 2 byte write */ | ||
55 | outb_p(0xB6, 0x43); | ||
56 | /* select desired HZ */ | ||
57 | outb_p(count & 0xff, 0x42); | ||
58 | outb((count >> 8) & 0xff, 0x42); | ||
59 | } else { | ||
60 | /* disable counter 2 */ | ||
61 | outb(inb_p(0x61) & 0xFC, 0x61); | ||
62 | } | ||
63 | |||
64 | spin_unlock_irqrestore(&i8253_beep_lock, flags); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int __init pcspkr_init(void) | ||
70 | { | ||
71 | pcspkr_dev.evbit[0] = BIT(EV_SND); | ||
72 | pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); | ||
73 | pcspkr_dev.event = pcspkr_event; | ||
74 | |||
75 | pcspkr_dev.name = pcspkr_name; | ||
76 | pcspkr_dev.phys = pcspkr_phys; | ||
77 | pcspkr_dev.id.bustype = BUS_ISA; | ||
78 | pcspkr_dev.id.vendor = 0x001f; | ||
79 | pcspkr_dev.id.product = 0x0001; | ||
80 | pcspkr_dev.id.version = 0x0100; | ||
81 | |||
82 | input_register_device(&pcspkr_dev); | ||
83 | |||
84 | printk(KERN_INFO "input: %s\n", pcspkr_name); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static void __exit pcspkr_exit(void) | ||
90 | { | ||
91 | input_unregister_device(&pcspkr_dev); | ||
92 | /* turn off the speaker */ | ||
93 | pcspkr_event(NULL, EV_SND, SND_BELL, 0); | ||
94 | } | ||
95 | |||
96 | module_init(pcspkr_init); | ||
97 | module_exit(pcspkr_exit); | ||
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c new file mode 100644 index 000000000000..cdc3fb3d5f46 --- /dev/null +++ b/drivers/input/misc/sparcspkr.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * Driver for PC-speaker like devices found on various Sparc systems. | ||
3 | * | ||
4 | * Copyright (c) 2002 Vojtech Pavlik | ||
5 | * Copyright (c) 2002 David S. Miller (davem@redhat.com) | ||
6 | */ | ||
7 | #include <linux/config.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/input.h> | ||
12 | |||
13 | #include <asm/io.h> | ||
14 | #include <asm/ebus.h> | ||
15 | #ifdef CONFIG_SPARC64 | ||
16 | #include <asm/isa.h> | ||
17 | #endif | ||
18 | |||
19 | MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); | ||
20 | MODULE_DESCRIPTION("PC Speaker beeper driver"); | ||
21 | MODULE_LICENSE("GPL"); | ||
22 | |||
23 | static unsigned long beep_iobase; | ||
24 | |||
25 | static char *sparcspkr_isa_name = "Sparc ISA Speaker"; | ||
26 | static char *sparcspkr_ebus_name = "Sparc EBUS Speaker"; | ||
27 | static char *sparcspkr_phys = "sparc/input0"; | ||
28 | static struct input_dev sparcspkr_dev; | ||
29 | |||
30 | DEFINE_SPINLOCK(beep_lock); | ||
31 | |||
32 | static void __init init_sparcspkr_struct(void) | ||
33 | { | ||
34 | sparcspkr_dev.evbit[0] = BIT(EV_SND); | ||
35 | sparcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); | ||
36 | |||
37 | sparcspkr_dev.phys = sparcspkr_phys; | ||
38 | sparcspkr_dev.id.bustype = BUS_ISA; | ||
39 | sparcspkr_dev.id.vendor = 0x001f; | ||
40 | sparcspkr_dev.id.product = 0x0001; | ||
41 | sparcspkr_dev.id.version = 0x0100; | ||
42 | } | ||
43 | |||
44 | static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
45 | { | ||
46 | unsigned int count = 0; | ||
47 | unsigned long flags; | ||
48 | |||
49 | if (type != EV_SND) | ||
50 | return -1; | ||
51 | |||
52 | switch (code) { | ||
53 | case SND_BELL: if (value) value = 1000; | ||
54 | case SND_TONE: break; | ||
55 | default: return -1; | ||
56 | } | ||
57 | |||
58 | if (value > 20 && value < 32767) | ||
59 | count = 1193182 / value; | ||
60 | |||
61 | spin_lock_irqsave(&beep_lock, flags); | ||
62 | |||
63 | /* EBUS speaker only has on/off state, the frequency does not | ||
64 | * appear to be programmable. | ||
65 | */ | ||
66 | if (count) { | ||
67 | if (beep_iobase & 0x2UL) | ||
68 | outb(1, beep_iobase); | ||
69 | else | ||
70 | outl(1, beep_iobase); | ||
71 | } else { | ||
72 | if (beep_iobase & 0x2UL) | ||
73 | outb(0, beep_iobase); | ||
74 | else | ||
75 | outl(0, beep_iobase); | ||
76 | } | ||
77 | |||
78 | spin_unlock_irqrestore(&beep_lock, flags); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int __init init_ebus_beep(struct linux_ebus_device *edev) | ||
84 | { | ||
85 | beep_iobase = edev->resource[0].start; | ||
86 | |||
87 | init_sparcspkr_struct(); | ||
88 | |||
89 | sparcspkr_dev.name = sparcspkr_ebus_name; | ||
90 | sparcspkr_dev.event = ebus_spkr_event; | ||
91 | |||
92 | input_register_device(&sparcspkr_dev); | ||
93 | |||
94 | printk(KERN_INFO "input: %s\n", sparcspkr_ebus_name); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | #ifdef CONFIG_SPARC64 | ||
99 | static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
100 | { | ||
101 | unsigned int count = 0; | ||
102 | unsigned long flags; | ||
103 | |||
104 | if (type != EV_SND) | ||
105 | return -1; | ||
106 | |||
107 | switch (code) { | ||
108 | case SND_BELL: if (value) value = 1000; | ||
109 | case SND_TONE: break; | ||
110 | default: return -1; | ||
111 | } | ||
112 | |||
113 | if (value > 20 && value < 32767) | ||
114 | count = 1193182 / value; | ||
115 | |||
116 | spin_lock_irqsave(&beep_lock, flags); | ||
117 | |||
118 | if (count) { | ||
119 | /* enable counter 2 */ | ||
120 | outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61); | ||
121 | /* set command for counter 2, 2 byte write */ | ||
122 | outb(0xB6, beep_iobase + 0x43); | ||
123 | /* select desired HZ */ | ||
124 | outb(count & 0xff, beep_iobase + 0x42); | ||
125 | outb((count >> 8) & 0xff, beep_iobase + 0x42); | ||
126 | } else { | ||
127 | /* disable counter 2 */ | ||
128 | outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61); | ||
129 | } | ||
130 | |||
131 | spin_unlock_irqrestore(&beep_lock, flags); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int __init init_isa_beep(struct sparc_isa_device *isa_dev) | ||
137 | { | ||
138 | beep_iobase = isa_dev->resource.start; | ||
139 | |||
140 | init_sparcspkr_struct(); | ||
141 | |||
142 | sparcspkr_dev.name = sparcspkr_isa_name; | ||
143 | sparcspkr_dev.event = isa_spkr_event; | ||
144 | sparcspkr_dev.id.bustype = BUS_ISA; | ||
145 | |||
146 | input_register_device(&sparcspkr_dev); | ||
147 | |||
148 | printk(KERN_INFO "input: %s\n", sparcspkr_isa_name); | ||
149 | return 0; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | static int __init sparcspkr_init(void) | ||
154 | { | ||
155 | struct linux_ebus *ebus; | ||
156 | struct linux_ebus_device *edev = NULL; | ||
157 | #ifdef CONFIG_SPARC64 | ||
158 | struct sparc_isa_bridge *isa_br; | ||
159 | struct sparc_isa_device *isa_dev; | ||
160 | #endif | ||
161 | |||
162 | for_each_ebus(ebus) { | ||
163 | for_each_ebusdev(edev, ebus) { | ||
164 | if (!strcmp(edev->prom_name, "beep")) | ||
165 | return init_ebus_beep(edev); | ||
166 | } | ||
167 | } | ||
168 | #ifdef CONFIG_SPARC64 | ||
169 | for_each_isa(isa_br) { | ||
170 | for_each_isadev(isa_dev, isa_br) { | ||
171 | /* A hack, the beep device's base lives in | ||
172 | * the DMA isa node. | ||
173 | */ | ||
174 | if (!strcmp(isa_dev->prom_name, "dma")) | ||
175 | return init_isa_beep(isa_dev); | ||
176 | } | ||
177 | } | ||
178 | #endif | ||
179 | |||
180 | return -ENODEV; | ||
181 | } | ||
182 | |||
183 | static void __exit sparcspkr_exit(void) | ||
184 | { | ||
185 | input_unregister_device(&sparcspkr_dev); | ||
186 | } | ||
187 | |||
188 | module_init(sparcspkr_init); | ||
189 | module_exit(sparcspkr_exit); | ||
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c new file mode 100644 index 000000000000..158c8e845ff9 --- /dev/null +++ b/drivers/input/misc/uinput.c | |||
@@ -0,0 +1,620 @@ | |||
1 | /* | ||
2 | * User level driver support for input subsystem | ||
3 | * | ||
4 | * Heavily based on evdev.c by Vojtech Pavlik | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> | ||
21 | * | ||
22 | * Changes/Revisions: | ||
23 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) | ||
24 | * - added force feedback support | ||
25 | * - added UI_SET_PHYS | ||
26 | * 0.1 20/06/2002 | ||
27 | * - first public version | ||
28 | */ | ||
29 | #include <linux/poll.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/input.h> | ||
34 | #include <linux/smp_lock.h> | ||
35 | #include <linux/fs.h> | ||
36 | #include <linux/miscdevice.h> | ||
37 | #include <linux/uinput.h> | ||
38 | |||
39 | static int uinput_dev_open(struct input_dev *dev) | ||
40 | { | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static void uinput_dev_close(struct input_dev *dev) | ||
45 | { | ||
46 | |||
47 | } | ||
48 | |||
49 | static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
50 | { | ||
51 | struct uinput_device *udev; | ||
52 | |||
53 | udev = dev->private; | ||
54 | |||
55 | udev->buff[udev->head].type = type; | ||
56 | udev->buff[udev->head].code = code; | ||
57 | udev->buff[udev->head].value = value; | ||
58 | do_gettimeofday(&udev->buff[udev->head].time); | ||
59 | udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; | ||
60 | |||
61 | wake_up_interruptible(&udev->waitq); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request) | ||
67 | { | ||
68 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ | ||
69 | struct uinput_device *udev = dev->private; | ||
70 | int id; | ||
71 | |||
72 | down(&udev->requests_sem); | ||
73 | for (id=0; id<UINPUT_NUM_REQUESTS; id++) | ||
74 | if (!udev->requests[id]) { | ||
75 | udev->requests[id] = request; | ||
76 | request->id = id; | ||
77 | up(&udev->requests_sem); | ||
78 | return 0; | ||
79 | } | ||
80 | up(&udev->requests_sem); | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id) | ||
85 | { | ||
86 | /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ | ||
87 | if (id >= UINPUT_NUM_REQUESTS || id < 0) | ||
88 | return NULL; | ||
89 | if (udev->requests[id]->completed) | ||
90 | return NULL; | ||
91 | return udev->requests[id]; | ||
92 | } | ||
93 | |||
94 | static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code) | ||
95 | { | ||
96 | struct uinput_device *udev = dev->private; | ||
97 | |||
98 | memset(request, 0, sizeof(struct uinput_request)); | ||
99 | request->code = code; | ||
100 | init_waitqueue_head(&request->waitq); | ||
101 | |||
102 | /* Allocate an ID. If none are available right away, wait. */ | ||
103 | request->retval = wait_event_interruptible(udev->requests_waitq, | ||
104 | !uinput_request_alloc_id(dev, request)); | ||
105 | } | ||
106 | |||
107 | static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request) | ||
108 | { | ||
109 | struct uinput_device *udev = dev->private; | ||
110 | int retval; | ||
111 | |||
112 | /* Tell our userspace app about this new request by queueing an input event */ | ||
113 | uinput_dev_event(dev, EV_UINPUT, request->code, request->id); | ||
114 | |||
115 | /* Wait for the request to complete */ | ||
116 | retval = wait_event_interruptible(request->waitq, request->completed); | ||
117 | if (retval) | ||
118 | request->retval = retval; | ||
119 | |||
120 | /* Release this request's ID, let others know it's available */ | ||
121 | udev->requests[request->id] = NULL; | ||
122 | wake_up_interruptible(&udev->requests_waitq); | ||
123 | } | ||
124 | |||
125 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) | ||
126 | { | ||
127 | struct uinput_request request; | ||
128 | |||
129 | if (!test_bit(EV_FF, dev->evbit)) | ||
130 | return -ENOSYS; | ||
131 | |||
132 | uinput_request_init(dev, &request, UI_FF_UPLOAD); | ||
133 | if (request.retval) | ||
134 | return request.retval; | ||
135 | request.u.effect = effect; | ||
136 | uinput_request_submit(dev, &request); | ||
137 | return request.retval; | ||
138 | } | ||
139 | |||
140 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) | ||
141 | { | ||
142 | struct uinput_request request; | ||
143 | |||
144 | if (!test_bit(EV_FF, dev->evbit)) | ||
145 | return -ENOSYS; | ||
146 | |||
147 | uinput_request_init(dev, &request, UI_FF_ERASE); | ||
148 | if (request.retval) | ||
149 | return request.retval; | ||
150 | request.u.effect_id = effect_id; | ||
151 | uinput_request_submit(dev, &request); | ||
152 | return request.retval; | ||
153 | } | ||
154 | |||
155 | static int uinput_create_device(struct uinput_device *udev) | ||
156 | { | ||
157 | if (!udev->dev->name) { | ||
158 | printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | udev->dev->open = uinput_dev_open; | ||
163 | udev->dev->close = uinput_dev_close; | ||
164 | udev->dev->event = uinput_dev_event; | ||
165 | udev->dev->upload_effect = uinput_dev_upload_effect; | ||
166 | udev->dev->erase_effect = uinput_dev_erase_effect; | ||
167 | udev->dev->private = udev; | ||
168 | |||
169 | init_waitqueue_head(&(udev->waitq)); | ||
170 | |||
171 | input_register_device(udev->dev); | ||
172 | |||
173 | set_bit(UIST_CREATED, &(udev->state)); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int uinput_destroy_device(struct uinput_device *udev) | ||
179 | { | ||
180 | if (!test_bit(UIST_CREATED, &(udev->state))) { | ||
181 | printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | |||
185 | input_unregister_device(udev->dev); | ||
186 | |||
187 | clear_bit(UIST_CREATED, &(udev->state)); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int uinput_open(struct inode *inode, struct file *file) | ||
193 | { | ||
194 | struct uinput_device *newdev; | ||
195 | struct input_dev *newinput; | ||
196 | |||
197 | newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL); | ||
198 | if (!newdev) | ||
199 | goto error; | ||
200 | memset(newdev, 0, sizeof(struct uinput_device)); | ||
201 | init_MUTEX(&newdev->requests_sem); | ||
202 | init_waitqueue_head(&newdev->requests_waitq); | ||
203 | |||
204 | newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); | ||
205 | if (!newinput) | ||
206 | goto cleanup; | ||
207 | memset(newinput, 0, sizeof(struct input_dev)); | ||
208 | |||
209 | newdev->dev = newinput; | ||
210 | |||
211 | file->private_data = newdev; | ||
212 | |||
213 | return 0; | ||
214 | cleanup: | ||
215 | kfree(newdev); | ||
216 | error: | ||
217 | return -ENOMEM; | ||
218 | } | ||
219 | |||
220 | static int uinput_validate_absbits(struct input_dev *dev) | ||
221 | { | ||
222 | unsigned int cnt; | ||
223 | int retval = 0; | ||
224 | |||
225 | for (cnt = 0; cnt < ABS_MAX + 1; cnt++) { | ||
226 | if (!test_bit(cnt, dev->absbit)) | ||
227 | continue; | ||
228 | |||
229 | if ((dev->absmax[cnt] <= dev->absmin[cnt])) { | ||
230 | printk(KERN_DEBUG | ||
231 | "%s: invalid abs[%02x] min:%d max:%d\n", | ||
232 | UINPUT_NAME, cnt, | ||
233 | dev->absmin[cnt], dev->absmax[cnt]); | ||
234 | retval = -EINVAL; | ||
235 | break; | ||
236 | } | ||
237 | |||
238 | if (dev->absflat[cnt] > (dev->absmax[cnt] - dev->absmin[cnt])) { | ||
239 | printk(KERN_DEBUG | ||
240 | "%s: absflat[%02x] out of range: %d " | ||
241 | "(min:%d/max:%d)\n", | ||
242 | UINPUT_NAME, cnt, dev->absflat[cnt], | ||
243 | dev->absmin[cnt], dev->absmax[cnt]); | ||
244 | retval = -EINVAL; | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | return retval; | ||
249 | } | ||
250 | |||
251 | static int uinput_alloc_device(struct file *file, const char __user *buffer, size_t count) | ||
252 | { | ||
253 | struct uinput_user_dev *user_dev; | ||
254 | struct input_dev *dev; | ||
255 | struct uinput_device *udev; | ||
256 | int size, | ||
257 | retval; | ||
258 | |||
259 | retval = count; | ||
260 | |||
261 | udev = file->private_data; | ||
262 | dev = udev->dev; | ||
263 | |||
264 | user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL); | ||
265 | if (!user_dev) { | ||
266 | retval = -ENOMEM; | ||
267 | goto exit; | ||
268 | } | ||
269 | |||
270 | if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { | ||
271 | retval = -EFAULT; | ||
272 | goto exit; | ||
273 | } | ||
274 | |||
275 | if (NULL != dev->name) | ||
276 | kfree(dev->name); | ||
277 | |||
278 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; | ||
279 | dev->name = kmalloc(size, GFP_KERNEL); | ||
280 | if (!dev->name) { | ||
281 | retval = -ENOMEM; | ||
282 | goto exit; | ||
283 | } | ||
284 | |||
285 | strlcpy(dev->name, user_dev->name, size); | ||
286 | dev->id.bustype = user_dev->id.bustype; | ||
287 | dev->id.vendor = user_dev->id.vendor; | ||
288 | dev->id.product = user_dev->id.product; | ||
289 | dev->id.version = user_dev->id.version; | ||
290 | dev->ff_effects_max = user_dev->ff_effects_max; | ||
291 | |||
292 | size = sizeof(int) * (ABS_MAX + 1); | ||
293 | memcpy(dev->absmax, user_dev->absmax, size); | ||
294 | memcpy(dev->absmin, user_dev->absmin, size); | ||
295 | memcpy(dev->absfuzz, user_dev->absfuzz, size); | ||
296 | memcpy(dev->absflat, user_dev->absflat, size); | ||
297 | |||
298 | /* check if absmin/absmax/absfuzz/absflat are filled as | ||
299 | * told in Documentation/input/input-programming.txt */ | ||
300 | if (test_bit(EV_ABS, dev->evbit)) { | ||
301 | retval = uinput_validate_absbits(dev); | ||
302 | if (retval < 0) | ||
303 | kfree(dev->name); | ||
304 | } | ||
305 | |||
306 | exit: | ||
307 | kfree(user_dev); | ||
308 | return retval; | ||
309 | } | ||
310 | |||
311 | static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | ||
312 | { | ||
313 | struct uinput_device *udev = file->private_data; | ||
314 | |||
315 | if (test_bit(UIST_CREATED, &(udev->state))) { | ||
316 | struct input_event ev; | ||
317 | |||
318 | if (copy_from_user(&ev, buffer, sizeof(struct input_event))) | ||
319 | return -EFAULT; | ||
320 | input_event(udev->dev, ev.type, ev.code, ev.value); | ||
321 | } | ||
322 | else | ||
323 | count = uinput_alloc_device(file, buffer, count); | ||
324 | |||
325 | return count; | ||
326 | } | ||
327 | |||
328 | static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | ||
329 | { | ||
330 | struct uinput_device *udev = file->private_data; | ||
331 | int retval = 0; | ||
332 | |||
333 | if (!test_bit(UIST_CREATED, &(udev->state))) | ||
334 | return -ENODEV; | ||
335 | |||
336 | if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK)) | ||
337 | return -EAGAIN; | ||
338 | |||
339 | retval = wait_event_interruptible(udev->waitq, | ||
340 | (udev->head != udev->tail) || | ||
341 | !test_bit(UIST_CREATED, &(udev->state))); | ||
342 | |||
343 | if (retval) | ||
344 | return retval; | ||
345 | |||
346 | if (!test_bit(UIST_CREATED, &(udev->state))) | ||
347 | return -ENODEV; | ||
348 | |||
349 | while ((udev->head != udev->tail) && | ||
350 | (retval + sizeof(struct input_event) <= count)) { | ||
351 | if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]), | ||
352 | sizeof(struct input_event))) return -EFAULT; | ||
353 | udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; | ||
354 | retval += sizeof(struct input_event); | ||
355 | } | ||
356 | |||
357 | return retval; | ||
358 | } | ||
359 | |||
360 | static unsigned int uinput_poll(struct file *file, poll_table *wait) | ||
361 | { | ||
362 | struct uinput_device *udev = file->private_data; | ||
363 | |||
364 | poll_wait(file, &udev->waitq, wait); | ||
365 | |||
366 | if (udev->head != udev->tail) | ||
367 | return POLLIN | POLLRDNORM; | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int uinput_burn_device(struct uinput_device *udev) | ||
373 | { | ||
374 | if (test_bit(UIST_CREATED, &(udev->state))) | ||
375 | uinput_destroy_device(udev); | ||
376 | |||
377 | if (NULL != udev->dev->name) | ||
378 | kfree(udev->dev->name); | ||
379 | if (NULL != udev->dev->phys) | ||
380 | kfree(udev->dev->phys); | ||
381 | |||
382 | kfree(udev->dev); | ||
383 | kfree(udev); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int uinput_close(struct inode *inode, struct file *file) | ||
389 | { | ||
390 | return uinput_burn_device(file->private_data); | ||
391 | } | ||
392 | |||
393 | static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
394 | { | ||
395 | int retval = 0; | ||
396 | struct uinput_device *udev; | ||
397 | void __user *p = (void __user *)arg; | ||
398 | struct uinput_ff_upload ff_up; | ||
399 | struct uinput_ff_erase ff_erase; | ||
400 | struct uinput_request *req; | ||
401 | int length; | ||
402 | |||
403 | udev = file->private_data; | ||
404 | |||
405 | /* device attributes can not be changed after the device is created */ | ||
406 | switch (cmd) { | ||
407 | case UI_SET_EVBIT: | ||
408 | case UI_SET_KEYBIT: | ||
409 | case UI_SET_RELBIT: | ||
410 | case UI_SET_ABSBIT: | ||
411 | case UI_SET_MSCBIT: | ||
412 | case UI_SET_LEDBIT: | ||
413 | case UI_SET_SNDBIT: | ||
414 | case UI_SET_FFBIT: | ||
415 | case UI_SET_PHYS: | ||
416 | if (test_bit(UIST_CREATED, &(udev->state))) | ||
417 | return -EINVAL; | ||
418 | } | ||
419 | |||
420 | switch (cmd) { | ||
421 | case UI_DEV_CREATE: | ||
422 | retval = uinput_create_device(udev); | ||
423 | break; | ||
424 | |||
425 | case UI_DEV_DESTROY: | ||
426 | retval = uinput_destroy_device(udev); | ||
427 | break; | ||
428 | |||
429 | case UI_SET_EVBIT: | ||
430 | if (arg > EV_MAX) { | ||
431 | retval = -EINVAL; | ||
432 | break; | ||
433 | } | ||
434 | set_bit(arg, udev->dev->evbit); | ||
435 | break; | ||
436 | |||
437 | case UI_SET_KEYBIT: | ||
438 | if (arg > KEY_MAX) { | ||
439 | retval = -EINVAL; | ||
440 | break; | ||
441 | } | ||
442 | set_bit(arg, udev->dev->keybit); | ||
443 | break; | ||
444 | |||
445 | case UI_SET_RELBIT: | ||
446 | if (arg > REL_MAX) { | ||
447 | retval = -EINVAL; | ||
448 | break; | ||
449 | } | ||
450 | set_bit(arg, udev->dev->relbit); | ||
451 | break; | ||
452 | |||
453 | case UI_SET_ABSBIT: | ||
454 | if (arg > ABS_MAX) { | ||
455 | retval = -EINVAL; | ||
456 | break; | ||
457 | } | ||
458 | set_bit(arg, udev->dev->absbit); | ||
459 | break; | ||
460 | |||
461 | case UI_SET_MSCBIT: | ||
462 | if (arg > MSC_MAX) { | ||
463 | retval = -EINVAL; | ||
464 | break; | ||
465 | } | ||
466 | set_bit(arg, udev->dev->mscbit); | ||
467 | break; | ||
468 | |||
469 | case UI_SET_LEDBIT: | ||
470 | if (arg > LED_MAX) { | ||
471 | retval = -EINVAL; | ||
472 | break; | ||
473 | } | ||
474 | set_bit(arg, udev->dev->ledbit); | ||
475 | break; | ||
476 | |||
477 | case UI_SET_SNDBIT: | ||
478 | if (arg > SND_MAX) { | ||
479 | retval = -EINVAL; | ||
480 | break; | ||
481 | } | ||
482 | set_bit(arg, udev->dev->sndbit); | ||
483 | break; | ||
484 | |||
485 | case UI_SET_FFBIT: | ||
486 | if (arg > FF_MAX) { | ||
487 | retval = -EINVAL; | ||
488 | break; | ||
489 | } | ||
490 | set_bit(arg, udev->dev->ffbit); | ||
491 | break; | ||
492 | |||
493 | case UI_SET_PHYS: | ||
494 | length = strnlen_user(p, 1024); | ||
495 | if (length <= 0) { | ||
496 | retval = -EFAULT; | ||
497 | break; | ||
498 | } | ||
499 | if (NULL != udev->dev->phys) | ||
500 | kfree(udev->dev->phys); | ||
501 | udev->dev->phys = kmalloc(length, GFP_KERNEL); | ||
502 | if (!udev->dev->phys) { | ||
503 | retval = -ENOMEM; | ||
504 | break; | ||
505 | } | ||
506 | if (copy_from_user(udev->dev->phys, p, length)) { | ||
507 | retval = -EFAULT; | ||
508 | kfree(udev->dev->phys); | ||
509 | udev->dev->phys = NULL; | ||
510 | break; | ||
511 | } | ||
512 | udev->dev->phys[length-1] = '\0'; | ||
513 | break; | ||
514 | |||
515 | case UI_BEGIN_FF_UPLOAD: | ||
516 | if (copy_from_user(&ff_up, p, sizeof(ff_up))) { | ||
517 | retval = -EFAULT; | ||
518 | break; | ||
519 | } | ||
520 | req = uinput_request_find(udev, ff_up.request_id); | ||
521 | if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) { | ||
522 | retval = -EINVAL; | ||
523 | break; | ||
524 | } | ||
525 | ff_up.retval = 0; | ||
526 | memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect)); | ||
527 | if (copy_to_user(p, &ff_up, sizeof(ff_up))) { | ||
528 | retval = -EFAULT; | ||
529 | break; | ||
530 | } | ||
531 | break; | ||
532 | |||
533 | case UI_BEGIN_FF_ERASE: | ||
534 | if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { | ||
535 | retval = -EFAULT; | ||
536 | break; | ||
537 | } | ||
538 | req = uinput_request_find(udev, ff_erase.request_id); | ||
539 | if (!(req && req->code==UI_FF_ERASE)) { | ||
540 | retval = -EINVAL; | ||
541 | break; | ||
542 | } | ||
543 | ff_erase.retval = 0; | ||
544 | ff_erase.effect_id = req->u.effect_id; | ||
545 | if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { | ||
546 | retval = -EFAULT; | ||
547 | break; | ||
548 | } | ||
549 | break; | ||
550 | |||
551 | case UI_END_FF_UPLOAD: | ||
552 | if (copy_from_user(&ff_up, p, sizeof(ff_up))) { | ||
553 | retval = -EFAULT; | ||
554 | break; | ||
555 | } | ||
556 | req = uinput_request_find(udev, ff_up.request_id); | ||
557 | if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) { | ||
558 | retval = -EINVAL; | ||
559 | break; | ||
560 | } | ||
561 | req->retval = ff_up.retval; | ||
562 | memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); | ||
563 | req->completed = 1; | ||
564 | wake_up_interruptible(&req->waitq); | ||
565 | break; | ||
566 | |||
567 | case UI_END_FF_ERASE: | ||
568 | if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { | ||
569 | retval = -EFAULT; | ||
570 | break; | ||
571 | } | ||
572 | req = uinput_request_find(udev, ff_erase.request_id); | ||
573 | if (!(req && req->code==UI_FF_ERASE)) { | ||
574 | retval = -EINVAL; | ||
575 | break; | ||
576 | } | ||
577 | req->retval = ff_erase.retval; | ||
578 | req->completed = 1; | ||
579 | wake_up_interruptible(&req->waitq); | ||
580 | break; | ||
581 | |||
582 | default: | ||
583 | retval = -EINVAL; | ||
584 | } | ||
585 | return retval; | ||
586 | } | ||
587 | |||
588 | static struct file_operations uinput_fops = { | ||
589 | .owner = THIS_MODULE, | ||
590 | .open = uinput_open, | ||
591 | .release = uinput_close, | ||
592 | .read = uinput_read, | ||
593 | .write = uinput_write, | ||
594 | .poll = uinput_poll, | ||
595 | .ioctl = uinput_ioctl, | ||
596 | }; | ||
597 | |||
598 | static struct miscdevice uinput_misc = { | ||
599 | .fops = &uinput_fops, | ||
600 | .minor = UINPUT_MINOR, | ||
601 | .name = UINPUT_NAME, | ||
602 | }; | ||
603 | |||
604 | static int __init uinput_init(void) | ||
605 | { | ||
606 | return misc_register(&uinput_misc); | ||
607 | } | ||
608 | |||
609 | static void __exit uinput_exit(void) | ||
610 | { | ||
611 | misc_deregister(&uinput_misc); | ||
612 | } | ||
613 | |||
614 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); | ||
615 | MODULE_DESCRIPTION("User level driver support for input subsystem"); | ||
616 | MODULE_LICENSE("GPL"); | ||
617 | |||
618 | module_init(uinput_init); | ||
619 | module_exit(uinput_exit); | ||
620 | |||
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig new file mode 100644 index 000000000000..537154dd7a87 --- /dev/null +++ b/drivers/input/mouse/Kconfig | |||
@@ -0,0 +1,138 @@ | |||
1 | # | ||
2 | # Mouse driver configuration | ||
3 | # | ||
4 | menuconfig INPUT_MOUSE | ||
5 | bool "Mouse" | ||
6 | default y | ||
7 | help | ||
8 | Say Y here, and a list of supported mice will be displayed. | ||
9 | This option doesn't affect the kernel. | ||
10 | |||
11 | If unsure, say Y. | ||
12 | |||
13 | if INPUT_MOUSE | ||
14 | |||
15 | config MOUSE_PS2 | ||
16 | tristate "PS/2 mouse" | ||
17 | default y | ||
18 | select SERIO | ||
19 | select SERIO_LIBPS2 | ||
20 | select SERIO_I8042 if PC | ||
21 | select SERIO_GSCPS2 if GSC | ||
22 | ---help--- | ||
23 | Say Y here if you have a PS/2 mouse connected to your system. This | ||
24 | includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 | ||
25 | mice with wheels and extra buttons, Microsoft, Logitech or Genius | ||
26 | compatible. | ||
27 | |||
28 | Synaptics TouchPad users might be interested in a specialized | ||
29 | XFree86 driver at: | ||
30 | <http://w1.894.telia.com/~u89404340/touchpad/index.html> | ||
31 | and a new version of GPM at: | ||
32 | <http://www.geocities.com/dt_or/gpm/gpm.html> | ||
33 | to take advantage of the advanced features of the touchpad. | ||
34 | |||
35 | If unsure, say Y. | ||
36 | |||
37 | To compile this driver as a module, choose M here: the | ||
38 | module will be called psmouse. | ||
39 | |||
40 | config MOUSE_SERIAL | ||
41 | tristate "Serial mouse" | ||
42 | select SERIO | ||
43 | ---help--- | ||
44 | Say Y here if you have a serial (RS-232, COM port) mouse connected | ||
45 | to your system. This includes Sun, MouseSystems, Microsoft, | ||
46 | Logitech and all other compatible serial mice. | ||
47 | |||
48 | If unsure, say N. | ||
49 | |||
50 | To compile this driver as a module, choose M here: the | ||
51 | module will be called sermouse. | ||
52 | |||
53 | config MOUSE_INPORT | ||
54 | tristate "InPort/MS/ATIXL busmouse" | ||
55 | depends on ISA | ||
56 | help | ||
57 | Say Y here if you have an InPort, Microsoft or ATI XL busmouse. | ||
58 | They are rather rare these days. | ||
59 | |||
60 | To compile this driver as a module, choose M here: the | ||
61 | module will be called inport. | ||
62 | |||
63 | config MOUSE_ATIXL | ||
64 | bool "ATI XL variant" | ||
65 | depends on MOUSE_INPORT | ||
66 | help | ||
67 | Say Y here if your mouse is of the ATI XL variety. | ||
68 | |||
69 | config MOUSE_LOGIBM | ||
70 | tristate "Logitech busmouse" | ||
71 | depends on ISA | ||
72 | help | ||
73 | Say Y here if you have a Logitech busmouse. | ||
74 | They are rather rare these days. | ||
75 | |||
76 | To compile this driver as a module, choose M here: the | ||
77 | module will be called logibm. | ||
78 | |||
79 | config MOUSE_PC110PAD | ||
80 | tristate "IBM PC110 touchpad" | ||
81 | depends on ISA | ||
82 | help | ||
83 | Say Y if you have the IBM PC-110 micro-notebook and want its | ||
84 | touchpad supported. | ||
85 | |||
86 | To compile this driver as a module, choose M here: the | ||
87 | module will be called pc110pad. | ||
88 | |||
89 | config MOUSE_MAPLE | ||
90 | tristate "Maple bus mouse" | ||
91 | depends on SH_DREAMCAST && MAPLE | ||
92 | help | ||
93 | Say Y if you have a DreamCast console and a mouse attached to | ||
94 | its Maple bus. | ||
95 | |||
96 | To compile this driver as a module, choose M here: the | ||
97 | module will be called maplemouse. | ||
98 | |||
99 | config MOUSE_AMIGA | ||
100 | tristate "Amiga mouse" | ||
101 | depends on AMIGA | ||
102 | help | ||
103 | Say Y here if you have an Amiga and want its native mouse | ||
104 | supported by the kernel. | ||
105 | |||
106 | To compile this driver as a module, choose M here: the | ||
107 | module will be called amimouse. | ||
108 | |||
109 | config MOUSE_RISCPC | ||
110 | tristate "Acorn RiscPC mouse" | ||
111 | depends on ARCH_ACORN | ||
112 | help | ||
113 | Say Y here if you have the Acorn RiscPC computer and want its | ||
114 | native mouse supported. | ||
115 | |||
116 | To compile this driver as a module, choose M here: the | ||
117 | module will be called rpcmouse. | ||
118 | |||
119 | config MOUSE_VSXXXAA | ||
120 | tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet" | ||
121 | select SERIO | ||
122 | help | ||
123 | Say Y (or M) if you want to use a DEC VSXXX-AA (hockey | ||
124 | puck) or a VSXXX-GA (rectangular) mouse. Theses mice are | ||
125 | typically used on DECstations or VAXstations, but can also | ||
126 | be used on any box capable of RS232 (with some adaptor | ||
127 | described in the source file). This driver also works with the | ||
128 | digitizer (VSXXX-AB) DEC produced. | ||
129 | |||
130 | config MOUSE_HIL | ||
131 | tristate "HIL pointers (mice etc)." | ||
132 | depends on GSC | ||
133 | select HP_SDC | ||
134 | select HIL_MLC | ||
135 | help | ||
136 | Say Y here to support HIL pointers. | ||
137 | |||
138 | endif | ||
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile new file mode 100644 index 000000000000..a7864195806a --- /dev/null +++ b/drivers/input/mouse/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | # | ||
2 | # Makefile for the mouse drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o | ||
8 | obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o | ||
9 | obj-$(CONFIG_MOUSE_INPORT) += inport.o | ||
10 | obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o | ||
11 | obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o | ||
12 | obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o | ||
13 | obj-$(CONFIG_MOUSE_PS2) += psmouse.o | ||
14 | obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o | ||
15 | obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o | ||
16 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o | ||
17 | |||
18 | psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o | ||
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c new file mode 100644 index 000000000000..1f85a9718c89 --- /dev/null +++ b/drivers/input/mouse/alps.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * ALPS touchpad PS/2 mouse driver | ||
3 | * | ||
4 | * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au> | ||
5 | * Copyright (c) 2003 Peter Osterlund <petero2@telia.com> | ||
6 | * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> | ||
7 | * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> | ||
8 | * | ||
9 | * ALPS detection, tap switching and status querying info is taken from | ||
10 | * tpconfig utility (by C. Scott Ananian and Bruce Kall). | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License version 2 as published by | ||
14 | * the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/input.h> | ||
18 | #include <linux/serio.h> | ||
19 | #include <linux/libps2.h> | ||
20 | |||
21 | #include "psmouse.h" | ||
22 | #include "alps.h" | ||
23 | |||
24 | #undef DEBUG | ||
25 | #ifdef DEBUG | ||
26 | #define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg) | ||
27 | #else | ||
28 | #define dbg(format, arg...) do {} while (0) | ||
29 | #endif | ||
30 | |||
31 | #define ALPS_DUALPOINT 0x01 | ||
32 | #define ALPS_WHEEL 0x02 | ||
33 | #define ALPS_FW_BK 0x04 | ||
34 | #define ALPS_4BTN 0x08 | ||
35 | #define ALPS_OLDPROTO 0x10 | ||
36 | #define ALPS_PASS 0x20 | ||
37 | |||
38 | static struct alps_model_info alps_model_data[] = { | ||
39 | { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ | ||
40 | { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, | ||
41 | { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, | ||
42 | { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, | ||
43 | { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, | ||
44 | { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 }, | ||
45 | { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ | ||
46 | { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK }, /* NEC Versa L320 */ | ||
47 | { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, | ||
48 | { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ | ||
49 | { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, | ||
50 | { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, | ||
51 | { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ | ||
52 | { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, | ||
53 | { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * XXX - this entry is suspicious. First byte has zero lower nibble, | ||
58 | * which is what a normal mouse would report. Also, the value 0x0e | ||
59 | * isn't valid per PS/2 spec. | ||
60 | */ | ||
61 | |||
62 | /* | ||
63 | * ALPS abolute Mode - new format | ||
64 | * | ||
65 | * byte 0: 1 ? ? ? 1 ? ? ? | ||
66 | * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 | ||
67 | * byte 2: 0 x10 x9 x8 x7 ? fin ges | ||
68 | * byte 3: 0 y9 y8 y7 1 M R L | ||
69 | * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 | ||
70 | * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 | ||
71 | * | ||
72 | * ?'s can have different meanings on different models, | ||
73 | * such as wheel rotation, extra buttons, stick buttons | ||
74 | * on a dualpoint, etc. | ||
75 | */ | ||
76 | |||
77 | static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) | ||
78 | { | ||
79 | struct alps_data *priv = psmouse->private; | ||
80 | unsigned char *packet = psmouse->packet; | ||
81 | struct input_dev *dev = &psmouse->dev; | ||
82 | struct input_dev *dev2 = &priv->dev2; | ||
83 | int x, y, z, ges, fin, left, right, middle; | ||
84 | |||
85 | input_regs(dev, regs); | ||
86 | |||
87 | if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ | ||
88 | input_report_key(dev2, BTN_LEFT, packet[0] & 1); | ||
89 | input_report_key(dev2, BTN_RIGHT, packet[0] & 2); | ||
90 | input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); | ||
91 | input_report_rel(dev2, REL_X, | ||
92 | packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); | ||
93 | input_report_rel(dev2, REL_Y, | ||
94 | packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); | ||
95 | input_sync(dev2); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | if (priv->i->flags & ALPS_OLDPROTO) { | ||
100 | left = packet[2] & 0x08; | ||
101 | right = packet[2] & 0x10; | ||
102 | middle = 0; | ||
103 | x = packet[1] | ((packet[0] & 0x07) << 7); | ||
104 | y = packet[4] | ((packet[3] & 0x07) << 7); | ||
105 | z = packet[5]; | ||
106 | } else { | ||
107 | left = packet[3] & 1; | ||
108 | right = packet[3] & 2; | ||
109 | middle = packet[3] & 4; | ||
110 | x = packet[1] | ((packet[2] & 0x78) << (7 - 3)); | ||
111 | y = packet[4] | ((packet[3] & 0x70) << (7 - 4)); | ||
112 | z = packet[5]; | ||
113 | } | ||
114 | |||
115 | ges = packet[2] & 1; | ||
116 | fin = packet[2] & 2; | ||
117 | |||
118 | input_report_key(dev, BTN_LEFT, left); | ||
119 | input_report_key(dev, BTN_RIGHT, right); | ||
120 | input_report_key(dev, BTN_MIDDLE, middle); | ||
121 | |||
122 | if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) { | ||
123 | input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); | ||
124 | input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); | ||
125 | input_sync(dev); | ||
126 | input_sync(dev2); | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | /* Convert hardware tap to a reasonable Z value */ | ||
131 | if (ges && !fin) z = 40; | ||
132 | |||
133 | /* | ||
134 | * A "tap and drag" operation is reported by the hardware as a transition | ||
135 | * from (!fin && ges) to (fin && ges). This should be translated to the | ||
136 | * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually. | ||
137 | */ | ||
138 | if (ges && fin && !priv->prev_fin) { | ||
139 | input_report_abs(dev, ABS_X, x); | ||
140 | input_report_abs(dev, ABS_Y, y); | ||
141 | input_report_abs(dev, ABS_PRESSURE, 0); | ||
142 | input_report_key(dev, BTN_TOOL_FINGER, 0); | ||
143 | input_sync(dev); | ||
144 | } | ||
145 | priv->prev_fin = fin; | ||
146 | |||
147 | if (z > 30) input_report_key(dev, BTN_TOUCH, 1); | ||
148 | if (z < 25) input_report_key(dev, BTN_TOUCH, 0); | ||
149 | |||
150 | if (z > 0) { | ||
151 | input_report_abs(dev, ABS_X, x); | ||
152 | input_report_abs(dev, ABS_Y, y); | ||
153 | } | ||
154 | |||
155 | input_report_abs(dev, ABS_PRESSURE, z); | ||
156 | input_report_key(dev, BTN_TOOL_FINGER, z > 0); | ||
157 | |||
158 | |||
159 | if (priv->i->flags & ALPS_WHEEL) | ||
160 | input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08)); | ||
161 | |||
162 | if (priv->i->flags & ALPS_FW_BK) { | ||
163 | input_report_key(dev, BTN_FORWARD, packet[0] & 0x10); | ||
164 | input_report_key(dev, BTN_BACK, packet[2] & 0x04); | ||
165 | } | ||
166 | |||
167 | input_sync(dev); | ||
168 | } | ||
169 | |||
170 | static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs) | ||
171 | { | ||
172 | struct alps_data *priv = psmouse->private; | ||
173 | |||
174 | if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ | ||
175 | if (psmouse->pktcnt == 3) { | ||
176 | alps_process_packet(psmouse, regs); | ||
177 | return PSMOUSE_FULL_PACKET; | ||
178 | } | ||
179 | return PSMOUSE_GOOD_DATA; | ||
180 | } | ||
181 | |||
182 | if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0) | ||
183 | return PSMOUSE_BAD_DATA; | ||
184 | |||
185 | /* Bytes 2 - 6 should have 0 in the highest bit */ | ||
186 | if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && | ||
187 | (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) | ||
188 | return PSMOUSE_BAD_DATA; | ||
189 | |||
190 | if (psmouse->pktcnt == 6) { | ||
191 | alps_process_packet(psmouse, regs); | ||
192 | return PSMOUSE_FULL_PACKET; | ||
193 | } | ||
194 | |||
195 | return PSMOUSE_GOOD_DATA; | ||
196 | } | ||
197 | |||
198 | static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) | ||
199 | { | ||
200 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
201 | unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; | ||
202 | unsigned char param[4]; | ||
203 | int i; | ||
204 | |||
205 | /* | ||
206 | * First try "E6 report". | ||
207 | * ALPS should return 0,0,10 or 0,0,100 | ||
208 | */ | ||
209 | param[0] = 0; | ||
210 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || | ||
211 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
212 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
213 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) | ||
214 | return NULL; | ||
215 | |||
216 | param[0] = param[1] = param[2] = 0xff; | ||
217 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
218 | return NULL; | ||
219 | |||
220 | dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); | ||
221 | |||
222 | if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100)) | ||
223 | return NULL; | ||
224 | |||
225 | /* | ||
226 | * Now try "E7 report". Allowed responses are in | ||
227 | * alps_model_data[].signature | ||
228 | */ | ||
229 | param[0] = 0; | ||
230 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || | ||
231 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | ||
232 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | ||
233 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21)) | ||
234 | return NULL; | ||
235 | |||
236 | param[0] = param[1] = param[2] = 0xff; | ||
237 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
238 | return NULL; | ||
239 | |||
240 | dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); | ||
241 | |||
242 | for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++); | ||
243 | *version = (param[0] << 8) | (param[1] << 4) | i; | ||
244 | |||
245 | for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) | ||
246 | if (!memcmp(param, alps_model_data[i].signature, sizeof(alps_model_data[i].signature))) | ||
247 | return alps_model_data + i; | ||
248 | |||
249 | return NULL; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * For DualPoint devices select the device that should respond to | ||
254 | * subsequent commands. It looks like glidepad is behind stickpointer, | ||
255 | * I'd thought it would be other way around... | ||
256 | */ | ||
257 | static int alps_passthrough_mode(struct psmouse *psmouse, int enable) | ||
258 | { | ||
259 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
260 | unsigned char param[3]; | ||
261 | int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; | ||
262 | |||
263 | if (ps2_command(ps2dev, NULL, cmd) || | ||
264 | ps2_command(ps2dev, NULL, cmd) || | ||
265 | ps2_command(ps2dev, NULL, cmd) || | ||
266 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) | ||
267 | return -1; | ||
268 | |||
269 | /* we may get 3 more bytes, just ignore them */ | ||
270 | ps2_command(ps2dev, param, 0x0300); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int alps_absolute_mode(struct psmouse *psmouse) | ||
276 | { | ||
277 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
278 | |||
279 | /* Try ALPS magic knock - 4 disable before enable */ | ||
280 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
281 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
282 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
283 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
284 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) | ||
285 | return -1; | ||
286 | |||
287 | /* | ||
288 | * Switch mouse to poll (remote) mode so motion data will not | ||
289 | * get in our way | ||
290 | */ | ||
291 | return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); | ||
292 | } | ||
293 | |||
294 | static int alps_get_status(struct psmouse *psmouse, char *param) | ||
295 | { | ||
296 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
297 | |||
298 | /* Get status: 0xF5 0xF5 0xF5 0xE9 */ | ||
299 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
300 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
301 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
302 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
303 | return -1; | ||
304 | |||
305 | dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * Turn touchpad tapping on or off. The sequences are: | ||
312 | * 0xE9 0xF5 0xF5 0xF3 0x0A to enable, | ||
313 | * 0xE9 0xF5 0xF5 0xE8 0x00 to disable. | ||
314 | * My guess that 0xE9 (GetInfo) is here as a sync point. | ||
315 | * For models that also have stickpointer (DualPoints) its tapping | ||
316 | * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but | ||
317 | * we don't fiddle with it. | ||
318 | */ | ||
319 | static int alps_tap_mode(struct psmouse *psmouse, int enable) | ||
320 | { | ||
321 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
322 | int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES; | ||
323 | unsigned char tap_arg = enable ? 0x0A : 0x00; | ||
324 | unsigned char param[4]; | ||
325 | |||
326 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) || | ||
327 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
328 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
329 | ps2_command(ps2dev, &tap_arg, cmd)) | ||
330 | return -1; | ||
331 | |||
332 | if (alps_get_status(psmouse, param)) | ||
333 | return -1; | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int alps_reconnect(struct psmouse *psmouse) | ||
339 | { | ||
340 | struct alps_data *priv = psmouse->private; | ||
341 | unsigned char param[4]; | ||
342 | int version; | ||
343 | |||
344 | if (!(priv->i = alps_get_model(psmouse, &version))) | ||
345 | return -1; | ||
346 | |||
347 | if (priv->i->flags & ALPS_PASS && alps_passthrough_mode(psmouse, 1)) | ||
348 | return -1; | ||
349 | |||
350 | if (alps_get_status(psmouse, param)) | ||
351 | return -1; | ||
352 | |||
353 | if (param[0] & 0x04) | ||
354 | alps_tap_mode(psmouse, 1); | ||
355 | |||
356 | if (alps_absolute_mode(psmouse)) { | ||
357 | printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); | ||
358 | return -1; | ||
359 | } | ||
360 | |||
361 | if (priv->i->flags == ALPS_PASS && alps_passthrough_mode(psmouse, 0)) | ||
362 | return -1; | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static void alps_disconnect(struct psmouse *psmouse) | ||
368 | { | ||
369 | struct alps_data *priv = psmouse->private; | ||
370 | psmouse_reset(psmouse); | ||
371 | input_unregister_device(&priv->dev2); | ||
372 | kfree(priv); | ||
373 | } | ||
374 | |||
375 | int alps_init(struct psmouse *psmouse) | ||
376 | { | ||
377 | struct alps_data *priv; | ||
378 | unsigned char param[4]; | ||
379 | int version; | ||
380 | |||
381 | psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL); | ||
382 | if (!priv) | ||
383 | goto init_fail; | ||
384 | memset(priv, 0, sizeof(struct alps_data)); | ||
385 | |||
386 | if (!(priv->i = alps_get_model(psmouse, &version))) | ||
387 | goto init_fail; | ||
388 | |||
389 | if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) | ||
390 | goto init_fail; | ||
391 | |||
392 | if (alps_get_status(psmouse, param)) { | ||
393 | printk(KERN_ERR "alps.c: touchpad status report request failed\n"); | ||
394 | goto init_fail; | ||
395 | } | ||
396 | |||
397 | if (param[0] & 0x04) { | ||
398 | printk(KERN_INFO " Enabling hardware tapping\n"); | ||
399 | if (alps_tap_mode(psmouse, 1)) | ||
400 | printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); | ||
401 | } | ||
402 | |||
403 | if (alps_absolute_mode(psmouse)) { | ||
404 | printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); | ||
405 | goto init_fail; | ||
406 | } | ||
407 | |||
408 | if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) | ||
409 | goto init_fail; | ||
410 | |||
411 | psmouse->dev.evbit[LONG(EV_KEY)] |= BIT(EV_KEY); | ||
412 | psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); | ||
413 | psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER); | ||
414 | psmouse->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
415 | |||
416 | psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS); | ||
417 | input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0); | ||
418 | input_set_abs_params(&psmouse->dev, ABS_Y, 0, 767, 0, 0); | ||
419 | input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0); | ||
420 | |||
421 | if (priv->i->flags & ALPS_WHEEL) { | ||
422 | psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL); | ||
423 | psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL); | ||
424 | } | ||
425 | |||
426 | if (priv->i->flags & ALPS_FW_BK) { | ||
427 | psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD); | ||
428 | psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); | ||
429 | } | ||
430 | |||
431 | sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys); | ||
432 | priv->dev2.phys = priv->phys; | ||
433 | priv->dev2.name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; | ||
434 | priv->dev2.id.bustype = BUS_I8042; | ||
435 | priv->dev2.id.vendor = 0x0002; | ||
436 | priv->dev2.id.product = PSMOUSE_ALPS; | ||
437 | priv->dev2.id.version = 0x0000; | ||
438 | |||
439 | priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
440 | priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); | ||
441 | priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
442 | |||
443 | input_register_device(&priv->dev2); | ||
444 | |||
445 | printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys); | ||
446 | |||
447 | psmouse->protocol_handler = alps_process_byte; | ||
448 | psmouse->disconnect = alps_disconnect; | ||
449 | psmouse->reconnect = alps_reconnect; | ||
450 | psmouse->pktsize = 6; | ||
451 | |||
452 | return 0; | ||
453 | |||
454 | init_fail: | ||
455 | kfree(priv); | ||
456 | return -1; | ||
457 | } | ||
458 | |||
459 | int alps_detect(struct psmouse *psmouse, int set_properties) | ||
460 | { | ||
461 | int version; | ||
462 | struct alps_model_info *model; | ||
463 | |||
464 | if (!(model = alps_get_model(psmouse, &version))) | ||
465 | return -1; | ||
466 | |||
467 | if (set_properties) { | ||
468 | psmouse->vendor = "ALPS"; | ||
469 | if (model->flags & ALPS_DUALPOINT) | ||
470 | psmouse->name = "DualPoint TouchPad"; | ||
471 | else | ||
472 | psmouse->name = "GlidePoint"; | ||
473 | psmouse->model = version; | ||
474 | } | ||
475 | return 0; | ||
476 | } | ||
477 | |||
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h new file mode 100644 index 000000000000..aba103dd65b7 --- /dev/null +++ b/drivers/input/mouse/alps.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * ALPS touchpad PS/2 mouse driver | ||
3 | * | ||
4 | * Copyright (c) 2003 Peter Osterlund <petero2@telia.com> | ||
5 | * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _ALPS_H | ||
13 | #define _ALPS_H | ||
14 | |||
15 | int alps_detect(struct psmouse *psmouse, int set_properties); | ||
16 | int alps_init(struct psmouse *psmouse); | ||
17 | |||
18 | struct alps_model_info { | ||
19 | unsigned char signature[3]; | ||
20 | unsigned char byte0, mask0; | ||
21 | unsigned char flags; | ||
22 | }; | ||
23 | |||
24 | struct alps_data { | ||
25 | struct input_dev dev2; /* Relative device */ | ||
26 | char name[32]; /* Name */ | ||
27 | char phys[32]; /* Phys */ | ||
28 | struct alps_model_info *i; /* Info */ | ||
29 | int prev_fin; /* Finger bit from previous packet */ | ||
30 | }; | ||
31 | |||
32 | #endif | ||
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c new file mode 100644 index 000000000000..7baa09cca7c5 --- /dev/null +++ b/drivers/input/mouse/amimouse.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Amiga mouse driver for Linux/m68k | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Michael Rausch James Banks | ||
8 | * Matther Dillon David Giller | ||
9 | * Nathan Laredo Linus Torvalds | ||
10 | * Johan Myreen Jes Sorensen | ||
11 | * Russell King | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License version 2 as published by | ||
17 | * the Free Software Foundation | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/input.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | |||
25 | #include <asm/irq.h> | ||
26 | #include <asm/setup.h> | ||
27 | #include <asm/system.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/amigahw.h> | ||
30 | #include <asm/amigaints.h> | ||
31 | |||
32 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
33 | MODULE_DESCRIPTION("Amiga mouse driver"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static int amimouse_used = 0; | ||
37 | static int amimouse_lastx, amimouse_lasty; | ||
38 | static struct input_dev amimouse_dev; | ||
39 | |||
40 | static char *amimouse_name = "Amiga mouse"; | ||
41 | static char *amimouse_phys = "amimouse/input0"; | ||
42 | |||
43 | static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) | ||
44 | { | ||
45 | unsigned short joy0dat, potgor; | ||
46 | int nx, ny, dx, dy; | ||
47 | |||
48 | joy0dat = custom.joy0dat; | ||
49 | |||
50 | nx = joy0dat & 0xff; | ||
51 | ny = joy0dat >> 8; | ||
52 | |||
53 | dx = nx - amimouse_lastx; | ||
54 | dy = ny - amimouse_lasty; | ||
55 | |||
56 | if (dx < -127) dx = (256 + nx) - amimouse_lastx; | ||
57 | if (dx > 127) dx = (nx - 256) - amimouse_lastx; | ||
58 | if (dy < -127) dy = (256 + ny) - amimouse_lasty; | ||
59 | if (dy > 127) dy = (ny - 256) - amimouse_lasty; | ||
60 | |||
61 | amimouse_lastx = nx; | ||
62 | amimouse_lasty = ny; | ||
63 | |||
64 | potgor = custom.potgor; | ||
65 | |||
66 | input_regs(&amimouse_dev, fp); | ||
67 | |||
68 | input_report_rel(&amimouse_dev, REL_X, dx); | ||
69 | input_report_rel(&amimouse_dev, REL_Y, dy); | ||
70 | |||
71 | input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); | ||
72 | input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100); | ||
73 | input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400); | ||
74 | |||
75 | input_sync(&amimouse_dev); | ||
76 | |||
77 | return IRQ_HANDLED; | ||
78 | } | ||
79 | |||
80 | static int amimouse_open(struct input_dev *dev) | ||
81 | { | ||
82 | unsigned short joy0dat; | ||
83 | |||
84 | if (amimouse_used++) | ||
85 | return 0; | ||
86 | |||
87 | joy0dat = custom.joy0dat; | ||
88 | |||
89 | amimouse_lastx = joy0dat & 0xff; | ||
90 | amimouse_lasty = joy0dat >> 8; | ||
91 | |||
92 | if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) { | ||
93 | amimouse_used--; | ||
94 | printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB); | ||
95 | return -EBUSY; | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static void amimouse_close(struct input_dev *dev) | ||
102 | { | ||
103 | if (!--amimouse_used) | ||
104 | free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt); | ||
105 | } | ||
106 | |||
107 | static int __init amimouse_init(void) | ||
108 | { | ||
109 | if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) | ||
110 | return -ENODEV; | ||
111 | |||
112 | amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
113 | amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
114 | amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
115 | amimouse_dev.open = amimouse_open; | ||
116 | amimouse_dev.close = amimouse_close; | ||
117 | |||
118 | amimouse_dev.name = amimouse_name; | ||
119 | amimouse_dev.phys = amimouse_phys; | ||
120 | amimouse_dev.id.bustype = BUS_AMIGA; | ||
121 | amimouse_dev.id.vendor = 0x0001; | ||
122 | amimouse_dev.id.product = 0x0002; | ||
123 | amimouse_dev.id.version = 0x0100; | ||
124 | |||
125 | input_register_device(&amimouse_dev); | ||
126 | |||
127 | printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void __exit amimouse_exit(void) | ||
132 | { | ||
133 | input_unregister_device(&amimouse_dev); | ||
134 | } | ||
135 | |||
136 | module_init(amimouse_init); | ||
137 | module_exit(amimouse_exit); | ||
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c new file mode 100644 index 000000000000..bc22849c6c79 --- /dev/null +++ b/drivers/input/mouse/hil_ptr.c | |||
@@ -0,0 +1,414 @@ | |||
1 | /* | ||
2 | * Generic linux-input device driver for axis-bearing devices | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/hil.h> | ||
35 | #include <linux/input.h> | ||
36 | #include <linux/serio.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/pci_ids.h> | ||
42 | |||
43 | #define PREFIX "HIL PTR: " | ||
44 | #define HIL_GENERIC_NAME "HIL pointer device" | ||
45 | |||
46 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
47 | MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); | ||
48 | MODULE_LICENSE("Dual BSD/GPL"); | ||
49 | |||
50 | |||
51 | #define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */ | ||
52 | #undef TABLET_AUTOADJUST /* auto-adjust valid tablet ranges */ | ||
53 | |||
54 | |||
55 | #define HIL_PTR_MAX_LENGTH 16 | ||
56 | |||
57 | struct hil_ptr { | ||
58 | struct input_dev dev; | ||
59 | struct serio *serio; | ||
60 | |||
61 | /* Input buffer and index for packets from HIL bus. */ | ||
62 | hil_packet data[HIL_PTR_MAX_LENGTH]; | ||
63 | int idx4; /* four counts per packet */ | ||
64 | |||
65 | /* Raw device info records from HIL bus, see hil.h for fields. */ | ||
66 | char idd[HIL_PTR_MAX_LENGTH]; /* DID byte and IDD record */ | ||
67 | char rsc[HIL_PTR_MAX_LENGTH]; /* RSC record */ | ||
68 | char exd[HIL_PTR_MAX_LENGTH]; /* EXD record */ | ||
69 | char rnm[HIL_PTR_MAX_LENGTH + 1]; /* RNM record + NULL term. */ | ||
70 | |||
71 | /* Extra device details not contained in struct input_dev. */ | ||
72 | unsigned int nbtn, naxes; | ||
73 | unsigned int btnmap[7]; | ||
74 | |||
75 | /* Something to sleep around with. */ | ||
76 | struct semaphore sem; | ||
77 | }; | ||
78 | |||
79 | /* Process a complete packet after transfer from the HIL */ | ||
80 | static void hil_ptr_process_record(struct hil_ptr *ptr) | ||
81 | { | ||
82 | struct input_dev *dev = &ptr->dev; | ||
83 | hil_packet *data = ptr->data; | ||
84 | hil_packet p; | ||
85 | int idx, i, cnt, laxis; | ||
86 | int ax16, absdev; | ||
87 | |||
88 | idx = ptr->idx4/4; | ||
89 | p = data[idx - 1]; | ||
90 | |||
91 | if ((p & ~HIL_CMDCT_POL) == | ||
92 | (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report; | ||
93 | if ((p & ~HIL_CMDCT_RPL) == | ||
94 | (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report; | ||
95 | |||
96 | /* Not a poll response. See if we are loading config records. */ | ||
97 | switch (p & HIL_PKT_DATA_MASK) { | ||
98 | case HIL_CMD_IDD: | ||
99 | for (i = 0; i < idx; i++) | ||
100 | ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; | ||
101 | for (; i < HIL_PTR_MAX_LENGTH; i++) | ||
102 | ptr->idd[i] = 0; | ||
103 | break; | ||
104 | case HIL_CMD_RSC: | ||
105 | for (i = 0; i < idx; i++) | ||
106 | ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK; | ||
107 | for (; i < HIL_PTR_MAX_LENGTH; i++) | ||
108 | ptr->rsc[i] = 0; | ||
109 | break; | ||
110 | case HIL_CMD_EXD: | ||
111 | for (i = 0; i < idx; i++) | ||
112 | ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; | ||
113 | for (; i < HIL_PTR_MAX_LENGTH; i++) | ||
114 | ptr->exd[i] = 0; | ||
115 | break; | ||
116 | case HIL_CMD_RNM: | ||
117 | for (i = 0; i < idx; i++) | ||
118 | ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK; | ||
119 | for (; i < HIL_PTR_MAX_LENGTH + 1; i++) | ||
120 | ptr->rnm[i] = '\0'; | ||
121 | break; | ||
122 | default: | ||
123 | /* These occur when device isn't present */ | ||
124 | if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; | ||
125 | /* Anything else we'd like to know about. */ | ||
126 | printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); | ||
127 | break; | ||
128 | } | ||
129 | goto out; | ||
130 | |||
131 | report: | ||
132 | if ((p & HIL_CMDCT_POL) != idx - 1) { | ||
133 | printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx); | ||
134 | goto out; | ||
135 | } | ||
136 | |||
137 | i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0; | ||
138 | laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK; | ||
139 | laxis += i; | ||
140 | |||
141 | ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ | ||
142 | absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; | ||
143 | |||
144 | for (cnt = 1; i < laxis; i++) { | ||
145 | unsigned int lo,hi,val; | ||
146 | lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; | ||
147 | hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; | ||
148 | if (absdev) { | ||
149 | val = lo + (hi<<8); | ||
150 | #ifdef TABLET_AUTOADJUST | ||
151 | if (val < ptr->dev.absmin[ABS_X + i]) | ||
152 | ptr->dev.absmin[ABS_X + i] = val; | ||
153 | if (val > ptr->dev.absmax[ABS_X + i]) | ||
154 | ptr->dev.absmax[ABS_X + i] = val; | ||
155 | #endif | ||
156 | if (i%3) val = ptr->dev.absmax[ABS_X + i] - val; | ||
157 | input_report_abs(dev, ABS_X + i, val); | ||
158 | } else { | ||
159 | val = (int) (((int8_t)lo) | ((int8_t)hi<<8)); | ||
160 | if (i%3) val *= -1; | ||
161 | input_report_rel(dev, REL_X + i, val); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | while (cnt < idx - 1) { | ||
166 | unsigned int btn; | ||
167 | int up; | ||
168 | btn = ptr->data[cnt++]; | ||
169 | up = btn & 1; | ||
170 | btn &= 0xfe; | ||
171 | if (btn == 0x8e) { | ||
172 | continue; /* TODO: proximity == touch? */ | ||
173 | } | ||
174 | else if ((btn > 0x8c) || (btn < 0x80)) continue; | ||
175 | btn = (btn - 0x80) >> 1; | ||
176 | btn = ptr->btnmap[btn]; | ||
177 | input_report_key(dev, btn, !up); | ||
178 | } | ||
179 | input_sync(dev); | ||
180 | out: | ||
181 | ptr->idx4 = 0; | ||
182 | up(&ptr->sem); | ||
183 | } | ||
184 | |||
185 | static void hil_ptr_process_err(struct hil_ptr *ptr) { | ||
186 | printk(KERN_WARNING PREFIX "errored HIL packet\n"); | ||
187 | ptr->idx4 = 0; | ||
188 | up(&ptr->sem); | ||
189 | return; | ||
190 | } | ||
191 | |||
192 | static irqreturn_t hil_ptr_interrupt(struct serio *serio, | ||
193 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
194 | { | ||
195 | struct hil_ptr *ptr; | ||
196 | hil_packet packet; | ||
197 | int idx; | ||
198 | |||
199 | ptr = (struct hil_ptr *)serio->private; | ||
200 | if (ptr == NULL) { | ||
201 | BUG(); | ||
202 | return IRQ_HANDLED; | ||
203 | } | ||
204 | |||
205 | if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) { | ||
206 | hil_ptr_process_err(ptr); | ||
207 | return IRQ_HANDLED; | ||
208 | } | ||
209 | idx = ptr->idx4/4; | ||
210 | if (!(ptr->idx4 % 4)) ptr->data[idx] = 0; | ||
211 | packet = ptr->data[idx]; | ||
212 | packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8); | ||
213 | ptr->data[idx] = packet; | ||
214 | |||
215 | /* Records of N 4-byte hil_packets must terminate with a command. */ | ||
216 | if ((++(ptr->idx4)) % 4) return IRQ_HANDLED; | ||
217 | if ((packet & 0xffff0000) != HIL_ERR_INT) { | ||
218 | hil_ptr_process_err(ptr); | ||
219 | return IRQ_HANDLED; | ||
220 | } | ||
221 | if (packet & HIL_PKT_CMD) | ||
222 | hil_ptr_process_record(ptr); | ||
223 | return IRQ_HANDLED; | ||
224 | } | ||
225 | |||
226 | static void hil_ptr_disconnect(struct serio *serio) | ||
227 | { | ||
228 | struct hil_ptr *ptr; | ||
229 | |||
230 | ptr = (struct hil_ptr *)serio->private; | ||
231 | if (ptr == NULL) { | ||
232 | BUG(); | ||
233 | return; | ||
234 | } | ||
235 | |||
236 | input_unregister_device(&ptr->dev); | ||
237 | serio_close(serio); | ||
238 | kfree(ptr); | ||
239 | } | ||
240 | |||
241 | static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver) | ||
242 | { | ||
243 | struct hil_ptr *ptr; | ||
244 | char *txt; | ||
245 | unsigned int i, naxsets, btntype; | ||
246 | uint8_t did, *idd; | ||
247 | |||
248 | if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; | ||
249 | |||
250 | if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return; | ||
251 | memset(ptr, 0, sizeof(struct hil_ptr)); | ||
252 | |||
253 | if (serio_open(serio, driver)) goto bail0; | ||
254 | |||
255 | serio->private = ptr; | ||
256 | ptr->serio = serio; | ||
257 | ptr->dev.private = ptr; | ||
258 | |||
259 | init_MUTEX_LOCKED(&(ptr->sem)); | ||
260 | |||
261 | /* Get device info. MLC driver supplies devid/status/etc. */ | ||
262 | serio->write(serio, 0); | ||
263 | serio->write(serio, 0); | ||
264 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
265 | serio->write(serio, HIL_CMD_IDD); | ||
266 | down(&(ptr->sem)); | ||
267 | |||
268 | serio->write(serio, 0); | ||
269 | serio->write(serio, 0); | ||
270 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
271 | serio->write(serio, HIL_CMD_RSC); | ||
272 | down(&(ptr->sem)); | ||
273 | |||
274 | serio->write(serio, 0); | ||
275 | serio->write(serio, 0); | ||
276 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
277 | serio->write(serio, HIL_CMD_RNM); | ||
278 | down(&(ptr->sem)); | ||
279 | |||
280 | serio->write(serio, 0); | ||
281 | serio->write(serio, 0); | ||
282 | serio->write(serio, HIL_PKT_CMD >> 8); | ||
283 | serio->write(serio, HIL_CMD_EXD); | ||
284 | down(&(ptr->sem)); | ||
285 | |||
286 | up(&(ptr->sem)); | ||
287 | |||
288 | init_input_dev(&ptr->dev); | ||
289 | did = ptr->idd[0]; | ||
290 | idd = ptr->idd + 1; | ||
291 | txt = "unknown"; | ||
292 | if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { | ||
293 | ptr->dev.evbit[0] = BIT(EV_REL); | ||
294 | txt = "relative"; | ||
295 | } | ||
296 | |||
297 | if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) { | ||
298 | ptr->dev.evbit[0] = BIT(EV_ABS); | ||
299 | txt = "absolute"; | ||
300 | } | ||
301 | if (!ptr->dev.evbit[0]) { | ||
302 | goto bail1; | ||
303 | } | ||
304 | |||
305 | ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); | ||
306 | if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY); | ||
307 | |||
308 | naxsets = HIL_IDD_NUM_AXSETS(*idd); | ||
309 | ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); | ||
310 | |||
311 | printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n", | ||
312 | did, txt); | ||
313 | printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n", | ||
314 | ptr->nbtn, naxsets, ptr->naxes); | ||
315 | |||
316 | btntype = BTN_MISC; | ||
317 | if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) | ||
318 | #ifdef TABLET_SIMULATES_MOUSE | ||
319 | btntype = BTN_TOUCH; | ||
320 | #else | ||
321 | btntype = BTN_DIGI; | ||
322 | #endif | ||
323 | if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) | ||
324 | btntype = BTN_TOUCH; | ||
325 | |||
326 | if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) | ||
327 | btntype = BTN_MOUSE; | ||
328 | |||
329 | for (i = 0; i < ptr->nbtn; i++) { | ||
330 | set_bit(btntype | i, ptr->dev.keybit); | ||
331 | ptr->btnmap[i] = btntype | i; | ||
332 | } | ||
333 | |||
334 | if (btntype == BTN_MOUSE) { | ||
335 | /* Swap buttons 2 and 3 */ | ||
336 | ptr->btnmap[1] = BTN_MIDDLE; | ||
337 | ptr->btnmap[2] = BTN_RIGHT; | ||
338 | } | ||
339 | |||
340 | if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { | ||
341 | for (i = 0; i < ptr->naxes; i++) { | ||
342 | set_bit(REL_X + i, ptr->dev.relbit); | ||
343 | } | ||
344 | for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { | ||
345 | set_bit(REL_X + i, ptr->dev.relbit); | ||
346 | } | ||
347 | } else { | ||
348 | for (i = 0; i < ptr->naxes; i++) { | ||
349 | set_bit(ABS_X + i, ptr->dev.absbit); | ||
350 | ptr->dev.absmin[ABS_X + i] = 0; | ||
351 | ptr->dev.absmax[ABS_X + i] = | ||
352 | HIL_IDD_AXIS_MAX((ptr->idd + 1), i); | ||
353 | } | ||
354 | for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { | ||
355 | set_bit(ABS_X + i, ptr->dev.absbit); | ||
356 | ptr->dev.absmin[ABS_X + i] = 0; | ||
357 | ptr->dev.absmax[ABS_X + i] = | ||
358 | HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3)); | ||
359 | } | ||
360 | #ifdef TABLET_AUTOADJUST | ||
361 | for (i = 0; i < ABS_MAX; i++) { | ||
362 | int diff = ptr->dev.absmax[ABS_X + i] / 10; | ||
363 | ptr->dev.absmin[ABS_X + i] += diff; | ||
364 | ptr->dev.absmax[ABS_X + i] -= diff; | ||
365 | } | ||
366 | #endif | ||
367 | } | ||
368 | |||
369 | ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME; | ||
370 | |||
371 | ptr->dev.id.bustype = BUS_HIL; | ||
372 | ptr->dev.id.vendor = PCI_VENDOR_ID_HP; | ||
373 | ptr->dev.id.product = 0x0001; /* TODO: get from ptr->rsc */ | ||
374 | ptr->dev.id.version = 0x0100; /* TODO: get from ptr->rsc */ | ||
375 | ptr->dev.dev = &serio->dev; | ||
376 | |||
377 | input_register_device(&ptr->dev); | ||
378 | printk(KERN_INFO "input: %s (%s), ID: %d\n", | ||
379 | ptr->dev.name, | ||
380 | (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", | ||
381 | did); | ||
382 | |||
383 | return; | ||
384 | bail1: | ||
385 | serio_close(serio); | ||
386 | bail0: | ||
387 | kfree(ptr); | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | |||
392 | static struct serio_driver hil_ptr_serio_driver = { | ||
393 | .driver = { | ||
394 | .name = "hil_ptr", | ||
395 | }, | ||
396 | .description = "HP HIL mouse/tablet driver", | ||
397 | .connect = hil_ptr_connect, | ||
398 | .disconnect = hil_ptr_disconnect, | ||
399 | .interrupt = hil_ptr_interrupt | ||
400 | }; | ||
401 | |||
402 | static int __init hil_ptr_init(void) | ||
403 | { | ||
404 | serio_register_driver(&hil_ptr_serio_driver); | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static void __exit hil_ptr_exit(void) | ||
409 | { | ||
410 | serio_unregister_driver(&hil_ptr_serio_driver); | ||
411 | } | ||
412 | |||
413 | module_init(hil_ptr_init); | ||
414 | module_exit(hil_ptr_exit); | ||
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c new file mode 100644 index 000000000000..ca4e96886627 --- /dev/null +++ b/drivers/input/mouse/inport.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Teemu Rantanen Derrick Cole | ||
8 | * Peter Cervasio Christoph Niemann | ||
9 | * Philip Blundell Russell King | ||
10 | * Bob Harris | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Inport (ATI XL and Microsoft) busmouse driver for Linux | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation; either version 2 of the License, or | ||
21 | * (at your option) any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
31 | * | ||
32 | * Should you need to contact me, the author, you can do so either by | ||
33 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
34 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
35 | */ | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/moduleparam.h> | ||
39 | #include <linux/config.h> | ||
40 | #include <linux/ioport.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <linux/input.h> | ||
44 | |||
45 | #include <asm/io.h> | ||
46 | #include <asm/irq.h> | ||
47 | |||
48 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
49 | MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver"); | ||
50 | MODULE_LICENSE("GPL"); | ||
51 | |||
52 | #define INPORT_BASE 0x23c | ||
53 | #define INPORT_EXTENT 4 | ||
54 | |||
55 | #define INPORT_CONTROL_PORT INPORT_BASE + 0 | ||
56 | #define INPORT_DATA_PORT INPORT_BASE + 1 | ||
57 | #define INPORT_SIGNATURE_PORT INPORT_BASE + 2 | ||
58 | |||
59 | #define INPORT_REG_BTNS 0x00 | ||
60 | #define INPORT_REG_X 0x01 | ||
61 | #define INPORT_REG_Y 0x02 | ||
62 | #define INPORT_REG_MODE 0x07 | ||
63 | #define INPORT_RESET 0x80 | ||
64 | |||
65 | #ifdef CONFIG_INPUT_ATIXL | ||
66 | #define INPORT_NAME "ATI XL Mouse" | ||
67 | #define INPORT_VENDOR 0x0002 | ||
68 | #define INPORT_SPEED_30HZ 0x01 | ||
69 | #define INPORT_SPEED_50HZ 0x02 | ||
70 | #define INPORT_SPEED_100HZ 0x03 | ||
71 | #define INPORT_SPEED_200HZ 0x04 | ||
72 | #define INPORT_MODE_BASE INPORT_SPEED_100HZ | ||
73 | #define INPORT_MODE_IRQ 0x08 | ||
74 | #else | ||
75 | #define INPORT_NAME "Microsoft InPort Mouse" | ||
76 | #define INPORT_VENDOR 0x0001 | ||
77 | #define INPORT_MODE_BASE 0x10 | ||
78 | #define INPORT_MODE_IRQ 0x01 | ||
79 | #endif | ||
80 | #define INPORT_MODE_HOLD 0x20 | ||
81 | |||
82 | #define INPORT_IRQ 5 | ||
83 | |||
84 | static int inport_irq = INPORT_IRQ; | ||
85 | module_param_named(irq, inport_irq, uint, 0); | ||
86 | MODULE_PARM_DESC(irq, "IRQ number (5=default)"); | ||
87 | |||
88 | __obsolete_setup("inport_irq="); | ||
89 | |||
90 | static int inport_used; | ||
91 | |||
92 | static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
93 | |||
94 | static int inport_open(struct input_dev *dev) | ||
95 | { | ||
96 | if (!inport_used++) { | ||
97 | if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL)) | ||
98 | return -EBUSY; | ||
99 | outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); | ||
100 | outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static void inport_close(struct input_dev *dev) | ||
107 | { | ||
108 | if (!--inport_used) { | ||
109 | outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); | ||
110 | outb(INPORT_MODE_BASE, INPORT_DATA_PORT); | ||
111 | free_irq(inport_irq, NULL); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static struct input_dev inport_dev = { | ||
116 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | ||
117 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, | ||
118 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | ||
119 | .open = inport_open, | ||
120 | .close = inport_close, | ||
121 | .name = INPORT_NAME, | ||
122 | .phys = "isa023c/input0", | ||
123 | .id = { | ||
124 | .bustype = BUS_ISA, | ||
125 | .vendor = INPORT_VENDOR, | ||
126 | .product = 0x0001, | ||
127 | .version = 0x0100, | ||
128 | }, | ||
129 | }; | ||
130 | |||
131 | static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
132 | { | ||
133 | unsigned char buttons; | ||
134 | |||
135 | outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); | ||
136 | outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); | ||
137 | |||
138 | input_regs(&inport_dev, regs); | ||
139 | |||
140 | outb(INPORT_REG_X, INPORT_CONTROL_PORT); | ||
141 | input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT)); | ||
142 | |||
143 | outb(INPORT_REG_Y, INPORT_CONTROL_PORT); | ||
144 | input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT)); | ||
145 | |||
146 | outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT); | ||
147 | buttons = inb(INPORT_DATA_PORT); | ||
148 | |||
149 | input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1); | ||
150 | input_report_key(&inport_dev, BTN_LEFT, buttons & 2); | ||
151 | input_report_key(&inport_dev, BTN_RIGHT, buttons & 4); | ||
152 | |||
153 | outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); | ||
154 | outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); | ||
155 | |||
156 | input_sync(&inport_dev); | ||
157 | return IRQ_HANDLED; | ||
158 | } | ||
159 | |||
160 | static int __init inport_init(void) | ||
161 | { | ||
162 | unsigned char a,b,c; | ||
163 | |||
164 | if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) { | ||
165 | printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE); | ||
166 | return -EBUSY; | ||
167 | } | ||
168 | |||
169 | a = inb(INPORT_SIGNATURE_PORT); | ||
170 | b = inb(INPORT_SIGNATURE_PORT); | ||
171 | c = inb(INPORT_SIGNATURE_PORT); | ||
172 | if (( a == b ) || ( a != c )) { | ||
173 | release_region(INPORT_BASE, INPORT_EXTENT); | ||
174 | printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE); | ||
175 | return -ENODEV; | ||
176 | } | ||
177 | |||
178 | outb(INPORT_RESET, INPORT_CONTROL_PORT); | ||
179 | outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); | ||
180 | outb(INPORT_MODE_BASE, INPORT_DATA_PORT); | ||
181 | |||
182 | input_register_device(&inport_dev); | ||
183 | |||
184 | printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", INPORT_BASE, inport_irq); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static void __exit inport_exit(void) | ||
190 | { | ||
191 | input_unregister_device(&inport_dev); | ||
192 | release_region(INPORT_BASE, INPORT_EXTENT); | ||
193 | } | ||
194 | |||
195 | module_init(inport_init); | ||
196 | module_exit(inport_exit); | ||
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c new file mode 100644 index 000000000000..77eb83e87f61 --- /dev/null +++ b/drivers/input/mouse/logibm.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * James Banks Matthew Dillon | ||
8 | * David Giller Nathan Laredo | ||
9 | * Linus Torvalds Johan Myreen | ||
10 | * Cliff Matthews Philip Blundell | ||
11 | * Russell King | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * Logitech Bus Mouse Driver for Linux | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * This program is free software; you can redistribute it and/or modify | ||
20 | * it under the terms of the GNU General Public License as published by | ||
21 | * the Free Software Foundation; either version 2 of the License, or | ||
22 | * (at your option) any later version. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | * GNU General Public License for more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License | ||
30 | * along with this program; if not, write to the Free Software | ||
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
32 | * | ||
33 | * Should you need to contact me, the author, you can do so either by | ||
34 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
35 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
36 | */ | ||
37 | |||
38 | #include <linux/module.h> | ||
39 | #include <linux/moduleparam.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <linux/ioport.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/input.h> | ||
44 | #include <linux/interrupt.h> | ||
45 | |||
46 | #include <asm/io.h> | ||
47 | #include <asm/irq.h> | ||
48 | |||
49 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
50 | MODULE_DESCRIPTION("Logitech busmouse driver"); | ||
51 | MODULE_LICENSE("GPL"); | ||
52 | |||
53 | #define LOGIBM_BASE 0x23c | ||
54 | #define LOGIBM_EXTENT 4 | ||
55 | |||
56 | #define LOGIBM_DATA_PORT LOGIBM_BASE + 0 | ||
57 | #define LOGIBM_SIGNATURE_PORT LOGIBM_BASE + 1 | ||
58 | #define LOGIBM_CONTROL_PORT LOGIBM_BASE + 2 | ||
59 | #define LOGIBM_CONFIG_PORT LOGIBM_BASE + 3 | ||
60 | |||
61 | #define LOGIBM_ENABLE_IRQ 0x00 | ||
62 | #define LOGIBM_DISABLE_IRQ 0x10 | ||
63 | #define LOGIBM_READ_X_LOW 0x80 | ||
64 | #define LOGIBM_READ_X_HIGH 0xa0 | ||
65 | #define LOGIBM_READ_Y_LOW 0xc0 | ||
66 | #define LOGIBM_READ_Y_HIGH 0xe0 | ||
67 | |||
68 | #define LOGIBM_DEFAULT_MODE 0x90 | ||
69 | #define LOGIBM_CONFIG_BYTE 0x91 | ||
70 | #define LOGIBM_SIGNATURE_BYTE 0xa5 | ||
71 | |||
72 | #define LOGIBM_IRQ 5 | ||
73 | |||
74 | static int logibm_irq = LOGIBM_IRQ; | ||
75 | module_param_named(irq, logibm_irq, uint, 0); | ||
76 | MODULE_PARM_DESC(irq, "IRQ number (5=default)"); | ||
77 | |||
78 | __obsolete_setup("logibm_irq="); | ||
79 | |||
80 | static int logibm_used = 0; | ||
81 | |||
82 | static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
83 | |||
84 | static int logibm_open(struct input_dev *dev) | ||
85 | { | ||
86 | if (logibm_used++) | ||
87 | return 0; | ||
88 | if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { | ||
89 | logibm_used--; | ||
90 | printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); | ||
91 | return -EBUSY; | ||
92 | } | ||
93 | outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static void logibm_close(struct input_dev *dev) | ||
98 | { | ||
99 | if (--logibm_used) | ||
100 | return; | ||
101 | outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); | ||
102 | free_irq(logibm_irq, NULL); | ||
103 | } | ||
104 | |||
105 | static struct input_dev logibm_dev = { | ||
106 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | ||
107 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, | ||
108 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | ||
109 | .open = logibm_open, | ||
110 | .close = logibm_close, | ||
111 | .name = "Logitech bus mouse", | ||
112 | .phys = "isa023c/input0", | ||
113 | .id = { | ||
114 | .bustype = BUS_ISA, | ||
115 | .vendor = 0x0003, | ||
116 | .product = 0x0001, | ||
117 | .version = 0x0100, | ||
118 | }, | ||
119 | }; | ||
120 | |||
121 | static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
122 | { | ||
123 | char dx, dy; | ||
124 | unsigned char buttons; | ||
125 | |||
126 | outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT); | ||
127 | dx = (inb(LOGIBM_DATA_PORT) & 0xf); | ||
128 | outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT); | ||
129 | dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4; | ||
130 | outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT); | ||
131 | dy = (inb(LOGIBM_DATA_PORT) & 0xf); | ||
132 | outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT); | ||
133 | buttons = inb(LOGIBM_DATA_PORT); | ||
134 | dy |= (buttons & 0xf) << 4; | ||
135 | buttons = ~buttons >> 5; | ||
136 | |||
137 | input_regs(&logibm_dev, regs); | ||
138 | input_report_rel(&logibm_dev, REL_X, dx); | ||
139 | input_report_rel(&logibm_dev, REL_Y, dy); | ||
140 | input_report_key(&logibm_dev, BTN_RIGHT, buttons & 1); | ||
141 | input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 2); | ||
142 | input_report_key(&logibm_dev, BTN_LEFT, buttons & 4); | ||
143 | input_sync(&logibm_dev); | ||
144 | |||
145 | outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); | ||
146 | return IRQ_HANDLED; | ||
147 | } | ||
148 | |||
149 | static int __init logibm_init(void) | ||
150 | { | ||
151 | if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { | ||
152 | printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE); | ||
153 | return -EBUSY; | ||
154 | } | ||
155 | |||
156 | outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT); | ||
157 | outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT); | ||
158 | udelay(100); | ||
159 | |||
160 | if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) { | ||
161 | release_region(LOGIBM_BASE, LOGIBM_EXTENT); | ||
162 | printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE); | ||
163 | return -ENODEV; | ||
164 | } | ||
165 | |||
166 | outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT); | ||
167 | outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); | ||
168 | |||
169 | input_register_device(&logibm_dev); | ||
170 | |||
171 | printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static void __exit logibm_exit(void) | ||
177 | { | ||
178 | input_unregister_device(&logibm_dev); | ||
179 | release_region(LOGIBM_BASE, LOGIBM_EXTENT); | ||
180 | } | ||
181 | |||
182 | module_init(logibm_init); | ||
183 | module_exit(logibm_exit); | ||
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c new file mode 100644 index 000000000000..5ab1bd7d529d --- /dev/null +++ b/drivers/input/mouse/logips2pp.c | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * Logitech PS/2++ mouse driver | ||
3 | * | ||
4 | * Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz> | ||
5 | * Copyright (c) 2003 Eric Wong <eric@yhbt.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/input.h> | ||
13 | #include <linux/serio.h> | ||
14 | #include <linux/libps2.h> | ||
15 | #include "psmouse.h" | ||
16 | #include "logips2pp.h" | ||
17 | |||
18 | /* Logitech mouse types */ | ||
19 | #define PS2PP_KIND_WHEEL 1 | ||
20 | #define PS2PP_KIND_MX 2 | ||
21 | #define PS2PP_KIND_TP3 3 | ||
22 | |||
23 | /* Logitech mouse features */ | ||
24 | #define PS2PP_WHEEL 0x01 | ||
25 | #define PS2PP_HWHEEL 0x02 | ||
26 | #define PS2PP_SIDE_BTN 0x04 | ||
27 | #define PS2PP_EXTRA_BTN 0x08 | ||
28 | #define PS2PP_TASK_BTN 0x10 | ||
29 | #define PS2PP_NAV_BTN 0x20 | ||
30 | |||
31 | struct ps2pp_info { | ||
32 | const int model; | ||
33 | unsigned const int kind; | ||
34 | unsigned const int features; | ||
35 | }; | ||
36 | |||
37 | /* | ||
38 | * Process a PS2++ or PS2T++ packet. | ||
39 | */ | ||
40 | |||
41 | static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs) | ||
42 | { | ||
43 | struct input_dev *dev = &psmouse->dev; | ||
44 | unsigned char *packet = psmouse->packet; | ||
45 | |||
46 | if (psmouse->pktcnt < 3) | ||
47 | return PSMOUSE_GOOD_DATA; | ||
48 | |||
49 | /* | ||
50 | * Full packet accumulated, process it | ||
51 | */ | ||
52 | |||
53 | input_regs(dev, regs); | ||
54 | |||
55 | if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) { | ||
56 | |||
57 | /* Logitech extended packet */ | ||
58 | switch ((packet[1] >> 4) | (packet[0] & 0x30)) { | ||
59 | |||
60 | case 0x0d: /* Mouse extra info */ | ||
61 | |||
62 | input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, | ||
63 | (int) (packet[2] & 8) - (int) (packet[2] & 7)); | ||
64 | input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); | ||
65 | input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); | ||
66 | |||
67 | break; | ||
68 | |||
69 | case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ | ||
70 | |||
71 | input_report_key(dev, BTN_SIDE, (packet[2]) & 1); | ||
72 | input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); | ||
73 | input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); | ||
74 | input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); | ||
75 | input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); | ||
76 | |||
77 | break; | ||
78 | |||
79 | case 0x0f: /* TouchPad extra info */ | ||
80 | |||
81 | input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, | ||
82 | (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); | ||
83 | packet[0] = packet[2] | 0x08; | ||
84 | break; | ||
85 | |||
86 | #ifdef DEBUG | ||
87 | default: | ||
88 | printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", | ||
89 | (packet[1] >> 4) | (packet[0] & 0x30)); | ||
90 | #endif | ||
91 | } | ||
92 | } else { | ||
93 | /* Standard PS/2 motion data */ | ||
94 | input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); | ||
95 | input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); | ||
96 | } | ||
97 | |||
98 | input_report_key(dev, BTN_LEFT, packet[0] & 1); | ||
99 | input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); | ||
100 | input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); | ||
101 | |||
102 | input_sync(dev); | ||
103 | |||
104 | return PSMOUSE_FULL_PACKET; | ||
105 | |||
106 | } | ||
107 | |||
108 | /* | ||
109 | * ps2pp_cmd() sends a PS2++ command, sliced into two bit | ||
110 | * pieces through the SETRES command. This is needed to send extended | ||
111 | * commands to mice on notebooks that try to understand the PS/2 protocol | ||
112 | * Ugly. | ||
113 | */ | ||
114 | |||
115 | static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) | ||
116 | { | ||
117 | if (psmouse_sliced_command(psmouse, command)) | ||
118 | return -1; | ||
119 | |||
120 | if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL)) | ||
121 | return -1; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * SmartScroll / CruiseControl for some newer Logitech mice Defaults to | ||
128 | * enabled if we do nothing to it. Of course I put this in because I want it | ||
129 | * disabled :P | ||
130 | * 1 - enabled (if previously disabled, also default) | ||
131 | * 0 - disabled | ||
132 | */ | ||
133 | |||
134 | static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll) | ||
135 | { | ||
136 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
137 | unsigned char param[4]; | ||
138 | |||
139 | if (smartscroll > 1) | ||
140 | smartscroll = 1; | ||
141 | |||
142 | ps2pp_cmd(psmouse, param, 0x32); | ||
143 | |||
144 | param[0] = 0; | ||
145 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
146 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
147 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
148 | |||
149 | param[0] = smartscroll; | ||
150 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
151 | } | ||
152 | |||
153 | static ssize_t psmouse_attr_show_smartscroll(struct psmouse *psmouse, char *buf) | ||
154 | { | ||
155 | return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0); | ||
156 | } | ||
157 | |||
158 | static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char *buf, size_t count) | ||
159 | { | ||
160 | unsigned long value; | ||
161 | char *rest; | ||
162 | |||
163 | value = simple_strtoul(buf, &rest, 10); | ||
164 | if (*rest || value > 1) | ||
165 | return -EINVAL; | ||
166 | |||
167 | ps2pp_set_smartscroll(psmouse, value); | ||
168 | psmouse->smartscroll = value; | ||
169 | return count; | ||
170 | } | ||
171 | |||
172 | PSMOUSE_DEFINE_ATTR(smartscroll); | ||
173 | |||
174 | /* | ||
175 | * Support 800 dpi resolution _only_ if the user wants it (there are good | ||
176 | * reasons to not use it even if the mouse supports it, and of course there are | ||
177 | * also good reasons to use it, let the user decide). | ||
178 | */ | ||
179 | |||
180 | static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution) | ||
181 | { | ||
182 | if (resolution > 400) { | ||
183 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
184 | unsigned char param = 3; | ||
185 | |||
186 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
187 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
188 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
189 | ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); | ||
190 | psmouse->resolution = 800; | ||
191 | } else | ||
192 | psmouse_set_resolution(psmouse, resolution); | ||
193 | } | ||
194 | |||
195 | static void ps2pp_disconnect(struct psmouse *psmouse) | ||
196 | { | ||
197 | device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); | ||
198 | } | ||
199 | |||
200 | static struct ps2pp_info *get_model_info(unsigned char model) | ||
201 | { | ||
202 | static struct ps2pp_info ps2pp_list[] = { | ||
203 | { 12, 0, PS2PP_SIDE_BTN}, | ||
204 | { 13, 0, 0 }, | ||
205 | { 15, PS2PP_KIND_MX, /* MX1000 */ | ||
206 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | | ||
207 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL }, | ||
208 | { 40, 0, PS2PP_SIDE_BTN }, | ||
209 | { 41, 0, PS2PP_SIDE_BTN }, | ||
210 | { 42, 0, PS2PP_SIDE_BTN }, | ||
211 | { 43, 0, PS2PP_SIDE_BTN }, | ||
212 | { 50, 0, 0 }, | ||
213 | { 51, 0, 0 }, | ||
214 | { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, | ||
215 | { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | ||
216 | { 61, PS2PP_KIND_MX, /* MX700 */ | ||
217 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | | ||
218 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, | ||
219 | { 73, 0, PS2PP_SIDE_BTN }, | ||
220 | { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | ||
221 | { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | ||
222 | { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, | ||
223 | { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | ||
224 | { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | ||
225 | { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | ||
226 | { 96, 0, 0 }, | ||
227 | { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, | ||
228 | { 100, PS2PP_KIND_MX, /* MX510 */ | ||
229 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | | ||
230 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, | ||
231 | { 111, PS2PP_KIND_MX, /* MX300 */ | ||
232 | PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN }, | ||
233 | { 112, PS2PP_KIND_MX, /* MX500 */ | ||
234 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | | ||
235 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, | ||
236 | { 114, PS2PP_KIND_MX, /* MX310 */ | ||
237 | PS2PP_WHEEL | PS2PP_SIDE_BTN | | ||
238 | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, | ||
239 | { } | ||
240 | }; | ||
241 | int i; | ||
242 | |||
243 | for (i = 0; ps2pp_list[i].model; i++) | ||
244 | if (model == ps2pp_list[i].model) | ||
245 | return &ps2pp_list[i]; | ||
246 | |||
247 | printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); | ||
248 | return NULL; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * Set up input device's properties based on the detected mouse model. | ||
253 | */ | ||
254 | |||
255 | static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info, | ||
256 | int using_ps2pp) | ||
257 | { | ||
258 | if (model_info->features & PS2PP_SIDE_BTN) | ||
259 | set_bit(BTN_SIDE, psmouse->dev.keybit); | ||
260 | |||
261 | if (model_info->features & PS2PP_EXTRA_BTN) | ||
262 | set_bit(BTN_EXTRA, psmouse->dev.keybit); | ||
263 | |||
264 | if (model_info->features & PS2PP_TASK_BTN) | ||
265 | set_bit(BTN_TASK, psmouse->dev.keybit); | ||
266 | |||
267 | if (model_info->features & PS2PP_NAV_BTN) { | ||
268 | set_bit(BTN_FORWARD, psmouse->dev.keybit); | ||
269 | set_bit(BTN_BACK, psmouse->dev.keybit); | ||
270 | } | ||
271 | |||
272 | if (model_info->features & PS2PP_WHEEL) | ||
273 | set_bit(REL_WHEEL, psmouse->dev.relbit); | ||
274 | |||
275 | if (model_info->features & PS2PP_HWHEEL) | ||
276 | set_bit(REL_HWHEEL, psmouse->dev.relbit); | ||
277 | |||
278 | switch (model_info->kind) { | ||
279 | case PS2PP_KIND_WHEEL: | ||
280 | psmouse->name = "Wheel Mouse"; | ||
281 | break; | ||
282 | |||
283 | case PS2PP_KIND_MX: | ||
284 | psmouse->name = "MX Mouse"; | ||
285 | break; | ||
286 | |||
287 | case PS2PP_KIND_TP3: | ||
288 | psmouse->name = "TouchPad 3"; | ||
289 | break; | ||
290 | |||
291 | default: | ||
292 | /* | ||
293 | * Set name to "Mouse" only when using PS2++, | ||
294 | * otherwise let other protocols define suitable | ||
295 | * name | ||
296 | */ | ||
297 | if (using_ps2pp) | ||
298 | psmouse->name = "Mouse"; | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | |||
304 | /* | ||
305 | * Logitech magic init. Detect whether the mouse is a Logitech one | ||
306 | * and its exact model and try turning on extended protocol for ones | ||
307 | * that support it. | ||
308 | */ | ||
309 | |||
310 | int ps2pp_init(struct psmouse *psmouse, int set_properties) | ||
311 | { | ||
312 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
313 | unsigned char param[4]; | ||
314 | unsigned char model, buttons; | ||
315 | struct ps2pp_info *model_info; | ||
316 | int use_ps2pp = 0; | ||
317 | |||
318 | param[0] = 0; | ||
319 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
320 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
321 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
322 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
323 | param[1] = 0; | ||
324 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); | ||
325 | |||
326 | if (!param[1]) | ||
327 | return -1; | ||
328 | |||
329 | model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); | ||
330 | buttons = param[1]; | ||
331 | |||
332 | if ((model_info = get_model_info(model)) != NULL) { | ||
333 | |||
334 | /* | ||
335 | * Do Logitech PS2++ / PS2T++ magic init. | ||
336 | */ | ||
337 | if (model == 97) { /* Touch Pad 3 */ | ||
338 | |||
339 | /* Unprotect RAM */ | ||
340 | param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; | ||
341 | ps2_command(ps2dev, param, 0x30d1); | ||
342 | /* Enable features */ | ||
343 | param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; | ||
344 | ps2_command(ps2dev, param, 0x30d1); | ||
345 | /* Enable PS2++ */ | ||
346 | param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; | ||
347 | ps2_command(ps2dev, param, 0x30d1); | ||
348 | |||
349 | param[0] = 0; | ||
350 | if (!ps2_command(ps2dev, param, 0x13d1) && | ||
351 | param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { | ||
352 | use_ps2pp = 1; | ||
353 | } | ||
354 | |||
355 | } else { | ||
356 | |||
357 | param[0] = param[1] = param[2] = 0; | ||
358 | ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ | ||
359 | ps2pp_cmd(psmouse, param, 0xDB); | ||
360 | |||
361 | if ((param[0] & 0x78) == 0x48 && | ||
362 | (param[1] & 0xf3) == 0xc2 && | ||
363 | (param[2] & 0x03) == ((param[1] >> 2) & 3)) { | ||
364 | ps2pp_set_smartscroll(psmouse, psmouse->smartscroll); | ||
365 | use_ps2pp = 1; | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | |||
370 | if (set_properties) { | ||
371 | psmouse->vendor = "Logitech"; | ||
372 | psmouse->model = model; | ||
373 | |||
374 | if (use_ps2pp) { | ||
375 | psmouse->protocol_handler = ps2pp_process_byte; | ||
376 | psmouse->pktsize = 3; | ||
377 | |||
378 | if (model_info->kind != PS2PP_KIND_TP3) { | ||
379 | psmouse->set_resolution = ps2pp_set_resolution; | ||
380 | psmouse->disconnect = ps2pp_disconnect; | ||
381 | |||
382 | device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | if (buttons < 3) | ||
387 | clear_bit(BTN_MIDDLE, psmouse->dev.keybit); | ||
388 | if (buttons < 2) | ||
389 | clear_bit(BTN_RIGHT, psmouse->dev.keybit); | ||
390 | |||
391 | if (model_info) | ||
392 | ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); | ||
393 | } | ||
394 | |||
395 | return use_ps2pp ? 0 : -1; | ||
396 | } | ||
397 | |||
diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h new file mode 100644 index 000000000000..64a8ec52ea6d --- /dev/null +++ b/drivers/input/mouse/logips2pp.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * Logitech PS/2++ mouse driver header | ||
3 | * | ||
4 | * Copyright (c) 2003 Vojtech Pavlik <vojtech@suse.cz> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _LOGIPS2PP_H | ||
12 | #define _LOGIPS2PP_H | ||
13 | |||
14 | int ps2pp_init(struct psmouse *psmouse, int set_properties); | ||
15 | |||
16 | #endif | ||
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c new file mode 100644 index 000000000000..12dc0ef5020f --- /dev/null +++ b/drivers/input/mouse/maplemouse.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $ | ||
3 | * SEGA Dreamcast mouse driver | ||
4 | * Based on drivers/usb/usbmouse.c | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/slab.h> | ||
9 | #include <linux/input.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/timer.h> | ||
13 | #include <linux/maple.h> | ||
14 | |||
15 | MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>"); | ||
16 | MODULE_DESCRIPTION("SEGA Dreamcast mouse driver"); | ||
17 | |||
18 | struct dc_mouse { | ||
19 | struct input_dev dev; | ||
20 | int open; | ||
21 | }; | ||
22 | |||
23 | |||
24 | static void dc_mouse_callback(struct mapleq *mq) | ||
25 | { | ||
26 | int buttons, relx, rely, relz; | ||
27 | struct maple_device *mapledev = mq->dev; | ||
28 | struct dc_mouse *mouse = mapledev->private_data; | ||
29 | struct input_dev *dev = &mouse->dev; | ||
30 | unsigned char *res = mq->recvbuf; | ||
31 | |||
32 | buttons = ~res[8]; | ||
33 | relx=*(unsigned short *)(res+12)-512; | ||
34 | rely=*(unsigned short *)(res+14)-512; | ||
35 | relz=*(unsigned short *)(res+16)-512; | ||
36 | |||
37 | input_report_key(dev, BTN_LEFT, buttons&4); | ||
38 | input_report_key(dev, BTN_MIDDLE, buttons&9); | ||
39 | input_report_key(dev, BTN_RIGHT, buttons&2); | ||
40 | input_report_rel(dev, REL_X, relx); | ||
41 | input_report_rel(dev, REL_Y, rely); | ||
42 | input_report_rel(dev, REL_WHEEL, relz); | ||
43 | input_sync(dev); | ||
44 | } | ||
45 | |||
46 | |||
47 | static int dc_mouse_open(struct input_dev *dev) | ||
48 | { | ||
49 | struct dc_mouse *mouse = dev->private; | ||
50 | mouse->open++; | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | |||
55 | static void dc_mouse_close(struct input_dev *dev) | ||
56 | { | ||
57 | struct dc_mouse *mouse = dev->private; | ||
58 | mouse->open--; | ||
59 | } | ||
60 | |||
61 | |||
62 | static int dc_mouse_connect(struct maple_device *dev) | ||
63 | { | ||
64 | unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); | ||
65 | struct dc_mouse *mouse; | ||
66 | |||
67 | if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL))) | ||
68 | return -1; | ||
69 | memset(mouse, 0, sizeof(struct dc_mouse)); | ||
70 | |||
71 | dev->private_data = mouse; | ||
72 | |||
73 | mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
74 | mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); | ||
75 | mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); | ||
76 | |||
77 | init_input_dev(&mouse->dev); | ||
78 | |||
79 | mouse->dev.private = mouse; | ||
80 | mouse->dev.open = dc_mouse_open; | ||
81 | mouse->dev.close = dc_mouse_close; | ||
82 | mouse->dev.event = NULL; | ||
83 | |||
84 | mouse->dev.name = dev->product_name; | ||
85 | mouse->dev.id.bustype = BUS_MAPLE; | ||
86 | |||
87 | input_register_device(&mouse->dev); | ||
88 | |||
89 | maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); | ||
90 | |||
91 | printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | |||
97 | static void dc_mouse_disconnect(struct maple_device *dev) | ||
98 | { | ||
99 | struct dc_mouse *mouse = dev->private_data; | ||
100 | |||
101 | input_unregister_device(&mouse->dev); | ||
102 | kfree(mouse); | ||
103 | } | ||
104 | |||
105 | |||
106 | static struct maple_driver dc_mouse_driver = { | ||
107 | .function = MAPLE_FUNC_MOUSE, | ||
108 | .name = "Dreamcast mouse", | ||
109 | .connect = dc_mouse_connect, | ||
110 | .disconnect = dc_mouse_disconnect, | ||
111 | }; | ||
112 | |||
113 | |||
114 | static int __init dc_mouse_init(void) | ||
115 | { | ||
116 | maple_register_driver(&dc_mouse_driver); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | |||
121 | static void __exit dc_mouse_exit(void) | ||
122 | { | ||
123 | maple_unregister_driver(&dc_mouse_driver); | ||
124 | } | ||
125 | |||
126 | |||
127 | module_init(dc_mouse_init); | ||
128 | module_exit(dc_mouse_exit); | ||
129 | |||
130 | /* | ||
131 | * Local variables: | ||
132 | * c-basic-offset: 8 | ||
133 | * End: | ||
134 | */ | ||
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c new file mode 100644 index 000000000000..0c74918fe254 --- /dev/null +++ b/drivers/input/mouse/pc110pad.c | |||
@@ -0,0 +1,178 @@ | |||
1 | /* | ||
2 | * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Alan Cox Robin O'Leary | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * IBM PC110 touchpad driver for Linux | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/input.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <linux/pci.h> | ||
42 | |||
43 | #include <asm/io.h> | ||
44 | #include <asm/irq.h> | ||
45 | |||
46 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
47 | MODULE_DESCRIPTION("IBM PC110 touchpad driver"); | ||
48 | MODULE_LICENSE("GPL"); | ||
49 | |||
50 | #define PC110PAD_OFF 0x30 | ||
51 | #define PC110PAD_ON 0x38 | ||
52 | |||
53 | static int pc110pad_irq = 10; | ||
54 | static int pc110pad_io = 0x15e0; | ||
55 | |||
56 | static struct input_dev pc110pad_dev; | ||
57 | static int pc110pad_data[3]; | ||
58 | static int pc110pad_count; | ||
59 | static int pc110pad_used; | ||
60 | |||
61 | static char *pc110pad_name = "IBM PC110 TouchPad"; | ||
62 | static char *pc110pad_phys = "isa15e0/input0"; | ||
63 | |||
64 | static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) | ||
65 | { | ||
66 | int value = inb_p(pc110pad_io); | ||
67 | int handshake = inb_p(pc110pad_io + 2); | ||
68 | |||
69 | outb_p(handshake | 1, pc110pad_io + 2); | ||
70 | outb_p(handshake & ~1, pc110pad_io + 2); | ||
71 | inb_p(0x64); | ||
72 | |||
73 | pc110pad_data[pc110pad_count++] = value; | ||
74 | |||
75 | if (pc110pad_count < 3) | ||
76 | return IRQ_HANDLED; | ||
77 | |||
78 | input_regs(&pc110pad_dev, regs); | ||
79 | input_report_key(&pc110pad_dev, BTN_TOUCH, | ||
80 | pc110pad_data[0] & 0x01); | ||
81 | input_report_abs(&pc110pad_dev, ABS_X, | ||
82 | pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); | ||
83 | input_report_abs(&pc110pad_dev, ABS_Y, | ||
84 | pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); | ||
85 | input_sync(&pc110pad_dev); | ||
86 | |||
87 | pc110pad_count = 0; | ||
88 | return IRQ_HANDLED; | ||
89 | } | ||
90 | |||
91 | static void pc110pad_close(struct input_dev *dev) | ||
92 | { | ||
93 | if (!--pc110pad_used) | ||
94 | outb(PC110PAD_OFF, pc110pad_io + 2); | ||
95 | } | ||
96 | |||
97 | static int pc110pad_open(struct input_dev *dev) | ||
98 | { | ||
99 | if (pc110pad_used++) | ||
100 | return 0; | ||
101 | |||
102 | pc110pad_interrupt(0,NULL,NULL); | ||
103 | pc110pad_interrupt(0,NULL,NULL); | ||
104 | pc110pad_interrupt(0,NULL,NULL); | ||
105 | outb(PC110PAD_ON, pc110pad_io + 2); | ||
106 | pc110pad_count = 0; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * We try to avoid enabling the hardware if it's not | ||
113 | * there, but we don't know how to test. But we do know | ||
114 | * that the PC110 is not a PCI system. So if we find any | ||
115 | * PCI devices in the machine, we don't have a PC110. | ||
116 | */ | ||
117 | static int __init pc110pad_init(void) | ||
118 | { | ||
119 | struct pci_dev *dev; | ||
120 | |||
121 | dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); | ||
122 | if (dev) { | ||
123 | pci_dev_put(dev); | ||
124 | return -ENOENT; | ||
125 | } | ||
126 | |||
127 | if (!request_region(pc110pad_io, 4, "pc110pad")) { | ||
128 | printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", | ||
129 | pc110pad_io, pc110pad_io + 4); | ||
130 | return -EBUSY; | ||
131 | } | ||
132 | |||
133 | outb(PC110PAD_OFF, pc110pad_io + 2); | ||
134 | |||
135 | if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) | ||
136 | { | ||
137 | release_region(pc110pad_io, 4); | ||
138 | printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq); | ||
139 | return -EBUSY; | ||
140 | } | ||
141 | |||
142 | pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
143 | pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | ||
144 | pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
145 | |||
146 | pc110pad_dev.absmax[ABS_X] = 0x1ff; | ||
147 | pc110pad_dev.absmax[ABS_Y] = 0x0ff; | ||
148 | |||
149 | pc110pad_dev.open = pc110pad_open; | ||
150 | pc110pad_dev.close = pc110pad_close; | ||
151 | |||
152 | pc110pad_dev.name = pc110pad_name; | ||
153 | pc110pad_dev.phys = pc110pad_phys; | ||
154 | pc110pad_dev.id.bustype = BUS_ISA; | ||
155 | pc110pad_dev.id.vendor = 0x0003; | ||
156 | pc110pad_dev.id.product = 0x0001; | ||
157 | pc110pad_dev.id.version = 0x0100; | ||
158 | |||
159 | input_register_device(&pc110pad_dev); | ||
160 | |||
161 | printk(KERN_INFO "input: %s at %#x irq %d\n", | ||
162 | pc110pad_name, pc110pad_io, pc110pad_irq); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static void __exit pc110pad_exit(void) | ||
168 | { | ||
169 | input_unregister_device(&pc110pad_dev); | ||
170 | |||
171 | outb(PC110PAD_OFF, pc110pad_io + 2); | ||
172 | |||
173 | free_irq(pc110pad_irq, NULL); | ||
174 | release_region(pc110pad_io, 4); | ||
175 | } | ||
176 | |||
177 | module_init(pc110pad_init); | ||
178 | module_exit(pc110pad_exit); | ||
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c new file mode 100644 index 000000000000..cd8509549eac --- /dev/null +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -0,0 +1,1011 @@ | |||
1 | /* | ||
2 | * PS/2 mouse driver | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * Copyright (c) 2003-2004 Dmitry Torokhov | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/serio.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/libps2.h> | ||
23 | #include "psmouse.h" | ||
24 | #include "synaptics.h" | ||
25 | #include "logips2pp.h" | ||
26 | #include "alps.h" | ||
27 | |||
28 | #define DRIVER_DESC "PS/2 mouse driver" | ||
29 | |||
30 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | ||
31 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | static unsigned int psmouse_max_proto = -1U; | ||
35 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp); | ||
36 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp); | ||
37 | static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL }; | ||
38 | #define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int) | ||
39 | #define param_set_proto_abbrev psmouse_set_maxproto | ||
40 | #define param_get_proto_abbrev psmouse_get_maxproto | ||
41 | module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644); | ||
42 | MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches."); | ||
43 | |||
44 | static unsigned int psmouse_resolution = 200; | ||
45 | module_param_named(resolution, psmouse_resolution, uint, 0644); | ||
46 | MODULE_PARM_DESC(resolution, "Resolution, in dpi."); | ||
47 | |||
48 | static unsigned int psmouse_rate = 100; | ||
49 | module_param_named(rate, psmouse_rate, uint, 0644); | ||
50 | MODULE_PARM_DESC(rate, "Report rate, in reports per second."); | ||
51 | |||
52 | static unsigned int psmouse_smartscroll = 1; | ||
53 | module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); | ||
54 | MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); | ||
55 | |||
56 | static unsigned int psmouse_resetafter; | ||
57 | module_param_named(resetafter, psmouse_resetafter, uint, 0644); | ||
58 | MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); | ||
59 | |||
60 | PSMOUSE_DEFINE_ATTR(rate); | ||
61 | PSMOUSE_DEFINE_ATTR(resolution); | ||
62 | PSMOUSE_DEFINE_ATTR(resetafter); | ||
63 | |||
64 | __obsolete_setup("psmouse_noext"); | ||
65 | __obsolete_setup("psmouse_resolution="); | ||
66 | __obsolete_setup("psmouse_smartscroll="); | ||
67 | __obsolete_setup("psmouse_resetafter="); | ||
68 | __obsolete_setup("psmouse_rate="); | ||
69 | |||
70 | static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" }; | ||
71 | |||
72 | /* | ||
73 | * psmouse_process_byte() analyzes the PS/2 data stream and reports | ||
74 | * relevant events to the input module once full packet has arrived. | ||
75 | */ | ||
76 | |||
77 | static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs) | ||
78 | { | ||
79 | struct input_dev *dev = &psmouse->dev; | ||
80 | unsigned char *packet = psmouse->packet; | ||
81 | |||
82 | if (psmouse->pktcnt < psmouse->pktsize) | ||
83 | return PSMOUSE_GOOD_DATA; | ||
84 | |||
85 | /* | ||
86 | * Full packet accumulated, process it | ||
87 | */ | ||
88 | |||
89 | input_regs(dev, regs); | ||
90 | |||
91 | /* | ||
92 | * Scroll wheel on IntelliMice, scroll buttons on NetMice | ||
93 | */ | ||
94 | |||
95 | if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS) | ||
96 | input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); | ||
97 | |||
98 | /* | ||
99 | * Scroll wheel and buttons on IntelliMouse Explorer | ||
100 | */ | ||
101 | |||
102 | if (psmouse->type == PSMOUSE_IMEX) { | ||
103 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); | ||
104 | input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); | ||
105 | input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Extra buttons on Genius NewNet 3D | ||
110 | */ | ||
111 | |||
112 | if (psmouse->type == PSMOUSE_GENPS) { | ||
113 | input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1); | ||
114 | input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1); | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Extra button on ThinkingMouse | ||
119 | */ | ||
120 | if (psmouse->type == PSMOUSE_THINKPS) { | ||
121 | input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1); | ||
122 | /* Without this bit of weirdness moving up gives wildly high Y changes. */ | ||
123 | packet[1] |= (packet[0] & 0x40) << 1; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Generic PS/2 Mouse | ||
128 | */ | ||
129 | |||
130 | input_report_key(dev, BTN_LEFT, packet[0] & 1); | ||
131 | input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); | ||
132 | input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); | ||
133 | |||
134 | input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); | ||
135 | input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); | ||
136 | |||
137 | input_sync(dev); | ||
138 | |||
139 | return PSMOUSE_FULL_PACKET; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * psmouse_interrupt() handles incoming characters, either gathering them into | ||
144 | * packets or passing them to the command routine as command output. | ||
145 | */ | ||
146 | |||
147 | static irqreturn_t psmouse_interrupt(struct serio *serio, | ||
148 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
149 | { | ||
150 | struct psmouse *psmouse = serio_get_drvdata(serio); | ||
151 | psmouse_ret_t rc; | ||
152 | |||
153 | if (psmouse->state == PSMOUSE_IGNORE) | ||
154 | goto out; | ||
155 | |||
156 | if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) { | ||
157 | if (psmouse->state == PSMOUSE_ACTIVATED) | ||
158 | printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", | ||
159 | flags & SERIO_TIMEOUT ? " timeout" : "", | ||
160 | flags & SERIO_PARITY ? " bad parity" : ""); | ||
161 | ps2_cmd_aborted(&psmouse->ps2dev); | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK)) | ||
166 | if (ps2_handle_ack(&psmouse->ps2dev, data)) | ||
167 | goto out; | ||
168 | |||
169 | if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD)) | ||
170 | if (ps2_handle_response(&psmouse->ps2dev, data)) | ||
171 | goto out; | ||
172 | |||
173 | if (psmouse->state == PSMOUSE_INITIALIZING) | ||
174 | goto out; | ||
175 | |||
176 | if (psmouse->state == PSMOUSE_ACTIVATED && | ||
177 | psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { | ||
178 | printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", | ||
179 | psmouse->name, psmouse->phys, psmouse->pktcnt); | ||
180 | psmouse->pktcnt = 0; | ||
181 | } | ||
182 | |||
183 | psmouse->last = jiffies; | ||
184 | psmouse->packet[psmouse->pktcnt++] = data; | ||
185 | |||
186 | if (psmouse->packet[0] == PSMOUSE_RET_BAT) { | ||
187 | if (psmouse->pktcnt == 1) | ||
188 | goto out; | ||
189 | |||
190 | if (psmouse->pktcnt == 2) { | ||
191 | if (psmouse->packet[1] == PSMOUSE_RET_ID) { | ||
192 | psmouse->state = PSMOUSE_IGNORE; | ||
193 | serio_reconnect(serio); | ||
194 | goto out; | ||
195 | } | ||
196 | if (psmouse->type == PSMOUSE_SYNAPTICS) { | ||
197 | /* neither 0xAA nor 0x00 are valid first bytes | ||
198 | * for a packet in absolute mode | ||
199 | */ | ||
200 | psmouse->pktcnt = 0; | ||
201 | goto out; | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | |||
206 | rc = psmouse->protocol_handler(psmouse, regs); | ||
207 | |||
208 | switch (rc) { | ||
209 | case PSMOUSE_BAD_DATA: | ||
210 | printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", | ||
211 | psmouse->name, psmouse->phys, psmouse->pktcnt); | ||
212 | psmouse->pktcnt = 0; | ||
213 | |||
214 | if (++psmouse->out_of_sync == psmouse->resetafter) { | ||
215 | psmouse->state = PSMOUSE_IGNORE; | ||
216 | printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); | ||
217 | serio_reconnect(psmouse->ps2dev.serio); | ||
218 | } | ||
219 | break; | ||
220 | |||
221 | case PSMOUSE_FULL_PACKET: | ||
222 | psmouse->pktcnt = 0; | ||
223 | if (psmouse->out_of_sync) { | ||
224 | psmouse->out_of_sync = 0; | ||
225 | printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", | ||
226 | psmouse->name, psmouse->phys); | ||
227 | } | ||
228 | break; | ||
229 | |||
230 | case PSMOUSE_GOOD_DATA: | ||
231 | break; | ||
232 | } | ||
233 | out: | ||
234 | return IRQ_HANDLED; | ||
235 | } | ||
236 | |||
237 | |||
238 | /* | ||
239 | * psmouse_sliced_command() sends an extended PS/2 command to the mouse | ||
240 | * using sliced syntax, understood by advanced devices, such as Logitech | ||
241 | * or Synaptics touchpads. The command is encoded as: | ||
242 | * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu | ||
243 | * is the command. | ||
244 | */ | ||
245 | int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command) | ||
246 | { | ||
247 | int i; | ||
248 | |||
249 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) | ||
250 | return -1; | ||
251 | |||
252 | for (i = 6; i >= 0; i -= 2) { | ||
253 | unsigned char d = (command >> i) & 3; | ||
254 | if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES)) | ||
255 | return -1; | ||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | |||
262 | /* | ||
263 | * psmouse_reset() resets the mouse into power-on state. | ||
264 | */ | ||
265 | int psmouse_reset(struct psmouse *psmouse) | ||
266 | { | ||
267 | unsigned char param[2]; | ||
268 | |||
269 | if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT)) | ||
270 | return -1; | ||
271 | |||
272 | if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID) | ||
273 | return -1; | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | |||
279 | /* | ||
280 | * Genius NetMouse magic init. | ||
281 | */ | ||
282 | static int genius_detect(struct psmouse *psmouse, int set_properties) | ||
283 | { | ||
284 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
285 | unsigned char param[4]; | ||
286 | |||
287 | param[0] = 3; | ||
288 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
289 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
290 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
291 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
292 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); | ||
293 | |||
294 | if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55) | ||
295 | return -1; | ||
296 | |||
297 | if (set_properties) { | ||
298 | set_bit(BTN_EXTRA, psmouse->dev.keybit); | ||
299 | set_bit(BTN_SIDE, psmouse->dev.keybit); | ||
300 | set_bit(REL_WHEEL, psmouse->dev.relbit); | ||
301 | |||
302 | psmouse->vendor = "Genius"; | ||
303 | psmouse->name = "Wheel Mouse"; | ||
304 | psmouse->pktsize = 4; | ||
305 | } | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * IntelliMouse magic init. | ||
312 | */ | ||
313 | static int intellimouse_detect(struct psmouse *psmouse, int set_properties) | ||
314 | { | ||
315 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
316 | unsigned char param[2]; | ||
317 | |||
318 | param[0] = 200; | ||
319 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
320 | param[0] = 100; | ||
321 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
322 | param[0] = 80; | ||
323 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
324 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); | ||
325 | |||
326 | if (param[0] != 3) | ||
327 | return -1; | ||
328 | |||
329 | if (set_properties) { | ||
330 | set_bit(REL_WHEEL, psmouse->dev.relbit); | ||
331 | |||
332 | if (!psmouse->vendor) psmouse->vendor = "Generic"; | ||
333 | if (!psmouse->name) psmouse->name = "Wheel Mouse"; | ||
334 | psmouse->pktsize = 4; | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * Try IntelliMouse/Explorer magic init. | ||
342 | */ | ||
343 | static int im_explorer_detect(struct psmouse *psmouse, int set_properties) | ||
344 | { | ||
345 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
346 | unsigned char param[2]; | ||
347 | |||
348 | intellimouse_detect(psmouse, 0); | ||
349 | |||
350 | param[0] = 200; | ||
351 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
352 | param[0] = 200; | ||
353 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
354 | param[0] = 80; | ||
355 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
356 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); | ||
357 | |||
358 | if (param[0] != 4) | ||
359 | return -1; | ||
360 | |||
361 | if (set_properties) { | ||
362 | set_bit(REL_WHEEL, psmouse->dev.relbit); | ||
363 | set_bit(BTN_SIDE, psmouse->dev.keybit); | ||
364 | set_bit(BTN_EXTRA, psmouse->dev.keybit); | ||
365 | |||
366 | if (!psmouse->vendor) psmouse->vendor = "Generic"; | ||
367 | if (!psmouse->name) psmouse->name = "Explorer Mouse"; | ||
368 | psmouse->pktsize = 4; | ||
369 | } | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Kensington ThinkingMouse / ExpertMouse magic init. | ||
376 | */ | ||
377 | static int thinking_detect(struct psmouse *psmouse, int set_properties) | ||
378 | { | ||
379 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
380 | unsigned char param[2]; | ||
381 | unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 }; | ||
382 | int i; | ||
383 | |||
384 | param[0] = 10; | ||
385 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
386 | param[0] = 0; | ||
387 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
388 | for (i = 0; seq[i]; i++) | ||
389 | ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE); | ||
390 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); | ||
391 | |||
392 | if (param[0] != 2) | ||
393 | return -1; | ||
394 | |||
395 | if (set_properties) { | ||
396 | set_bit(BTN_EXTRA, psmouse->dev.keybit); | ||
397 | |||
398 | psmouse->vendor = "Kensington"; | ||
399 | psmouse->name = "ThinkingMouse"; | ||
400 | } | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * Bare PS/2 protocol "detection". Always succeeds. | ||
407 | */ | ||
408 | static int ps2bare_detect(struct psmouse *psmouse, int set_properties) | ||
409 | { | ||
410 | if (!psmouse->vendor) psmouse->vendor = "Generic"; | ||
411 | if (!psmouse->name) psmouse->name = "Mouse"; | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * psmouse_extensions() probes for any extensions to the basic PS/2 protocol | ||
418 | * the mouse may have. | ||
419 | */ | ||
420 | |||
421 | static int psmouse_extensions(struct psmouse *psmouse, | ||
422 | unsigned int max_proto, int set_properties) | ||
423 | { | ||
424 | int synaptics_hardware = 0; | ||
425 | |||
426 | /* | ||
427 | * Try Kensington ThinkingMouse (we try first, because synaptics probe | ||
428 | * upsets the thinkingmouse). | ||
429 | */ | ||
430 | |||
431 | if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0) | ||
432 | return PSMOUSE_THINKPS; | ||
433 | |||
434 | /* | ||
435 | * Try Synaptics TouchPad | ||
436 | */ | ||
437 | if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) { | ||
438 | synaptics_hardware = 1; | ||
439 | |||
440 | if (max_proto > PSMOUSE_IMEX) { | ||
441 | if (!set_properties || synaptics_init(psmouse) == 0) | ||
442 | return PSMOUSE_SYNAPTICS; | ||
443 | /* | ||
444 | * Some Synaptics touchpads can emulate extended protocols (like IMPS/2). | ||
445 | * Unfortunately Logitech/Genius probes confuse some firmware versions so | ||
446 | * we'll have to skip them. | ||
447 | */ | ||
448 | max_proto = PSMOUSE_IMEX; | ||
449 | } | ||
450 | /* | ||
451 | * Make sure that touchpad is in relative mode, gestures (taps) are enabled | ||
452 | */ | ||
453 | synaptics_reset(psmouse); | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * Try ALPS TouchPad | ||
458 | */ | ||
459 | if (max_proto > PSMOUSE_IMEX) { | ||
460 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); | ||
461 | if (alps_detect(psmouse, set_properties) == 0) { | ||
462 | if (!set_properties || alps_init(psmouse) == 0) | ||
463 | return PSMOUSE_ALPS; | ||
464 | /* | ||
465 | * Init failed, try basic relative protocols | ||
466 | */ | ||
467 | max_proto = PSMOUSE_IMEX; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0) | ||
472 | return PSMOUSE_GENPS; | ||
473 | |||
474 | if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0) | ||
475 | return PSMOUSE_PS2PP; | ||
476 | |||
477 | /* | ||
478 | * Reset to defaults in case the device got confused by extended | ||
479 | * protocol probes. | ||
480 | */ | ||
481 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); | ||
482 | |||
483 | if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0) | ||
484 | return PSMOUSE_IMEX; | ||
485 | |||
486 | if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0) | ||
487 | return PSMOUSE_IMPS; | ||
488 | |||
489 | /* | ||
490 | * Okay, all failed, we have a standard mouse here. The number of the buttons | ||
491 | * is still a question, though. We assume 3. | ||
492 | */ | ||
493 | ps2bare_detect(psmouse, set_properties); | ||
494 | |||
495 | if (synaptics_hardware) { | ||
496 | /* | ||
497 | * We detected Synaptics hardware but it did not respond to IMPS/2 probes. | ||
498 | * We need to reset the touchpad because if there is a track point on the | ||
499 | * pass through port it could get disabled while probing for protocol | ||
500 | * extensions. | ||
501 | */ | ||
502 | psmouse_reset(psmouse); | ||
503 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); | ||
504 | } | ||
505 | |||
506 | return PSMOUSE_PS2; | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * psmouse_probe() probes for a PS/2 mouse. | ||
511 | */ | ||
512 | |||
513 | static int psmouse_probe(struct psmouse *psmouse) | ||
514 | { | ||
515 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
516 | unsigned char param[2]; | ||
517 | |||
518 | /* | ||
519 | * First, we check if it's a mouse. It should send 0x00 or 0x03 | ||
520 | * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. | ||
521 | */ | ||
522 | |||
523 | param[0] = 0xa5; | ||
524 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) | ||
525 | return -1; | ||
526 | |||
527 | if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) | ||
528 | return -1; | ||
529 | |||
530 | /* | ||
531 | * Then we reset and disable the mouse so that it doesn't generate events. | ||
532 | */ | ||
533 | |||
534 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS)) | ||
535 | printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys); | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * Here we set the mouse resolution. | ||
542 | */ | ||
543 | |||
544 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) | ||
545 | { | ||
546 | unsigned char params[] = { 0, 1, 2, 2, 3 }; | ||
547 | |||
548 | if (resolution == 0 || resolution > 200) | ||
549 | resolution = 200; | ||
550 | |||
551 | ps2_command(&psmouse->ps2dev, ¶ms[resolution / 50], PSMOUSE_CMD_SETRES); | ||
552 | psmouse->resolution = 25 << params[resolution / 50]; | ||
553 | } | ||
554 | |||
555 | /* | ||
556 | * Here we set the mouse report rate. | ||
557 | */ | ||
558 | |||
559 | static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) | ||
560 | { | ||
561 | unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; | ||
562 | int i = 0; | ||
563 | |||
564 | while (rates[i] > rate) i++; | ||
565 | ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE); | ||
566 | psmouse->rate = rates[i]; | ||
567 | } | ||
568 | |||
569 | /* | ||
570 | * psmouse_initialize() initializes the mouse to a sane state. | ||
571 | */ | ||
572 | |||
573 | static void psmouse_initialize(struct psmouse *psmouse) | ||
574 | { | ||
575 | /* | ||
576 | * We set the mouse into streaming mode. | ||
577 | */ | ||
578 | |||
579 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM); | ||
580 | |||
581 | /* | ||
582 | * We set the mouse report rate, resolution and scaling. | ||
583 | */ | ||
584 | |||
585 | if (psmouse_max_proto != PSMOUSE_PS2) { | ||
586 | psmouse->set_rate(psmouse, psmouse->rate); | ||
587 | psmouse->set_resolution(psmouse, psmouse->resolution); | ||
588 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | /* | ||
593 | * psmouse_set_state() sets new psmouse state and resets all flags and | ||
594 | * counters while holding serio lock so fighting with interrupt handler | ||
595 | * is not a concern. | ||
596 | */ | ||
597 | |||
598 | static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) | ||
599 | { | ||
600 | serio_pause_rx(psmouse->ps2dev.serio); | ||
601 | psmouse->state = new_state; | ||
602 | psmouse->pktcnt = psmouse->out_of_sync = 0; | ||
603 | psmouse->ps2dev.flags = 0; | ||
604 | serio_continue_rx(psmouse->ps2dev.serio); | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * psmouse_activate() enables the mouse so that we get motion reports from it. | ||
609 | */ | ||
610 | |||
611 | static void psmouse_activate(struct psmouse *psmouse) | ||
612 | { | ||
613 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) | ||
614 | printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", | ||
615 | psmouse->ps2dev.serio->phys); | ||
616 | |||
617 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | ||
618 | } | ||
619 | |||
620 | |||
621 | /* | ||
622 | * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion | ||
623 | * reports from it unless we explicitely request it. | ||
624 | */ | ||
625 | |||
626 | static void psmouse_deactivate(struct psmouse *psmouse) | ||
627 | { | ||
628 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) | ||
629 | printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", | ||
630 | psmouse->ps2dev.serio->phys); | ||
631 | |||
632 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
633 | } | ||
634 | |||
635 | |||
636 | /* | ||
637 | * psmouse_cleanup() resets the mouse into power-on state. | ||
638 | */ | ||
639 | |||
640 | static void psmouse_cleanup(struct serio *serio) | ||
641 | { | ||
642 | struct psmouse *psmouse = serio_get_drvdata(serio); | ||
643 | |||
644 | psmouse_reset(psmouse); | ||
645 | } | ||
646 | |||
647 | /* | ||
648 | * psmouse_disconnect() closes and frees. | ||
649 | */ | ||
650 | |||
651 | static void psmouse_disconnect(struct serio *serio) | ||
652 | { | ||
653 | struct psmouse *psmouse, *parent; | ||
654 | |||
655 | device_remove_file(&serio->dev, &psmouse_attr_rate); | ||
656 | device_remove_file(&serio->dev, &psmouse_attr_resolution); | ||
657 | device_remove_file(&serio->dev, &psmouse_attr_resetafter); | ||
658 | |||
659 | psmouse = serio_get_drvdata(serio); | ||
660 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
661 | |||
662 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | ||
663 | parent = serio_get_drvdata(serio->parent); | ||
664 | if (parent->pt_deactivate) | ||
665 | parent->pt_deactivate(parent); | ||
666 | } | ||
667 | |||
668 | if (psmouse->disconnect) | ||
669 | psmouse->disconnect(psmouse); | ||
670 | |||
671 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
672 | |||
673 | input_unregister_device(&psmouse->dev); | ||
674 | serio_close(serio); | ||
675 | serio_set_drvdata(serio, NULL); | ||
676 | kfree(psmouse); | ||
677 | } | ||
678 | |||
679 | /* | ||
680 | * psmouse_connect() is a callback from the serio module when | ||
681 | * an unhandled serio port is found. | ||
682 | */ | ||
683 | static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | ||
684 | { | ||
685 | struct psmouse *psmouse, *parent = NULL; | ||
686 | int retval; | ||
687 | |||
688 | /* | ||
689 | * If this is a pass-through port deactivate parent so the device | ||
690 | * connected to this port can be successfully identified | ||
691 | */ | ||
692 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | ||
693 | parent = serio_get_drvdata(serio->parent); | ||
694 | psmouse_deactivate(parent); | ||
695 | } | ||
696 | |||
697 | if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) { | ||
698 | retval = -ENOMEM; | ||
699 | goto out; | ||
700 | } | ||
701 | |||
702 | memset(psmouse, 0, sizeof(struct psmouse)); | ||
703 | |||
704 | ps2_init(&psmouse->ps2dev, serio); | ||
705 | sprintf(psmouse->phys, "%s/input0", serio->phys); | ||
706 | psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
707 | psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
708 | psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
709 | psmouse->dev.private = psmouse; | ||
710 | psmouse->dev.dev = &serio->dev; | ||
711 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | ||
712 | |||
713 | serio_set_drvdata(serio, psmouse); | ||
714 | |||
715 | retval = serio_open(serio, drv); | ||
716 | if (retval) { | ||
717 | serio_set_drvdata(serio, NULL); | ||
718 | kfree(psmouse); | ||
719 | goto out; | ||
720 | } | ||
721 | |||
722 | if (psmouse_probe(psmouse) < 0) { | ||
723 | serio_close(serio); | ||
724 | serio_set_drvdata(serio, NULL); | ||
725 | kfree(psmouse); | ||
726 | retval = -ENODEV; | ||
727 | goto out; | ||
728 | } | ||
729 | |||
730 | psmouse->rate = psmouse_rate; | ||
731 | psmouse->resolution = psmouse_resolution; | ||
732 | psmouse->resetafter = psmouse_resetafter; | ||
733 | psmouse->smartscroll = psmouse_smartscroll; | ||
734 | psmouse->set_rate = psmouse_set_rate; | ||
735 | psmouse->set_resolution = psmouse_set_resolution; | ||
736 | psmouse->protocol_handler = psmouse_process_byte; | ||
737 | psmouse->pktsize = 3; | ||
738 | |||
739 | psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); | ||
740 | |||
741 | sprintf(psmouse->devname, "%s %s %s", | ||
742 | psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); | ||
743 | |||
744 | psmouse->dev.name = psmouse->devname; | ||
745 | psmouse->dev.phys = psmouse->phys; | ||
746 | psmouse->dev.id.bustype = BUS_I8042; | ||
747 | psmouse->dev.id.vendor = 0x0002; | ||
748 | psmouse->dev.id.product = psmouse->type; | ||
749 | psmouse->dev.id.version = psmouse->model; | ||
750 | |||
751 | input_register_device(&psmouse->dev); | ||
752 | |||
753 | printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); | ||
754 | |||
755 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
756 | |||
757 | psmouse_initialize(psmouse); | ||
758 | |||
759 | if (parent && parent->pt_activate) | ||
760 | parent->pt_activate(parent); | ||
761 | |||
762 | device_create_file(&serio->dev, &psmouse_attr_rate); | ||
763 | device_create_file(&serio->dev, &psmouse_attr_resolution); | ||
764 | device_create_file(&serio->dev, &psmouse_attr_resetafter); | ||
765 | |||
766 | psmouse_activate(psmouse); | ||
767 | |||
768 | retval = 0; | ||
769 | |||
770 | out: | ||
771 | /* If this is a pass-through port the parent awaits to be activated */ | ||
772 | if (parent) | ||
773 | psmouse_activate(parent); | ||
774 | |||
775 | return retval; | ||
776 | } | ||
777 | |||
778 | |||
779 | static int psmouse_reconnect(struct serio *serio) | ||
780 | { | ||
781 | struct psmouse *psmouse = serio_get_drvdata(serio); | ||
782 | struct psmouse *parent = NULL; | ||
783 | struct serio_driver *drv = serio->drv; | ||
784 | int rc = -1; | ||
785 | |||
786 | if (!drv || !psmouse) { | ||
787 | printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); | ||
788 | return -1; | ||
789 | } | ||
790 | |||
791 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | ||
792 | parent = serio_get_drvdata(serio->parent); | ||
793 | psmouse_deactivate(parent); | ||
794 | } | ||
795 | |||
796 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | ||
797 | |||
798 | if (psmouse->reconnect) { | ||
799 | if (psmouse->reconnect(psmouse)) | ||
800 | goto out; | ||
801 | } else if (psmouse_probe(psmouse) < 0 || | ||
802 | psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0)) | ||
803 | goto out; | ||
804 | |||
805 | /* ok, the device type (and capabilities) match the old one, | ||
806 | * we can continue using it, complete intialization | ||
807 | */ | ||
808 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
809 | |||
810 | psmouse_initialize(psmouse); | ||
811 | |||
812 | if (parent && parent->pt_activate) | ||
813 | parent->pt_activate(parent); | ||
814 | |||
815 | psmouse_activate(psmouse); | ||
816 | rc = 0; | ||
817 | |||
818 | out: | ||
819 | /* If this is a pass-through port the parent waits to be activated */ | ||
820 | if (parent) | ||
821 | psmouse_activate(parent); | ||
822 | |||
823 | return rc; | ||
824 | } | ||
825 | |||
826 | static struct serio_device_id psmouse_serio_ids[] = { | ||
827 | { | ||
828 | .type = SERIO_8042, | ||
829 | .proto = SERIO_ANY, | ||
830 | .id = SERIO_ANY, | ||
831 | .extra = SERIO_ANY, | ||
832 | }, | ||
833 | { | ||
834 | .type = SERIO_PS_PSTHRU, | ||
835 | .proto = SERIO_ANY, | ||
836 | .id = SERIO_ANY, | ||
837 | .extra = SERIO_ANY, | ||
838 | }, | ||
839 | { 0 } | ||
840 | }; | ||
841 | |||
842 | MODULE_DEVICE_TABLE(serio, psmouse_serio_ids); | ||
843 | |||
844 | static struct serio_driver psmouse_drv = { | ||
845 | .driver = { | ||
846 | .name = "psmouse", | ||
847 | }, | ||
848 | .description = DRIVER_DESC, | ||
849 | .id_table = psmouse_serio_ids, | ||
850 | .interrupt = psmouse_interrupt, | ||
851 | .connect = psmouse_connect, | ||
852 | .reconnect = psmouse_reconnect, | ||
853 | .disconnect = psmouse_disconnect, | ||
854 | .cleanup = psmouse_cleanup, | ||
855 | }; | ||
856 | |||
857 | ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, | ||
858 | ssize_t (*handler)(struct psmouse *, char *)) | ||
859 | { | ||
860 | struct serio *serio = to_serio_port(dev); | ||
861 | int retval; | ||
862 | |||
863 | retval = serio_pin_driver(serio); | ||
864 | if (retval) | ||
865 | return retval; | ||
866 | |||
867 | if (serio->drv != &psmouse_drv) { | ||
868 | retval = -ENODEV; | ||
869 | goto out; | ||
870 | } | ||
871 | |||
872 | retval = handler(serio_get_drvdata(serio), buf); | ||
873 | |||
874 | out: | ||
875 | serio_unpin_driver(serio); | ||
876 | return retval; | ||
877 | } | ||
878 | |||
879 | ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, | ||
880 | ssize_t (*handler)(struct psmouse *, const char *, size_t)) | ||
881 | { | ||
882 | struct serio *serio = to_serio_port(dev); | ||
883 | struct psmouse *psmouse = serio_get_drvdata(serio); | ||
884 | struct psmouse *parent = NULL; | ||
885 | int retval; | ||
886 | |||
887 | retval = serio_pin_driver(serio); | ||
888 | if (retval) | ||
889 | return retval; | ||
890 | |||
891 | if (serio->drv != &psmouse_drv) { | ||
892 | retval = -ENODEV; | ||
893 | goto out; | ||
894 | } | ||
895 | |||
896 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | ||
897 | parent = serio_get_drvdata(serio->parent); | ||
898 | psmouse_deactivate(parent); | ||
899 | } | ||
900 | psmouse_deactivate(psmouse); | ||
901 | |||
902 | retval = handler(psmouse, buf, count); | ||
903 | |||
904 | psmouse_activate(psmouse); | ||
905 | if (parent) | ||
906 | psmouse_activate(parent); | ||
907 | |||
908 | out: | ||
909 | serio_unpin_driver(serio); | ||
910 | return retval; | ||
911 | } | ||
912 | |||
913 | static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf) | ||
914 | { | ||
915 | return sprintf(buf, "%d\n", psmouse->rate); | ||
916 | } | ||
917 | |||
918 | static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, size_t count) | ||
919 | { | ||
920 | unsigned long value; | ||
921 | char *rest; | ||
922 | |||
923 | value = simple_strtoul(buf, &rest, 10); | ||
924 | if (*rest) | ||
925 | return -EINVAL; | ||
926 | |||
927 | psmouse->set_rate(psmouse, value); | ||
928 | return count; | ||
929 | } | ||
930 | |||
931 | static ssize_t psmouse_attr_show_resolution(struct psmouse *psmouse, char *buf) | ||
932 | { | ||
933 | return sprintf(buf, "%d\n", psmouse->resolution); | ||
934 | } | ||
935 | |||
936 | static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *buf, size_t count) | ||
937 | { | ||
938 | unsigned long value; | ||
939 | char *rest; | ||
940 | |||
941 | value = simple_strtoul(buf, &rest, 10); | ||
942 | if (*rest) | ||
943 | return -EINVAL; | ||
944 | |||
945 | psmouse->set_resolution(psmouse, value); | ||
946 | return count; | ||
947 | } | ||
948 | |||
949 | static ssize_t psmouse_attr_show_resetafter(struct psmouse *psmouse, char *buf) | ||
950 | { | ||
951 | return sprintf(buf, "%d\n", psmouse->resetafter); | ||
952 | } | ||
953 | |||
954 | static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *buf, size_t count) | ||
955 | { | ||
956 | unsigned long value; | ||
957 | char *rest; | ||
958 | |||
959 | value = simple_strtoul(buf, &rest, 10); | ||
960 | if (*rest) | ||
961 | return -EINVAL; | ||
962 | |||
963 | psmouse->resetafter = value; | ||
964 | return count; | ||
965 | } | ||
966 | |||
967 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) | ||
968 | { | ||
969 | int i; | ||
970 | |||
971 | if (!val) | ||
972 | return -EINVAL; | ||
973 | |||
974 | if (!strncmp(val, "any", 3)) { | ||
975 | *((unsigned int *)kp->arg) = -1UL; | ||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) { | ||
980 | if (!psmouse_proto_abbrev[i]) | ||
981 | continue; | ||
982 | |||
983 | if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) { | ||
984 | *((unsigned int *)kp->arg) = i; | ||
985 | return 0; | ||
986 | } | ||
987 | } | ||
988 | |||
989 | return -EINVAL; \ | ||
990 | } | ||
991 | |||
992 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) | ||
993 | { | ||
994 | return sprintf(buffer, "%s\n", | ||
995 | psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ? | ||
996 | psmouse_proto_abbrev[psmouse_max_proto] : "any"); | ||
997 | } | ||
998 | |||
999 | static int __init psmouse_init(void) | ||
1000 | { | ||
1001 | serio_register_driver(&psmouse_drv); | ||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | static void __exit psmouse_exit(void) | ||
1006 | { | ||
1007 | serio_unregister_driver(&psmouse_drv); | ||
1008 | } | ||
1009 | |||
1010 | module_init(psmouse_init); | ||
1011 | module_exit(psmouse_exit); | ||
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h new file mode 100644 index 000000000000..bda5b065d03c --- /dev/null +++ b/drivers/input/mouse/psmouse.h | |||
@@ -0,0 +1,106 @@ | |||
1 | #ifndef _PSMOUSE_H | ||
2 | #define _PSMOUSE_H | ||
3 | |||
4 | #define PSMOUSE_CMD_SETSCALE11 0x00e6 | ||
5 | #define PSMOUSE_CMD_SETSCALE21 0x00e7 | ||
6 | #define PSMOUSE_CMD_SETRES 0x10e8 | ||
7 | #define PSMOUSE_CMD_GETINFO 0x03e9 | ||
8 | #define PSMOUSE_CMD_SETSTREAM 0x00ea | ||
9 | #define PSMOUSE_CMD_SETPOLL 0x00f0 | ||
10 | #define PSMOUSE_CMD_POLL 0x03eb | ||
11 | #define PSMOUSE_CMD_GETID 0x02f2 | ||
12 | #define PSMOUSE_CMD_SETRATE 0x10f3 | ||
13 | #define PSMOUSE_CMD_ENABLE 0x00f4 | ||
14 | #define PSMOUSE_CMD_DISABLE 0x00f5 | ||
15 | #define PSMOUSE_CMD_RESET_DIS 0x00f6 | ||
16 | #define PSMOUSE_CMD_RESET_BAT 0x02ff | ||
17 | |||
18 | #define PSMOUSE_RET_BAT 0xaa | ||
19 | #define PSMOUSE_RET_ID 0x00 | ||
20 | #define PSMOUSE_RET_ACK 0xfa | ||
21 | #define PSMOUSE_RET_NAK 0xfe | ||
22 | |||
23 | enum psmouse_state { | ||
24 | PSMOUSE_IGNORE, | ||
25 | PSMOUSE_INITIALIZING, | ||
26 | PSMOUSE_CMD_MODE, | ||
27 | PSMOUSE_ACTIVATED, | ||
28 | }; | ||
29 | |||
30 | /* psmouse protocol handler return codes */ | ||
31 | typedef enum { | ||
32 | PSMOUSE_BAD_DATA, | ||
33 | PSMOUSE_GOOD_DATA, | ||
34 | PSMOUSE_FULL_PACKET | ||
35 | } psmouse_ret_t; | ||
36 | |||
37 | struct psmouse { | ||
38 | void *private; | ||
39 | struct input_dev dev; | ||
40 | struct ps2dev ps2dev; | ||
41 | char *vendor; | ||
42 | char *name; | ||
43 | unsigned char packet[8]; | ||
44 | unsigned char pktcnt; | ||
45 | unsigned char pktsize; | ||
46 | unsigned char type; | ||
47 | unsigned int model; | ||
48 | unsigned long last; | ||
49 | unsigned long out_of_sync; | ||
50 | enum psmouse_state state; | ||
51 | char devname[64]; | ||
52 | char phys[32]; | ||
53 | |||
54 | unsigned int rate; | ||
55 | unsigned int resolution; | ||
56 | unsigned int resetafter; | ||
57 | unsigned int smartscroll; /* Logitech only */ | ||
58 | |||
59 | psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); | ||
60 | void (*set_rate)(struct psmouse *psmouse, unsigned int rate); | ||
61 | void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution); | ||
62 | |||
63 | int (*reconnect)(struct psmouse *psmouse); | ||
64 | void (*disconnect)(struct psmouse *psmouse); | ||
65 | |||
66 | void (*pt_activate)(struct psmouse *psmouse); | ||
67 | void (*pt_deactivate)(struct psmouse *psmouse); | ||
68 | }; | ||
69 | |||
70 | enum psmouse_type { | ||
71 | PSMOUSE_NONE, | ||
72 | PSMOUSE_PS2, | ||
73 | PSMOUSE_PS2PP, | ||
74 | PSMOUSE_THINKPS, | ||
75 | PSMOUSE_GENPS, | ||
76 | PSMOUSE_IMPS, | ||
77 | PSMOUSE_IMEX, | ||
78 | PSMOUSE_SYNAPTICS, | ||
79 | PSMOUSE_ALPS, | ||
80 | }; | ||
81 | |||
82 | int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); | ||
83 | int psmouse_reset(struct psmouse *psmouse); | ||
84 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); | ||
85 | |||
86 | ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, | ||
87 | ssize_t (*handler)(struct psmouse *, char *)); | ||
88 | ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, | ||
89 | ssize_t (*handler)(struct psmouse *, const char *, size_t)); | ||
90 | |||
91 | #define PSMOUSE_DEFINE_ATTR(_name) \ | ||
92 | static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *); \ | ||
93 | static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\ | ||
94 | static ssize_t psmouse_do_show_##_name(struct device *d, char *b) \ | ||
95 | { \ | ||
96 | return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name); \ | ||
97 | } \ | ||
98 | static ssize_t psmouse_do_set_##_name(struct device *d, const char *b, size_t s)\ | ||
99 | { \ | ||
100 | return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \ | ||
101 | } \ | ||
102 | static struct device_attribute psmouse_attr_##_name = \ | ||
103 | __ATTR(_name, S_IWUSR | S_IRUGO, \ | ||
104 | psmouse_do_show_##_name, psmouse_do_set_##_name); | ||
105 | |||
106 | #endif /* _PSMOUSE_H */ | ||
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c new file mode 100644 index 000000000000..7280f68afcee --- /dev/null +++ b/drivers/input/mouse/rpcmouse.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Acorn RiscPC mouse driver for Linux/ARM | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik | ||
5 | * Copyright (C) 1996-2002 Russell King | ||
6 | * | ||
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 | * This handles the Acorn RiscPCs mouse. We basically have a couple of | ||
15 | * hardware registers that track the sensor count for the X-Y movement and | ||
16 | * another register holding the button state. On every VSYNC interrupt we read | ||
17 | * the complete state and then work out if something has changed. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/ptrace.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/input.h> | ||
26 | |||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/hardware/iomd.h> | ||
31 | |||
32 | MODULE_AUTHOR("Vojtech Pavlik, Russell King"); | ||
33 | MODULE_DESCRIPTION("Acorn RiscPC mouse driver"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static short rpcmouse_lastx, rpcmouse_lasty; | ||
37 | |||
38 | static struct input_dev rpcmouse_dev = { | ||
39 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | ||
40 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, | ||
41 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | ||
42 | .name = "Acorn RiscPC Mouse", | ||
43 | .phys = "rpcmouse/input0", | ||
44 | .id = { | ||
45 | .bustype = BUS_HOST, | ||
46 | .vendor = 0x0005, | ||
47 | .product = 0x0001, | ||
48 | .version = 0x0100, | ||
49 | }, | ||
50 | }; | ||
51 | |||
52 | static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
53 | { | ||
54 | struct input_dev *dev = dev_id; | ||
55 | short x, y, dx, dy, b; | ||
56 | |||
57 | x = (short) iomd_readl(IOMD_MOUSEX); | ||
58 | y = (short) iomd_readl(IOMD_MOUSEY); | ||
59 | b = (short) (__raw_readl(0xe0310000) ^ 0x70); | ||
60 | |||
61 | dx = x - rpcmouse_lastx; | ||
62 | dy = y - rpcmouse_lasty; | ||
63 | |||
64 | rpcmouse_lastx = x; | ||
65 | rpcmouse_lasty = y; | ||
66 | |||
67 | input_regs(dev, regs); | ||
68 | |||
69 | input_report_rel(dev, REL_X, dx); | ||
70 | input_report_rel(dev, REL_Y, -dy); | ||
71 | |||
72 | input_report_key(dev, BTN_LEFT, b & 0x40); | ||
73 | input_report_key(dev, BTN_MIDDLE, b & 0x20); | ||
74 | input_report_key(dev, BTN_RIGHT, b & 0x10); | ||
75 | |||
76 | input_sync(dev); | ||
77 | |||
78 | return IRQ_HANDLED; | ||
79 | } | ||
80 | |||
81 | static int __init rpcmouse_init(void) | ||
82 | { | ||
83 | init_input_dev(&rpcmouse_dev); | ||
84 | |||
85 | rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX); | ||
86 | rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY); | ||
87 | |||
88 | if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", &rpcmouse_dev)) { | ||
89 | printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n"); | ||
90 | return -1; | ||
91 | } | ||
92 | |||
93 | input_register_device(&rpcmouse_dev); | ||
94 | |||
95 | printk(KERN_INFO "input: Acorn RiscPC mouse\n"); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static void __exit rpcmouse_exit(void) | ||
101 | { | ||
102 | input_unregister_device(&rpcmouse_dev); | ||
103 | free_irq(IRQ_VSYNCPULSE, &rpcmouse_dev); | ||
104 | } | ||
105 | |||
106 | module_init(rpcmouse_init); | ||
107 | module_exit(rpcmouse_exit); | ||
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c new file mode 100644 index 000000000000..d12b93ae3900 --- /dev/null +++ b/drivers/input/mouse/sermouse.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * $Id: sermouse.c,v 1.17 2002/03/13 10:03:43 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Serial mouse 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/delay.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/input.h> | ||
36 | #include <linux/config.h> | ||
37 | #include <linux/serio.h> | ||
38 | #include <linux/init.h> | ||
39 | |||
40 | #define DRIVER_DESC "Serial mouse driver" | ||
41 | |||
42 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
43 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", | ||
47 | "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", | ||
48 | "Logitech MZ++ Mouse"}; | ||
49 | |||
50 | struct sermouse { | ||
51 | struct input_dev dev; | ||
52 | signed char buf[8]; | ||
53 | unsigned char count; | ||
54 | unsigned char type; | ||
55 | unsigned long last; | ||
56 | char phys[32]; | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and | ||
61 | * applies some prediction to the data, resulting in 96 updates per | ||
62 | * second, which is as good as a PS/2 or USB mouse. | ||
63 | */ | ||
64 | |||
65 | static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs) | ||
66 | { | ||
67 | struct input_dev *dev = &sermouse->dev; | ||
68 | signed char *buf = sermouse->buf; | ||
69 | |||
70 | input_regs(dev, regs); | ||
71 | |||
72 | switch (sermouse->count) { | ||
73 | |||
74 | case 0: | ||
75 | if ((data & 0xf8) != 0x80) return; | ||
76 | input_report_key(dev, BTN_LEFT, !(data & 4)); | ||
77 | input_report_key(dev, BTN_RIGHT, !(data & 1)); | ||
78 | input_report_key(dev, BTN_MIDDLE, !(data & 2)); | ||
79 | break; | ||
80 | |||
81 | case 1: | ||
82 | case 3: | ||
83 | input_report_rel(dev, REL_X, data / 2); | ||
84 | input_report_rel(dev, REL_Y, -buf[1]); | ||
85 | buf[0] = data - data / 2; | ||
86 | break; | ||
87 | |||
88 | case 2: | ||
89 | case 4: | ||
90 | input_report_rel(dev, REL_X, buf[0]); | ||
91 | input_report_rel(dev, REL_Y, buf[1] - data); | ||
92 | buf[1] = data / 2; | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | input_sync(dev); | ||
97 | |||
98 | if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1))) | ||
99 | sermouse->count = 0; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and | ||
104 | * generates events. With prediction it gets 80 updates/sec, assuming | ||
105 | * standard 3-byte packets and 1200 bps. | ||
106 | */ | ||
107 | |||
108 | static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs) | ||
109 | { | ||
110 | struct input_dev *dev = &sermouse->dev; | ||
111 | signed char *buf = sermouse->buf; | ||
112 | |||
113 | if (data & 0x40) sermouse->count = 0; | ||
114 | |||
115 | input_regs(dev, regs); | ||
116 | |||
117 | switch (sermouse->count) { | ||
118 | |||
119 | case 0: | ||
120 | buf[1] = data; | ||
121 | input_report_key(dev, BTN_LEFT, (data >> 5) & 1); | ||
122 | input_report_key(dev, BTN_RIGHT, (data >> 4) & 1); | ||
123 | break; | ||
124 | |||
125 | case 1: | ||
126 | buf[2] = data; | ||
127 | data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f)); | ||
128 | input_report_rel(dev, REL_X, data / 2); | ||
129 | input_report_rel(dev, REL_Y, buf[4]); | ||
130 | buf[3] = data - data / 2; | ||
131 | break; | ||
132 | |||
133 | case 2: | ||
134 | /* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */ | ||
135 | if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1])) | ||
136 | input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key)); | ||
137 | buf[0] = buf[1]; | ||
138 | |||
139 | data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f)); | ||
140 | input_report_rel(dev, REL_X, buf[3]); | ||
141 | input_report_rel(dev, REL_Y, data - buf[4]); | ||
142 | buf[4] = data / 2; | ||
143 | break; | ||
144 | |||
145 | case 3: | ||
146 | |||
147 | switch (sermouse->type) { | ||
148 | |||
149 | case SERIO_MS: | ||
150 | sermouse->type = SERIO_MP; | ||
151 | |||
152 | case SERIO_MP: | ||
153 | if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */ | ||
154 | input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1); | ||
155 | input_report_key(dev, BTN_SIDE, (data >> 4) & 1); | ||
156 | break; | ||
157 | |||
158 | case SERIO_MZP: | ||
159 | case SERIO_MZPP: | ||
160 | input_report_key(dev, BTN_SIDE, (data >> 5) & 1); | ||
161 | |||
162 | case SERIO_MZ: | ||
163 | input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1); | ||
164 | input_report_rel(dev, REL_WHEEL, (data & 8) - (data & 7)); | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | break; | ||
169 | |||
170 | case 4: | ||
171 | case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */ | ||
172 | buf[1] = (data >> 2) & 0x0f; | ||
173 | break; | ||
174 | |||
175 | case 5: | ||
176 | case 7: /* Ignore anything besides MZ++ */ | ||
177 | if (sermouse->type != SERIO_MZPP) break; | ||
178 | |||
179 | switch (buf[1]) { | ||
180 | |||
181 | case 1: /* Extra mouse info */ | ||
182 | |||
183 | input_report_key(dev, BTN_SIDE, (data >> 4) & 1); | ||
184 | input_report_key(dev, BTN_EXTRA, (data >> 5) & 1); | ||
185 | input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8)); | ||
186 | |||
187 | break; | ||
188 | |||
189 | default: /* We don't decode anything else yet. */ | ||
190 | |||
191 | printk(KERN_WARNING | ||
192 | "sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]); | ||
193 | break; | ||
194 | } | ||
195 | |||
196 | break; | ||
197 | } | ||
198 | |||
199 | input_sync(dev); | ||
200 | |||
201 | sermouse->count++; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * sermouse_interrupt() handles incoming characters, either gathering them into | ||
206 | * packets or passing them to the command routine as command output. | ||
207 | */ | ||
208 | |||
209 | static irqreturn_t sermouse_interrupt(struct serio *serio, | ||
210 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
211 | { | ||
212 | struct sermouse *sermouse = serio_get_drvdata(serio); | ||
213 | |||
214 | if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0; | ||
215 | sermouse->last = jiffies; | ||
216 | |||
217 | if (sermouse->type > SERIO_SUN) | ||
218 | sermouse_process_ms(sermouse, data, regs); | ||
219 | else | ||
220 | sermouse_process_msc(sermouse, data, regs); | ||
221 | return IRQ_HANDLED; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * sermouse_disconnect() cleans up after we don't want talk | ||
226 | * to the mouse anymore. | ||
227 | */ | ||
228 | |||
229 | static void sermouse_disconnect(struct serio *serio) | ||
230 | { | ||
231 | struct sermouse *sermouse = serio_get_drvdata(serio); | ||
232 | |||
233 | input_unregister_device(&sermouse->dev); | ||
234 | serio_close(serio); | ||
235 | serio_set_drvdata(serio, NULL); | ||
236 | kfree(sermouse); | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * sermouse_connect() is a callback form the serio module when | ||
241 | * an unhandled serio port is found. | ||
242 | */ | ||
243 | |||
244 | static int sermouse_connect(struct serio *serio, struct serio_driver *drv) | ||
245 | { | ||
246 | struct sermouse *sermouse; | ||
247 | unsigned char c; | ||
248 | int err; | ||
249 | |||
250 | if (!serio->id.proto || serio->id.proto > SERIO_MZPP) | ||
251 | return -ENODEV; | ||
252 | |||
253 | if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL))) | ||
254 | return -ENOMEM; | ||
255 | |||
256 | memset(sermouse, 0, sizeof(struct sermouse)); | ||
257 | |||
258 | init_input_dev(&sermouse->dev); | ||
259 | sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
260 | sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); | ||
261 | sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
262 | sermouse->dev.private = sermouse; | ||
263 | |||
264 | sermouse->type = serio->id.proto; | ||
265 | c = serio->id.extra; | ||
266 | |||
267 | if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit); | ||
268 | if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit); | ||
269 | if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit); | ||
270 | if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit); | ||
271 | if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit); | ||
272 | |||
273 | sprintf(sermouse->phys, "%s/input0", serio->phys); | ||
274 | |||
275 | sermouse->dev.name = sermouse_protocols[sermouse->type]; | ||
276 | sermouse->dev.phys = sermouse->phys; | ||
277 | sermouse->dev.id.bustype = BUS_RS232; | ||
278 | sermouse->dev.id.vendor = sermouse->type; | ||
279 | sermouse->dev.id.product = c; | ||
280 | sermouse->dev.id.version = 0x0100; | ||
281 | sermouse->dev.dev = &serio->dev; | ||
282 | |||
283 | serio_set_drvdata(serio, sermouse); | ||
284 | |||
285 | err = serio_open(serio, drv); | ||
286 | if (err) { | ||
287 | serio_set_drvdata(serio, NULL); | ||
288 | kfree(sermouse); | ||
289 | return err; | ||
290 | } | ||
291 | |||
292 | input_register_device(&sermouse->dev); | ||
293 | |||
294 | printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static struct serio_device_id sermouse_serio_ids[] = { | ||
300 | { | ||
301 | .type = SERIO_RS232, | ||
302 | .proto = SERIO_MSC, | ||
303 | .id = SERIO_ANY, | ||
304 | .extra = SERIO_ANY, | ||
305 | }, | ||
306 | { | ||
307 | .type = SERIO_RS232, | ||
308 | .proto = SERIO_SUN, | ||
309 | .id = SERIO_ANY, | ||
310 | .extra = SERIO_ANY, | ||
311 | }, | ||
312 | { | ||
313 | .type = SERIO_RS232, | ||
314 | .proto = SERIO_MS, | ||
315 | .id = SERIO_ANY, | ||
316 | .extra = SERIO_ANY, | ||
317 | }, | ||
318 | { | ||
319 | .type = SERIO_RS232, | ||
320 | .proto = SERIO_MP, | ||
321 | .id = SERIO_ANY, | ||
322 | .extra = SERIO_ANY, | ||
323 | }, | ||
324 | { | ||
325 | .type = SERIO_RS232, | ||
326 | .proto = SERIO_MZ, | ||
327 | .id = SERIO_ANY, | ||
328 | .extra = SERIO_ANY, | ||
329 | }, | ||
330 | { | ||
331 | .type = SERIO_RS232, | ||
332 | .proto = SERIO_MZP, | ||
333 | .id = SERIO_ANY, | ||
334 | .extra = SERIO_ANY, | ||
335 | }, | ||
336 | { | ||
337 | .type = SERIO_RS232, | ||
338 | .proto = SERIO_MZPP, | ||
339 | .id = SERIO_ANY, | ||
340 | .extra = SERIO_ANY, | ||
341 | }, | ||
342 | { 0 } | ||
343 | }; | ||
344 | |||
345 | MODULE_DEVICE_TABLE(serio, sermouse_serio_ids); | ||
346 | |||
347 | static struct serio_driver sermouse_drv = { | ||
348 | .driver = { | ||
349 | .name = "sermouse", | ||
350 | }, | ||
351 | .description = DRIVER_DESC, | ||
352 | .id_table = sermouse_serio_ids, | ||
353 | .interrupt = sermouse_interrupt, | ||
354 | .connect = sermouse_connect, | ||
355 | .disconnect = sermouse_disconnect, | ||
356 | }; | ||
357 | |||
358 | static int __init sermouse_init(void) | ||
359 | { | ||
360 | serio_register_driver(&sermouse_drv); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static void __exit sermouse_exit(void) | ||
365 | { | ||
366 | serio_unregister_driver(&sermouse_drv); | ||
367 | } | ||
368 | |||
369 | module_init(sermouse_init); | ||
370 | module_exit(sermouse_exit); | ||
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c new file mode 100644 index 000000000000..69832f8fb720 --- /dev/null +++ b/drivers/input/mouse/synaptics.c | |||
@@ -0,0 +1,700 @@ | |||
1 | /* | ||
2 | * Synaptics TouchPad PS/2 mouse driver | ||
3 | * | ||
4 | * 2003 Dmitry Torokhov <dtor@mail.ru> | ||
5 | * Added support for pass-through port. Special thanks to Peter Berg Larsen | ||
6 | * for explaining various Synaptics quirks. | ||
7 | * | ||
8 | * 2003 Peter Osterlund <petero2@telia.com> | ||
9 | * Ported to 2.5 input device infrastructure. | ||
10 | * | ||
11 | * Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch> | ||
12 | * start merging tpconfig and gpm code to a xfree-input module | ||
13 | * adding some changes and extensions (ex. 3rd and 4th button) | ||
14 | * | ||
15 | * Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu> | ||
16 | * Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com> | ||
17 | * code for the special synaptics commands (from the tpconfig-source) | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify it | ||
20 | * under the terms of the GNU General Public License version 2 as published by | ||
21 | * the Free Software Foundation. | ||
22 | * | ||
23 | * Trademarks are the property of their respective owners. | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/input.h> | ||
28 | #include <linux/serio.h> | ||
29 | #include <linux/libps2.h> | ||
30 | #include "psmouse.h" | ||
31 | #include "synaptics.h" | ||
32 | |||
33 | /* | ||
34 | * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, | ||
35 | * section 2.3.2, which says that they should be valid regardless of the | ||
36 | * actual size of the sensor. | ||
37 | */ | ||
38 | #define XMIN_NOMINAL 1472 | ||
39 | #define XMAX_NOMINAL 5472 | ||
40 | #define YMIN_NOMINAL 1408 | ||
41 | #define YMAX_NOMINAL 4448 | ||
42 | |||
43 | /***************************************************************************** | ||
44 | * Synaptics communications functions | ||
45 | ****************************************************************************/ | ||
46 | |||
47 | /* | ||
48 | * Send a command to the synpatics touchpad by special commands | ||
49 | */ | ||
50 | static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) | ||
51 | { | ||
52 | if (psmouse_sliced_command(psmouse, c)) | ||
53 | return -1; | ||
54 | if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
55 | return -1; | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Set the synaptics touchpad mode byte by special commands | ||
61 | */ | ||
62 | static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) | ||
63 | { | ||
64 | unsigned char param[1]; | ||
65 | |||
66 | if (psmouse_sliced_command(psmouse, mode)) | ||
67 | return -1; | ||
68 | param[0] = SYN_PS_SET_MODE2; | ||
69 | if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) | ||
70 | return -1; | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Read the model-id bytes from the touchpad | ||
76 | * see also SYN_MODEL_* macros | ||
77 | */ | ||
78 | static int synaptics_model_id(struct psmouse *psmouse) | ||
79 | { | ||
80 | struct synaptics_data *priv = psmouse->private; | ||
81 | unsigned char mi[3]; | ||
82 | |||
83 | if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi)) | ||
84 | return -1; | ||
85 | priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2]; | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Read the capability-bits from the touchpad | ||
91 | * see also the SYN_CAP_* macros | ||
92 | */ | ||
93 | static int synaptics_capability(struct psmouse *psmouse) | ||
94 | { | ||
95 | struct synaptics_data *priv = psmouse->private; | ||
96 | unsigned char cap[3]; | ||
97 | |||
98 | if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) | ||
99 | return -1; | ||
100 | priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; | ||
101 | priv->ext_cap = 0; | ||
102 | if (!SYN_CAP_VALID(priv->capabilities)) | ||
103 | return -1; | ||
104 | |||
105 | /* | ||
106 | * Unless capExtended is set the rest of the flags should be ignored | ||
107 | */ | ||
108 | if (!SYN_CAP_EXTENDED(priv->capabilities)) | ||
109 | priv->capabilities = 0; | ||
110 | |||
111 | if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { | ||
112 | if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { | ||
113 | printk(KERN_ERR "Synaptics claims to have extended capabilities," | ||
114 | " but I'm not able to read them."); | ||
115 | } else { | ||
116 | priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; | ||
117 | |||
118 | /* | ||
119 | * if nExtBtn is greater than 8 it should be considered | ||
120 | * invalid and treated as 0 | ||
121 | */ | ||
122 | if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8) | ||
123 | priv->ext_cap &= 0xff0fff; | ||
124 | } | ||
125 | } | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Identify Touchpad | ||
131 | * See also the SYN_ID_* macros | ||
132 | */ | ||
133 | static int synaptics_identify(struct psmouse *psmouse) | ||
134 | { | ||
135 | struct synaptics_data *priv = psmouse->private; | ||
136 | unsigned char id[3]; | ||
137 | |||
138 | if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id)) | ||
139 | return -1; | ||
140 | priv->identity = (id[0]<<16) | (id[1]<<8) | id[2]; | ||
141 | if (SYN_ID_IS_SYNAPTICS(priv->identity)) | ||
142 | return 0; | ||
143 | return -1; | ||
144 | } | ||
145 | |||
146 | static void print_ident(struct synaptics_data *priv) | ||
147 | { | ||
148 | printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity)); | ||
149 | printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity), | ||
150 | SYN_ID_MINOR(priv->identity)); | ||
151 | if (SYN_MODEL_ROT180(priv->model_id)) | ||
152 | printk(KERN_INFO " 180 degree mounted touchpad\n"); | ||
153 | if (SYN_MODEL_PORTRAIT(priv->model_id)) | ||
154 | printk(KERN_INFO " portrait touchpad\n"); | ||
155 | printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id)); | ||
156 | if (SYN_MODEL_NEWABS(priv->model_id)) | ||
157 | printk(KERN_INFO " new absolute packet format\n"); | ||
158 | if (SYN_MODEL_PEN(priv->model_id)) | ||
159 | printk(KERN_INFO " pen detection\n"); | ||
160 | |||
161 | if (SYN_CAP_EXTENDED(priv->capabilities)) { | ||
162 | printk(KERN_INFO " Touchpad has extended capability bits\n"); | ||
163 | if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) | ||
164 | printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n", | ||
165 | (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))); | ||
166 | if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) | ||
167 | printk(KERN_INFO " -> middle button\n"); | ||
168 | if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) | ||
169 | printk(KERN_INFO " -> four buttons\n"); | ||
170 | if (SYN_CAP_MULTIFINGER(priv->capabilities)) | ||
171 | printk(KERN_INFO " -> multifinger detection\n"); | ||
172 | if (SYN_CAP_PALMDETECT(priv->capabilities)) | ||
173 | printk(KERN_INFO " -> palm detection\n"); | ||
174 | if (SYN_CAP_PASS_THROUGH(priv->capabilities)) | ||
175 | printk(KERN_INFO " -> pass-through port\n"); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static int synaptics_query_hardware(struct psmouse *psmouse) | ||
180 | { | ||
181 | int retries = 0; | ||
182 | |||
183 | while ((retries++ < 3) && psmouse_reset(psmouse)) | ||
184 | printk(KERN_ERR "synaptics reset failed\n"); | ||
185 | |||
186 | if (synaptics_identify(psmouse)) | ||
187 | return -1; | ||
188 | if (synaptics_model_id(psmouse)) | ||
189 | return -1; | ||
190 | if (synaptics_capability(psmouse)) | ||
191 | return -1; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int synaptics_set_absolute_mode(struct psmouse *psmouse) | ||
197 | { | ||
198 | struct synaptics_data *priv = psmouse->private; | ||
199 | |||
200 | priv->mode = SYN_BIT_ABSOLUTE_MODE; | ||
201 | if (SYN_ID_MAJOR(priv->identity) >= 4) | ||
202 | priv->mode |= SYN_BIT_DISABLE_GESTURE; | ||
203 | if (SYN_CAP_EXTENDED(priv->capabilities)) | ||
204 | priv->mode |= SYN_BIT_W_MODE; | ||
205 | |||
206 | if (synaptics_mode_cmd(psmouse, priv->mode)) | ||
207 | return -1; | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) | ||
213 | { | ||
214 | struct synaptics_data *priv = psmouse->private; | ||
215 | |||
216 | if (rate >= 80) { | ||
217 | priv->mode |= SYN_BIT_HIGH_RATE; | ||
218 | psmouse->rate = 80; | ||
219 | } else { | ||
220 | priv->mode &= ~SYN_BIT_HIGH_RATE; | ||
221 | psmouse->rate = 40; | ||
222 | } | ||
223 | |||
224 | synaptics_mode_cmd(psmouse, priv->mode); | ||
225 | } | ||
226 | |||
227 | /***************************************************************************** | ||
228 | * Synaptics pass-through PS/2 port support | ||
229 | ****************************************************************************/ | ||
230 | static int synaptics_pt_write(struct serio *serio, unsigned char c) | ||
231 | { | ||
232 | struct psmouse *parent = serio_get_drvdata(serio->parent); | ||
233 | char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ | ||
234 | |||
235 | if (psmouse_sliced_command(parent, c)) | ||
236 | return -1; | ||
237 | if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE)) | ||
238 | return -1; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static inline int synaptics_is_pt_packet(unsigned char *buf) | ||
243 | { | ||
244 | return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; | ||
245 | } | ||
246 | |||
247 | static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet) | ||
248 | { | ||
249 | struct psmouse *child = serio_get_drvdata(ptport); | ||
250 | |||
251 | if (child && child->state == PSMOUSE_ACTIVATED) { | ||
252 | serio_interrupt(ptport, packet[1], 0, NULL); | ||
253 | serio_interrupt(ptport, packet[4], 0, NULL); | ||
254 | serio_interrupt(ptport, packet[5], 0, NULL); | ||
255 | if (child->type >= PSMOUSE_GENPS) | ||
256 | serio_interrupt(ptport, packet[2], 0, NULL); | ||
257 | } else | ||
258 | serio_interrupt(ptport, packet[1], 0, NULL); | ||
259 | } | ||
260 | |||
261 | static void synaptics_pt_activate(struct psmouse *psmouse) | ||
262 | { | ||
263 | struct serio *ptport = psmouse->ps2dev.serio->child; | ||
264 | struct psmouse *child = serio_get_drvdata(ptport); | ||
265 | struct synaptics_data *priv = psmouse->private; | ||
266 | |||
267 | /* adjust the touchpad to child's choice of protocol */ | ||
268 | if (child) { | ||
269 | if (child->type >= PSMOUSE_GENPS) | ||
270 | priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT; | ||
271 | else | ||
272 | priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT; | ||
273 | |||
274 | if (synaptics_mode_cmd(psmouse, priv->mode)) | ||
275 | printk(KERN_INFO "synaptics: failed to switch guest protocol\n"); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | static void synaptics_pt_create(struct psmouse *psmouse) | ||
280 | { | ||
281 | struct serio *serio; | ||
282 | |||
283 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
284 | if (!serio) { | ||
285 | printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); | ||
286 | return; | ||
287 | } | ||
288 | |||
289 | memset(serio, 0, sizeof(struct serio)); | ||
290 | |||
291 | serio->id.type = SERIO_PS_PSTHRU; | ||
292 | strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); | ||
293 | strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); | ||
294 | serio->write = synaptics_pt_write; | ||
295 | serio->parent = psmouse->ps2dev.serio; | ||
296 | |||
297 | psmouse->pt_activate = synaptics_pt_activate; | ||
298 | |||
299 | printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys); | ||
300 | serio_register_port(serio); | ||
301 | } | ||
302 | |||
303 | /***************************************************************************** | ||
304 | * Functions to interpret the absolute mode packets | ||
305 | ****************************************************************************/ | ||
306 | |||
307 | static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) | ||
308 | { | ||
309 | memset(hw, 0, sizeof(struct synaptics_hw_state)); | ||
310 | |||
311 | if (SYN_MODEL_NEWABS(priv->model_id)) { | ||
312 | hw->x = (((buf[3] & 0x10) << 8) | | ||
313 | ((buf[1] & 0x0f) << 8) | | ||
314 | buf[4]); | ||
315 | hw->y = (((buf[3] & 0x20) << 7) | | ||
316 | ((buf[1] & 0xf0) << 4) | | ||
317 | buf[5]); | ||
318 | |||
319 | hw->z = buf[2]; | ||
320 | hw->w = (((buf[0] & 0x30) >> 2) | | ||
321 | ((buf[0] & 0x04) >> 1) | | ||
322 | ((buf[3] & 0x04) >> 2)); | ||
323 | |||
324 | hw->left = (buf[0] & 0x01) ? 1 : 0; | ||
325 | hw->right = (buf[0] & 0x02) ? 1 : 0; | ||
326 | |||
327 | if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { | ||
328 | hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; | ||
329 | if (hw->w == 2) | ||
330 | hw->scroll = (signed char)(buf[1]); | ||
331 | } | ||
332 | |||
333 | if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { | ||
334 | hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; | ||
335 | hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; | ||
336 | } | ||
337 | |||
338 | if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && | ||
339 | ((buf[0] ^ buf[3]) & 0x02)) { | ||
340 | switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { | ||
341 | default: | ||
342 | /* | ||
343 | * if nExtBtn is greater than 8 it should be | ||
344 | * considered invalid and treated as 0 | ||
345 | */ | ||
346 | break; | ||
347 | case 8: | ||
348 | hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0; | ||
349 | hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0; | ||
350 | case 6: | ||
351 | hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0; | ||
352 | hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0; | ||
353 | case 4: | ||
354 | hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0; | ||
355 | hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0; | ||
356 | case 2: | ||
357 | hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0; | ||
358 | hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0; | ||
359 | } | ||
360 | } | ||
361 | } else { | ||
362 | hw->x = (((buf[1] & 0x1f) << 8) | buf[2]); | ||
363 | hw->y = (((buf[4] & 0x1f) << 8) | buf[5]); | ||
364 | |||
365 | hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F)); | ||
366 | hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1)); | ||
367 | |||
368 | hw->left = (buf[0] & 0x01) ? 1 : 0; | ||
369 | hw->right = (buf[0] & 0x02) ? 1 : 0; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * called for each full received packet from the touchpad | ||
375 | */ | ||
376 | static void synaptics_process_packet(struct psmouse *psmouse) | ||
377 | { | ||
378 | struct input_dev *dev = &psmouse->dev; | ||
379 | struct synaptics_data *priv = psmouse->private; | ||
380 | struct synaptics_hw_state hw; | ||
381 | int num_fingers; | ||
382 | int finger_width; | ||
383 | int i; | ||
384 | |||
385 | synaptics_parse_hw_state(psmouse->packet, priv, &hw); | ||
386 | |||
387 | if (hw.scroll) { | ||
388 | priv->scroll += hw.scroll; | ||
389 | |||
390 | while (priv->scroll >= 4) { | ||
391 | input_report_key(dev, BTN_BACK, !hw.down); | ||
392 | input_sync(dev); | ||
393 | input_report_key(dev, BTN_BACK, hw.down); | ||
394 | input_sync(dev); | ||
395 | priv->scroll -= 4; | ||
396 | } | ||
397 | while (priv->scroll <= -4) { | ||
398 | input_report_key(dev, BTN_FORWARD, !hw.up); | ||
399 | input_sync(dev); | ||
400 | input_report_key(dev, BTN_FORWARD, hw.up); | ||
401 | input_sync(dev); | ||
402 | priv->scroll += 4; | ||
403 | } | ||
404 | return; | ||
405 | } | ||
406 | |||
407 | if (hw.z > 0) { | ||
408 | num_fingers = 1; | ||
409 | finger_width = 5; | ||
410 | if (SYN_CAP_EXTENDED(priv->capabilities)) { | ||
411 | switch (hw.w) { | ||
412 | case 0 ... 1: | ||
413 | if (SYN_CAP_MULTIFINGER(priv->capabilities)) | ||
414 | num_fingers = hw.w + 2; | ||
415 | break; | ||
416 | case 2: | ||
417 | if (SYN_MODEL_PEN(priv->model_id)) | ||
418 | ; /* Nothing, treat a pen as a single finger */ | ||
419 | break; | ||
420 | case 4 ... 15: | ||
421 | if (SYN_CAP_PALMDETECT(priv->capabilities)) | ||
422 | finger_width = hw.w; | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | } else { | ||
427 | num_fingers = 0; | ||
428 | finger_width = 0; | ||
429 | } | ||
430 | |||
431 | /* Post events | ||
432 | * BTN_TOUCH has to be first as mousedev relies on it when doing | ||
433 | * absolute -> relative conversion | ||
434 | */ | ||
435 | if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); | ||
436 | if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); | ||
437 | |||
438 | if (hw.z > 0) { | ||
439 | input_report_abs(dev, ABS_X, hw.x); | ||
440 | input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); | ||
441 | } | ||
442 | input_report_abs(dev, ABS_PRESSURE, hw.z); | ||
443 | |||
444 | input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); | ||
445 | input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); | ||
446 | input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); | ||
447 | input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); | ||
448 | |||
449 | input_report_key(dev, BTN_LEFT, hw.left); | ||
450 | input_report_key(dev, BTN_RIGHT, hw.right); | ||
451 | |||
452 | if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) | ||
453 | input_report_key(dev, BTN_MIDDLE, hw.middle); | ||
454 | |||
455 | if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { | ||
456 | input_report_key(dev, BTN_FORWARD, hw.up); | ||
457 | input_report_key(dev, BTN_BACK, hw.down); | ||
458 | } | ||
459 | |||
460 | for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) | ||
461 | input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i)); | ||
462 | |||
463 | input_sync(dev); | ||
464 | } | ||
465 | |||
466 | static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) | ||
467 | { | ||
468 | static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; | ||
469 | static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; | ||
470 | static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; | ||
471 | static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; | ||
472 | static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; | ||
473 | |||
474 | if (idx < 0 || idx > 4) | ||
475 | return 0; | ||
476 | |||
477 | switch (pkt_type) { | ||
478 | case SYN_NEWABS: | ||
479 | case SYN_NEWABS_RELAXED: | ||
480 | return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; | ||
481 | |||
482 | case SYN_NEWABS_STRICT: | ||
483 | return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; | ||
484 | |||
485 | case SYN_OLDABS: | ||
486 | return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; | ||
487 | |||
488 | default: | ||
489 | printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); | ||
490 | return 0; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) | ||
495 | { | ||
496 | int i; | ||
497 | |||
498 | for (i = 0; i < 5; i++) | ||
499 | if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) { | ||
500 | printk(KERN_INFO "synaptics: using relaxed packet validation\n"); | ||
501 | return SYN_NEWABS_RELAXED; | ||
502 | } | ||
503 | |||
504 | return SYN_NEWABS_STRICT; | ||
505 | } | ||
506 | |||
507 | static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) | ||
508 | { | ||
509 | struct input_dev *dev = &psmouse->dev; | ||
510 | struct synaptics_data *priv = psmouse->private; | ||
511 | |||
512 | input_regs(dev, regs); | ||
513 | |||
514 | if (psmouse->pktcnt >= 6) { /* Full packet received */ | ||
515 | if (unlikely(priv->pkt_type == SYN_NEWABS)) | ||
516 | priv->pkt_type = synaptics_detect_pkt_type(psmouse); | ||
517 | |||
518 | if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { | ||
519 | if (psmouse->ps2dev.serio->child) | ||
520 | synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet); | ||
521 | } else | ||
522 | synaptics_process_packet(psmouse); | ||
523 | |||
524 | return PSMOUSE_FULL_PACKET; | ||
525 | } | ||
526 | |||
527 | return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ? | ||
528 | PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; | ||
529 | } | ||
530 | |||
531 | /***************************************************************************** | ||
532 | * Driver initialization/cleanup functions | ||
533 | ****************************************************************************/ | ||
534 | static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | ||
535 | { | ||
536 | int i; | ||
537 | |||
538 | set_bit(EV_ABS, dev->evbit); | ||
539 | input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); | ||
540 | input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); | ||
541 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | ||
542 | set_bit(ABS_TOOL_WIDTH, dev->absbit); | ||
543 | |||
544 | set_bit(EV_KEY, dev->evbit); | ||
545 | set_bit(BTN_TOUCH, dev->keybit); | ||
546 | set_bit(BTN_TOOL_FINGER, dev->keybit); | ||
547 | set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); | ||
548 | set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); | ||
549 | |||
550 | set_bit(BTN_LEFT, dev->keybit); | ||
551 | set_bit(BTN_RIGHT, dev->keybit); | ||
552 | |||
553 | if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) | ||
554 | set_bit(BTN_MIDDLE, dev->keybit); | ||
555 | |||
556 | if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || | ||
557 | SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { | ||
558 | set_bit(BTN_FORWARD, dev->keybit); | ||
559 | set_bit(BTN_BACK, dev->keybit); | ||
560 | } | ||
561 | |||
562 | for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) | ||
563 | set_bit(BTN_0 + i, dev->keybit); | ||
564 | |||
565 | clear_bit(EV_REL, dev->evbit); | ||
566 | clear_bit(REL_X, dev->relbit); | ||
567 | clear_bit(REL_Y, dev->relbit); | ||
568 | } | ||
569 | |||
570 | void synaptics_reset(struct psmouse *psmouse) | ||
571 | { | ||
572 | /* reset touchpad back to relative mode, gestures enabled */ | ||
573 | synaptics_mode_cmd(psmouse, 0); | ||
574 | } | ||
575 | |||
576 | static void synaptics_disconnect(struct psmouse *psmouse) | ||
577 | { | ||
578 | synaptics_reset(psmouse); | ||
579 | kfree(psmouse->private); | ||
580 | psmouse->private = NULL; | ||
581 | } | ||
582 | |||
583 | static int synaptics_reconnect(struct psmouse *psmouse) | ||
584 | { | ||
585 | struct synaptics_data *priv = psmouse->private; | ||
586 | struct synaptics_data old_priv = *priv; | ||
587 | |||
588 | if (synaptics_detect(psmouse, 0)) | ||
589 | return -1; | ||
590 | |||
591 | if (synaptics_query_hardware(psmouse)) { | ||
592 | printk(KERN_ERR "Unable to query Synaptics hardware.\n"); | ||
593 | return -1; | ||
594 | } | ||
595 | |||
596 | if (old_priv.identity != priv->identity || | ||
597 | old_priv.model_id != priv->model_id || | ||
598 | old_priv.capabilities != priv->capabilities || | ||
599 | old_priv.ext_cap != priv->ext_cap) | ||
600 | return -1; | ||
601 | |||
602 | if (synaptics_set_absolute_mode(psmouse)) { | ||
603 | printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); | ||
604 | return -1; | ||
605 | } | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | int synaptics_detect(struct psmouse *psmouse, int set_properties) | ||
611 | { | ||
612 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
613 | unsigned char param[4]; | ||
614 | |||
615 | param[0] = 0; | ||
616 | |||
617 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
618 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
619 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
620 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | ||
621 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); | ||
622 | |||
623 | if (param[1] != 0x47) | ||
624 | return -1; | ||
625 | |||
626 | if (set_properties) { | ||
627 | psmouse->vendor = "Synaptics"; | ||
628 | psmouse->name = "TouchPad"; | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | #if defined(__i386__) | ||
635 | #include <linux/dmi.h> | ||
636 | static struct dmi_system_id toshiba_dmi_table[] = { | ||
637 | { | ||
638 | .ident = "Toshiba Satellite", | ||
639 | .matches = { | ||
640 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
641 | DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"), | ||
642 | }, | ||
643 | }, | ||
644 | { } | ||
645 | }; | ||
646 | #endif | ||
647 | |||
648 | int synaptics_init(struct psmouse *psmouse) | ||
649 | { | ||
650 | struct synaptics_data *priv; | ||
651 | |||
652 | psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL); | ||
653 | if (!priv) | ||
654 | return -1; | ||
655 | memset(priv, 0, sizeof(struct synaptics_data)); | ||
656 | |||
657 | if (synaptics_query_hardware(psmouse)) { | ||
658 | printk(KERN_ERR "Unable to query Synaptics hardware.\n"); | ||
659 | goto init_fail; | ||
660 | } | ||
661 | |||
662 | if (synaptics_set_absolute_mode(psmouse)) { | ||
663 | printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); | ||
664 | goto init_fail; | ||
665 | } | ||
666 | |||
667 | priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; | ||
668 | |||
669 | print_ident(priv); | ||
670 | set_input_params(&psmouse->dev, priv); | ||
671 | |||
672 | psmouse->protocol_handler = synaptics_process_byte; | ||
673 | psmouse->set_rate = synaptics_set_rate; | ||
674 | psmouse->disconnect = synaptics_disconnect; | ||
675 | psmouse->reconnect = synaptics_reconnect; | ||
676 | psmouse->pktsize = 6; | ||
677 | |||
678 | if (SYN_CAP_PASS_THROUGH(priv->capabilities)) | ||
679 | synaptics_pt_create(psmouse); | ||
680 | |||
681 | #if defined(__i386__) | ||
682 | /* | ||
683 | * Toshiba's KBC seems to have trouble handling data from | ||
684 | * Synaptics as full rate, switch to lower rate which is roughly | ||
685 | * thye same as rate of standard PS/2 mouse. | ||
686 | */ | ||
687 | if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) { | ||
688 | printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n"); | ||
689 | psmouse->rate = 40; | ||
690 | } | ||
691 | #endif | ||
692 | |||
693 | return 0; | ||
694 | |||
695 | init_fail: | ||
696 | kfree(priv); | ||
697 | return -1; | ||
698 | } | ||
699 | |||
700 | |||
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h new file mode 100644 index 000000000000..68fff1dcd7de --- /dev/null +++ b/drivers/input/mouse/synaptics.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Synaptics TouchPad PS/2 mouse driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License version 2 as published by | ||
6 | * the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _SYNAPTICS_H | ||
10 | #define _SYNAPTICS_H | ||
11 | |||
12 | extern int synaptics_detect(struct psmouse *psmouse, int set_properties); | ||
13 | extern int synaptics_init(struct psmouse *psmouse); | ||
14 | extern void synaptics_reset(struct psmouse *psmouse); | ||
15 | |||
16 | /* synaptics queries */ | ||
17 | #define SYN_QUE_IDENTIFY 0x00 | ||
18 | #define SYN_QUE_MODES 0x01 | ||
19 | #define SYN_QUE_CAPABILITIES 0x02 | ||
20 | #define SYN_QUE_MODEL 0x03 | ||
21 | #define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06 | ||
22 | #define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07 | ||
23 | #define SYN_QUE_RESOLUTION 0x08 | ||
24 | #define SYN_QUE_EXT_CAPAB 0x09 | ||
25 | |||
26 | /* synatics modes */ | ||
27 | #define SYN_BIT_ABSOLUTE_MODE (1 << 7) | ||
28 | #define SYN_BIT_HIGH_RATE (1 << 6) | ||
29 | #define SYN_BIT_SLEEP_MODE (1 << 3) | ||
30 | #define SYN_BIT_DISABLE_GESTURE (1 << 2) | ||
31 | #define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1) | ||
32 | #define SYN_BIT_W_MODE (1 << 0) | ||
33 | |||
34 | /* synaptics model ID bits */ | ||
35 | #define SYN_MODEL_ROT180(m) ((m) & (1 << 23)) | ||
36 | #define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22)) | ||
37 | #define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f) | ||
38 | #define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f) | ||
39 | #define SYN_MODEL_NEWABS(m) ((m) & (1 << 7)) | ||
40 | #define SYN_MODEL_PEN(m) ((m) & (1 << 6)) | ||
41 | #define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5)) | ||
42 | #define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f) | ||
43 | |||
44 | /* synaptics capability bits */ | ||
45 | #define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) | ||
46 | #define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18)) | ||
47 | #define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) | ||
48 | #define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) | ||
49 | #define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) | ||
50 | #define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) | ||
51 | #define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) | ||
52 | #define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) | ||
53 | #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) | ||
54 | #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) | ||
55 | |||
56 | /* synaptics modes query bits */ | ||
57 | #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) | ||
58 | #define SYN_MODE_RATE(m) ((m) & (1 << 6)) | ||
59 | #define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3)) | ||
60 | #define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2)) | ||
61 | #define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1)) | ||
62 | #define SYN_MODE_WMODE(m) ((m) & (1 << 0)) | ||
63 | |||
64 | /* synaptics identify query bits */ | ||
65 | #define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) | ||
66 | #define SYN_ID_MAJOR(i) ((i) & 0x0f) | ||
67 | #define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) | ||
68 | #define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) | ||
69 | |||
70 | /* synaptics special commands */ | ||
71 | #define SYN_PS_SET_MODE2 0x14 | ||
72 | #define SYN_PS_CLIENT_CMD 0x28 | ||
73 | |||
74 | /* synaptics packet types */ | ||
75 | #define SYN_NEWABS 0 | ||
76 | #define SYN_NEWABS_STRICT 1 | ||
77 | #define SYN_NEWABS_RELAXED 2 | ||
78 | #define SYN_OLDABS 3 | ||
79 | |||
80 | /* | ||
81 | * A structure to describe the state of the touchpad hardware (buttons and pad) | ||
82 | */ | ||
83 | |||
84 | struct synaptics_hw_state { | ||
85 | int x; | ||
86 | int y; | ||
87 | int z; | ||
88 | int w; | ||
89 | unsigned int left:1; | ||
90 | unsigned int right:1; | ||
91 | unsigned int middle:1; | ||
92 | unsigned int up:1; | ||
93 | unsigned int down:1; | ||
94 | unsigned char ext_buttons; | ||
95 | signed char scroll; | ||
96 | }; | ||
97 | |||
98 | struct synaptics_data { | ||
99 | /* Data read from the touchpad */ | ||
100 | unsigned long int model_id; /* Model-ID */ | ||
101 | unsigned long int capabilities; /* Capabilities */ | ||
102 | unsigned long int ext_cap; /* Extended Capabilities */ | ||
103 | unsigned long int identity; /* Identification */ | ||
104 | |||
105 | unsigned char pkt_type; /* packet type - old, new, etc */ | ||
106 | unsigned char mode; /* current mode byte */ | ||
107 | int scroll; | ||
108 | }; | ||
109 | |||
110 | #endif /* _SYNAPTICS_H */ | ||
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c new file mode 100644 index 000000000000..b2cb101c8110 --- /dev/null +++ b/drivers/input/mouse/vsxxxaa.c | |||
@@ -0,0 +1,591 @@ | |||
1 | /* | ||
2 | * Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers) | ||
3 | * DEC VSXXX-GA mouse (rectangular mouse, with ball) | ||
4 | * DEC VSXXX-AB tablet (digitizer with hair cross or stylus) | ||
5 | * | ||
6 | * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de> | ||
7 | * | ||
8 | * The packet format was initially taken from a patch to GPM which is (C) 2001 | ||
9 | * by Karsten Merker <merker@linuxtag.org> | ||
10 | * and Maciej W. Rozycki <macro@ds2.pg.gda.pl> | ||
11 | * Later on, I had access to the device's documentation (referenced below). | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | * Building an adaptor to DE9 / DB25 RS232 | ||
32 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
33 | * | ||
34 | * DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for | ||
35 | * anything if you break your mouse, your computer or whatever! | ||
36 | * | ||
37 | * In theory, this mouse is a simple RS232 device. In practice, it has got | ||
38 | * a quite uncommon plug and the requirement to additionally get a power | ||
39 | * supply at +5V and -12V. | ||
40 | * | ||
41 | * If you look at the socket/jack (_not_ at the plug), we use this pin | ||
42 | * numbering: | ||
43 | * _______ | ||
44 | * / 7 6 5 \ | ||
45 | * | 4 --- 3 | | ||
46 | * \ 2 1 / | ||
47 | * ------- | ||
48 | * | ||
49 | * DEC socket DE9 DB25 Note | ||
50 | * 1 (GND) 5 7 - | ||
51 | * 2 (RxD) 2 3 - | ||
52 | * 3 (TxD) 3 2 - | ||
53 | * 4 (-12V) - - Somewhere from the PSU. At ATX, it's | ||
54 | * the thin blue wire at pin 12 of the | ||
55 | * ATX power connector. Only required for | ||
56 | * VSXXX-AA/-GA mice. | ||
57 | * 5 (+5V) - - PSU (red wires of ATX power connector | ||
58 | * on pin 4, 6, 19 or 20) or HDD power | ||
59 | * connector (also red wire). | ||
60 | * 6 (+12V) - - HDD power connector, yellow wire. Only | ||
61 | * required for VSXXX-AB digitizer. | ||
62 | * 7 (dev. avail.) - - The mouse shorts this one to pin 1. | ||
63 | * This way, the host computer can detect | ||
64 | * the mouse. To use it with the adaptor, | ||
65 | * simply don't connect this pin. | ||
66 | * | ||
67 | * So to get a working adaptor, you need to connect the mouse with three | ||
68 | * wires to a RS232 port and two or three additional wires for +5V, +12V and | ||
69 | * -12V to the PSU. | ||
70 | * | ||
71 | * Flow specification for the link is 4800, 8o1. | ||
72 | * | ||
73 | * The mice and tablet are described in "VCB02 Video Subsystem - Technical | ||
74 | * Manual", DEC EK-104AA-TM-001. You'll find it at MANX, a search engine | ||
75 | * specific for DEC documentation. Try | ||
76 | * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1 | ||
77 | */ | ||
78 | |||
79 | #include <linux/delay.h> | ||
80 | #include <linux/module.h> | ||
81 | #include <linux/slab.h> | ||
82 | #include <linux/interrupt.h> | ||
83 | #include <linux/input.h> | ||
84 | #include <linux/config.h> | ||
85 | #include <linux/serio.h> | ||
86 | #include <linux/init.h> | ||
87 | |||
88 | #define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet" | ||
89 | |||
90 | MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); | ||
91 | MODULE_DESCRIPTION (DRIVER_DESC); | ||
92 | MODULE_LICENSE ("GPL"); | ||
93 | |||
94 | #undef VSXXXAA_DEBUG | ||
95 | #ifdef VSXXXAA_DEBUG | ||
96 | #define DBG(x...) printk (x) | ||
97 | #else | ||
98 | #define DBG(x...) do {} while (0) | ||
99 | #endif | ||
100 | |||
101 | #define VSXXXAA_INTRO_MASK 0x80 | ||
102 | #define VSXXXAA_INTRO_HEAD 0x80 | ||
103 | #define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \ | ||
104 | == VSXXXAA_INTRO_HEAD) | ||
105 | |||
106 | #define VSXXXAA_PACKET_MASK 0xe0 | ||
107 | #define VSXXXAA_PACKET_REL 0x80 | ||
108 | #define VSXXXAA_PACKET_ABS 0xc0 | ||
109 | #define VSXXXAA_PACKET_POR 0xa0 | ||
110 | #define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == (type)) | ||
111 | |||
112 | |||
113 | |||
114 | struct vsxxxaa { | ||
115 | struct input_dev dev; | ||
116 | struct serio *serio; | ||
117 | #define BUFLEN 15 /* At least 5 is needed for a full tablet packet */ | ||
118 | unsigned char buf[BUFLEN]; | ||
119 | unsigned char count; | ||
120 | unsigned char version; | ||
121 | unsigned char country; | ||
122 | unsigned char type; | ||
123 | char name[64]; | ||
124 | char phys[32]; | ||
125 | }; | ||
126 | |||
127 | static void | ||
128 | vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num) | ||
129 | { | ||
130 | if (num >= mouse->count) | ||
131 | mouse->count = 0; | ||
132 | else { | ||
133 | memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num); | ||
134 | mouse->count -= num; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | static void | ||
139 | vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte) | ||
140 | { | ||
141 | if (mouse->count == BUFLEN) { | ||
142 | printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", | ||
143 | mouse->name, mouse->phys); | ||
144 | vsxxxaa_drop_bytes (mouse, 1); | ||
145 | } | ||
146 | DBG (KERN_INFO "Queueing byte 0x%02x\n", byte); | ||
147 | |||
148 | mouse->buf[mouse->count++] = byte; | ||
149 | } | ||
150 | |||
151 | static void | ||
152 | vsxxxaa_detection_done (struct vsxxxaa *mouse) | ||
153 | { | ||
154 | switch (mouse->type) { | ||
155 | case 0x02: | ||
156 | sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse"); | ||
157 | break; | ||
158 | |||
159 | case 0x04: | ||
160 | sprintf (mouse->name, "DEC VSXXX-AB digitizer"); | ||
161 | break; | ||
162 | |||
163 | default: | ||
164 | sprintf (mouse->name, "unknown DEC pointer device " | ||
165 | "(type = 0x%02x)", mouse->type); | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x " | ||
170 | "on port %s\n", mouse->name, mouse->version, | ||
171 | mouse->country, mouse->phys); | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * Returns number of bytes to be dropped, 0 if packet is okay. | ||
176 | */ | ||
177 | static int | ||
178 | vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len) | ||
179 | { | ||
180 | int i; | ||
181 | |||
182 | /* First byte must be a header byte */ | ||
183 | if (!IS_HDR_BYTE (mouse->buf[0])) { | ||
184 | DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | /* Check all following bytes */ | ||
189 | if (packet_len > 1) { | ||
190 | for (i = 1; i < packet_len; i++) { | ||
191 | if (IS_HDR_BYTE (mouse->buf[i])) { | ||
192 | printk (KERN_ERR "Need to drop %d bytes " | ||
193 | "of a broken packet.\n", | ||
194 | i - 1); | ||
195 | DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n", | ||
196 | packet_len, i, mouse->buf[i]); | ||
197 | return i - 1; | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static __inline__ int | ||
206 | vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len) | ||
207 | { | ||
208 | return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type); | ||
209 | } | ||
210 | |||
211 | static void | ||
212 | vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) | ||
213 | { | ||
214 | struct input_dev *dev = &mouse->dev; | ||
215 | unsigned char *buf = mouse->buf; | ||
216 | int left, middle, right; | ||
217 | int dx, dy; | ||
218 | |||
219 | /* | ||
220 | * Check for normal stream packets. This is three bytes, | ||
221 | * with the first byte's 3 MSB set to 100. | ||
222 | * | ||
223 | * [0]: 1 0 0 SignX SignY Left Middle Right | ||
224 | * [1]: 0 dx dx dx dx dx dx dx | ||
225 | * [2]: 0 dy dy dy dy dy dy dy | ||
226 | */ | ||
227 | |||
228 | /* | ||
229 | * Low 7 bit of byte 1 are abs(dx), bit 7 is | ||
230 | * 0, bit 4 of byte 0 is direction. | ||
231 | */ | ||
232 | dx = buf[1] & 0x7f; | ||
233 | dx *= ((buf[0] >> 4) & 0x01)? 1: -1; | ||
234 | |||
235 | /* | ||
236 | * Low 7 bit of byte 2 are abs(dy), bit 7 is | ||
237 | * 0, bit 3 of byte 0 is direction. | ||
238 | */ | ||
239 | dy = buf[2] & 0x7f; | ||
240 | dy *= ((buf[0] >> 3) & 0x01)? -1: 1; | ||
241 | |||
242 | /* | ||
243 | * Get button state. It's the low three bits | ||
244 | * (for three buttons) of byte 0. | ||
245 | */ | ||
246 | left = (buf[0] & 0x04)? 1: 0; | ||
247 | middle = (buf[0] & 0x02)? 1: 0; | ||
248 | right = (buf[0] & 0x01)? 1: 0; | ||
249 | |||
250 | vsxxxaa_drop_bytes (mouse, 3); | ||
251 | |||
252 | DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", | ||
253 | mouse->name, mouse->phys, dx, dy, | ||
254 | left? "L": "l", middle? "M": "m", right? "R": "r"); | ||
255 | |||
256 | /* | ||
257 | * Report what we've found so far... | ||
258 | */ | ||
259 | input_regs (dev, regs); | ||
260 | input_report_key (dev, BTN_LEFT, left); | ||
261 | input_report_key (dev, BTN_MIDDLE, middle); | ||
262 | input_report_key (dev, BTN_RIGHT, right); | ||
263 | input_report_key (dev, BTN_TOUCH, 0); | ||
264 | input_report_rel (dev, REL_X, dx); | ||
265 | input_report_rel (dev, REL_Y, dy); | ||
266 | input_sync (dev); | ||
267 | } | ||
268 | |||
269 | static void | ||
270 | vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) | ||
271 | { | ||
272 | struct input_dev *dev = &mouse->dev; | ||
273 | unsigned char *buf = mouse->buf; | ||
274 | int left, middle, right, touch; | ||
275 | int x, y; | ||
276 | |||
277 | /* | ||
278 | * Tablet position / button packet | ||
279 | * | ||
280 | * [0]: 1 1 0 B4 B3 B2 B1 Pr | ||
281 | * [1]: 0 0 X5 X4 X3 X2 X1 X0 | ||
282 | * [2]: 0 0 X11 X10 X9 X8 X7 X6 | ||
283 | * [3]: 0 0 Y5 Y4 Y3 Y2 Y1 Y0 | ||
284 | * [4]: 0 0 Y11 Y10 Y9 Y8 Y7 Y6 | ||
285 | */ | ||
286 | |||
287 | /* | ||
288 | * Get X/Y position. Y axis needs to be inverted since VSXXX-AB | ||
289 | * counts down->top while monitor counts top->bottom. | ||
290 | */ | ||
291 | x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f); | ||
292 | y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f); | ||
293 | y = 1023 - y; | ||
294 | |||
295 | /* | ||
296 | * Get button state. It's bits <4..1> of byte 0. | ||
297 | */ | ||
298 | left = (buf[0] & 0x02)? 1: 0; | ||
299 | middle = (buf[0] & 0x04)? 1: 0; | ||
300 | right = (buf[0] & 0x08)? 1: 0; | ||
301 | touch = (buf[0] & 0x10)? 1: 0; | ||
302 | |||
303 | vsxxxaa_drop_bytes (mouse, 5); | ||
304 | |||
305 | DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", | ||
306 | mouse->name, mouse->phys, x, y, | ||
307 | left? "L": "l", middle? "M": "m", | ||
308 | right? "R": "r", touch? "T": "t"); | ||
309 | |||
310 | /* | ||
311 | * Report what we've found so far... | ||
312 | */ | ||
313 | input_regs (dev, regs); | ||
314 | input_report_key (dev, BTN_LEFT, left); | ||
315 | input_report_key (dev, BTN_MIDDLE, middle); | ||
316 | input_report_key (dev, BTN_RIGHT, right); | ||
317 | input_report_key (dev, BTN_TOUCH, touch); | ||
318 | input_report_abs (dev, ABS_X, x); | ||
319 | input_report_abs (dev, ABS_Y, y); | ||
320 | input_sync (dev); | ||
321 | } | ||
322 | |||
323 | static void | ||
324 | vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) | ||
325 | { | ||
326 | struct input_dev *dev = &mouse->dev; | ||
327 | unsigned char *buf = mouse->buf; | ||
328 | int left, middle, right; | ||
329 | unsigned char error; | ||
330 | |||
331 | /* | ||
332 | * Check for Power-On-Reset packets. These are sent out | ||
333 | * after plugging the mouse in, or when explicitely | ||
334 | * requested by sending 'T'. | ||
335 | * | ||
336 | * [0]: 1 0 1 0 R3 R2 R1 R0 | ||
337 | * [1]: 0 M2 M1 M0 D3 D2 D1 D0 | ||
338 | * [2]: 0 E6 E5 E4 E3 E2 E1 E0 | ||
339 | * [3]: 0 0 0 0 0 Left Middle Right | ||
340 | * | ||
341 | * M: manufacturer location code | ||
342 | * R: revision code | ||
343 | * E: Error code. If it's in the range of 0x00..0x1f, only some | ||
344 | * minor problem occured. Errors >= 0x20 are considered bad | ||
345 | * and the device may not work properly... | ||
346 | * D: <0010> == mouse, <0100> == tablet | ||
347 | */ | ||
348 | |||
349 | mouse->version = buf[0] & 0x0f; | ||
350 | mouse->country = (buf[1] >> 4) & 0x07; | ||
351 | mouse->type = buf[1] & 0x0f; | ||
352 | error = buf[2] & 0x7f; | ||
353 | |||
354 | /* | ||
355 | * Get button state. It's the low three bits | ||
356 | * (for three buttons) of byte 0. Maybe even the bit <3> | ||
357 | * has some meaning if a tablet is attached. | ||
358 | */ | ||
359 | left = (buf[0] & 0x04)? 1: 0; | ||
360 | middle = (buf[0] & 0x02)? 1: 0; | ||
361 | right = (buf[0] & 0x01)? 1: 0; | ||
362 | |||
363 | vsxxxaa_drop_bytes (mouse, 4); | ||
364 | vsxxxaa_detection_done (mouse); | ||
365 | |||
366 | if (error <= 0x1f) { | ||
367 | /* No (serious) error. Report buttons */ | ||
368 | input_regs (dev, regs); | ||
369 | input_report_key (dev, BTN_LEFT, left); | ||
370 | input_report_key (dev, BTN_MIDDLE, middle); | ||
371 | input_report_key (dev, BTN_RIGHT, right); | ||
372 | input_report_key (dev, BTN_TOUCH, 0); | ||
373 | input_sync (dev); | ||
374 | |||
375 | if (error != 0) | ||
376 | printk (KERN_INFO "Your %s on %s reports error=0x%02x\n", | ||
377 | mouse->name, mouse->phys, error); | ||
378 | |||
379 | } | ||
380 | |||
381 | /* | ||
382 | * If the mouse was hot-plugged, we need to force differential mode | ||
383 | * now... However, give it a second to recover from it's reset. | ||
384 | */ | ||
385 | printk (KERN_NOTICE "%s on %s: Forceing standard packet format, " | ||
386 | "incremental streaming mode and 72 samples/sec\n", | ||
387 | mouse->name, mouse->phys); | ||
388 | mouse->serio->write (mouse->serio, 'S'); /* Standard format */ | ||
389 | mdelay (50); | ||
390 | mouse->serio->write (mouse->serio, 'R'); /* Incremental */ | ||
391 | mdelay (50); | ||
392 | mouse->serio->write (mouse->serio, 'L'); /* 72 samples/sec */ | ||
393 | } | ||
394 | |||
395 | static void | ||
396 | vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) | ||
397 | { | ||
398 | unsigned char *buf = mouse->buf; | ||
399 | int stray_bytes; | ||
400 | |||
401 | /* | ||
402 | * Parse buffer to death... | ||
403 | */ | ||
404 | do { | ||
405 | /* | ||
406 | * Out of sync? Throw away what we don't understand. Each | ||
407 | * packet starts with a byte whose bit 7 is set. Unhandled | ||
408 | * packets (ie. which we don't know about or simply b0rk3d | ||
409 | * data...) will get shifted out of the buffer after some | ||
410 | * activity on the mouse. | ||
411 | */ | ||
412 | while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { | ||
413 | printk (KERN_ERR "%s on %s: Dropping a byte to regain " | ||
414 | "sync with mouse data stream...\n", | ||
415 | mouse->name, mouse->phys); | ||
416 | vsxxxaa_drop_bytes (mouse, 1); | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * Check for packets we know about. | ||
421 | */ | ||
422 | |||
423 | if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) { | ||
424 | /* Check for broken packet */ | ||
425 | stray_bytes = vsxxxaa_check_packet (mouse, 3); | ||
426 | if (stray_bytes > 0) { | ||
427 | printk (KERN_ERR "Dropping %d bytes now...\n", | ||
428 | stray_bytes); | ||
429 | vsxxxaa_drop_bytes (mouse, stray_bytes); | ||
430 | continue; | ||
431 | } | ||
432 | |||
433 | vsxxxaa_handle_REL_packet (mouse, regs); | ||
434 | continue; /* More to parse? */ | ||
435 | } | ||
436 | |||
437 | if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) { | ||
438 | /* Check for broken packet */ | ||
439 | stray_bytes = vsxxxaa_check_packet (mouse, 5); | ||
440 | if (stray_bytes > 0) { | ||
441 | printk (KERN_ERR "Dropping %d bytes now...\n", | ||
442 | stray_bytes); | ||
443 | vsxxxaa_drop_bytes (mouse, stray_bytes); | ||
444 | continue; | ||
445 | } | ||
446 | |||
447 | vsxxxaa_handle_ABS_packet (mouse, regs); | ||
448 | continue; /* More to parse? */ | ||
449 | } | ||
450 | |||
451 | if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) { | ||
452 | /* Check for broken packet */ | ||
453 | stray_bytes = vsxxxaa_check_packet (mouse, 4); | ||
454 | if (stray_bytes > 0) { | ||
455 | printk (KERN_ERR "Dropping %d bytes now...\n", | ||
456 | stray_bytes); | ||
457 | vsxxxaa_drop_bytes (mouse, stray_bytes); | ||
458 | continue; | ||
459 | } | ||
460 | |||
461 | vsxxxaa_handle_POR_packet (mouse, regs); | ||
462 | continue; /* More to parse? */ | ||
463 | } | ||
464 | |||
465 | break; /* No REL, ABS or POR packet found */ | ||
466 | } while (1); | ||
467 | } | ||
468 | |||
469 | static irqreturn_t | ||
470 | vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags, | ||
471 | struct pt_regs *regs) | ||
472 | { | ||
473 | struct vsxxxaa *mouse = serio_get_drvdata (serio); | ||
474 | |||
475 | vsxxxaa_queue_byte (mouse, data); | ||
476 | vsxxxaa_parse_buffer (mouse, regs); | ||
477 | |||
478 | return IRQ_HANDLED; | ||
479 | } | ||
480 | |||
481 | static void | ||
482 | vsxxxaa_disconnect (struct serio *serio) | ||
483 | { | ||
484 | struct vsxxxaa *mouse = serio_get_drvdata (serio); | ||
485 | |||
486 | input_unregister_device (&mouse->dev); | ||
487 | serio_close (serio); | ||
488 | serio_set_drvdata (serio, NULL); | ||
489 | kfree (mouse); | ||
490 | } | ||
491 | |||
492 | static int | ||
493 | vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) | ||
494 | { | ||
495 | struct vsxxxaa *mouse; | ||
496 | int err; | ||
497 | |||
498 | if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL))) | ||
499 | return -ENOMEM; | ||
500 | |||
501 | memset (mouse, 0, sizeof (struct vsxxxaa)); | ||
502 | |||
503 | init_input_dev (&mouse->dev); | ||
504 | set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */ | ||
505 | set_bit (EV_REL, mouse->dev.evbit); | ||
506 | set_bit (EV_ABS, mouse->dev.evbit); | ||
507 | set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */ | ||
508 | set_bit (BTN_MIDDLE, mouse->dev.keybit); | ||
509 | set_bit (BTN_RIGHT, mouse->dev.keybit); | ||
510 | set_bit (BTN_TOUCH, mouse->dev.keybit); /* ...and Tablet */ | ||
511 | set_bit (REL_X, mouse->dev.relbit); | ||
512 | set_bit (REL_Y, mouse->dev.relbit); | ||
513 | set_bit (ABS_X, mouse->dev.absbit); | ||
514 | set_bit (ABS_Y, mouse->dev.absbit); | ||
515 | |||
516 | mouse->dev.absmin[ABS_X] = 0; | ||
517 | mouse->dev.absmax[ABS_X] = 1023; | ||
518 | mouse->dev.absmin[ABS_Y] = 0; | ||
519 | mouse->dev.absmax[ABS_Y] = 1023; | ||
520 | |||
521 | mouse->dev.private = mouse; | ||
522 | |||
523 | sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer"); | ||
524 | sprintf (mouse->phys, "%s/input0", serio->phys); | ||
525 | mouse->dev.name = mouse->name; | ||
526 | mouse->dev.phys = mouse->phys; | ||
527 | mouse->dev.id.bustype = BUS_RS232; | ||
528 | mouse->dev.dev = &serio->dev; | ||
529 | mouse->serio = serio; | ||
530 | |||
531 | serio_set_drvdata (serio, mouse); | ||
532 | |||
533 | err = serio_open (serio, drv); | ||
534 | if (err) { | ||
535 | serio_set_drvdata (serio, NULL); | ||
536 | kfree (mouse); | ||
537 | return err; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * Request selftest. Standard packet format and differential | ||
542 | * mode will be requested after the device ID'ed successfully. | ||
543 | */ | ||
544 | mouse->serio->write (mouse->serio, 'T'); /* Test */ | ||
545 | |||
546 | input_register_device (&mouse->dev); | ||
547 | |||
548 | printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static struct serio_device_id vsxxaa_serio_ids[] = { | ||
554 | { | ||
555 | .type = SERIO_RS232, | ||
556 | .proto = SERIO_VSXXXAA, | ||
557 | .id = SERIO_ANY, | ||
558 | .extra = SERIO_ANY, | ||
559 | }, | ||
560 | { 0 } | ||
561 | }; | ||
562 | |||
563 | MODULE_DEVICE_TABLE(serio, vsxxaa_serio_ids); | ||
564 | |||
565 | static struct serio_driver vsxxxaa_drv = { | ||
566 | .driver = { | ||
567 | .name = "vsxxxaa", | ||
568 | }, | ||
569 | .description = DRIVER_DESC, | ||
570 | .id_table = vsxxaa_serio_ids, | ||
571 | .connect = vsxxxaa_connect, | ||
572 | .interrupt = vsxxxaa_interrupt, | ||
573 | .disconnect = vsxxxaa_disconnect, | ||
574 | }; | ||
575 | |||
576 | static int __init | ||
577 | vsxxxaa_init (void) | ||
578 | { | ||
579 | serio_register_driver(&vsxxxaa_drv); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static void __exit | ||
584 | vsxxxaa_exit (void) | ||
585 | { | ||
586 | serio_unregister_driver(&vsxxxaa_drv); | ||
587 | } | ||
588 | |||
589 | module_init (vsxxxaa_init); | ||
590 | module_exit (vsxxxaa_exit); | ||
591 | |||
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c new file mode 100644 index 000000000000..564974ce5793 --- /dev/null +++ b/drivers/input/mousedev.c | |||
@@ -0,0 +1,758 @@ | |||
1 | /* | ||
2 | * Input driver to ExplorerPS/2 device driver module. | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #define MOUSEDEV_MINOR_BASE 32 | ||
13 | #define MOUSEDEV_MINORS 32 | ||
14 | #define MOUSEDEV_MIX 31 | ||
15 | |||
16 | #include <linux/slab.h> | ||
17 | #include <linux/poll.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/config.h> | ||
23 | #include <linux/smp_lock.h> | ||
24 | #include <linux/random.h> | ||
25 | #include <linux/major.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/devfs_fs_kernel.h> | ||
28 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | ||
29 | #include <linux/miscdevice.h> | ||
30 | #endif | ||
31 | |||
32 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
33 | MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X | ||
37 | #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 | ||
38 | #endif | ||
39 | #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y | ||
40 | #define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 | ||
41 | #endif | ||
42 | |||
43 | static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; | ||
44 | module_param(xres, uint, 0); | ||
45 | MODULE_PARM_DESC(xres, "Horizontal screen resolution"); | ||
46 | |||
47 | static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; | ||
48 | module_param(yres, uint, 0); | ||
49 | MODULE_PARM_DESC(yres, "Vertical screen resolution"); | ||
50 | |||
51 | static unsigned tap_time = 200; | ||
52 | module_param(tap_time, uint, 0); | ||
53 | MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); | ||
54 | |||
55 | struct mousedev_hw_data { | ||
56 | int dx, dy, dz; | ||
57 | int x, y; | ||
58 | int abs_event; | ||
59 | unsigned long buttons; | ||
60 | }; | ||
61 | |||
62 | struct mousedev { | ||
63 | int exist; | ||
64 | int open; | ||
65 | int minor; | ||
66 | char name[16]; | ||
67 | wait_queue_head_t wait; | ||
68 | struct list_head list; | ||
69 | struct input_handle handle; | ||
70 | |||
71 | struct mousedev_hw_data packet; | ||
72 | unsigned int pkt_count; | ||
73 | int old_x[4], old_y[4]; | ||
74 | int frac_dx, frac_dy; | ||
75 | unsigned long touch; | ||
76 | }; | ||
77 | |||
78 | enum mousedev_emul { | ||
79 | MOUSEDEV_EMUL_PS2, | ||
80 | MOUSEDEV_EMUL_IMPS, | ||
81 | MOUSEDEV_EMUL_EXPS | ||
82 | }; | ||
83 | |||
84 | struct mousedev_motion { | ||
85 | int dx, dy, dz; | ||
86 | unsigned long buttons; | ||
87 | }; | ||
88 | |||
89 | #define PACKET_QUEUE_LEN 16 | ||
90 | struct mousedev_list { | ||
91 | struct fasync_struct *fasync; | ||
92 | struct mousedev *mousedev; | ||
93 | struct list_head node; | ||
94 | |||
95 | struct mousedev_motion packets[PACKET_QUEUE_LEN]; | ||
96 | unsigned int head, tail; | ||
97 | spinlock_t packet_lock; | ||
98 | int pos_x, pos_y; | ||
99 | |||
100 | signed char ps2[6]; | ||
101 | unsigned char ready, buffer, bufsiz; | ||
102 | unsigned char imexseq, impsseq; | ||
103 | enum mousedev_emul mode; | ||
104 | }; | ||
105 | |||
106 | #define MOUSEDEV_SEQ_LEN 6 | ||
107 | |||
108 | static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; | ||
109 | static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | ||
110 | |||
111 | static struct input_handler mousedev_handler; | ||
112 | |||
113 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | ||
114 | static struct mousedev mousedev_mix; | ||
115 | |||
116 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) | ||
117 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) | ||
118 | |||
119 | static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) | ||
120 | { | ||
121 | int size, tmp; | ||
122 | enum { FRACTION_DENOM = 128 }; | ||
123 | |||
124 | if (mousedev->touch) { | ||
125 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | ||
126 | if (size == 0) size = 256 * 2; | ||
127 | switch (code) { | ||
128 | case ABS_X: | ||
129 | fx(0) = value; | ||
130 | if (mousedev->pkt_count >= 2) { | ||
131 | tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; | ||
132 | tmp += mousedev->frac_dx; | ||
133 | mousedev->packet.dx = tmp / FRACTION_DENOM; | ||
134 | mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; | ||
135 | } | ||
136 | break; | ||
137 | |||
138 | case ABS_Y: | ||
139 | fy(0) = value; | ||
140 | if (mousedev->pkt_count >= 2) { | ||
141 | tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; | ||
142 | tmp += mousedev->frac_dy; | ||
143 | mousedev->packet.dy = tmp / FRACTION_DENOM; | ||
144 | mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; | ||
145 | } | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) | ||
152 | { | ||
153 | int size; | ||
154 | |||
155 | switch (code) { | ||
156 | case ABS_X: | ||
157 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | ||
158 | if (size == 0) size = xres; | ||
159 | if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X]; | ||
160 | if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X]; | ||
161 | mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; | ||
162 | mousedev->packet.abs_event = 1; | ||
163 | break; | ||
164 | |||
165 | case ABS_Y: | ||
166 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | ||
167 | if (size == 0) size = yres; | ||
168 | if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y]; | ||
169 | if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y]; | ||
170 | mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; | ||
171 | mousedev->packet.abs_event = 1; | ||
172 | break; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value) | ||
177 | { | ||
178 | switch (code) { | ||
179 | case REL_X: mousedev->packet.dx += value; break; | ||
180 | case REL_Y: mousedev->packet.dy -= value; break; | ||
181 | case REL_WHEEL: mousedev->packet.dz -= value; break; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value) | ||
186 | { | ||
187 | int index; | ||
188 | |||
189 | switch (code) { | ||
190 | case BTN_TOUCH: | ||
191 | case BTN_0: | ||
192 | case BTN_FORWARD: | ||
193 | case BTN_LEFT: index = 0; break; | ||
194 | case BTN_STYLUS: | ||
195 | case BTN_1: | ||
196 | case BTN_RIGHT: index = 1; break; | ||
197 | case BTN_2: | ||
198 | case BTN_STYLUS2: | ||
199 | case BTN_MIDDLE: index = 2; break; | ||
200 | case BTN_3: | ||
201 | case BTN_BACK: | ||
202 | case BTN_SIDE: index = 3; break; | ||
203 | case BTN_4: | ||
204 | case BTN_EXTRA: index = 4; break; | ||
205 | default: return; | ||
206 | } | ||
207 | |||
208 | if (value) { | ||
209 | set_bit(index, &mousedev->packet.buttons); | ||
210 | set_bit(index, &mousedev_mix.packet.buttons); | ||
211 | } else { | ||
212 | clear_bit(index, &mousedev->packet.buttons); | ||
213 | clear_bit(index, &mousedev_mix.packet.buttons); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) | ||
218 | { | ||
219 | struct mousedev_list *list; | ||
220 | struct mousedev_motion *p; | ||
221 | unsigned long flags; | ||
222 | |||
223 | list_for_each_entry(list, &mousedev->list, node) { | ||
224 | spin_lock_irqsave(&list->packet_lock, flags); | ||
225 | |||
226 | p = &list->packets[list->head]; | ||
227 | if (list->ready && p->buttons != packet->buttons) { | ||
228 | unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; | ||
229 | if (new_head != list->tail) { | ||
230 | p = &list->packets[list->head = new_head]; | ||
231 | memset(p, 0, sizeof(struct mousedev_motion)); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (packet->abs_event) { | ||
236 | p->dx += packet->x - list->pos_x; | ||
237 | p->dy += packet->y - list->pos_y; | ||
238 | list->pos_x = packet->x; | ||
239 | list->pos_y = packet->y; | ||
240 | } | ||
241 | |||
242 | list->pos_x += packet->dx; | ||
243 | list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x); | ||
244 | list->pos_y += packet->dy; | ||
245 | list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y); | ||
246 | |||
247 | p->dx += packet->dx; | ||
248 | p->dy += packet->dy; | ||
249 | p->dz += packet->dz; | ||
250 | p->buttons = mousedev->packet.buttons; | ||
251 | |||
252 | list->ready = 1; | ||
253 | |||
254 | spin_unlock_irqrestore(&list->packet_lock, flags); | ||
255 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
256 | } | ||
257 | |||
258 | wake_up_interruptible(&mousedev->wait); | ||
259 | } | ||
260 | |||
261 | static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | ||
262 | { | ||
263 | if (!value) { | ||
264 | if (mousedev->touch && | ||
265 | time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { | ||
266 | /* | ||
267 | * Toggle left button to emulate tap. | ||
268 | * We rely on the fact that mousedev_mix always has 0 | ||
269 | * motion packet so we won't mess current position. | ||
270 | */ | ||
271 | set_bit(0, &mousedev->packet.buttons); | ||
272 | set_bit(0, &mousedev_mix.packet.buttons); | ||
273 | mousedev_notify_readers(mousedev, &mousedev_mix.packet); | ||
274 | mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet); | ||
275 | clear_bit(0, &mousedev->packet.buttons); | ||
276 | clear_bit(0, &mousedev_mix.packet.buttons); | ||
277 | } | ||
278 | mousedev->touch = mousedev->pkt_count = 0; | ||
279 | mousedev->frac_dx = 0; | ||
280 | mousedev->frac_dy = 0; | ||
281 | } | ||
282 | else | ||
283 | if (!mousedev->touch) | ||
284 | mousedev->touch = jiffies; | ||
285 | } | ||
286 | |||
287 | static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | ||
288 | { | ||
289 | struct mousedev *mousedev = handle->private; | ||
290 | |||
291 | switch (type) { | ||
292 | case EV_ABS: | ||
293 | /* Ignore joysticks */ | ||
294 | if (test_bit(BTN_TRIGGER, handle->dev->keybit)) | ||
295 | return; | ||
296 | |||
297 | if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | ||
298 | mousedev_touchpad_event(handle->dev, mousedev, code, value); | ||
299 | else | ||
300 | mousedev_abs_event(handle->dev, mousedev, code, value); | ||
301 | |||
302 | break; | ||
303 | |||
304 | case EV_REL: | ||
305 | mousedev_rel_event(mousedev, code, value); | ||
306 | break; | ||
307 | |||
308 | case EV_KEY: | ||
309 | if (value != 2) { | ||
310 | if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | ||
311 | mousedev_touchpad_touch(mousedev, value); | ||
312 | else | ||
313 | mousedev_key_event(mousedev, code, value); | ||
314 | } | ||
315 | break; | ||
316 | |||
317 | case EV_SYN: | ||
318 | if (code == SYN_REPORT) { | ||
319 | if (mousedev->touch) { | ||
320 | mousedev->pkt_count++; | ||
321 | /* Input system eats duplicate events, but we need all of them | ||
322 | * to do correct averaging so apply present one forward | ||
323 | */ | ||
324 | fx(0) = fx(1); | ||
325 | fy(0) = fy(1); | ||
326 | } | ||
327 | |||
328 | mousedev_notify_readers(mousedev, &mousedev->packet); | ||
329 | mousedev_notify_readers(&mousedev_mix, &mousedev->packet); | ||
330 | |||
331 | mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; | ||
332 | mousedev->packet.abs_event = 0; | ||
333 | } | ||
334 | break; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | static int mousedev_fasync(int fd, struct file *file, int on) | ||
339 | { | ||
340 | int retval; | ||
341 | struct mousedev_list *list = file->private_data; | ||
342 | retval = fasync_helper(fd, file, on, &list->fasync); | ||
343 | return retval < 0 ? retval : 0; | ||
344 | } | ||
345 | |||
346 | static void mousedev_free(struct mousedev *mousedev) | ||
347 | { | ||
348 | mousedev_table[mousedev->minor] = NULL; | ||
349 | kfree(mousedev); | ||
350 | } | ||
351 | |||
352 | static int mixdev_release(void) | ||
353 | { | ||
354 | struct input_handle *handle; | ||
355 | |||
356 | list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { | ||
357 | struct mousedev *mousedev = handle->private; | ||
358 | |||
359 | if (!mousedev->open) { | ||
360 | if (mousedev->exist) | ||
361 | input_close_device(&mousedev->handle); | ||
362 | else | ||
363 | mousedev_free(mousedev); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int mousedev_release(struct inode * inode, struct file * file) | ||
371 | { | ||
372 | struct mousedev_list *list = file->private_data; | ||
373 | |||
374 | mousedev_fasync(-1, file, 0); | ||
375 | |||
376 | list_del(&list->node); | ||
377 | |||
378 | if (!--list->mousedev->open) { | ||
379 | if (list->mousedev->minor == MOUSEDEV_MIX) | ||
380 | return mixdev_release(); | ||
381 | |||
382 | if (!mousedev_mix.open) { | ||
383 | if (list->mousedev->exist) | ||
384 | input_close_device(&list->mousedev->handle); | ||
385 | else | ||
386 | mousedev_free(list->mousedev); | ||
387 | } | ||
388 | } | ||
389 | |||
390 | kfree(list); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int mousedev_open(struct inode * inode, struct file * file) | ||
395 | { | ||
396 | struct mousedev_list *list; | ||
397 | struct input_handle *handle; | ||
398 | struct mousedev *mousedev; | ||
399 | int i; | ||
400 | |||
401 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | ||
402 | if (imajor(inode) == MISC_MAJOR) | ||
403 | i = MOUSEDEV_MIX; | ||
404 | else | ||
405 | #endif | ||
406 | i = iminor(inode) - MOUSEDEV_MINOR_BASE; | ||
407 | |||
408 | if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) | ||
409 | return -ENODEV; | ||
410 | |||
411 | if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) | ||
412 | return -ENOMEM; | ||
413 | memset(list, 0, sizeof(struct mousedev_list)); | ||
414 | |||
415 | spin_lock_init(&list->packet_lock); | ||
416 | list->pos_x = xres / 2; | ||
417 | list->pos_y = yres / 2; | ||
418 | list->mousedev = mousedev_table[i]; | ||
419 | list_add_tail(&list->node, &mousedev_table[i]->list); | ||
420 | file->private_data = list; | ||
421 | |||
422 | if (!list->mousedev->open++) { | ||
423 | if (list->mousedev->minor == MOUSEDEV_MIX) { | ||
424 | list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { | ||
425 | mousedev = handle->private; | ||
426 | if (!mousedev->open && mousedev->exist) | ||
427 | input_open_device(handle); | ||
428 | } | ||
429 | } else | ||
430 | if (!mousedev_mix.open && list->mousedev->exist) | ||
431 | input_open_device(&list->mousedev->handle); | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static inline int mousedev_limit_delta(int delta, int limit) | ||
438 | { | ||
439 | return delta > limit ? limit : (delta < -limit ? -limit : delta); | ||
440 | } | ||
441 | |||
442 | static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) | ||
443 | { | ||
444 | struct mousedev_motion *p; | ||
445 | unsigned long flags; | ||
446 | |||
447 | spin_lock_irqsave(&list->packet_lock, flags); | ||
448 | p = &list->packets[list->tail]; | ||
449 | |||
450 | ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); | ||
451 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); | ||
452 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); | ||
453 | p->dx -= ps2_data[1]; | ||
454 | p->dy -= ps2_data[2]; | ||
455 | |||
456 | switch (list->mode) { | ||
457 | case MOUSEDEV_EMUL_EXPS: | ||
458 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); | ||
459 | p->dz -= ps2_data[3]; | ||
460 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); | ||
461 | list->bufsiz = 4; | ||
462 | break; | ||
463 | |||
464 | case MOUSEDEV_EMUL_IMPS: | ||
465 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | ||
466 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); | ||
467 | p->dz -= ps2_data[3]; | ||
468 | list->bufsiz = 4; | ||
469 | break; | ||
470 | |||
471 | case MOUSEDEV_EMUL_PS2: | ||
472 | default: | ||
473 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | ||
474 | p->dz = 0; | ||
475 | list->bufsiz = 3; | ||
476 | break; | ||
477 | } | ||
478 | |||
479 | if (!p->dx && !p->dy && !p->dz) { | ||
480 | if (list->tail == list->head) | ||
481 | list->ready = 0; | ||
482 | else | ||
483 | list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; | ||
484 | } | ||
485 | |||
486 | spin_unlock_irqrestore(&list->packet_lock, flags); | ||
487 | } | ||
488 | |||
489 | |||
490 | static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | ||
491 | { | ||
492 | struct mousedev_list *list = file->private_data; | ||
493 | unsigned char c; | ||
494 | unsigned int i; | ||
495 | |||
496 | for (i = 0; i < count; i++) { | ||
497 | |||
498 | if (get_user(c, buffer + i)) | ||
499 | return -EFAULT; | ||
500 | |||
501 | if (c == mousedev_imex_seq[list->imexseq]) { | ||
502 | if (++list->imexseq == MOUSEDEV_SEQ_LEN) { | ||
503 | list->imexseq = 0; | ||
504 | list->mode = MOUSEDEV_EMUL_EXPS; | ||
505 | } | ||
506 | } else list->imexseq = 0; | ||
507 | |||
508 | if (c == mousedev_imps_seq[list->impsseq]) { | ||
509 | if (++list->impsseq == MOUSEDEV_SEQ_LEN) { | ||
510 | list->impsseq = 0; | ||
511 | list->mode = MOUSEDEV_EMUL_IMPS; | ||
512 | } | ||
513 | } else list->impsseq = 0; | ||
514 | |||
515 | list->ps2[0] = 0xfa; | ||
516 | |||
517 | switch (c) { | ||
518 | |||
519 | case 0xeb: /* Poll */ | ||
520 | mousedev_packet(list, &list->ps2[1]); | ||
521 | list->bufsiz++; /* account for leading ACK */ | ||
522 | break; | ||
523 | |||
524 | case 0xf2: /* Get ID */ | ||
525 | switch (list->mode) { | ||
526 | case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break; | ||
527 | case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break; | ||
528 | case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break; | ||
529 | } | ||
530 | list->bufsiz = 2; | ||
531 | break; | ||
532 | |||
533 | case 0xe9: /* Get info */ | ||
534 | list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; | ||
535 | list->bufsiz = 4; | ||
536 | break; | ||
537 | |||
538 | case 0xff: /* Reset */ | ||
539 | list->impsseq = list->imexseq = 0; | ||
540 | list->mode = MOUSEDEV_EMUL_PS2; | ||
541 | list->ps2[1] = 0xaa; list->ps2[2] = 0x00; | ||
542 | list->bufsiz = 3; | ||
543 | break; | ||
544 | |||
545 | default: | ||
546 | list->bufsiz = 1; | ||
547 | break; | ||
548 | } | ||
549 | |||
550 | list->buffer = list->bufsiz; | ||
551 | } | ||
552 | |||
553 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
554 | |||
555 | wake_up_interruptible(&list->mousedev->wait); | ||
556 | |||
557 | return count; | ||
558 | } | ||
559 | |||
560 | static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) | ||
561 | { | ||
562 | struct mousedev_list *list = file->private_data; | ||
563 | int retval = 0; | ||
564 | |||
565 | if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK)) | ||
566 | return -EAGAIN; | ||
567 | |||
568 | retval = wait_event_interruptible(list->mousedev->wait, | ||
569 | !list->mousedev->exist || list->ready || list->buffer); | ||
570 | |||
571 | if (retval) | ||
572 | return retval; | ||
573 | |||
574 | if (!list->mousedev->exist) | ||
575 | return -ENODEV; | ||
576 | |||
577 | if (!list->buffer && list->ready) { | ||
578 | mousedev_packet(list, list->ps2); | ||
579 | list->buffer = list->bufsiz; | ||
580 | } | ||
581 | |||
582 | if (count > list->buffer) | ||
583 | count = list->buffer; | ||
584 | |||
585 | list->buffer -= count; | ||
586 | |||
587 | if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count)) | ||
588 | return -EFAULT; | ||
589 | |||
590 | return count; | ||
591 | } | ||
592 | |||
593 | /* No kernel lock - fine */ | ||
594 | static unsigned int mousedev_poll(struct file *file, poll_table *wait) | ||
595 | { | ||
596 | struct mousedev_list *list = file->private_data; | ||
597 | poll_wait(file, &list->mousedev->wait, wait); | ||
598 | return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) | | ||
599 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); | ||
600 | } | ||
601 | |||
602 | static struct file_operations mousedev_fops = { | ||
603 | .owner = THIS_MODULE, | ||
604 | .read = mousedev_read, | ||
605 | .write = mousedev_write, | ||
606 | .poll = mousedev_poll, | ||
607 | .open = mousedev_open, | ||
608 | .release = mousedev_release, | ||
609 | .fasync = mousedev_fasync, | ||
610 | }; | ||
611 | |||
612 | static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | ||
613 | { | ||
614 | struct mousedev *mousedev; | ||
615 | int minor = 0; | ||
616 | |||
617 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | ||
618 | if (minor == MOUSEDEV_MINORS) { | ||
619 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | ||
620 | return NULL; | ||
621 | } | ||
622 | |||
623 | if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL))) | ||
624 | return NULL; | ||
625 | memset(mousedev, 0, sizeof(struct mousedev)); | ||
626 | |||
627 | INIT_LIST_HEAD(&mousedev->list); | ||
628 | init_waitqueue_head(&mousedev->wait); | ||
629 | |||
630 | mousedev->minor = minor; | ||
631 | mousedev->exist = 1; | ||
632 | mousedev->handle.dev = dev; | ||
633 | mousedev->handle.name = mousedev->name; | ||
634 | mousedev->handle.handler = handler; | ||
635 | mousedev->handle.private = mousedev; | ||
636 | sprintf(mousedev->name, "mouse%d", minor); | ||
637 | |||
638 | if (mousedev_mix.open) | ||
639 | input_open_device(&mousedev->handle); | ||
640 | |||
641 | mousedev_table[minor] = mousedev; | ||
642 | |||
643 | devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), | ||
644 | S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); | ||
645 | class_simple_device_add(input_class, | ||
646 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), | ||
647 | dev->dev, "mouse%d", minor); | ||
648 | |||
649 | return &mousedev->handle; | ||
650 | } | ||
651 | |||
652 | static void mousedev_disconnect(struct input_handle *handle) | ||
653 | { | ||
654 | struct mousedev *mousedev = handle->private; | ||
655 | struct mousedev_list *list; | ||
656 | |||
657 | class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); | ||
658 | devfs_remove("input/mouse%d", mousedev->minor); | ||
659 | mousedev->exist = 0; | ||
660 | |||
661 | if (mousedev->open) { | ||
662 | input_close_device(handle); | ||
663 | wake_up_interruptible(&mousedev->wait); | ||
664 | list_for_each_entry(list, &mousedev->list, node) | ||
665 | kill_fasync(&list->fasync, SIGIO, POLL_HUP); | ||
666 | } else { | ||
667 | if (mousedev_mix.open) | ||
668 | input_close_device(handle); | ||
669 | mousedev_free(mousedev); | ||
670 | } | ||
671 | } | ||
672 | |||
673 | static struct input_device_id mousedev_ids[] = { | ||
674 | { | ||
675 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | ||
676 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | ||
677 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | ||
678 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | ||
679 | }, /* A mouse like device, at least one button, two relative axes */ | ||
680 | { | ||
681 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | ||
682 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | ||
683 | .relbit = { BIT(REL_WHEEL) }, | ||
684 | }, /* A separate scrollwheel */ | ||
685 | { | ||
686 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
687 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | ||
688 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | ||
689 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | ||
690 | }, /* A tablet like device, at least touch detection, two absolute axes */ | ||
691 | { | ||
692 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
693 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | ||
694 | .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, | ||
695 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) }, | ||
696 | }, /* A touchpad */ | ||
697 | |||
698 | { }, /* Terminating entry */ | ||
699 | }; | ||
700 | |||
701 | MODULE_DEVICE_TABLE(input, mousedev_ids); | ||
702 | |||
703 | static struct input_handler mousedev_handler = { | ||
704 | .event = mousedev_event, | ||
705 | .connect = mousedev_connect, | ||
706 | .disconnect = mousedev_disconnect, | ||
707 | .fops = &mousedev_fops, | ||
708 | .minor = MOUSEDEV_MINOR_BASE, | ||
709 | .name = "mousedev", | ||
710 | .id_table = mousedev_ids, | ||
711 | }; | ||
712 | |||
713 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | ||
714 | static struct miscdevice psaux_mouse = { | ||
715 | PSMOUSE_MINOR, "psaux", &mousedev_fops | ||
716 | }; | ||
717 | static int psaux_registered; | ||
718 | #endif | ||
719 | |||
720 | static int __init mousedev_init(void) | ||
721 | { | ||
722 | input_register_handler(&mousedev_handler); | ||
723 | |||
724 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); | ||
725 | INIT_LIST_HEAD(&mousedev_mix.list); | ||
726 | init_waitqueue_head(&mousedev_mix.wait); | ||
727 | mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; | ||
728 | mousedev_mix.exist = 1; | ||
729 | mousedev_mix.minor = MOUSEDEV_MIX; | ||
730 | |||
731 | devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), | ||
732 | S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); | ||
733 | class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), | ||
734 | NULL, "mice"); | ||
735 | |||
736 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | ||
737 | if (!(psaux_registered = !misc_register(&psaux_mouse))) | ||
738 | printk(KERN_WARNING "mice: could not misc_register the device\n"); | ||
739 | #endif | ||
740 | |||
741 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static void __exit mousedev_exit(void) | ||
747 | { | ||
748 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | ||
749 | if (psaux_registered) | ||
750 | misc_deregister(&psaux_mouse); | ||
751 | #endif | ||
752 | devfs_remove("input/mice"); | ||
753 | class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); | ||
754 | input_unregister_handler(&mousedev_handler); | ||
755 | } | ||
756 | |||
757 | module_init(mousedev_init); | ||
758 | module_exit(mousedev_exit); | ||
diff --git a/drivers/input/power.c b/drivers/input/power.c new file mode 100644 index 000000000000..bfc5c63ebffe --- /dev/null +++ b/drivers/input/power.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2001 "Crazy" James Simmons | ||
5 | * | ||
6 | * Input driver Power Management. | ||
7 | * | ||
8 | * Sponsored by Transvirtual Technology. | ||
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 by | ||
27 | * e-mail - mail your message to <jsimmons@transvirtual.com>. | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/config.h> | ||
32 | #include <linux/input.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/tty.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/pm.h> | ||
38 | |||
39 | static struct input_handler power_handler; | ||
40 | |||
41 | /* | ||
42 | * Power management can't be done in a interrupt context. So we have to | ||
43 | * use keventd. | ||
44 | */ | ||
45 | static int suspend_button_pushed = 0; | ||
46 | static void suspend_button_task_handler(void *data) | ||
47 | { | ||
48 | udelay(200); /* debounce */ | ||
49 | suspend_button_pushed = 0; | ||
50 | } | ||
51 | |||
52 | static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); | ||
53 | |||
54 | static void power_event(struct input_handle *handle, unsigned int type, | ||
55 | unsigned int code, int down) | ||
56 | { | ||
57 | struct input_dev *dev = handle->dev; | ||
58 | |||
59 | printk("Entering power_event\n"); | ||
60 | |||
61 | if (type == EV_PWR) { | ||
62 | switch (code) { | ||
63 | case KEY_SUSPEND: | ||
64 | printk("Powering down entire device\n"); | ||
65 | |||
66 | if (!suspend_button_pushed) { | ||
67 | suspend_button_pushed = 1; | ||
68 | schedule_work(&suspend_button_task); | ||
69 | } | ||
70 | break; | ||
71 | case KEY_POWER: | ||
72 | /* Hum power down the machine. */ | ||
73 | break; | ||
74 | default: | ||
75 | return; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | if (type == EV_KEY) { | ||
80 | switch (code) { | ||
81 | case KEY_SUSPEND: | ||
82 | printk("Powering down input device\n"); | ||
83 | /* This is risky. See pm.h for details. */ | ||
84 | if (dev->state != PM_RESUME) | ||
85 | dev->state = PM_RESUME; | ||
86 | else | ||
87 | dev->state = PM_SUSPEND; | ||
88 | pm_send(dev->pm_dev, dev->state, dev); | ||
89 | break; | ||
90 | case KEY_POWER: | ||
91 | /* Turn the input device off completely ? */ | ||
92 | break; | ||
93 | default: | ||
94 | return; | ||
95 | } | ||
96 | } | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | static struct input_handle *power_connect(struct input_handler *handler, | ||
101 | struct input_dev *dev, | ||
102 | struct input_device_id *id) | ||
103 | { | ||
104 | struct input_handle *handle; | ||
105 | |||
106 | if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) | ||
107 | return NULL; | ||
108 | memset(handle, 0, sizeof(struct input_handle)); | ||
109 | |||
110 | handle->dev = dev; | ||
111 | handle->handler = handler; | ||
112 | |||
113 | input_open_device(handle); | ||
114 | |||
115 | printk(KERN_INFO "power.c: Adding power management to input layer\n"); | ||
116 | return handle; | ||
117 | } | ||
118 | |||
119 | static void power_disconnect(struct input_handle *handle) | ||
120 | { | ||
121 | input_close_device(handle); | ||
122 | kfree(handle); | ||
123 | } | ||
124 | |||
125 | static struct input_device_id power_ids[] = { | ||
126 | { | ||
127 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
128 | .evbit = { BIT(EV_KEY) }, | ||
129 | .keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } | ||
130 | }, | ||
131 | { | ||
132 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
133 | .evbit = { BIT(EV_KEY) }, | ||
134 | .keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) } | ||
135 | }, | ||
136 | { | ||
137 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, | ||
138 | .evbit = { BIT(EV_PWR) }, | ||
139 | }, | ||
140 | { }, /* Terminating entry */ | ||
141 | }; | ||
142 | |||
143 | MODULE_DEVICE_TABLE(input, power_ids); | ||
144 | |||
145 | static struct input_handler power_handler = { | ||
146 | .event = power_event, | ||
147 | .connect = power_connect, | ||
148 | .disconnect = power_disconnect, | ||
149 | .name = "power", | ||
150 | .id_table = power_ids, | ||
151 | }; | ||
152 | |||
153 | static int __init power_init(void) | ||
154 | { | ||
155 | input_register_handler(&power_handler); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static void __exit power_exit(void) | ||
160 | { | ||
161 | input_unregister_handler(&power_handler); | ||
162 | } | ||
163 | |||
164 | module_init(power_init); | ||
165 | module_exit(power_exit); | ||
166 | |||
167 | MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); | ||
168 | MODULE_DESCRIPTION("Input Power Management driver"); | ||
169 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig new file mode 100644 index 000000000000..b3710733b36b --- /dev/null +++ b/drivers/input/serio/Kconfig | |||
@@ -0,0 +1,183 @@ | |||
1 | # | ||
2 | # Input core configuration | ||
3 | # | ||
4 | config SERIO | ||
5 | tristate "Serial I/O support" if EMBEDDED || !X86 | ||
6 | default y | ||
7 | ---help--- | ||
8 | Say Yes here if you have any input device that uses serial I/O to | ||
9 | communicate with the system. This includes the | ||
10 | * standard AT keyboard and PS/2 mouse * | ||
11 | as well as serial mice, Sun keyboards, some joysticks and 6dof | ||
12 | devices and more. | ||
13 | |||
14 | If unsure, say Y. | ||
15 | |||
16 | To compile this driver as a module, choose M here: the | ||
17 | module will be called serio. | ||
18 | |||
19 | if SERIO | ||
20 | |||
21 | config SERIO_I8042 | ||
22 | tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 | ||
23 | default y | ||
24 | depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K | ||
25 | ---help--- | ||
26 | i8042 is the chip over which the standard AT keyboard and PS/2 | ||
27 | mouse are connected to the computer. If you use these devices, | ||
28 | you'll need to say Y here. | ||
29 | |||
30 | If unsure, say Y. | ||
31 | |||
32 | To compile this driver as a module, choose M here: the | ||
33 | module will be called i8042. | ||
34 | |||
35 | config SERIO_SERPORT | ||
36 | tristate "Serial port line discipline" | ||
37 | default y | ||
38 | ---help--- | ||
39 | Say Y here if you plan to use an input device (mouse, joystick, | ||
40 | tablet, 6dof) that communicates over the RS232 serial (COM) port. | ||
41 | |||
42 | More information is available: <file:Documentation/input/input.txt> | ||
43 | |||
44 | If unsure, say Y. | ||
45 | |||
46 | To compile this driver as a module, choose M here: the | ||
47 | module will be called serport. | ||
48 | |||
49 | config SERIO_CT82C710 | ||
50 | tristate "ct82c710 Aux port controller" | ||
51 | depends on X86 | ||
52 | ---help--- | ||
53 | Say Y here if you have a Texas Instruments TravelMate notebook | ||
54 | equipped with the ct82c710 chip and want to use a mouse connected | ||
55 | to the "QuickPort". | ||
56 | |||
57 | If unsure, say N. | ||
58 | |||
59 | To compile this driver as a module, choose M here: the | ||
60 | module will be called ct82c710. | ||
61 | |||
62 | config SERIO_Q40KBD | ||
63 | tristate "Q40 keyboard controller" | ||
64 | depends on Q40 | ||
65 | |||
66 | config SERIO_PARKBD | ||
67 | tristate "Parallel port keyboard adapter" | ||
68 | depends on PARPORT | ||
69 | ---help--- | ||
70 | Say Y here if you built a simple parallel port adapter to attach | ||
71 | an additional AT keyboard, XT keyboard or PS/2 mouse. | ||
72 | |||
73 | More information is available: <file:Documentation/input/input.txt> | ||
74 | |||
75 | If unsure, say N. | ||
76 | |||
77 | To compile this driver as a module, choose M here: the | ||
78 | module will be called parkbd. | ||
79 | |||
80 | config SERIO_RPCKBD | ||
81 | tristate "Acorn RiscPC keyboard controller" | ||
82 | depends on ARCH_ACORN || ARCH_CLPS7500 | ||
83 | default y | ||
84 | help | ||
85 | Say Y here if you have the Acorn RiscPC and want to use an AT | ||
86 | keyboard connected to its keyboard controller. | ||
87 | |||
88 | To compile this driver as a module, choose M here: the | ||
89 | module will be called rpckbd. | ||
90 | |||
91 | config SERIO_AMBAKMI | ||
92 | tristate "AMBA KMI keyboard controller" | ||
93 | depends on ARM_AMBA | ||
94 | |||
95 | config SERIO_SA1111 | ||
96 | tristate "Intel SA1111 keyboard controller" | ||
97 | depends on SA1111 | ||
98 | |||
99 | config SERIO_GSCPS2 | ||
100 | tristate "HP GSC PS/2 keyboard and PS/2 mouse controller" | ||
101 | depends on GSC | ||
102 | default y | ||
103 | help | ||
104 | This driver provides support for the PS/2 ports on PA-RISC machines | ||
105 | over which HP PS/2 keyboards and PS/2 mice may be connected. | ||
106 | If you use these devices, you'll need to say Y here. | ||
107 | |||
108 | It's safe to enable this driver, so if unsure, say Y. | ||
109 | |||
110 | To compile this driver as a module, choose M here: the | ||
111 | module will be called gscps2. | ||
112 | |||
113 | config HP_SDC | ||
114 | tristate "HP System Device Controller i8042 Support" | ||
115 | depends on GSC && SERIO | ||
116 | default y | ||
117 | ---help--- | ||
118 | This option enables supports for the the "System Device | ||
119 | Controller", an i8042 carrying microcode to manage a | ||
120 | few miscellanous devices on some Hewlett Packard systems. | ||
121 | The SDC itself contains a 10ms resolution timer/clock capable | ||
122 | of delivering interrupts on a periodic and one-shot basis. | ||
123 | The SDC may also be connected to a battery-backed real-time | ||
124 | clock, a basic audio waveform generator, and an HP-HIL Master | ||
125 | Link Controller serving up to seven input devices. | ||
126 | |||
127 | By itself this option is rather useless, but enabling it will | ||
128 | enable selection of drivers for the abovementioned devices. | ||
129 | It is, however, incompatible with the old, reliable HIL keyboard | ||
130 | driver, and the new HIL driver is experimental, so if you plan | ||
131 | to use a HIL keyboard as your primary keyboard, you may wish | ||
132 | to keep using that driver until the new HIL drivers have had | ||
133 | more testing. | ||
134 | |||
135 | config HIL_MLC | ||
136 | tristate "HIL MLC Support (needed for HIL input devices)" | ||
137 | depends on HP_SDC | ||
138 | |||
139 | config SERIO_PCIPS2 | ||
140 | tristate "PCI PS/2 keyboard and PS/2 mouse controller" | ||
141 | depends on PCI | ||
142 | help | ||
143 | Say Y here if you have a Mobility Docking station with PS/2 | ||
144 | keyboard and mice ports. | ||
145 | |||
146 | To compile this driver as a module, choose M here: the | ||
147 | module will be called pcips2. | ||
148 | |||
149 | config SERIO_MACEPS2 | ||
150 | tristate "SGI O2 MACE PS/2 controller" | ||
151 | depends on SGI_IP32 | ||
152 | help | ||
153 | Say Y here if you have SGI O2 workstation and want to use its | ||
154 | PS/2 ports. | ||
155 | |||
156 | To compile this driver as a module, choose M here: the | ||
157 | module will be called maceps2. | ||
158 | |||
159 | config SERIO_LIBPS2 | ||
160 | tristate "PS/2 driver library" if EMBEDDED | ||
161 | help | ||
162 | Say Y here if you are using a driver for device connected | ||
163 | to a PS/2 port, such as PS/2 mouse or standard AT keyboard. | ||
164 | |||
165 | To compile this driver as a module, choose M here: the | ||
166 | module will be called libps2. | ||
167 | |||
168 | config SERIO_RAW | ||
169 | tristate "Raw access to serio ports" | ||
170 | help | ||
171 | Say Y here if you want to have raw access to serio ports, such as | ||
172 | AUX ports on i8042 keyboard controller. Each serio port that is | ||
173 | bound to this driver will be accessible via a char device with | ||
174 | major 10 and dynamically allocated minor. The driver will try | ||
175 | allocating minor 1 (that historically corresponds to /dev/psaux) | ||
176 | first. To bind this driver to a serio port use sysfs interface: | ||
177 | |||
178 | echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver | ||
179 | |||
180 | To compile this driver as a module, choose M here: the | ||
181 | module will be called serio_raw. | ||
182 | |||
183 | endif | ||
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile new file mode 100644 index 000000000000..678a8599f9ff --- /dev/null +++ b/drivers/input/serio/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | # | ||
2 | # Makefile for the input core drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_SERIO) += serio.o | ||
8 | obj-$(CONFIG_SERIO_I8042) += i8042.o | ||
9 | obj-$(CONFIG_SERIO_PARKBD) += parkbd.o | ||
10 | obj-$(CONFIG_SERIO_SERPORT) += serport.o | ||
11 | obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o | ||
12 | obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o | ||
13 | obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o | ||
14 | obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o | ||
15 | obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o | ||
16 | obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o | ||
17 | obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o | ||
18 | obj-$(CONFIG_HP_SDC) += hp_sdc.o | ||
19 | obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o | ||
20 | obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o | ||
21 | obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o | ||
22 | obj-$(CONFIG_SERIO_LIBPS2) += libps2.o | ||
23 | obj-$(CONFIG_SERIO_RAW) += serio_raw.o | ||
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c new file mode 100644 index 000000000000..9b1ab5e7a98d --- /dev/null +++ b/drivers/input/serio/ambakmi.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * linux/drivers/input/serio/ambakmi.c | ||
3 | * | ||
4 | * Copyright (C) 2000-2003 Deep Blue Solutions Ltd. | ||
5 | * Copyright (C) 2002 Russell King. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/serio.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/err.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <asm/irq.h> | ||
25 | #include <asm/hardware/amba.h> | ||
26 | #include <asm/hardware/amba_kmi.h> | ||
27 | #include <asm/hardware/clock.h> | ||
28 | |||
29 | #define KMI_BASE (kmi->base) | ||
30 | |||
31 | struct amba_kmi_port { | ||
32 | struct serio *io; | ||
33 | struct clk *clk; | ||
34 | void __iomem *base; | ||
35 | unsigned int irq; | ||
36 | unsigned int divisor; | ||
37 | unsigned int open; | ||
38 | }; | ||
39 | |||
40 | static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) | ||
41 | { | ||
42 | struct amba_kmi_port *kmi = dev_id; | ||
43 | unsigned int status = readb(KMIIR); | ||
44 | int handled = IRQ_NONE; | ||
45 | |||
46 | while (status & KMIIR_RXINTR) { | ||
47 | serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); | ||
48 | status = readb(KMIIR); | ||
49 | handled = IRQ_HANDLED; | ||
50 | } | ||
51 | |||
52 | return handled; | ||
53 | } | ||
54 | |||
55 | static int amba_kmi_write(struct serio *io, unsigned char val) | ||
56 | { | ||
57 | struct amba_kmi_port *kmi = io->port_data; | ||
58 | unsigned int timeleft = 10000; /* timeout in 100ms */ | ||
59 | |||
60 | while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) | ||
61 | udelay(10); | ||
62 | |||
63 | if (timeleft) | ||
64 | writeb(val, KMIDATA); | ||
65 | |||
66 | return timeleft ? 0 : SERIO_TIMEOUT; | ||
67 | } | ||
68 | |||
69 | static int amba_kmi_open(struct serio *io) | ||
70 | { | ||
71 | struct amba_kmi_port *kmi = io->port_data; | ||
72 | unsigned int divisor; | ||
73 | int ret; | ||
74 | |||
75 | ret = clk_use(kmi->clk); | ||
76 | if (ret) | ||
77 | goto out; | ||
78 | |||
79 | ret = clk_enable(kmi->clk); | ||
80 | if (ret) | ||
81 | goto clk_unuse; | ||
82 | |||
83 | divisor = clk_get_rate(kmi->clk) / 8000000 - 1; | ||
84 | writeb(divisor, KMICLKDIV); | ||
85 | writeb(KMICR_EN, KMICR); | ||
86 | |||
87 | ret = request_irq(kmi->irq, amba_kmi_int, 0, "kmi-pl050", kmi); | ||
88 | if (ret) { | ||
89 | printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq); | ||
90 | writeb(0, KMICR); | ||
91 | goto clk_disable; | ||
92 | } | ||
93 | |||
94 | writeb(KMICR_EN | KMICR_RXINTREN, KMICR); | ||
95 | |||
96 | return 0; | ||
97 | |||
98 | clk_disable: | ||
99 | clk_disable(kmi->clk); | ||
100 | clk_unuse: | ||
101 | clk_unuse(kmi->clk); | ||
102 | out: | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static void amba_kmi_close(struct serio *io) | ||
107 | { | ||
108 | struct amba_kmi_port *kmi = io->port_data; | ||
109 | |||
110 | writeb(0, KMICR); | ||
111 | |||
112 | free_irq(kmi->irq, kmi); | ||
113 | clk_disable(kmi->clk); | ||
114 | clk_unuse(kmi->clk); | ||
115 | } | ||
116 | |||
117 | static int amba_kmi_probe(struct amba_device *dev, void *id) | ||
118 | { | ||
119 | struct amba_kmi_port *kmi; | ||
120 | struct serio *io; | ||
121 | int ret; | ||
122 | |||
123 | ret = amba_request_regions(dev, NULL); | ||
124 | if (ret) | ||
125 | return ret; | ||
126 | |||
127 | kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); | ||
128 | io = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
129 | if (!kmi || !io) { | ||
130 | ret = -ENOMEM; | ||
131 | goto out; | ||
132 | } | ||
133 | |||
134 | memset(kmi, 0, sizeof(struct amba_kmi_port)); | ||
135 | memset(io, 0, sizeof(struct serio)); | ||
136 | |||
137 | io->id.type = SERIO_8042; | ||
138 | io->write = amba_kmi_write; | ||
139 | io->open = amba_kmi_open; | ||
140 | io->close = amba_kmi_close; | ||
141 | strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); | ||
142 | strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); | ||
143 | io->port_data = kmi; | ||
144 | io->dev.parent = &dev->dev; | ||
145 | |||
146 | kmi->io = io; | ||
147 | kmi->base = ioremap(dev->res.start, KMI_SIZE); | ||
148 | if (!kmi->base) { | ||
149 | ret = -ENOMEM; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | kmi->clk = clk_get(&dev->dev, "KMIREFCLK"); | ||
154 | if (IS_ERR(kmi->clk)) { | ||
155 | ret = PTR_ERR(kmi->clk); | ||
156 | goto unmap; | ||
157 | } | ||
158 | |||
159 | kmi->irq = dev->irq[0]; | ||
160 | amba_set_drvdata(dev, kmi); | ||
161 | |||
162 | serio_register_port(kmi->io); | ||
163 | return 0; | ||
164 | |||
165 | unmap: | ||
166 | iounmap(kmi->base); | ||
167 | out: | ||
168 | kfree(kmi); | ||
169 | kfree(io); | ||
170 | amba_release_regions(dev); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | static int amba_kmi_remove(struct amba_device *dev) | ||
175 | { | ||
176 | struct amba_kmi_port *kmi = amba_get_drvdata(dev); | ||
177 | |||
178 | amba_set_drvdata(dev, NULL); | ||
179 | |||
180 | serio_unregister_port(kmi->io); | ||
181 | clk_put(kmi->clk); | ||
182 | iounmap(kmi->base); | ||
183 | kfree(kmi); | ||
184 | amba_release_regions(dev); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int amba_kmi_resume(struct amba_device *dev) | ||
189 | { | ||
190 | struct amba_kmi_port *kmi = amba_get_drvdata(dev); | ||
191 | |||
192 | /* kick the serio layer to rescan this port */ | ||
193 | serio_reconnect(kmi->io); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static struct amba_id amba_kmi_idtable[] = { | ||
199 | { | ||
200 | .id = 0x00041050, | ||
201 | .mask = 0x000fffff, | ||
202 | }, | ||
203 | { 0, 0 } | ||
204 | }; | ||
205 | |||
206 | static struct amba_driver ambakmi_driver = { | ||
207 | .drv = { | ||
208 | .name = "kmi-pl050", | ||
209 | }, | ||
210 | .id_table = amba_kmi_idtable, | ||
211 | .probe = amba_kmi_probe, | ||
212 | .remove = amba_kmi_remove, | ||
213 | .resume = amba_kmi_resume, | ||
214 | }; | ||
215 | |||
216 | static int __init amba_kmi_init(void) | ||
217 | { | ||
218 | return amba_driver_register(&ambakmi_driver); | ||
219 | } | ||
220 | |||
221 | static void __exit amba_kmi_exit(void) | ||
222 | { | ||
223 | amba_driver_unregister(&ambakmi_driver); | ||
224 | } | ||
225 | |||
226 | module_init(amba_kmi_init); | ||
227 | module_exit(amba_kmi_exit); | ||
228 | |||
229 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | ||
230 | MODULE_DESCRIPTION("AMBA KMI controller driver"); | ||
231 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c new file mode 100644 index 000000000000..dd0f5bd90241 --- /dev/null +++ b/drivers/input/serio/ct82c710.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 82C710 C&T mouse port chip 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/delay.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/config.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/serio.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/err.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | |||
43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
44 | MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | |||
47 | /* | ||
48 | * ct82c710 interface | ||
49 | */ | ||
50 | |||
51 | #define CT82C710_DEV_IDLE 0x01 /* Device Idle */ | ||
52 | #define CT82C710_RX_FULL 0x02 /* Device Char received */ | ||
53 | #define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */ | ||
54 | #define CT82C710_RESET 0x08 /* Device Reset */ | ||
55 | #define CT82C710_INTS_ON 0x10 /* Device Interrupt On */ | ||
56 | #define CT82C710_ERROR_FLAG 0x20 /* Device Error */ | ||
57 | #define CT82C710_CLEAR 0x40 /* Device Clear */ | ||
58 | #define CT82C710_ENABLE 0x80 /* Device Enable */ | ||
59 | |||
60 | #define CT82C710_IRQ 12 | ||
61 | |||
62 | #define CT82C710_DATA ct82c710_iores.start | ||
63 | #define CT82C710_STATUS (ct82c710_iores.start + 1) | ||
64 | |||
65 | static struct serio *ct82c710_port; | ||
66 | static struct platform_device *ct82c710_device; | ||
67 | static struct resource ct82c710_iores; | ||
68 | |||
69 | /* | ||
70 | * Interrupt handler for the 82C710 mouse port. A character | ||
71 | * is waiting in the 82C710. | ||
72 | */ | ||
73 | |||
74 | static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) | ||
75 | { | ||
76 | return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Wait for device to send output char and flush any input char. | ||
81 | */ | ||
82 | |||
83 | static int ct82c170_wait(void) | ||
84 | { | ||
85 | int timeout = 60000; | ||
86 | |||
87 | while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) | ||
88 | != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { | ||
89 | |||
90 | if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA); | ||
91 | |||
92 | udelay(1); | ||
93 | timeout--; | ||
94 | } | ||
95 | |||
96 | return !timeout; | ||
97 | } | ||
98 | |||
99 | static void ct82c710_close(struct serio *serio) | ||
100 | { | ||
101 | if (ct82c170_wait()) | ||
102 | printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); | ||
103 | |||
104 | outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS); | ||
105 | |||
106 | if (ct82c170_wait()) | ||
107 | printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); | ||
108 | |||
109 | free_irq(CT82C710_IRQ, NULL); | ||
110 | } | ||
111 | |||
112 | static int ct82c710_open(struct serio *serio) | ||
113 | { | ||
114 | unsigned char status; | ||
115 | |||
116 | if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) | ||
117 | return -1; | ||
118 | |||
119 | status = inb_p(CT82C710_STATUS); | ||
120 | |||
121 | status |= (CT82C710_ENABLE | CT82C710_RESET); | ||
122 | outb_p(status, CT82C710_STATUS); | ||
123 | |||
124 | status &= ~(CT82C710_RESET); | ||
125 | outb_p(status, CT82C710_STATUS); | ||
126 | |||
127 | status |= CT82C710_INTS_ON; | ||
128 | outb_p(status, CT82C710_STATUS); /* Enable interrupts */ | ||
129 | |||
130 | while (ct82c170_wait()) { | ||
131 | printk(KERN_ERR "ct82c710: Device busy in open()\n"); | ||
132 | status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); | ||
133 | outb_p(status, CT82C710_STATUS); | ||
134 | free_irq(CT82C710_IRQ, NULL); | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Write to the 82C710 mouse device. | ||
143 | */ | ||
144 | |||
145 | static int ct82c710_write(struct serio *port, unsigned char c) | ||
146 | { | ||
147 | if (ct82c170_wait()) return -1; | ||
148 | outb_p(c, CT82C710_DATA); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * See if we can find a 82C710 device. Read mouse address. | ||
154 | */ | ||
155 | |||
156 | static int __init ct82c710_probe(void) | ||
157 | { | ||
158 | outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ | ||
159 | outb_p(0xaa, 0x3fa); /* Inverse of 55 */ | ||
160 | outb_p(0x36, 0x3fa); /* Address the chip */ | ||
161 | outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ | ||
162 | outb_p(0x1b, 0x2fa); /* Inverse of e4 */ | ||
163 | outb_p(0x0f, 0x390); /* Write index */ | ||
164 | if (inb_p(0x391) != 0xe4) /* Config address found? */ | ||
165 | return -1; /* No: no 82C710 here */ | ||
166 | |||
167 | outb_p(0x0d, 0x390); /* Write index */ | ||
168 | ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */ | ||
169 | ct82c710_iores.end = ct82c710_iores.start + 1; | ||
170 | ct82c710_iores.flags = IORESOURCE_IO; | ||
171 | outb_p(0x0f, 0x390); | ||
172 | outb_p(0x0f, 0x391); /* Close config mode */ | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static struct serio * __init ct82c710_allocate_port(void) | ||
178 | { | ||
179 | struct serio *serio; | ||
180 | |||
181 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
182 | if (serio) { | ||
183 | memset(serio, 0, sizeof(struct serio)); | ||
184 | serio->id.type = SERIO_8042; | ||
185 | serio->open = ct82c710_open; | ||
186 | serio->close = ct82c710_close; | ||
187 | serio->write = ct82c710_write; | ||
188 | serio->dev.parent = &ct82c710_device->dev; | ||
189 | strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); | ||
190 | snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA); | ||
191 | } | ||
192 | |||
193 | return serio; | ||
194 | } | ||
195 | |||
196 | static int __init ct82c710_init(void) | ||
197 | { | ||
198 | if (ct82c710_probe()) | ||
199 | return -ENODEV; | ||
200 | |||
201 | ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1); | ||
202 | if (IS_ERR(ct82c710_device)) | ||
203 | return PTR_ERR(ct82c710_device); | ||
204 | |||
205 | if (!(ct82c710_port = ct82c710_allocate_port())) { | ||
206 | platform_device_unregister(ct82c710_device); | ||
207 | return -ENOMEM; | ||
208 | } | ||
209 | |||
210 | serio_register_port(ct82c710_port); | ||
211 | |||
212 | printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n", | ||
213 | CT82C710_DATA, CT82C710_IRQ); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void __exit ct82c710_exit(void) | ||
219 | { | ||
220 | serio_unregister_port(ct82c710_port); | ||
221 | platform_device_unregister(ct82c710_device); | ||
222 | } | ||
223 | |||
224 | module_init(ct82c710_init); | ||
225 | module_exit(ct82c710_exit); | ||
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c new file mode 100644 index 000000000000..897e4c12b642 --- /dev/null +++ b/drivers/input/serio/gscps2.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * drivers/input/serio/gscps2.c | ||
3 | * | ||
4 | * Copyright (c) 2004 Helge Deller <deller@gmx.de> | ||
5 | * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr> | ||
6 | * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org> | ||
7 | * | ||
8 | * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c | ||
9 | * Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca> | ||
10 | * Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org> | ||
11 | * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr> | ||
12 | * Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr> | ||
13 | * | ||
14 | * HP GSC PS/2 port driver, found in PA/RISC Workstations | ||
15 | * | ||
16 | * This file is subject to the terms and conditions of the GNU General Public | ||
17 | * License. See the file "COPYING" in the main directory of this archive | ||
18 | * for more details. | ||
19 | * | ||
20 | * TODO: | ||
21 | * - Dino testing (did HP ever shipped a machine on which this port | ||
22 | * was usable/enabled ?) | ||
23 | */ | ||
24 | |||
25 | #include <linux/config.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/serio.h> | ||
29 | #include <linux/input.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/pci_ids.h> | ||
35 | |||
36 | #include <asm/irq.h> | ||
37 | #include <asm/io.h> | ||
38 | #include <asm/parisc-device.h> | ||
39 | |||
40 | MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>"); | ||
41 | MODULE_DESCRIPTION("HP GSC PS2 port driver"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); | ||
44 | |||
45 | #define PFX "gscps2.c: " | ||
46 | |||
47 | /* | ||
48 | * Driver constants | ||
49 | */ | ||
50 | |||
51 | /* various constants */ | ||
52 | #define ENABLE 1 | ||
53 | #define DISABLE 0 | ||
54 | |||
55 | #define GSC_DINO_OFFSET 0x0800 /* offset for DINO controller versus LASI one */ | ||
56 | |||
57 | /* PS/2 IO port offsets */ | ||
58 | #define GSC_ID 0x00 /* device ID offset (see: GSC_ID_XXX) */ | ||
59 | #define GSC_RESET 0x00 /* reset port offset */ | ||
60 | #define GSC_RCVDATA 0x04 /* receive port offset */ | ||
61 | #define GSC_XMTDATA 0x04 /* transmit port offset */ | ||
62 | #define GSC_CONTROL 0x08 /* see: Control register bits */ | ||
63 | #define GSC_STATUS 0x0C /* see: Status register bits */ | ||
64 | |||
65 | /* Control register bits */ | ||
66 | #define GSC_CTRL_ENBL 0x01 /* enable interface */ | ||
67 | #define GSC_CTRL_LPBXR 0x02 /* loopback operation */ | ||
68 | #define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */ | ||
69 | #define GSC_CTRL_DATDIR 0x40 /* data line direct control */ | ||
70 | #define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */ | ||
71 | |||
72 | /* Status register bits */ | ||
73 | #define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */ | ||
74 | #define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */ | ||
75 | #define GSC_STAT_TERR 0x04 /* Timeout Error */ | ||
76 | #define GSC_STAT_PERR 0x08 /* Parity Error */ | ||
77 | #define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt = irq on any port */ | ||
78 | #define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */ | ||
79 | #define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */ | ||
80 | |||
81 | /* IDs returned by GSC_ID port register */ | ||
82 | #define GSC_ID_KEYBOARD 0 /* device ID values */ | ||
83 | #define GSC_ID_MOUSE 1 | ||
84 | |||
85 | |||
86 | static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); | ||
87 | |||
88 | #define BUFFER_SIZE 0x0f | ||
89 | |||
90 | /* GSC PS/2 port device struct */ | ||
91 | struct gscps2port { | ||
92 | struct list_head node; | ||
93 | struct parisc_device *padev; | ||
94 | struct serio *port; | ||
95 | spinlock_t lock; | ||
96 | char *addr; | ||
97 | u8 act, append; /* position in buffer[] */ | ||
98 | struct { | ||
99 | u8 data; | ||
100 | u8 str; | ||
101 | } buffer[BUFFER_SIZE+1]; | ||
102 | int id; | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | * Various HW level routines | ||
107 | */ | ||
108 | |||
109 | #define gscps2_readb_input(x) readb((x)+GSC_RCVDATA) | ||
110 | #define gscps2_readb_control(x) readb((x)+GSC_CONTROL) | ||
111 | #define gscps2_readb_status(x) readb((x)+GSC_STATUS) | ||
112 | #define gscps2_writeb_control(x, y) writeb((x), (y)+GSC_CONTROL) | ||
113 | |||
114 | |||
115 | /* | ||
116 | * wait_TBE() - wait for Transmit Buffer Empty | ||
117 | */ | ||
118 | |||
119 | static int wait_TBE(char *addr) | ||
120 | { | ||
121 | int timeout = 25000; /* device is expected to react within 250 msec */ | ||
122 | while (gscps2_readb_status(addr) & GSC_STAT_TBNE) { | ||
123 | if (!--timeout) | ||
124 | return 0; /* This should not happen */ | ||
125 | udelay(10); | ||
126 | } | ||
127 | return 1; | ||
128 | } | ||
129 | |||
130 | |||
131 | /* | ||
132 | * gscps2_flush() - flush the receive buffer | ||
133 | */ | ||
134 | |||
135 | static void gscps2_flush(struct gscps2port *ps2port) | ||
136 | { | ||
137 | while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) | ||
138 | gscps2_readb_input(ps2port->addr); | ||
139 | ps2port->act = ps2port->append = 0; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * gscps2_writeb_output() - write a byte to the port | ||
144 | * | ||
145 | * returns 1 on sucess, 0 on error | ||
146 | */ | ||
147 | |||
148 | static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) | ||
149 | { | ||
150 | unsigned long flags; | ||
151 | char *addr = ps2port->addr; | ||
152 | |||
153 | if (!wait_TBE(addr)) { | ||
154 | printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) | ||
159 | /* wait */; | ||
160 | |||
161 | spin_lock_irqsave(&ps2port->lock, flags); | ||
162 | writeb(data, addr+GSC_XMTDATA); | ||
163 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
164 | |||
165 | /* this is ugly, but due to timing of the port it seems to be necessary. */ | ||
166 | mdelay(6); | ||
167 | |||
168 | /* make sure any received data is returned as fast as possible */ | ||
169 | /* this is important e.g. when we set the LEDs on the keyboard */ | ||
170 | gscps2_interrupt(0, NULL, NULL); | ||
171 | |||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | |||
176 | /* | ||
177 | * gscps2_enable() - enables or disables the port | ||
178 | */ | ||
179 | |||
180 | static void gscps2_enable(struct gscps2port *ps2port, int enable) | ||
181 | { | ||
182 | unsigned long flags; | ||
183 | u8 data; | ||
184 | |||
185 | /* now enable/disable the port */ | ||
186 | spin_lock_irqsave(&ps2port->lock, flags); | ||
187 | gscps2_flush(ps2port); | ||
188 | data = gscps2_readb_control(ps2port->addr); | ||
189 | if (enable) | ||
190 | data |= GSC_CTRL_ENBL; | ||
191 | else | ||
192 | data &= ~GSC_CTRL_ENBL; | ||
193 | gscps2_writeb_control(data, ps2port->addr); | ||
194 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
195 | wait_TBE(ps2port->addr); | ||
196 | gscps2_flush(ps2port); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * gscps2_reset() - resets the PS/2 port | ||
201 | */ | ||
202 | |||
203 | static void gscps2_reset(struct gscps2port *ps2port) | ||
204 | { | ||
205 | char *addr = ps2port->addr; | ||
206 | unsigned long flags; | ||
207 | |||
208 | /* reset the interface */ | ||
209 | spin_lock_irqsave(&ps2port->lock, flags); | ||
210 | gscps2_flush(ps2port); | ||
211 | writeb(0xff, addr+GSC_RESET); | ||
212 | gscps2_flush(ps2port); | ||
213 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
214 | |||
215 | /* enable it */ | ||
216 | gscps2_enable(ps2port, ENABLE); | ||
217 | } | ||
218 | |||
219 | static LIST_HEAD(ps2port_list); | ||
220 | |||
221 | /** | ||
222 | * gscps2_interrupt() - Interruption service routine | ||
223 | * | ||
224 | * This function reads received PS/2 bytes and processes them on | ||
225 | * all interfaces. | ||
226 | * The problematic part here is, that the keyboard and mouse PS/2 port | ||
227 | * share the same interrupt and it's not possible to send data if any | ||
228 | * one of them holds input data. To solve this problem we try to receive | ||
229 | * the data as fast as possible and handle the reporting to the upper layer | ||
230 | * later. | ||
231 | */ | ||
232 | |||
233 | static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
234 | { | ||
235 | struct gscps2port *ps2port; | ||
236 | |||
237 | list_for_each_entry(ps2port, &ps2port_list, node) { | ||
238 | |||
239 | unsigned long flags; | ||
240 | spin_lock_irqsave(&ps2port->lock, flags); | ||
241 | |||
242 | while ( (ps2port->buffer[ps2port->append].str = | ||
243 | gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) { | ||
244 | ps2port->buffer[ps2port->append].data = | ||
245 | gscps2_readb_input(ps2port->addr); | ||
246 | ps2port->append = ((ps2port->append+1) & BUFFER_SIZE); | ||
247 | } | ||
248 | |||
249 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
250 | |||
251 | } /* list_for_each_entry */ | ||
252 | |||
253 | /* all data was read from the ports - now report the data to upper layer */ | ||
254 | |||
255 | list_for_each_entry(ps2port, &ps2port_list, node) { | ||
256 | |||
257 | while (ps2port->act != ps2port->append) { | ||
258 | |||
259 | unsigned int rxflags; | ||
260 | u8 data, status; | ||
261 | |||
262 | /* Did new data arrived while we read existing data ? | ||
263 | If yes, exit now and let the new irq handler start over again */ | ||
264 | if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR) | ||
265 | return IRQ_HANDLED; | ||
266 | |||
267 | status = ps2port->buffer[ps2port->act].str; | ||
268 | data = ps2port->buffer[ps2port->act].data; | ||
269 | |||
270 | ps2port->act = ((ps2port->act+1) & BUFFER_SIZE); | ||
271 | rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | | ||
272 | ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); | ||
273 | |||
274 | serio_interrupt(ps2port->port, data, rxflags, regs); | ||
275 | |||
276 | } /* while() */ | ||
277 | |||
278 | } /* list_for_each_entry */ | ||
279 | |||
280 | return IRQ_HANDLED; | ||
281 | } | ||
282 | |||
283 | |||
284 | /* | ||
285 | * gscps2_write() - send a byte out through the aux interface. | ||
286 | */ | ||
287 | |||
288 | static int gscps2_write(struct serio *port, unsigned char data) | ||
289 | { | ||
290 | struct gscps2port *ps2port = port->port_data; | ||
291 | |||
292 | if (!gscps2_writeb_output(ps2port, data)) { | ||
293 | printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); | ||
294 | return -1; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * gscps2_open() is called when a port is opened by the higher layer. | ||
301 | * It resets and enables the port. | ||
302 | */ | ||
303 | |||
304 | static int gscps2_open(struct serio *port) | ||
305 | { | ||
306 | struct gscps2port *ps2port = port->port_data; | ||
307 | |||
308 | gscps2_reset(ps2port); | ||
309 | |||
310 | gscps2_interrupt(0, NULL, NULL); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * gscps2_close() disables the port | ||
317 | */ | ||
318 | |||
319 | static void gscps2_close(struct serio *port) | ||
320 | { | ||
321 | struct gscps2port *ps2port = port->port_data; | ||
322 | gscps2_enable(ps2port, DISABLE); | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * gscps2_probe() - Probes PS2 devices | ||
327 | * @return: success/error report | ||
328 | */ | ||
329 | |||
330 | static int __init gscps2_probe(struct parisc_device *dev) | ||
331 | { | ||
332 | struct gscps2port *ps2port; | ||
333 | struct serio *serio; | ||
334 | unsigned long hpa = dev->hpa; | ||
335 | int ret; | ||
336 | |||
337 | if (!dev->irq) | ||
338 | return -ENODEV; | ||
339 | |||
340 | /* Offset for DINO PS/2. Works with LASI even */ | ||
341 | if (dev->id.sversion == 0x96) | ||
342 | hpa += GSC_DINO_OFFSET; | ||
343 | |||
344 | ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); | ||
345 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
346 | if (!ps2port || !serio) { | ||
347 | ret = -ENOMEM; | ||
348 | goto fail_nomem; | ||
349 | } | ||
350 | |||
351 | dev_set_drvdata(&dev->dev, ps2port); | ||
352 | |||
353 | memset(ps2port, 0, sizeof(struct gscps2port)); | ||
354 | memset(serio, 0, sizeof(struct serio)); | ||
355 | ps2port->port = serio; | ||
356 | ps2port->padev = dev; | ||
357 | ps2port->addr = ioremap(hpa, GSC_STATUS + 4); | ||
358 | spin_lock_init(&ps2port->lock); | ||
359 | |||
360 | gscps2_reset(ps2port); | ||
361 | ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; | ||
362 | |||
363 | snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", | ||
364 | (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); | ||
365 | strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); | ||
366 | serio->id.type = SERIO_8042; | ||
367 | serio->write = gscps2_write; | ||
368 | serio->open = gscps2_open; | ||
369 | serio->close = gscps2_close; | ||
370 | serio->port_data = ps2port; | ||
371 | serio->dev.parent = &dev->dev; | ||
372 | |||
373 | list_add_tail(&ps2port->node, &ps2port_list); | ||
374 | |||
375 | ret = -EBUSY; | ||
376 | if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) | ||
377 | goto fail_miserably; | ||
378 | |||
379 | if (ps2port->id != GSC_ID_KEYBOARD && ps2port->id != GSC_ID_MOUSE) { | ||
380 | printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", | ||
381 | hpa, ps2port->id); | ||
382 | ret = -ENODEV; | ||
383 | goto fail; | ||
384 | } | ||
385 | |||
386 | #if 0 | ||
387 | if (!request_mem_region(hpa, GSC_STATUS + 4, ps2port->port.name)) | ||
388 | goto fail; | ||
389 | #endif | ||
390 | |||
391 | printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", | ||
392 | ps2port->port->name, | ||
393 | ps2port->addr, | ||
394 | ps2port->padev->irq, | ||
395 | ps2port->port->phys); | ||
396 | |||
397 | serio_register_port(ps2port->port); | ||
398 | |||
399 | return 0; | ||
400 | |||
401 | fail: | ||
402 | free_irq(dev->irq, ps2port); | ||
403 | |||
404 | fail_miserably: | ||
405 | list_del(&ps2port->node); | ||
406 | iounmap(ps2port->addr); | ||
407 | release_mem_region(dev->hpa, GSC_STATUS + 4); | ||
408 | |||
409 | fail_nomem: | ||
410 | kfree(ps2port); | ||
411 | kfree(serio); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * gscps2_remove() - Removes PS2 devices | ||
417 | * @return: success/error report | ||
418 | */ | ||
419 | |||
420 | static int __devexit gscps2_remove(struct parisc_device *dev) | ||
421 | { | ||
422 | struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); | ||
423 | |||
424 | serio_unregister_port(ps2port->port); | ||
425 | free_irq(dev->irq, ps2port); | ||
426 | gscps2_flush(ps2port); | ||
427 | list_del(&ps2port->node); | ||
428 | iounmap(ps2port->addr); | ||
429 | #if 0 | ||
430 | release_mem_region(dev->hpa, GSC_STATUS + 4); | ||
431 | #endif | ||
432 | dev_set_drvdata(&dev->dev, NULL); | ||
433 | kfree(ps2port); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | |||
438 | static struct parisc_device_id gscps2_device_tbl[] = { | ||
439 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ | ||
440 | #ifdef DINO_TESTED | ||
441 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ | ||
442 | #endif | ||
443 | { 0, } /* 0 terminated list */ | ||
444 | }; | ||
445 | |||
446 | static struct parisc_driver parisc_ps2_driver = { | ||
447 | .name = "GSC PS2", | ||
448 | .id_table = gscps2_device_tbl, | ||
449 | .probe = gscps2_probe, | ||
450 | .remove = gscps2_remove, | ||
451 | }; | ||
452 | |||
453 | static int __init gscps2_init(void) | ||
454 | { | ||
455 | register_parisc_driver(&parisc_ps2_driver); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static void __exit gscps2_exit(void) | ||
460 | { | ||
461 | unregister_parisc_driver(&parisc_ps2_driver); | ||
462 | } | ||
463 | |||
464 | |||
465 | module_init(gscps2_init); | ||
466 | module_exit(gscps2_exit); | ||
467 | |||
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c new file mode 100644 index 000000000000..c243cb6fdfc4 --- /dev/null +++ b/drivers/input/serio/hil_mlc.c | |||
@@ -0,0 +1,949 @@ | |||
1 | /* | ||
2 | * HIL MLC state machine and serio interface driver | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A | ||
31 | * | ||
32 | * | ||
33 | * Driver theory of operation: | ||
34 | * | ||
35 | * Some access methods and an ISR is defined by the sub-driver | ||
36 | * (e.g. hp_sdc_mlc.c). These methods are expected to provide a | ||
37 | * few bits of logic in addition to raw access to the HIL MLC, | ||
38 | * specifically, the ISR, which is entirely registered by the | ||
39 | * sub-driver and invoked directly, must check for record | ||
40 | * termination or packet match, at which point a semaphore must | ||
41 | * be cleared and then the hil_mlcs_tasklet must be scheduled. | ||
42 | * | ||
43 | * The hil_mlcs_tasklet processes the state machine for all MLCs | ||
44 | * each time it runs, checking each MLC's progress at the current | ||
45 | * node in the state machine, and moving the MLC to subsequent nodes | ||
46 | * in the state machine when appropriate. It will reschedule | ||
47 | * itself if output is pending. (This rescheduling should be replaced | ||
48 | * at some point with a sub-driver-specific mechanism.) | ||
49 | * | ||
50 | * A timer task prods the tasklet once per second to prevent | ||
51 | * hangups when attached devices do not return expected data | ||
52 | * and to initiate probes of the loop for new devices. | ||
53 | */ | ||
54 | |||
55 | #include <linux/hil_mlc.h> | ||
56 | #include <linux/errno.h> | ||
57 | #include <linux/kernel.h> | ||
58 | #include <linux/module.h> | ||
59 | #include <linux/init.h> | ||
60 | #include <linux/interrupt.h> | ||
61 | #include <linux/timer.h> | ||
62 | #include <linux/sched.h> | ||
63 | #include <linux/list.h> | ||
64 | |||
65 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
66 | MODULE_DESCRIPTION("HIL MLC serio"); | ||
67 | MODULE_LICENSE("Dual BSD/GPL"); | ||
68 | |||
69 | EXPORT_SYMBOL(hil_mlc_register); | ||
70 | EXPORT_SYMBOL(hil_mlc_unregister); | ||
71 | |||
72 | #define PREFIX "HIL MLC: " | ||
73 | |||
74 | static LIST_HEAD(hil_mlcs); | ||
75 | static DEFINE_RWLOCK(hil_mlcs_lock); | ||
76 | static struct timer_list hil_mlcs_kicker; | ||
77 | static int hil_mlcs_probe; | ||
78 | |||
79 | static void hil_mlcs_process(unsigned long unused); | ||
80 | DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0); | ||
81 | |||
82 | |||
83 | /* #define HIL_MLC_DEBUG */ | ||
84 | |||
85 | /********************** Device info/instance management **********************/ | ||
86 | |||
87 | static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) { | ||
88 | int j; | ||
89 | for (j = val; j < 7 ; j++) { | ||
90 | mlc->di_map[j] = -1; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static void hil_mlc_clear_di_scratch (hil_mlc *mlc) { | ||
95 | memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch)); | ||
96 | } | ||
97 | |||
98 | static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) { | ||
99 | memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch)); | ||
100 | } | ||
101 | |||
102 | static int hil_mlc_match_di_scratch (hil_mlc *mlc) { | ||
103 | int idx; | ||
104 | |||
105 | for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { | ||
106 | int j, found; | ||
107 | |||
108 | /* In-use slots are not eligible. */ | ||
109 | found = 0; | ||
110 | for (j = 0; j < 7 ; j++) { | ||
111 | if (mlc->di_map[j] == idx) found++; | ||
112 | } | ||
113 | if (found) continue; | ||
114 | if (!memcmp(mlc->di + idx, | ||
115 | &(mlc->di_scratch), | ||
116 | sizeof(mlc->di_scratch))) break; | ||
117 | } | ||
118 | return((idx >= HIL_MLC_DEVMEM) ? -1 : idx); | ||
119 | } | ||
120 | |||
121 | static int hil_mlc_find_free_di(hil_mlc *mlc) { | ||
122 | int idx; | ||
123 | /* TODO: Pick all-zero slots first, failing that, | ||
124 | * randomize the slot picked among those eligible. | ||
125 | */ | ||
126 | for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { | ||
127 | int j, found; | ||
128 | found = 0; | ||
129 | for (j = 0; j < 7 ; j++) { | ||
130 | if (mlc->di_map[j] == idx) found++; | ||
131 | } | ||
132 | if (!found) break; | ||
133 | } | ||
134 | return(idx); /* Note: It is guaranteed at least one above will match */ | ||
135 | } | ||
136 | |||
137 | static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) { | ||
138 | int idx; | ||
139 | for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { | ||
140 | int j, found; | ||
141 | found = 0; | ||
142 | for (j = 0; j < 7 ; j++) { | ||
143 | if (mlc->di_map[j] == idx) found++; | ||
144 | } | ||
145 | if (!found) mlc->serio_map[idx].di_revmap = -1; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void hil_mlc_send_polls(hil_mlc *mlc) { | ||
150 | int did, i, cnt; | ||
151 | struct serio *serio; | ||
152 | struct serio_driver *drv; | ||
153 | |||
154 | i = cnt = 0; | ||
155 | did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8; | ||
156 | serio = did ? mlc->serio[mlc->di_map[did - 1]] : NULL; | ||
157 | drv = (serio != NULL) ? serio->drv : NULL; | ||
158 | |||
159 | while (mlc->icount < 15 - i) { | ||
160 | hil_packet p; | ||
161 | p = mlc->ipacket[i]; | ||
162 | if (did != (p & HIL_PKT_ADDR_MASK) >> 8) { | ||
163 | if (drv == NULL || drv->interrupt == NULL) goto skip; | ||
164 | |||
165 | drv->interrupt(serio, 0, 0, NULL); | ||
166 | drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); | ||
167 | drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); | ||
168 | drv->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL); | ||
169 | skip: | ||
170 | did = (p & HIL_PKT_ADDR_MASK) >> 8; | ||
171 | serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL; | ||
172 | drv = (serio != NULL) ? serio->drv : NULL; | ||
173 | cnt = 0; | ||
174 | } | ||
175 | cnt++; i++; | ||
176 | if (drv == NULL || drv->interrupt == NULL) continue; | ||
177 | drv->interrupt(serio, (p >> 24), 0, NULL); | ||
178 | drv->interrupt(serio, (p >> 16) & 0xff, 0, NULL); | ||
179 | drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL); | ||
180 | drv->interrupt(serio, p & 0xff, 0, NULL); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /*************************** State engine *********************************/ | ||
185 | |||
186 | #define HILSEN_SCHED 0x000100 /* Schedule the tasklet */ | ||
187 | #define HILSEN_BREAK 0x000200 /* Wait until next pass */ | ||
188 | #define HILSEN_UP 0x000400 /* relative node#, decrement */ | ||
189 | #define HILSEN_DOWN 0x000800 /* relative node#, increment */ | ||
190 | #define HILSEN_FOLLOW 0x001000 /* use retval as next node# */ | ||
191 | |||
192 | #define HILSEN_MASK 0x0000ff | ||
193 | #define HILSEN_START 0 | ||
194 | #define HILSEN_RESTART 1 | ||
195 | #define HILSEN_DHR 9 | ||
196 | #define HILSEN_DHR2 10 | ||
197 | #define HILSEN_IFC 14 | ||
198 | #define HILSEN_HEAL0 16 | ||
199 | #define HILSEN_HEAL 18 | ||
200 | #define HILSEN_ACF 21 | ||
201 | #define HILSEN_ACF2 22 | ||
202 | #define HILSEN_DISC0 25 | ||
203 | #define HILSEN_DISC 27 | ||
204 | #define HILSEN_MATCH 40 | ||
205 | #define HILSEN_OPERATE 41 | ||
206 | #define HILSEN_PROBE 44 | ||
207 | #define HILSEN_DSR 52 | ||
208 | #define HILSEN_REPOLL 55 | ||
209 | #define HILSEN_IFCACF 58 | ||
210 | #define HILSEN_END 60 | ||
211 | |||
212 | #define HILSEN_NEXT (HILSEN_DOWN | 1) | ||
213 | #define HILSEN_SAME (HILSEN_DOWN | 0) | ||
214 | #define HILSEN_LAST (HILSEN_UP | 1) | ||
215 | |||
216 | #define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK) | ||
217 | #define HILSEN_SLEEP (HILSEN_SAME | HILSEN_BREAK) | ||
218 | |||
219 | static int hilse_match(hil_mlc *mlc, int unused) { | ||
220 | int rc; | ||
221 | rc = hil_mlc_match_di_scratch(mlc); | ||
222 | if (rc == -1) { | ||
223 | rc = hil_mlc_find_free_di(mlc); | ||
224 | if (rc == -1) goto err; | ||
225 | #ifdef HIL_MLC_DEBUG | ||
226 | printk(KERN_DEBUG PREFIX "new in slot %i\n", rc); | ||
227 | #endif | ||
228 | hil_mlc_copy_di_scratch(mlc, rc); | ||
229 | mlc->di_map[mlc->ddi] = rc; | ||
230 | mlc->serio_map[rc].di_revmap = mlc->ddi; | ||
231 | hil_mlc_clean_serio_map(mlc); | ||
232 | serio_rescan(mlc->serio[rc]); | ||
233 | return -1; | ||
234 | } | ||
235 | mlc->di_map[mlc->ddi] = rc; | ||
236 | #ifdef HIL_MLC_DEBUG | ||
237 | printk(KERN_DEBUG PREFIX "same in slot %i\n", rc); | ||
238 | #endif | ||
239 | mlc->serio_map[rc].di_revmap = mlc->ddi; | ||
240 | hil_mlc_clean_serio_map(mlc); | ||
241 | return 0; | ||
242 | err: | ||
243 | printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n"); | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ | ||
248 | static int hilse_init_lcv(hil_mlc *mlc, int unused) { | ||
249 | struct timeval tv; | ||
250 | |||
251 | do_gettimeofday(&tv); | ||
252 | |||
253 | if(mlc->lcv == 0) goto restart; /* First init, no need to dally */ | ||
254 | if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1; | ||
255 | restart: | ||
256 | mlc->lcv_tv = tv; | ||
257 | mlc->lcv = 0; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int hilse_inc_lcv(hil_mlc *mlc, int lim) { | ||
262 | if (mlc->lcv++ >= lim) return -1; | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | #if 0 | ||
267 | static int hilse_set_lcv(hil_mlc *mlc, int val) { | ||
268 | mlc->lcv = val; | ||
269 | return 0; | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | /* Management of the discovered device index (zero based, -1 means no devs) */ | ||
274 | static int hilse_set_ddi(hil_mlc *mlc, int val) { | ||
275 | mlc->ddi = val; | ||
276 | hil_mlc_clear_di_map(mlc, val + 1); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int hilse_dec_ddi(hil_mlc *mlc, int unused) { | ||
281 | mlc->ddi--; | ||
282 | if (mlc->ddi <= -1) { | ||
283 | mlc->ddi = -1; | ||
284 | hil_mlc_clear_di_map(mlc, 0); | ||
285 | return -1; | ||
286 | } | ||
287 | hil_mlc_clear_di_map(mlc, mlc->ddi + 1); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int hilse_inc_ddi(hil_mlc *mlc, int unused) { | ||
292 | if (mlc->ddi >= 6) { | ||
293 | BUG(); | ||
294 | return -1; | ||
295 | } | ||
296 | mlc->ddi++; | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int hilse_take_idd(hil_mlc *mlc, int unused) { | ||
301 | int i; | ||
302 | |||
303 | /* Help the state engine: | ||
304 | * Is this a real IDD response or just an echo? | ||
305 | * | ||
306 | * Real IDD response does not start with a command. | ||
307 | */ | ||
308 | if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail; | ||
309 | /* Should have the command echoed further down. */ | ||
310 | for (i = 1; i < 16; i++) { | ||
311 | if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == | ||
312 | (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) && | ||
313 | (mlc->ipacket[i] & HIL_PKT_CMD) && | ||
314 | ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD)) | ||
315 | break; | ||
316 | } | ||
317 | if (i > 15) goto bail; | ||
318 | /* And the rest of the packets should still be clear. */ | ||
319 | while (++i < 16) { | ||
320 | if (mlc->ipacket[i]) break; | ||
321 | } | ||
322 | if (i < 16) goto bail; | ||
323 | for (i = 0; i < 16; i++) { | ||
324 | mlc->di_scratch.idd[i] = | ||
325 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
326 | } | ||
327 | /* Next step is to see if RSC supported */ | ||
328 | if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) | ||
329 | return HILSEN_NEXT; | ||
330 | if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) | ||
331 | return HILSEN_DOWN | 4; | ||
332 | return 0; | ||
333 | bail: | ||
334 | mlc->ddi--; | ||
335 | return -1; /* This should send us off to ACF */ | ||
336 | } | ||
337 | |||
338 | static int hilse_take_rsc(hil_mlc *mlc, int unused) { | ||
339 | int i; | ||
340 | |||
341 | for (i = 0; i < 16; i++) { | ||
342 | mlc->di_scratch.rsc[i] = | ||
343 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
344 | } | ||
345 | /* Next step is to see if EXD supported (IDD has already been read) */ | ||
346 | if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) | ||
347 | return HILSEN_NEXT; | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int hilse_take_exd(hil_mlc *mlc, int unused) { | ||
352 | int i; | ||
353 | |||
354 | for (i = 0; i < 16; i++) { | ||
355 | mlc->di_scratch.exd[i] = | ||
356 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
357 | } | ||
358 | /* Next step is to see if RNM supported. */ | ||
359 | if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) | ||
360 | return HILSEN_NEXT; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int hilse_take_rnm(hil_mlc *mlc, int unused) { | ||
365 | int i; | ||
366 | |||
367 | for (i = 0; i < 16; i++) { | ||
368 | mlc->di_scratch.rnm[i] = | ||
369 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
370 | } | ||
371 | do { | ||
372 | char nam[17]; | ||
373 | snprintf(nam, 16, "%s", mlc->di_scratch.rnm); | ||
374 | nam[16] = '\0'; | ||
375 | printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam); | ||
376 | } while (0); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int hilse_operate(hil_mlc *mlc, int repoll) { | ||
381 | |||
382 | if (mlc->opercnt == 0) hil_mlcs_probe = 0; | ||
383 | mlc->opercnt = 1; | ||
384 | |||
385 | hil_mlc_send_polls(mlc); | ||
386 | |||
387 | if (!hil_mlcs_probe) return 0; | ||
388 | hil_mlcs_probe = 0; | ||
389 | mlc->opercnt = 0; | ||
390 | return 1; | ||
391 | } | ||
392 | |||
393 | #define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \ | ||
394 | { HILSE_FUNC, { func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc }, | ||
395 | #define OUT(pack) \ | ||
396 | { HILSE_OUT, { packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 }, | ||
397 | #define CTS \ | ||
398 | { HILSE_CTS, { packet: 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 }, | ||
399 | #define EXPECT(comp, to, got, got_wrong, timed_out) \ | ||
400 | { HILSE_EXPECT, { packet: comp }, to, got, got_wrong, timed_out }, | ||
401 | #define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \ | ||
402 | { HILSE_EXPECT_LAST, { packet: comp }, to, got, got_wrong, timed_out }, | ||
403 | #define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \ | ||
404 | { HILSE_EXPECT_DISC, { packet: comp }, to, got, got_wrong, timed_out }, | ||
405 | #define IN(to, got, got_error, timed_out) \ | ||
406 | { HILSE_IN, { packet: 0 }, to, got, got_error, timed_out }, | ||
407 | #define OUT_DISC(pack) \ | ||
408 | { HILSE_OUT_DISC, { packet: pack }, 0, 0, 0, 0 }, | ||
409 | #define OUT_LAST(pack) \ | ||
410 | { HILSE_OUT_LAST, { packet: pack }, 0, 0, 0, 0 }, | ||
411 | |||
412 | struct hilse_node hil_mlc_se[HILSEN_END] = { | ||
413 | |||
414 | /* 0 HILSEN_START */ | ||
415 | FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) | ||
416 | |||
417 | /* 1 HILSEN_RESTART */ | ||
418 | FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) | ||
419 | OUT(HIL_CTRL_ONLY) /* Disable APE */ | ||
420 | CTS | ||
421 | |||
422 | #define TEST_PACKET(x) \ | ||
423 | (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT) | x << 4 | x) | ||
424 | |||
425 | OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0x5)) | ||
426 | EXPECT(HIL_ERR_INT | TEST_PACKET(0x5), | ||
427 | 2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART) | ||
428 | OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0xa)) | ||
429 | EXPECT(HIL_ERR_INT | TEST_PACKET(0xa), | ||
430 | 2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART) | ||
431 | OUT(HIL_CTRL_ONLY | 0) /* Disable test mode */ | ||
432 | |||
433 | /* 9 HILSEN_DHR */ | ||
434 | FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) | ||
435 | |||
436 | /* 10 HILSEN_DHR2 */ | ||
437 | FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) | ||
438 | FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0) | ||
439 | OUT(HIL_PKT_CMD | HIL_CMD_DHR) | ||
440 | IN(300000, HILSEN_DHR2, HILSEN_DHR2, HILSEN_NEXT) | ||
441 | |||
442 | /* 14 HILSEN_IFC */ | ||
443 | OUT(HIL_PKT_CMD | HIL_CMD_IFC) | ||
444 | EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, | ||
445 | 20000, HILSEN_DISC, HILSEN_DHR2, HILSEN_NEXT ) | ||
446 | |||
447 | /* If devices are there, they weren't in PUP or other loopback mode. | ||
448 | * We're more concerned at this point with restoring operation | ||
449 | * to devices than discovering new ones, so we try to salvage | ||
450 | * the loop configuration by closing off the loop. | ||
451 | */ | ||
452 | |||
453 | /* 16 HILSEN_HEAL0 */ | ||
454 | FUNC(hilse_dec_ddi, 0, HILSEN_NEXT, HILSEN_ACF, 0) | ||
455 | FUNC(hilse_inc_ddi, 0, HILSEN_NEXT, 0, 0) | ||
456 | |||
457 | /* 18 HILSEN_HEAL */ | ||
458 | OUT_LAST(HIL_CMD_ELB) | ||
459 | EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, | ||
460 | 20000, HILSEN_REPOLL, HILSEN_DSR, HILSEN_NEXT) | ||
461 | FUNC(hilse_dec_ddi, 0, HILSEN_HEAL, HILSEN_NEXT, 0) | ||
462 | |||
463 | /* 21 HILSEN_ACF */ | ||
464 | FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_DOZE, 0) | ||
465 | |||
466 | /* 22 HILSEN_ACF2 */ | ||
467 | FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) | ||
468 | OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1) | ||
469 | IN(20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) | ||
470 | |||
471 | /* 25 HILSEN_DISC0 */ | ||
472 | OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB) | ||
473 | EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_ELB | HIL_ERR_INT, | ||
474 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
475 | |||
476 | /* Only enter here if response just received */ | ||
477 | /* 27 HILSEN_DISC */ | ||
478 | OUT_DISC(HIL_PKT_CMD | HIL_CMD_IDD) | ||
479 | EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_IDD | HIL_ERR_INT, | ||
480 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_START) | ||
481 | FUNC(hilse_inc_ddi, 0, HILSEN_NEXT, HILSEN_START, 0) | ||
482 | FUNC(hilse_take_idd, 0, HILSEN_MATCH, HILSEN_IFCACF, HILSEN_FOLLOW) | ||
483 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_RSC) | ||
484 | EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RSC | HIL_ERR_INT, | ||
485 | 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
486 | FUNC(hilse_take_rsc, 0, HILSEN_MATCH, 0, HILSEN_FOLLOW) | ||
487 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_EXD) | ||
488 | EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_EXD | HIL_ERR_INT, | ||
489 | 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
490 | FUNC(hilse_take_exd, 0, HILSEN_MATCH, 0, HILSEN_FOLLOW) | ||
491 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_RNM) | ||
492 | EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RNM | HIL_ERR_INT, | ||
493 | 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
494 | FUNC(hilse_take_rnm, 0, HILSEN_MATCH, 0, 0) | ||
495 | |||
496 | /* 40 HILSEN_MATCH */ | ||
497 | FUNC(hilse_match, 0, HILSEN_NEXT, HILSEN_NEXT, /* TODO */ 0) | ||
498 | |||
499 | /* 41 HILSEN_OPERATE */ | ||
500 | OUT(HIL_PKT_CMD | HIL_CMD_POL) | ||
501 | EXPECT(HIL_PKT_CMD | HIL_CMD_POL | HIL_ERR_INT, | ||
502 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) | ||
503 | FUNC(hilse_operate, 0, HILSEN_OPERATE, HILSEN_IFC, HILSEN_NEXT) | ||
504 | |||
505 | /* 44 HILSEN_PROBE */ | ||
506 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT) | ||
507 | IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) | ||
508 | OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB) | ||
509 | IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) | ||
510 | OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1) | ||
511 | IN(10000, HILSEN_DISC0, HILSEN_DSR, HILSEN_NEXT) | ||
512 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_ELB) | ||
513 | IN(10000, HILSEN_OPERATE, HILSEN_DSR, HILSEN_DSR) | ||
514 | |||
515 | /* 52 HILSEN_DSR */ | ||
516 | FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0) | ||
517 | OUT(HIL_PKT_CMD | HIL_CMD_DSR) | ||
518 | IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC) | ||
519 | |||
520 | /* 55 HILSEN_REPOLL */ | ||
521 | OUT(HIL_PKT_CMD | HIL_CMD_RPL) | ||
522 | EXPECT(HIL_PKT_CMD | HIL_CMD_RPL | HIL_ERR_INT, | ||
523 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) | ||
524 | FUNC(hilse_operate, 1, HILSEN_OPERATE, HILSEN_IFC, HILSEN_PROBE) | ||
525 | |||
526 | /* 58 HILSEN_IFCACF */ | ||
527 | OUT(HIL_PKT_CMD | HIL_CMD_IFC) | ||
528 | EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, | ||
529 | 20000, HILSEN_ACF2, HILSEN_DHR2, HILSEN_HEAL) | ||
530 | |||
531 | /* 60 HILSEN_END */ | ||
532 | }; | ||
533 | |||
534 | static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) { | ||
535 | |||
536 | switch (node->act) { | ||
537 | case HILSE_EXPECT_DISC: | ||
538 | mlc->imatch = node->object.packet; | ||
539 | mlc->imatch |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT); | ||
540 | break; | ||
541 | case HILSE_EXPECT_LAST: | ||
542 | mlc->imatch = node->object.packet; | ||
543 | mlc->imatch |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT); | ||
544 | break; | ||
545 | case HILSE_EXPECT: | ||
546 | mlc->imatch = node->object.packet; | ||
547 | break; | ||
548 | case HILSE_IN: | ||
549 | mlc->imatch = 0; | ||
550 | break; | ||
551 | default: | ||
552 | BUG(); | ||
553 | } | ||
554 | mlc->istarted = 1; | ||
555 | mlc->intimeout = node->arg; | ||
556 | do_gettimeofday(&(mlc->instart)); | ||
557 | mlc->icount = 15; | ||
558 | memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); | ||
559 | if (down_trylock(&(mlc->isem))) BUG(); | ||
560 | |||
561 | return; | ||
562 | } | ||
563 | |||
564 | #ifdef HIL_MLC_DEBUG | ||
565 | static int doze = 0; | ||
566 | static int seidx; /* For debug */ | ||
567 | static int kick = 1; | ||
568 | #endif | ||
569 | |||
570 | static int hilse_donode (hil_mlc *mlc) { | ||
571 | struct hilse_node *node; | ||
572 | int nextidx = 0; | ||
573 | int sched_long = 0; | ||
574 | unsigned long flags; | ||
575 | |||
576 | #ifdef HIL_MLC_DEBUG | ||
577 | if (mlc->seidx && (mlc->seidx != seidx) && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) { | ||
578 | printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx); | ||
579 | doze = 0; | ||
580 | } | ||
581 | kick = 0; | ||
582 | |||
583 | seidx = mlc->seidx; | ||
584 | #endif | ||
585 | node = hil_mlc_se + mlc->seidx; | ||
586 | |||
587 | switch (node->act) { | ||
588 | int rc; | ||
589 | hil_packet pack; | ||
590 | |||
591 | case HILSE_FUNC: | ||
592 | if (node->object.func == NULL) break; | ||
593 | rc = node->object.func(mlc, node->arg); | ||
594 | nextidx = (rc > 0) ? node->ugly : | ||
595 | ((rc < 0) ? node->bad : node->good); | ||
596 | if (nextidx == HILSEN_FOLLOW) nextidx = rc; | ||
597 | break; | ||
598 | case HILSE_EXPECT_LAST: | ||
599 | case HILSE_EXPECT_DISC: | ||
600 | case HILSE_EXPECT: | ||
601 | case HILSE_IN: | ||
602 | /* Already set up from previous HILSE_OUT_* */ | ||
603 | write_lock_irqsave(&(mlc->lock), flags); | ||
604 | rc = mlc->in(mlc, node->arg); | ||
605 | if (rc == 2) { | ||
606 | nextidx = HILSEN_DOZE; | ||
607 | sched_long = 1; | ||
608 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
609 | break; | ||
610 | } | ||
611 | if (rc == 1) nextidx = node->ugly; | ||
612 | else if (rc == 0) nextidx = node->good; | ||
613 | else nextidx = node->bad; | ||
614 | mlc->istarted = 0; | ||
615 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
616 | break; | ||
617 | case HILSE_OUT_LAST: | ||
618 | write_lock_irqsave(&(mlc->lock), flags); | ||
619 | pack = node->object.packet; | ||
620 | pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT); | ||
621 | goto out; | ||
622 | case HILSE_OUT_DISC: | ||
623 | write_lock_irqsave(&(mlc->lock), flags); | ||
624 | pack = node->object.packet; | ||
625 | pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT); | ||
626 | goto out; | ||
627 | case HILSE_OUT: | ||
628 | write_lock_irqsave(&(mlc->lock), flags); | ||
629 | pack = node->object.packet; | ||
630 | out: | ||
631 | if (mlc->istarted) goto out2; | ||
632 | /* Prepare to receive input */ | ||
633 | if ((node + 1)->act & HILSE_IN) | ||
634 | hilse_setup_input(mlc, node + 1); | ||
635 | |||
636 | out2: | ||
637 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
638 | |||
639 | if (down_trylock(&mlc->osem)) { | ||
640 | nextidx = HILSEN_DOZE; | ||
641 | break; | ||
642 | } | ||
643 | up(&mlc->osem); | ||
644 | |||
645 | write_lock_irqsave(&(mlc->lock), flags); | ||
646 | if (!(mlc->ostarted)) { | ||
647 | mlc->ostarted = 1; | ||
648 | mlc->opacket = pack; | ||
649 | mlc->out(mlc); | ||
650 | nextidx = HILSEN_DOZE; | ||
651 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
652 | break; | ||
653 | } | ||
654 | mlc->ostarted = 0; | ||
655 | do_gettimeofday(&(mlc->instart)); | ||
656 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
657 | nextidx = HILSEN_NEXT; | ||
658 | break; | ||
659 | case HILSE_CTS: | ||
660 | nextidx = mlc->cts(mlc) ? node->bad : node->good; | ||
661 | break; | ||
662 | default: | ||
663 | BUG(); | ||
664 | nextidx = 0; | ||
665 | break; | ||
666 | } | ||
667 | |||
668 | #ifdef HIL_MLC_DEBUG | ||
669 | if (nextidx == HILSEN_DOZE) doze++; | ||
670 | #endif | ||
671 | |||
672 | while (nextidx & HILSEN_SCHED) { | ||
673 | struct timeval tv; | ||
674 | |||
675 | if (!sched_long) goto sched; | ||
676 | |||
677 | do_gettimeofday(&tv); | ||
678 | tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); | ||
679 | tv.tv_usec -= mlc->instart.tv_usec; | ||
680 | if (tv.tv_usec >= mlc->intimeout) goto sched; | ||
681 | tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000; | ||
682 | if (!tv.tv_usec) goto sched; | ||
683 | mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); | ||
684 | break; | ||
685 | sched: | ||
686 | tasklet_schedule(&hil_mlcs_tasklet); | ||
687 | break; | ||
688 | } | ||
689 | if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK; | ||
690 | else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK; | ||
691 | else mlc->seidx = nextidx & HILSEN_MASK; | ||
692 | |||
693 | if (nextidx & HILSEN_BREAK) return 1; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /******************** tasklet context functions **************************/ | ||
698 | static void hil_mlcs_process(unsigned long unused) { | ||
699 | struct list_head *tmp; | ||
700 | |||
701 | read_lock(&hil_mlcs_lock); | ||
702 | list_for_each(tmp, &hil_mlcs) { | ||
703 | struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list); | ||
704 | while (hilse_donode(mlc) == 0) { | ||
705 | #ifdef HIL_MLC_DEBUG | ||
706 | if (mlc->seidx != 41 && | ||
707 | mlc->seidx != 42 && | ||
708 | mlc->seidx != 43) | ||
709 | printk(KERN_DEBUG PREFIX " + "); | ||
710 | #endif | ||
711 | }; | ||
712 | } | ||
713 | read_unlock(&hil_mlcs_lock); | ||
714 | } | ||
715 | |||
716 | /************************* Keepalive timer task *********************/ | ||
717 | |||
718 | void hil_mlcs_timer (unsigned long data) { | ||
719 | hil_mlcs_probe = 1; | ||
720 | tasklet_schedule(&hil_mlcs_tasklet); | ||
721 | /* Re-insert the periodic task. */ | ||
722 | if (!timer_pending(&hil_mlcs_kicker)) | ||
723 | mod_timer(&hil_mlcs_kicker, jiffies + HZ); | ||
724 | } | ||
725 | |||
726 | /******************** user/kernel context functions **********************/ | ||
727 | |||
728 | static int hil_mlc_serio_write(struct serio *serio, unsigned char c) { | ||
729 | struct hil_mlc_serio_map *map; | ||
730 | struct hil_mlc *mlc; | ||
731 | struct serio_driver *drv; | ||
732 | uint8_t *idx, *last; | ||
733 | |||
734 | map = serio->port_data; | ||
735 | if (map == NULL) { | ||
736 | BUG(); | ||
737 | return -EIO; | ||
738 | } | ||
739 | mlc = map->mlc; | ||
740 | if (mlc == NULL) { | ||
741 | BUG(); | ||
742 | return -EIO; | ||
743 | } | ||
744 | mlc->serio_opacket[map->didx] |= | ||
745 | ((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx])); | ||
746 | |||
747 | if (mlc->serio_oidx[map->didx] >= 3) { | ||
748 | /* for now only commands */ | ||
749 | if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) | ||
750 | return -EIO; | ||
751 | switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) { | ||
752 | case HIL_CMD_IDD: | ||
753 | idx = mlc->di[map->didx].idd; | ||
754 | goto emu; | ||
755 | case HIL_CMD_RSC: | ||
756 | idx = mlc->di[map->didx].rsc; | ||
757 | goto emu; | ||
758 | case HIL_CMD_EXD: | ||
759 | idx = mlc->di[map->didx].exd; | ||
760 | goto emu; | ||
761 | case HIL_CMD_RNM: | ||
762 | idx = mlc->di[map->didx].rnm; | ||
763 | goto emu; | ||
764 | default: | ||
765 | break; | ||
766 | } | ||
767 | mlc->serio_oidx[map->didx] = 0; | ||
768 | mlc->serio_opacket[map->didx] = 0; | ||
769 | } | ||
770 | |||
771 | mlc->serio_oidx[map->didx]++; | ||
772 | return -EIO; | ||
773 | emu: | ||
774 | drv = serio->drv; | ||
775 | if (drv == NULL) { | ||
776 | BUG(); | ||
777 | return -EIO; | ||
778 | } | ||
779 | last = idx + 15; | ||
780 | while ((last != idx) && (*last == 0)) last--; | ||
781 | |||
782 | while (idx != last) { | ||
783 | drv->interrupt(serio, 0, 0, NULL); | ||
784 | drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); | ||
785 | drv->interrupt(serio, 0, 0, NULL); | ||
786 | drv->interrupt(serio, *idx, 0, NULL); | ||
787 | idx++; | ||
788 | } | ||
789 | drv->interrupt(serio, 0, 0, NULL); | ||
790 | drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); | ||
791 | drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); | ||
792 | drv->interrupt(serio, *idx, 0, NULL); | ||
793 | |||
794 | mlc->serio_oidx[map->didx] = 0; | ||
795 | mlc->serio_opacket[map->didx] = 0; | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int hil_mlc_serio_open(struct serio *serio) { | ||
801 | struct hil_mlc_serio_map *map; | ||
802 | struct hil_mlc *mlc; | ||
803 | |||
804 | if (serio->private != NULL) return -EBUSY; | ||
805 | |||
806 | map = serio->port_data; | ||
807 | if (map == NULL) { | ||
808 | BUG(); | ||
809 | return -ENODEV; | ||
810 | } | ||
811 | mlc = map->mlc; | ||
812 | if (mlc == NULL) { | ||
813 | BUG(); | ||
814 | return -ENODEV; | ||
815 | } | ||
816 | |||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static void hil_mlc_serio_close(struct serio *serio) { | ||
821 | struct hil_mlc_serio_map *map; | ||
822 | struct hil_mlc *mlc; | ||
823 | |||
824 | map = serio->port_data; | ||
825 | if (map == NULL) { | ||
826 | BUG(); | ||
827 | return; | ||
828 | } | ||
829 | mlc = map->mlc; | ||
830 | if (mlc == NULL) { | ||
831 | BUG(); | ||
832 | return; | ||
833 | } | ||
834 | |||
835 | serio->private = NULL; | ||
836 | serio->drv = NULL; | ||
837 | /* TODO wake up interruptable */ | ||
838 | } | ||
839 | |||
840 | int hil_mlc_register(hil_mlc *mlc) { | ||
841 | int i; | ||
842 | unsigned long flags; | ||
843 | |||
844 | if (mlc == NULL) { | ||
845 | return -EINVAL; | ||
846 | } | ||
847 | |||
848 | mlc->istarted = 0; | ||
849 | mlc->ostarted = 0; | ||
850 | |||
851 | rwlock_init(&mlc->lock); | ||
852 | init_MUTEX(&(mlc->osem)); | ||
853 | |||
854 | init_MUTEX(&(mlc->isem)); | ||
855 | mlc->icount = -1; | ||
856 | mlc->imatch = 0; | ||
857 | |||
858 | mlc->opercnt = 0; | ||
859 | |||
860 | init_MUTEX_LOCKED(&(mlc->csem)); | ||
861 | |||
862 | hil_mlc_clear_di_scratch(mlc); | ||
863 | hil_mlc_clear_di_map(mlc, 0); | ||
864 | for (i = 0; i < HIL_MLC_DEVMEM; i++) { | ||
865 | struct serio *mlc_serio; | ||
866 | hil_mlc_copy_di_scratch(mlc, i); | ||
867 | mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL); | ||
868 | mlc->serio[i] = mlc_serio; | ||
869 | memset(mlc_serio, 0, sizeof(*mlc_serio)); | ||
870 | mlc_serio->type = SERIO_HIL | SERIO_HIL_MLC; | ||
871 | mlc_serio->write = hil_mlc_serio_write; | ||
872 | mlc_serio->open = hil_mlc_serio_open; | ||
873 | mlc_serio->close = hil_mlc_serio_close; | ||
874 | mlc_serio->port_data = &(mlc->serio_map[i]); | ||
875 | mlc->serio_map[i].mlc = mlc; | ||
876 | mlc->serio_map[i].didx = i; | ||
877 | mlc->serio_map[i].di_revmap = -1; | ||
878 | mlc->serio_opacket[i] = 0; | ||
879 | mlc->serio_oidx[i] = 0; | ||
880 | serio_register_port(mlc_serio); | ||
881 | } | ||
882 | |||
883 | mlc->tasklet = &hil_mlcs_tasklet; | ||
884 | |||
885 | write_lock_irqsave(&hil_mlcs_lock, flags); | ||
886 | list_add_tail(&mlc->list, &hil_mlcs); | ||
887 | mlc->seidx = HILSEN_START; | ||
888 | write_unlock_irqrestore(&hil_mlcs_lock, flags); | ||
889 | |||
890 | tasklet_schedule(&hil_mlcs_tasklet); | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | int hil_mlc_unregister(hil_mlc *mlc) { | ||
895 | struct list_head *tmp; | ||
896 | unsigned long flags; | ||
897 | int i; | ||
898 | |||
899 | if (mlc == NULL) | ||
900 | return -EINVAL; | ||
901 | |||
902 | write_lock_irqsave(&hil_mlcs_lock, flags); | ||
903 | list_for_each(tmp, &hil_mlcs) { | ||
904 | if (list_entry(tmp, hil_mlc, list) == mlc) | ||
905 | goto found; | ||
906 | } | ||
907 | |||
908 | /* not found in list */ | ||
909 | write_unlock_irqrestore(&hil_mlcs_lock, flags); | ||
910 | tasklet_schedule(&hil_mlcs_tasklet); | ||
911 | return -ENODEV; | ||
912 | |||
913 | found: | ||
914 | list_del(tmp); | ||
915 | write_unlock_irqrestore(&hil_mlcs_lock, flags); | ||
916 | |||
917 | for (i = 0; i < HIL_MLC_DEVMEM; i++) { | ||
918 | serio_unregister_port(mlc->serio[i]); | ||
919 | mlc->serio[i] = NULL; | ||
920 | } | ||
921 | |||
922 | tasklet_schedule(&hil_mlcs_tasklet); | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | /**************************** Module interface *************************/ | ||
927 | |||
928 | static int __init hil_mlc_init(void) | ||
929 | { | ||
930 | init_timer(&hil_mlcs_kicker); | ||
931 | hil_mlcs_kicker.expires = jiffies + HZ; | ||
932 | hil_mlcs_kicker.function = &hil_mlcs_timer; | ||
933 | add_timer(&hil_mlcs_kicker); | ||
934 | |||
935 | tasklet_enable(&hil_mlcs_tasklet); | ||
936 | |||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static void __exit hil_mlc_exit(void) | ||
941 | { | ||
942 | del_timer(&hil_mlcs_kicker); | ||
943 | |||
944 | tasklet_disable(&hil_mlcs_tasklet); | ||
945 | tasklet_kill(&hil_mlcs_tasklet); | ||
946 | } | ||
947 | |||
948 | module_init(hil_mlc_init); | ||
949 | module_exit(hil_mlc_exit); | ||
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c new file mode 100644 index 000000000000..7629452dd64b --- /dev/null +++ b/drivers/input/serio/hp_sdc.c | |||
@@ -0,0 +1,1054 @@ | |||
1 | /* | ||
2 | * HP i8042-based System Device Controller driver. | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * System Device Controller Microprocessor Firmware Theory of Operation | ||
31 | * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 | ||
32 | * Helge Deller's original hilkbd.c port for PA-RISC. | ||
33 | * | ||
34 | * | ||
35 | * Driver theory of operation: | ||
36 | * | ||
37 | * hp_sdc_put does all writing to the SDC. ISR can run on a different | ||
38 | * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time | ||
39 | * (it cannot really benefit from SMP anyway.) A tasket fit this perfectly. | ||
40 | * | ||
41 | * All data coming back from the SDC is sent via interrupt and can be read | ||
42 | * fully in the ISR, so there are no latency/throughput problems there. | ||
43 | * The problem is with output, due to the slow clock speed of the SDC | ||
44 | * compared to the CPU. This should not be too horrible most of the time, | ||
45 | * but if used with HIL devices that support the multibyte transfer command, | ||
46 | * keeping outbound throughput flowing at the 6500KBps that the HIL is | ||
47 | * capable of is more than can be done at HZ=100. | ||
48 | * | ||
49 | * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf | ||
50 | * is set to 0 when the IBF flag in the status register has cleared. ISR | ||
51 | * may do this, and may also access the parts of queued transactions related | ||
52 | * to reading data back from the SDC, but otherwise will not touch the | ||
53 | * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1. | ||
54 | * | ||
55 | * The i8042 write index and the values in the 4-byte input buffer | ||
56 | * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively, | ||
57 | * to minimize the amount of IO needed to the SDC. However these values | ||
58 | * do not need to be locked since they are only ever accessed by hp_sdc_put. | ||
59 | * | ||
60 | * A timer task schedules the tasklet once per second just to make | ||
61 | * sure it doesn't freeze up and to allow for bad reads to time out. | ||
62 | */ | ||
63 | |||
64 | #include <linux/hp_sdc.h> | ||
65 | #include <linux/sched.h> | ||
66 | #include <linux/errno.h> | ||
67 | #include <linux/init.h> | ||
68 | #include <linux/module.h> | ||
69 | #include <linux/ioport.h> | ||
70 | #include <linux/time.h> | ||
71 | #include <linux/slab.h> | ||
72 | #include <linux/hil.h> | ||
73 | #include <asm/io.h> | ||
74 | #include <asm/system.h> | ||
75 | |||
76 | /* Machine-specific abstraction */ | ||
77 | |||
78 | #if defined(__hppa__) | ||
79 | # include <asm/parisc-device.h> | ||
80 | # define sdc_readb(p) gsc_readb(p) | ||
81 | # define sdc_writeb(v,p) gsc_writeb((v),(p)) | ||
82 | #elif defined(__mc68000__) | ||
83 | # include <asm/uaccess.h> | ||
84 | # define sdc_readb(p) in_8(p) | ||
85 | # define sdc_writeb(v,p) out_8((p),(v)) | ||
86 | #else | ||
87 | # error "HIL is not supported on this platform" | ||
88 | #endif | ||
89 | |||
90 | #define PREFIX "HP SDC: " | ||
91 | |||
92 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
93 | MODULE_DESCRIPTION("HP i8042-based SDC Driver"); | ||
94 | MODULE_LICENSE("Dual BSD/GPL"); | ||
95 | |||
96 | EXPORT_SYMBOL(hp_sdc_request_timer_irq); | ||
97 | EXPORT_SYMBOL(hp_sdc_request_hil_irq); | ||
98 | EXPORT_SYMBOL(hp_sdc_request_cooked_irq); | ||
99 | |||
100 | EXPORT_SYMBOL(hp_sdc_release_timer_irq); | ||
101 | EXPORT_SYMBOL(hp_sdc_release_hil_irq); | ||
102 | EXPORT_SYMBOL(hp_sdc_release_cooked_irq); | ||
103 | |||
104 | EXPORT_SYMBOL(hp_sdc_enqueue_transaction); | ||
105 | EXPORT_SYMBOL(hp_sdc_dequeue_transaction); | ||
106 | |||
107 | static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */ | ||
108 | |||
109 | /*************** primitives for use in any context *********************/ | ||
110 | static inline uint8_t hp_sdc_status_in8 (void) { | ||
111 | uint8_t status; | ||
112 | unsigned long flags; | ||
113 | |||
114 | write_lock_irqsave(&hp_sdc.ibf_lock, flags); | ||
115 | status = sdc_readb(hp_sdc.status_io); | ||
116 | if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0; | ||
117 | write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); | ||
118 | |||
119 | return status; | ||
120 | } | ||
121 | |||
122 | static inline uint8_t hp_sdc_data_in8 (void) { | ||
123 | return sdc_readb(hp_sdc.data_io); | ||
124 | } | ||
125 | |||
126 | static inline void hp_sdc_status_out8 (uint8_t val) { | ||
127 | unsigned long flags; | ||
128 | |||
129 | write_lock_irqsave(&hp_sdc.ibf_lock, flags); | ||
130 | hp_sdc.ibf = 1; | ||
131 | if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff; | ||
132 | sdc_writeb(val, hp_sdc.status_io); | ||
133 | write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); | ||
134 | } | ||
135 | |||
136 | static inline void hp_sdc_data_out8 (uint8_t val) { | ||
137 | unsigned long flags; | ||
138 | |||
139 | write_lock_irqsave(&hp_sdc.ibf_lock, flags); | ||
140 | hp_sdc.ibf = 1; | ||
141 | sdc_writeb(val, hp_sdc.data_io); | ||
142 | write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); | ||
143 | } | ||
144 | |||
145 | /* Care must be taken to only invoke hp_sdc_spin_ibf when | ||
146 | * absolutely needed, or in rarely invoked subroutines. | ||
147 | * Not only does it waste CPU cycles, it also wastes bus cycles. | ||
148 | */ | ||
149 | static inline void hp_sdc_spin_ibf(void) { | ||
150 | unsigned long flags; | ||
151 | rwlock_t *lock; | ||
152 | |||
153 | lock = &hp_sdc.ibf_lock; | ||
154 | |||
155 | read_lock_irqsave(lock, flags); | ||
156 | if (!hp_sdc.ibf) { | ||
157 | read_unlock_irqrestore(lock, flags); | ||
158 | return; | ||
159 | } | ||
160 | read_unlock(lock); | ||
161 | write_lock(lock); | ||
162 | while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {}; | ||
163 | hp_sdc.ibf = 0; | ||
164 | write_unlock_irqrestore(lock, flags); | ||
165 | } | ||
166 | |||
167 | |||
168 | /************************ Interrupt context functions ************************/ | ||
169 | static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) { | ||
170 | hp_sdc_transaction *curr; | ||
171 | |||
172 | read_lock(&hp_sdc.rtq_lock); | ||
173 | if (hp_sdc.rcurr < 0) { | ||
174 | read_unlock(&hp_sdc.rtq_lock); | ||
175 | return; | ||
176 | } | ||
177 | curr = hp_sdc.tq[hp_sdc.rcurr]; | ||
178 | read_unlock(&hp_sdc.rtq_lock); | ||
179 | |||
180 | curr->seq[curr->idx++] = status; | ||
181 | curr->seq[curr->idx++] = data; | ||
182 | hp_sdc.rqty -= 2; | ||
183 | do_gettimeofday(&hp_sdc.rtv); | ||
184 | |||
185 | if (hp_sdc.rqty <= 0) { | ||
186 | /* All data has been gathered. */ | ||
187 | if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) { | ||
188 | if (curr->act.semaphore) up(curr->act.semaphore); | ||
189 | } | ||
190 | if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) { | ||
191 | if (curr->act.irqhook) | ||
192 | curr->act.irqhook(irq, dev_id, status, data); | ||
193 | } | ||
194 | curr->actidx = curr->idx; | ||
195 | curr->idx++; | ||
196 | /* Return control of this transaction */ | ||
197 | write_lock(&hp_sdc.rtq_lock); | ||
198 | hp_sdc.rcurr = -1; | ||
199 | hp_sdc.rqty = 0; | ||
200 | write_unlock(&hp_sdc.rtq_lock); | ||
201 | tasklet_schedule(&hp_sdc.task); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) { | ||
206 | uint8_t status, data; | ||
207 | |||
208 | status = hp_sdc_status_in8(); | ||
209 | /* Read data unconditionally to advance i8042. */ | ||
210 | data = hp_sdc_data_in8(); | ||
211 | |||
212 | /* For now we are ignoring these until we get the SDC to behave. */ | ||
213 | if (((status & 0xf1) == 0x51) && data == 0x82) { | ||
214 | return IRQ_HANDLED; | ||
215 | } | ||
216 | |||
217 | switch(status & HP_SDC_STATUS_IRQMASK) { | ||
218 | case 0: /* This case is not documented. */ | ||
219 | break; | ||
220 | case HP_SDC_STATUS_USERTIMER: | ||
221 | case HP_SDC_STATUS_PERIODIC: | ||
222 | case HP_SDC_STATUS_TIMER: | ||
223 | read_lock(&hp_sdc.hook_lock); | ||
224 | if (hp_sdc.timer != NULL) | ||
225 | hp_sdc.timer(irq, dev_id, status, data); | ||
226 | read_unlock(&hp_sdc.hook_lock); | ||
227 | break; | ||
228 | case HP_SDC_STATUS_REG: | ||
229 | hp_sdc_take(irq, dev_id, status, data); | ||
230 | break; | ||
231 | case HP_SDC_STATUS_HILCMD: | ||
232 | case HP_SDC_STATUS_HILDATA: | ||
233 | read_lock(&hp_sdc.hook_lock); | ||
234 | if (hp_sdc.hil != NULL) | ||
235 | hp_sdc.hil(irq, dev_id, status, data); | ||
236 | read_unlock(&hp_sdc.hook_lock); | ||
237 | break; | ||
238 | case HP_SDC_STATUS_PUP: | ||
239 | read_lock(&hp_sdc.hook_lock); | ||
240 | if (hp_sdc.pup != NULL) | ||
241 | hp_sdc.pup(irq, dev_id, status, data); | ||
242 | else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n"); | ||
243 | read_unlock(&hp_sdc.hook_lock); | ||
244 | break; | ||
245 | default: | ||
246 | read_lock(&hp_sdc.hook_lock); | ||
247 | if (hp_sdc.cooked != NULL) | ||
248 | hp_sdc.cooked(irq, dev_id, status, data); | ||
249 | read_unlock(&hp_sdc.hook_lock); | ||
250 | break; | ||
251 | } | ||
252 | return IRQ_HANDLED; | ||
253 | } | ||
254 | |||
255 | |||
256 | static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) { | ||
257 | int status; | ||
258 | |||
259 | status = hp_sdc_status_in8(); | ||
260 | printk(KERN_WARNING PREFIX "NMI !\n"); | ||
261 | |||
262 | #if 0 | ||
263 | if (status & HP_SDC_NMISTATUS_FHS) { | ||
264 | read_lock(&hp_sdc.hook_lock); | ||
265 | if (hp_sdc.timer != NULL) | ||
266 | hp_sdc.timer(irq, dev_id, status, 0); | ||
267 | read_unlock(&hp_sdc.hook_lock); | ||
268 | } | ||
269 | else { | ||
270 | /* TODO: pass this on to the HIL handler, or do SAK here? */ | ||
271 | printk(KERN_WARNING PREFIX "HIL NMI\n"); | ||
272 | } | ||
273 | #endif | ||
274 | return IRQ_HANDLED; | ||
275 | } | ||
276 | |||
277 | |||
278 | /***************** Kernel (tasklet) context functions ****************/ | ||
279 | |||
280 | unsigned long hp_sdc_put(void); | ||
281 | |||
282 | static void hp_sdc_tasklet(unsigned long foo) { | ||
283 | |||
284 | write_lock_irq(&hp_sdc.rtq_lock); | ||
285 | if (hp_sdc.rcurr >= 0) { | ||
286 | struct timeval tv; | ||
287 | do_gettimeofday(&tv); | ||
288 | if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000; | ||
289 | if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { | ||
290 | hp_sdc_transaction *curr; | ||
291 | uint8_t tmp; | ||
292 | |||
293 | curr = hp_sdc.tq[hp_sdc.rcurr]; | ||
294 | /* If this turns out to be a normal failure mode | ||
295 | * we'll need to figure out a way to communicate | ||
296 | * it back to the application. and be less verbose. | ||
297 | */ | ||
298 | printk(KERN_WARNING PREFIX "read timeout (%ius)!\n", | ||
299 | tv.tv_usec - hp_sdc.rtv.tv_usec); | ||
300 | curr->idx += hp_sdc.rqty; | ||
301 | hp_sdc.rqty = 0; | ||
302 | tmp = curr->seq[curr->actidx]; | ||
303 | curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD; | ||
304 | if(tmp & HP_SDC_ACT_SEMAPHORE) { | ||
305 | if (curr->act.semaphore) | ||
306 | up(curr->act.semaphore); | ||
307 | } | ||
308 | if(tmp & HP_SDC_ACT_CALLBACK) { | ||
309 | /* Note this means that irqhooks may be called | ||
310 | * in tasklet/bh context. | ||
311 | */ | ||
312 | if (curr->act.irqhook) | ||
313 | curr->act.irqhook(0, 0, 0, 0); | ||
314 | } | ||
315 | curr->actidx = curr->idx; | ||
316 | curr->idx++; | ||
317 | hp_sdc.rcurr = -1; | ||
318 | } | ||
319 | } | ||
320 | write_unlock_irq(&hp_sdc.rtq_lock); | ||
321 | hp_sdc_put(); | ||
322 | } | ||
323 | |||
324 | unsigned long hp_sdc_put(void) { | ||
325 | hp_sdc_transaction *curr; | ||
326 | uint8_t act; | ||
327 | int idx, curridx; | ||
328 | |||
329 | int limit = 0; | ||
330 | |||
331 | write_lock(&hp_sdc.lock); | ||
332 | |||
333 | /* If i8042 buffers are full, we cannot do anything that | ||
334 | requires output, so we skip to the administrativa. */ | ||
335 | if (hp_sdc.ibf) { | ||
336 | hp_sdc_status_in8(); | ||
337 | if (hp_sdc.ibf) goto finish; | ||
338 | } | ||
339 | |||
340 | anew: | ||
341 | /* See if we are in the middle of a sequence. */ | ||
342 | if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0; | ||
343 | read_lock_irq(&hp_sdc.rtq_lock); | ||
344 | if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++; | ||
345 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
346 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
347 | curridx = hp_sdc.wcurr; | ||
348 | |||
349 | if (hp_sdc.tq[curridx] != NULL) goto start; | ||
350 | |||
351 | while (++curridx != hp_sdc.wcurr) { | ||
352 | if (curridx >= HP_SDC_QUEUE_LEN) { | ||
353 | curridx = -1; /* Wrap to top */ | ||
354 | continue; | ||
355 | } | ||
356 | read_lock_irq(&hp_sdc.rtq_lock); | ||
357 | if (hp_sdc.rcurr == curridx) { | ||
358 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
359 | continue; | ||
360 | } | ||
361 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
362 | if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */ | ||
363 | } | ||
364 | if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */ | ||
365 | curridx = -1; | ||
366 | } | ||
367 | hp_sdc.wcurr = curridx; | ||
368 | |||
369 | start: | ||
370 | |||
371 | /* Check to see if the interrupt mask needs to be set. */ | ||
372 | if (hp_sdc.set_im) { | ||
373 | hp_sdc_status_out8(hp_sdc.im | HP_SDC_CMD_SET_IM); | ||
374 | hp_sdc.set_im = 0; | ||
375 | goto finish; | ||
376 | } | ||
377 | |||
378 | if (hp_sdc.wcurr == -1) goto done; | ||
379 | |||
380 | curr = hp_sdc.tq[curridx]; | ||
381 | idx = curr->actidx; | ||
382 | |||
383 | if (curr->actidx >= curr->endidx) { | ||
384 | hp_sdc.tq[curridx] = NULL; | ||
385 | /* Interleave outbound data between the transactions. */ | ||
386 | hp_sdc.wcurr++; | ||
387 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
388 | goto finish; | ||
389 | } | ||
390 | |||
391 | act = curr->seq[idx]; | ||
392 | idx++; | ||
393 | |||
394 | if (curr->idx >= curr->endidx) { | ||
395 | if (act & HP_SDC_ACT_DEALLOC) kfree(curr); | ||
396 | hp_sdc.tq[curridx] = NULL; | ||
397 | /* Interleave outbound data between the transactions. */ | ||
398 | hp_sdc.wcurr++; | ||
399 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
400 | goto finish; | ||
401 | } | ||
402 | |||
403 | while (act & HP_SDC_ACT_PRECMD) { | ||
404 | if (curr->idx != idx) { | ||
405 | idx++; | ||
406 | act &= ~HP_SDC_ACT_PRECMD; | ||
407 | break; | ||
408 | } | ||
409 | hp_sdc_status_out8(curr->seq[idx]); | ||
410 | curr->idx++; | ||
411 | /* act finished? */ | ||
412 | if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD) | ||
413 | goto actdone; | ||
414 | /* skip quantity field if data-out sequence follows. */ | ||
415 | if (act & HP_SDC_ACT_DATAOUT) curr->idx++; | ||
416 | goto finish; | ||
417 | } | ||
418 | if (act & HP_SDC_ACT_DATAOUT) { | ||
419 | int qty; | ||
420 | |||
421 | qty = curr->seq[idx]; | ||
422 | idx++; | ||
423 | if (curr->idx - idx < qty) { | ||
424 | hp_sdc_data_out8(curr->seq[curr->idx]); | ||
425 | curr->idx++; | ||
426 | /* act finished? */ | ||
427 | if ((curr->idx - idx >= qty) && | ||
428 | ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)) | ||
429 | goto actdone; | ||
430 | goto finish; | ||
431 | } | ||
432 | idx += qty; | ||
433 | act &= ~HP_SDC_ACT_DATAOUT; | ||
434 | } | ||
435 | else while (act & HP_SDC_ACT_DATAREG) { | ||
436 | int mask; | ||
437 | uint8_t w7[4]; | ||
438 | |||
439 | mask = curr->seq[idx]; | ||
440 | if (idx != curr->idx) { | ||
441 | idx++; | ||
442 | idx += !!(mask & 1); | ||
443 | idx += !!(mask & 2); | ||
444 | idx += !!(mask & 4); | ||
445 | idx += !!(mask & 8); | ||
446 | act &= ~HP_SDC_ACT_DATAREG; | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0]; | ||
451 | w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1]; | ||
452 | w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2]; | ||
453 | w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3]; | ||
454 | |||
455 | if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 || | ||
456 | w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) { | ||
457 | int i = 0; | ||
458 | |||
459 | /* Need to point the write index register */ | ||
460 | while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; | ||
461 | if (i < 4) { | ||
462 | hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i); | ||
463 | hp_sdc.wi = 0x70 + i; | ||
464 | goto finish; | ||
465 | } | ||
466 | idx++; | ||
467 | if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG) | ||
468 | goto actdone; | ||
469 | curr->idx = idx; | ||
470 | act &= ~HP_SDC_ACT_DATAREG; | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | hp_sdc_data_out8(w7[hp_sdc.wi - 0x70]); | ||
475 | hp_sdc.r7[hp_sdc.wi - 0x70] = w7[hp_sdc.wi - 0x70]; | ||
476 | hp_sdc.wi++; /* write index register autoincrements */ | ||
477 | { | ||
478 | int i = 0; | ||
479 | |||
480 | while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; | ||
481 | if (i >= 4) { | ||
482 | curr->idx = idx + 1; | ||
483 | if ((act & HP_SDC_ACT_DURING) == | ||
484 | HP_SDC_ACT_DATAREG) | ||
485 | goto actdone; | ||
486 | } | ||
487 | } | ||
488 | goto finish; | ||
489 | } | ||
490 | /* We don't go any further in the command if there is a pending read, | ||
491 | because we don't want interleaved results. */ | ||
492 | read_lock_irq(&hp_sdc.rtq_lock); | ||
493 | if (hp_sdc.rcurr >= 0) { | ||
494 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
495 | goto finish; | ||
496 | } | ||
497 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
498 | |||
499 | |||
500 | if (act & HP_SDC_ACT_POSTCMD) { | ||
501 | uint8_t postcmd; | ||
502 | |||
503 | /* curr->idx should == idx at this point. */ | ||
504 | postcmd = curr->seq[idx]; | ||
505 | curr->idx++; | ||
506 | if (act & HP_SDC_ACT_DATAIN) { | ||
507 | |||
508 | /* Start a new read */ | ||
509 | hp_sdc.rqty = curr->seq[curr->idx]; | ||
510 | do_gettimeofday(&hp_sdc.rtv); | ||
511 | curr->idx++; | ||
512 | /* Still need to lock here in case of spurious irq. */ | ||
513 | write_lock_irq(&hp_sdc.rtq_lock); | ||
514 | hp_sdc.rcurr = curridx; | ||
515 | write_unlock_irq(&hp_sdc.rtq_lock); | ||
516 | hp_sdc_status_out8(postcmd); | ||
517 | goto finish; | ||
518 | } | ||
519 | hp_sdc_status_out8(postcmd); | ||
520 | goto actdone; | ||
521 | } | ||
522 | |||
523 | actdone: | ||
524 | if (act & HP_SDC_ACT_SEMAPHORE) { | ||
525 | up(curr->act.semaphore); | ||
526 | } | ||
527 | else if (act & HP_SDC_ACT_CALLBACK) { | ||
528 | curr->act.irqhook(0,0,0,0); | ||
529 | } | ||
530 | if (curr->idx >= curr->endidx) { /* This transaction is over. */ | ||
531 | if (act & HP_SDC_ACT_DEALLOC) kfree(curr); | ||
532 | hp_sdc.tq[curridx] = NULL; | ||
533 | } | ||
534 | else { | ||
535 | curr->actidx = idx + 1; | ||
536 | curr->idx = idx + 2; | ||
537 | } | ||
538 | /* Interleave outbound data between the transactions. */ | ||
539 | hp_sdc.wcurr++; | ||
540 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
541 | |||
542 | finish: | ||
543 | /* If by some quirk IBF has cleared and our ISR has run to | ||
544 | see that that has happened, do it all again. */ | ||
545 | if (!hp_sdc.ibf && limit++ < 20) goto anew; | ||
546 | |||
547 | done: | ||
548 | if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task); | ||
549 | write_unlock(&hp_sdc.lock); | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | /******* Functions called in either user or kernel context ****/ | ||
554 | int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { | ||
555 | unsigned long flags; | ||
556 | int i; | ||
557 | |||
558 | if (this == NULL) { | ||
559 | tasklet_schedule(&hp_sdc.task); | ||
560 | return -EINVAL; | ||
561 | }; | ||
562 | |||
563 | write_lock_irqsave(&hp_sdc.lock, flags); | ||
564 | |||
565 | /* Can't have same transaction on queue twice */ | ||
566 | for (i=0; i < HP_SDC_QUEUE_LEN; i++) | ||
567 | if (hp_sdc.tq[i] == this) goto fail; | ||
568 | |||
569 | this->actidx = 0; | ||
570 | this->idx = 1; | ||
571 | |||
572 | /* Search for empty slot */ | ||
573 | for (i=0; i < HP_SDC_QUEUE_LEN; i++) { | ||
574 | if (hp_sdc.tq[i] == NULL) { | ||
575 | hp_sdc.tq[i] = this; | ||
576 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
577 | tasklet_schedule(&hp_sdc.task); | ||
578 | return 0; | ||
579 | } | ||
580 | } | ||
581 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
582 | printk(KERN_WARNING PREFIX "No free slot to add transaction.\n"); | ||
583 | return -EBUSY; | ||
584 | |||
585 | fail: | ||
586 | write_unlock_irqrestore(&hp_sdc.lock,flags); | ||
587 | printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n"); | ||
588 | return -EINVAL; | ||
589 | } | ||
590 | |||
591 | int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) { | ||
592 | unsigned long flags; | ||
593 | int i; | ||
594 | |||
595 | write_lock_irqsave(&hp_sdc.lock, flags); | ||
596 | |||
597 | /* TODO: don't remove it if it's not done. */ | ||
598 | |||
599 | for (i=0; i < HP_SDC_QUEUE_LEN; i++) | ||
600 | if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL; | ||
601 | |||
602 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | |||
607 | |||
608 | /********************** User context functions **************************/ | ||
609 | int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) { | ||
610 | |||
611 | if (callback == NULL || hp_sdc.dev == NULL) { | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | write_lock_irq(&hp_sdc.hook_lock); | ||
615 | if (hp_sdc.timer != NULL) { | ||
616 | write_unlock_irq(&hp_sdc.hook_lock); | ||
617 | return -EBUSY; | ||
618 | } | ||
619 | |||
620 | hp_sdc.timer = callback; | ||
621 | /* Enable interrupts from the timers */ | ||
622 | hp_sdc.im &= ~HP_SDC_IM_FH; | ||
623 | hp_sdc.im &= ~HP_SDC_IM_PT; | ||
624 | hp_sdc.im &= ~HP_SDC_IM_TIMERS; | ||
625 | hp_sdc.set_im = 1; | ||
626 | write_unlock_irq(&hp_sdc.hook_lock); | ||
627 | |||
628 | tasklet_schedule(&hp_sdc.task); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) { | ||
634 | |||
635 | if (callback == NULL || hp_sdc.dev == NULL) { | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | write_lock_irq(&hp_sdc.hook_lock); | ||
639 | if (hp_sdc.hil != NULL) { | ||
640 | write_unlock_irq(&hp_sdc.hook_lock); | ||
641 | return -EBUSY; | ||
642 | } | ||
643 | |||
644 | hp_sdc.hil = callback; | ||
645 | hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
646 | hp_sdc.set_im = 1; | ||
647 | write_unlock_irq(&hp_sdc.hook_lock); | ||
648 | |||
649 | tasklet_schedule(&hp_sdc.task); | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) { | ||
655 | |||
656 | if (callback == NULL || hp_sdc.dev == NULL) { | ||
657 | return -EINVAL; | ||
658 | } | ||
659 | write_lock_irq(&hp_sdc.hook_lock); | ||
660 | if (hp_sdc.cooked != NULL) { | ||
661 | write_unlock_irq(&hp_sdc.hook_lock); | ||
662 | return -EBUSY; | ||
663 | } | ||
664 | |||
665 | /* Enable interrupts from the HIL MLC */ | ||
666 | hp_sdc.cooked = callback; | ||
667 | hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
668 | hp_sdc.set_im = 1; | ||
669 | write_unlock_irq(&hp_sdc.hook_lock); | ||
670 | |||
671 | tasklet_schedule(&hp_sdc.task); | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) { | ||
677 | |||
678 | |||
679 | write_lock_irq(&hp_sdc.hook_lock); | ||
680 | if ((callback != hp_sdc.timer) || | ||
681 | (hp_sdc.timer == NULL)) { | ||
682 | write_unlock_irq(&hp_sdc.hook_lock); | ||
683 | return -EINVAL; | ||
684 | } | ||
685 | |||
686 | /* Disable interrupts from the timers */ | ||
687 | hp_sdc.timer = NULL; | ||
688 | hp_sdc.im |= HP_SDC_IM_TIMERS; | ||
689 | hp_sdc.im |= HP_SDC_IM_FH; | ||
690 | hp_sdc.im |= HP_SDC_IM_PT; | ||
691 | hp_sdc.set_im = 1; | ||
692 | write_unlock_irq(&hp_sdc.hook_lock); | ||
693 | tasklet_schedule(&hp_sdc.task); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) { | ||
699 | |||
700 | write_lock_irq(&hp_sdc.hook_lock); | ||
701 | if ((callback != hp_sdc.hil) || | ||
702 | (hp_sdc.hil == NULL)) { | ||
703 | write_unlock_irq(&hp_sdc.hook_lock); | ||
704 | return -EINVAL; | ||
705 | } | ||
706 | |||
707 | hp_sdc.hil = NULL; | ||
708 | /* Disable interrupts from HIL only if there is no cooked driver. */ | ||
709 | if(hp_sdc.cooked == NULL) { | ||
710 | hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
711 | hp_sdc.set_im = 1; | ||
712 | } | ||
713 | write_unlock_irq(&hp_sdc.hook_lock); | ||
714 | tasklet_schedule(&hp_sdc.task); | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) { | ||
720 | |||
721 | write_lock_irq(&hp_sdc.hook_lock); | ||
722 | if ((callback != hp_sdc.cooked) || | ||
723 | (hp_sdc.cooked == NULL)) { | ||
724 | write_unlock_irq(&hp_sdc.hook_lock); | ||
725 | return -EINVAL; | ||
726 | } | ||
727 | |||
728 | hp_sdc.cooked = NULL; | ||
729 | /* Disable interrupts from HIL only if there is no raw HIL driver. */ | ||
730 | if(hp_sdc.hil == NULL) { | ||
731 | hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
732 | hp_sdc.set_im = 1; | ||
733 | } | ||
734 | write_unlock_irq(&hp_sdc.hook_lock); | ||
735 | tasklet_schedule(&hp_sdc.task); | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | /************************* Keepalive timer task *********************/ | ||
741 | |||
742 | void hp_sdc_kicker (unsigned long data) { | ||
743 | tasklet_schedule(&hp_sdc.task); | ||
744 | /* Re-insert the periodic task. */ | ||
745 | mod_timer(&hp_sdc.kicker, jiffies + HZ); | ||
746 | } | ||
747 | |||
748 | /************************** Module Initialization ***************************/ | ||
749 | |||
750 | #if defined(__hppa__) | ||
751 | |||
752 | static struct parisc_device_id hp_sdc_tbl[] = { | ||
753 | { | ||
754 | .hw_type = HPHW_FIO, | ||
755 | .hversion_rev = HVERSION_REV_ANY_ID, | ||
756 | .hversion = HVERSION_ANY_ID, | ||
757 | .sversion = 0x73, | ||
758 | }, | ||
759 | { 0, } | ||
760 | }; | ||
761 | |||
762 | MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl); | ||
763 | |||
764 | static int __init hp_sdc_init_hppa(struct parisc_device *d); | ||
765 | |||
766 | static struct parisc_driver hp_sdc_driver = { | ||
767 | .name = "HP SDC", | ||
768 | .id_table = hp_sdc_tbl, | ||
769 | .probe = hp_sdc_init_hppa, | ||
770 | }; | ||
771 | |||
772 | #endif /* __hppa__ */ | ||
773 | |||
774 | static int __init hp_sdc_init(void) | ||
775 | { | ||
776 | int i; | ||
777 | char *errstr; | ||
778 | hp_sdc_transaction t_sync; | ||
779 | uint8_t ts_sync[6]; | ||
780 | struct semaphore s_sync; | ||
781 | |||
782 | rwlock_init(&hp_sdc.lock); | ||
783 | rwlock_init(&hp_sdc.ibf_lock); | ||
784 | rwlock_init(&hp_sdc.rtq_lock); | ||
785 | rwlock_init(&hp_sdc.hook_lock); | ||
786 | |||
787 | hp_sdc.timer = NULL; | ||
788 | hp_sdc.hil = NULL; | ||
789 | hp_sdc.pup = NULL; | ||
790 | hp_sdc.cooked = NULL; | ||
791 | hp_sdc.im = HP_SDC_IM_MASK; /* Mask maskable irqs */ | ||
792 | hp_sdc.set_im = 1; | ||
793 | hp_sdc.wi = 0xff; | ||
794 | hp_sdc.r7[0] = 0xff; | ||
795 | hp_sdc.r7[1] = 0xff; | ||
796 | hp_sdc.r7[2] = 0xff; | ||
797 | hp_sdc.r7[3] = 0xff; | ||
798 | hp_sdc.ibf = 1; | ||
799 | |||
800 | for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL; | ||
801 | hp_sdc.wcurr = -1; | ||
802 | hp_sdc.rcurr = -1; | ||
803 | hp_sdc.rqty = 0; | ||
804 | |||
805 | hp_sdc.dev_err = -ENODEV; | ||
806 | |||
807 | errstr = "IO not found for"; | ||
808 | if (!hp_sdc.base_io) goto err0; | ||
809 | |||
810 | errstr = "IRQ not found for"; | ||
811 | if (!hp_sdc.irq) goto err0; | ||
812 | |||
813 | hp_sdc.dev_err = -EBUSY; | ||
814 | |||
815 | #if defined(__hppa__) | ||
816 | errstr = "IO not available for"; | ||
817 | if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0; | ||
818 | #endif | ||
819 | |||
820 | errstr = "IRQ not available for"; | ||
821 | if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC", | ||
822 | (void *) hp_sdc.base_io)) goto err1; | ||
823 | |||
824 | errstr = "NMI not available for"; | ||
825 | if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", | ||
826 | (void *) hp_sdc.base_io)) goto err2; | ||
827 | |||
828 | printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", | ||
829 | (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); | ||
830 | |||
831 | hp_sdc_status_in8(); | ||
832 | hp_sdc_data_in8(); | ||
833 | |||
834 | tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0); | ||
835 | |||
836 | /* Sync the output buffer registers, thus scheduling hp_sdc_tasklet. */ | ||
837 | t_sync.actidx = 0; | ||
838 | t_sync.idx = 1; | ||
839 | t_sync.endidx = 6; | ||
840 | t_sync.seq = ts_sync; | ||
841 | ts_sync[0] = HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE; | ||
842 | ts_sync[1] = 0x0f; | ||
843 | ts_sync[2] = ts_sync[3] = ts_sync[4] = ts_sync[5] = 0; | ||
844 | t_sync.act.semaphore = &s_sync; | ||
845 | init_MUTEX_LOCKED(&s_sync); | ||
846 | hp_sdc_enqueue_transaction(&t_sync); | ||
847 | down(&s_sync); /* Wait for t_sync to complete */ | ||
848 | |||
849 | /* Create the keepalive task */ | ||
850 | init_timer(&hp_sdc.kicker); | ||
851 | hp_sdc.kicker.expires = jiffies + HZ; | ||
852 | hp_sdc.kicker.function = &hp_sdc_kicker; | ||
853 | add_timer(&hp_sdc.kicker); | ||
854 | |||
855 | hp_sdc.dev_err = 0; | ||
856 | return 0; | ||
857 | err2: | ||
858 | free_irq(hp_sdc.irq, NULL); | ||
859 | err1: | ||
860 | release_region(hp_sdc.data_io, 2); | ||
861 | err0: | ||
862 | printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", | ||
863 | errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); | ||
864 | hp_sdc.dev = NULL; | ||
865 | return hp_sdc.dev_err; | ||
866 | } | ||
867 | |||
868 | #if defined(__hppa__) | ||
869 | |||
870 | static int __init hp_sdc_init_hppa(struct parisc_device *d) | ||
871 | { | ||
872 | if (!d) return 1; | ||
873 | if (hp_sdc.dev != NULL) return 1; /* We only expect one SDC */ | ||
874 | |||
875 | hp_sdc.dev = d; | ||
876 | hp_sdc.irq = d->irq; | ||
877 | hp_sdc.nmi = d->aux_irq; | ||
878 | hp_sdc.base_io = d->hpa; | ||
879 | hp_sdc.data_io = d->hpa + 0x800; | ||
880 | hp_sdc.status_io = d->hpa + 0x801; | ||
881 | |||
882 | return hp_sdc_init(); | ||
883 | } | ||
884 | |||
885 | #endif /* __hppa__ */ | ||
886 | |||
887 | #if !defined(__mc68000__) /* Link error on m68k! */ | ||
888 | static void __exit hp_sdc_exit(void) | ||
889 | #else | ||
890 | static void hp_sdc_exit(void) | ||
891 | #endif | ||
892 | { | ||
893 | write_lock_irq(&hp_sdc.lock); | ||
894 | |||
895 | /* Turn off all maskable "sub-function" irq's. */ | ||
896 | hp_sdc_spin_ibf(); | ||
897 | sdc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io); | ||
898 | |||
899 | /* Wait until we know this has been processed by the i8042 */ | ||
900 | hp_sdc_spin_ibf(); | ||
901 | |||
902 | free_irq(hp_sdc.nmi, NULL); | ||
903 | free_irq(hp_sdc.irq, NULL); | ||
904 | write_unlock_irq(&hp_sdc.lock); | ||
905 | |||
906 | del_timer(&hp_sdc.kicker); | ||
907 | |||
908 | tasklet_kill(&hp_sdc.task); | ||
909 | |||
910 | /* release_region(hp_sdc.data_io, 2); */ | ||
911 | |||
912 | #if defined(__hppa__) | ||
913 | if (unregister_parisc_driver(&hp_sdc_driver)) | ||
914 | printk(KERN_WARNING PREFIX "Error unregistering HP SDC"); | ||
915 | #endif | ||
916 | } | ||
917 | |||
918 | static int __init hp_sdc_register(void) | ||
919 | { | ||
920 | hp_sdc_transaction tq_init; | ||
921 | uint8_t tq_init_seq[5]; | ||
922 | struct semaphore tq_init_sem; | ||
923 | #if defined(__mc68000__) | ||
924 | mm_segment_t fs; | ||
925 | unsigned char i; | ||
926 | #endif | ||
927 | |||
928 | hp_sdc.dev = NULL; | ||
929 | hp_sdc.dev_err = 0; | ||
930 | #if defined(__hppa__) | ||
931 | if (register_parisc_driver(&hp_sdc_driver)) { | ||
932 | printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n"); | ||
933 | return -ENODEV; | ||
934 | } | ||
935 | #elif defined(__mc68000__) | ||
936 | if (!MACH_IS_HP300) | ||
937 | return -ENODEV; | ||
938 | |||
939 | hp_sdc.irq = 1; | ||
940 | hp_sdc.nmi = 7; | ||
941 | hp_sdc.base_io = (unsigned long) 0xf0428000; | ||
942 | hp_sdc.data_io = (unsigned long) hp_sdc.base_io + 1; | ||
943 | hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3; | ||
944 | fs = get_fs(); | ||
945 | set_fs(KERNEL_DS); | ||
946 | if (!get_user(i, (unsigned char *)hp_sdc.data_io)) | ||
947 | hp_sdc.dev = (void *)1; | ||
948 | set_fs(fs); | ||
949 | hp_sdc.dev_err = hp_sdc_init(); | ||
950 | #endif | ||
951 | if (hp_sdc.dev == NULL) { | ||
952 | printk(KERN_WARNING PREFIX "No SDC found.\n"); | ||
953 | return hp_sdc.dev_err; | ||
954 | } | ||
955 | |||
956 | init_MUTEX_LOCKED(&tq_init_sem); | ||
957 | |||
958 | tq_init.actidx = 0; | ||
959 | tq_init.idx = 1; | ||
960 | tq_init.endidx = 5; | ||
961 | tq_init.seq = tq_init_seq; | ||
962 | tq_init.act.semaphore = &tq_init_sem; | ||
963 | |||
964 | tq_init_seq[0] = | ||
965 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; | ||
966 | tq_init_seq[1] = HP_SDC_CMD_READ_KCC; | ||
967 | tq_init_seq[2] = 1; | ||
968 | tq_init_seq[3] = 0; | ||
969 | tq_init_seq[4] = 0; | ||
970 | |||
971 | hp_sdc_enqueue_transaction(&tq_init); | ||
972 | |||
973 | down(&tq_init_sem); | ||
974 | up(&tq_init_sem); | ||
975 | |||
976 | if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) { | ||
977 | printk(KERN_WARNING PREFIX "Error reading config byte.\n"); | ||
978 | hp_sdc_exit(); | ||
979 | return -ENODEV; | ||
980 | } | ||
981 | hp_sdc.r11 = tq_init_seq[4]; | ||
982 | if (hp_sdc.r11 & HP_SDC_CFG_NEW) { | ||
983 | char *str; | ||
984 | printk(KERN_INFO PREFIX "New style SDC\n"); | ||
985 | tq_init_seq[1] = HP_SDC_CMD_READ_XTD; | ||
986 | tq_init.actidx = 0; | ||
987 | tq_init.idx = 1; | ||
988 | down(&tq_init_sem); | ||
989 | hp_sdc_enqueue_transaction(&tq_init); | ||
990 | down(&tq_init_sem); | ||
991 | up(&tq_init_sem); | ||
992 | if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) { | ||
993 | printk(KERN_WARNING PREFIX "Error reading extended config byte.\n"); | ||
994 | return -ENODEV; | ||
995 | } | ||
996 | hp_sdc.r7e = tq_init_seq[4]; | ||
997 | HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str) | ||
998 | printk(KERN_INFO PREFIX "Revision: %s\n", str); | ||
999 | if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) { | ||
1000 | printk(KERN_INFO PREFIX "TI SN76494 beeper present\n"); | ||
1001 | } | ||
1002 | if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) { | ||
1003 | printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n"); | ||
1004 | } | ||
1005 | printk(KERN_INFO PREFIX "Spunking the self test register to force PUP " | ||
1006 | "on next firmware reset.\n"); | ||
1007 | tq_init_seq[0] = HP_SDC_ACT_PRECMD | | ||
1008 | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; | ||
1009 | tq_init_seq[1] = HP_SDC_CMD_SET_STR; | ||
1010 | tq_init_seq[2] = 1; | ||
1011 | tq_init_seq[3] = 0; | ||
1012 | tq_init.actidx = 0; | ||
1013 | tq_init.idx = 1; | ||
1014 | tq_init.endidx = 4; | ||
1015 | down(&tq_init_sem); | ||
1016 | hp_sdc_enqueue_transaction(&tq_init); | ||
1017 | down(&tq_init_sem); | ||
1018 | up(&tq_init_sem); | ||
1019 | } | ||
1020 | else { | ||
1021 | printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", | ||
1022 | (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087"); | ||
1023 | } | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | module_init(hp_sdc_register); | ||
1029 | module_exit(hp_sdc_exit); | ||
1030 | |||
1031 | /* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64) | ||
1032 | * cycles cycles-adj time | ||
1033 | * between two consecutive mfctl(16)'s: 4 n/a 63ns | ||
1034 | * hp_sdc_spin_ibf when idle: 119 115 1.7us | ||
1035 | * gsc_writeb status register: 83 79 1.2us | ||
1036 | * IBF to clear after sending SET_IM: 6204 6006 93us | ||
1037 | * IBF to clear after sending LOAD_RT: 4467 4352 68us | ||
1038 | * IBF to clear after sending two LOAD_RTs: 18974 18859 295us | ||
1039 | * READ_T1, read status/data, IRQ, call handler: 35564 n/a 556us | ||
1040 | * cmd to ~IBF READ_T1 2nd time right after: 5158403 n/a 81ms | ||
1041 | * between IRQ received and ~IBF for above: 2578877 n/a 40ms | ||
1042 | * | ||
1043 | * Performance stats after a run of this module configuring HIL and | ||
1044 | * receiving a few mouse events: | ||
1045 | * | ||
1046 | * status in8 282508 cycles 7128 calls | ||
1047 | * status out8 8404 cycles 341 calls | ||
1048 | * data out8 1734 cycles 78 calls | ||
1049 | * isr 174324 cycles 617 calls (includes take) | ||
1050 | * take 1241 cycles 2 calls | ||
1051 | * put 1411504 cycles 6937 calls | ||
1052 | * task 1655209 cycles 6937 calls (includes put) | ||
1053 | * | ||
1054 | */ | ||
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c new file mode 100644 index 000000000000..e3c44ffae674 --- /dev/null +++ b/drivers/input/serio/hp_sdc_mlc.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /* | ||
2 | * Access to HP-HIL MLC through HP System Device Controller. | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A | ||
31 | * System Device Controller Microprocessor Firmware Theory of Operation | ||
32 | * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/hil_mlc.h> | ||
37 | #include <linux/hp_sdc.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/string.h> | ||
43 | |||
44 | #define PREFIX "HP SDC MLC: " | ||
45 | |||
46 | static hil_mlc hp_sdc_mlc; | ||
47 | |||
48 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
49 | MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines"); | ||
50 | MODULE_LICENSE("Dual BSD/GPL"); | ||
51 | |||
52 | struct hp_sdc_mlc_priv_s { | ||
53 | int emtestmode; | ||
54 | hp_sdc_transaction trans; | ||
55 | u8 tseq[16]; | ||
56 | int got5x; | ||
57 | } hp_sdc_mlc_priv; | ||
58 | |||
59 | /************************* Interrupt context ******************************/ | ||
60 | static void hp_sdc_mlc_isr (int irq, void *dev_id, | ||
61 | uint8_t status, uint8_t data) { | ||
62 | int idx; | ||
63 | hil_mlc *mlc = &hp_sdc_mlc; | ||
64 | |||
65 | write_lock(&(mlc->lock)); | ||
66 | if (mlc->icount < 0) { | ||
67 | printk(KERN_WARNING PREFIX "HIL Overflow!\n"); | ||
68 | up(&mlc->isem); | ||
69 | goto out; | ||
70 | } | ||
71 | idx = 15 - mlc->icount; | ||
72 | if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) { | ||
73 | mlc->ipacket[idx] |= data | HIL_ERR_INT; | ||
74 | mlc->icount--; | ||
75 | if (hp_sdc_mlc_priv.got5x) goto check; | ||
76 | if (!idx) goto check; | ||
77 | if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) != | ||
78 | (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) { | ||
79 | mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK; | ||
80 | mlc->ipacket[idx] |= (mlc->ipacket[idx-1] | ||
81 | & HIL_PKT_ADDR_MASK); | ||
82 | } | ||
83 | goto check; | ||
84 | } | ||
85 | /* We know status is 5X */ | ||
86 | if (data & HP_SDC_HIL_ISERR) goto err; | ||
87 | mlc->ipacket[idx] = | ||
88 | (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT; | ||
89 | hp_sdc_mlc_priv.got5x = 1; | ||
90 | goto out; | ||
91 | |||
92 | check: | ||
93 | hp_sdc_mlc_priv.got5x = 0; | ||
94 | if (mlc->imatch == 0) goto done; | ||
95 | if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) | ||
96 | && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done; | ||
97 | if (mlc->ipacket[idx] == mlc->imatch) goto done; | ||
98 | goto out; | ||
99 | |||
100 | err: | ||
101 | printk(KERN_DEBUG PREFIX "err code %x\n", data); | ||
102 | switch (data) { | ||
103 | case HP_SDC_HIL_RC_DONE: | ||
104 | printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n"); | ||
105 | break; | ||
106 | case HP_SDC_HIL_ERR: | ||
107 | mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | | ||
108 | HIL_ERR_FERR | HIL_ERR_FOF; | ||
109 | break; | ||
110 | case HP_SDC_HIL_TO: | ||
111 | mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR; | ||
112 | break; | ||
113 | case HP_SDC_HIL_RC: | ||
114 | printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n"); | ||
115 | break; | ||
116 | default: | ||
117 | printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data); | ||
118 | break; | ||
119 | } | ||
120 | /* No more data will be coming due to an error. */ | ||
121 | done: | ||
122 | tasklet_schedule(mlc->tasklet); | ||
123 | up(&(mlc->isem)); | ||
124 | out: | ||
125 | write_unlock(&(mlc->lock)); | ||
126 | } | ||
127 | |||
128 | |||
129 | /******************** Tasklet or userspace context functions ****************/ | ||
130 | |||
131 | static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) { | ||
132 | unsigned long flags; | ||
133 | struct hp_sdc_mlc_priv_s *priv; | ||
134 | int rc = 2; | ||
135 | |||
136 | priv = mlc->priv; | ||
137 | |||
138 | write_lock_irqsave(&(mlc->lock), flags); | ||
139 | |||
140 | /* Try to down the semaphore */ | ||
141 | if (down_trylock(&(mlc->isem))) { | ||
142 | struct timeval tv; | ||
143 | if (priv->emtestmode) { | ||
144 | mlc->ipacket[0] = | ||
145 | HIL_ERR_INT | (mlc->opacket & | ||
146 | (HIL_PKT_CMD | | ||
147 | HIL_PKT_ADDR_MASK | | ||
148 | HIL_PKT_DATA_MASK)); | ||
149 | mlc->icount = 14; | ||
150 | /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ | ||
151 | goto wasup; | ||
152 | } | ||
153 | do_gettimeofday(&tv); | ||
154 | tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); | ||
155 | if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) { | ||
156 | /* printk("!%i %i", | ||
157 | tv.tv_usec - mlc->instart.tv_usec, | ||
158 | mlc->intimeout); | ||
159 | */ | ||
160 | rc = 1; | ||
161 | up(&(mlc->isem)); | ||
162 | } | ||
163 | goto done; | ||
164 | } | ||
165 | wasup: | ||
166 | up(&(mlc->isem)); | ||
167 | rc = 0; | ||
168 | goto done; | ||
169 | done: | ||
170 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
171 | return rc; | ||
172 | } | ||
173 | |||
174 | static int hp_sdc_mlc_cts (hil_mlc *mlc) { | ||
175 | struct hp_sdc_mlc_priv_s *priv; | ||
176 | unsigned long flags; | ||
177 | |||
178 | priv = mlc->priv; | ||
179 | |||
180 | write_lock_irqsave(&(mlc->lock), flags); | ||
181 | |||
182 | /* Try to down the semaphores -- they should be up. */ | ||
183 | if (down_trylock(&(mlc->isem))) { | ||
184 | BUG(); | ||
185 | goto busy; | ||
186 | } | ||
187 | if (down_trylock(&(mlc->osem))) { | ||
188 | BUG(); | ||
189 | up(&(mlc->isem)); | ||
190 | goto busy; | ||
191 | } | ||
192 | up(&(mlc->isem)); | ||
193 | up(&(mlc->osem)); | ||
194 | |||
195 | if (down_trylock(&(mlc->csem))) { | ||
196 | if (priv->trans.act.semaphore != &(mlc->csem)) goto poll; | ||
197 | goto busy; | ||
198 | } | ||
199 | if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done; | ||
200 | |||
201 | poll: | ||
202 | priv->trans.act.semaphore = &(mlc->csem); | ||
203 | priv->trans.actidx = 0; | ||
204 | priv->trans.idx = 1; | ||
205 | priv->trans.endidx = 5; | ||
206 | priv->tseq[0] = | ||
207 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; | ||
208 | priv->tseq[1] = HP_SDC_CMD_READ_USE; | ||
209 | priv->tseq[2] = 1; | ||
210 | priv->tseq[3] = 0; | ||
211 | priv->tseq[4] = 0; | ||
212 | hp_sdc_enqueue_transaction(&(priv->trans)); | ||
213 | busy: | ||
214 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
215 | return 1; | ||
216 | done: | ||
217 | priv->trans.act.semaphore = &(mlc->osem); | ||
218 | up(&(mlc->csem)); | ||
219 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static void hp_sdc_mlc_out (hil_mlc *mlc) { | ||
224 | struct hp_sdc_mlc_priv_s *priv; | ||
225 | unsigned long flags; | ||
226 | |||
227 | priv = mlc->priv; | ||
228 | |||
229 | write_lock_irqsave(&(mlc->lock), flags); | ||
230 | |||
231 | /* Try to down the semaphore -- it should be up. */ | ||
232 | if (down_trylock(&(mlc->osem))) { | ||
233 | BUG(); | ||
234 | goto done; | ||
235 | } | ||
236 | |||
237 | if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control; | ||
238 | |||
239 | do_data: | ||
240 | if (priv->emtestmode) { | ||
241 | up(&(mlc->osem)); | ||
242 | goto done; | ||
243 | } | ||
244 | /* Shouldn't be sending commands when loop may be busy */ | ||
245 | if (down_trylock(&(mlc->csem))) { | ||
246 | BUG(); | ||
247 | goto done; | ||
248 | } | ||
249 | up(&(mlc->csem)); | ||
250 | |||
251 | priv->trans.actidx = 0; | ||
252 | priv->trans.idx = 1; | ||
253 | priv->trans.act.semaphore = &(mlc->osem); | ||
254 | priv->trans.endidx = 6; | ||
255 | priv->tseq[0] = | ||
256 | HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE; | ||
257 | priv->tseq[1] = 0x7; | ||
258 | priv->tseq[2] = | ||
259 | (mlc->opacket & | ||
260 | (HIL_PKT_ADDR_MASK | HIL_PKT_CMD)) | ||
261 | >> HIL_PKT_ADDR_SHIFT; | ||
262 | priv->tseq[3] = | ||
263 | (mlc->opacket & HIL_PKT_DATA_MASK) | ||
264 | >> HIL_PKT_DATA_SHIFT; | ||
265 | priv->tseq[4] = 0; /* No timeout */ | ||
266 | if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1; | ||
267 | priv->tseq[5] = HP_SDC_CMD_DO_HIL; | ||
268 | goto enqueue; | ||
269 | |||
270 | do_control: | ||
271 | priv->emtestmode = mlc->opacket & HIL_CTRL_TEST; | ||
272 | if ((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE) { | ||
273 | BUG(); /* we cannot emulate this, it should not be used. */ | ||
274 | } | ||
275 | if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only; | ||
276 | if (mlc->opacket & HIL_CTRL_APE) { | ||
277 | BUG(); /* Should not send command/data after engaging APE */ | ||
278 | goto done; | ||
279 | } | ||
280 | /* Disengaging APE this way would not be valid either since | ||
281 | * the loop must be allowed to idle. | ||
282 | * | ||
283 | * So, it works out that we really never actually send control | ||
284 | * and data when using SDC, we just send the data. | ||
285 | */ | ||
286 | goto do_data; | ||
287 | |||
288 | control_only: | ||
289 | priv->trans.actidx = 0; | ||
290 | priv->trans.idx = 1; | ||
291 | priv->trans.act.semaphore = &(mlc->osem); | ||
292 | priv->trans.endidx = 4; | ||
293 | priv->tseq[0] = | ||
294 | HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; | ||
295 | priv->tseq[1] = HP_SDC_CMD_SET_LPC; | ||
296 | priv->tseq[2] = 1; | ||
297 | // priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; | ||
298 | priv->tseq[3] = 0; | ||
299 | if (mlc->opacket & HIL_CTRL_APE) { | ||
300 | priv->tseq[3] |= HP_SDC_LPC_APE_IPF; | ||
301 | down_trylock(&(mlc->csem)); | ||
302 | } | ||
303 | enqueue: | ||
304 | hp_sdc_enqueue_transaction(&(priv->trans)); | ||
305 | done: | ||
306 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
307 | } | ||
308 | |||
309 | static int __init hp_sdc_mlc_init(void) | ||
310 | { | ||
311 | hil_mlc *mlc = &hp_sdc_mlc; | ||
312 | |||
313 | printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n"); | ||
314 | |||
315 | hp_sdc_mlc_priv.emtestmode = 0; | ||
316 | hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq; | ||
317 | hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem); | ||
318 | hp_sdc_mlc_priv.got5x = 0; | ||
319 | |||
320 | mlc->cts = &hp_sdc_mlc_cts; | ||
321 | mlc->in = &hp_sdc_mlc_in; | ||
322 | mlc->out = &hp_sdc_mlc_out; | ||
323 | |||
324 | if (hil_mlc_register(mlc)) { | ||
325 | printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n"); | ||
326 | goto err0; | ||
327 | } | ||
328 | mlc->priv = &hp_sdc_mlc_priv; | ||
329 | |||
330 | if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) { | ||
331 | printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n"); | ||
332 | goto err1; | ||
333 | } | ||
334 | return 0; | ||
335 | err1: | ||
336 | if (hil_mlc_unregister(mlc)) { | ||
337 | printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" | ||
338 | "This is bad. Could cause an oops.\n"); | ||
339 | } | ||
340 | err0: | ||
341 | return -EBUSY; | ||
342 | } | ||
343 | |||
344 | static void __exit hp_sdc_mlc_exit(void) | ||
345 | { | ||
346 | hil_mlc *mlc = &hp_sdc_mlc; | ||
347 | if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) { | ||
348 | printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n" | ||
349 | "This is bad. Could cause an oops.\n"); | ||
350 | } | ||
351 | if (hil_mlc_unregister(mlc)) { | ||
352 | printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" | ||
353 | "This is bad. Could cause an oops.\n"); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | module_init(hp_sdc_mlc_init); | ||
358 | module_exit(hp_sdc_mlc_exit); | ||
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h new file mode 100644 index 000000000000..c9e633d21d90 --- /dev/null +++ b/drivers/input/serio/i8042-io.h | |||
@@ -0,0 +1,93 @@ | |||
1 | #ifndef _I8042_IO_H | ||
2 | #define _I8042_IO_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Names. | ||
12 | */ | ||
13 | |||
14 | #define I8042_KBD_PHYS_DESC "isa0060/serio0" | ||
15 | #define I8042_AUX_PHYS_DESC "isa0060/serio1" | ||
16 | #define I8042_MUX_PHYS_DESC "isa0060/serio%d" | ||
17 | |||
18 | /* | ||
19 | * IRQs. | ||
20 | */ | ||
21 | |||
22 | #ifdef __alpha__ | ||
23 | # define I8042_KBD_IRQ 1 | ||
24 | # define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */ | ||
25 | #elif defined(__arm__) | ||
26 | /* defined in include/asm-arm/arch-xxx/irqs.h */ | ||
27 | #include <asm/irq.h> | ||
28 | #elif defined(CONFIG_SUPERH64) | ||
29 | #include <asm/irq.h> | ||
30 | #else | ||
31 | # define I8042_KBD_IRQ 1 | ||
32 | # define I8042_AUX_IRQ 12 | ||
33 | #endif | ||
34 | |||
35 | |||
36 | /* | ||
37 | * Register numbers. | ||
38 | */ | ||
39 | |||
40 | #define I8042_COMMAND_REG 0x64 | ||
41 | #define I8042_STATUS_REG 0x64 | ||
42 | #define I8042_DATA_REG 0x60 | ||
43 | |||
44 | static inline int i8042_read_data(void) | ||
45 | { | ||
46 | return inb(I8042_DATA_REG); | ||
47 | } | ||
48 | |||
49 | static inline int i8042_read_status(void) | ||
50 | { | ||
51 | return inb(I8042_STATUS_REG); | ||
52 | } | ||
53 | |||
54 | static inline void i8042_write_data(int val) | ||
55 | { | ||
56 | outb(val, I8042_DATA_REG); | ||
57 | } | ||
58 | |||
59 | static inline void i8042_write_command(int val) | ||
60 | { | ||
61 | outb(val, I8042_COMMAND_REG); | ||
62 | } | ||
63 | |||
64 | static inline int i8042_platform_init(void) | ||
65 | { | ||
66 | /* | ||
67 | * On some platforms touching the i8042 data register region can do really | ||
68 | * bad things. Because of this the region is always reserved on such boxes. | ||
69 | */ | ||
70 | #if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64) | ||
71 | if (!request_region(I8042_DATA_REG, 16, "i8042")) | ||
72 | return -1; | ||
73 | #endif | ||
74 | |||
75 | i8042_reset = 1; | ||
76 | |||
77 | #if defined(CONFIG_PPC64) | ||
78 | if (check_legacy_ioport(I8042_DATA_REG)) | ||
79 | return -1; | ||
80 | if (!request_region(I8042_DATA_REG, 16, "i8042")) | ||
81 | return -1; | ||
82 | #endif | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static inline void i8042_platform_exit(void) | ||
87 | { | ||
88 | #if !defined(__sh__) && !defined(__alpha__) && !defined(CONFIG_PPC64) | ||
89 | release_region(I8042_DATA_REG, 16); | ||
90 | #endif | ||
91 | } | ||
92 | |||
93 | #endif /* _I8042_IO_H */ | ||
diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h new file mode 100644 index 000000000000..863b9c95fbb8 --- /dev/null +++ b/drivers/input/serio/i8042-ip22io.h | |||
@@ -0,0 +1,76 @@ | |||
1 | #ifndef _I8042_IP22_H | ||
2 | #define _I8042_IP22_H | ||
3 | |||
4 | #include <asm/sgi/ioc.h> | ||
5 | #include <asm/sgi/ip22.h> | ||
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 | * Names. | ||
15 | */ | ||
16 | |||
17 | #define I8042_KBD_PHYS_DESC "hpc3ps2/serio0" | ||
18 | #define I8042_AUX_PHYS_DESC "hpc3ps2/serio1" | ||
19 | #define I8042_MUX_PHYS_DESC "hpc3ps2/serio%d" | ||
20 | |||
21 | /* | ||
22 | * IRQs. | ||
23 | */ | ||
24 | |||
25 | #define I8042_KBD_IRQ SGI_KEYBD_IRQ | ||
26 | #define I8042_AUX_IRQ SGI_KEYBD_IRQ | ||
27 | |||
28 | /* | ||
29 | * Register numbers. | ||
30 | */ | ||
31 | |||
32 | #define I8042_COMMAND_REG ((unsigned long)&sgioc->kbdmouse.command) | ||
33 | #define I8042_STATUS_REG ((unsigned long)&sgioc->kbdmouse.command) | ||
34 | #define I8042_DATA_REG ((unsigned long)&sgioc->kbdmouse.data) | ||
35 | |||
36 | static inline int i8042_read_data(void) | ||
37 | { | ||
38 | return sgioc->kbdmouse.data; | ||
39 | } | ||
40 | |||
41 | static inline int i8042_read_status(void) | ||
42 | { | ||
43 | return sgioc->kbdmouse.command; | ||
44 | } | ||
45 | |||
46 | static inline void i8042_write_data(int val) | ||
47 | { | ||
48 | sgioc->kbdmouse.data = val; | ||
49 | } | ||
50 | |||
51 | static inline void i8042_write_command(int val) | ||
52 | { | ||
53 | sgioc->kbdmouse.command = val; | ||
54 | } | ||
55 | |||
56 | static inline int i8042_platform_init(void) | ||
57 | { | ||
58 | #if 0 | ||
59 | /* XXX sgi_kh is a virtual address */ | ||
60 | if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) | ||
61 | return 1; | ||
62 | #endif | ||
63 | |||
64 | i8042_reset = 1; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline void i8042_platform_exit(void) | ||
70 | { | ||
71 | #if 0 | ||
72 | release_mem_region(JAZZ_KEYBOARD_ADDRESS, sizeof(struct hpc_keyb)); | ||
73 | #endif | ||
74 | } | ||
75 | |||
76 | #endif /* _I8042_IP22_H */ | ||
diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h new file mode 100644 index 000000000000..5c20ab131488 --- /dev/null +++ b/drivers/input/serio/i8042-jazzio.h | |||
@@ -0,0 +1,69 @@ | |||
1 | #ifndef _I8042_JAZZ_H | ||
2 | #define _I8042_JAZZ_H | ||
3 | |||
4 | #include <asm/jazz.h> | ||
5 | |||
6 | /* | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * Names. | ||
14 | */ | ||
15 | |||
16 | #define I8042_KBD_PHYS_DESC "R4030/serio0" | ||
17 | #define I8042_AUX_PHYS_DESC "R4030/serio1" | ||
18 | #define I8042_MUX_PHYS_DESC "R4030/serio%d" | ||
19 | |||
20 | /* | ||
21 | * IRQs. | ||
22 | */ | ||
23 | |||
24 | #define I8042_KBD_IRQ JAZZ_KEYBOARD_IRQ | ||
25 | #define I8042_AUX_IRQ JAZZ_MOUSE_IRQ | ||
26 | |||
27 | #define I8042_COMMAND_REG ((unsigned long)&jazz_kh->command) | ||
28 | #define I8042_STATUS_REG ((unsigned long)&jazz_kh->command) | ||
29 | #define I8042_DATA_REG ((unsigned long)&jazz_kh->data) | ||
30 | |||
31 | static inline int i8042_read_data(void) | ||
32 | { | ||
33 | return jazz_kh->data; | ||
34 | } | ||
35 | |||
36 | static inline int i8042_read_status(void) | ||
37 | { | ||
38 | return jazz_kh->command; | ||
39 | } | ||
40 | |||
41 | static inline void i8042_write_data(int val) | ||
42 | { | ||
43 | jazz_kh->data = val; | ||
44 | } | ||
45 | |||
46 | static inline void i8042_write_command(int val) | ||
47 | { | ||
48 | jazz_kh->command = val; | ||
49 | } | ||
50 | |||
51 | static inline int i8042_platform_init(void) | ||
52 | { | ||
53 | #if 0 | ||
54 | /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ | ||
55 | if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) | ||
56 | return 1; | ||
57 | #endif | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static inline void i8042_platform_exit(void) | ||
63 | { | ||
64 | #if 0 | ||
65 | release_mem_region(JAZZ_KEYBOARD_ADDRESS, 2); | ||
66 | #endif | ||
67 | } | ||
68 | |||
69 | #endif /* _I8042_JAZZ_H */ | ||
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h new file mode 100644 index 000000000000..2906e1b60c04 --- /dev/null +++ b/drivers/input/serio/i8042-ppcio.h | |||
@@ -0,0 +1,136 @@ | |||
1 | #ifndef _I8042_PPCIO_H | ||
2 | #define _I8042_PPCIO_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #if defined(CONFIG_WALNUT) | ||
11 | |||
12 | #define I8042_KBD_IRQ 25 | ||
13 | #define I8042_AUX_IRQ 26 | ||
14 | |||
15 | #define I8042_KBD_PHYS_DESC "walnutps2/serio0" | ||
16 | #define I8042_AUX_PHYS_DESC "walnutps2/serio1" | ||
17 | #define I8042_MUX_PHYS_DESC "walnutps2/serio%d" | ||
18 | |||
19 | extern void *kb_cs; | ||
20 | extern void *kb_data; | ||
21 | |||
22 | #define I8042_COMMAND_REG (*(int *)kb_cs) | ||
23 | #define I8042_DATA_REG (*(int *)kb_data) | ||
24 | |||
25 | static inline int i8042_read_data(void) | ||
26 | { | ||
27 | return readb(kb_data); | ||
28 | } | ||
29 | |||
30 | static inline int i8042_read_status(void) | ||
31 | { | ||
32 | return readb(kb_cs); | ||
33 | } | ||
34 | |||
35 | static inline void i8042_write_data(int val) | ||
36 | { | ||
37 | writeb(val, kb_data); | ||
38 | } | ||
39 | |||
40 | static inline void i8042_write_command(int val) | ||
41 | { | ||
42 | writeb(val, kb_cs); | ||
43 | } | ||
44 | |||
45 | static inline int i8042_platform_init(void) | ||
46 | { | ||
47 | i8042_reset = 1; | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static inline void i8042_platform_exit(void) | ||
52 | { | ||
53 | } | ||
54 | |||
55 | #elif defined(CONFIG_SPRUCE) | ||
56 | |||
57 | #define I8042_KBD_IRQ 22 | ||
58 | #define I8042_AUX_IRQ 21 | ||
59 | |||
60 | #define I8042_KBD_PHYS_DESC "spruceps2/serio0" | ||
61 | #define I8042_AUX_PHYS_DESC "spruceps2/serio1" | ||
62 | #define I8042_MUX_PHYS_DESC "spruceps2/serio%d" | ||
63 | |||
64 | #define I8042_COMMAND_REG 0xff810000 | ||
65 | #define I8042_DATA_REG 0xff810001 | ||
66 | |||
67 | static inline int i8042_read_data(void) | ||
68 | { | ||
69 | unsigned long kbd_data; | ||
70 | |||
71 | __raw_writel(0x00000088, 0xff500008); | ||
72 | eieio(); | ||
73 | |||
74 | __raw_writel(0x03000000, 0xff50000c); | ||
75 | eieio(); | ||
76 | |||
77 | asm volatile("lis 7,0xff88 \n\ | ||
78 | lswi 6,7,0x8 \n\ | ||
79 | mr %0,6" | ||
80 | : "=r" (kbd_data) :: "6", "7"); | ||
81 | |||
82 | __raw_writel(0x00000000, 0xff50000c); | ||
83 | eieio(); | ||
84 | |||
85 | return (unsigned char)(kbd_data >> 24); | ||
86 | } | ||
87 | |||
88 | static inline int i8042_read_status(void) | ||
89 | { | ||
90 | unsigned long kbd_status; | ||
91 | |||
92 | __raw_writel(0x00000088, 0xff500008); | ||
93 | eieio(); | ||
94 | |||
95 | __raw_writel(0x03000000, 0xff50000c); | ||
96 | eieio(); | ||
97 | |||
98 | asm volatile("lis 7,0xff88 \n\ | ||
99 | ori 7,7,0x8 \n\ | ||
100 | lswi 6,7,0x8 \n\ | ||
101 | mr %0,6" | ||
102 | : "=r" (kbd_status) :: "6", "7"); | ||
103 | |||
104 | __raw_writel(0x00000000, 0xff50000c); | ||
105 | eieio(); | ||
106 | |||
107 | return (unsigned char)(kbd_status >> 24); | ||
108 | } | ||
109 | |||
110 | static inline void i8042_write_data(int val) | ||
111 | { | ||
112 | *((unsigned char *)0xff810000) = (char)val; | ||
113 | } | ||
114 | |||
115 | static inline void i8042_write_command(int val) | ||
116 | { | ||
117 | *((unsigned char *)0xff810001) = (char)val; | ||
118 | } | ||
119 | |||
120 | static inline int i8042_platform_init(void) | ||
121 | { | ||
122 | i8042_reset = 1; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static inline void i8042_platform_exit(void) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | #else | ||
131 | |||
132 | #include "i8042-io.h" | ||
133 | |||
134 | #endif | ||
135 | |||
136 | #endif /* _I8042_PPCIO_H */ | ||
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h new file mode 100644 index 000000000000..da2a19812485 --- /dev/null +++ b/drivers/input/serio/i8042-sparcio.h | |||
@@ -0,0 +1,116 @@ | |||
1 | #ifndef _I8042_SPARCIO_H | ||
2 | #define _I8042_SPARCIO_H | ||
3 | |||
4 | #include <linux/config.h> | ||
5 | #include <asm/io.h> | ||
6 | |||
7 | #ifdef CONFIG_PCI | ||
8 | #include <asm/oplib.h> | ||
9 | #include <asm/ebus.h> | ||
10 | #endif | ||
11 | |||
12 | static int i8042_kbd_irq = -1; | ||
13 | static int i8042_aux_irq = -1; | ||
14 | #define I8042_KBD_IRQ i8042_kbd_irq | ||
15 | #define I8042_AUX_IRQ i8042_aux_irq | ||
16 | |||
17 | #define I8042_KBD_PHYS_DESC "sparcps2/serio0" | ||
18 | #define I8042_AUX_PHYS_DESC "sparcps2/serio1" | ||
19 | #define I8042_MUX_PHYS_DESC "sparcps2/serio%d" | ||
20 | |||
21 | static void __iomem *kbd_iobase; | ||
22 | |||
23 | #define I8042_COMMAND_REG (kbd_iobase + 0x64UL) | ||
24 | #define I8042_DATA_REG (kbd_iobase + 0x60UL) | ||
25 | |||
26 | static inline int i8042_read_data(void) | ||
27 | { | ||
28 | return readb(kbd_iobase + 0x60UL); | ||
29 | } | ||
30 | |||
31 | static inline int i8042_read_status(void) | ||
32 | { | ||
33 | return readb(kbd_iobase + 0x64UL); | ||
34 | } | ||
35 | |||
36 | static inline void i8042_write_data(int val) | ||
37 | { | ||
38 | writeb(val, kbd_iobase + 0x60UL); | ||
39 | } | ||
40 | |||
41 | static inline void i8042_write_command(int val) | ||
42 | { | ||
43 | writeb(val, kbd_iobase + 0x64UL); | ||
44 | } | ||
45 | |||
46 | #define OBP_PS2KBD_NAME1 "kb_ps2" | ||
47 | #define OBP_PS2KBD_NAME2 "keyboard" | ||
48 | #define OBP_PS2MS_NAME1 "kdmouse" | ||
49 | #define OBP_PS2MS_NAME2 "mouse" | ||
50 | |||
51 | static int i8042_platform_init(void) | ||
52 | { | ||
53 | #ifndef CONFIG_PCI | ||
54 | return -1; | ||
55 | #else | ||
56 | char prop[128]; | ||
57 | int len; | ||
58 | |||
59 | len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); | ||
60 | if (len < 0) { | ||
61 | printk("i8042: Cannot get name property of root OBP node.\n"); | ||
62 | return -1; | ||
63 | } | ||
64 | if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { | ||
65 | /* Hardcoded values for MrCoffee. */ | ||
66 | i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; | ||
67 | kbd_iobase = ioremap(0x71300060, 8); | ||
68 | if (!kbd_iobase) | ||
69 | return -1; | ||
70 | } else { | ||
71 | struct linux_ebus *ebus; | ||
72 | struct linux_ebus_device *edev; | ||
73 | struct linux_ebus_child *child; | ||
74 | |||
75 | for_each_ebus(ebus) { | ||
76 | for_each_ebusdev(edev, ebus) { | ||
77 | if (!strcmp(edev->prom_name, "8042")) | ||
78 | goto edev_found; | ||
79 | } | ||
80 | } | ||
81 | return -1; | ||
82 | |||
83 | edev_found: | ||
84 | for_each_edevchild(edev, child) { | ||
85 | if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) || | ||
86 | !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) { | ||
87 | i8042_kbd_irq = child->irqs[0]; | ||
88 | kbd_iobase = | ||
89 | ioremap(child->resource[0].start, 8); | ||
90 | } | ||
91 | if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) || | ||
92 | !strcmp(child->prom_name, OBP_PS2MS_NAME2)) | ||
93 | i8042_aux_irq = child->irqs[0]; | ||
94 | } | ||
95 | if (i8042_kbd_irq == -1 || | ||
96 | i8042_aux_irq == -1) { | ||
97 | printk("i8042: Error, 8042 device lacks both kbd and " | ||
98 | "mouse nodes.\n"); | ||
99 | return -1; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | i8042_reset = 1; | ||
104 | |||
105 | return 0; | ||
106 | #endif /* CONFIG_PCI */ | ||
107 | } | ||
108 | |||
109 | static inline void i8042_platform_exit(void) | ||
110 | { | ||
111 | #ifdef CONFIG_PCI | ||
112 | iounmap(kbd_iobase); | ||
113 | #endif | ||
114 | } | ||
115 | |||
116 | #endif /* _I8042_SPARCIO_H */ | ||
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h new file mode 100644 index 000000000000..f64867808fea --- /dev/null +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
@@ -0,0 +1,333 @@ | |||
1 | #ifndef _I8042_X86IA64IO_H | ||
2 | #define _I8042_X86IA64IO_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Names. | ||
12 | */ | ||
13 | |||
14 | #define I8042_KBD_PHYS_DESC "isa0060/serio0" | ||
15 | #define I8042_AUX_PHYS_DESC "isa0060/serio1" | ||
16 | #define I8042_MUX_PHYS_DESC "isa0060/serio%d" | ||
17 | |||
18 | /* | ||
19 | * IRQs. | ||
20 | */ | ||
21 | |||
22 | #if defined(__ia64__) | ||
23 | # define I8042_MAP_IRQ(x) isa_irq_to_vector((x)) | ||
24 | #else | ||
25 | # define I8042_MAP_IRQ(x) (x) | ||
26 | #endif | ||
27 | |||
28 | #define I8042_KBD_IRQ i8042_kbd_irq | ||
29 | #define I8042_AUX_IRQ i8042_aux_irq | ||
30 | |||
31 | static int i8042_kbd_irq; | ||
32 | static int i8042_aux_irq; | ||
33 | |||
34 | /* | ||
35 | * Register numbers. | ||
36 | */ | ||
37 | |||
38 | #define I8042_COMMAND_REG i8042_command_reg | ||
39 | #define I8042_STATUS_REG i8042_command_reg | ||
40 | #define I8042_DATA_REG i8042_data_reg | ||
41 | |||
42 | static int i8042_command_reg = 0x64; | ||
43 | static int i8042_data_reg = 0x60; | ||
44 | |||
45 | |||
46 | static inline int i8042_read_data(void) | ||
47 | { | ||
48 | return inb(I8042_DATA_REG); | ||
49 | } | ||
50 | |||
51 | static inline int i8042_read_status(void) | ||
52 | { | ||
53 | return inb(I8042_STATUS_REG); | ||
54 | } | ||
55 | |||
56 | static inline void i8042_write_data(int val) | ||
57 | { | ||
58 | outb(val, I8042_DATA_REG); | ||
59 | } | ||
60 | |||
61 | static inline void i8042_write_command(int val) | ||
62 | { | ||
63 | outb(val, I8042_COMMAND_REG); | ||
64 | } | ||
65 | |||
66 | #if defined(__i386__) | ||
67 | |||
68 | #include <linux/dmi.h> | ||
69 | |||
70 | static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { | ||
71 | { | ||
72 | .ident = "Compaq Proliant 8500", | ||
73 | .matches = { | ||
74 | DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), | ||
75 | DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), | ||
76 | DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), | ||
77 | }, | ||
78 | }, | ||
79 | { | ||
80 | .ident = "Compaq Proliant DL760", | ||
81 | .matches = { | ||
82 | DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), | ||
83 | DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), | ||
84 | DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), | ||
85 | }, | ||
86 | }, | ||
87 | { } | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * Some Fujitsu notebooks are ahving trouble with touhcpads if | ||
92 | * active multiplexing mode is activated. Luckily they don't have | ||
93 | * external PS/2 ports so we can safely disable it. | ||
94 | */ | ||
95 | static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { | ||
96 | { | ||
97 | .ident = "Fujitsu Lifebook P7010/P7010D", | ||
98 | .matches = { | ||
99 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
100 | DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), | ||
101 | }, | ||
102 | }, | ||
103 | { | ||
104 | .ident = "Fujitsu Lifebook P5020D", | ||
105 | .matches = { | ||
106 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
107 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), | ||
108 | }, | ||
109 | }, | ||
110 | { | ||
111 | .ident = "Fujitsu Lifebook S2000", | ||
112 | .matches = { | ||
113 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
114 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), | ||
115 | }, | ||
116 | }, | ||
117 | { | ||
118 | .ident = "Fujitsu T70H", | ||
119 | .matches = { | ||
120 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
121 | DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), | ||
122 | }, | ||
123 | }, | ||
124 | { } | ||
125 | }; | ||
126 | |||
127 | |||
128 | |||
129 | #endif | ||
130 | |||
131 | |||
132 | #ifdef CONFIG_PNP | ||
133 | #include <linux/pnp.h> | ||
134 | |||
135 | static int i8042_pnp_kbd_registered; | ||
136 | static int i8042_pnp_aux_registered; | ||
137 | |||
138 | static int i8042_pnp_command_reg; | ||
139 | static int i8042_pnp_data_reg; | ||
140 | static int i8042_pnp_kbd_irq; | ||
141 | static int i8042_pnp_aux_irq; | ||
142 | |||
143 | static char i8042_pnp_kbd_name[32]; | ||
144 | static char i8042_pnp_aux_name[32]; | ||
145 | |||
146 | static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *did) | ||
147 | { | ||
148 | if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1) | ||
149 | i8042_pnp_data_reg = pnp_port_start(dev,0); | ||
150 | |||
151 | if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1) | ||
152 | i8042_pnp_command_reg = pnp_port_start(dev, 1); | ||
153 | |||
154 | if (pnp_irq_valid(dev,0)) | ||
155 | i8042_pnp_kbd_irq = pnp_irq(dev, 0); | ||
156 | |||
157 | strncpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name)); | ||
158 | if (strlen(pnp_dev_name(dev))) { | ||
159 | strncat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name)); | ||
160 | strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name)); | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *did) | ||
167 | { | ||
168 | if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1) | ||
169 | i8042_pnp_data_reg = pnp_port_start(dev,0); | ||
170 | |||
171 | if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1) | ||
172 | i8042_pnp_command_reg = pnp_port_start(dev, 1); | ||
173 | |||
174 | if (pnp_irq_valid(dev, 0)) | ||
175 | i8042_pnp_aux_irq = pnp_irq(dev, 0); | ||
176 | |||
177 | strncpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name)); | ||
178 | if (strlen(pnp_dev_name(dev))) { | ||
179 | strncat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name)); | ||
180 | strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name)); | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static struct pnp_device_id pnp_kbd_devids[] = { | ||
187 | { .id = "PNP0303", .driver_data = 0 }, | ||
188 | { .id = "PNP030b", .driver_data = 0 }, | ||
189 | { .id = "", }, | ||
190 | }; | ||
191 | |||
192 | static struct pnp_driver i8042_pnp_kbd_driver = { | ||
193 | .name = "i8042 kbd", | ||
194 | .id_table = pnp_kbd_devids, | ||
195 | .probe = i8042_pnp_kbd_probe, | ||
196 | }; | ||
197 | |||
198 | static struct pnp_device_id pnp_aux_devids[] = { | ||
199 | { .id = "PNP0f03", .driver_data = 0 }, | ||
200 | { .id = "PNP0f0b", .driver_data = 0 }, | ||
201 | { .id = "PNP0f0e", .driver_data = 0 }, | ||
202 | { .id = "PNP0f12", .driver_data = 0 }, | ||
203 | { .id = "PNP0f13", .driver_data = 0 }, | ||
204 | { .id = "PNP0f19", .driver_data = 0 }, | ||
205 | { .id = "PNP0f1c", .driver_data = 0 }, | ||
206 | { .id = "SYN0801", .driver_data = 0 }, | ||
207 | { .id = "", }, | ||
208 | }; | ||
209 | |||
210 | static struct pnp_driver i8042_pnp_aux_driver = { | ||
211 | .name = "i8042 aux", | ||
212 | .id_table = pnp_aux_devids, | ||
213 | .probe = i8042_pnp_aux_probe, | ||
214 | }; | ||
215 | |||
216 | static void i8042_pnp_exit(void) | ||
217 | { | ||
218 | if (i8042_pnp_kbd_registered) | ||
219 | pnp_unregister_driver(&i8042_pnp_kbd_driver); | ||
220 | |||
221 | if (i8042_pnp_aux_registered) | ||
222 | pnp_unregister_driver(&i8042_pnp_aux_driver); | ||
223 | } | ||
224 | |||
225 | static int i8042_pnp_init(void) | ||
226 | { | ||
227 | int result_kbd, result_aux; | ||
228 | |||
229 | if (i8042_nopnp) { | ||
230 | printk("i8042: PNP detection disabled\n"); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0) | ||
235 | i8042_pnp_kbd_registered = 1; | ||
236 | if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0) | ||
237 | i8042_pnp_aux_registered = 1; | ||
238 | |||
239 | if (result_kbd <= 0 && result_aux <= 0) { | ||
240 | i8042_pnp_exit(); | ||
241 | #if defined(__ia64__) | ||
242 | return -ENODEV; | ||
243 | #else | ||
244 | printk(KERN_WARNING "PNP: No PS/2 controller found. Probing ports directly.\n"); | ||
245 | return 0; | ||
246 | #endif | ||
247 | } | ||
248 | |||
249 | if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) && | ||
250 | i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) { | ||
251 | printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n", | ||
252 | i8042_pnp_data_reg, i8042_data_reg); | ||
253 | i8042_pnp_data_reg = i8042_data_reg; | ||
254 | } | ||
255 | |||
256 | if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) && | ||
257 | i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) { | ||
258 | printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n", | ||
259 | i8042_pnp_command_reg, i8042_command_reg); | ||
260 | i8042_pnp_command_reg = i8042_command_reg; | ||
261 | } | ||
262 | |||
263 | if (!i8042_pnp_kbd_irq) { | ||
264 | printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq); | ||
265 | i8042_pnp_kbd_irq = i8042_kbd_irq; | ||
266 | } | ||
267 | |||
268 | if (result_aux > 0 && !i8042_pnp_aux_irq) { | ||
269 | printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq); | ||
270 | i8042_pnp_aux_irq = i8042_aux_irq; | ||
271 | } | ||
272 | |||
273 | #if defined(__ia64__) | ||
274 | if (result_aux <= 0) | ||
275 | i8042_noaux = 1; | ||
276 | #endif | ||
277 | |||
278 | i8042_data_reg = i8042_pnp_data_reg; | ||
279 | i8042_command_reg = i8042_pnp_command_reg; | ||
280 | i8042_kbd_irq = i8042_pnp_kbd_irq; | ||
281 | i8042_aux_irq = i8042_pnp_aux_irq; | ||
282 | |||
283 | printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n", | ||
284 | i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name, | ||
285 | i8042_data_reg, i8042_command_reg, i8042_kbd_irq, | ||
286 | (result_aux > 0) ? "," : "", i8042_aux_irq); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | #endif | ||
292 | |||
293 | static inline int i8042_platform_init(void) | ||
294 | { | ||
295 | /* | ||
296 | * On ix86 platforms touching the i8042 data register region can do really | ||
297 | * bad things. Because of this the region is always reserved on ix86 boxes. | ||
298 | * | ||
299 | * if (!request_region(I8042_DATA_REG, 16, "i8042")) | ||
300 | * return -1; | ||
301 | */ | ||
302 | |||
303 | i8042_kbd_irq = I8042_MAP_IRQ(1); | ||
304 | i8042_aux_irq = I8042_MAP_IRQ(12); | ||
305 | |||
306 | #ifdef CONFIG_PNP | ||
307 | if (i8042_pnp_init()) | ||
308 | return -1; | ||
309 | #endif | ||
310 | |||
311 | #if defined(__ia64__) | ||
312 | i8042_reset = 1; | ||
313 | #endif | ||
314 | |||
315 | #if defined(__i386__) | ||
316 | if (dmi_check_system(i8042_dmi_noloop_table)) | ||
317 | i8042_noloop = 1; | ||
318 | |||
319 | if (dmi_check_system(i8042_dmi_nomux_table)) | ||
320 | i8042_nomux = 1; | ||
321 | #endif | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static inline void i8042_platform_exit(void) | ||
327 | { | ||
328 | #ifdef CONFIG_PNP | ||
329 | i8042_pnp_exit(); | ||
330 | #endif | ||
331 | } | ||
332 | |||
333 | #endif /* _I8042_X86IA64IO_H */ | ||
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c new file mode 100644 index 000000000000..8e63e464d361 --- /dev/null +++ b/drivers/input/serio/i8042.c | |||
@@ -0,0 +1,1116 @@ | |||
1 | /* | ||
2 | * i8042 keyboard and mouse controller driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 1999-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 | #include <linux/delay.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/serio.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/rcupdate.h> | ||
23 | |||
24 | #include <asm/io.h> | ||
25 | |||
26 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | ||
27 | MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | static unsigned int i8042_noaux; | ||
31 | module_param_named(noaux, i8042_noaux, bool, 0); | ||
32 | MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); | ||
33 | |||
34 | static unsigned int i8042_nomux; | ||
35 | module_param_named(nomux, i8042_nomux, bool, 0); | ||
36 | MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present."); | ||
37 | |||
38 | static unsigned int i8042_unlock; | ||
39 | module_param_named(unlock, i8042_unlock, bool, 0); | ||
40 | MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); | ||
41 | |||
42 | static unsigned int i8042_reset; | ||
43 | module_param_named(reset, i8042_reset, bool, 0); | ||
44 | MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); | ||
45 | |||
46 | static unsigned int i8042_direct; | ||
47 | module_param_named(direct, i8042_direct, bool, 0); | ||
48 | MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); | ||
49 | |||
50 | static unsigned int i8042_dumbkbd; | ||
51 | module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); | ||
52 | MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); | ||
53 | |||
54 | static unsigned int i8042_noloop; | ||
55 | module_param_named(noloop, i8042_noloop, bool, 0); | ||
56 | MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); | ||
57 | |||
58 | static unsigned int i8042_blink_frequency = 500; | ||
59 | module_param_named(panicblink, i8042_blink_frequency, uint, 0600); | ||
60 | MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); | ||
61 | |||
62 | #ifdef CONFIG_PNP | ||
63 | static int i8042_nopnp; | ||
64 | module_param_named(nopnp, i8042_nopnp, bool, 0); | ||
65 | MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); | ||
66 | #endif | ||
67 | |||
68 | #define DEBUG | ||
69 | #ifdef DEBUG | ||
70 | static int i8042_debug; | ||
71 | module_param_named(debug, i8042_debug, bool, 0600); | ||
72 | MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); | ||
73 | #endif | ||
74 | |||
75 | __obsolete_setup("i8042_noaux"); | ||
76 | __obsolete_setup("i8042_nomux"); | ||
77 | __obsolete_setup("i8042_unlock"); | ||
78 | __obsolete_setup("i8042_reset"); | ||
79 | __obsolete_setup("i8042_direct"); | ||
80 | __obsolete_setup("i8042_dumbkbd"); | ||
81 | |||
82 | #include "i8042.h" | ||
83 | |||
84 | static DEFINE_SPINLOCK(i8042_lock); | ||
85 | |||
86 | struct i8042_port { | ||
87 | struct serio *serio; | ||
88 | int irq; | ||
89 | unsigned char disable; | ||
90 | unsigned char irqen; | ||
91 | unsigned char exists; | ||
92 | signed char mux; | ||
93 | char name[8]; | ||
94 | }; | ||
95 | |||
96 | #define I8042_KBD_PORT_NO 0 | ||
97 | #define I8042_AUX_PORT_NO 1 | ||
98 | #define I8042_MUX_PORT_NO 2 | ||
99 | #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) | ||
100 | static struct i8042_port i8042_ports[I8042_NUM_PORTS] = { | ||
101 | { | ||
102 | .disable = I8042_CTR_KBDDIS, | ||
103 | .irqen = I8042_CTR_KBDINT, | ||
104 | .mux = -1, | ||
105 | .name = "KBD", | ||
106 | }, | ||
107 | { | ||
108 | .disable = I8042_CTR_AUXDIS, | ||
109 | .irqen = I8042_CTR_AUXINT, | ||
110 | .mux = -1, | ||
111 | .name = "AUX", | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | static unsigned char i8042_initial_ctr; | ||
116 | static unsigned char i8042_ctr; | ||
117 | static unsigned char i8042_mux_open; | ||
118 | static unsigned char i8042_mux_present; | ||
119 | static struct timer_list i8042_timer; | ||
120 | static struct platform_device *i8042_platform_device; | ||
121 | |||
122 | |||
123 | /* | ||
124 | * Shared IRQ's require a device pointer, but this driver doesn't support | ||
125 | * multiple devices | ||
126 | */ | ||
127 | #define i8042_request_irq_cookie (&i8042_timer) | ||
128 | |||
129 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
130 | |||
131 | /* | ||
132 | * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to | ||
133 | * be ready for reading values from it / writing values to it. | ||
134 | * Called always with i8042_lock held. | ||
135 | */ | ||
136 | |||
137 | static int i8042_wait_read(void) | ||
138 | { | ||
139 | int i = 0; | ||
140 | while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { | ||
141 | udelay(50); | ||
142 | i++; | ||
143 | } | ||
144 | return -(i == I8042_CTL_TIMEOUT); | ||
145 | } | ||
146 | |||
147 | static int i8042_wait_write(void) | ||
148 | { | ||
149 | int i = 0; | ||
150 | while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { | ||
151 | udelay(50); | ||
152 | i++; | ||
153 | } | ||
154 | return -(i == I8042_CTL_TIMEOUT); | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * i8042_flush() flushes all data that may be in the keyboard and mouse buffers | ||
159 | * of the i8042 down the toilet. | ||
160 | */ | ||
161 | |||
162 | static int i8042_flush(void) | ||
163 | { | ||
164 | unsigned long flags; | ||
165 | unsigned char data, str; | ||
166 | int i = 0; | ||
167 | |||
168 | spin_lock_irqsave(&i8042_lock, flags); | ||
169 | |||
170 | while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { | ||
171 | udelay(50); | ||
172 | data = i8042_read_data(); | ||
173 | i++; | ||
174 | dbg("%02x <- i8042 (flush, %s)", data, | ||
175 | str & I8042_STR_AUXDATA ? "aux" : "kbd"); | ||
176 | } | ||
177 | |||
178 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
179 | |||
180 | return i; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * i8042_command() executes a command on the i8042. It also sends the input | ||
185 | * parameter(s) of the commands to it, and receives the output value(s). The | ||
186 | * parameters are to be stored in the param array, and the output is placed | ||
187 | * into the same array. The number of the parameters and output values is | ||
188 | * encoded in bits 8-11 of the command number. | ||
189 | */ | ||
190 | |||
191 | static int i8042_command(unsigned char *param, int command) | ||
192 | { | ||
193 | unsigned long flags; | ||
194 | int retval = 0, i = 0; | ||
195 | |||
196 | if (i8042_noloop && command == I8042_CMD_AUX_LOOP) | ||
197 | return -1; | ||
198 | |||
199 | spin_lock_irqsave(&i8042_lock, flags); | ||
200 | |||
201 | retval = i8042_wait_write(); | ||
202 | if (!retval) { | ||
203 | dbg("%02x -> i8042 (command)", command & 0xff); | ||
204 | i8042_write_command(command & 0xff); | ||
205 | } | ||
206 | |||
207 | if (!retval) | ||
208 | for (i = 0; i < ((command >> 12) & 0xf); i++) { | ||
209 | if ((retval = i8042_wait_write())) break; | ||
210 | dbg("%02x -> i8042 (parameter)", param[i]); | ||
211 | i8042_write_data(param[i]); | ||
212 | } | ||
213 | |||
214 | if (!retval) | ||
215 | for (i = 0; i < ((command >> 8) & 0xf); i++) { | ||
216 | if ((retval = i8042_wait_read())) break; | ||
217 | if (i8042_read_status() & I8042_STR_AUXDATA) | ||
218 | param[i] = ~i8042_read_data(); | ||
219 | else | ||
220 | param[i] = i8042_read_data(); | ||
221 | dbg("%02x <- i8042 (return)", param[i]); | ||
222 | } | ||
223 | |||
224 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
225 | |||
226 | if (retval) | ||
227 | dbg(" -- i8042 (timeout)"); | ||
228 | |||
229 | return retval; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * i8042_kbd_write() sends a byte out through the keyboard interface. | ||
234 | */ | ||
235 | |||
236 | static int i8042_kbd_write(struct serio *port, unsigned char c) | ||
237 | { | ||
238 | unsigned long flags; | ||
239 | int retval = 0; | ||
240 | |||
241 | spin_lock_irqsave(&i8042_lock, flags); | ||
242 | |||
243 | if(!(retval = i8042_wait_write())) { | ||
244 | dbg("%02x -> i8042 (kbd-data)", c); | ||
245 | i8042_write_data(c); | ||
246 | } | ||
247 | |||
248 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
249 | |||
250 | return retval; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * i8042_aux_write() sends a byte out through the aux interface. | ||
255 | */ | ||
256 | |||
257 | static int i8042_aux_write(struct serio *serio, unsigned char c) | ||
258 | { | ||
259 | struct i8042_port *port = serio->port_data; | ||
260 | int retval; | ||
261 | |||
262 | /* | ||
263 | * Send the byte out. | ||
264 | */ | ||
265 | |||
266 | if (port->mux == -1) | ||
267 | retval = i8042_command(&c, I8042_CMD_AUX_SEND); | ||
268 | else | ||
269 | retval = i8042_command(&c, I8042_CMD_MUX_SEND + port->mux); | ||
270 | |||
271 | /* | ||
272 | * Make sure the interrupt happens and the character is received even | ||
273 | * in the case the IRQ isn't wired, so that we can receive further | ||
274 | * characters later. | ||
275 | */ | ||
276 | |||
277 | i8042_interrupt(0, NULL, NULL); | ||
278 | return retval; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * i8042_activate_port() enables port on a chip. | ||
283 | */ | ||
284 | |||
285 | static int i8042_activate_port(struct i8042_port *port) | ||
286 | { | ||
287 | if (!port->serio) | ||
288 | return -1; | ||
289 | |||
290 | i8042_flush(); | ||
291 | |||
292 | /* | ||
293 | * Enable port again here because it is disabled if we are | ||
294 | * resuming (normally it is enabled already). | ||
295 | */ | ||
296 | i8042_ctr &= ~port->disable; | ||
297 | |||
298 | i8042_ctr |= port->irqen; | ||
299 | |||
300 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
301 | i8042_ctr &= ~port->irqen; | ||
302 | return -1; | ||
303 | } | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | |||
309 | /* | ||
310 | * i8042_open() is called when a port is open by the higher layer. | ||
311 | * It allocates the interrupt and calls i8042_enable_port. | ||
312 | */ | ||
313 | |||
314 | static int i8042_open(struct serio *serio) | ||
315 | { | ||
316 | struct i8042_port *port = serio->port_data; | ||
317 | |||
318 | if (port->mux != -1) | ||
319 | if (i8042_mux_open++) | ||
320 | return 0; | ||
321 | |||
322 | if (request_irq(port->irq, i8042_interrupt, | ||
323 | SA_SHIRQ, "i8042", i8042_request_irq_cookie)) { | ||
324 | printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name); | ||
325 | goto irq_fail; | ||
326 | } | ||
327 | |||
328 | if (i8042_activate_port(port)) { | ||
329 | printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name); | ||
330 | goto activate_fail; | ||
331 | } | ||
332 | |||
333 | i8042_interrupt(0, NULL, NULL); | ||
334 | |||
335 | return 0; | ||
336 | |||
337 | activate_fail: | ||
338 | free_irq(port->irq, i8042_request_irq_cookie); | ||
339 | |||
340 | irq_fail: | ||
341 | serio_unregister_port_delayed(serio); | ||
342 | |||
343 | return -1; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * i8042_close() frees the interrupt, so that it can possibly be used | ||
348 | * by another driver. We never know - if the user doesn't have a mouse, | ||
349 | * the BIOS could have used the AUX interrupt for PCI. | ||
350 | */ | ||
351 | |||
352 | static void i8042_close(struct serio *serio) | ||
353 | { | ||
354 | struct i8042_port *port = serio->port_data; | ||
355 | |||
356 | if (port->mux != -1) | ||
357 | if (--i8042_mux_open) | ||
358 | return; | ||
359 | |||
360 | i8042_ctr &= ~port->irqen; | ||
361 | |||
362 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
363 | printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name); | ||
364 | /* | ||
365 | * We still want to continue and free IRQ so if more data keeps coming in | ||
366 | * kernel will just ignore the irq. | ||
367 | */ | ||
368 | } | ||
369 | |||
370 | free_irq(port->irq, i8042_request_irq_cookie); | ||
371 | |||
372 | i8042_flush(); | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * i8042_start() is called by serio core when port is about to finish | ||
377 | * registering. It will mark port as existing so i8042_interrupt can | ||
378 | * start sending data through it. | ||
379 | */ | ||
380 | static int i8042_start(struct serio *serio) | ||
381 | { | ||
382 | struct i8042_port *port = serio->port_data; | ||
383 | |||
384 | port->exists = 1; | ||
385 | mb(); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * i8042_stop() marks serio port as non-existing so i8042_interrupt | ||
391 | * will not try to send data to the port that is about to go away. | ||
392 | * The function is called by serio core as part of unregister procedure. | ||
393 | */ | ||
394 | static void i8042_stop(struct serio *serio) | ||
395 | { | ||
396 | struct i8042_port *port = serio->port_data; | ||
397 | |||
398 | port->exists = 0; | ||
399 | synchronize_kernel(); | ||
400 | port->serio = NULL; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * i8042_interrupt() is the most important function in this driver - | ||
405 | * it handles the interrupts from the i8042, and sends incoming bytes | ||
406 | * to the upper layers. | ||
407 | */ | ||
408 | |||
409 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
410 | { | ||
411 | struct i8042_port *port; | ||
412 | unsigned long flags; | ||
413 | unsigned char str, data; | ||
414 | unsigned int dfl; | ||
415 | unsigned int port_no; | ||
416 | int ret; | ||
417 | |||
418 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
419 | |||
420 | spin_lock_irqsave(&i8042_lock, flags); | ||
421 | str = i8042_read_status(); | ||
422 | if (unlikely(~str & I8042_STR_OBF)) { | ||
423 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
424 | if (irq) dbg("Interrupt %d, without any data", irq); | ||
425 | ret = 0; | ||
426 | goto out; | ||
427 | } | ||
428 | data = i8042_read_data(); | ||
429 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
430 | |||
431 | if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { | ||
432 | static unsigned long last_transmit; | ||
433 | static unsigned char last_str; | ||
434 | |||
435 | dfl = 0; | ||
436 | if (str & I8042_STR_MUXERR) { | ||
437 | dbg("MUX error, status is %02x, data is %02x", str, data); | ||
438 | switch (data) { | ||
439 | default: | ||
440 | /* | ||
441 | * When MUXERR condition is signalled the data register can only contain | ||
442 | * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately | ||
443 | * it is not always the case. Some KBC just get confused which port the | ||
444 | * data came from and signal error leaving the data intact. They _do not_ | ||
445 | * revert to legacy mode (actually I've never seen KBC reverting to legacy | ||
446 | * mode yet, when we see one we'll add proper handling). | ||
447 | * Anyway, we will assume that the data came from the same serio last byte | ||
448 | * was transmitted (if transmission happened not too long ago). | ||
449 | */ | ||
450 | if (time_before(jiffies, last_transmit + HZ/10)) { | ||
451 | str = last_str; | ||
452 | break; | ||
453 | } | ||
454 | /* fall through - report timeout */ | ||
455 | case 0xfd: | ||
456 | case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; | ||
457 | case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); | ||
462 | last_str = str; | ||
463 | last_transmit = jiffies; | ||
464 | } else { | ||
465 | |||
466 | dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | | ||
467 | ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); | ||
468 | |||
469 | port_no = (str & I8042_STR_AUXDATA) ? | ||
470 | I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; | ||
471 | } | ||
472 | |||
473 | port = &i8042_ports[port_no]; | ||
474 | |||
475 | dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", | ||
476 | data, port->name, irq, | ||
477 | dfl & SERIO_PARITY ? ", bad parity" : "", | ||
478 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); | ||
479 | |||
480 | if (likely(port->exists)) | ||
481 | serio_interrupt(port->serio, data, dfl, regs); | ||
482 | |||
483 | ret = 1; | ||
484 | out: | ||
485 | return IRQ_RETVAL(ret); | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * i8042_set_mux_mode checks whether the controller has an active | ||
490 | * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. | ||
491 | */ | ||
492 | |||
493 | static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) | ||
494 | { | ||
495 | |||
496 | unsigned char param; | ||
497 | /* | ||
498 | * Get rid of bytes in the queue. | ||
499 | */ | ||
500 | |||
501 | i8042_flush(); | ||
502 | |||
503 | /* | ||
504 | * Internal loopback test - send three bytes, they should come back from the | ||
505 | * mouse interface, the last should be version. Note that we negate mouseport | ||
506 | * command responses for the i8042_check_aux() routine. | ||
507 | */ | ||
508 | |||
509 | param = 0xf0; | ||
510 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x0f) | ||
511 | return -1; | ||
512 | param = mode ? 0x56 : 0xf6; | ||
513 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09)) | ||
514 | return -1; | ||
515 | param = mode ? 0xa4 : 0xa5; | ||
516 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a)) | ||
517 | return -1; | ||
518 | |||
519 | if (mux_version) | ||
520 | *mux_version = ~param; | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | |||
526 | /* | ||
527 | * i8042_enable_mux_ports enables 4 individual AUX ports after | ||
528 | * the controller has been switched into Multiplexed mode | ||
529 | */ | ||
530 | |||
531 | static int i8042_enable_mux_ports(void) | ||
532 | { | ||
533 | unsigned char param; | ||
534 | int i; | ||
535 | /* | ||
536 | * Disable all muxed ports by disabling AUX. | ||
537 | */ | ||
538 | |||
539 | i8042_ctr |= I8042_CTR_AUXDIS; | ||
540 | i8042_ctr &= ~I8042_CTR_AUXINT; | ||
541 | |||
542 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
543 | printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); | ||
544 | return -1; | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Enable all muxed ports. | ||
549 | */ | ||
550 | |||
551 | for (i = 0; i < 4; i++) { | ||
552 | i8042_command(¶m, I8042_CMD_MUX_PFX + i); | ||
553 | i8042_command(¶m, I8042_CMD_AUX_ENABLE); | ||
554 | } | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | |||
560 | /* | ||
561 | * i8042_check_mux() checks whether the controller supports the PS/2 Active | ||
562 | * Multiplexing specification by Synaptics, Phoenix, Insyde and | ||
563 | * LCS/Telegraphics. | ||
564 | */ | ||
565 | |||
566 | static int __init i8042_check_mux(void) | ||
567 | { | ||
568 | unsigned char mux_version; | ||
569 | |||
570 | if (i8042_set_mux_mode(1, &mux_version)) | ||
571 | return -1; | ||
572 | |||
573 | /* Workaround for interference with USB Legacy emulation */ | ||
574 | /* that causes a v10.12 MUX to be found. */ | ||
575 | if (mux_version == 0xAC) | ||
576 | return -1; | ||
577 | |||
578 | printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", | ||
579 | (mux_version >> 4) & 0xf, mux_version & 0xf); | ||
580 | |||
581 | if (i8042_enable_mux_ports()) | ||
582 | return -1; | ||
583 | |||
584 | i8042_mux_present = 1; | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | |||
589 | /* | ||
590 | * i8042_check_aux() applies as much paranoia as it can at detecting | ||
591 | * the presence of an AUX interface. | ||
592 | */ | ||
593 | |||
594 | static int __init i8042_check_aux(void) | ||
595 | { | ||
596 | unsigned char param; | ||
597 | static int i8042_check_aux_cookie; | ||
598 | |||
599 | /* | ||
600 | * Check if AUX irq is available. If it isn't, then there is no point | ||
601 | * in trying to detect AUX presence. | ||
602 | */ | ||
603 | |||
604 | if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt, | ||
605 | SA_SHIRQ, "i8042", &i8042_check_aux_cookie)) | ||
606 | return -1; | ||
607 | free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie); | ||
608 | |||
609 | /* | ||
610 | * Get rid of bytes in the queue. | ||
611 | */ | ||
612 | |||
613 | i8042_flush(); | ||
614 | |||
615 | /* | ||
616 | * Internal loopback test - filters out AT-type i8042's. Unfortunately | ||
617 | * SiS screwed up and their 5597 doesn't support the LOOP command even | ||
618 | * though it has an AUX port. | ||
619 | */ | ||
620 | |||
621 | param = 0x5a; | ||
622 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa5) { | ||
623 | |||
624 | /* | ||
625 | * External connection test - filters out AT-soldered PS/2 i8042's | ||
626 | * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error | ||
627 | * 0xfa - no error on some notebooks which ignore the spec | ||
628 | * Because it's common for chipsets to return error on perfectly functioning | ||
629 | * AUX ports, we test for this only when the LOOP command failed. | ||
630 | */ | ||
631 | |||
632 | if (i8042_command(¶m, I8042_CMD_AUX_TEST) | ||
633 | || (param && param != 0xfa && param != 0xff)) | ||
634 | return -1; | ||
635 | } | ||
636 | |||
637 | /* | ||
638 | * Bit assignment test - filters out PS/2 i8042's in AT mode | ||
639 | */ | ||
640 | |||
641 | if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) | ||
642 | return -1; | ||
643 | if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) { | ||
644 | printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); | ||
645 | printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); | ||
646 | } | ||
647 | |||
648 | if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) | ||
649 | return -1; | ||
650 | if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) | ||
651 | return -1; | ||
652 | |||
653 | /* | ||
654 | * Disable the interface. | ||
655 | */ | ||
656 | |||
657 | i8042_ctr |= I8042_CTR_AUXDIS; | ||
658 | i8042_ctr &= ~I8042_CTR_AUXINT; | ||
659 | |||
660 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | ||
661 | return -1; | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | |||
667 | /* | ||
668 | * i8042_port_register() marks the device as existing, | ||
669 | * registers it, and reports to the user. | ||
670 | */ | ||
671 | |||
672 | static int __init i8042_port_register(struct i8042_port *port) | ||
673 | { | ||
674 | i8042_ctr &= ~port->disable; | ||
675 | |||
676 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
677 | printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n"); | ||
678 | kfree(port->serio); | ||
679 | port->serio = NULL; | ||
680 | i8042_ctr |= port->disable; | ||
681 | return -1; | ||
682 | } | ||
683 | |||
684 | printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", | ||
685 | port->name, | ||
686 | (unsigned long) I8042_DATA_REG, | ||
687 | (unsigned long) I8042_COMMAND_REG, | ||
688 | port->irq); | ||
689 | |||
690 | serio_register_port(port->serio); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | |||
696 | static void i8042_timer_func(unsigned long data) | ||
697 | { | ||
698 | i8042_interrupt(0, NULL, NULL); | ||
699 | } | ||
700 | |||
701 | |||
702 | /* | ||
703 | * i8042_controller init initializes the i8042 controller, and, | ||
704 | * most importantly, sets it into non-xlated mode if that's | ||
705 | * desired. | ||
706 | */ | ||
707 | |||
708 | static int i8042_controller_init(void) | ||
709 | { | ||
710 | unsigned long flags; | ||
711 | |||
712 | /* | ||
713 | * Test the i8042. We need to know if it thinks it's working correctly | ||
714 | * before doing anything else. | ||
715 | */ | ||
716 | |||
717 | if (i8042_flush() == I8042_BUFFER_SIZE) { | ||
718 | printk(KERN_ERR "i8042.c: No controller found.\n"); | ||
719 | return -1; | ||
720 | } | ||
721 | |||
722 | if (i8042_reset) { | ||
723 | |||
724 | unsigned char param; | ||
725 | |||
726 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { | ||
727 | printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); | ||
728 | return -1; | ||
729 | } | ||
730 | |||
731 | if (param != I8042_RET_CTL_TEST) { | ||
732 | printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", | ||
733 | param, I8042_RET_CTL_TEST); | ||
734 | return -1; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * Save the CTR for restoral on unload / reboot. | ||
740 | */ | ||
741 | |||
742 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { | ||
743 | printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); | ||
744 | return -1; | ||
745 | } | ||
746 | |||
747 | i8042_initial_ctr = i8042_ctr; | ||
748 | |||
749 | /* | ||
750 | * Disable the keyboard interface and interrupt. | ||
751 | */ | ||
752 | |||
753 | i8042_ctr |= I8042_CTR_KBDDIS; | ||
754 | i8042_ctr &= ~I8042_CTR_KBDINT; | ||
755 | |||
756 | /* | ||
757 | * Handle keylock. | ||
758 | */ | ||
759 | |||
760 | spin_lock_irqsave(&i8042_lock, flags); | ||
761 | if (~i8042_read_status() & I8042_STR_KEYLOCK) { | ||
762 | if (i8042_unlock) | ||
763 | i8042_ctr |= I8042_CTR_IGNKEYLOCK; | ||
764 | else | ||
765 | printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); | ||
766 | } | ||
767 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
768 | |||
769 | /* | ||
770 | * If the chip is configured into nontranslated mode by the BIOS, don't | ||
771 | * bother enabling translating and be happy. | ||
772 | */ | ||
773 | |||
774 | if (~i8042_ctr & I8042_CTR_XLATE) | ||
775 | i8042_direct = 1; | ||
776 | |||
777 | /* | ||
778 | * Set nontranslated mode for the kbd interface if requested by an option. | ||
779 | * After this the kbd interface becomes a simple serial in/out, like the aux | ||
780 | * interface is. We don't do this by default, since it can confuse notebook | ||
781 | * BIOSes. | ||
782 | */ | ||
783 | |||
784 | if (i8042_direct) | ||
785 | i8042_ctr &= ~I8042_CTR_XLATE; | ||
786 | |||
787 | /* | ||
788 | * Write CTR back. | ||
789 | */ | ||
790 | |||
791 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
792 | printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); | ||
793 | return -1; | ||
794 | } | ||
795 | |||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | |||
800 | /* | ||
801 | * Reset the controller. | ||
802 | */ | ||
803 | static void i8042_controller_reset(void) | ||
804 | { | ||
805 | unsigned char param; | ||
806 | |||
807 | /* | ||
808 | * Reset the controller if requested. | ||
809 | */ | ||
810 | |||
811 | if (i8042_reset) | ||
812 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) | ||
813 | printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n"); | ||
814 | |||
815 | /* | ||
816 | * Disable MUX mode if present. | ||
817 | */ | ||
818 | |||
819 | if (i8042_mux_present) | ||
820 | i8042_set_mux_mode(0, NULL); | ||
821 | |||
822 | /* | ||
823 | * Restore the original control register setting. | ||
824 | */ | ||
825 | |||
826 | i8042_ctr = i8042_initial_ctr; | ||
827 | |||
828 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | ||
829 | printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); | ||
830 | } | ||
831 | |||
832 | |||
833 | /* | ||
834 | * Here we try to reset everything back to a state in which the BIOS will be | ||
835 | * able to talk to the hardware when rebooting. | ||
836 | */ | ||
837 | |||
838 | static void i8042_controller_cleanup(void) | ||
839 | { | ||
840 | int i; | ||
841 | |||
842 | i8042_flush(); | ||
843 | |||
844 | /* | ||
845 | * Reset anything that is connected to the ports. | ||
846 | */ | ||
847 | |||
848 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
849 | if (i8042_ports[i].exists) | ||
850 | serio_cleanup(i8042_ports[i].serio); | ||
851 | |||
852 | i8042_controller_reset(); | ||
853 | } | ||
854 | |||
855 | |||
856 | /* | ||
857 | * i8042_panic_blink() will flash the keyboard LEDs and is called when | ||
858 | * kernel panics. Flashing LEDs is useful for users running X who may | ||
859 | * not see the console and will help distingushing panics from "real" | ||
860 | * lockups. | ||
861 | * | ||
862 | * Note that DELAY has a limit of 10ms so we will not get stuck here | ||
863 | * waiting for KBC to free up even if KBD interrupt is off | ||
864 | */ | ||
865 | |||
866 | #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) | ||
867 | |||
868 | static long i8042_panic_blink(long count) | ||
869 | { | ||
870 | long delay = 0; | ||
871 | static long last_blink; | ||
872 | static char led; | ||
873 | |||
874 | /* | ||
875 | * We expect frequency to be about 1/2s. KDB uses about 1s. | ||
876 | * Make sure they are different. | ||
877 | */ | ||
878 | if (!i8042_blink_frequency) | ||
879 | return 0; | ||
880 | if (count - last_blink < i8042_blink_frequency) | ||
881 | return 0; | ||
882 | |||
883 | led ^= 0x01 | 0x04; | ||
884 | while (i8042_read_status() & I8042_STR_IBF) | ||
885 | DELAY; | ||
886 | i8042_write_data(0xed); /* set leds */ | ||
887 | DELAY; | ||
888 | while (i8042_read_status() & I8042_STR_IBF) | ||
889 | DELAY; | ||
890 | DELAY; | ||
891 | i8042_write_data(led); | ||
892 | DELAY; | ||
893 | last_blink = count; | ||
894 | return delay; | ||
895 | } | ||
896 | |||
897 | #undef DELAY | ||
898 | |||
899 | /* | ||
900 | * Here we try to restore the original BIOS settings | ||
901 | */ | ||
902 | |||
903 | static int i8042_suspend(struct device *dev, pm_message_t state, u32 level) | ||
904 | { | ||
905 | if (level == SUSPEND_DISABLE) { | ||
906 | del_timer_sync(&i8042_timer); | ||
907 | i8042_controller_reset(); | ||
908 | } | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | |||
914 | /* | ||
915 | * Here we try to reset everything back to a state in which suspended | ||
916 | */ | ||
917 | |||
918 | static int i8042_resume(struct device *dev, u32 level) | ||
919 | { | ||
920 | int i; | ||
921 | |||
922 | if (level != RESUME_ENABLE) | ||
923 | return 0; | ||
924 | |||
925 | if (i8042_controller_init()) { | ||
926 | printk(KERN_ERR "i8042: resume failed\n"); | ||
927 | return -1; | ||
928 | } | ||
929 | |||
930 | if (i8042_mux_present) | ||
931 | if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) | ||
932 | printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n"); | ||
933 | |||
934 | /* | ||
935 | * Activate all ports. | ||
936 | */ | ||
937 | |||
938 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
939 | i8042_activate_port(&i8042_ports[i]); | ||
940 | |||
941 | /* | ||
942 | * Restart timer (for polling "stuck" data) | ||
943 | */ | ||
944 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
945 | |||
946 | panic_blink = i8042_panic_blink; | ||
947 | |||
948 | return 0; | ||
949 | |||
950 | } | ||
951 | |||
952 | /* | ||
953 | * We need to reset the 8042 back to original mode on system shutdown, | ||
954 | * because otherwise BIOSes will be confused. | ||
955 | */ | ||
956 | |||
957 | static void i8042_shutdown(struct device *dev) | ||
958 | { | ||
959 | i8042_controller_cleanup(); | ||
960 | } | ||
961 | |||
962 | static struct device_driver i8042_driver = { | ||
963 | .name = "i8042", | ||
964 | .bus = &platform_bus_type, | ||
965 | .suspend = i8042_suspend, | ||
966 | .resume = i8042_resume, | ||
967 | .shutdown = i8042_shutdown, | ||
968 | }; | ||
969 | |||
970 | static void __init i8042_create_kbd_port(void) | ||
971 | { | ||
972 | struct serio *serio; | ||
973 | struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; | ||
974 | |||
975 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
976 | if (serio) { | ||
977 | memset(serio, 0, sizeof(struct serio)); | ||
978 | serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; | ||
979 | serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; | ||
980 | serio->open = i8042_open; | ||
981 | serio->close = i8042_close; | ||
982 | serio->start = i8042_start; | ||
983 | serio->stop = i8042_stop; | ||
984 | serio->port_data = port; | ||
985 | serio->dev.parent = &i8042_platform_device->dev; | ||
986 | strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); | ||
987 | strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); | ||
988 | |||
989 | port->serio = serio; | ||
990 | i8042_port_register(port); | ||
991 | } | ||
992 | } | ||
993 | |||
994 | static void __init i8042_create_aux_port(void) | ||
995 | { | ||
996 | struct serio *serio; | ||
997 | struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; | ||
998 | |||
999 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
1000 | if (serio) { | ||
1001 | memset(serio, 0, sizeof(struct serio)); | ||
1002 | serio->id.type = SERIO_8042; | ||
1003 | serio->write = i8042_aux_write; | ||
1004 | serio->open = i8042_open; | ||
1005 | serio->close = i8042_close; | ||
1006 | serio->start = i8042_start; | ||
1007 | serio->stop = i8042_stop; | ||
1008 | serio->port_data = port; | ||
1009 | serio->dev.parent = &i8042_platform_device->dev; | ||
1010 | strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); | ||
1011 | strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); | ||
1012 | |||
1013 | port->serio = serio; | ||
1014 | i8042_port_register(port); | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | static void __init i8042_create_mux_port(int index) | ||
1019 | { | ||
1020 | struct serio *serio; | ||
1021 | struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; | ||
1022 | |||
1023 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
1024 | if (serio) { | ||
1025 | memset(serio, 0, sizeof(struct serio)); | ||
1026 | serio->id.type = SERIO_8042; | ||
1027 | serio->write = i8042_aux_write; | ||
1028 | serio->open = i8042_open; | ||
1029 | serio->close = i8042_close; | ||
1030 | serio->start = i8042_start; | ||
1031 | serio->stop = i8042_stop; | ||
1032 | serio->port_data = port; | ||
1033 | serio->dev.parent = &i8042_platform_device->dev; | ||
1034 | snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); | ||
1035 | snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); | ||
1036 | |||
1037 | *port = i8042_ports[I8042_AUX_PORT_NO]; | ||
1038 | port->exists = 0; | ||
1039 | snprintf(port->name, sizeof(port->name), "AUX%d", index); | ||
1040 | port->mux = index; | ||
1041 | port->serio = serio; | ||
1042 | i8042_port_register(port); | ||
1043 | } | ||
1044 | } | ||
1045 | |||
1046 | static int __init i8042_init(void) | ||
1047 | { | ||
1048 | int i; | ||
1049 | int err; | ||
1050 | |||
1051 | dbg_init(); | ||
1052 | |||
1053 | init_timer(&i8042_timer); | ||
1054 | i8042_timer.function = i8042_timer_func; | ||
1055 | |||
1056 | if (i8042_platform_init()) | ||
1057 | return -EBUSY; | ||
1058 | |||
1059 | i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; | ||
1060 | i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; | ||
1061 | |||
1062 | if (i8042_controller_init()) { | ||
1063 | i8042_platform_exit(); | ||
1064 | return -ENODEV; | ||
1065 | } | ||
1066 | |||
1067 | err = driver_register(&i8042_driver); | ||
1068 | if (err) { | ||
1069 | i8042_platform_exit(); | ||
1070 | return err; | ||
1071 | } | ||
1072 | |||
1073 | i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); | ||
1074 | if (IS_ERR(i8042_platform_device)) { | ||
1075 | driver_unregister(&i8042_driver); | ||
1076 | i8042_platform_exit(); | ||
1077 | return PTR_ERR(i8042_platform_device); | ||
1078 | } | ||
1079 | |||
1080 | if (!i8042_noaux && !i8042_check_aux()) { | ||
1081 | if (!i8042_nomux && !i8042_check_mux()) | ||
1082 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) | ||
1083 | i8042_create_mux_port(i); | ||
1084 | else | ||
1085 | i8042_create_aux_port(); | ||
1086 | } | ||
1087 | |||
1088 | i8042_create_kbd_port(); | ||
1089 | |||
1090 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
1091 | |||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | static void __exit i8042_exit(void) | ||
1096 | { | ||
1097 | int i; | ||
1098 | |||
1099 | i8042_controller_cleanup(); | ||
1100 | |||
1101 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
1102 | if (i8042_ports[i].exists) | ||
1103 | serio_unregister_port(i8042_ports[i].serio); | ||
1104 | |||
1105 | del_timer_sync(&i8042_timer); | ||
1106 | |||
1107 | platform_device_unregister(i8042_platform_device); | ||
1108 | driver_unregister(&i8042_driver); | ||
1109 | |||
1110 | i8042_platform_exit(); | ||
1111 | |||
1112 | panic_blink = NULL; | ||
1113 | } | ||
1114 | |||
1115 | module_init(i8042_init); | ||
1116 | module_exit(i8042_exit); | ||
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h new file mode 100644 index 000000000000..13835039a2a7 --- /dev/null +++ b/drivers/input/serio/i8042.h | |||
@@ -0,0 +1,133 @@ | |||
1 | #ifndef _I8042_H | ||
2 | #define _I8042_H | ||
3 | |||
4 | #include <linux/config.h> | ||
5 | |||
6 | /* | ||
7 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * Arch-dependent inline functions and defines. | ||
16 | */ | ||
17 | |||
18 | #if defined(CONFIG_MACH_JAZZ) | ||
19 | #include "i8042-jazzio.h" | ||
20 | #elif defined(CONFIG_SGI_IP22) | ||
21 | #include "i8042-ip22io.h" | ||
22 | #elif defined(CONFIG_PPC) | ||
23 | #include "i8042-ppcio.h" | ||
24 | #elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) | ||
25 | #include "i8042-sparcio.h" | ||
26 | #elif defined(CONFIG_X86) || defined(CONFIG_IA64) | ||
27 | #include "i8042-x86ia64io.h" | ||
28 | #else | ||
29 | #include "i8042-io.h" | ||
30 | #endif | ||
31 | |||
32 | /* | ||
33 | * This is in 50us units, the time we wait for the i8042 to react. This | ||
34 | * has to be long enough for the i8042 itself to timeout on sending a byte | ||
35 | * to a non-existent mouse. | ||
36 | */ | ||
37 | |||
38 | #define I8042_CTL_TIMEOUT 10000 | ||
39 | |||
40 | /* | ||
41 | * When the device isn't opened and it's interrupts aren't used, we poll it at | ||
42 | * regular intervals to see if any characters arrived. If yes, we can start | ||
43 | * probing for any mouse / keyboard connected. This is the period of the | ||
44 | * polling. | ||
45 | */ | ||
46 | |||
47 | #define I8042_POLL_PERIOD HZ/20 | ||
48 | |||
49 | /* | ||
50 | * Status register bits. | ||
51 | */ | ||
52 | |||
53 | #define I8042_STR_PARITY 0x80 | ||
54 | #define I8042_STR_TIMEOUT 0x40 | ||
55 | #define I8042_STR_AUXDATA 0x20 | ||
56 | #define I8042_STR_KEYLOCK 0x10 | ||
57 | #define I8042_STR_CMDDAT 0x08 | ||
58 | #define I8042_STR_MUXERR 0x04 | ||
59 | #define I8042_STR_IBF 0x02 | ||
60 | #define I8042_STR_OBF 0x01 | ||
61 | |||
62 | /* | ||
63 | * Control register bits. | ||
64 | */ | ||
65 | |||
66 | #define I8042_CTR_KBDINT 0x01 | ||
67 | #define I8042_CTR_AUXINT 0x02 | ||
68 | #define I8042_CTR_IGNKEYLOCK 0x08 | ||
69 | #define I8042_CTR_KBDDIS 0x10 | ||
70 | #define I8042_CTR_AUXDIS 0x20 | ||
71 | #define I8042_CTR_XLATE 0x40 | ||
72 | |||
73 | /* | ||
74 | * Commands. | ||
75 | */ | ||
76 | |||
77 | #define I8042_CMD_CTL_RCTR 0x0120 | ||
78 | #define I8042_CMD_CTL_WCTR 0x1060 | ||
79 | #define I8042_CMD_CTL_TEST 0x01aa | ||
80 | |||
81 | #define I8042_CMD_KBD_DISABLE 0x00ad | ||
82 | #define I8042_CMD_KBD_ENABLE 0x00ae | ||
83 | #define I8042_CMD_KBD_TEST 0x01ab | ||
84 | #define I8042_CMD_KBD_LOOP 0x11d2 | ||
85 | |||
86 | #define I8042_CMD_AUX_DISABLE 0x00a7 | ||
87 | #define I8042_CMD_AUX_ENABLE 0x00a8 | ||
88 | #define I8042_CMD_AUX_TEST 0x01a9 | ||
89 | #define I8042_CMD_AUX_SEND 0x10d4 | ||
90 | #define I8042_CMD_AUX_LOOP 0x11d3 | ||
91 | |||
92 | #define I8042_CMD_MUX_PFX 0x0090 | ||
93 | #define I8042_CMD_MUX_SEND 0x1090 | ||
94 | |||
95 | /* | ||
96 | * Return codes. | ||
97 | */ | ||
98 | |||
99 | #define I8042_RET_CTL_TEST 0x55 | ||
100 | |||
101 | /* | ||
102 | * Expected maximum internal i8042 buffer size. This is used for flushing | ||
103 | * the i8042 buffers. | ||
104 | */ | ||
105 | |||
106 | #define I8042_BUFFER_SIZE 16 | ||
107 | |||
108 | /* | ||
109 | * Number of AUX ports on controllers supporting active multiplexing | ||
110 | * specification | ||
111 | */ | ||
112 | |||
113 | #define I8042_NUM_MUX_PORTS 4 | ||
114 | |||
115 | /* | ||
116 | * Debug. | ||
117 | */ | ||
118 | |||
119 | #ifdef DEBUG | ||
120 | static unsigned long i8042_start_time; | ||
121 | #define dbg_init() do { i8042_start_time = jiffies; } while (0) | ||
122 | #define dbg(format, arg...) \ | ||
123 | do { \ | ||
124 | if (i8042_debug) \ | ||
125 | printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" , \ | ||
126 | ## arg, (int) (jiffies - i8042_start_time)); \ | ||
127 | } while (0) | ||
128 | #else | ||
129 | #define dbg_init() do { } while (0) | ||
130 | #define dbg(format, arg...) do {} while (0) | ||
131 | #endif | ||
132 | |||
133 | #endif /* _I8042_H */ | ||
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c new file mode 100644 index 000000000000..c978657068c5 --- /dev/null +++ b/drivers/input/serio/libps2.c | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * PS/2 driver library | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/serio.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/libps2.h> | ||
23 | |||
24 | #define DRIVER_DESC "PS/2 driver library" | ||
25 | |||
26 | MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); | ||
27 | MODULE_DESCRIPTION("PS/2 driver library"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | EXPORT_SYMBOL(ps2_init); | ||
31 | EXPORT_SYMBOL(ps2_sendbyte); | ||
32 | EXPORT_SYMBOL(ps2_command); | ||
33 | EXPORT_SYMBOL(ps2_schedule_command); | ||
34 | EXPORT_SYMBOL(ps2_handle_ack); | ||
35 | EXPORT_SYMBOL(ps2_handle_response); | ||
36 | EXPORT_SYMBOL(ps2_cmd_aborted); | ||
37 | |||
38 | /* Work structure to schedule execution of a command */ | ||
39 | struct ps2work { | ||
40 | struct work_struct work; | ||
41 | struct ps2dev *ps2dev; | ||
42 | int command; | ||
43 | unsigned char param[0]; | ||
44 | }; | ||
45 | |||
46 | |||
47 | /* | ||
48 | * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge. | ||
49 | * It doesn't handle retransmission, though it could - because when there would | ||
50 | * be need for retransmissions, the mouse has to be replaced anyway. | ||
51 | * | ||
52 | * ps2_sendbyte() can only be called from a process context | ||
53 | */ | ||
54 | |||
55 | int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) | ||
56 | { | ||
57 | serio_pause_rx(ps2dev->serio); | ||
58 | ps2dev->nak = 1; | ||
59 | ps2dev->flags |= PS2_FLAG_ACK; | ||
60 | serio_continue_rx(ps2dev->serio); | ||
61 | |||
62 | if (serio_write(ps2dev->serio, byte) == 0) | ||
63 | wait_event_timeout(ps2dev->wait, | ||
64 | !(ps2dev->flags & PS2_FLAG_ACK), | ||
65 | msecs_to_jiffies(timeout)); | ||
66 | |||
67 | serio_pause_rx(ps2dev->serio); | ||
68 | ps2dev->flags &= ~PS2_FLAG_ACK; | ||
69 | serio_continue_rx(ps2dev->serio); | ||
70 | |||
71 | return -ps2dev->nak; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * ps2_command() sends a command and its parameters to the mouse, | ||
76 | * then waits for the response and puts it in the param array. | ||
77 | * | ||
78 | * ps2_command() can only be called from a process context | ||
79 | */ | ||
80 | |||
81 | int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | ||
82 | { | ||
83 | int timeout; | ||
84 | int send = (command >> 12) & 0xf; | ||
85 | int receive = (command >> 8) & 0xf; | ||
86 | int rc = -1; | ||
87 | int i; | ||
88 | |||
89 | down(&ps2dev->cmd_sem); | ||
90 | |||
91 | serio_pause_rx(ps2dev->serio); | ||
92 | ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; | ||
93 | ps2dev->cmdcnt = receive; | ||
94 | if (receive && param) | ||
95 | for (i = 0; i < receive; i++) | ||
96 | ps2dev->cmdbuf[(receive - 1) - i] = param[i]; | ||
97 | serio_continue_rx(ps2dev->serio); | ||
98 | |||
99 | /* | ||
100 | * Some devices (Synaptics) peform the reset before | ||
101 | * ACKing the reset command, and so it can take a long | ||
102 | * time before the ACK arrrives. | ||
103 | */ | ||
104 | if (command & 0xff) | ||
105 | if (ps2_sendbyte(ps2dev, command & 0xff, | ||
106 | command == PS2_CMD_RESET_BAT ? 1000 : 200)) | ||
107 | goto out; | ||
108 | |||
109 | for (i = 0; i < send; i++) | ||
110 | if (ps2_sendbyte(ps2dev, param[i], 200)) | ||
111 | goto out; | ||
112 | |||
113 | /* | ||
114 | * The reset command takes a long time to execute. | ||
115 | */ | ||
116 | timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500); | ||
117 | |||
118 | timeout = wait_event_timeout(ps2dev->wait, | ||
119 | !(ps2dev->flags & PS2_FLAG_CMD1), timeout); | ||
120 | |||
121 | if (ps2dev->cmdcnt && timeout > 0) { | ||
122 | |||
123 | if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) { | ||
124 | /* | ||
125 | * Device has sent the first response byte | ||
126 | * after a reset command, reset is thus done, | ||
127 | * shorten the timeout. The next byte will come | ||
128 | * soon (keyboard) or not at all (mouse). | ||
129 | */ | ||
130 | timeout = msecs_to_jiffies(100); | ||
131 | } | ||
132 | |||
133 | if (command == PS2_CMD_GETID && | ||
134 | ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */ | ||
135 | ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */ | ||
136 | ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */ | ||
137 | ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */ | ||
138 | ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */ | ||
139 | ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */ | ||
140 | /* | ||
141 | * Device behind the port is not a keyboard | ||
142 | * so we don't need to wait for the 2nd byte | ||
143 | * of ID response. | ||
144 | */ | ||
145 | serio_pause_rx(ps2dev->serio); | ||
146 | ps2dev->flags = ps2dev->cmdcnt = 0; | ||
147 | serio_continue_rx(ps2dev->serio); | ||
148 | } | ||
149 | |||
150 | wait_event_timeout(ps2dev->wait, | ||
151 | !(ps2dev->flags & PS2_FLAG_CMD), timeout); | ||
152 | } | ||
153 | |||
154 | if (param) | ||
155 | for (i = 0; i < receive; i++) | ||
156 | param[i] = ps2dev->cmdbuf[(receive - 1) - i]; | ||
157 | |||
158 | if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) | ||
159 | goto out; | ||
160 | |||
161 | rc = 0; | ||
162 | |||
163 | out: | ||
164 | serio_pause_rx(ps2dev->serio); | ||
165 | ps2dev->flags = 0; | ||
166 | serio_continue_rx(ps2dev->serio); | ||
167 | |||
168 | up(&ps2dev->cmd_sem); | ||
169 | return rc; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * ps2_execute_scheduled_command() sends a command, previously scheduled by | ||
174 | * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.) | ||
175 | */ | ||
176 | |||
177 | static void ps2_execute_scheduled_command(void *data) | ||
178 | { | ||
179 | struct ps2work *ps2work = data; | ||
180 | |||
181 | ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command); | ||
182 | kfree(ps2work); | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * ps2_schedule_command() allows to schedule delayed execution of a PS/2 | ||
187 | * command and can be used to issue a command from an interrupt or softirq | ||
188 | * context. | ||
189 | */ | ||
190 | |||
191 | int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command) | ||
192 | { | ||
193 | struct ps2work *ps2work; | ||
194 | int send = (command >> 12) & 0xf; | ||
195 | int receive = (command >> 8) & 0xf; | ||
196 | |||
197 | if (!(ps2work = kmalloc(sizeof(struct ps2work) + max(send, receive), GFP_ATOMIC))) | ||
198 | return -1; | ||
199 | |||
200 | memset(ps2work, 0, sizeof(struct ps2work)); | ||
201 | ps2work->ps2dev = ps2dev; | ||
202 | ps2work->command = command; | ||
203 | memcpy(ps2work->param, param, send); | ||
204 | INIT_WORK(&ps2work->work, ps2_execute_scheduled_command, ps2work); | ||
205 | |||
206 | if (!schedule_work(&ps2work->work)) { | ||
207 | kfree(ps2work); | ||
208 | return -1; | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * ps2_init() initializes ps2dev structure | ||
216 | */ | ||
217 | |||
218 | void ps2_init(struct ps2dev *ps2dev, struct serio *serio) | ||
219 | { | ||
220 | init_MUTEX(&ps2dev->cmd_sem); | ||
221 | init_waitqueue_head(&ps2dev->wait); | ||
222 | ps2dev->serio = serio; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * ps2_handle_ack() is supposed to be used in interrupt handler | ||
227 | * to properly process ACK/NAK of a command from a PS/2 device. | ||
228 | */ | ||
229 | |||
230 | int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) | ||
231 | { | ||
232 | switch (data) { | ||
233 | case PS2_RET_ACK: | ||
234 | ps2dev->nak = 0; | ||
235 | break; | ||
236 | |||
237 | case PS2_RET_NAK: | ||
238 | ps2dev->nak = 1; | ||
239 | break; | ||
240 | |||
241 | /* | ||
242 | * Workaround for mice which don't ACK the Get ID command. | ||
243 | * These are valid mouse IDs that we recognize. | ||
244 | */ | ||
245 | case 0x00: | ||
246 | case 0x03: | ||
247 | case 0x04: | ||
248 | if (ps2dev->flags & PS2_FLAG_WAITID) { | ||
249 | ps2dev->nak = 0; | ||
250 | break; | ||
251 | } | ||
252 | /* Fall through */ | ||
253 | default: | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | |||
258 | if (!ps2dev->nak && ps2dev->cmdcnt) | ||
259 | ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; | ||
260 | |||
261 | ps2dev->flags &= ~PS2_FLAG_ACK; | ||
262 | wake_up(&ps2dev->wait); | ||
263 | |||
264 | if (data != PS2_RET_ACK) | ||
265 | ps2_handle_response(ps2dev, data); | ||
266 | |||
267 | return 1; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * ps2_handle_response() is supposed to be used in interrupt handler | ||
272 | * to properly store device's response to a command and notify process | ||
273 | * waiting for completion of the command. | ||
274 | */ | ||
275 | |||
276 | int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) | ||
277 | { | ||
278 | if (ps2dev->cmdcnt) | ||
279 | ps2dev->cmdbuf[--ps2dev->cmdcnt] = data; | ||
280 | |||
281 | if (ps2dev->flags & PS2_FLAG_CMD1) { | ||
282 | ps2dev->flags &= ~PS2_FLAG_CMD1; | ||
283 | if (ps2dev->cmdcnt) | ||
284 | wake_up(&ps2dev->wait); | ||
285 | } | ||
286 | |||
287 | if (!ps2dev->cmdcnt) { | ||
288 | ps2dev->flags &= ~PS2_FLAG_CMD; | ||
289 | wake_up(&ps2dev->wait); | ||
290 | } | ||
291 | |||
292 | return 1; | ||
293 | } | ||
294 | |||
295 | void ps2_cmd_aborted(struct ps2dev *ps2dev) | ||
296 | { | ||
297 | if (ps2dev->flags & PS2_FLAG_ACK) | ||
298 | ps2dev->nak = 1; | ||
299 | |||
300 | if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) | ||
301 | wake_up(&ps2dev->wait); | ||
302 | |||
303 | ps2dev->flags = 0; | ||
304 | } | ||
305 | |||
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c new file mode 100644 index 000000000000..9880fc145d90 --- /dev/null +++ b/drivers/input/serio/maceps2.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * SGI O2 MACE PS2 controller driver for linux | ||
3 | * | ||
4 | * Copyright (C) 2002 Vivien Chappelier | ||
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 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/serio.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/irq.h> | ||
24 | #include <asm/system.h> | ||
25 | #include <asm/ip32/mace.h> | ||
26 | #include <asm/ip32/ip32_ints.h> | ||
27 | |||
28 | MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org"); | ||
29 | MODULE_DESCRIPTION("SGI O2 MACE PS2 controller driver"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | #define MACE_PS2_TIMEOUT 10000 /* in 50us unit */ | ||
33 | |||
34 | #define PS2_STATUS_CLOCK_SIGNAL BIT(0) /* external clock signal */ | ||
35 | #define PS2_STATUS_CLOCK_INHIBIT BIT(1) /* clken output signal */ | ||
36 | #define PS2_STATUS_TX_INPROGRESS BIT(2) /* transmission in progress */ | ||
37 | #define PS2_STATUS_TX_EMPTY BIT(3) /* empty transmit buffer */ | ||
38 | #define PS2_STATUS_RX_FULL BIT(4) /* full receive buffer */ | ||
39 | #define PS2_STATUS_RX_INPROGRESS BIT(5) /* reception in progress */ | ||
40 | #define PS2_STATUS_ERROR_PARITY BIT(6) /* parity error */ | ||
41 | #define PS2_STATUS_ERROR_FRAMING BIT(7) /* framing error */ | ||
42 | |||
43 | #define PS2_CONTROL_TX_CLOCK_DISABLE BIT(0) /* inhibit clock signal after TX */ | ||
44 | #define PS2_CONTROL_TX_ENABLE BIT(1) /* transmit enable */ | ||
45 | #define PS2_CONTROL_TX_INT_ENABLE BIT(2) /* enable transmit interrupt */ | ||
46 | #define PS2_CONTROL_RX_INT_ENABLE BIT(3) /* enable receive interrupt */ | ||
47 | #define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ | ||
48 | #define PS2_CONTROL_RESET BIT(5) /* reset */ | ||
49 | |||
50 | struct maceps2_data { | ||
51 | struct mace_ps2port *port; | ||
52 | int irq; | ||
53 | }; | ||
54 | |||
55 | static struct maceps2_data port_data[2]; | ||
56 | static struct serio *maceps2_port[2]; | ||
57 | static struct platform_device *maceps2_device; | ||
58 | |||
59 | static int maceps2_write(struct serio *dev, unsigned char val) | ||
60 | { | ||
61 | struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; | ||
62 | unsigned int timeout = MACE_PS2_TIMEOUT; | ||
63 | |||
64 | do { | ||
65 | if (port->status & PS2_STATUS_TX_EMPTY) { | ||
66 | port->tx = val; | ||
67 | return 0; | ||
68 | } | ||
69 | udelay(50); | ||
70 | } while (timeout--); | ||
71 | |||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | static irqreturn_t maceps2_interrupt(int irq, void *dev_id, | ||
76 | struct pt_regs *regs) | ||
77 | { | ||
78 | struct serio *dev = dev_id; | ||
79 | struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; | ||
80 | unsigned long byte; | ||
81 | |||
82 | if (port->status & PS2_STATUS_RX_FULL) { | ||
83 | byte = port->rx; | ||
84 | serio_interrupt(dev, byte & 0xff, 0, regs); | ||
85 | } | ||
86 | |||
87 | return IRQ_HANDLED; | ||
88 | } | ||
89 | |||
90 | static int maceps2_open(struct serio *dev) | ||
91 | { | ||
92 | struct maceps2_data *data = (struct maceps2_data *)dev->port_data; | ||
93 | |||
94 | if (request_irq(data->irq, maceps2_interrupt, 0, "PS2 port", dev)) { | ||
95 | printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); | ||
96 | return -EBUSY; | ||
97 | } | ||
98 | |||
99 | /* Reset port */ | ||
100 | data->port->control = PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET; | ||
101 | udelay(100); | ||
102 | |||
103 | /* Enable interrupts */ | ||
104 | data->port->control = PS2_CONTROL_RX_CLOCK_ENABLE | | ||
105 | PS2_CONTROL_TX_ENABLE | | ||
106 | PS2_CONTROL_RX_INT_ENABLE; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void maceps2_close(struct serio *dev) | ||
112 | { | ||
113 | struct maceps2_data *data = (struct maceps2_data *)dev->port_data; | ||
114 | |||
115 | data->port->control = PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET; | ||
116 | udelay(100); | ||
117 | free_irq(data->irq, dev); | ||
118 | } | ||
119 | |||
120 | |||
121 | static struct serio * __init maceps2_allocate_port(int idx) | ||
122 | { | ||
123 | struct serio *serio; | ||
124 | |||
125 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
126 | if (serio) { | ||
127 | memset(serio, 0, sizeof(struct serio)); | ||
128 | serio->id.type = SERIO_8042; | ||
129 | serio->write = maceps2_write; | ||
130 | serio->open = maceps2_open; | ||
131 | serio->close = maceps2_close; | ||
132 | snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx); | ||
133 | snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx); | ||
134 | serio->port_data = &port_data[idx]; | ||
135 | serio->dev.parent = &maceps2_device->dev; | ||
136 | } | ||
137 | |||
138 | return serio; | ||
139 | } | ||
140 | |||
141 | |||
142 | static int __init maceps2_init(void) | ||
143 | { | ||
144 | maceps2_device = platform_device_register_simple("maceps2", -1, NULL, 0); | ||
145 | if (IS_ERR(maceps2_device)) | ||
146 | return PTR_ERR(maceps2_device); | ||
147 | |||
148 | port_data[0].port = &mace->perif.ps2.keyb; | ||
149 | port_data[0].irq = MACEISA_KEYB_IRQ; | ||
150 | port_data[1].port = &mace->perif.ps2.mouse; | ||
151 | port_data[1].irq = MACEISA_MOUSE_IRQ; | ||
152 | |||
153 | maceps2_port[0] = maceps2_allocate_port(0); | ||
154 | maceps2_port[1] = maceps2_allocate_port(1); | ||
155 | if (!maceps2_port[0] || !maceps2_port[1]) { | ||
156 | kfree(maceps2_port[0]); | ||
157 | kfree(maceps2_port[1]); | ||
158 | platform_device_unregister(maceps2_device); | ||
159 | return -ENOMEM; | ||
160 | } | ||
161 | |||
162 | serio_register_port(maceps2_port[0]); | ||
163 | serio_register_port(maceps2_port[1]); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static void __exit maceps2_exit(void) | ||
169 | { | ||
170 | serio_unregister_port(maceps2_port[0]); | ||
171 | serio_unregister_port(maceps2_port[1]); | ||
172 | platform_device_unregister(maceps2_device); | ||
173 | } | ||
174 | |||
175 | module_init(maceps2_init); | ||
176 | module_exit(maceps2_exit); | ||
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c new file mode 100644 index 000000000000..1d15c2819818 --- /dev/null +++ b/drivers/input/serio/parkbd.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * Parallel port to Keyboard port adapter driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 1999-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 | * To connect an AT or XT keyboard to the parallel port, a fairly simple adapter | ||
15 | * can be made: | ||
16 | * | ||
17 | * Parallel port Keyboard port | ||
18 | * | ||
19 | * +5V --------------------- +5V (4) | ||
20 | * | ||
21 | * ______ | ||
22 | * +5V -------|______|--. | ||
23 | * | | ||
24 | * ACK (10) ------------| | ||
25 | * |--- KBD CLOCK (5) | ||
26 | * STROBE (1) ---|<|----' | ||
27 | * | ||
28 | * ______ | ||
29 | * +5V -------|______|--. | ||
30 | * | | ||
31 | * BUSY (11) -----------| | ||
32 | * |--- KBD DATA (1) | ||
33 | * AUTOFD (14) --|<|----' | ||
34 | * | ||
35 | * GND (18-25) ------------- GND (3) | ||
36 | * | ||
37 | * The diodes can be fairly any type, and the resistors should be somewhere | ||
38 | * around 5 kOhm, but the adapter will likely work without the resistors, | ||
39 | * too. | ||
40 | * | ||
41 | * The +5V source can be taken either from USB, from mouse or keyboard ports, | ||
42 | * or from a joystick port. Unfortunately, the parallel port of a PC doesn't | ||
43 | * have a +5V pin, and feeding the keyboard from signal pins is out of question | ||
44 | * with 300 mA power reqirement of a typical AT keyboard. | ||
45 | */ | ||
46 | |||
47 | #include <linux/module.h> | ||
48 | #include <linux/parport.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/serio.h> | ||
51 | |||
52 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
53 | MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver"); | ||
54 | MODULE_LICENSE("GPL"); | ||
55 | |||
56 | static unsigned int parkbd_pp_no; | ||
57 | module_param_named(port, parkbd_pp_no, int, 0); | ||
58 | MODULE_PARM_DESC(port, "Parallel port the adapter is connected to (default is 0)"); | ||
59 | |||
60 | static unsigned int parkbd_mode = SERIO_8042; | ||
61 | module_param_named(mode, parkbd_mode, uint, 0); | ||
62 | MODULE_PARM_DESC(mode, "Mode of operation: XT = 0/AT = 1 (default)"); | ||
63 | |||
64 | #define PARKBD_CLOCK 0x01 /* Strobe & Ack */ | ||
65 | #define PARKBD_DATA 0x02 /* AutoFd & Busy */ | ||
66 | |||
67 | static int parkbd_buffer; | ||
68 | static int parkbd_counter; | ||
69 | static unsigned long parkbd_last; | ||
70 | static int parkbd_writing; | ||
71 | static unsigned long parkbd_start; | ||
72 | |||
73 | static struct pardevice *parkbd_dev; | ||
74 | static struct serio *parkbd_port; | ||
75 | |||
76 | static int parkbd_readlines(void) | ||
77 | { | ||
78 | return (parport_read_status(parkbd_dev->port) >> 6) ^ 2; | ||
79 | } | ||
80 | |||
81 | static void parkbd_writelines(int data) | ||
82 | { | ||
83 | parport_write_control(parkbd_dev->port, (~data & 3) | 0x10); | ||
84 | } | ||
85 | |||
86 | static int parkbd_write(struct serio *port, unsigned char c) | ||
87 | { | ||
88 | unsigned char p; | ||
89 | |||
90 | if (!parkbd_mode) return -1; | ||
91 | |||
92 | p = c ^ (c >> 4); | ||
93 | p = p ^ (p >> 2); | ||
94 | p = p ^ (p >> 1); | ||
95 | |||
96 | parkbd_counter = 0; | ||
97 | parkbd_writing = 1; | ||
98 | parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600; | ||
99 | |||
100 | parkbd_writelines(2); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
106 | { | ||
107 | |||
108 | if (parkbd_writing) { | ||
109 | |||
110 | if (parkbd_counter && ((parkbd_counter == 11) || time_after(jiffies, parkbd_last + HZ/100))) { | ||
111 | parkbd_counter = 0; | ||
112 | parkbd_buffer = 0; | ||
113 | parkbd_writing = 0; | ||
114 | parkbd_writelines(3); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2); | ||
119 | |||
120 | if (parkbd_counter == 11) { | ||
121 | parkbd_counter = 0; | ||
122 | parkbd_buffer = 0; | ||
123 | parkbd_writing = 0; | ||
124 | parkbd_writelines(3); | ||
125 | } | ||
126 | |||
127 | } else { | ||
128 | |||
129 | if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) { | ||
130 | parkbd_counter = 0; | ||
131 | parkbd_buffer = 0; | ||
132 | } | ||
133 | |||
134 | parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; | ||
135 | |||
136 | if (parkbd_counter == parkbd_mode + 10) | ||
137 | serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); | ||
138 | } | ||
139 | |||
140 | parkbd_last = jiffies; | ||
141 | } | ||
142 | |||
143 | static int parkbd_getport(void) | ||
144 | { | ||
145 | struct parport *pp; | ||
146 | |||
147 | pp = parport_find_number(parkbd_pp_no); | ||
148 | |||
149 | if (pp == NULL) { | ||
150 | printk(KERN_ERR "parkbd: no such parport\n"); | ||
151 | return -ENODEV; | ||
152 | } | ||
153 | |||
154 | parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL); | ||
155 | parport_put_port(pp); | ||
156 | |||
157 | if (!parkbd_dev) | ||
158 | return -ENODEV; | ||
159 | |||
160 | if (parport_claim(parkbd_dev)) { | ||
161 | parport_unregister_device(parkbd_dev); | ||
162 | return -EBUSY; | ||
163 | } | ||
164 | |||
165 | parkbd_start = jiffies; | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static struct serio * __init parkbd_allocate_serio(void) | ||
171 | { | ||
172 | struct serio *serio; | ||
173 | |||
174 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
175 | if (serio) { | ||
176 | memset(serio, 0, sizeof(struct serio)); | ||
177 | serio->id.type = parkbd_mode; | ||
178 | serio->write = parkbd_write, | ||
179 | strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); | ||
180 | snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name); | ||
181 | } | ||
182 | |||
183 | return serio; | ||
184 | } | ||
185 | |||
186 | static int __init parkbd_init(void) | ||
187 | { | ||
188 | int err; | ||
189 | |||
190 | err = parkbd_getport(); | ||
191 | if (err) | ||
192 | return err; | ||
193 | |||
194 | parkbd_port = parkbd_allocate_serio(); | ||
195 | if (!parkbd_port) { | ||
196 | parport_release(parkbd_dev); | ||
197 | return -ENOMEM; | ||
198 | } | ||
199 | |||
200 | parkbd_writelines(3); | ||
201 | |||
202 | serio_register_port(parkbd_port); | ||
203 | |||
204 | printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", | ||
205 | parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static void __exit parkbd_exit(void) | ||
211 | { | ||
212 | parport_release(parkbd_dev); | ||
213 | serio_unregister_port(parkbd_port); | ||
214 | parport_unregister_device(parkbd_dev); | ||
215 | } | ||
216 | |||
217 | module_init(parkbd_init); | ||
218 | module_exit(parkbd_exit); | ||
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c new file mode 100644 index 000000000000..1e139c5e59de --- /dev/null +++ b/drivers/input/serio/pcips2.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * linux/drivers/input/serio/pcips2.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Russell King, All Rights Reserved. | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License. | ||
9 | * | ||
10 | * I'm not sure if this is a generic PS/2 PCI interface or specific to | ||
11 | * the Mobility Electronics docking station. | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/input.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/serio.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | #define PS2_CTRL (0) | ||
24 | #define PS2_STATUS (1) | ||
25 | #define PS2_DATA (2) | ||
26 | |||
27 | #define PS2_CTRL_CLK (1<<0) | ||
28 | #define PS2_CTRL_DAT (1<<1) | ||
29 | #define PS2_CTRL_TXIRQ (1<<2) | ||
30 | #define PS2_CTRL_ENABLE (1<<3) | ||
31 | #define PS2_CTRL_RXIRQ (1<<4) | ||
32 | |||
33 | #define PS2_STAT_CLK (1<<0) | ||
34 | #define PS2_STAT_DAT (1<<1) | ||
35 | #define PS2_STAT_PARITY (1<<2) | ||
36 | #define PS2_STAT_RXFULL (1<<5) | ||
37 | #define PS2_STAT_TXBUSY (1<<6) | ||
38 | #define PS2_STAT_TXEMPTY (1<<7) | ||
39 | |||
40 | struct pcips2_data { | ||
41 | struct serio *io; | ||
42 | unsigned int base; | ||
43 | struct pci_dev *dev; | ||
44 | }; | ||
45 | |||
46 | static int pcips2_write(struct serio *io, unsigned char val) | ||
47 | { | ||
48 | struct pcips2_data *ps2if = io->port_data; | ||
49 | unsigned int stat; | ||
50 | |||
51 | do { | ||
52 | stat = inb(ps2if->base + PS2_STATUS); | ||
53 | cpu_relax(); | ||
54 | } while (!(stat & PS2_STAT_TXEMPTY)); | ||
55 | |||
56 | outb(val, ps2if->base + PS2_DATA); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs) | ||
62 | { | ||
63 | struct pcips2_data *ps2if = devid; | ||
64 | unsigned char status, scancode; | ||
65 | int handled = 0; | ||
66 | |||
67 | do { | ||
68 | unsigned int flag; | ||
69 | |||
70 | status = inb(ps2if->base + PS2_STATUS); | ||
71 | if (!(status & PS2_STAT_RXFULL)) | ||
72 | break; | ||
73 | handled = 1; | ||
74 | scancode = inb(ps2if->base + PS2_DATA); | ||
75 | if (status == 0xff && scancode == 0xff) | ||
76 | break; | ||
77 | |||
78 | flag = (status & PS2_STAT_PARITY) ? 0 : SERIO_PARITY; | ||
79 | |||
80 | if (hweight8(scancode) & 1) | ||
81 | flag ^= SERIO_PARITY; | ||
82 | |||
83 | serio_interrupt(ps2if->io, scancode, flag, regs); | ||
84 | } while (1); | ||
85 | return IRQ_RETVAL(handled); | ||
86 | } | ||
87 | |||
88 | static void pcips2_flush_input(struct pcips2_data *ps2if) | ||
89 | { | ||
90 | unsigned char status, scancode; | ||
91 | |||
92 | do { | ||
93 | status = inb(ps2if->base + PS2_STATUS); | ||
94 | if (!(status & PS2_STAT_RXFULL)) | ||
95 | break; | ||
96 | scancode = inb(ps2if->base + PS2_DATA); | ||
97 | if (status == 0xff && scancode == 0xff) | ||
98 | break; | ||
99 | } while (1); | ||
100 | } | ||
101 | |||
102 | static int pcips2_open(struct serio *io) | ||
103 | { | ||
104 | struct pcips2_data *ps2if = io->port_data; | ||
105 | int ret, val = 0; | ||
106 | |||
107 | outb(PS2_CTRL_ENABLE, ps2if->base); | ||
108 | pcips2_flush_input(ps2if); | ||
109 | |||
110 | ret = request_irq(ps2if->dev->irq, pcips2_interrupt, SA_SHIRQ, | ||
111 | "pcips2", ps2if); | ||
112 | if (ret == 0) | ||
113 | val = PS2_CTRL_ENABLE | PS2_CTRL_RXIRQ; | ||
114 | |||
115 | outb(val, ps2if->base); | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static void pcips2_close(struct serio *io) | ||
121 | { | ||
122 | struct pcips2_data *ps2if = io->port_data; | ||
123 | |||
124 | outb(0, ps2if->base); | ||
125 | |||
126 | free_irq(ps2if->dev->irq, ps2if); | ||
127 | } | ||
128 | |||
129 | static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
130 | { | ||
131 | struct pcips2_data *ps2if; | ||
132 | struct serio *serio; | ||
133 | int ret; | ||
134 | |||
135 | ret = pci_enable_device(dev); | ||
136 | if (ret) | ||
137 | goto out; | ||
138 | |||
139 | ret = pci_request_regions(dev, "pcips2"); | ||
140 | if (ret) | ||
141 | goto disable; | ||
142 | |||
143 | ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); | ||
144 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
145 | if (!ps2if || !serio) { | ||
146 | ret = -ENOMEM; | ||
147 | goto release; | ||
148 | } | ||
149 | |||
150 | memset(ps2if, 0, sizeof(struct pcips2_data)); | ||
151 | memset(serio, 0, sizeof(struct serio)); | ||
152 | |||
153 | serio->id.type = SERIO_8042; | ||
154 | serio->write = pcips2_write; | ||
155 | serio->open = pcips2_open; | ||
156 | serio->close = pcips2_close; | ||
157 | strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); | ||
158 | strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); | ||
159 | serio->port_data = ps2if; | ||
160 | serio->dev.parent = &dev->dev; | ||
161 | ps2if->io = serio; | ||
162 | ps2if->dev = dev; | ||
163 | ps2if->base = pci_resource_start(dev, 0); | ||
164 | |||
165 | pci_set_drvdata(dev, ps2if); | ||
166 | |||
167 | serio_register_port(ps2if->io); | ||
168 | return 0; | ||
169 | |||
170 | release: | ||
171 | kfree(ps2if); | ||
172 | kfree(serio); | ||
173 | pci_release_regions(dev); | ||
174 | disable: | ||
175 | pci_disable_device(dev); | ||
176 | out: | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static void __devexit pcips2_remove(struct pci_dev *dev) | ||
181 | { | ||
182 | struct pcips2_data *ps2if = pci_get_drvdata(dev); | ||
183 | |||
184 | serio_unregister_port(ps2if->io); | ||
185 | pci_set_drvdata(dev, NULL); | ||
186 | kfree(ps2if); | ||
187 | pci_release_regions(dev); | ||
188 | pci_disable_device(dev); | ||
189 | } | ||
190 | |||
191 | static struct pci_device_id pcips2_ids[] = { | ||
192 | { | ||
193 | .vendor = 0x14f2, /* MOBILITY */ | ||
194 | .device = 0x0123, /* Keyboard */ | ||
195 | .subvendor = PCI_ANY_ID, | ||
196 | .subdevice = PCI_ANY_ID, | ||
197 | .class = PCI_CLASS_INPUT_KEYBOARD << 8, | ||
198 | .class_mask = 0xffff00, | ||
199 | }, | ||
200 | { | ||
201 | .vendor = 0x14f2, /* MOBILITY */ | ||
202 | .device = 0x0124, /* Mouse */ | ||
203 | .subvendor = PCI_ANY_ID, | ||
204 | .subdevice = PCI_ANY_ID, | ||
205 | .class = PCI_CLASS_INPUT_MOUSE << 8, | ||
206 | .class_mask = 0xffff00, | ||
207 | }, | ||
208 | { 0, } | ||
209 | }; | ||
210 | |||
211 | static struct pci_driver pcips2_driver = { | ||
212 | .name = "pcips2", | ||
213 | .id_table = pcips2_ids, | ||
214 | .probe = pcips2_probe, | ||
215 | .remove = __devexit_p(pcips2_remove), | ||
216 | }; | ||
217 | |||
218 | static int __init pcips2_init(void) | ||
219 | { | ||
220 | return pci_register_driver(&pcips2_driver); | ||
221 | } | ||
222 | |||
223 | static void __exit pcips2_exit(void) | ||
224 | { | ||
225 | pci_unregister_driver(&pcips2_driver); | ||
226 | } | ||
227 | |||
228 | module_init(pcips2_init); | ||
229 | module_exit(pcips2_exit); | ||
230 | |||
231 | MODULE_LICENSE("GPL"); | ||
232 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | ||
233 | MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver"); | ||
234 | MODULE_DEVICE_TABLE(pci, pcips2_ids); | ||
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c new file mode 100644 index 000000000000..46093c507988 --- /dev/null +++ b/drivers/input/serio/q40kbd.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * $Id: q40kbd.c,v 1.12 2002/02/02 22:26:44 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de> | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Q40 PS/2 keyboard controller driver for Linux/m68k | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/serio.h> | ||
37 | #include <linux/interrupt.h> | ||
38 | #include <linux/err.h> | ||
39 | #include <linux/bitops.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/q40_master.h> | ||
44 | #include <asm/irq.h> | ||
45 | #include <asm/q40ints.h> | ||
46 | |||
47 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
48 | MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); | ||
49 | MODULE_LICENSE("GPL"); | ||
50 | |||
51 | DEFINE_SPINLOCK(q40kbd_lock); | ||
52 | static struct serio *q40kbd_port; | ||
53 | static struct platform_device *q40kbd_device; | ||
54 | |||
55 | static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | |||
59 | spin_lock_irqsave(&q40kbd_lock, flags); | ||
60 | |||
61 | if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) | ||
62 | serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs); | ||
63 | |||
64 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
65 | |||
66 | spin_unlock_irqrestore(&q40kbd_lock, flags); | ||
67 | |||
68 | return IRQ_HANDLED; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * q40kbd_flush() flushes all data that may be in the keyboard buffers | ||
73 | */ | ||
74 | |||
75 | static void q40kbd_flush(void) | ||
76 | { | ||
77 | int maxread = 100; | ||
78 | unsigned long flags; | ||
79 | |||
80 | spin_lock_irqsave(&q40kbd_lock, flags); | ||
81 | |||
82 | while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) | ||
83 | master_inb(KEYCODE_REG); | ||
84 | |||
85 | spin_unlock_irqrestore(&q40kbd_lock, flags); | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * q40kbd_open() is called when a port is open by the higher layer. | ||
90 | * It allocates the interrupt and enables in in the chip. | ||
91 | */ | ||
92 | |||
93 | static int q40kbd_open(struct serio *port) | ||
94 | { | ||
95 | q40kbd_flush(); | ||
96 | |||
97 | if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { | ||
98 | printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); | ||
99 | return -1; | ||
100 | } | ||
101 | |||
102 | /* off we go */ | ||
103 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
104 | master_outb(1, KEY_IRQ_ENABLE_REG); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void q40kbd_close(struct serio *port) | ||
110 | { | ||
111 | master_outb(0, KEY_IRQ_ENABLE_REG); | ||
112 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
113 | free_irq(Q40_IRQ_KEYBOARD, NULL); | ||
114 | |||
115 | q40kbd_flush(); | ||
116 | } | ||
117 | |||
118 | static struct serio * __init q40kbd_allocate_port(void) | ||
119 | { | ||
120 | struct serio *serio; | ||
121 | |||
122 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
123 | if (serio) { | ||
124 | memset(serio, 0, sizeof(struct serio)); | ||
125 | serio->id.type = SERIO_8042; | ||
126 | serio->open = q40kbd_open; | ||
127 | serio->close = q40kbd_close; | ||
128 | serio->dev.parent = &q40kbd_device->dev; | ||
129 | strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); | ||
130 | strlcpy(serio->phys, "Q40", sizeof(serio->phys)); | ||
131 | } | ||
132 | |||
133 | return serio; | ||
134 | } | ||
135 | |||
136 | static int __init q40kbd_init(void) | ||
137 | { | ||
138 | if (!MACH_IS_Q40) | ||
139 | return -EIO; | ||
140 | |||
141 | q40kbd_device = platform_device_register_simple("q40kbd", -1, NULL, 0); | ||
142 | if (IS_ERR(q40kbd_device)) | ||
143 | return PTR_ERR(q40kbd_device); | ||
144 | |||
145 | if (!(q40kbd_port = q40kbd_allocate_port())) { | ||
146 | platform_device_unregister(q40kbd_device); | ||
147 | return -ENOMEM; | ||
148 | } | ||
149 | |||
150 | serio_register_port(q40kbd_port); | ||
151 | printk(KERN_INFO "serio: Q40 kbd registered\n"); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static void __exit q40kbd_exit(void) | ||
157 | { | ||
158 | serio_unregister_port(q40kbd_port); | ||
159 | platform_device_unregister(q40kbd_device); | ||
160 | } | ||
161 | |||
162 | module_init(q40kbd_init); | ||
163 | module_exit(q40kbd_exit); | ||
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c new file mode 100644 index 000000000000..106f5eefd89a --- /dev/null +++ b/drivers/input/serio/rpckbd.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * Copyright (c) 2002 Russell King | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * Should you need to contact me, the author, you can do so either by | ||
28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
30 | */ | ||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/serio.h> | ||
36 | #include <linux/err.h> | ||
37 | |||
38 | #include <asm/irq.h> | ||
39 | #include <asm/hardware.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <asm/hardware/iomd.h> | ||
42 | #include <asm/system.h> | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik, Russell King"); | ||
45 | MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | static int rpckbd_write(struct serio *port, unsigned char val) | ||
49 | { | ||
50 | while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) | ||
51 | cpu_relax(); | ||
52 | |||
53 | iomd_writeb(val, IOMD_KARTTX); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs) | ||
59 | { | ||
60 | struct serio *port = dev_id; | ||
61 | unsigned int byte; | ||
62 | int handled = IRQ_NONE; | ||
63 | |||
64 | while (iomd_readb(IOMD_KCTRL) & (1 << 5)) { | ||
65 | byte = iomd_readb(IOMD_KARTRX); | ||
66 | |||
67 | serio_interrupt(port, byte, 0, regs); | ||
68 | handled = IRQ_HANDLED; | ||
69 | } | ||
70 | return handled; | ||
71 | } | ||
72 | |||
73 | static irqreturn_t rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs) | ||
74 | { | ||
75 | return IRQ_HANDLED; | ||
76 | } | ||
77 | |||
78 | static int rpckbd_open(struct serio *port) | ||
79 | { | ||
80 | /* Reset the keyboard state machine. */ | ||
81 | iomd_writeb(0, IOMD_KCTRL); | ||
82 | iomd_writeb(8, IOMD_KCTRL); | ||
83 | iomd_readb(IOMD_KARTRX); | ||
84 | |||
85 | if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) { | ||
86 | printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n"); | ||
87 | return -EBUSY; | ||
88 | } | ||
89 | |||
90 | if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) { | ||
91 | printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n"); | ||
92 | free_irq(IRQ_KEYBOARDRX, NULL); | ||
93 | return -EBUSY; | ||
94 | } | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static void rpckbd_close(struct serio *port) | ||
100 | { | ||
101 | free_irq(IRQ_KEYBOARDRX, port); | ||
102 | free_irq(IRQ_KEYBOARDTX, port); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Allocate and initialize serio structure for subsequent registration | ||
107 | * with serio core. | ||
108 | */ | ||
109 | static int __devinit rpckbd_probe(struct device *dev) | ||
110 | { | ||
111 | struct serio *serio; | ||
112 | |||
113 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
114 | if (!serio) | ||
115 | return -ENOMEM; | ||
116 | |||
117 | memset(serio, 0, sizeof(struct serio)); | ||
118 | serio->id.type = SERIO_8042; | ||
119 | serio->write = rpckbd_write; | ||
120 | serio->open = rpckbd_open; | ||
121 | serio->close = rpckbd_close; | ||
122 | serio->dev.parent = dev; | ||
123 | strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); | ||
124 | strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); | ||
125 | |||
126 | dev_set_drvdata(dev, serio); | ||
127 | serio_register_port(serio); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int __devexit rpckbd_remove(struct device *dev) | ||
132 | { | ||
133 | struct serio *serio = dev_get_drvdata(dev); | ||
134 | serio_unregister_port(serio); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static struct device_driver rpckbd_driver = { | ||
139 | .name = "kart", | ||
140 | .bus = &platform_bus_type, | ||
141 | .probe = rpckbd_probe, | ||
142 | .remove = __devexit_p(rpckbd_remove), | ||
143 | }; | ||
144 | |||
145 | static int __init rpckbd_init(void) | ||
146 | { | ||
147 | return driver_register(&rpckbd_driver); | ||
148 | } | ||
149 | |||
150 | static void __exit rpckbd_exit(void) | ||
151 | { | ||
152 | driver_unregister(&rpckbd_driver); | ||
153 | } | ||
154 | |||
155 | module_init(rpckbd_init); | ||
156 | module_exit(rpckbd_exit); | ||
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c new file mode 100644 index 000000000000..3f0df3330fb2 --- /dev/null +++ b/drivers/input/serio/sa1111ps2.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * linux/drivers/input/serio/sa1111ps2.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Russell King | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License. | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/input.h> | ||
13 | #include <linux/serio.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/irq.h> | ||
24 | #include <asm/system.h> | ||
25 | |||
26 | #include <asm/hardware/sa1111.h> | ||
27 | |||
28 | struct ps2if { | ||
29 | struct serio *io; | ||
30 | struct sa1111_dev *dev; | ||
31 | void __iomem *base; | ||
32 | unsigned int open; | ||
33 | spinlock_t lock; | ||
34 | unsigned int head; | ||
35 | unsigned int tail; | ||
36 | unsigned char buf[4]; | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * Read all bytes waiting in the PS2 port. There should be | ||
41 | * at the most one, but we loop for safety. If there was a | ||
42 | * framing error, we have to manually clear the status. | ||
43 | */ | ||
44 | static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) | ||
45 | { | ||
46 | struct ps2if *ps2if = dev_id; | ||
47 | unsigned int scancode, flag, status; | ||
48 | |||
49 | status = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
50 | while (status & PS2STAT_RXF) { | ||
51 | if (status & PS2STAT_STP) | ||
52 | sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT); | ||
53 | |||
54 | flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) | | ||
55 | (status & PS2STAT_RXP ? 0 : SERIO_PARITY); | ||
56 | |||
57 | scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff; | ||
58 | |||
59 | if (hweight8(scancode) & 1) | ||
60 | flag ^= SERIO_PARITY; | ||
61 | |||
62 | serio_interrupt(ps2if->io, scancode, flag, regs); | ||
63 | |||
64 | status = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
65 | } | ||
66 | |||
67 | return IRQ_HANDLED; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Completion of ps2 write | ||
72 | */ | ||
73 | static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs) | ||
74 | { | ||
75 | struct ps2if *ps2if = dev_id; | ||
76 | unsigned int status; | ||
77 | |||
78 | spin_lock(&ps2if->lock); | ||
79 | status = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
80 | if (ps2if->head == ps2if->tail) { | ||
81 | disable_irq(irq); | ||
82 | /* done */ | ||
83 | } else if (status & PS2STAT_TXE) { | ||
84 | sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA); | ||
85 | ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1); | ||
86 | } | ||
87 | spin_unlock(&ps2if->lock); | ||
88 | |||
89 | return IRQ_HANDLED; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Write a byte to the PS2 port. We have to wait for the | ||
94 | * port to indicate that the transmitter is empty. | ||
95 | */ | ||
96 | static int ps2_write(struct serio *io, unsigned char val) | ||
97 | { | ||
98 | struct ps2if *ps2if = io->port_data; | ||
99 | unsigned long flags; | ||
100 | unsigned int head; | ||
101 | |||
102 | spin_lock_irqsave(&ps2if->lock, flags); | ||
103 | |||
104 | /* | ||
105 | * If the TX register is empty, we can go straight out. | ||
106 | */ | ||
107 | if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) { | ||
108 | sa1111_writel(val, ps2if->base + SA1111_PS2DATA); | ||
109 | } else { | ||
110 | if (ps2if->head == ps2if->tail) | ||
111 | enable_irq(ps2if->dev->irq[1]); | ||
112 | head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1); | ||
113 | if (head != ps2if->tail) { | ||
114 | ps2if->buf[ps2if->head] = val; | ||
115 | ps2if->head = head; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | spin_unlock_irqrestore(&ps2if->lock, flags); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int ps2_open(struct serio *io) | ||
124 | { | ||
125 | struct ps2if *ps2if = io->port_data; | ||
126 | int ret; | ||
127 | |||
128 | sa1111_enable_device(ps2if->dev); | ||
129 | |||
130 | ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0, | ||
131 | SA1111_DRIVER_NAME(ps2if->dev), ps2if); | ||
132 | if (ret) { | ||
133 | printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", | ||
134 | ps2if->dev->irq[0], ret); | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0, | ||
139 | SA1111_DRIVER_NAME(ps2if->dev), ps2if); | ||
140 | if (ret) { | ||
141 | printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", | ||
142 | ps2if->dev->irq[1], ret); | ||
143 | free_irq(ps2if->dev->irq[0], ps2if); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | ps2if->open = 1; | ||
148 | |||
149 | enable_irq_wake(ps2if->dev->irq[0]); | ||
150 | |||
151 | sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void ps2_close(struct serio *io) | ||
156 | { | ||
157 | struct ps2if *ps2if = io->port_data; | ||
158 | |||
159 | sa1111_writel(0, ps2if->base + SA1111_PS2CR); | ||
160 | |||
161 | disable_irq_wake(ps2if->dev->irq[0]); | ||
162 | |||
163 | ps2if->open = 0; | ||
164 | |||
165 | free_irq(ps2if->dev->irq[1], ps2if); | ||
166 | free_irq(ps2if->dev->irq[0], ps2if); | ||
167 | |||
168 | sa1111_disable_device(ps2if->dev); | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Clear the input buffer. | ||
173 | */ | ||
174 | static void __init ps2_clear_input(struct ps2if *ps2if) | ||
175 | { | ||
176 | int maxread = 100; | ||
177 | |||
178 | while (maxread--) { | ||
179 | if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff) | ||
180 | break; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static inline unsigned int | ||
185 | ps2_test_one(struct ps2if *ps2if, unsigned int mask) | ||
186 | { | ||
187 | unsigned int val; | ||
188 | |||
189 | sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR); | ||
190 | |||
191 | udelay(2); | ||
192 | |||
193 | val = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
194 | return val & (PS2STAT_KBC | PS2STAT_KBD); | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Test the keyboard interface. We basically check to make sure that | ||
199 | * we can drive each line to the keyboard independently of each other. | ||
200 | */ | ||
201 | static int __init ps2_test(struct ps2if *ps2if) | ||
202 | { | ||
203 | unsigned int stat; | ||
204 | int ret = 0; | ||
205 | |||
206 | stat = ps2_test_one(ps2if, PS2CR_FKC); | ||
207 | if (stat != PS2STAT_KBD) { | ||
208 | printk("PS/2 interface test failed[1]: %02x\n", stat); | ||
209 | ret = -ENODEV; | ||
210 | } | ||
211 | |||
212 | stat = ps2_test_one(ps2if, 0); | ||
213 | if (stat != (PS2STAT_KBC | PS2STAT_KBD)) { | ||
214 | printk("PS/2 interface test failed[2]: %02x\n", stat); | ||
215 | ret = -ENODEV; | ||
216 | } | ||
217 | |||
218 | stat = ps2_test_one(ps2if, PS2CR_FKD); | ||
219 | if (stat != PS2STAT_KBC) { | ||
220 | printk("PS/2 interface test failed[3]: %02x\n", stat); | ||
221 | ret = -ENODEV; | ||
222 | } | ||
223 | |||
224 | sa1111_writel(0, ps2if->base + SA1111_PS2CR); | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * Add one device to this driver. | ||
231 | */ | ||
232 | static int ps2_probe(struct sa1111_dev *dev) | ||
233 | { | ||
234 | struct ps2if *ps2if; | ||
235 | struct serio *serio; | ||
236 | int ret; | ||
237 | |||
238 | ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); | ||
239 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
240 | if (!ps2if || !serio) { | ||
241 | ret = -ENOMEM; | ||
242 | goto free; | ||
243 | } | ||
244 | |||
245 | memset(ps2if, 0, sizeof(struct ps2if)); | ||
246 | memset(serio, 0, sizeof(struct serio)); | ||
247 | |||
248 | serio->id.type = SERIO_8042; | ||
249 | serio->write = ps2_write; | ||
250 | serio->open = ps2_open; | ||
251 | serio->close = ps2_close; | ||
252 | strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); | ||
253 | strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); | ||
254 | serio->port_data = ps2if; | ||
255 | serio->dev.parent = &dev->dev; | ||
256 | ps2if->io = serio; | ||
257 | ps2if->dev = dev; | ||
258 | sa1111_set_drvdata(dev, ps2if); | ||
259 | |||
260 | spin_lock_init(&ps2if->lock); | ||
261 | |||
262 | /* | ||
263 | * Request the physical region for this PS2 port. | ||
264 | */ | ||
265 | if (!request_mem_region(dev->res.start, | ||
266 | dev->res.end - dev->res.start + 1, | ||
267 | SA1111_DRIVER_NAME(dev))) { | ||
268 | ret = -EBUSY; | ||
269 | goto free; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Our parent device has already mapped the region. | ||
274 | */ | ||
275 | ps2if->base = dev->mapbase; | ||
276 | |||
277 | sa1111_enable_device(ps2if->dev); | ||
278 | |||
279 | /* Incoming clock is 8MHz */ | ||
280 | sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV); | ||
281 | sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT); | ||
282 | |||
283 | /* | ||
284 | * Flush any pending input. | ||
285 | */ | ||
286 | ps2_clear_input(ps2if); | ||
287 | |||
288 | /* | ||
289 | * Test the keyboard interface. | ||
290 | */ | ||
291 | ret = ps2_test(ps2if); | ||
292 | if (ret) | ||
293 | goto out; | ||
294 | |||
295 | /* | ||
296 | * Flush any pending input. | ||
297 | */ | ||
298 | ps2_clear_input(ps2if); | ||
299 | |||
300 | sa1111_disable_device(ps2if->dev); | ||
301 | serio_register_port(ps2if->io); | ||
302 | return 0; | ||
303 | |||
304 | out: | ||
305 | sa1111_disable_device(ps2if->dev); | ||
306 | release_mem_region(dev->res.start, | ||
307 | dev->res.end - dev->res.start + 1); | ||
308 | free: | ||
309 | sa1111_set_drvdata(dev, NULL); | ||
310 | kfree(ps2if); | ||
311 | kfree(serio); | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * Remove one device from this driver. | ||
317 | */ | ||
318 | static int ps2_remove(struct sa1111_dev *dev) | ||
319 | { | ||
320 | struct ps2if *ps2if = sa1111_get_drvdata(dev); | ||
321 | |||
322 | serio_unregister_port(ps2if->io); | ||
323 | release_mem_region(dev->res.start, | ||
324 | dev->res.end - dev->res.start + 1); | ||
325 | sa1111_set_drvdata(dev, NULL); | ||
326 | |||
327 | kfree(ps2if); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Our device driver structure | ||
334 | */ | ||
335 | static struct sa1111_driver ps2_driver = { | ||
336 | .drv = { | ||
337 | .name = "sa1111-ps2", | ||
338 | }, | ||
339 | .devid = SA1111_DEVID_PS2, | ||
340 | .probe = ps2_probe, | ||
341 | .remove = ps2_remove, | ||
342 | }; | ||
343 | |||
344 | static int __init ps2_init(void) | ||
345 | { | ||
346 | return sa1111_driver_register(&ps2_driver); | ||
347 | } | ||
348 | |||
349 | static void __exit ps2_exit(void) | ||
350 | { | ||
351 | sa1111_driver_unregister(&ps2_driver); | ||
352 | } | ||
353 | |||
354 | module_init(ps2_init); | ||
355 | module_exit(ps2_exit); | ||
356 | |||
357 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | ||
358 | MODULE_DESCRIPTION("SA1111 PS2 controller driver"); | ||
359 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c new file mode 100644 index 000000000000..3313e2daeab0 --- /dev/null +++ b/drivers/input/serio/serio.c | |||
@@ -0,0 +1,859 @@ | |||
1 | /* | ||
2 | * The Serio abstraction module | ||
3 | * | ||
4 | * Copyright (c) 1999-2004 Vojtech Pavlik | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | * Copyright (c) 2003 Daniele Bellucci | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Should you need to contact me, the author, you can do so either by | ||
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
27 | */ | ||
28 | |||
29 | #include <linux/stddef.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/serio.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/completion.h> | ||
35 | #include <linux/sched.h> | ||
36 | #include <linux/smp_lock.h> | ||
37 | #include <linux/slab.h> | ||
38 | |||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
40 | MODULE_DESCRIPTION("Serio abstraction core"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | EXPORT_SYMBOL(serio_interrupt); | ||
44 | EXPORT_SYMBOL(__serio_register_port); | ||
45 | EXPORT_SYMBOL(serio_unregister_port); | ||
46 | EXPORT_SYMBOL(__serio_unregister_port_delayed); | ||
47 | EXPORT_SYMBOL(__serio_register_driver); | ||
48 | EXPORT_SYMBOL(serio_unregister_driver); | ||
49 | EXPORT_SYMBOL(serio_open); | ||
50 | EXPORT_SYMBOL(serio_close); | ||
51 | EXPORT_SYMBOL(serio_rescan); | ||
52 | EXPORT_SYMBOL(serio_reconnect); | ||
53 | |||
54 | /* | ||
55 | * serio_sem protects entire serio subsystem and is taken every time | ||
56 | * serio port or driver registrered or unregistered. | ||
57 | */ | ||
58 | static DECLARE_MUTEX(serio_sem); | ||
59 | |||
60 | static LIST_HEAD(serio_list); | ||
61 | |||
62 | static struct bus_type serio_bus = { | ||
63 | .name = "serio", | ||
64 | }; | ||
65 | |||
66 | static void serio_add_port(struct serio *serio); | ||
67 | static void serio_destroy_port(struct serio *serio); | ||
68 | static void serio_reconnect_port(struct serio *serio); | ||
69 | static void serio_disconnect_port(struct serio *serio); | ||
70 | |||
71 | static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) | ||
72 | { | ||
73 | while (ids->type || ids->proto) { | ||
74 | if ((ids->type == SERIO_ANY || ids->type == serio->id.type) && | ||
75 | (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) && | ||
76 | (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) && | ||
77 | (ids->id == SERIO_ANY || ids->id == serio->id.id)) | ||
78 | return 1; | ||
79 | ids++; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Basic serio -> driver core mappings | ||
86 | */ | ||
87 | |||
88 | static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) | ||
89 | { | ||
90 | down_write(&serio_bus.subsys.rwsem); | ||
91 | |||
92 | if (serio_match_port(drv->id_table, serio)) { | ||
93 | serio->dev.driver = &drv->driver; | ||
94 | if (drv->connect(serio, drv)) { | ||
95 | serio->dev.driver = NULL; | ||
96 | goto out; | ||
97 | } | ||
98 | device_bind_driver(&serio->dev); | ||
99 | } | ||
100 | out: | ||
101 | up_write(&serio_bus.subsys.rwsem); | ||
102 | } | ||
103 | |||
104 | static void serio_release_driver(struct serio *serio) | ||
105 | { | ||
106 | down_write(&serio_bus.subsys.rwsem); | ||
107 | device_release_driver(&serio->dev); | ||
108 | up_write(&serio_bus.subsys.rwsem); | ||
109 | } | ||
110 | |||
111 | static void serio_find_driver(struct serio *serio) | ||
112 | { | ||
113 | down_write(&serio_bus.subsys.rwsem); | ||
114 | device_attach(&serio->dev); | ||
115 | up_write(&serio_bus.subsys.rwsem); | ||
116 | } | ||
117 | |||
118 | |||
119 | /* | ||
120 | * Serio event processing. | ||
121 | */ | ||
122 | |||
123 | enum serio_event_type { | ||
124 | SERIO_RESCAN, | ||
125 | SERIO_RECONNECT, | ||
126 | SERIO_REGISTER_PORT, | ||
127 | SERIO_UNREGISTER_PORT, | ||
128 | SERIO_REGISTER_DRIVER, | ||
129 | }; | ||
130 | |||
131 | struct serio_event { | ||
132 | enum serio_event_type type; | ||
133 | void *object; | ||
134 | struct module *owner; | ||
135 | struct list_head node; | ||
136 | }; | ||
137 | |||
138 | static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ | ||
139 | static LIST_HEAD(serio_event_list); | ||
140 | static DECLARE_WAIT_QUEUE_HEAD(serio_wait); | ||
141 | static DECLARE_COMPLETION(serio_exited); | ||
142 | static int serio_pid; | ||
143 | |||
144 | static void serio_queue_event(void *object, struct module *owner, | ||
145 | enum serio_event_type event_type) | ||
146 | { | ||
147 | unsigned long flags; | ||
148 | struct serio_event *event; | ||
149 | |||
150 | spin_lock_irqsave(&serio_event_lock, flags); | ||
151 | |||
152 | /* | ||
153 | * Scan event list for the other events for the same serio port, | ||
154 | * starting with the most recent one. If event is the same we | ||
155 | * do not need add new one. If event is of different type we | ||
156 | * need to add this event and should not look further because | ||
157 | * we need to preseve sequence of distinct events. | ||
158 | */ | ||
159 | list_for_each_entry_reverse(event, &serio_event_list, node) { | ||
160 | if (event->object == object) { | ||
161 | if (event->type == event_type) | ||
162 | goto out; | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { | ||
168 | if (!try_module_get(owner)) { | ||
169 | printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | event->type = event_type; | ||
174 | event->object = object; | ||
175 | event->owner = owner; | ||
176 | |||
177 | list_add_tail(&event->node, &serio_event_list); | ||
178 | wake_up(&serio_wait); | ||
179 | } else { | ||
180 | printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type); | ||
181 | } | ||
182 | out: | ||
183 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
184 | } | ||
185 | |||
186 | static void serio_free_event(struct serio_event *event) | ||
187 | { | ||
188 | module_put(event->owner); | ||
189 | kfree(event); | ||
190 | } | ||
191 | |||
192 | static void serio_remove_duplicate_events(struct serio_event *event) | ||
193 | { | ||
194 | struct list_head *node, *next; | ||
195 | struct serio_event *e; | ||
196 | unsigned long flags; | ||
197 | |||
198 | spin_lock_irqsave(&serio_event_lock, flags); | ||
199 | |||
200 | list_for_each_safe(node, next, &serio_event_list) { | ||
201 | e = list_entry(node, struct serio_event, node); | ||
202 | if (event->object == e->object) { | ||
203 | /* | ||
204 | * If this event is of different type we should not | ||
205 | * look further - we only suppress duplicate events | ||
206 | * that were sent back-to-back. | ||
207 | */ | ||
208 | if (event->type != e->type) | ||
209 | break; | ||
210 | |||
211 | list_del_init(node); | ||
212 | serio_free_event(e); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
217 | } | ||
218 | |||
219 | |||
220 | static struct serio_event *serio_get_event(void) | ||
221 | { | ||
222 | struct serio_event *event; | ||
223 | struct list_head *node; | ||
224 | unsigned long flags; | ||
225 | |||
226 | spin_lock_irqsave(&serio_event_lock, flags); | ||
227 | |||
228 | if (list_empty(&serio_event_list)) { | ||
229 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
230 | return NULL; | ||
231 | } | ||
232 | |||
233 | node = serio_event_list.next; | ||
234 | event = list_entry(node, struct serio_event, node); | ||
235 | list_del_init(node); | ||
236 | |||
237 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
238 | |||
239 | return event; | ||
240 | } | ||
241 | |||
242 | static void serio_handle_events(void) | ||
243 | { | ||
244 | struct serio_event *event; | ||
245 | struct serio_driver *serio_drv; | ||
246 | |||
247 | down(&serio_sem); | ||
248 | |||
249 | while ((event = serio_get_event())) { | ||
250 | |||
251 | switch (event->type) { | ||
252 | case SERIO_REGISTER_PORT: | ||
253 | serio_add_port(event->object); | ||
254 | break; | ||
255 | |||
256 | case SERIO_UNREGISTER_PORT: | ||
257 | serio_disconnect_port(event->object); | ||
258 | serio_destroy_port(event->object); | ||
259 | break; | ||
260 | |||
261 | case SERIO_RECONNECT: | ||
262 | serio_reconnect_port(event->object); | ||
263 | break; | ||
264 | |||
265 | case SERIO_RESCAN: | ||
266 | serio_disconnect_port(event->object); | ||
267 | serio_find_driver(event->object); | ||
268 | break; | ||
269 | |||
270 | case SERIO_REGISTER_DRIVER: | ||
271 | serio_drv = event->object; | ||
272 | driver_register(&serio_drv->driver); | ||
273 | break; | ||
274 | |||
275 | default: | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | serio_remove_duplicate_events(event); | ||
280 | serio_free_event(event); | ||
281 | } | ||
282 | |||
283 | up(&serio_sem); | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Remove all events that have been submitted for a given serio port. | ||
288 | */ | ||
289 | static void serio_remove_pending_events(struct serio *serio) | ||
290 | { | ||
291 | struct list_head *node, *next; | ||
292 | struct serio_event *event; | ||
293 | unsigned long flags; | ||
294 | |||
295 | spin_lock_irqsave(&serio_event_lock, flags); | ||
296 | |||
297 | list_for_each_safe(node, next, &serio_event_list) { | ||
298 | event = list_entry(node, struct serio_event, node); | ||
299 | if (event->object == serio) { | ||
300 | list_del_init(node); | ||
301 | serio_free_event(event); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * Destroy child serio port (if any) that has not been fully registered yet. | ||
310 | * | ||
311 | * Note that we rely on the fact that port can have only one child and therefore | ||
312 | * only one child registration request can be pending. Additionally, children | ||
313 | * are registered by driver's connect() handler so there can't be a grandchild | ||
314 | * pending registration together with a child. | ||
315 | */ | ||
316 | static struct serio *serio_get_pending_child(struct serio *parent) | ||
317 | { | ||
318 | struct serio_event *event; | ||
319 | struct serio *serio, *child = NULL; | ||
320 | unsigned long flags; | ||
321 | |||
322 | spin_lock_irqsave(&serio_event_lock, flags); | ||
323 | |||
324 | list_for_each_entry(event, &serio_event_list, node) { | ||
325 | if (event->type == SERIO_REGISTER_PORT) { | ||
326 | serio = event->object; | ||
327 | if (serio->parent == parent) { | ||
328 | child = serio; | ||
329 | break; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | |||
334 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
335 | return child; | ||
336 | } | ||
337 | |||
338 | static int serio_thread(void *nothing) | ||
339 | { | ||
340 | lock_kernel(); | ||
341 | daemonize("kseriod"); | ||
342 | allow_signal(SIGTERM); | ||
343 | |||
344 | do { | ||
345 | serio_handle_events(); | ||
346 | wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); | ||
347 | try_to_freeze(PF_FREEZE); | ||
348 | } while (!signal_pending(current)); | ||
349 | |||
350 | printk(KERN_DEBUG "serio: kseriod exiting\n"); | ||
351 | |||
352 | unlock_kernel(); | ||
353 | complete_and_exit(&serio_exited, 0); | ||
354 | } | ||
355 | |||
356 | |||
357 | /* | ||
358 | * Serio port operations | ||
359 | */ | ||
360 | |||
361 | static ssize_t serio_show_description(struct device *dev, char *buf) | ||
362 | { | ||
363 | struct serio *serio = to_serio_port(dev); | ||
364 | return sprintf(buf, "%s\n", serio->name); | ||
365 | } | ||
366 | |||
367 | static ssize_t serio_show_id_type(struct device *dev, char *buf) | ||
368 | { | ||
369 | struct serio *serio = to_serio_port(dev); | ||
370 | return sprintf(buf, "%02x\n", serio->id.type); | ||
371 | } | ||
372 | |||
373 | static ssize_t serio_show_id_proto(struct device *dev, char *buf) | ||
374 | { | ||
375 | struct serio *serio = to_serio_port(dev); | ||
376 | return sprintf(buf, "%02x\n", serio->id.proto); | ||
377 | } | ||
378 | |||
379 | static ssize_t serio_show_id_id(struct device *dev, char *buf) | ||
380 | { | ||
381 | struct serio *serio = to_serio_port(dev); | ||
382 | return sprintf(buf, "%02x\n", serio->id.id); | ||
383 | } | ||
384 | |||
385 | static ssize_t serio_show_id_extra(struct device *dev, char *buf) | ||
386 | { | ||
387 | struct serio *serio = to_serio_port(dev); | ||
388 | return sprintf(buf, "%02x\n", serio->id.extra); | ||
389 | } | ||
390 | |||
391 | static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) | ||
392 | { | ||
393 | struct serio *serio = to_serio_port(dev); | ||
394 | struct device_driver *drv; | ||
395 | int retval; | ||
396 | |||
397 | retval = down_interruptible(&serio_sem); | ||
398 | if (retval) | ||
399 | return retval; | ||
400 | |||
401 | retval = count; | ||
402 | if (!strncmp(buf, "none", count)) { | ||
403 | serio_disconnect_port(serio); | ||
404 | } else if (!strncmp(buf, "reconnect", count)) { | ||
405 | serio_reconnect_port(serio); | ||
406 | } else if (!strncmp(buf, "rescan", count)) { | ||
407 | serio_disconnect_port(serio); | ||
408 | serio_find_driver(serio); | ||
409 | } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { | ||
410 | serio_disconnect_port(serio); | ||
411 | serio_bind_driver(serio, to_serio_driver(drv)); | ||
412 | put_driver(drv); | ||
413 | } else { | ||
414 | retval = -EINVAL; | ||
415 | } | ||
416 | |||
417 | up(&serio_sem); | ||
418 | |||
419 | return retval; | ||
420 | } | ||
421 | |||
422 | static ssize_t serio_show_bind_mode(struct device *dev, char *buf) | ||
423 | { | ||
424 | struct serio *serio = to_serio_port(dev); | ||
425 | return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); | ||
426 | } | ||
427 | |||
428 | static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count) | ||
429 | { | ||
430 | struct serio *serio = to_serio_port(dev); | ||
431 | int retval; | ||
432 | |||
433 | retval = count; | ||
434 | if (!strncmp(buf, "manual", count)) { | ||
435 | serio->manual_bind = 1; | ||
436 | } else if (!strncmp(buf, "auto", count)) { | ||
437 | serio->manual_bind = 0; | ||
438 | } else { | ||
439 | retval = -EINVAL; | ||
440 | } | ||
441 | |||
442 | return retval; | ||
443 | } | ||
444 | |||
445 | static struct device_attribute serio_device_attrs[] = { | ||
446 | __ATTR(description, S_IRUGO, serio_show_description, NULL), | ||
447 | __ATTR(id_type, S_IRUGO, serio_show_id_type, NULL), | ||
448 | __ATTR(id_proto, S_IRUGO, serio_show_id_proto, NULL), | ||
449 | __ATTR(id_id, S_IRUGO, serio_show_id_id, NULL), | ||
450 | __ATTR(id_extra, S_IRUGO, serio_show_id_extra, NULL), | ||
451 | __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), | ||
452 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), | ||
453 | __ATTR_NULL | ||
454 | }; | ||
455 | |||
456 | |||
457 | static void serio_release_port(struct device *dev) | ||
458 | { | ||
459 | struct serio *serio = to_serio_port(dev); | ||
460 | |||
461 | kfree(serio); | ||
462 | module_put(THIS_MODULE); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Prepare serio port for registration. | ||
467 | */ | ||
468 | static void serio_init_port(struct serio *serio) | ||
469 | { | ||
470 | static atomic_t serio_no = ATOMIC_INIT(0); | ||
471 | |||
472 | __module_get(THIS_MODULE); | ||
473 | |||
474 | spin_lock_init(&serio->lock); | ||
475 | init_MUTEX(&serio->drv_sem); | ||
476 | device_initialize(&serio->dev); | ||
477 | snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), | ||
478 | "serio%ld", (long)atomic_inc_return(&serio_no) - 1); | ||
479 | serio->dev.bus = &serio_bus; | ||
480 | serio->dev.release = serio_release_port; | ||
481 | if (serio->parent) | ||
482 | serio->dev.parent = &serio->parent->dev; | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * Complete serio port registration. | ||
487 | * Driver core will attempt to find appropriate driver for the port. | ||
488 | */ | ||
489 | static void serio_add_port(struct serio *serio) | ||
490 | { | ||
491 | if (serio->parent) { | ||
492 | serio_pause_rx(serio->parent); | ||
493 | serio->parent->child = serio; | ||
494 | serio_continue_rx(serio->parent); | ||
495 | } | ||
496 | |||
497 | list_add_tail(&serio->node, &serio_list); | ||
498 | if (serio->start) | ||
499 | serio->start(serio); | ||
500 | device_add(&serio->dev); | ||
501 | serio->registered = 1; | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | * serio_destroy_port() completes deregistration process and removes | ||
506 | * port from the system | ||
507 | */ | ||
508 | static void serio_destroy_port(struct serio *serio) | ||
509 | { | ||
510 | struct serio *child; | ||
511 | |||
512 | child = serio_get_pending_child(serio); | ||
513 | if (child) { | ||
514 | serio_remove_pending_events(child); | ||
515 | put_device(&child->dev); | ||
516 | } | ||
517 | |||
518 | if (serio->stop) | ||
519 | serio->stop(serio); | ||
520 | |||
521 | if (serio->parent) { | ||
522 | serio_pause_rx(serio->parent); | ||
523 | serio->parent->child = NULL; | ||
524 | serio_continue_rx(serio->parent); | ||
525 | serio->parent = NULL; | ||
526 | } | ||
527 | |||
528 | if (serio->registered) { | ||
529 | device_del(&serio->dev); | ||
530 | list_del_init(&serio->node); | ||
531 | serio->registered = 0; | ||
532 | } | ||
533 | |||
534 | serio_remove_pending_events(serio); | ||
535 | put_device(&serio->dev); | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Reconnect serio port and all its children (re-initialize attached devices) | ||
540 | */ | ||
541 | static void serio_reconnect_port(struct serio *serio) | ||
542 | { | ||
543 | do { | ||
544 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | ||
545 | serio_disconnect_port(serio); | ||
546 | serio_find_driver(serio); | ||
547 | /* Ok, old children are now gone, we are done */ | ||
548 | break; | ||
549 | } | ||
550 | serio = serio->child; | ||
551 | } while (serio); | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * serio_disconnect_port() unbinds a port from its driver. As a side effect | ||
556 | * all child ports are unbound and destroyed. | ||
557 | */ | ||
558 | static void serio_disconnect_port(struct serio *serio) | ||
559 | { | ||
560 | struct serio *s, *parent; | ||
561 | |||
562 | if (serio->child) { | ||
563 | /* | ||
564 | * Children ports should be disconnected and destroyed | ||
565 | * first, staring with the leaf one, since we don't want | ||
566 | * to do recursion | ||
567 | */ | ||
568 | for (s = serio; s->child; s = s->child) | ||
569 | /* empty */; | ||
570 | |||
571 | do { | ||
572 | parent = s->parent; | ||
573 | |||
574 | serio_release_driver(s); | ||
575 | serio_destroy_port(s); | ||
576 | } while ((s = parent) != serio); | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * Ok, no children left, now disconnect this port | ||
581 | */ | ||
582 | serio_release_driver(serio); | ||
583 | } | ||
584 | |||
585 | void serio_rescan(struct serio *serio) | ||
586 | { | ||
587 | serio_queue_event(serio, NULL, SERIO_RESCAN); | ||
588 | } | ||
589 | |||
590 | void serio_reconnect(struct serio *serio) | ||
591 | { | ||
592 | serio_queue_event(serio, NULL, SERIO_RECONNECT); | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * Submits register request to kseriod for subsequent execution. | ||
597 | * Note that port registration is always asynchronous. | ||
598 | */ | ||
599 | void __serio_register_port(struct serio *serio, struct module *owner) | ||
600 | { | ||
601 | serio_init_port(serio); | ||
602 | serio_queue_event(serio, owner, SERIO_REGISTER_PORT); | ||
603 | } | ||
604 | |||
605 | /* | ||
606 | * Synchronously unregisters serio port. | ||
607 | */ | ||
608 | void serio_unregister_port(struct serio *serio) | ||
609 | { | ||
610 | down(&serio_sem); | ||
611 | serio_disconnect_port(serio); | ||
612 | serio_destroy_port(serio); | ||
613 | up(&serio_sem); | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * Submits register request to kseriod for subsequent execution. | ||
618 | * Can be used when it is not obvious whether the serio_sem is | ||
619 | * taken or not and when delayed execution is feasible. | ||
620 | */ | ||
621 | void __serio_unregister_port_delayed(struct serio *serio, struct module *owner) | ||
622 | { | ||
623 | serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT); | ||
624 | } | ||
625 | |||
626 | |||
627 | /* | ||
628 | * Serio driver operations | ||
629 | */ | ||
630 | |||
631 | static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) | ||
632 | { | ||
633 | struct serio_driver *driver = to_serio_driver(drv); | ||
634 | return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); | ||
635 | } | ||
636 | |||
637 | static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf) | ||
638 | { | ||
639 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
640 | return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); | ||
641 | } | ||
642 | |||
643 | static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count) | ||
644 | { | ||
645 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
646 | int retval; | ||
647 | |||
648 | retval = count; | ||
649 | if (!strncmp(buf, "manual", count)) { | ||
650 | serio_drv->manual_bind = 1; | ||
651 | } else if (!strncmp(buf, "auto", count)) { | ||
652 | serio_drv->manual_bind = 0; | ||
653 | } else { | ||
654 | retval = -EINVAL; | ||
655 | } | ||
656 | |||
657 | return retval; | ||
658 | } | ||
659 | |||
660 | |||
661 | static struct driver_attribute serio_driver_attrs[] = { | ||
662 | __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), | ||
663 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, | ||
664 | serio_driver_show_bind_mode, serio_driver_set_bind_mode), | ||
665 | __ATTR_NULL | ||
666 | }; | ||
667 | |||
668 | static int serio_driver_probe(struct device *dev) | ||
669 | { | ||
670 | struct serio *serio = to_serio_port(dev); | ||
671 | struct serio_driver *drv = to_serio_driver(dev->driver); | ||
672 | |||
673 | return drv->connect(serio, drv); | ||
674 | } | ||
675 | |||
676 | static int serio_driver_remove(struct device *dev) | ||
677 | { | ||
678 | struct serio *serio = to_serio_port(dev); | ||
679 | struct serio_driver *drv = to_serio_driver(dev->driver); | ||
680 | |||
681 | drv->disconnect(serio); | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | void __serio_register_driver(struct serio_driver *drv, struct module *owner) | ||
686 | { | ||
687 | drv->driver.bus = &serio_bus; | ||
688 | drv->driver.probe = serio_driver_probe; | ||
689 | drv->driver.remove = serio_driver_remove; | ||
690 | |||
691 | serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER); | ||
692 | } | ||
693 | |||
694 | void serio_unregister_driver(struct serio_driver *drv) | ||
695 | { | ||
696 | struct serio *serio; | ||
697 | |||
698 | down(&serio_sem); | ||
699 | drv->manual_bind = 1; /* so serio_find_driver ignores it */ | ||
700 | |||
701 | start_over: | ||
702 | list_for_each_entry(serio, &serio_list, node) { | ||
703 | if (serio->drv == drv) { | ||
704 | serio_disconnect_port(serio); | ||
705 | serio_find_driver(serio); | ||
706 | /* we could've deleted some ports, restart */ | ||
707 | goto start_over; | ||
708 | } | ||
709 | } | ||
710 | |||
711 | driver_unregister(&drv->driver); | ||
712 | up(&serio_sem); | ||
713 | } | ||
714 | |||
715 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) | ||
716 | { | ||
717 | down(&serio->drv_sem); | ||
718 | serio_pause_rx(serio); | ||
719 | serio->drv = drv; | ||
720 | serio_continue_rx(serio); | ||
721 | up(&serio->drv_sem); | ||
722 | } | ||
723 | |||
724 | static int serio_bus_match(struct device *dev, struct device_driver *drv) | ||
725 | { | ||
726 | struct serio *serio = to_serio_port(dev); | ||
727 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
728 | |||
729 | if (serio->manual_bind || serio_drv->manual_bind) | ||
730 | return 0; | ||
731 | |||
732 | return serio_match_port(serio_drv->id_table, serio); | ||
733 | } | ||
734 | |||
735 | #ifdef CONFIG_HOTPLUG | ||
736 | |||
737 | #define PUT_ENVP(fmt, val) \ | ||
738 | do { \ | ||
739 | envp[i++] = buffer; \ | ||
740 | length += snprintf(buffer, buffer_size - length, fmt, val); \ | ||
741 | if (buffer_size - length <= 0 || i >= num_envp) \ | ||
742 | return -ENOMEM; \ | ||
743 | length++; \ | ||
744 | buffer += length; \ | ||
745 | } while (0) | ||
746 | static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | ||
747 | { | ||
748 | struct serio *serio; | ||
749 | int i = 0; | ||
750 | int length = 0; | ||
751 | |||
752 | if (!dev) | ||
753 | return -ENODEV; | ||
754 | |||
755 | serio = to_serio_port(dev); | ||
756 | |||
757 | PUT_ENVP("SERIO_TYPE=%02x", serio->id.type); | ||
758 | PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto); | ||
759 | PUT_ENVP("SERIO_ID=%02x", serio->id.id); | ||
760 | PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra); | ||
761 | |||
762 | envp[i] = NULL; | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | #undef PUT_ENVP | ||
767 | |||
768 | #else | ||
769 | |||
770 | static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | ||
771 | { | ||
772 | return -ENODEV; | ||
773 | } | ||
774 | |||
775 | #endif /* CONFIG_HOTPLUG */ | ||
776 | |||
777 | static int serio_resume(struct device *dev) | ||
778 | { | ||
779 | struct serio *serio = to_serio_port(dev); | ||
780 | |||
781 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | ||
782 | serio_disconnect_port(serio); | ||
783 | /* | ||
784 | * Driver re-probing can take a while, so better let kseriod | ||
785 | * deal with it. | ||
786 | */ | ||
787 | serio_rescan(serio); | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | /* called from serio_driver->connect/disconnect methods under serio_sem */ | ||
794 | int serio_open(struct serio *serio, struct serio_driver *drv) | ||
795 | { | ||
796 | serio_set_drv(serio, drv); | ||
797 | |||
798 | if (serio->open && serio->open(serio)) { | ||
799 | serio_set_drv(serio, NULL); | ||
800 | return -1; | ||
801 | } | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | /* called from serio_driver->connect/disconnect methods under serio_sem */ | ||
806 | void serio_close(struct serio *serio) | ||
807 | { | ||
808 | if (serio->close) | ||
809 | serio->close(serio); | ||
810 | |||
811 | serio_set_drv(serio, NULL); | ||
812 | } | ||
813 | |||
814 | irqreturn_t serio_interrupt(struct serio *serio, | ||
815 | unsigned char data, unsigned int dfl, struct pt_regs *regs) | ||
816 | { | ||
817 | unsigned long flags; | ||
818 | irqreturn_t ret = IRQ_NONE; | ||
819 | |||
820 | spin_lock_irqsave(&serio->lock, flags); | ||
821 | |||
822 | if (likely(serio->drv)) { | ||
823 | ret = serio->drv->interrupt(serio, data, dfl, regs); | ||
824 | } else if (!dfl && serio->registered) { | ||
825 | serio_rescan(serio); | ||
826 | ret = IRQ_HANDLED; | ||
827 | } | ||
828 | |||
829 | spin_unlock_irqrestore(&serio->lock, flags); | ||
830 | |||
831 | return ret; | ||
832 | } | ||
833 | |||
834 | static int __init serio_init(void) | ||
835 | { | ||
836 | if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { | ||
837 | printk(KERN_ERR "serio: Failed to start kseriod\n"); | ||
838 | return -1; | ||
839 | } | ||
840 | |||
841 | serio_bus.dev_attrs = serio_device_attrs; | ||
842 | serio_bus.drv_attrs = serio_driver_attrs; | ||
843 | serio_bus.match = serio_bus_match; | ||
844 | serio_bus.hotplug = serio_hotplug; | ||
845 | serio_bus.resume = serio_resume; | ||
846 | bus_register(&serio_bus); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static void __exit serio_exit(void) | ||
852 | { | ||
853 | bus_unregister(&serio_bus); | ||
854 | kill_proc(serio_pid, SIGTERM, 1); | ||
855 | wait_for_completion(&serio_exited); | ||
856 | } | ||
857 | |||
858 | module_init(serio_init); | ||
859 | module_exit(serio_exit); | ||
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c new file mode 100644 index 000000000000..d914e7e93db4 --- /dev/null +++ b/drivers/input/serio/serio_raw.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * Raw serio device providing access to a raw byte stream from underlying | ||
3 | * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device | ||
4 | * | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <linux/poll.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/serio.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/major.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/devfs_fs_kernel.h> | ||
20 | #include <linux/miscdevice.h> | ||
21 | #include <linux/wait.h> | ||
22 | |||
23 | #define DRIVER_DESC "Raw serio driver" | ||
24 | |||
25 | MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); | ||
26 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
27 | MODULE_LICENSE("GPL"); | ||
28 | |||
29 | #define SERIO_RAW_QUEUE_LEN 64 | ||
30 | struct serio_raw { | ||
31 | unsigned char queue[SERIO_RAW_QUEUE_LEN]; | ||
32 | unsigned int tail, head; | ||
33 | |||
34 | char name[16]; | ||
35 | unsigned int refcnt; | ||
36 | struct serio *serio; | ||
37 | struct miscdevice dev; | ||
38 | wait_queue_head_t wait; | ||
39 | struct list_head list; | ||
40 | struct list_head node; | ||
41 | }; | ||
42 | |||
43 | struct serio_raw_list { | ||
44 | struct fasync_struct *fasync; | ||
45 | struct serio_raw *serio_raw; | ||
46 | struct list_head node; | ||
47 | }; | ||
48 | |||
49 | static DECLARE_MUTEX(serio_raw_sem); | ||
50 | static LIST_HEAD(serio_raw_list); | ||
51 | static unsigned int serio_raw_no; | ||
52 | |||
53 | /********************************************************************* | ||
54 | * Interface with userspace (file operations) * | ||
55 | *********************************************************************/ | ||
56 | |||
57 | static int serio_raw_fasync(int fd, struct file *file, int on) | ||
58 | { | ||
59 | struct serio_raw_list *list = file->private_data; | ||
60 | int retval; | ||
61 | |||
62 | retval = fasync_helper(fd, file, on, &list->fasync); | ||
63 | return retval < 0 ? retval : 0; | ||
64 | } | ||
65 | |||
66 | static struct serio_raw *serio_raw_locate(int minor) | ||
67 | { | ||
68 | struct serio_raw *serio_raw; | ||
69 | |||
70 | list_for_each_entry(serio_raw, &serio_raw_list, node) { | ||
71 | if (serio_raw->dev.minor == minor) | ||
72 | return serio_raw; | ||
73 | } | ||
74 | |||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | static int serio_raw_open(struct inode *inode, struct file *file) | ||
79 | { | ||
80 | struct serio_raw *serio_raw; | ||
81 | struct serio_raw_list *list; | ||
82 | int retval = 0; | ||
83 | |||
84 | retval = down_interruptible(&serio_raw_sem); | ||
85 | if (retval) | ||
86 | return retval; | ||
87 | |||
88 | if (!(serio_raw = serio_raw_locate(iminor(inode)))) { | ||
89 | retval = -ENODEV; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | if (!serio_raw->serio) { | ||
94 | retval = -ENODEV; | ||
95 | goto out; | ||
96 | } | ||
97 | |||
98 | if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { | ||
99 | retval = -ENOMEM; | ||
100 | goto out; | ||
101 | } | ||
102 | |||
103 | memset(list, 0, sizeof(struct serio_raw_list)); | ||
104 | list->serio_raw = serio_raw; | ||
105 | file->private_data = list; | ||
106 | |||
107 | serio_raw->refcnt++; | ||
108 | list_add_tail(&list->node, &serio_raw->list); | ||
109 | |||
110 | out: | ||
111 | up(&serio_raw_sem); | ||
112 | return retval; | ||
113 | } | ||
114 | |||
115 | static int serio_raw_cleanup(struct serio_raw *serio_raw) | ||
116 | { | ||
117 | if (--serio_raw->refcnt == 0) { | ||
118 | misc_deregister(&serio_raw->dev); | ||
119 | list_del_init(&serio_raw->node); | ||
120 | kfree(serio_raw); | ||
121 | |||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int serio_raw_release(struct inode *inode, struct file *file) | ||
129 | { | ||
130 | struct serio_raw_list *list = file->private_data; | ||
131 | struct serio_raw *serio_raw = list->serio_raw; | ||
132 | |||
133 | down(&serio_raw_sem); | ||
134 | |||
135 | serio_raw_fasync(-1, file, 0); | ||
136 | serio_raw_cleanup(serio_raw); | ||
137 | |||
138 | up(&serio_raw_sem); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) | ||
143 | { | ||
144 | unsigned long flags; | ||
145 | int empty; | ||
146 | |||
147 | spin_lock_irqsave(&serio_raw->serio->lock, flags); | ||
148 | |||
149 | empty = serio_raw->head == serio_raw->tail; | ||
150 | if (!empty) { | ||
151 | *c = serio_raw->queue[serio_raw->tail]; | ||
152 | serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; | ||
153 | } | ||
154 | |||
155 | spin_unlock_irqrestore(&serio_raw->serio->lock, flags); | ||
156 | |||
157 | return !empty; | ||
158 | } | ||
159 | |||
160 | static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | ||
161 | { | ||
162 | struct serio_raw_list *list = file->private_data; | ||
163 | struct serio_raw *serio_raw = list->serio_raw; | ||
164 | char c; | ||
165 | ssize_t retval = 0; | ||
166 | |||
167 | if (!serio_raw->serio) | ||
168 | return -ENODEV; | ||
169 | |||
170 | if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) | ||
171 | return -EAGAIN; | ||
172 | |||
173 | retval = wait_event_interruptible(list->serio_raw->wait, | ||
174 | serio_raw->head != serio_raw->tail || !serio_raw->serio); | ||
175 | if (retval) | ||
176 | return retval; | ||
177 | |||
178 | if (!serio_raw->serio) | ||
179 | return -ENODEV; | ||
180 | |||
181 | while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { | ||
182 | if (put_user(c, buffer++)) | ||
183 | return -EFAULT; | ||
184 | retval++; | ||
185 | } | ||
186 | |||
187 | return retval; | ||
188 | } | ||
189 | |||
190 | static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | ||
191 | { | ||
192 | struct serio_raw_list *list = file->private_data; | ||
193 | ssize_t written = 0; | ||
194 | int retval; | ||
195 | unsigned char c; | ||
196 | |||
197 | retval = down_interruptible(&serio_raw_sem); | ||
198 | if (retval) | ||
199 | return retval; | ||
200 | |||
201 | if (!list->serio_raw->serio) { | ||
202 | retval = -ENODEV; | ||
203 | goto out; | ||
204 | } | ||
205 | |||
206 | if (count > 32) | ||
207 | count = 32; | ||
208 | |||
209 | while (count--) { | ||
210 | if (get_user(c, buffer++)) { | ||
211 | retval = -EFAULT; | ||
212 | goto out; | ||
213 | } | ||
214 | if (serio_write(list->serio_raw->serio, c)) { | ||
215 | retval = -EIO; | ||
216 | goto out; | ||
217 | } | ||
218 | written++; | ||
219 | }; | ||
220 | |||
221 | out: | ||
222 | up(&serio_raw_sem); | ||
223 | return written; | ||
224 | } | ||
225 | |||
226 | static unsigned int serio_raw_poll(struct file *file, poll_table *wait) | ||
227 | { | ||
228 | struct serio_raw_list *list = file->private_data; | ||
229 | |||
230 | poll_wait(file, &list->serio_raw->wait, wait); | ||
231 | |||
232 | if (list->serio_raw->head != list->serio_raw->tail) | ||
233 | return POLLIN | POLLRDNORM; | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static struct file_operations serio_raw_fops = { | ||
239 | .owner = THIS_MODULE, | ||
240 | .open = serio_raw_open, | ||
241 | .release = serio_raw_release, | ||
242 | .read = serio_raw_read, | ||
243 | .write = serio_raw_write, | ||
244 | .poll = serio_raw_poll, | ||
245 | .fasync = serio_raw_fasync, | ||
246 | }; | ||
247 | |||
248 | |||
249 | /********************************************************************* | ||
250 | * Interface with serio port * | ||
251 | *********************************************************************/ | ||
252 | |||
253 | static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, | ||
254 | unsigned int dfl, struct pt_regs *regs) | ||
255 | { | ||
256 | struct serio_raw *serio_raw = serio_get_drvdata(serio); | ||
257 | struct serio_raw_list *list; | ||
258 | unsigned int head = serio_raw->head; | ||
259 | |||
260 | /* we are holding serio->lock here so we are prootected */ | ||
261 | serio_raw->queue[head] = data; | ||
262 | head = (head + 1) % SERIO_RAW_QUEUE_LEN; | ||
263 | if (likely(head != serio_raw->tail)) { | ||
264 | serio_raw->head = head; | ||
265 | list_for_each_entry(list, &serio_raw->list, node) | ||
266 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
267 | wake_up_interruptible(&serio_raw->wait); | ||
268 | } | ||
269 | |||
270 | return IRQ_HANDLED; | ||
271 | } | ||
272 | |||
273 | static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) | ||
274 | { | ||
275 | struct serio_raw *serio_raw; | ||
276 | int err; | ||
277 | |||
278 | if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) { | ||
279 | printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); | ||
280 | return -ENOMEM; | ||
281 | } | ||
282 | |||
283 | down(&serio_raw_sem); | ||
284 | |||
285 | memset(serio_raw, 0, sizeof(struct serio_raw)); | ||
286 | snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); | ||
287 | serio_raw->refcnt = 1; | ||
288 | serio_raw->serio = serio; | ||
289 | INIT_LIST_HEAD(&serio_raw->list); | ||
290 | init_waitqueue_head(&serio_raw->wait); | ||
291 | |||
292 | serio_set_drvdata(serio, serio_raw); | ||
293 | |||
294 | err = serio_open(serio, drv); | ||
295 | if (err) | ||
296 | goto out_free; | ||
297 | |||
298 | list_add_tail(&serio_raw->node, &serio_raw_list); | ||
299 | |||
300 | serio_raw->dev.minor = PSMOUSE_MINOR; | ||
301 | serio_raw->dev.name = serio_raw->name; | ||
302 | serio_raw->dev.fops = &serio_raw_fops; | ||
303 | |||
304 | err = misc_register(&serio_raw->dev); | ||
305 | if (err) { | ||
306 | serio_raw->dev.minor = MISC_DYNAMIC_MINOR; | ||
307 | err = misc_register(&serio_raw->dev); | ||
308 | } | ||
309 | |||
310 | if (err) { | ||
311 | printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n", | ||
312 | serio->phys); | ||
313 | goto out_close; | ||
314 | } | ||
315 | |||
316 | printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n", | ||
317 | serio->phys, serio_raw->name, serio_raw->dev.minor); | ||
318 | goto out; | ||
319 | |||
320 | out_close: | ||
321 | serio_close(serio); | ||
322 | list_del_init(&serio_raw->node); | ||
323 | out_free: | ||
324 | serio_set_drvdata(serio, NULL); | ||
325 | kfree(serio_raw); | ||
326 | out: | ||
327 | up(&serio_raw_sem); | ||
328 | return err; | ||
329 | } | ||
330 | |||
331 | static int serio_raw_reconnect(struct serio *serio) | ||
332 | { | ||
333 | struct serio_raw *serio_raw = serio_get_drvdata(serio); | ||
334 | struct serio_driver *drv = serio->drv; | ||
335 | |||
336 | if (!drv || !serio_raw) { | ||
337 | printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n"); | ||
338 | return -1; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Nothing needs to be done here, we just need this method to | ||
343 | * keep the same device. | ||
344 | */ | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void serio_raw_disconnect(struct serio *serio) | ||
349 | { | ||
350 | struct serio_raw *serio_raw; | ||
351 | |||
352 | down(&serio_raw_sem); | ||
353 | |||
354 | serio_raw = serio_get_drvdata(serio); | ||
355 | |||
356 | serio_close(serio); | ||
357 | serio_set_drvdata(serio, NULL); | ||
358 | |||
359 | serio_raw->serio = NULL; | ||
360 | if (!serio_raw_cleanup(serio_raw)) | ||
361 | wake_up_interruptible(&serio_raw->wait); | ||
362 | |||
363 | up(&serio_raw_sem); | ||
364 | } | ||
365 | |||
366 | static struct serio_device_id serio_raw_serio_ids[] = { | ||
367 | { | ||
368 | .type = SERIO_8042, | ||
369 | .proto = SERIO_ANY, | ||
370 | .id = SERIO_ANY, | ||
371 | .extra = SERIO_ANY, | ||
372 | }, | ||
373 | { 0 } | ||
374 | }; | ||
375 | |||
376 | MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids); | ||
377 | |||
378 | static struct serio_driver serio_raw_drv = { | ||
379 | .driver = { | ||
380 | .name = "serio_raw", | ||
381 | }, | ||
382 | .description = DRIVER_DESC, | ||
383 | .id_table = serio_raw_serio_ids, | ||
384 | .interrupt = serio_raw_interrupt, | ||
385 | .connect = serio_raw_connect, | ||
386 | .reconnect = serio_raw_reconnect, | ||
387 | .disconnect = serio_raw_disconnect, | ||
388 | .manual_bind = 1, | ||
389 | }; | ||
390 | |||
391 | static int __init serio_raw_init(void) | ||
392 | { | ||
393 | serio_register_driver(&serio_raw_drv); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static void __exit serio_raw_exit(void) | ||
398 | { | ||
399 | serio_unregister_driver(&serio_raw_drv); | ||
400 | } | ||
401 | |||
402 | module_init(serio_raw_init); | ||
403 | module_exit(serio_raw_exit); | ||
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c new file mode 100644 index 000000000000..22f73683952b --- /dev/null +++ b/drivers/input/serio/serport.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * Input device TTY line discipline | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * | ||
6 | * This is a module that converts a tty line into a much simpler | ||
7 | * 'serial io port' abstraction that the input device drivers use. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License version 2 as published by | ||
13 | * the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <asm/uaccess.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/serio.h> | ||
22 | #include <linux/tty.h> | ||
23 | |||
24 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
25 | MODULE_DESCRIPTION("Input device TTY line discipline"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | MODULE_ALIAS_LDISC(N_MOUSE); | ||
28 | |||
29 | #define SERPORT_BUSY 1 | ||
30 | |||
31 | struct serport { | ||
32 | struct tty_struct *tty; | ||
33 | wait_queue_head_t wait; | ||
34 | struct serio *serio; | ||
35 | unsigned long flags; | ||
36 | }; | ||
37 | |||
38 | /* | ||
39 | * Callback functions from the serio code. | ||
40 | */ | ||
41 | |||
42 | static int serport_serio_write(struct serio *serio, unsigned char data) | ||
43 | { | ||
44 | struct serport *serport = serio->port_data; | ||
45 | return -(serport->tty->driver->write(serport->tty, &data, 1) != 1); | ||
46 | } | ||
47 | |||
48 | static void serport_serio_close(struct serio *serio) | ||
49 | { | ||
50 | struct serport *serport = serio->port_data; | ||
51 | |||
52 | serport->serio->id.type = 0; | ||
53 | wake_up_interruptible(&serport->wait); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * serport_ldisc_open() is the routine that is called upon setting our line | ||
58 | * discipline on a tty. It prepares the serio struct. | ||
59 | */ | ||
60 | |||
61 | static int serport_ldisc_open(struct tty_struct *tty) | ||
62 | { | ||
63 | struct serport *serport; | ||
64 | struct serio *serio; | ||
65 | char name[64]; | ||
66 | |||
67 | if (!capable(CAP_SYS_ADMIN)) | ||
68 | return -EPERM; | ||
69 | |||
70 | serport = kmalloc(sizeof(struct serport), GFP_KERNEL); | ||
71 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
72 | if (unlikely(!serport || !serio)) { | ||
73 | kfree(serport); | ||
74 | kfree(serio); | ||
75 | return -ENOMEM; | ||
76 | } | ||
77 | |||
78 | memset(serport, 0, sizeof(struct serport)); | ||
79 | serport->serio = serio; | ||
80 | set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
81 | serport->tty = tty; | ||
82 | tty->disc_data = serport; | ||
83 | |||
84 | memset(serio, 0, sizeof(struct serio)); | ||
85 | strlcpy(serio->name, "Serial port", sizeof(serio->name)); | ||
86 | snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); | ||
87 | serio->id.type = SERIO_RS232; | ||
88 | serio->write = serport_serio_write; | ||
89 | serio->close = serport_serio_close; | ||
90 | serio->port_data = serport; | ||
91 | |||
92 | init_waitqueue_head(&serport->wait); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * serport_ldisc_close() is the opposite of serport_ldisc_open() | ||
99 | */ | ||
100 | |||
101 | static void serport_ldisc_close(struct tty_struct *tty) | ||
102 | { | ||
103 | struct serport *serport = (struct serport*) tty->disc_data; | ||
104 | kfree(serport); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * serport_ldisc_receive() is called by the low level tty driver when characters | ||
109 | * are ready for us. We forward the characters, one by one to the 'interrupt' | ||
110 | * routine. | ||
111 | * | ||
112 | * FIXME: We should get pt_regs from the tty layer and forward them to | ||
113 | * serio_interrupt here. | ||
114 | */ | ||
115 | |||
116 | static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) | ||
117 | { | ||
118 | struct serport *serport = (struct serport*) tty->disc_data; | ||
119 | int i; | ||
120 | for (i = 0; i < count; i++) | ||
121 | serio_interrupt(serport->serio, cp[i], 0, NULL); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * serport_ldisc_room() reports how much room we do have for receiving data. | ||
126 | * Although we in fact have infinite room, we need to specify some value | ||
127 | * here, and 256 seems to be reasonable. | ||
128 | */ | ||
129 | |||
130 | static int serport_ldisc_room(struct tty_struct *tty) | ||
131 | { | ||
132 | return 256; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * serport_ldisc_read() just waits indefinitely if everything goes well. | ||
137 | * However, when the serio driver closes the serio port, it finishes, | ||
138 | * returning 0 characters. | ||
139 | */ | ||
140 | |||
141 | static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr) | ||
142 | { | ||
143 | struct serport *serport = (struct serport*) tty->disc_data; | ||
144 | char name[64]; | ||
145 | |||
146 | if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) | ||
147 | return -EBUSY; | ||
148 | |||
149 | serio_register_port(serport->serio); | ||
150 | printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); | ||
151 | wait_event_interruptible(serport->wait, !serport->serio->id.type); | ||
152 | serio_unregister_port(serport->serio); | ||
153 | |||
154 | clear_bit(SERPORT_BUSY, &serport->flags); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * serport_ldisc_ioctl() allows to set the port protocol, and device ID | ||
161 | */ | ||
162 | |||
163 | static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) | ||
164 | { | ||
165 | struct serport *serport = (struct serport*) tty->disc_data; | ||
166 | struct serio *serio = serport->serio; | ||
167 | unsigned long type; | ||
168 | |||
169 | if (cmd == SPIOCSTYPE) { | ||
170 | if (get_user(type, (unsigned long __user *) arg)) | ||
171 | return -EFAULT; | ||
172 | |||
173 | serio->id.proto = type & 0x000000ff; | ||
174 | serio->id.id = (type & 0x0000ff00) >> 8; | ||
175 | serio->id.extra = (type & 0x00ff0000) >> 16; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | static void serport_ldisc_write_wakeup(struct tty_struct * tty) | ||
184 | { | ||
185 | struct serport *sp = (struct serport *) tty->disc_data; | ||
186 | |||
187 | serio_drv_write_wakeup(sp->serio); | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * The line discipline structure. | ||
192 | */ | ||
193 | |||
194 | static struct tty_ldisc serport_ldisc = { | ||
195 | .owner = THIS_MODULE, | ||
196 | .name = "input", | ||
197 | .open = serport_ldisc_open, | ||
198 | .close = serport_ldisc_close, | ||
199 | .read = serport_ldisc_read, | ||
200 | .ioctl = serport_ldisc_ioctl, | ||
201 | .receive_buf = serport_ldisc_receive, | ||
202 | .receive_room = serport_ldisc_room, | ||
203 | .write_wakeup = serport_ldisc_write_wakeup | ||
204 | }; | ||
205 | |||
206 | /* | ||
207 | * The functions for insering/removing us as a module. | ||
208 | */ | ||
209 | |||
210 | static int __init serport_init(void) | ||
211 | { | ||
212 | int retval; | ||
213 | retval = tty_register_ldisc(N_MOUSE, &serport_ldisc); | ||
214 | if (retval) | ||
215 | printk(KERN_ERR "serport.c: Error registering line discipline.\n"); | ||
216 | |||
217 | return retval; | ||
218 | } | ||
219 | |||
220 | static void __exit serport_exit(void) | ||
221 | { | ||
222 | tty_register_ldisc(N_MOUSE, NULL); | ||
223 | } | ||
224 | |||
225 | module_init(serport_init); | ||
226 | module_exit(serport_exit); | ||
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); | ||
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c new file mode 100644 index 000000000000..d0afba85720b --- /dev/null +++ b/drivers/input/tsdev.c | |||
@@ -0,0 +1,492 @@ | |||
1 | /* | ||
2 | * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2001 "Crazy" james Simmons | ||
5 | * | ||
6 | * Compaq touchscreen protocol driver. The protocol emulated by this driver | ||
7 | * is obsolete; for new programs use the tslib library which can read directly | ||
8 | * from evdev and perform dejittering, variance filtering and calibration - | ||
9 | * all in user space, not at kernel level. The meaning of this driver is | ||
10 | * to allow usage of newer input drivers with old applications that use the | ||
11 | * old /dev/h3600_ts and /dev/h3600_tsraw devices. | ||
12 | * | ||
13 | * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru> | ||
14 | * Fixed to actually work, not just output random numbers. | ||
15 | * Added support for both h3600_ts and h3600_tsraw protocol | ||
16 | * emulation. | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License as published by | ||
22 | * the Free Software Foundation; either version 2 of the License, or | ||
23 | * (at your option) any later version. | ||
24 | * | ||
25 | * This program is distributed in the hope that it will be useful, | ||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | * GNU General Public License for more details. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License | ||
31 | * along with this program; if not, write to the Free Software | ||
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
33 | * | ||
34 | * Should you need to contact me, the author, you can do so either by | ||
35 | * e-mail - mail your message to <jsimmons@infradead.org>. | ||
36 | */ | ||
37 | |||
38 | #define TSDEV_MINOR_BASE 128 | ||
39 | #define TSDEV_MINORS 32 | ||
40 | /* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ | ||
41 | #define TSDEV_MINOR_MASK 15 | ||
42 | #define TSDEV_BUFFER_SIZE 64 | ||
43 | |||
44 | #include <linux/slab.h> | ||
45 | #include <linux/poll.h> | ||
46 | #include <linux/module.h> | ||
47 | #include <linux/moduleparam.h> | ||
48 | #include <linux/init.h> | ||
49 | #include <linux/input.h> | ||
50 | #include <linux/major.h> | ||
51 | #include <linux/config.h> | ||
52 | #include <linux/smp_lock.h> | ||
53 | #include <linux/random.h> | ||
54 | #include <linux/time.h> | ||
55 | #include <linux/device.h> | ||
56 | #include <linux/devfs_fs_kernel.h> | ||
57 | |||
58 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_X | ||
59 | #define CONFIG_INPUT_TSDEV_SCREEN_X 240 | ||
60 | #endif | ||
61 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_Y | ||
62 | #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 | ||
63 | #endif | ||
64 | |||
65 | /* This driver emulates both protocols of the old h3600_ts and h3600_tsraw | ||
66 | * devices. The first one must output X/Y data in 'cooked' format, e.g. | ||
67 | * filtered, dejittered and calibrated. Second device just outputs raw | ||
68 | * data received from the hardware. | ||
69 | * | ||
70 | * This driver doesn't support filtering and dejittering; it supports only | ||
71 | * calibration. Filtering and dejittering must be done in the low-level | ||
72 | * driver, if needed, because it may gain additional benefits from knowing | ||
73 | * the low-level details, the nature of noise and so on. | ||
74 | * | ||
75 | * The driver precomputes a calibration matrix given the initial xres and | ||
76 | * yres values (quite innacurate for most touchscreens) that will result | ||
77 | * in a more or less expected range of output values. The driver supports | ||
78 | * the TS_SET_CAL ioctl, which will replace the calibration matrix with a | ||
79 | * new one, supposedly generated from the values taken from the raw device. | ||
80 | */ | ||
81 | |||
82 | MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); | ||
83 | MODULE_DESCRIPTION("Input driver to touchscreen converter"); | ||
84 | MODULE_LICENSE("GPL"); | ||
85 | |||
86 | static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; | ||
87 | module_param(xres, uint, 0); | ||
88 | MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); | ||
89 | |||
90 | static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; | ||
91 | module_param(yres, uint, 0); | ||
92 | MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); | ||
93 | |||
94 | /* From Compaq's Touch Screen Specification version 0.2 (draft) */ | ||
95 | struct ts_event { | ||
96 | short pressure; | ||
97 | short x; | ||
98 | short y; | ||
99 | short millisecs; | ||
100 | }; | ||
101 | |||
102 | struct ts_calibration { | ||
103 | int xscale; | ||
104 | int xtrans; | ||
105 | int yscale; | ||
106 | int ytrans; | ||
107 | int xyswap; | ||
108 | }; | ||
109 | |||
110 | struct tsdev { | ||
111 | int exist; | ||
112 | int open; | ||
113 | int minor; | ||
114 | char name[8]; | ||
115 | wait_queue_head_t wait; | ||
116 | struct list_head list; | ||
117 | struct input_handle handle; | ||
118 | int x, y, pressure; | ||
119 | struct ts_calibration cal; | ||
120 | }; | ||
121 | |||
122 | struct tsdev_list { | ||
123 | struct fasync_struct *fasync; | ||
124 | struct list_head node; | ||
125 | struct tsdev *tsdev; | ||
126 | int head, tail; | ||
127 | struct ts_event event[TSDEV_BUFFER_SIZE]; | ||
128 | int raw; | ||
129 | }; | ||
130 | |||
131 | /* The following ioctl codes are defined ONLY for backward compatibility. | ||
132 | * Don't use tsdev for new developement; use the tslib library instead. | ||
133 | * Touchscreen calibration is a fully userspace task. | ||
134 | */ | ||
135 | /* Use 'f' as magic number */ | ||
136 | #define IOC_H3600_TS_MAGIC 'f' | ||
137 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) | ||
138 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) | ||
139 | |||
140 | static struct input_handler tsdev_handler; | ||
141 | |||
142 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; | ||
143 | |||
144 | static int tsdev_fasync(int fd, struct file *file, int on) | ||
145 | { | ||
146 | struct tsdev_list *list = file->private_data; | ||
147 | int retval; | ||
148 | |||
149 | retval = fasync_helper(fd, file, on, &list->fasync); | ||
150 | return retval < 0 ? retval : 0; | ||
151 | } | ||
152 | |||
153 | static int tsdev_open(struct inode *inode, struct file *file) | ||
154 | { | ||
155 | int i = iminor(inode) - TSDEV_MINOR_BASE; | ||
156 | struct tsdev_list *list; | ||
157 | |||
158 | if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) | ||
159 | return -ENODEV; | ||
160 | |||
161 | if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) | ||
162 | return -ENOMEM; | ||
163 | memset(list, 0, sizeof(struct tsdev_list)); | ||
164 | |||
165 | list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; | ||
166 | |||
167 | i &= TSDEV_MINOR_MASK; | ||
168 | list->tsdev = tsdev_table[i]; | ||
169 | list_add_tail(&list->node, &tsdev_table[i]->list); | ||
170 | file->private_data = list; | ||
171 | |||
172 | if (!list->tsdev->open++) | ||
173 | if (list->tsdev->exist) | ||
174 | input_open_device(&list->tsdev->handle); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static void tsdev_free(struct tsdev *tsdev) | ||
179 | { | ||
180 | tsdev_table[tsdev->minor] = NULL; | ||
181 | kfree(tsdev); | ||
182 | } | ||
183 | |||
184 | static int tsdev_release(struct inode *inode, struct file *file) | ||
185 | { | ||
186 | struct tsdev_list *list = file->private_data; | ||
187 | |||
188 | tsdev_fasync(-1, file, 0); | ||
189 | list_del(&list->node); | ||
190 | |||
191 | if (!--list->tsdev->open) { | ||
192 | if (list->tsdev->exist) | ||
193 | input_close_device(&list->tsdev->handle); | ||
194 | else | ||
195 | tsdev_free(list->tsdev); | ||
196 | } | ||
197 | kfree(list); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, | ||
202 | loff_t * ppos) | ||
203 | { | ||
204 | struct tsdev_list *list = file->private_data; | ||
205 | int retval = 0; | ||
206 | |||
207 | if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK)) | ||
208 | return -EAGAIN; | ||
209 | |||
210 | retval = wait_event_interruptible(list->tsdev->wait, | ||
211 | list->head != list->tail || !list->tsdev->exist); | ||
212 | |||
213 | if (retval) | ||
214 | return retval; | ||
215 | |||
216 | if (!list->tsdev->exist) | ||
217 | return -ENODEV; | ||
218 | |||
219 | while (list->head != list->tail && | ||
220 | retval + sizeof (struct ts_event) <= count) { | ||
221 | if (copy_to_user (buffer + retval, list->event + list->tail, | ||
222 | sizeof (struct ts_event))) | ||
223 | return -EFAULT; | ||
224 | list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); | ||
225 | retval += sizeof (struct ts_event); | ||
226 | } | ||
227 | |||
228 | return retval; | ||
229 | } | ||
230 | |||
231 | /* No kernel lock - fine */ | ||
232 | static unsigned int tsdev_poll(struct file *file, poll_table * wait) | ||
233 | { | ||
234 | struct tsdev_list *list = file->private_data; | ||
235 | poll_wait(file, &list->tsdev->wait, wait); | ||
236 | return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | | ||
237 | (list->tsdev->exist ? 0 : (POLLHUP | POLLERR)); | ||
238 | } | ||
239 | |||
240 | static int tsdev_ioctl(struct inode *inode, struct file *file, | ||
241 | unsigned int cmd, unsigned long arg) | ||
242 | { | ||
243 | struct tsdev_list *list = file->private_data; | ||
244 | struct tsdev *tsdev = list->tsdev; | ||
245 | int retval = 0; | ||
246 | |||
247 | switch (cmd) { | ||
248 | case TS_GET_CAL: | ||
249 | if (copy_to_user ((void __user *)arg, &tsdev->cal, | ||
250 | sizeof (struct ts_calibration))) | ||
251 | retval = -EFAULT; | ||
252 | break; | ||
253 | case TS_SET_CAL: | ||
254 | if (copy_from_user (&tsdev->cal, (void __user *)arg, | ||
255 | sizeof (struct ts_calibration))) | ||
256 | retval = -EFAULT; | ||
257 | break; | ||
258 | default: | ||
259 | retval = -EINVAL; | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | return retval; | ||
264 | } | ||
265 | |||
266 | static struct file_operations tsdev_fops = { | ||
267 | .owner = THIS_MODULE, | ||
268 | .open = tsdev_open, | ||
269 | .release = tsdev_release, | ||
270 | .read = tsdev_read, | ||
271 | .poll = tsdev_poll, | ||
272 | .fasync = tsdev_fasync, | ||
273 | .ioctl = tsdev_ioctl, | ||
274 | }; | ||
275 | |||
276 | static void tsdev_event(struct input_handle *handle, unsigned int type, | ||
277 | unsigned int code, int value) | ||
278 | { | ||
279 | struct tsdev *tsdev = handle->private; | ||
280 | struct tsdev_list *list; | ||
281 | struct timeval time; | ||
282 | |||
283 | switch (type) { | ||
284 | case EV_ABS: | ||
285 | switch (code) { | ||
286 | case ABS_X: | ||
287 | tsdev->x = value; | ||
288 | break; | ||
289 | case ABS_Y: | ||
290 | tsdev->y = value; | ||
291 | break; | ||
292 | case ABS_PRESSURE: | ||
293 | if (value > handle->dev->absmax[ABS_PRESSURE]) | ||
294 | value = handle->dev->absmax[ABS_PRESSURE]; | ||
295 | value -= handle->dev->absmin[ABS_PRESSURE]; | ||
296 | if (value < 0) | ||
297 | value = 0; | ||
298 | tsdev->pressure = value; | ||
299 | break; | ||
300 | } | ||
301 | break; | ||
302 | |||
303 | case EV_REL: | ||
304 | switch (code) { | ||
305 | case REL_X: | ||
306 | tsdev->x += value; | ||
307 | if (tsdev->x < 0) | ||
308 | tsdev->x = 0; | ||
309 | else if (tsdev->x > xres) | ||
310 | tsdev->x = xres; | ||
311 | break; | ||
312 | case REL_Y: | ||
313 | tsdev->y += value; | ||
314 | if (tsdev->y < 0) | ||
315 | tsdev->y = 0; | ||
316 | else if (tsdev->y > yres) | ||
317 | tsdev->y = yres; | ||
318 | break; | ||
319 | } | ||
320 | break; | ||
321 | |||
322 | case EV_KEY: | ||
323 | if (code == BTN_TOUCH || code == BTN_MOUSE) { | ||
324 | switch (value) { | ||
325 | case 0: | ||
326 | tsdev->pressure = 0; | ||
327 | break; | ||
328 | case 1: | ||
329 | if (!tsdev->pressure) | ||
330 | tsdev->pressure = 1; | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | if (type != EV_SYN || code != SYN_REPORT) | ||
338 | return; | ||
339 | |||
340 | list_for_each_entry(list, &tsdev->list, node) { | ||
341 | int x, y, tmp; | ||
342 | |||
343 | do_gettimeofday(&time); | ||
344 | list->event[list->head].millisecs = time.tv_usec / 100; | ||
345 | list->event[list->head].pressure = tsdev->pressure; | ||
346 | |||
347 | x = tsdev->x; | ||
348 | y = tsdev->y; | ||
349 | |||
350 | /* Calibration */ | ||
351 | if (!list->raw) { | ||
352 | x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; | ||
353 | y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; | ||
354 | if (tsdev->cal.xyswap) { | ||
355 | tmp = x; x = y; y = tmp; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | list->event[list->head].x = x; | ||
360 | list->event[list->head].y = y; | ||
361 | list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); | ||
362 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
363 | } | ||
364 | wake_up_interruptible(&tsdev->wait); | ||
365 | } | ||
366 | |||
367 | static struct input_handle *tsdev_connect(struct input_handler *handler, | ||
368 | struct input_dev *dev, | ||
369 | struct input_device_id *id) | ||
370 | { | ||
371 | struct tsdev *tsdev; | ||
372 | int minor, delta; | ||
373 | |||
374 | for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; | ||
375 | minor++); | ||
376 | if (minor >= TSDEV_MINORS/2) { | ||
377 | printk(KERN_ERR | ||
378 | "tsdev: You have way too many touchscreens\n"); | ||
379 | return NULL; | ||
380 | } | ||
381 | |||
382 | if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL))) | ||
383 | return NULL; | ||
384 | memset(tsdev, 0, sizeof(struct tsdev)); | ||
385 | |||
386 | INIT_LIST_HEAD(&tsdev->list); | ||
387 | init_waitqueue_head(&tsdev->wait); | ||
388 | |||
389 | sprintf(tsdev->name, "ts%d", minor); | ||
390 | |||
391 | tsdev->exist = 1; | ||
392 | tsdev->minor = minor; | ||
393 | tsdev->handle.dev = dev; | ||
394 | tsdev->handle.name = tsdev->name; | ||
395 | tsdev->handle.handler = handler; | ||
396 | tsdev->handle.private = tsdev; | ||
397 | |||
398 | /* Precompute the rough calibration matrix */ | ||
399 | delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; | ||
400 | if (delta == 0) | ||
401 | delta = 1; | ||
402 | tsdev->cal.xscale = (xres << 8) / delta; | ||
403 | tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); | ||
404 | |||
405 | delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; | ||
406 | if (delta == 0) | ||
407 | delta = 1; | ||
408 | tsdev->cal.yscale = (yres << 8) / delta; | ||
409 | tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); | ||
410 | |||
411 | tsdev_table[minor] = tsdev; | ||
412 | |||
413 | devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), | ||
414 | S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); | ||
415 | devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), | ||
416 | S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); | ||
417 | class_simple_device_add(input_class, | ||
418 | MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), | ||
419 | dev->dev, "ts%d", minor); | ||
420 | |||
421 | return &tsdev->handle; | ||
422 | } | ||
423 | |||
424 | static void tsdev_disconnect(struct input_handle *handle) | ||
425 | { | ||
426 | struct tsdev *tsdev = handle->private; | ||
427 | struct tsdev_list *list; | ||
428 | |||
429 | class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); | ||
430 | devfs_remove("input/ts%d", tsdev->minor); | ||
431 | devfs_remove("input/tsraw%d", tsdev->minor); | ||
432 | tsdev->exist = 0; | ||
433 | |||
434 | if (tsdev->open) { | ||
435 | input_close_device(handle); | ||
436 | wake_up_interruptible(&tsdev->wait); | ||
437 | list_for_each_entry(list, &tsdev->list, node) | ||
438 | kill_fasync(&list->fasync, SIGIO, POLL_HUP); | ||
439 | } else | ||
440 | tsdev_free(tsdev); | ||
441 | } | ||
442 | |||
443 | static struct input_device_id tsdev_ids[] = { | ||
444 | { | ||
445 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | ||
446 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | ||
447 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | ||
448 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | ||
449 | },/* A mouse like device, at least one button, two relative axes */ | ||
450 | |||
451 | { | ||
452 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
453 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | ||
454 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | ||
455 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | ||
456 | },/* A tablet like device, at least touch detection, two absolute axes */ | ||
457 | |||
458 | { | ||
459 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
460 | .evbit = { BIT(EV_ABS) }, | ||
461 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, | ||
462 | },/* A tablet like device with several gradations of pressure */ | ||
463 | |||
464 | {},/* Terminating entry */ | ||
465 | }; | ||
466 | |||
467 | MODULE_DEVICE_TABLE(input, tsdev_ids); | ||
468 | |||
469 | static struct input_handler tsdev_handler = { | ||
470 | .event = tsdev_event, | ||
471 | .connect = tsdev_connect, | ||
472 | .disconnect = tsdev_disconnect, | ||
473 | .fops = &tsdev_fops, | ||
474 | .minor = TSDEV_MINOR_BASE, | ||
475 | .name = "tsdev", | ||
476 | .id_table = tsdev_ids, | ||
477 | }; | ||
478 | |||
479 | static int __init tsdev_init(void) | ||
480 | { | ||
481 | input_register_handler(&tsdev_handler); | ||
482 | printk(KERN_INFO "ts: Compaq touchscreen protocol output\n"); | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static void __exit tsdev_exit(void) | ||
487 | { | ||
488 | input_unregister_handler(&tsdev_handler); | ||
489 | } | ||
490 | |||
491 | module_init(tsdev_init); | ||
492 | module_exit(tsdev_exit); | ||