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 #include <linux/stddef.h>
32 #include <linux/module.h>
33 #include <linux/serio.h>
34 #include <linux/errno.h>
35 #include <linux/wait.h>
36 #include <linux/completion.h>
37 #include <linux/sched.h>
38 #include <linux/smp_lock.h>
39 #include <linux/suspend.h>
40 #include <linux/slab.h>
42 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
43 MODULE_DESCRIPTION("Serio abstraction core");
44 MODULE_LICENSE("GPL");
46 EXPORT_SYMBOL(serio_interrupt);
47 EXPORT_SYMBOL(serio_register_port);
48 EXPORT_SYMBOL(serio_unregister_port);
49 EXPORT_SYMBOL(serio_register_device);
50 EXPORT_SYMBOL(serio_unregister_device);
51 EXPORT_SYMBOL(serio_open);
52 EXPORT_SYMBOL(serio_close);
53 EXPORT_SYMBOL(serio_rescan);
58 struct list_head node;
61 static DECLARE_MUTEX(serio_sem);
62 static LIST_HEAD(serio_list);
63 static LIST_HEAD(serio_dev_list);
64 static LIST_HEAD(serio_event_list);
67 static void serio_find_dev(struct serio *serio)
69 struct serio_dev *dev;
71 list_for_each_entry(dev, &serio_dev_list, node) {
75 dev->connect(serio, dev);
79 #define SERIO_RESCAN 1
81 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
82 static DECLARE_COMPLETION(serio_exited);
84 void serio_handle_events(void)
86 struct list_head *node, *next;
87 struct serio_event *event;
89 list_for_each_safe(node, next, &serio_event_list) {
90 event = container_of(node, struct serio_event, node);
92 switch (event->type) {
95 if (event->serio->dev && event->serio->dev->disconnect)
96 event->serio->dev->disconnect(event->serio);
97 serio_find_dev(event->serio);
108 static int serio_thread(void *nothing)
111 daemonize("kseriod");
112 allow_signal(SIGTERM);
115 serio_handle_events();
116 wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
117 if (current->flags & PF_FREEZE)
118 refrigerator(PF_IOTHREAD);
119 } while (!signal_pending(current));
121 printk(KERN_DEBUG "serio: kseriod exiting\n");
124 complete_and_exit(&serio_exited, 0);
127 void serio_rescan(struct serio *serio)
129 struct serio_event *event;
131 if (!(event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC)))
134 event->type = SERIO_RESCAN;
135 event->serio = serio;
137 list_add_tail(&event->node, &serio_event_list);
138 wake_up(&serio_wait);
141 irqreturn_t serio_interrupt(struct serio *serio,
142 unsigned char data, unsigned int flags, struct pt_regs *regs)
144 irqreturn_t ret = IRQ_NONE;
146 if (serio->dev && serio->dev->interrupt) {
147 ret = serio->dev->interrupt(serio, data, flags, regs);
157 void serio_register_port(struct serio *serio)
160 list_add_tail(&serio->node, &serio_list);
161 serio_find_dev(serio);
165 void serio_unregister_port(struct serio *serio)
168 list_del_init(&serio->node);
169 if (serio->dev && serio->dev->disconnect)
170 serio->dev->disconnect(serio);
174 void serio_register_device(struct serio_dev *dev)
178 list_add_tail(&dev->node, &serio_dev_list);
179 list_for_each_entry(serio, &serio_list, node)
180 if (!serio->dev && dev->connect)
181 dev->connect(serio, dev);
185 void serio_unregister_device(struct serio_dev *dev)
190 list_del_init(&dev->node);
192 list_for_each_entry(serio, &serio_list, node) {
193 if (serio->dev == dev && dev->disconnect)
194 dev->disconnect(serio);
195 serio_find_dev(serio);
200 /* called from serio_dev->connect/disconnect methods under serio_sem */
201 int serio_open(struct serio *serio, struct serio_dev *dev)
203 if (serio->open(serio))
209 /* called from serio_dev->connect/disconnect methods under serio_sem */
210 void serio_close(struct serio *serio)
220 pid = kernel_thread(serio_thread, NULL,
221 CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
224 printk(KERN_WARNING "serio: Failed to start kseriod\n");
233 void serio_exit(void)
235 kill_proc(serio_pid, SIGTERM, 1);
236 wait_for_completion(&serio_exited);
239 module_init(serio_init);
240 module_exit(serio_exit);