spin_lock_irqsave(&fm->lock, flags);
        fm->socket_change_set |= 1 << sock->socket_id;
-       wake_up_all(&fm->change_set_notify);
+       tifm_queue_work(&fm->media_switcher);
        spin_unlock_irqrestore(&fm->lock, flags);
 }
 
        }
        writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
 
-       if (!fm->socket_change_set)
+       if (fm->finish_me)
+               complete_all(fm->finish_me);
+       else if (!fm->socket_change_set)
                writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
        else
-               wake_up_all(&fm->change_set_notify);
+               tifm_queue_work(&fm->media_switcher);
 
        spin_unlock(&fm->lock);
        return IRQ_HANDLED;
        return base_addr + ((sock_num + 1) << 10);
 }
 
-static int tifm_7xx1_switch_media(void *data)
+static void tifm_7xx1_switch_media(struct work_struct *work)
 {
-       struct tifm_adapter *fm = data;
+       struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
+                                              media_switcher);
        unsigned long flags;
        unsigned char media_id;
        char *card_name = "xx";
-       int cnt, rc;
+       int cnt;
        struct tifm_dev *sock;
        unsigned int socket_change_set;
 
-       while (1) {
-               rc = wait_event_interruptible(fm->change_set_notify,
-                                             fm->socket_change_set);
-               if (rc == -ERESTARTSYS)
-                       try_to_freeze();
-
-               spin_lock_irqsave(&fm->lock, flags);
-               socket_change_set = fm->socket_change_set;
-               fm->socket_change_set = 0;
+       spin_lock_irqsave(&fm->lock, flags);
+       socket_change_set = fm->socket_change_set;
+       fm->socket_change_set = 0;
 
-               dev_dbg(fm->dev, "checking media set %x\n",
-                       socket_change_set);
+       dev_dbg(fm->dev, "checking media set %x\n",
+               socket_change_set);
 
-               if (kthread_should_stop())
-                       socket_change_set = (1 << fm->num_sockets) - 1;
+       if (!socket_change_set) {
                spin_unlock_irqrestore(&fm->lock, flags);
+               return;
+       }
 
-               if (!socket_change_set)
-                       continue;
-
-               spin_lock_irqsave(&fm->lock, flags);
                for (cnt = 0; cnt < fm->num_sockets; cnt++) {
                        if (!(socket_change_set & (1 << cnt)))
                                continue;
                                       tifm_7xx1_sock_addr(fm->addr, cnt)
                                       + SOCK_CONTROL);
                        }
-                       if (kthread_should_stop())
-                               continue;
 
                        spin_unlock_irqrestore(&fm->lock, flags);
                        media_id = tifm_7xx1_toggle_sock_power(
                        }
                }
 
-               if (!kthread_should_stop()) {
-                       writel(TIFM_IRQ_FIFOMASK(socket_change_set)
-                              | TIFM_IRQ_CARDMASK(socket_change_set),
-                              fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-                       writel(TIFM_IRQ_FIFOMASK(socket_change_set)
-                              | TIFM_IRQ_CARDMASK(socket_change_set),
-                              fm->addr + FM_SET_INTERRUPT_ENABLE);
-                       writel(TIFM_IRQ_ENABLE,
-                              fm->addr + FM_SET_INTERRUPT_ENABLE);
-                       spin_unlock_irqrestore(&fm->lock, flags);
-               } else {
-                       for (cnt = 0; cnt < fm->num_sockets; cnt++) {
-                               if (fm->sockets[cnt])
-                                       fm->socket_change_set |= 1 << cnt;
-                       }
-                       if (!fm->socket_change_set) {
-                               spin_unlock_irqrestore(&fm->lock, flags);
-                               return 0;
-                       } else {
-                               spin_unlock_irqrestore(&fm->lock, flags);
-                       }
-               }
-       }
-       return 0;
+       writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+              | TIFM_IRQ_CARDMASK(socket_change_set),
+              fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+
+       writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+              | TIFM_IRQ_CARDMASK(socket_change_set),
+              fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+       writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+       spin_unlock_irqrestore(&fm->lock, flags);
 }
 
 #ifdef CONFIG_PM
        int cnt, rc;
        unsigned long flags;
        unsigned char new_ids[fm->num_sockets];
+       DECLARE_COMPLETION_ONSTACK(finish_resume);
 
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
                return 0;
        } else {
                fm->socket_change_set = 0;
+               fm->finish_me = &finish_resume;
                spin_unlock_irqrestore(&fm->lock, flags);
        }
 
-       wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+       wait_for_completion_timeout(&finish_resume, HZ);
 
        spin_lock_irqsave(&fm->lock, flags);
+       fm->finish_me = NULL;
        writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
               | TIFM_IRQ_CARDMASK(fm->socket_change_set),
               fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
        if (!fm->sockets)
                goto err_out_free;
 
+       INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
        fm->eject = tifm_7xx1_eject;
        pci_set_drvdata(dev, fm);
 
        if (rc)
                goto err_out_unmap;
 
-       init_waitqueue_head(&fm->change_set_notify);
-       rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
+       rc = tifm_add_adapter(fm);
        if (rc)
                goto err_out_irq;
 
        writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
        writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
               fm->addr + FM_SET_INTERRUPT_ENABLE);
-       wake_up_process(fm->media_switcher);
+
        return 0;
 
 err_out_irq:
        fm->socket_change_set = (1 << fm->num_sockets) - 1;
        spin_unlock_irqrestore(&fm->lock, flags);
 
-       kthread_stop(fm->media_switcher);
-
        tifm_remove_adapter(fm);
 
        pci_set_drvdata(dev, NULL);
 
 #define DRIVER_NAME "tifm_core"
 #define DRIVER_VERSION "0.8"
 
+static struct workqueue_struct *workqueue;
 static DEFINE_IDR(tifm_adapter_idr);
 static DEFINE_SPINLOCK(tifm_adapter_lock);
 
 }
 EXPORT_SYMBOL(tifm_free_adapter);
 
-int tifm_add_adapter(struct tifm_adapter *fm,
-                    int (*mediathreadfn)(void *data))
+int tifm_add_adapter(struct tifm_adapter *fm)
 {
        int rc;
 
        spin_unlock(&tifm_adapter_lock);
        if (!rc) {
                snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
-               fm->media_switcher = kthread_create(mediathreadfn,
-                                                   fm, "tifm/%u", fm->id);
+               rc = class_device_add(&fm->cdev);
 
-               if (!IS_ERR(fm->media_switcher))
-                       return class_device_add(&fm->cdev);
-
-               spin_lock(&tifm_adapter_lock);
-               idr_remove(&tifm_adapter_idr, fm->id);
-               spin_unlock(&tifm_adapter_lock);
-               rc = -ENOMEM;
+               if (rc) {
+                       spin_lock(&tifm_adapter_lock);
+                       idr_remove(&tifm_adapter_idr, fm->id);
+                       spin_unlock(&tifm_adapter_lock);
+               }
        }
        return rc;
 }
 
 void tifm_remove_adapter(struct tifm_adapter *fm)
 {
+       flush_workqueue(workqueue);
        class_device_del(&fm->cdev);
 
        spin_lock(&tifm_adapter_lock);
 }
 EXPORT_SYMBOL(tifm_unmap_sg);
 
+void tifm_queue_work(struct work_struct *work)
+{
+       queue_work(workqueue, work);
+}
+EXPORT_SYMBOL(tifm_queue_work);
+
 int tifm_register_driver(struct tifm_driver *drv)
 {
        drv->driver.bus = &tifm_bus_type;
 
 static int __init tifm_init(void)
 {
-       int rc = bus_register(&tifm_bus_type);
+       int rc;
 
-       if (!rc) {
-               rc = class_register(&tifm_adapter_class);
-               if (rc)
-                       bus_unregister(&tifm_bus_type);
-       }
+       workqueue = create_freezeable_workqueue("tifm");
+       if (!workqueue)
+               return -ENOMEM;
+
+       rc = bus_register(&tifm_bus_type);
+
+       if (rc)
+               goto err_out_wq;
+
+       rc = class_register(&tifm_adapter_class);
+       if (!rc)
+               return 0;
+
+       bus_unregister(&tifm_bus_type);
+
+err_out_wq:
+       destroy_workqueue(workqueue);
 
        return rc;
 }
 {
        class_unregister(&tifm_adapter_class);
        bus_unregister(&tifm_bus_type);
+       destroy_workqueue(workqueue);
 }
 
 subsys_initcall(tifm_init);
 
        spinlock_t              lock;
        unsigned int            irq_status;
        unsigned int            socket_change_set;
-       wait_queue_head_t       change_set_notify;
        unsigned int            id;
        unsigned int            num_sockets;
+       struct completion       *finish_me;
        struct tifm_dev         **sockets;
-       struct task_struct      *media_switcher;
+       struct work_struct      media_switcher;
        struct class_device     cdev;
        struct device           *dev;
 
 struct tifm_adapter *tifm_alloc_adapter(void);
 void tifm_free_device(struct device *dev);
 void tifm_free_adapter(struct tifm_adapter *fm);
-int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
+int tifm_add_adapter(struct tifm_adapter *fm);
 void tifm_remove_adapter(struct tifm_adapter *fm);
 struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
 int tifm_register_driver(struct tifm_driver *drv);
                int direction);
 void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
                   int direction);
-
+void tifm_queue_work(struct work_struct *work);
 
 static inline void *tifm_get_drvdata(struct tifm_dev *dev)
 {