Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[powerpc.git] / drivers / input / gameport / gameport.c
index c77a82e..b765a15 100644 (file)
 #include <linux/init.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
-#include <linux/completion.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>       /* HZ */
 
 /*#include <asm/io.h>*/
 
@@ -50,9 +50,7 @@ static DECLARE_MUTEX(gameport_sem);
 
 static LIST_HEAD(gameport_list);
 
-static struct bus_type gameport_bus = {
-       .name = "gameport",
-};
+static struct bus_type gameport_bus;
 
 static void gameport_add_port(struct gameport *gameport);
 static void gameport_destroy_port(struct gameport *gameport);
@@ -61,12 +59,13 @@ static void gameport_disconnect_port(struct gameport *gameport);
 
 #if defined(__i386__)
 
+#include <asm/i8253.h>
+
 #define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193182/HZ:0))
 #define GET_TIME(x)     do { x = get_time_pit(); } while (0)
 
 static unsigned int get_time_pit(void)
 {
-       extern spinlock_t i8253_lock;
        unsigned long flags;
        unsigned int count;
 
@@ -238,8 +237,7 @@ struct gameport_event {
 static DEFINE_SPINLOCK(gameport_event_lock);   /* protects gameport_event_list */
 static LIST_HEAD(gameport_event_list);
 static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static DECLARE_COMPLETION(gameport_exited);
-static int gameport_pid;
+static struct task_struct *gameport_task;
 
 static void gameport_queue_event(void *object, struct module *owner,
                              enum gameport_event_type event_type)
@@ -250,12 +248,12 @@ static void gameport_queue_event(void *object, struct module *owner,
        spin_lock_irqsave(&gameport_event_lock, flags);
 
        /*
-        * Scan event list for the other events for the same gameport port,
+        * Scan event list for the other events for the same gameport port,
         * starting with the most recent one. If event is the same we
         * do not need add new one. If event is of different type we
         * need to add this event and should not look further because
         * we need to preseve sequence of distinct events.
-        */
+        */
        list_for_each_entry_reverse(event, &gameport_event_list, node) {
                if (event->object == object) {
                        if (event->type == event_type)
@@ -339,14 +337,20 @@ static struct gameport_event *gameport_get_event(void)
        return event;
 }
 
-static void gameport_handle_events(void)
+static void gameport_handle_event(void)
 {
        struct gameport_event *event;
        struct gameport_driver *gameport_drv;
 
        down(&gameport_sem);
 
-       while ((event = gameport_get_event())) {
+       /*
+        * Note that we handle only one event here to give swsusp
+        * a chance to freeze kgameportd thread. Gameport events
+        * should be pretty rare so we are not concerned about
+        * taking performance hit.
+        */
+       if ((event = gameport_get_event())) {
 
                switch (event->type) {
                        case GAMEPORT_REGISTER_PORT:
@@ -432,20 +436,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
 
 static int gameport_thread(void *nothing)
 {
-       lock_kernel();
-       daemonize("kgameportd");
-       allow_signal(SIGTERM);
-
        do {
-               gameport_handle_events();
-               wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
+               gameport_handle_event();
+               wait_event_interruptible(gameport_wait,
+                       kthread_should_stop() || !list_empty(&gameport_event_list));
                try_to_freeze();
-       } while (!signal_pending(current));
+       } while (!kthread_should_stop());
 
        printk(KERN_DEBUG "gameport: kgameportd exiting\n");
-
-       unlock_kernel();
-       complete_and_exit(&gameport_exited, 0);
+       return 0;
 }
 
 
@@ -702,11 +701,15 @@ static int gameport_driver_remove(struct device *dev)
        return 0;
 }
 
+static struct bus_type gameport_bus = {
+       .name = "gameport",
+       .probe = gameport_driver_probe,
+       .remove = gameport_driver_remove,
+};
+
 void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
 {
        drv->driver.bus = &gameport_bus;
-       drv->driver.probe = gameport_driver_probe;
-       drv->driver.remove = gameport_driver_remove;
        gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
 }
 
@@ -773,9 +776,10 @@ void gameport_close(struct gameport *gameport)
 
 static int __init gameport_init(void)
 {
-       if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+       gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
+       if (IS_ERR(gameport_task)) {
                printk(KERN_ERR "gameport: Failed to start kgameportd\n");
-               return -1;
+               return PTR_ERR(gameport_task);
        }
 
        gameport_bus.dev_attrs = gameport_device_attrs;
@@ -789,8 +793,7 @@ static int __init gameport_init(void)
 static void __exit gameport_exit(void)
 {
        bus_unregister(&gameport_bus);
-       kill_proc(gameport_pid, SIGTERM, 1);
-       wait_for_completion(&gameport_exited);
+       kthread_stop(gameport_task);
 }
 
 module_init(gameport_init);