diff options
Diffstat (limited to 'drivers/media/rc/lirc_dev.c')
-rw-r--r-- | drivers/media/rc/lirc_dev.c | 299 |
1 files changed, 140 insertions, 159 deletions
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 92ae1903c010..91f9bb87ce68 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -80,8 +82,6 @@ static void lirc_irctl_init(struct irctl *ir) static void lirc_irctl_cleanup(struct irctl *ir) { - dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); - device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); if (ir->buf != ir->d.rbuf) { @@ -97,28 +97,25 @@ static void lirc_irctl_cleanup(struct irctl *ir) */ static int lirc_add_to_buf(struct irctl *ir) { - if (ir->d.add_to_buf) { - int res = -ENODATA; - int got_data = 0; + int res; + int got_data = -1; - /* - * service the device as long as it is returning - * data and we have space - */ -get_data: - res = ir->d.add_to_buf(ir->d.data, ir->buf); - if (res == 0) { - got_data++; - goto get_data; - } + if (!ir->d.add_to_buf) + return 0; - if (res == -ENODEV) - kthread_stop(ir->task); + /* + * service the device as long as it is returning + * data and we have space + */ + do { + got_data++; + res = ir->d.add_to_buf(ir->d.data, ir->buf); + } while (!res); - return got_data ? 0 : res; - } + if (res == -ENODEV) + kthread_stop(ir->task); - return 0; + return got_data ? 0 : res; } /* main function of the polling thread @@ -127,9 +124,6 @@ static int lirc_thread(void *irctl) { struct irctl *ir = irctl; - dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", - ir->d.name, ir->d.minor); - do { if (ir->open) { if (ir->jiffies_to_wait) { @@ -146,9 +140,6 @@ static int lirc_thread(void *irctl) } } while (!kthread_should_stop()); - dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", - ir->d.name, ir->d.minor); - return 0; } @@ -203,74 +194,86 @@ err_out: return retval; } -int lirc_register_driver(struct lirc_driver *d) +static int lirc_allocate_buffer(struct irctl *ir) { - struct irctl *ir; - int minor; + int err = 0; int bytes_in_key; unsigned int chunk_size; unsigned int buffer_size; + struct lirc_driver *d = &ir->d; + + mutex_lock(&lirc_dev_lock); + + bytes_in_key = BITS_TO_LONGS(d->code_length) + + (d->code_length % 8 ? 1 : 0); + buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; + chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; + + if (d->rbuf) { + ir->buf = d->rbuf; + } else { + ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!ir->buf) { + err = -ENOMEM; + goto out; + } + + err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); + if (err) { + kfree(ir->buf); + goto out; + } + } + ir->chunk_size = ir->buf->chunk_size; + +out: + mutex_unlock(&lirc_dev_lock); + + return err; +} + +static int lirc_allocate_driver(struct lirc_driver *d) +{ + struct irctl *ir; + int minor; int err; if (!d) { - printk(KERN_ERR "lirc_dev: lirc_register_driver: " - "driver pointer must be not NULL!\n"); - err = -EBADRQC; - goto out; + pr_err("driver pointer must be not NULL!\n"); + return -EBADRQC; } if (!d->dev) { - printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__); - err = -EINVAL; - goto out; + pr_err("dev pointer not filled in!\n"); + return -EINVAL; } - 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); - err = -EBADRQC; - goto out; + if (d->minor >= MAX_IRCTL_DEVICES) { + dev_err(d->dev, "minor must be between 0 and %d!\n", + MAX_IRCTL_DEVICES - 1); + return -EBADRQC; } - if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "code length in bits for minor (%d) " - "must be less than %d!\n", - d->minor, BUFLEN * 8); - err = -EBADRQC; - goto out; + if (d->code_length < 1 || d->code_length > (BUFLEN * 8)) { + dev_err(d->dev, "code length must be less than %d bits\n", + BUFLEN * 8); + return -EBADRQC; } - dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", - d->sample_rate); if (d->sample_rate) { if (2 > d->sample_rate || HZ < d->sample_rate) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "sample_rate must be between 2 and %d!\n", HZ); - err = -EBADRQC; - goto out; + dev_err(d->dev, "invalid %d sample rate\n", + d->sample_rate); + return -EBADRQC; } if (!d->add_to_buf) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "add_to_buf cannot be NULL when " - "sample_rate is set\n"); - err = -EBADRQC; - goto out; - } - } else if (!(d->fops && d->fops->read) && !d->rbuf) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "fops->read and rbuf cannot all be NULL!\n"); - err = -EBADRQC; - goto out; - } else if (!d->rbuf) { - if (!(d->fops && d->fops->read && d->fops->poll && - d->fops->unlocked_ioctl)) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "neither read, poll nor unlocked_ioctl can be NULL!\n"); - err = -EBADRQC; - goto out; + dev_err(d->dev, "add_to_buf not set\n"); + return -EBADRQC; } + } else if (!d->rbuf && !(d->fops && d->fops->read && + d->fops->poll && d->fops->unlocked_ioctl)) { + dev_err(d->dev, "undefined read, poll, ioctl\n"); + return -EBADRQC; } mutex_lock(&lirc_dev_lock); @@ -282,15 +285,13 @@ int lirc_register_driver(struct lirc_driver *d) for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) if (!irctls[minor]) break; - if (MAX_IRCTL_DEVICES == minor) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "no free slots for drivers!\n"); + if (minor == MAX_IRCTL_DEVICES) { + dev_err(d->dev, "no free slots for drivers!\n"); err = -ENOMEM; goto out_lock; } } else if (irctls[minor]) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "minor (%d) just registered!\n", minor); + dev_err(d->dev, "minor (%d) just registered!\n", minor); err = -EBUSY; goto out_lock; } @@ -304,37 +305,9 @@ int lirc_register_driver(struct lirc_driver *d) irctls[minor] = ir; d->minor = minor; - if (d->sample_rate) { - ir->jiffies_to_wait = HZ / d->sample_rate; - } else { - /* it means - wait for external event in task queue */ - ir->jiffies_to_wait = 0; - } - /* some safety check 8-) */ d->name[sizeof(d->name)-1] = '\0'; - bytes_in_key = BITS_TO_LONGS(d->code_length) + - (d->code_length % 8 ? 1 : 0); - buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; - chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; - - if (d->rbuf) { - ir->buf = d->rbuf; - } else { - ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!ir->buf) { - err = -ENOMEM; - goto out_lock; - } - err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); - if (err) { - kfree(ir->buf); - goto out_lock; - } - } - ir->chunk_size = ir->buf->chunk_size; - if (d->features == 0) d->features = LIRC_CAN_REC_LIRCCODE; @@ -345,15 +318,19 @@ int lirc_register_driver(struct lirc_driver *d) "lirc%u", ir->d.minor); if (d->sample_rate) { + ir->jiffies_to_wait = HZ / d->sample_rate; + /* try to fire up polling thread */ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); if (IS_ERR(ir->task)) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "cannot run poll thread for minor = %d\n", - d->minor); + dev_err(d->dev, "cannot run thread for minor = %d\n", + d->minor); err = -ECHILD; goto out_sysfs; } + } else { + /* it means - wait for external event in task queue */ + ir->jiffies_to_wait = 0; } err = lirc_cdev_add(ir); @@ -371,9 +348,26 @@ out_sysfs: device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); out_lock: mutex_unlock(&lirc_dev_lock); -out: + return err; } + +int lirc_register_driver(struct lirc_driver *d) +{ + int minor, err = 0; + + minor = lirc_allocate_driver(d); + if (minor < 0) + return minor; + + if (LIRC_CAN_REC(d->features)) { + err = lirc_allocate_buffer(irctls[minor]); + if (err) + lirc_unregister_driver(minor); + } + + return err ? err : minor; +} EXPORT_SYMBOL(lirc_register_driver); int lirc_unregister_driver(int minor) @@ -382,15 +376,14 @@ int lirc_unregister_driver(int minor) struct cdev *cdev; 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); + pr_err("minor (%d) must be between 0 and %d!\n", + minor, MAX_IRCTL_DEVICES - 1); return -EBADRQC; } ir = irctls[minor]; if (!ir) { - printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct " - "for minor %d!\n", __func__, minor); + pr_err("failed to get irctl\n"); return -ENOENT; } @@ -399,8 +392,8 @@ int lirc_unregister_driver(int minor) mutex_lock(&lirc_dev_lock); if (ir->d.minor != minor) { - printk(KERN_ERR "lirc_dev: %s: minor (%d) device not " - "registered!\n", __func__, minor); + dev_err(ir->d.dev, "lirc_dev: minor %d device not registered\n", + minor); mutex_unlock(&lirc_dev_lock); return -ENOENT; } @@ -418,7 +411,10 @@ int lirc_unregister_driver(int minor) ir->d.name, ir->d.minor); wake_up_interruptible(&ir->buf->wait_poll); mutex_lock(&ir->irctl_lock); - ir->d.set_use_dec(ir->d.data); + + if (ir->d.set_use_dec) + ir->d.set_use_dec(ir->d.data); + module_put(cdev->owner); mutex_unlock(&ir->irctl_lock); } else { @@ -442,8 +438,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) int retval = 0; if (iminor(inode) >= MAX_IRCTL_DEVICES) { - printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", - iminor(inode)); + pr_err("open result for %d is -ENODEV\n", iminor(inode)); return -ENODEV; } @@ -477,7 +472,8 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) cdev = ir->cdev; if (try_module_get(cdev->owner)) { ir->open++; - retval = ir->d.set_use_inc(ir->d.data); + if (ir->d.set_use_inc) + retval = ir->d.set_use_inc(ir->d.data); if (retval) { module_put(cdev->owner); @@ -490,10 +486,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) } error: - if (ir) - dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", - ir->d.name, ir->d.minor, retval); - mutex_unlock(&lirc_dev_lock); nonseekable_open(inode, file); @@ -509,14 +501,12 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) int ret; if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + pr_err("called with invalid irctl\n"); return -EINVAL; } cdev = ir->cdev; - dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); - ret = mutex_lock_killable(&lirc_dev_lock); WARN_ON(ret); @@ -524,7 +514,8 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) ir->open--; if (ir->attached) { - ir->d.set_use_dec(ir->d.data); + if (ir->d.set_use_dec) + ir->d.set_use_dec(ir->d.data); module_put(cdev->owner); } else { lirc_irctl_cleanup(ir); @@ -547,12 +538,10 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) unsigned int ret; if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + pr_err("called with invalid irctl\n"); return POLLERR; } - dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); - if (!ir->attached) return POLLERR; @@ -580,7 +569,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct irctl *ir = irctls[iminor(file_inode(file))]; if (!ir) { - printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__); + pr_err("no irctl found!\n"); return -ENODEV; } @@ -588,7 +577,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ir->d.name, ir->d.minor, cmd); if (ir->d.minor == NOPLUG || !ir->attached) { - dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", + dev_err(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", ir->d.name, ir->d.minor); return -ENODEV; } @@ -600,8 +589,8 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) result = put_user(ir->d.features, (__u32 __user *)arg); break; case LIRC_GET_REC_MODE: - if (!(ir->d.features & LIRC_CAN_REC_MASK)) { - result = -ENOSYS; + if (LIRC_CAN_REC(ir->d.features)) { + result = -ENOTTY; break; } @@ -610,8 +599,8 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (__u32 __user *)arg); break; case LIRC_SET_REC_MODE: - if (!(ir->d.features & LIRC_CAN_REC_MASK)) { - result = -ENOSYS; + if (LIRC_CAN_REC(ir->d.features)) { + result = -ENOTTY; break; } @@ -629,7 +618,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case LIRC_GET_MIN_TIMEOUT: if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || ir->d.min_timeout == 0) { - result = -ENOSYS; + result = -ENOTTY; break; } @@ -638,7 +627,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case LIRC_GET_MAX_TIMEOUT: if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || ir->d.max_timeout == 0) { - result = -ENOSYS; + result = -ENOTTY; break; } @@ -648,9 +637,6 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) result = -EINVAL; } - dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", - ir->d.name, ir->d.minor, result); - mutex_unlock(&ir->irctl_lock); return result; @@ -668,7 +654,7 @@ ssize_t lirc_dev_fop_read(struct file *file, DECLARE_WAITQUEUE(wait, current); if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + pr_err("called with invalid irctl\n"); return -ENODEV; } @@ -709,7 +695,8 @@ ssize_t lirc_dev_fop_read(struct file *file, /* According to the read(2) man page, 'written' can be * returned as less than 'length', instead of blocking * again, returning -EWOULDBLOCK, or returning - * -ERESTARTSYS */ + * -ERESTARTSYS + */ if (written) break; if (file->f_flags & O_NONBLOCK) { @@ -755,8 +742,6 @@ out_locked: out_unlocked: kfree(buf); - dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", - ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret); return ret ? ret : written; } @@ -775,12 +760,10 @@ ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer, struct irctl *ir = irctls[iminor(file_inode(file))]; if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + pr_err("called with invalid irctl\n"); return -ENODEV; } - dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); - if (!ir->attached) return -ENODEV; @@ -795,25 +778,23 @@ static int __init lirc_dev_init(void) lirc_class = class_create(THIS_MODULE, "lirc"); if (IS_ERR(lirc_class)) { - retval = PTR_ERR(lirc_class); - printk(KERN_ERR "lirc_dev: class_create failed\n"); - goto error; + pr_err("class_create failed\n"); + return PTR_ERR(lirc_class); } retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, IRCTL_DEV_NAME); if (retval) { class_destroy(lirc_class); - printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); - goto error; + pr_err("alloc_chrdev_region failed\n"); + return retval; } - printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " - "major %d \n", MAJOR(lirc_base_dev)); + pr_info("IR Remote Control driver registered, major %d\n", + MAJOR(lirc_base_dev)); -error: - return retval; + return 0; } @@ -822,7 +803,7 @@ static void __exit lirc_dev_exit(void) { class_destroy(lirc_class); unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); - printk(KERN_INFO "lirc_dev: module unloaded\n"); + pr_info("module unloaded\n"); } module_init(lirc_dev_init); |