From: Jarod Wilson <jarod@redhat.com>
To: linux-media@vger.kernel.org
Subject: [PATCH 3/3] IR: add ir-core to lirc interface bridge driver
Date: Tue, 1 Jun 2010 16:52:58 -0400 [thread overview]
Message-ID: <20100601205258.GC31616@redhat.com> (raw)
In-Reply-To: <20100601205005.GA28322@redhat.com>
This is a new ir-core protocol plugin, which bridges from ir-core
raw IR data collection to the classic lirc device interface, which
allows pure ir-core drivers to pass raw IR data out to userspace to
be handled by the lirc userspace daemon.
At the moment, only the receive side is wired up, with future plans
to enable the transmit side as well. Tested successfully with the
mceusb driver and lirc 0.8.6.
Nb: since we're still hashing out what transmit support will look like,
its possible this should actually be ir-lirc-decoder, and transmit
support provided by a separate ir-lirc-encoder, but for the moment, I'm
going with ir-lirc-codec, as lirc_dev is also a two-way device interface.
Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
drivers/media/IR/Kconfig | 10 ++
drivers/media/IR/Makefile | 1 +
drivers/media/IR/ir-core-priv.h | 7 +
drivers/media/IR/ir-lirc-codec.c | 301 ++++++++++++++++++++++++++++++++++++++
drivers/media/IR/ir-raw-event.c | 1 +
5 files changed, 320 insertions(+), 0 deletions(-)
create mode 100644 drivers/media/IR/ir-lirc-codec.c
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
index c3010fb..bd7ee8b 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/IR/Kconfig
@@ -66,6 +66,16 @@ config IR_SONY_DECODER
Enable this option if you have an infrared remote control which
uses the Sony protocol, and you need software decoding support.
+config IR_LIRC_CODEC
+ tristate "Enable IR to LIRC bridge"
+ depends on IR_CORE
+ depends on LIRC
+ default y
+
+ ---help---
+ Enable this option to pass raw IR to and from userspace via
+ the LIRC interface.
+
config IR_IMON
tristate "SoundGraph iMON Receiver and Display"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index 3ba00bb..2ae4f3a 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
+obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index b79446f..7ad080d 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -122,4 +122,11 @@ void ir_raw_init(void);
#define load_sony_decode() 0
#endif
+/* from ir-lirc-codec.c */
+#ifdef CONFIG_IR_LIRC_CODEC_MODULE
+#define load_lirc_codec() request_module("ir-lirc-codec")
+#else
+#define load_lirc_codec() 0
+#endif
+
#endif /* _IR_RAW_EVENT */
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
new file mode 100644
index 0000000..b838ab8
--- /dev/null
+++ b/drivers/media/IR/ir-lirc-codec.c
@@ -0,0 +1,301 @@
+/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
+ *
+ * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <media/lirc.h>
+#include <media/ir-core.h>
+#include "ir-core-priv.h"
+#include "lirc_dev.h"
+
+/* Used to register lirc_codec clients */
+static LIST_HEAD(decoder_list);
+static DEFINE_SPINLOCK(decoder_lock);
+
+struct decoder_data {
+ struct list_head list;
+ struct ir_input_dev *ir_dev;
+ int enabled:1;
+
+ /* lirc interface bits */
+ struct lirc_driver *drv;
+ int lircdata;
+};
+
+#define LIRCBUF_SIZE 256
+
+/**
+ * get_decoder_data() - gets decoder data
+ * @ir_input_dev: input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
+{
+ struct decoder_data *data = NULL;
+
+ spin_lock(&decoder_lock);
+ list_for_each_entry(data, &decoder_list, list) {
+ if (data->ir_dev == ir_dev)
+ break;
+ }
+ spin_unlock(&decoder_lock);
+ return data;
+}
+
+static ssize_t store_enabled(struct device *d,
+ struct device_attribute *mattr,
+ const char *buf,
+ size_t len)
+{
+ unsigned long value;
+ struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+ struct decoder_data *data = get_decoder_data(ir_dev);
+
+ if (!data)
+ return -EINVAL;
+
+ if (strict_strtoul(buf, 10, &value) || value > 1)
+ return -EINVAL;
+
+ data->enabled = value;
+
+ return len;
+}
+
+static ssize_t show_enabled(struct device *d,
+ struct device_attribute *mattr, char *buf)
+{
+ struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+ struct decoder_data *data = get_decoder_data(ir_dev);
+
+ if (!data)
+ return -EINVAL;
+
+ if (data->enabled)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
+
+static struct attribute *decoder_attributes[] = {
+ &dev_attr_enabled.attr,
+ NULL
+};
+
+static struct attribute_group decoder_attribute_group = {
+ .name = "lirc_codec",
+ .attrs = decoder_attributes,
+};
+
+/**
+ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
+ * lircd userspace daemon for decoding.
+ * @input_dev: the struct input_dev descriptor of the device
+ * @duration: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the lirc interfaces aren't wired up.
+ */
+static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+ struct decoder_data *data;
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+ data = get_decoder_data(ir_dev);
+ if (!data)
+ return -EINVAL;
+
+ if (!data->enabled)
+ return 0;
+
+ if (!data->drv || !data->drv->rbuf)
+ return -EINVAL;
+
+ IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
+ TO_US(ev.duration), TO_STR(ev.pulse));
+
+ data->lircdata += ev.duration / 1000;
+ if (ev.pulse)
+ data->lircdata |= PULSE_BIT;
+
+ lirc_buffer_write(data->drv->rbuf, (unsigned char *) &data->lircdata);
+ wake_up(&data->drv->rbuf->wait_poll);
+
+ data->lircdata = 0;
+
+ return 0;
+}
+
+static int ir_lirc_ioctl(struct inode *node, struct file *filep,
+ unsigned int cmd, unsigned long arg)
+{
+ struct decoder_data *data;
+
+ data = lirc_get_pdata(filep);
+ if (!data)
+ return -EFAULT;
+
+ switch (cmd) {
+ case LIRC_SET_TRANSMITTER_MASK:
+ /* FIXME: implement this */
+ break;
+ default:
+ return lirc_dev_fop_ioctl(node, filep, cmd, arg);
+ }
+
+ return 0;
+}
+
+static int ir_lirc_open(void *data)
+{
+ return 0;
+}
+
+static void ir_lirc_close(void *data)
+{
+ return;
+}
+
+static struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ /*.write = lirc_transmit_ir,*/
+ .ioctl = ir_lirc_ioctl,
+ .read = lirc_dev_fop_read,
+ .poll = lirc_dev_fop_poll,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+};
+
+static int ir_lirc_register(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct decoder_data *data;
+ struct lirc_driver *drv;
+ struct lirc_buffer *rbuf;
+ int rc;
+
+ rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+ if (rc < 0)
+ return rc;
+
+ rc = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+ return rc;
+ }
+
+ drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+ if (!drv)
+ goto drv_alloc_failed;
+
+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!drv)
+ goto rbuf_alloc_failed;
+
+ rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
+ if (rc)
+ goto rbuf_init_failed;
+
+ strcpy(drv->name, "ir-lirc-codec");
+ drv->minor = -1;
+ drv->features = LIRC_CAN_REC_MODE2;
+ drv->data = data;
+ drv->rbuf = rbuf;
+ drv->set_use_inc = &ir_lirc_open;
+ drv->set_use_dec = &ir_lirc_close;
+ drv->code_length = sizeof(struct ir_raw_event) * 8;
+ drv->fops = &lirc_fops;
+ drv->dev = &ir_dev->dev;
+ drv->owner = THIS_MODULE;
+
+ drv->minor = lirc_register_driver(drv);
+ if (drv->minor < 0) {
+ rc = -ENODEV;
+ goto lirc_register_failed;
+ }
+
+ data->ir_dev = ir_dev;
+ data->enabled = 1;
+ data->drv = drv;
+ data->lircdata = PULSE_MASK;
+
+ spin_lock(&decoder_lock);
+ list_add_tail(&data->list, &decoder_list);
+ spin_unlock(&decoder_lock);
+
+ return 0;
+
+lirc_register_failed:
+rbuf_init_failed:
+ kfree(rbuf);
+rbuf_alloc_failed:
+ kfree(drv);
+drv_alloc_failed:
+ kfree(data);
+
+ return rc;
+}
+
+static int ir_lirc_unregister(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ static struct decoder_data *data;
+
+ data = get_decoder_data(ir_dev);
+ if (!data)
+ return 0;
+
+ sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+
+ lirc_unregister_driver(data->drv->minor);
+ kfree(data->drv);
+
+ spin_lock(&decoder_lock);
+ list_del(&data->list);
+ spin_unlock(&decoder_lock);
+
+ kfree(data);
+
+ return 0;
+}
+
+static struct ir_raw_handler lirc_handler = {
+ .decode = ir_lirc_decode,
+ .raw_register = ir_lirc_register,
+ .raw_unregister = ir_lirc_unregister,
+};
+
+static int __init ir_lirc_codec_init(void)
+{
+ ir_raw_handler_register(&lirc_handler);
+
+ printk(KERN_INFO "IR LIRC bridge handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_lirc_codec_exit(void)
+{
+ ir_raw_handler_unregister(&lirc_handler);
+}
+
+module_init(ir_lirc_codec_init);
+module_exit(ir_lirc_codec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("LIRC IR handler bridge");
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 7edfa10..596445f 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -234,6 +234,7 @@ static void init_decoders(struct work_struct *work)
load_rc6_decode();
load_jvc_decode();
load_sony_decode();
+ load_lirc_codec();
/* If needed, we may later add some init code. In this case,
it is needed to change the CONFIG_MODULE test at ir-core.h
--
1.6.5.2
--
Jarod Wilson
jarod@redhat.com
next prev parent reply other threads:[~2010-06-01 20:53 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-01 20:50 [PATCH 0/3] IR: add lirc support to ir-core Jarod Wilson
2010-06-01 20:51 ` [PATCH 1/3] IR: add core lirc device interface Jarod Wilson
2010-06-03 6:02 ` Mauro Carvalho Chehab
2010-06-03 22:06 ` Jarod Wilson
2010-06-04 4:10 ` Mauro Carvalho Chehab
2010-06-04 15:51 ` Christoph Bartelmus
2010-06-04 18:38 ` Mauro Carvalho Chehab
2010-06-04 18:57 ` Jon Smirl
2010-06-04 20:17 ` Jarod Wilson
2010-06-04 21:17 ` Jarod Wilson
2010-06-04 23:16 ` Jon Smirl
2010-06-05 2:45 ` Jarod Wilson
2010-06-05 12:43 ` Jarod Wilson
2010-06-05 17:43 ` Stefan Richter
2010-06-05 17:24 ` Andy Walls
2010-06-05 17:52 ` Jon Smirl
2010-06-07 18:44 ` David Härdeman
2010-06-07 19:45 ` Jarod Wilson
2010-06-08 17:40 ` David Härdeman
2010-07-03 3:27 ` Jarod Wilson
2010-06-01 20:52 ` [PATCH 2/3] IR: add an empty lirc "protocol" keymap Jarod Wilson
2010-06-01 20:52 ` Jarod Wilson [this message]
2010-07-03 4:05 ` [PATCH v2 0/3] IR: add lirc support to ir-core Jarod Wilson
2010-07-03 4:06 ` [PATCH 1/3] IR: add lirc device interface Jarod Wilson
2010-07-03 4:07 ` [PATCH v2 2/3] IR: add ir-core to lirc userspace decoder bridge driver Jarod Wilson
2010-07-03 4:08 ` [PATCH v2 3/3] IR: add empty lirc pseudo-keymap Jarod Wilson
2010-07-03 4:10 ` [PATCH 4/3] IR/lirc: add docbook info covering lirc device interface Jarod Wilson
2010-07-04 15:31 ` Mauro Carvalho Chehab
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100601205258.GC31616@redhat.com \
--to=jarod@redhat.com \
--cc=linux-media@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.