diff options
Diffstat (limited to 'drivers/hid/hidraw.c')
-rw-r--r-- | drivers/hid/hidraw.c | 60 |
1 files changed, 25 insertions, 35 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index a7451632ceb4..612a655bc9f0 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -113,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, __u8 *buf; int ret = 0; - if (!hidraw_table[minor]) { + if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { ret = -ENODEV; goto out; } @@ -261,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file) } mutex_lock(&minors_lock); - if (!hidraw_table[minor]) { + if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { err = -ENODEV; goto out_unlock; } @@ -302,39 +302,38 @@ static int hidraw_fasync(int fd, struct file *file, int on) return fasync_helper(fd, file, on, &list->fasync); } +static void drop_ref(struct hidraw *hidraw, int exists_bit) +{ + if (exists_bit) { + hid_hw_close(hidraw->hid); + hidraw->exist = 0; + if (hidraw->open) + wake_up_interruptible(&hidraw->wait); + } else { + --hidraw->open; + } + + if (!hidraw->open && !hidraw->exist) { + device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); + hidraw_table[hidraw->minor] = NULL; + kfree(hidraw); + } +} + static int hidraw_release(struct inode * inode, struct file * file) { unsigned int minor = iminor(inode); - struct hidraw *dev; struct hidraw_list *list = file->private_data; - int ret; - int i; mutex_lock(&minors_lock); - if (!hidraw_table[minor]) { - ret = -ENODEV; - goto unlock; - } list_del(&list->node); - dev = hidraw_table[minor]; - if (!--dev->open) { - if (list->hidraw->exist) { - hid_hw_power(dev->hid, PM_HINT_NORMAL); - hid_hw_close(dev->hid); - } else { - kfree(list->hidraw); - } - } - - for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i) - kfree(list->buffer[i].value); kfree(list); - ret = 0; -unlock: - mutex_unlock(&minors_lock); - return ret; + drop_ref(hidraw_table[minor], 0); + + mutex_unlock(&minors_lock); + return 0; } static long hidraw_ioctl(struct file *file, unsigned int cmd, @@ -539,18 +538,9 @@ void hidraw_disconnect(struct hid_device *hid) struct hidraw *hidraw = hid->hidraw; mutex_lock(&minors_lock); - hidraw->exist = 0; - - device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); - hidraw_table[hidraw->minor] = NULL; + drop_ref(hidraw, 1); - if (hidraw->open) { - hid_hw_close(hid); - wake_up_interruptible(&hidraw->wait); - } else { - kfree(hidraw); - } mutex_unlock(&minors_lock); } EXPORT_SYMBOL_GPL(hidraw_disconnect); |