aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorJarod Wilson <jarod@redhat.com>2010-10-18 17:39:20 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-22 18:05:36 -0400
commitc1cbb7029e81894c056680d61c64741bd2ff246f (patch)
tree99a96186dae129398300db241fbf5eff6bfd7d44 /drivers/media
parent09c8dd8de67cf781be95d809cd45af22f40c37df (diff)
[media] lirc_dev: rework storage for cdev data
Fixes an oops when an lirc driver that doesn't provide its own fops is unplugged while the lirc cdev is open. Tested with lirc_igorplugusb, with a special thanks to Timo Boettcher for providing the test hardware. Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/IR/lirc_dev.c40
1 files changed, 23 insertions, 17 deletions
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c
index 8fdb7e11a138..3ef15625fa84 100644
--- a/drivers/media/IR/lirc_dev.c
+++ b/drivers/media/IR/lirc_dev.c
@@ -58,13 +58,12 @@ struct irctl {
58 58
59 struct task_struct *task; 59 struct task_struct *task;
60 long jiffies_to_wait; 60 long jiffies_to_wait;
61
62 struct cdev cdev;
63}; 61};
64 62
65static DEFINE_MUTEX(lirc_dev_lock); 63static DEFINE_MUTEX(lirc_dev_lock);
66 64
67static struct irctl *irctls[MAX_IRCTL_DEVICES]; 65static struct irctl *irctls[MAX_IRCTL_DEVICES];
66static struct cdev cdevs[MAX_IRCTL_DEVICES];
68 67
69/* Only used for sysfs but defined to void otherwise */ 68/* Only used for sysfs but defined to void otherwise */
70static struct class *lirc_class; 69static struct class *lirc_class;
@@ -170,19 +169,20 @@ static int lirc_cdev_add(struct irctl *ir)
170{ 169{
171 int retval; 170 int retval;
172 struct lirc_driver *d = &ir->d; 171 struct lirc_driver *d = &ir->d;
172 struct cdev *cdev = &cdevs[d->minor];
173 173
174 if (d->fops) { 174 if (d->fops) {
175 cdev_init(&ir->cdev, d->fops); 175 cdev_init(cdev, d->fops);
176 ir->cdev.owner = d->owner; 176 cdev->owner = d->owner;
177 } else { 177 } else {
178 cdev_init(&ir->cdev, &lirc_dev_fops); 178 cdev_init(cdev, &lirc_dev_fops);
179 ir->cdev.owner = THIS_MODULE; 179 cdev->owner = THIS_MODULE;
180 } 180 }
181 kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); 181 kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
182 182
183 retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); 183 retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
184 if (retval) 184 if (retval)
185 kobject_put(&ir->cdev.kobj); 185 kobject_put(&cdev->kobj);
186 186
187 return retval; 187 return retval;
188} 188}
@@ -363,6 +363,7 @@ EXPORT_SYMBOL(lirc_register_driver);
363int lirc_unregister_driver(int minor) 363int lirc_unregister_driver(int minor)
364{ 364{
365 struct irctl *ir; 365 struct irctl *ir;
366 struct cdev *cdev;
366 367
367 if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { 368 if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
368 printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " 369 printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
@@ -377,6 +378,8 @@ int lirc_unregister_driver(int minor)
377 return -ENOENT; 378 return -ENOENT;
378 } 379 }
379 380
381 cdev = &cdevs[minor];
382
380 mutex_lock(&lirc_dev_lock); 383 mutex_lock(&lirc_dev_lock);
381 384
382 if (ir->d.minor != minor) { 385 if (ir->d.minor != minor) {
@@ -400,11 +403,11 @@ int lirc_unregister_driver(int minor)
400 wake_up_interruptible(&ir->buf->wait_poll); 403 wake_up_interruptible(&ir->buf->wait_poll);
401 mutex_lock(&ir->irctl_lock); 404 mutex_lock(&ir->irctl_lock);
402 ir->d.set_use_dec(ir->d.data); 405 ir->d.set_use_dec(ir->d.data);
403 module_put(ir->cdev.owner); 406 module_put(cdev->owner);
404 mutex_unlock(&ir->irctl_lock); 407 mutex_unlock(&ir->irctl_lock);
405 } else { 408 } else {
406 lirc_irctl_cleanup(ir); 409 lirc_irctl_cleanup(ir);
407 cdev_del(&ir->cdev); 410 cdev_del(cdev);
408 kfree(ir); 411 kfree(ir);
409 irctls[minor] = NULL; 412 irctls[minor] = NULL;
410 } 413 }
@@ -418,6 +421,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
418int lirc_dev_fop_open(struct inode *inode, struct file *file) 421int lirc_dev_fop_open(struct inode *inode, struct file *file)
419{ 422{
420 struct irctl *ir; 423 struct irctl *ir;
424 struct cdev *cdev;
421 int retval = 0; 425 int retval = 0;
422 426
423 if (iminor(inode) >= MAX_IRCTL_DEVICES) { 427 if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@@ -447,13 +451,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
447 goto error; 451 goto error;
448 } 452 }
449 453
450 if (try_module_get(ir->cdev.owner)) { 454 cdev = &cdevs[iminor(inode)];
451 ++ir->open; 455 if (try_module_get(cdev->owner)) {
456 ir->open++;
452 retval = ir->d.set_use_inc(ir->d.data); 457 retval = ir->d.set_use_inc(ir->d.data);
453 458
454 if (retval) { 459 if (retval) {
455 module_put(ir->cdev.owner); 460 module_put(cdev->owner);
456 --ir->open; 461 ir->open--;
457 } else { 462 } else {
458 lirc_buffer_clear(ir->buf); 463 lirc_buffer_clear(ir->buf);
459 } 464 }
@@ -475,6 +480,7 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
475int lirc_dev_fop_close(struct inode *inode, struct file *file) 480int lirc_dev_fop_close(struct inode *inode, struct file *file)
476{ 481{
477 struct irctl *ir = irctls[iminor(inode)]; 482 struct irctl *ir = irctls[iminor(inode)];
483 struct cdev *cdev = &cdevs[iminor(inode)];
478 484
479 if (!ir) { 485 if (!ir) {
480 printk(KERN_ERR "%s: called with invalid irctl\n", __func__); 486 printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
@@ -488,10 +494,10 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
488 ir->open--; 494 ir->open--;
489 if (ir->attached) { 495 if (ir->attached) {
490 ir->d.set_use_dec(ir->d.data); 496 ir->d.set_use_dec(ir->d.data);
491 module_put(ir->cdev.owner); 497 module_put(cdev->owner);
492 } else { 498 } else {
493 lirc_irctl_cleanup(ir); 499 lirc_irctl_cleanup(ir);
494 cdev_del(&ir->cdev); 500 cdev_del(cdev);
495 irctls[ir->d.minor] = NULL; 501 irctls[ir->d.minor] = NULL;
496 kfree(ir); 502 kfree(ir);
497 } 503 }