summaryrefslogtreecommitdiff
path: root/drivers/char/ir.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ir.c')
-rw-r--r--drivers/char/ir.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/drivers/char/ir.c b/drivers/char/ir.c
new file mode 100644
index 000000000000..67fe4628606d
--- /dev/null
+++ b/drivers/char/ir.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2005-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/ir.h>
+
+#define IR_MINOR 255
+
+static DEFINE_MUTEX(ir_mutex);
+
+static int ir_open_cnt; /* #times opened */
+
+static int ir_open(struct inode *inode, struct file *file)
+{
+ int ret;
+
+ mutex_lock(&ir_mutex);
+ if (0 == ir_open_cnt) {
+ ret = 0;
+ ir_open_cnt++;
+ } else {
+ ret = -1;
+ }
+ mutex_unlock(&ir_mutex);
+ return ret;
+}
+
+static int ir_release(struct inode *inode, struct file *file)
+{
+ mutex_lock(&ir_mutex);
+ ir_open_cnt--;
+ mutex_unlock(&ir_mutex);
+ return 0;
+}
+
+
+static long ir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct miscdevice *c;
+ void *devdata;
+ int ret = 0;
+
+ mutex_lock(&ir_mutex);
+ c = file->private_data;
+ if (!c) {
+ mutex_unlock(&ir_mutex);
+ return -EINVAL;
+ }
+ devdata = dev_get_drvdata(c->this_device);
+ if (!devdata) {
+ mutex_unlock(&ir_mutex);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case IR_GET_CARRIER_FREQS:
+ {
+ struct ir_carrier_freq ir_carrier;
+ int id;
+
+ if (copy_from_user(&ir_carrier,
+ arg,
+ sizeof(struct ir_carrier_freq))) {
+ ret = -EINVAL;
+ } else {
+ id = ir_carrier.id;
+ ret = ir_get_carrier_range(id,
+ &ir_carrier.min,
+ &ir_carrier.max);
+ if (0 == ret) {
+ if (copy_to_user(arg, &ir_carrier, sizeof(ir_carrier)))
+ ret = -EINVAL;
+ }
+ }
+ break;
+ }
+ case IR_GET_CARRIER_FREQS_NUM:
+ {
+ int num = ir_get_num_carrier_freqs();
+ if (copy_to_user(arg, &num, 1))
+ ret = -EINVAL;
+ break;
+ }
+ case IR_CFG_CARRIER:
+ {
+ int carrier = (int)(arg);
+ ir_config(devdata, carrier);
+ break;
+ }
+ case IR_DATA_TRANSMIT:
+ {
+ struct ir_data_pattern p;
+ int *pattern;
+
+ if (!arg) {
+ mutex_unlock(&ir_mutex);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&p, arg, sizeof(struct ir_data_pattern))) {
+ mutex_unlock(&ir_mutex);
+ return -EINVAL;
+ }
+
+ pattern = kzalloc(p.len*sizeof(int), GFP_KERNEL);
+ if (!pattern) {
+ mutex_unlock(&ir_mutex);
+ printk(KERN_ERR "memory allocate for IR pattern error.\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(pattern, p.pattern, p.len*sizeof(int))) {
+ printk(KERN_ERR "memory allocate for IR pattern error.\n");
+ ret = -EINVAL;
+ } else {
+ ir_transmit(devdata, p.len, pattern, 1);
+ }
+ kfree(pattern);
+ break;
+ }
+ default:
+ break;
+ }
+ mutex_unlock(&ir_mutex);
+ return ret;
+}
+
+static const struct file_operations ir_fops = {
+ .owner = THIS_MODULE,
+ .open = ir_open,
+ .release = ir_release,
+ .unlocked_ioctl = ir_ioctl,
+};
+
+static struct miscdevice ir_miscdev = {
+ .minor = IR_MINOR,
+ .name = "ir",
+ .fops = &ir_fops,
+};
+
+void ir_device_register(const char *name, struct device *parent, void *devdata)
+{
+ int ret;
+ ret = misc_register(&ir_miscdev);
+ dev_set_drvdata(ir_miscdev.this_device, devdata);
+ return ret;
+}
+EXPORT_SYMBOL(ir_device_register);
+
+void ir_device_unregister(void)
+{
+ misc_deregister(&ir_miscdev);
+}
+EXPORT_SYMBOL(ir_device_unregister);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IR Low Abstract Layer");
+MODULE_LICENSE("GPL");
+