#include <linux/wait.h>
 #include <net/nfc/nci_core.h>
 
-enum virtual_ncidev_mode {
-       virtual_ncidev_enabled,
-       virtual_ncidev_disabled,
-       virtual_ncidev_disabling,
-};
-
 #define IOCTL_GET_NCIDEV_IDX    0
 #define VIRTUAL_NFC_PROTOCOLS  (NFC_PROTO_JEWEL_MASK | \
                                 NFC_PROTO_MIFARE_MASK | \
                                 NFC_PROTO_ISO14443_B_MASK | \
                                 NFC_PROTO_ISO15693_MASK)
 
-static enum virtual_ncidev_mode state;
-static DECLARE_WAIT_QUEUE_HEAD(wq);
-static struct miscdevice miscdev;
-static struct sk_buff *send_buff;
-static struct nci_dev *ndev;
-static DEFINE_MUTEX(nci_mutex);
+struct virtual_nci_dev {
+       struct nci_dev *ndev;
+       struct mutex mtx;
+       struct sk_buff *send_buff;
+       struct wait_queue_head wq;
+};
 
 static int virtual_nci_open(struct nci_dev *ndev)
 {
 
 static int virtual_nci_close(struct nci_dev *ndev)
 {
-       mutex_lock(&nci_mutex);
-       kfree_skb(send_buff);
-       send_buff = NULL;
-       mutex_unlock(&nci_mutex);
+       struct virtual_nci_dev *vdev = nci_get_drvdata(ndev);
+
+       mutex_lock(&vdev->mtx);
+       kfree_skb(vdev->send_buff);
+       vdev->send_buff = NULL;
+       mutex_unlock(&vdev->mtx);
 
        return 0;
 }
 
 static int virtual_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
 {
-       mutex_lock(&nci_mutex);
-       if (state != virtual_ncidev_enabled) {
-               mutex_unlock(&nci_mutex);
+       struct virtual_nci_dev *vdev = nci_get_drvdata(ndev);
+
+       mutex_lock(&vdev->mtx);
+       if (vdev->send_buff) {
+               mutex_unlock(&vdev->mtx);
                kfree_skb(skb);
-               return 0;
+               return -1;
        }
-
-       if (send_buff) {
-               mutex_unlock(&nci_mutex);
+       vdev->send_buff = skb_copy(skb, GFP_KERNEL);
+       if (!vdev->send_buff) {
+               mutex_unlock(&vdev->mtx);
                kfree_skb(skb);
                return -1;
        }
-       send_buff = skb_copy(skb, GFP_KERNEL);
-       mutex_unlock(&nci_mutex);
-       wake_up_interruptible(&wq);
+       mutex_unlock(&vdev->mtx);
+       wake_up_interruptible(&vdev->wq);
        consume_skb(skb);
 
        return 0;
 static ssize_t virtual_ncidev_read(struct file *file, char __user *buf,
                                   size_t count, loff_t *ppos)
 {
+       struct virtual_nci_dev *vdev = file->private_data;
        size_t actual_len;
 
-       mutex_lock(&nci_mutex);
-       while (!send_buff) {
-               mutex_unlock(&nci_mutex);
-               if (wait_event_interruptible(wq, send_buff))
+       mutex_lock(&vdev->mtx);
+       while (!vdev->send_buff) {
+               mutex_unlock(&vdev->mtx);
+               if (wait_event_interruptible(vdev->wq, vdev->send_buff))
                        return -EFAULT;
-               mutex_lock(&nci_mutex);
+               mutex_lock(&vdev->mtx);
        }
 
-       actual_len = min_t(size_t, count, send_buff->len);
+       actual_len = min_t(size_t, count, vdev->send_buff->len);
 
-       if (copy_to_user(buf, send_buff->data, actual_len)) {
-               mutex_unlock(&nci_mutex);
+       if (copy_to_user(buf, vdev->send_buff->data, actual_len)) {
+               mutex_unlock(&vdev->mtx);
                return -EFAULT;
        }
 
-       skb_pull(send_buff, actual_len);
-       if (send_buff->len == 0) {
-               consume_skb(send_buff);
-               send_buff = NULL;
+       skb_pull(vdev->send_buff, actual_len);
+       if (vdev->send_buff->len == 0) {
+               consume_skb(vdev->send_buff);
+               vdev->send_buff = NULL;
        }
-       mutex_unlock(&nci_mutex);
+       mutex_unlock(&vdev->mtx);
 
        return actual_len;
 }
                                    const char __user *buf,
                                    size_t count, loff_t *ppos)
 {
+       struct virtual_nci_dev *vdev = file->private_data;
        struct sk_buff *skb;
 
        skb = alloc_skb(count, GFP_KERNEL);
                return -EFAULT;
        }
 
-       nci_recv_frame(ndev, skb);
+       nci_recv_frame(vdev->ndev, skb);
        return count;
 }
 
 static int virtual_ncidev_open(struct inode *inode, struct file *file)
 {
        int ret = 0;
+       struct virtual_nci_dev *vdev;
 
-       mutex_lock(&nci_mutex);
-       if (state != virtual_ncidev_disabled) {
-               mutex_unlock(&nci_mutex);
-               return -EBUSY;
-       }
-
-       ndev = nci_allocate_device(&virtual_nci_ops, VIRTUAL_NFC_PROTOCOLS,
-                                  0, 0);
-       if (!ndev) {
-               mutex_unlock(&nci_mutex);
+       vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+       if (!vdev)
+               return -ENOMEM;
+       vdev->ndev = nci_allocate_device(&virtual_nci_ops,
+               VIRTUAL_NFC_PROTOCOLS, 0, 0);
+       if (!vdev->ndev) {
+               kfree(vdev);
                return -ENOMEM;
        }
 
-       ret = nci_register_device(ndev);
+       mutex_init(&vdev->mtx);
+       init_waitqueue_head(&vdev->wq);
+       file->private_data = vdev;
+       nci_set_drvdata(vdev->ndev, vdev);
+
+       ret = nci_register_device(vdev->ndev);
        if (ret < 0) {
-               nci_free_device(ndev);
-               mutex_unlock(&nci_mutex);
+               nci_free_device(vdev->ndev);
+               mutex_destroy(&vdev->mtx);
+               kfree(vdev);
                return ret;
        }
-       state = virtual_ncidev_enabled;
-       mutex_unlock(&nci_mutex);
 
        return 0;
 }
 
 static int virtual_ncidev_close(struct inode *inode, struct file *file)
 {
-       mutex_lock(&nci_mutex);
-
-       if (state == virtual_ncidev_enabled) {
-               state = virtual_ncidev_disabling;
-               mutex_unlock(&nci_mutex);
+       struct virtual_nci_dev *vdev = file->private_data;
 
-               nci_unregister_device(ndev);
-               nci_free_device(ndev);
-
-               mutex_lock(&nci_mutex);
-       }
-
-       state = virtual_ncidev_disabled;
-       mutex_unlock(&nci_mutex);
+       nci_unregister_device(vdev->ndev);
+       nci_free_device(vdev->ndev);
+       mutex_destroy(&vdev->mtx);
+       kfree(vdev);
 
        return 0;
 }
 
-static long virtual_ncidev_ioctl(struct file *flip, unsigned int cmd,
+static long virtual_ncidev_ioctl(struct file *file, unsigned int cmd,
                                 unsigned long arg)
 {
-       const struct nfc_dev *nfc_dev = ndev->nfc_dev;
+       struct virtual_nci_dev *vdev = file->private_data;
+       const struct nfc_dev *nfc_dev = vdev->ndev->nfc_dev;
        void __user *p = (void __user *)arg;
 
        if (cmd != IOCTL_GET_NCIDEV_IDX)
        .unlocked_ioctl = virtual_ncidev_ioctl
 };
 
+static struct miscdevice miscdev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "virtual_nci",
+       .fops = &virtual_ncidev_fops,
+       .mode = 0600,
+};
+
 static int __init virtual_ncidev_init(void)
 {
-       state = virtual_ncidev_disabled;
-       miscdev.minor = MISC_DYNAMIC_MINOR;
-       miscdev.name = "virtual_nci";
-       miscdev.fops = &virtual_ncidev_fops;
-       miscdev.mode = 0600;
-
        return misc_register(&miscdev);
 }