|
@@ -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);
|