summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Levitsky <maximlevitsky@gmail.com>2010-09-06 18:26:07 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 07:54:13 -0200
commit58b3dd449feaa997129bde23592c6a31da039e4e (patch)
treef2ea7542e56dccc9750593248e0651b914b4302c
parentc6ef1e7fdc752bbaeacb3570cf955ba2ad60c61b (diff)
[media] IR: make sure we register the input device when it is safe to do so
As soon as input device is registered, it might be accessed (and it is) This can trigger a hardware interrupt that can access not yet initialized ir->raw, (by sending a sample) This can be reproduced by holding down a remote button and reloading the module. And this always crashes the systems where hardware decides to send an interrupt right at the moment it is enabled. Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Acked-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/IR/ir-core-priv.h1
-rw-r--r--drivers/media/IR/ir-keytable.c2
-rw-r--r--drivers/media/IR/ir-sysfs.c27
3 files changed, 20 insertions, 10 deletions
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index 90eb3912c455..6830580ae4db 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -122,6 +122,7 @@ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
* Routines from ir-sysfs.c - Meant to be called only internally inside
* ir-core
*/
+int ir_register_input(struct input_dev *input_dev);
int ir_register_class(struct input_dev *input_dev);
void ir_unregister_class(struct input_dev *input_dev);
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 59510cd33419..a616bd052336 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -506,6 +506,8 @@ int __ir_input_register(struct input_dev *input_dev,
goto out_event;
}
+ rc = ir_register_input(input_dev);
+
IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
driver_name, rc_tab->name,
(ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ?
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 186807aa226d..38423a8da871 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -265,8 +265,6 @@ static struct device_type rc_dev_type = {
*/
int ir_register_class(struct input_dev *input_dev)
{
- int rc;
- const char *path;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
int devno = find_first_zero_bit(&ir_core_dev_number,
IRRCV_NUM_DEVICES);
@@ -275,17 +273,28 @@ int ir_register_class(struct input_dev *input_dev)
return devno;
ir_dev->dev.type = &rc_dev_type;
+ ir_dev->devno = devno;
ir_dev->dev.class = &ir_input_class;
ir_dev->dev.parent = input_dev->dev.parent;
+ input_dev->dev.parent = &ir_dev->dev;
dev_set_name(&ir_dev->dev, "rc%d", devno);
dev_set_drvdata(&ir_dev->dev, ir_dev);
- rc = device_register(&ir_dev->dev);
- if (rc)
- return rc;
+ return device_register(&ir_dev->dev);
+};
+
+/**
+ * ir_register_input - registers ir input device with input subsystem
+ * @input_dev: the struct input_dev descriptor of the device
+ */
+
+int ir_register_input(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ int rc;
+ const char *path;
- input_dev->dev.parent = &ir_dev->dev;
rc = input_register_device(input_dev);
if (rc < 0) {
device_del(&ir_dev->dev);
@@ -301,11 +310,9 @@ int ir_register_class(struct input_dev *input_dev)
path ? path : "N/A");
kfree(path);
- ir_dev->devno = devno;
- set_bit(devno, &ir_core_dev_number);
-
+ set_bit(ir_dev->devno, &ir_core_dev_number);
return 0;
-};
+}
/**
* ir_unregister_class() - removes the sysfs for sysfs for