|
@@ -55,6 +55,8 @@ struct irctl {
|
|
|
struct lirc_buffer *buf;
|
|
|
unsigned int chunk_size;
|
|
|
|
|
|
+ struct cdev *cdev;
|
|
|
+
|
|
|
struct task_struct *task;
|
|
|
long jiffies_to_wait;
|
|
|
};
|
|
@@ -62,7 +64,6 @@ struct irctl {
|
|
|
static DEFINE_MUTEX(lirc_dev_lock);
|
|
|
|
|
|
static struct irctl *irctls[MAX_IRCTL_DEVICES];
|
|
|
-static struct cdev cdevs[MAX_IRCTL_DEVICES];
|
|
|
|
|
|
/* Only used for sysfs but defined to void otherwise */
|
|
|
static struct class *lirc_class;
|
|
@@ -167,9 +168,13 @@ static struct file_operations lirc_dev_fops = {
|
|
|
|
|
|
static int lirc_cdev_add(struct irctl *ir)
|
|
|
{
|
|
|
- int retval;
|
|
|
+ int retval = -ENOMEM;
|
|
|
struct lirc_driver *d = &ir->d;
|
|
|
- struct cdev *cdev = &cdevs[d->minor];
|
|
|
+ struct cdev *cdev;
|
|
|
+
|
|
|
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
|
|
|
+ if (!cdev)
|
|
|
+ goto err_out;
|
|
|
|
|
|
if (d->fops) {
|
|
|
cdev_init(cdev, d->fops);
|
|
@@ -180,12 +185,20 @@ static int lirc_cdev_add(struct irctl *ir)
|
|
|
}
|
|
|
retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
|
|
|
if (retval)
|
|
|
- return retval;
|
|
|
+ goto err_out;
|
|
|
|
|
|
retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
|
|
|
- if (retval)
|
|
|
+ if (retval) {
|
|
|
kobject_put(&cdev->kobj);
|
|
|
+ goto err_out;
|
|
|
+ }
|
|
|
+
|
|
|
+ ir->cdev = cdev;
|
|
|
+
|
|
|
+ return 0;
|
|
|
|
|
|
+err_out:
|
|
|
+ kfree(cdev);
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
@@ -214,7 +227,7 @@ int lirc_register_driver(struct lirc_driver *d)
|
|
|
if (MAX_IRCTL_DEVICES <= d->minor) {
|
|
|
dev_err(d->dev, "lirc_dev: lirc_register_driver: "
|
|
|
"\"minor\" must be between 0 and %d (%d)!\n",
|
|
|
- MAX_IRCTL_DEVICES-1, d->minor);
|
|
|
+ MAX_IRCTL_DEVICES - 1, d->minor);
|
|
|
err = -EBADRQC;
|
|
|
goto out;
|
|
|
}
|
|
@@ -369,7 +382,7 @@ int lirc_unregister_driver(int minor)
|
|
|
|
|
|
if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
|
|
|
printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
|
|
|
- "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1);
|
|
|
+ "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES - 1);
|
|
|
return -EBADRQC;
|
|
|
}
|
|
|
|
|
@@ -380,7 +393,7 @@ int lirc_unregister_driver(int minor)
|
|
|
return -ENOENT;
|
|
|
}
|
|
|
|
|
|
- cdev = &cdevs[minor];
|
|
|
+ cdev = ir->cdev;
|
|
|
|
|
|
mutex_lock(&lirc_dev_lock);
|
|
|
|
|
@@ -410,6 +423,7 @@ int lirc_unregister_driver(int minor)
|
|
|
} else {
|
|
|
lirc_irctl_cleanup(ir);
|
|
|
cdev_del(cdev);
|
|
|
+ kfree(cdev);
|
|
|
kfree(ir);
|
|
|
irctls[minor] = NULL;
|
|
|
}
|
|
@@ -453,7 +467,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- cdev = &cdevs[iminor(inode)];
|
|
|
+ cdev = ir->cdev;
|
|
|
if (try_module_get(cdev->owner)) {
|
|
|
ir->open++;
|
|
|
retval = ir->d.set_use_inc(ir->d.data);
|
|
@@ -484,13 +498,15 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
|
|
|
int lirc_dev_fop_close(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
struct irctl *ir = irctls[iminor(inode)];
|
|
|
- struct cdev *cdev = &cdevs[iminor(inode)];
|
|
|
+ struct cdev *cdev;
|
|
|
|
|
|
if (!ir) {
|
|
|
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ cdev = ir->cdev;
|
|
|
+
|
|
|
dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
|
|
|
|
|
|
WARN_ON(mutex_lock_killable(&lirc_dev_lock));
|
|
@@ -503,6 +519,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
|
|
|
lirc_irctl_cleanup(ir);
|
|
|
cdev_del(cdev);
|
|
|
irctls[ir->d.minor] = NULL;
|
|
|
+ kfree(cdev);
|
|
|
kfree(ir);
|
|
|
}
|
|
|
|