bool attached;
        int open;
 
-       struct mutex irctl_lock;
+       struct mutex mutex;     /* protect from simultaneous accesses */
        struct lirc_buffer *buf;
        bool buf_internal;
 
        struct cdev cdev;
 };
 
+/* This mutex protects the irctls array */
 static DEFINE_MUTEX(lirc_dev_lock);
 
 static struct irctl *irctls[MAX_IRCTL_DEVICES];
 /* Only used for sysfs but defined to void otherwise */
 static struct class *lirc_class;
 
-static void lirc_release(struct device *ld)
+static void lirc_free_buffer(struct irctl *ir)
 {
-       struct irctl *ir = container_of(ld, struct irctl, dev);
-
        put_device(ir->dev.parent);
 
        if (ir->buf_internal) {
                lirc_buffer_free(ir->buf);
                kfree(ir->buf);
+               ir->buf = NULL;
        }
+}
+
+static void lirc_release(struct device *ld)
+{
+       struct irctl *ir = container_of(ld, struct irctl, dev);
 
        mutex_lock(&lirc_dev_lock);
        irctls[ir->d.minor] = NULL;
        mutex_unlock(&lirc_dev_lock);
+       lirc_free_buffer(ir);
        kfree(ir);
 }
 
                return -EBADRQC;
        }
 
+       /* some safety check 8-) */
+       d->name[sizeof(d->name) - 1] = '\0';
+
+       if (d->features == 0)
+               d->features = LIRC_CAN_REC_LIRCCODE;
+
+       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+       if (!ir)
+               return -ENOMEM;
+
+       mutex_init(&ir->mutex);
+       ir->d = *d;
+
+       if (LIRC_CAN_REC(d->features)) {
+               err = lirc_allocate_buffer(ir);
+               if (err) {
+                       kfree(ir);
+                       return err;
+               }
+               d->rbuf = ir->buf;
+       }
+
        mutex_lock(&lirc_dev_lock);
 
        /* find first free slot for driver */
 
        if (minor == MAX_IRCTL_DEVICES) {
                dev_err(d->dev, "no free slots for drivers!\n");
-               err = -ENOMEM;
-               goto out_lock;
-       }
-
-       ir = kzalloc(sizeof(struct irctl), GFP_KERNEL);
-       if (!ir) {
-               err = -ENOMEM;
-               goto out_lock;
+               mutex_unlock(&lirc_dev_lock);
+               lirc_free_buffer(ir);
+               kfree(ir);
+               return -ENOMEM;
        }
 
-       mutex_init(&ir->irctl_lock);
        irctls[minor] = ir;
        d->irctl = ir;
        d->minor = minor;
+       ir->d.minor = minor;
 
-       /* some safety check 8-) */
-       d->name[sizeof(d->name)-1] = '\0';
-
-       if (d->features == 0)
-               d->features = LIRC_CAN_REC_LIRCCODE;
-
-       ir->d = *d;
-
-       if (LIRC_CAN_REC(d->features)) {
-               err = lirc_allocate_buffer(irctls[minor]);
-               if (err) {
-                       kfree(ir);
-                       goto out_lock;
-               }
-               d->rbuf = ir->buf;
-       }
+       mutex_unlock(&lirc_dev_lock);
 
        device_initialize(&ir->dev);
        ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor);
        ir->attached = true;
 
        err = cdev_device_add(&ir->cdev, &ir->dev);
-       if (err)
-               goto out_dev;
-
-       mutex_unlock(&lirc_dev_lock);
+       if (err) {
+               put_device(&ir->dev);
+               return err;
+       }
 
        get_device(ir->dev.parent);
 
                 ir->d.name, ir->d.minor);
 
        return 0;
-
-out_dev:
-       put_device(&ir->dev);
-out_lock:
-       mutex_unlock(&lirc_dev_lock);
-
-       return err;
 }
 EXPORT_SYMBOL(lirc_register_driver);
 
 
        ir = d->irctl;
 
-       mutex_lock(&lirc_dev_lock);
-
        dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
                d->name, d->minor);
 
+       cdev_device_del(&ir->cdev, &ir->dev);
+
+       mutex_lock(&ir->mutex);
+
        ir->attached = false;
        if (ir->open) {
                dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
                wake_up_interruptible(&ir->buf->wait_poll);
        }
 
-       mutex_unlock(&lirc_dev_lock);
+       mutex_unlock(&ir->mutex);
 
-       cdev_device_del(&ir->cdev, &ir->dev);
        put_device(&ir->dev);
 }
 EXPORT_SYMBOL(lirc_unregister_driver);
 
        dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
 
-       if (ir->open)
-               return -EBUSY;
+       retval = mutex_lock_interruptible(&ir->mutex);
+       if (retval)
+               return retval;
+
+       if (!ir->attached) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       if (ir->open) {
+               retval = -EBUSY;
+               goto out;
+       }
 
        if (ir->d.rdev) {
                retval = rc_open(ir->d.rdev);
                if (retval)
-                       return retval;
+                       goto out;
        }
 
        if (ir->buf)
 
        lirc_init_pdata(inode, file);
        nonseekable_open(inode, file);
+       mutex_unlock(&ir->mutex);
 
        return 0;
+
+out:
+       mutex_unlock(&ir->mutex);
+       return retval;
 }
 EXPORT_SYMBOL(lirc_dev_fop_open);
 
 int lirc_dev_fop_close(struct inode *inode, struct file *file)
 {
        struct irctl *ir = file->private_data;
-       int ret;
 
-       ret = mutex_lock_killable(&lirc_dev_lock);
-       WARN_ON(ret);
+       mutex_lock(&ir->mutex);
 
        rc_close(ir->d.rdev);
-
        ir->open--;
-       if (!ret)
-               mutex_unlock(&lirc_dev_lock);
+
+       mutex_unlock(&ir->mutex);
 
        return 0;
 }
 {
        struct irctl *ir = file->private_data;
        __u32 mode;
-       int result = 0;
+       int result;
 
        dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
                ir->d.name, ir->d.minor, cmd);
 
+       result = mutex_lock_interruptible(&ir->mutex);
+       if (result)
+               return result;
+
        if (!ir->attached) {
-               dev_err(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
-                       ir->d.name, ir->d.minor);
-               return -ENODEV;
+               result = -ENODEV;
+               goto out;
        }
 
-       mutex_lock(&ir->irctl_lock);
-
        switch (cmd) {
        case LIRC_GET_FEATURES:
                result = put_user(ir->d.features, (__u32 __user *)arg);
                result = -ENOTTY;
        }
 
-       mutex_unlock(&ir->irctl_lock);
-
+out:
+       mutex_unlock(&ir->mutex);
        return result;
 }
 EXPORT_SYMBOL(lirc_dev_fop_ioctl);
 {
        struct irctl *ir = file->private_data;
        unsigned char *buf;
-       int ret = 0, written = 0;
+       int ret, written = 0;
        DECLARE_WAITQUEUE(wait, current);
 
-       if (!LIRC_CAN_REC(ir->d.features))
-               return -EINVAL;
-
        dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
 
        buf = kzalloc(ir->buf->chunk_size, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       if (mutex_lock_interruptible(&ir->irctl_lock)) {
-               ret = -ERESTARTSYS;
-               goto out_unlocked;
+       ret = mutex_lock_interruptible(&ir->mutex);
+       if (ret) {
+               kfree(buf);
+               return ret;
        }
+
        if (!ir->attached) {
                ret = -ENODEV;
                goto out_locked;
        }
 
+       if (!LIRC_CAN_REC(ir->d.features)) {
+               ret = -EINVAL;
+               goto out_locked;
+       }
+
        if (length % ir->buf->chunk_size) {
                ret = -EINVAL;
                goto out_locked;
                                break;
                        }
 
-                       mutex_unlock(&ir->irctl_lock);
+                       mutex_unlock(&ir->mutex);
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
                        set_current_state(TASK_RUNNING);
 
-                       if (mutex_lock_interruptible(&ir->irctl_lock)) {
-                               ret = -ERESTARTSYS;
+                       ret = mutex_lock_interruptible(&ir->mutex);
+                       if (ret) {
                                remove_wait_queue(&ir->buf->wait_poll, &wait);
                                goto out_unlocked;
                        }
        remove_wait_queue(&ir->buf->wait_poll, &wait);
 
 out_locked:
-       mutex_unlock(&ir->irctl_lock);
+       mutex_unlock(&ir->mutex);
 
 out_unlocked:
        kfree(buf);