aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hidraw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hidraw.c')
-rw-r--r--drivers/hid/hidraw.c80
1 files changed, 40 insertions, 40 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 6f1feb2c2e97..8918dd12bb69 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 }
@@ -253,6 +253,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
253 unsigned int minor = iminor(inode); 253 unsigned int minor = iminor(inode);
254 struct hidraw *dev; 254 struct hidraw *dev;
255 struct hidraw_list *list; 255 struct hidraw_list *list;
256 unsigned long flags;
256 int err = 0; 257 int err = 0;
257 258
258 if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) { 259 if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
@@ -261,16 +262,11 @@ static int hidraw_open(struct inode *inode, struct file *file)
261 } 262 }
262 263
263 mutex_lock(&minors_lock); 264 mutex_lock(&minors_lock);
264 if (!hidraw_table[minor]) { 265 if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
265 err = -ENODEV; 266 err = -ENODEV;
266 goto out_unlock; 267 goto out_unlock;
267 } 268 }
268 269
269 list->hidraw = hidraw_table[minor];
270 mutex_init(&list->read_mutex);
271 list_add_tail(&list->node, &hidraw_table[minor]->list);
272 file->private_data = list;
273
274 dev = hidraw_table[minor]; 270 dev = hidraw_table[minor];
275 if (!dev->open++) { 271 if (!dev->open++) {
276 err = hid_hw_power(dev->hid, PM_HINT_FULLON); 272 err = hid_hw_power(dev->hid, PM_HINT_FULLON);
@@ -283,9 +279,16 @@ static int hidraw_open(struct inode *inode, struct file *file)
283 if (err < 0) { 279 if (err < 0) {
284 hid_hw_power(dev->hid, PM_HINT_NORMAL); 280 hid_hw_power(dev->hid, PM_HINT_NORMAL);
285 dev->open--; 281 dev->open--;
282 goto out_unlock;
286 } 283 }
287 } 284 }
288 285
286 list->hidraw = hidraw_table[minor];
287 mutex_init(&list->read_mutex);
288 spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
289 list_add_tail(&list->node, &hidraw_table[minor]->list);
290 spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
291 file->private_data = list;
289out_unlock: 292out_unlock:
290 mutex_unlock(&minors_lock); 293 mutex_unlock(&minors_lock);
291out: 294out:
@@ -302,39 +305,41 @@ static int hidraw_fasync(int fd, struct file *file, int on)
302 return fasync_helper(fd, file, on, &list->fasync); 305 return fasync_helper(fd, file, on, &list->fasync);
303} 306}
304 307
308static void drop_ref(struct hidraw *hidraw, int exists_bit)
309{
310 if (exists_bit) {
311 hid_hw_close(hidraw->hid);
312 hidraw->exist = 0;
313 if (hidraw->open)
314 wake_up_interruptible(&hidraw->wait);
315 } else {
316 --hidraw->open;
317 }
318
319 if (!hidraw->open && !hidraw->exist) {
320 device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
321 hidraw_table[hidraw->minor] = NULL;
322 kfree(hidraw);
323 }
324}
325
305static int hidraw_release(struct inode * inode, struct file * file) 326static int hidraw_release(struct inode * inode, struct file * file)
306{ 327{
307 unsigned int minor = iminor(inode); 328 unsigned int minor = iminor(inode);
308 struct hidraw *dev;
309 struct hidraw_list *list = file->private_data; 329 struct hidraw_list *list = file->private_data;
310 int ret; 330 unsigned long flags;
311 int i;
312 331
313 mutex_lock(&minors_lock); 332 mutex_lock(&minors_lock);
314 if (!hidraw_table[minor]) {
315 ret = -ENODEV;
316 goto unlock;
317 }
318 333
334 spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
319 list_del(&list->node); 335 list_del(&list->node);
320 dev = hidraw_table[minor]; 336 spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
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); 337 kfree(list);
333 ret = 0;
334unlock:
335 mutex_unlock(&minors_lock);
336 338
337 return ret; 339 drop_ref(hidraw_table[minor], 0);
340
341 mutex_unlock(&minors_lock);
342 return 0;
338} 343}
339 344
340static long hidraw_ioctl(struct file *file, unsigned int cmd, 345static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@ -457,7 +462,9 @@ int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
457 struct hidraw *dev = hid->hidraw; 462 struct hidraw *dev = hid->hidraw;
458 struct hidraw_list *list; 463 struct hidraw_list *list;
459 int ret = 0; 464 int ret = 0;
465 unsigned long flags;
460 466
467 spin_lock_irqsave(&dev->list_lock, flags);
461 list_for_each_entry(list, &dev->list, node) { 468 list_for_each_entry(list, &dev->list, node) {
462 int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); 469 int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
463 470
@@ -472,6 +479,7 @@ int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
472 list->head = new_head; 479 list->head = new_head;
473 kill_fasync(&list->fasync, SIGIO, POLL_IN); 480 kill_fasync(&list->fasync, SIGIO, POLL_IN);
474 } 481 }
482 spin_unlock_irqrestore(&dev->list_lock, flags);
475 483
476 wake_up_interruptible(&dev->wait); 484 wake_up_interruptible(&dev->wait);
477 return ret; 485 return ret;
@@ -519,6 +527,7 @@ int hidraw_connect(struct hid_device *hid)
519 } 527 }
520 528
521 init_waitqueue_head(&dev->wait); 529 init_waitqueue_head(&dev->wait);
530 spin_lock_init(&dev->list_lock);
522 INIT_LIST_HEAD(&dev->list); 531 INIT_LIST_HEAD(&dev->list);
523 532
524 dev->hid = hid; 533 dev->hid = hid;
@@ -539,18 +548,9 @@ void hidraw_disconnect(struct hid_device *hid)
539 struct hidraw *hidraw = hid->hidraw; 548 struct hidraw *hidraw = hid->hidraw;
540 549
541 mutex_lock(&minors_lock); 550 mutex_lock(&minors_lock);
542 hidraw->exist = 0;
543 551
544 device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); 552 drop_ref(hidraw, 1);
545 553
546 hidraw_table[hidraw->minor] = NULL;
547
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); 554 mutex_unlock(&minors_lock);
555} 555}
556EXPORT_SYMBOL_GPL(hidraw_disconnect); 556EXPORT_SYMBOL_GPL(hidraw_disconnect);