aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hidraw.c60
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
305static 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
305static int hidraw_release(struct inode * inode, struct file * file) 323static 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;
334unlock:
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
340static long hidraw_ioctl(struct file *file, unsigned int cmd, 339static 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}
556EXPORT_SYMBOL_GPL(hidraw_disconnect); 546EXPORT_SYMBOL_GPL(hidraw_disconnect);