diff options
-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, | |||
113 | __u8 *buf; | 113 | __u8 *buf; |
114 | int ret = 0; | 114 | int ret = 0; |
115 | 115 | ||
116 | if (!hidraw_table[minor]) { | 116 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { |
117 | ret = -ENODEV; | 117 | ret = -ENODEV; |
118 | goto out; | 118 | goto out; |
119 | } | 119 | } |
@@ -261,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
261 | } | 261 | } |
262 | 262 | ||
263 | mutex_lock(&minors_lock); | 263 | mutex_lock(&minors_lock); |
264 | if (!hidraw_table[minor]) { | 264 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { |
265 | err = -ENODEV; | 265 | err = -ENODEV; |
266 | goto out_unlock; | 266 | goto out_unlock; |
267 | } | 267 | } |
@@ -302,39 +302,38 @@ static int hidraw_fasync(int fd, struct file *file, int on) | |||
302 | return fasync_helper(fd, file, on, &list->fasync); | 302 | return fasync_helper(fd, file, on, &list->fasync); |
303 | } | 303 | } |
304 | 304 | ||
305 | static void drop_ref(struct hidraw *hidraw, int exists_bit) | ||
306 | { | ||
307 | if (exists_bit) { | ||
308 | hid_hw_close(hidraw->hid); | ||
309 | hidraw->exist = 0; | ||
310 | if (hidraw->open) | ||
311 | wake_up_interruptible(&hidraw->wait); | ||
312 | } else { | ||
313 | --hidraw->open; | ||
314 | } | ||
315 | |||
316 | if (!hidraw->open && !hidraw->exist) { | ||
317 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | ||
318 | hidraw_table[hidraw->minor] = NULL; | ||
319 | kfree(hidraw); | ||
320 | } | ||
321 | } | ||
322 | |||
305 | static int hidraw_release(struct inode * inode, struct file * file) | 323 | static int hidraw_release(struct inode * inode, struct file * file) |
306 | { | 324 | { |
307 | unsigned int minor = iminor(inode); | 325 | unsigned int minor = iminor(inode); |
308 | struct hidraw *dev; | ||
309 | struct hidraw_list *list = file->private_data; | 326 | struct hidraw_list *list = file->private_data; |
310 | int ret; | ||
311 | int i; | ||
312 | 327 | ||
313 | mutex_lock(&minors_lock); | 328 | mutex_lock(&minors_lock); |
314 | if (!hidraw_table[minor]) { | ||
315 | ret = -ENODEV; | ||
316 | goto unlock; | ||
317 | } | ||
318 | 329 | ||
319 | list_del(&list->node); | 330 | list_del(&list->node); |
320 | dev = hidraw_table[minor]; | ||
321 | if (!--dev->open) { | ||
322 | if (list->hidraw->exist) { | ||
323 | hid_hw_power(dev->hid, PM_HINT_NORMAL); | ||
324 | hid_hw_close(dev->hid); | ||
325 | } else { | ||
326 | kfree(list->hidraw); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i) | ||
331 | kfree(list->buffer[i].value); | ||
332 | kfree(list); | 331 | kfree(list); |
333 | ret = 0; | ||
334 | unlock: | ||
335 | mutex_unlock(&minors_lock); | ||
336 | 332 | ||
337 | return ret; | 333 | drop_ref(hidraw_table[minor], 0); |
334 | |||
335 | mutex_unlock(&minors_lock); | ||
336 | return 0; | ||
338 | } | 337 | } |
339 | 338 | ||
340 | static long hidraw_ioctl(struct file *file, unsigned int cmd, | 339 | static long hidraw_ioctl(struct file *file, unsigned int cmd, |
@@ -539,18 +538,9 @@ void hidraw_disconnect(struct hid_device *hid) | |||
539 | struct hidraw *hidraw = hid->hidraw; | 538 | struct hidraw *hidraw = hid->hidraw; |
540 | 539 | ||
541 | mutex_lock(&minors_lock); | 540 | mutex_lock(&minors_lock); |
542 | hidraw->exist = 0; | ||
543 | |||
544 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | ||
545 | 541 | ||
546 | hidraw_table[hidraw->minor] = NULL; | 542 | drop_ref(hidraw, 1); |
547 | 543 | ||
548 | if (hidraw->open) { | ||
549 | hid_hw_close(hid); | ||
550 | wake_up_interruptible(&hidraw->wait); | ||
551 | } else { | ||
552 | kfree(hidraw); | ||
553 | } | ||
554 | mutex_unlock(&minors_lock); | 544 | mutex_unlock(&minors_lock); |
555 | } | 545 | } |
556 | EXPORT_SYMBOL_GPL(hidraw_disconnect); | 546 | EXPORT_SYMBOL_GPL(hidraw_disconnect); |