2 * $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $
4 * Copyright (c) 1999-2001 Vojtech Pavlik
8 * The Serio abstraction module
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.
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.
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
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
31 * 20 Jul. 2003 Daniele Bellucci <bellucda@tiscali.it>
35 #include <linux/stddef.h>
36 #include <linux/module.h>
37 #include <linux/serio.h>
38 #include <linux/errno.h>
39 #include <linux/wait.h>
40 #include <linux/completion.h>
41 #include <linux/sched.h>
42 #include <linux/smp_lock.h>
43 #include <linux/suspend.h>
44 #include <linux/slab.h>
46 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
47 MODULE_DESCRIPTION("Serio abstraction core");
48 MODULE_LICENSE("GPL");
50 EXPORT_SYMBOL(serio_interrupt);
51 EXPORT_SYMBOL(serio_register_port);
52 EXPORT_SYMBOL(serio_register_port_delayed);
53 EXPORT_SYMBOL(__serio_register_port);
54 EXPORT_SYMBOL(serio_unregister_port);
55 EXPORT_SYMBOL(serio_unregister_port_delayed);
56 EXPORT_SYMBOL(__serio_unregister_port);
57 EXPORT_SYMBOL(serio_register_device);
58 EXPORT_SYMBOL(serio_unregister_device);
59 EXPORT_SYMBOL(serio_open);
60 EXPORT_SYMBOL(serio_close);
61 EXPORT_SYMBOL(serio_rescan);
62 EXPORT_SYMBOL(serio_reconnect);
67 struct list_head node;
70 static DECLARE_MUTEX(serio_sem);
71 static LIST_HEAD(serio_list);
72 static LIST_HEAD(serio_dev_list);
73 static LIST_HEAD(serio_event_list);
76 static void serio_find_dev(struct serio *serio)
78 struct serio_dev *dev;
80 list_for_each_entry(dev, &serio_dev_list, node) {
84 dev->connect(serio, dev);
88 #define SERIO_RESCAN 1
89 #define SERIO_RECONNECT 2
90 #define SERIO_REGISTER_PORT 3
91 #define SERIO_UNREGISTER_PORT 4
93 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
94 static DECLARE_COMPLETION(serio_exited);
96 static void serio_invalidate_pending_events(struct serio *serio)
98 struct serio_event *event;
100 list_for_each_entry(event, &serio_event_list, node)
101 if (event->serio == serio)
105 void serio_handle_events(void)
107 struct list_head *node, *next;
108 struct serio_event *event;
110 list_for_each_safe(node, next, &serio_event_list) {
111 event = container_of(node, struct serio_event, node);
114 if (event->serio == NULL)
117 switch (event->type) {
118 case SERIO_REGISTER_PORT :
119 __serio_register_port(event->serio);
122 case SERIO_UNREGISTER_PORT :
123 __serio_unregister_port(event->serio);
126 case SERIO_RECONNECT :
127 if (event->serio->dev && event->serio->dev->reconnect)
128 if (event->serio->dev->reconnect(event->serio) == 0)
130 /* reconnect failed - fall through to rescan */
133 if (event->serio->dev && event->serio->dev->disconnect)
134 event->serio->dev->disconnect(event->serio);
135 serio_find_dev(event->serio);
147 static int serio_thread(void *nothing)
150 daemonize("kseriod");
151 allow_signal(SIGTERM);
154 serio_handle_events();
155 wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
156 if (current->flags & PF_FREEZE)
157 refrigerator(PF_FREEZE);
158 } while (!signal_pending(current));
160 printk(KERN_DEBUG "serio: kseriod exiting\n");
163 complete_and_exit(&serio_exited, 0);
166 static void serio_queue_event(struct serio *serio, int event_type)
168 struct serio_event *event;
170 if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
171 event->type = event_type;
172 event->serio = serio;
174 list_add_tail(&event->node, &serio_event_list);
175 wake_up(&serio_wait);
179 void serio_rescan(struct serio *serio)
181 serio_queue_event(serio, SERIO_RESCAN);
184 void serio_reconnect(struct serio *serio)
186 serio_queue_event(serio, SERIO_RECONNECT);
189 irqreturn_t serio_interrupt(struct serio *serio,
190 unsigned char data, unsigned int flags, struct pt_regs *regs)
192 irqreturn_t ret = IRQ_NONE;
194 if (serio->dev && serio->dev->interrupt) {
195 ret = serio->dev->interrupt(serio, data, flags, regs);
198 if ((serio->type == SERIO_8042 ||
199 serio->type == SERIO_8042_XL) && (data != 0xaa))
208 void serio_register_port(struct serio *serio)
211 __serio_register_port(serio);
216 * Submits register request to kseriod for subsequent execution.
217 * Can be used when it is not obvious whether the serio_sem is
218 * taken or not and when delayed execution is feasible.
220 void serio_register_port_delayed(struct serio *serio)
222 serio_queue_event(serio, SERIO_REGISTER_PORT);
226 * Should only be called directly if serio_sem has already been taken,
227 * for example when unregistering a serio from other input device's
228 * connect() function.
230 void __serio_register_port(struct serio *serio)
232 list_add_tail(&serio->node, &serio_list);
233 serio_find_dev(serio);
236 void serio_unregister_port(struct serio *serio)
239 __serio_unregister_port(serio);
244 * Submits unregister request to kseriod for subsequent execution.
245 * Can be used when it is not obvious whether the serio_sem is
246 * taken or not and when delayed execution is feasible.
248 void serio_unregister_port_delayed(struct serio *serio)
250 serio_queue_event(serio, SERIO_UNREGISTER_PORT);
254 * Should only be called directly if serio_sem has already been taken,
255 * for example when unregistering a serio from other input device's
256 * disconnect() function.
258 void __serio_unregister_port(struct serio *serio)
260 serio_invalidate_pending_events(serio);
261 list_del_init(&serio->node);
262 if (serio->dev && serio->dev->disconnect)
263 serio->dev->disconnect(serio);
266 void serio_register_device(struct serio_dev *dev)
270 list_add_tail(&dev->node, &serio_dev_list);
271 list_for_each_entry(serio, &serio_list, node)
272 if (!serio->dev && dev->connect)
273 dev->connect(serio, dev);
277 void serio_unregister_device(struct serio_dev *dev)
282 list_del_init(&dev->node);
284 list_for_each_entry(serio, &serio_list, node) {
285 if (serio->dev == dev && dev->disconnect)
286 dev->disconnect(serio);
287 serio_find_dev(serio);
292 /* called from serio_dev->connect/disconnect methods under serio_sem */
293 int serio_open(struct serio *serio, struct serio_dev *dev)
296 if (serio->open(serio)) {
303 /* called from serio_dev->connect/disconnect methods under serio_sem */
304 void serio_close(struct serio *serio)
310 static int __init serio_init(void)
314 pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL);
317 printk(KERN_WARNING "serio: Failed to start kseriod\n");
326 static void __exit serio_exit(void)
328 kill_proc(serio_pid, SIGTERM, 1);
329 wait_for_completion(&serio_exited);
332 module_init(serio_init);
333 module_exit(serio_exit);