From 06435a6ebd2374b500fbd0037e16a0451668f193 Mon Sep 17 00:00:00 2001
From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
Date: Fri, 12 Jul 2013 09:07:37 +0100
Subject: [PATCH RFC] media: lirc: Allow lirc dev to talk to rc device
The use case is simple, if any rc device has allowed protocols =
RC_TYPE_LIRC and map_name = RC_MAP_LIRC set, the driver open will be never
called. The reason for this is, all of the key maps except lirc have some
KEYS in there map, so during rc_register_device process these keys are
matched against the input drivers and open is performed, so for the case
of RC_MAP_EMPTY, a vt/keyboard is matched and the driver open is
performed.
In case of lirc, there is no match and result is that there is no open
performed, however the lirc-dev will go ahead and create a /dev/lirc0
node. Now when lircd/mode2 opens this device, no data is available
because the driver was never opened.
lirc_dev seems to have no link with actual rc device w.r.t open/close.
This patch adds rc_dev pointer to lirc_driver structure for cases like
this, so that it can do the open/close of the real driver in accordance
to lircd/mode2 open/close.
Without this patch its impossible to open a rc device which has
RC_TYPE_LIRC ad RC_MAP_LIRC set.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
---
drivers/media/rc/ir-lirc-codec.c | 1 +
drivers/media/rc/lirc_dev.c | 16 ++++++++++++++++
drivers/media/rc/rc-main.c | 11 +++++++++--
include/media/lirc_dev.h | 1 +
include/media/rc-core.h | 1 +
5 files changed, 28 insertions(+), 2 deletions(-)
@@ -375,6 +375,7 @@ static int ir_lirc_register(struct rc_dev *dev)
drv->code_length = sizeof(struct ir_raw_event) * 8;
drv->fops = &lirc_fops;
drv->dev = &dev->dev;
+ drv->rc_dev = dev;
drv->owner = THIS_MODULE;
drv->minor = lirc_register_driver(drv);
@@ -35,6 +35,7 @@
#include <linux/device.h>
#include <linux/cdev.h>
+#include <media/rc-core.h>
#include <media/lirc.h>
#include <media/lirc_dev.h>
@@ -437,6 +438,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
int lirc_dev_fop_open(struct inode *inode, struct file *file)
{
struct irctl *ir;
+ struct rc_dev *rc_dev;
struct cdev *cdev;
int retval = 0;
@@ -467,6 +469,15 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
goto error;
}
+ rc_dev = ir->d.rc_dev;
+ if (!rc_dev->users++ && rc_dev && rc_dev->open) {
+ retval = rc_dev->open(rc_dev);
+ if (retval) {
+ rc_dev->users--;
+ goto error;
+ }
+ }
+
cdev = ir->cdev;
if (try_module_get(cdev->owner)) {
ir->open++;
@@ -499,6 +510,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
{
struct irctl *ir = irctls[iminor(inode)];
struct cdev *cdev;
+ struct rc_dev *rc_dev;
if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
@@ -511,6 +523,10 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
WARN_ON(mutex_lock_killable(&lirc_dev_lock));
+ rc_dev = ir->d.rc_dev;
+ if (rc_dev && !--rc_dev->users && rc_dev->close)
+ rc_dev->close(rc_dev);
+
ir->open--;
if (ir->attached) {
ir->d.set_use_dec(ir->d.data);
@@ -702,15 +702,22 @@ EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
static int ir_open(struct input_dev *idev)
{
struct rc_dev *rdev = input_get_drvdata(idev);
+ int rval = 0;
- return rdev->open(rdev);
+ if (!rdev->users++)
+ rval = rdev->open(rdev);
+
+ if (rval)
+ rdev->users--;
+
+ return rval;
}
static void ir_close(struct input_dev *idev)
{
struct rc_dev *rdev = input_get_drvdata(idev);
- if (rdev)
+ if (rdev && !--rdev->users)
rdev->close(rdev);
}
@@ -139,6 +139,7 @@ struct lirc_driver {
struct lirc_buffer *rbuf;
int (*set_use_inc) (void *data);
void (*set_use_dec) (void *data);
+ struct rc_dev *rc_dev;
const struct file_operations *fops;
struct device *dev;
struct module *owner;
@@ -101,6 +101,7 @@ struct rc_dev {
bool idle;
u64 allowed_protos;
u64 enabled_protocols;
+ u32 users;
u32 scanmask;
void *priv;
spinlock_t keylock;
--
1.7.6.5