|
@@ -54,7 +54,8 @@ struct irctl {
|
|
|
struct lirc_buffer *buf;
|
|
|
unsigned int chunk_size;
|
|
|
|
|
|
- struct cdev *cdev;
|
|
|
+ struct device dev;
|
|
|
+ struct cdev cdev;
|
|
|
|
|
|
struct task_struct *task;
|
|
|
long jiffies_to_wait;
|
|
@@ -76,15 +77,21 @@ static void lirc_irctl_init(struct irctl *ir)
|
|
|
ir->d.minor = NOPLUG;
|
|
|
}
|
|
|
|
|
|
-static void lirc_irctl_cleanup(struct irctl *ir)
|
|
|
+static void lirc_release(struct device *ld)
|
|
|
{
|
|
|
- device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
|
|
|
+ struct irctl *ir = container_of(ld, struct irctl, dev);
|
|
|
+
|
|
|
+ put_device(ir->dev.parent);
|
|
|
|
|
|
if (ir->buf != ir->d.rbuf) {
|
|
|
lirc_buffer_free(ir->buf);
|
|
|
kfree(ir->buf);
|
|
|
}
|
|
|
- ir->buf = NULL;
|
|
|
+
|
|
|
+ mutex_lock(&lirc_dev_lock);
|
|
|
+ irctls[ir->d.minor] = NULL;
|
|
|
+ mutex_unlock(&lirc_dev_lock);
|
|
|
+ kfree(ir);
|
|
|
}
|
|
|
|
|
|
/* helper function
|
|
@@ -157,32 +164,21 @@ static int lirc_cdev_add(struct irctl *ir)
|
|
|
struct cdev *cdev;
|
|
|
int retval;
|
|
|
|
|
|
- cdev = cdev_alloc();
|
|
|
- if (!cdev)
|
|
|
- return -ENOMEM;
|
|
|
+ cdev = &ir->cdev;
|
|
|
|
|
|
if (d->fops) {
|
|
|
- cdev->ops = d->fops;
|
|
|
+ cdev_init(cdev, d->fops);
|
|
|
cdev->owner = d->owner;
|
|
|
} else {
|
|
|
- cdev->ops = &lirc_dev_fops;
|
|
|
+ cdev_init(cdev, &lirc_dev_fops);
|
|
|
cdev->owner = THIS_MODULE;
|
|
|
}
|
|
|
retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
|
|
|
if (retval)
|
|
|
- goto err_out;
|
|
|
-
|
|
|
- retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
|
|
|
- if (retval)
|
|
|
- goto err_out;
|
|
|
-
|
|
|
- ir->cdev = cdev;
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return retval;
|
|
|
|
|
|
-err_out:
|
|
|
- cdev_del(cdev);
|
|
|
- return retval;
|
|
|
+ cdev->kobj.parent = &ir->dev.kobj;
|
|
|
+ return cdev_add(cdev, ir->dev.devt, 1);
|
|
|
}
|
|
|
|
|
|
static int lirc_allocate_buffer(struct irctl *ir)
|
|
@@ -304,9 +300,12 @@ static int lirc_allocate_driver(struct lirc_driver *d)
|
|
|
|
|
|
ir->d = *d;
|
|
|
|
|
|
- device_create(lirc_class, ir->d.dev,
|
|
|
- MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
|
|
|
- "lirc%u", ir->d.minor);
|
|
|
+ ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor);
|
|
|
+ ir->dev.class = lirc_class;
|
|
|
+ ir->dev.parent = d->dev;
|
|
|
+ ir->dev.release = lirc_release;
|
|
|
+ dev_set_name(&ir->dev, "lirc%d", ir->d.minor);
|
|
|
+ device_initialize(&ir->dev);
|
|
|
|
|
|
if (d->sample_rate) {
|
|
|
ir->jiffies_to_wait = HZ / d->sample_rate;
|
|
@@ -329,14 +328,22 @@ static int lirc_allocate_driver(struct lirc_driver *d)
|
|
|
goto out_sysfs;
|
|
|
|
|
|
ir->attached = 1;
|
|
|
+
|
|
|
+ err = device_add(&ir->dev);
|
|
|
+ if (err)
|
|
|
+ goto out_cdev;
|
|
|
+
|
|
|
mutex_unlock(&lirc_dev_lock);
|
|
|
|
|
|
+ get_device(ir->dev.parent);
|
|
|
+
|
|
|
dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
|
|
|
ir->d.name, ir->d.minor);
|
|
|
return minor;
|
|
|
-
|
|
|
+out_cdev:
|
|
|
+ cdev_del(&ir->cdev);
|
|
|
out_sysfs:
|
|
|
- device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
|
|
|
+ put_device(&ir->dev);
|
|
|
out_lock:
|
|
|
mutex_unlock(&lirc_dev_lock);
|
|
|
|
|
@@ -364,7 +371,6 @@ EXPORT_SYMBOL(lirc_register_driver);
|
|
|
int lirc_unregister_driver(int minor)
|
|
|
{
|
|
|
struct irctl *ir;
|
|
|
- struct cdev *cdev;
|
|
|
|
|
|
if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
|
|
|
pr_err("minor (%d) must be between 0 and %d!\n",
|
|
@@ -378,8 +384,6 @@ int lirc_unregister_driver(int minor)
|
|
|
return -ENOENT;
|
|
|
}
|
|
|
|
|
|
- cdev = ir->cdev;
|
|
|
-
|
|
|
mutex_lock(&lirc_dev_lock);
|
|
|
|
|
|
if (ir->d.minor != minor) {
|
|
@@ -401,22 +405,20 @@ int lirc_unregister_driver(int minor)
|
|
|
dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
|
|
|
ir->d.name, ir->d.minor);
|
|
|
wake_up_interruptible(&ir->buf->wait_poll);
|
|
|
- mutex_lock(&ir->irctl_lock);
|
|
|
+ }
|
|
|
|
|
|
- if (ir->d.set_use_dec)
|
|
|
- ir->d.set_use_dec(ir->d.data);
|
|
|
+ mutex_lock(&ir->irctl_lock);
|
|
|
|
|
|
- module_put(cdev->owner);
|
|
|
- mutex_unlock(&ir->irctl_lock);
|
|
|
- } else {
|
|
|
- lirc_irctl_cleanup(ir);
|
|
|
- cdev_del(cdev);
|
|
|
- kfree(ir);
|
|
|
- irctls[minor] = NULL;
|
|
|
- }
|
|
|
+ if (ir->d.set_use_dec)
|
|
|
+ ir->d.set_use_dec(ir->d.data);
|
|
|
|
|
|
+ mutex_unlock(&ir->irctl_lock);
|
|
|
mutex_unlock(&lirc_dev_lock);
|
|
|
|
|
|
+ device_del(&ir->dev);
|
|
|
+ cdev_del(&ir->cdev);
|
|
|
+ put_device(&ir->dev);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(lirc_unregister_driver);
|
|
@@ -424,7 +426,6 @@ EXPORT_SYMBOL(lirc_unregister_driver);
|
|
|
int lirc_dev_fop_open(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
struct irctl *ir;
|
|
|
- struct cdev *cdev;
|
|
|
int retval = 0;
|
|
|
|
|
|
if (iminor(inode) >= MAX_IRCTL_DEVICES) {
|
|
@@ -459,18 +460,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- cdev = ir->cdev;
|
|
|
- if (try_module_get(cdev->owner)) {
|
|
|
- ir->open++;
|
|
|
- if (ir->d.set_use_inc)
|
|
|
- retval = ir->d.set_use_inc(ir->d.data);
|
|
|
-
|
|
|
- if (retval) {
|
|
|
- module_put(cdev->owner);
|
|
|
- ir->open--;
|
|
|
- } else if (ir->buf) {
|
|
|
+ ir->open++;
|
|
|
+ if (ir->d.set_use_inc)
|
|
|
+ retval = ir->d.set_use_inc(ir->d.data);
|
|
|
+ if (retval) {
|
|
|
+ ir->open--;
|
|
|
+ } else {
|
|
|
+ if (ir->buf)
|
|
|
lirc_buffer_clear(ir->buf);
|
|
|
- }
|
|
|
if (ir->task)
|
|
|
wake_up_process(ir->task);
|
|
|
}
|
|
@@ -487,7 +484,6 @@ 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;
|
|
|
int ret;
|
|
|
|
|
|
if (!ir) {
|
|
@@ -495,25 +491,14 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- cdev = ir->cdev;
|
|
|
-
|
|
|
ret = mutex_lock_killable(&lirc_dev_lock);
|
|
|
WARN_ON(ret);
|
|
|
|
|
|
rc_close(ir->d.rdev);
|
|
|
|
|
|
ir->open--;
|
|
|
- if (ir->attached) {
|
|
|
- if (ir->d.set_use_dec)
|
|
|
- ir->d.set_use_dec(ir->d.data);
|
|
|
- module_put(cdev->owner);
|
|
|
- } else {
|
|
|
- lirc_irctl_cleanup(ir);
|
|
|
- cdev_del(cdev);
|
|
|
- irctls[ir->d.minor] = NULL;
|
|
|
- kfree(ir);
|
|
|
- }
|
|
|
-
|
|
|
+ if (ir->d.set_use_dec)
|
|
|
+ ir->d.set_use_dec(ir->d.data);
|
|
|
if (!ret)
|
|
|
mutex_unlock(&lirc_dev_lock);
|
|
|
|
|
@@ -780,15 +765,12 @@ static int __init lirc_dev_init(void)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
pr_info("IR Remote Control driver registered, major %d\n",
|
|
|
MAJOR(lirc_base_dev));
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
static void __exit lirc_dev_exit(void)
|
|
|
{
|
|
|
class_destroy(lirc_class);
|