Commit f56928ab authored by David Härdeman's avatar David Härdeman Committed by Mauro Carvalho Chehab

[media] rc-core: cleanup rc_register_device

The device core infrastructure is based on the presumption that
once a driver calls device_add(), it must be ready to accept
userspace interaction.

This requires splitting rc_setup_rx_device() into two functions
and reorganizing rc_register_device() so that as much work
as possible is performed before calling device_add().
Signed-off-by: default avatarDavid Härdeman <david@hardeman.nu>
Signed-off-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 6709e03c
...@@ -263,7 +263,9 @@ int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max, ...@@ -263,7 +263,9 @@ int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max,
* Routines from rc-raw.c to be used internally and by decoders * Routines from rc-raw.c to be used internally and by decoders
*/ */
u64 ir_raw_get_allowed_protocols(void); u64 ir_raw_get_allowed_protocols(void);
int ir_raw_event_prepare(struct rc_dev *dev);
int ir_raw_event_register(struct rc_dev *dev); int ir_raw_event_register(struct rc_dev *dev);
void ir_raw_event_free(struct rc_dev *dev);
void ir_raw_event_unregister(struct rc_dev *dev); void ir_raw_event_unregister(struct rc_dev *dev);
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler); void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
......
...@@ -486,15 +486,18 @@ EXPORT_SYMBOL(ir_raw_encode_scancode); ...@@ -486,15 +486,18 @@ EXPORT_SYMBOL(ir_raw_encode_scancode);
/* /*
* Used to (un)register raw event clients * Used to (un)register raw event clients
*/ */
int ir_raw_event_register(struct rc_dev *dev) int ir_raw_event_prepare(struct rc_dev *dev)
{ {
int rc; static bool raw_init; /* 'false' default value, raw decoders loaded? */
struct ir_raw_handler *handler;
struct task_struct *thread;
if (!dev) if (!dev)
return -EINVAL; return -EINVAL;
if (!raw_init) {
request_module("ir-lirc-codec");
raw_init = true;
}
dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL); dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
if (!dev->raw) if (!dev->raw)
return -ENOMEM; return -ENOMEM;
...@@ -503,6 +506,14 @@ int ir_raw_event_register(struct rc_dev *dev) ...@@ -503,6 +506,14 @@ int ir_raw_event_register(struct rc_dev *dev)
dev->change_protocol = change_protocol; dev->change_protocol = change_protocol;
INIT_KFIFO(dev->raw->kfifo); INIT_KFIFO(dev->raw->kfifo);
return 0;
}
int ir_raw_event_register(struct rc_dev *dev)
{
struct ir_raw_handler *handler;
struct task_struct *thread;
/* /*
* raw transmitters do not need any event registration * raw transmitters do not need any event registration
* because the event is coming from userspace * because the event is coming from userspace
...@@ -511,10 +522,8 @@ int ir_raw_event_register(struct rc_dev *dev) ...@@ -511,10 +522,8 @@ int ir_raw_event_register(struct rc_dev *dev)
thread = kthread_run(ir_raw_event_thread, dev->raw, "rc%u", thread = kthread_run(ir_raw_event_thread, dev->raw, "rc%u",
dev->minor); dev->minor);
if (IS_ERR(thread)) { if (IS_ERR(thread))
rc = PTR_ERR(thread); return PTR_ERR(thread);
goto out;
}
dev->raw->thread = thread; dev->raw->thread = thread;
} }
...@@ -527,11 +536,15 @@ int ir_raw_event_register(struct rc_dev *dev) ...@@ -527,11 +536,15 @@ int ir_raw_event_register(struct rc_dev *dev)
mutex_unlock(&ir_raw_handler_lock); mutex_unlock(&ir_raw_handler_lock);
return 0; return 0;
}
void ir_raw_event_free(struct rc_dev *dev)
{
if (!dev)
return;
out:
kfree(dev->raw); kfree(dev->raw);
dev->raw = NULL; dev->raw = NULL;
return rc;
} }
void ir_raw_event_unregister(struct rc_dev *dev) void ir_raw_event_unregister(struct rc_dev *dev)
...@@ -550,8 +563,7 @@ void ir_raw_event_unregister(struct rc_dev *dev) ...@@ -550,8 +563,7 @@ void ir_raw_event_unregister(struct rc_dev *dev)
handler->raw_unregister(dev); handler->raw_unregister(dev);
mutex_unlock(&ir_raw_handler_lock); mutex_unlock(&ir_raw_handler_lock);
kfree(dev->raw); ir_raw_event_free(dev);
dev->raw = NULL;
} }
/* /*
......
...@@ -1663,7 +1663,7 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev, ...@@ -1663,7 +1663,7 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev,
} }
EXPORT_SYMBOL_GPL(devm_rc_allocate_device); EXPORT_SYMBOL_GPL(devm_rc_allocate_device);
static int rc_setup_rx_device(struct rc_dev *dev) static int rc_prepare_rx_device(struct rc_dev *dev)
{ {
int rc; int rc;
struct rc_map *rc_map; struct rc_map *rc_map;
...@@ -1708,10 +1708,22 @@ static int rc_setup_rx_device(struct rc_dev *dev) ...@@ -1708,10 +1708,22 @@ static int rc_setup_rx_device(struct rc_dev *dev)
dev->input_dev->phys = dev->input_phys; dev->input_dev->phys = dev->input_phys;
dev->input_dev->name = dev->input_name; dev->input_dev->name = dev->input_name;
return 0;
out_table:
ir_free_table(&dev->rc_map);
return rc;
}
static int rc_setup_rx_device(struct rc_dev *dev)
{
int rc;
/* rc_open will be called here */ /* rc_open will be called here */
rc = input_register_device(dev->input_dev); rc = input_register_device(dev->input_dev);
if (rc) if (rc)
goto out_table; return rc;
/* /*
* Default delay of 250ms is too short for some protocols, especially * Default delay of 250ms is too short for some protocols, especially
...@@ -1729,27 +1741,23 @@ static int rc_setup_rx_device(struct rc_dev *dev) ...@@ -1729,27 +1741,23 @@ static int rc_setup_rx_device(struct rc_dev *dev)
dev->input_dev->rep[REP_PERIOD] = 125; dev->input_dev->rep[REP_PERIOD] = 125;
return 0; return 0;
out_table:
ir_free_table(&dev->rc_map);
return rc;
} }
static void rc_free_rx_device(struct rc_dev *dev) static void rc_free_rx_device(struct rc_dev *dev)
{ {
if (!dev || dev->driver_type == RC_DRIVER_IR_RAW_TX) if (!dev)
return; return;
ir_free_table(&dev->rc_map); if (dev->input_dev) {
input_unregister_device(dev->input_dev);
dev->input_dev = NULL;
}
input_unregister_device(dev->input_dev); ir_free_table(&dev->rc_map);
dev->input_dev = NULL;
} }
int rc_register_device(struct rc_dev *dev) int rc_register_device(struct rc_dev *dev)
{ {
static bool raw_init; /* 'false' default value, raw decoders loaded? */
const char *path; const char *path;
int attr = 0; int attr = 0;
int minor; int minor;
...@@ -1776,30 +1784,39 @@ int rc_register_device(struct rc_dev *dev) ...@@ -1776,30 +1784,39 @@ int rc_register_device(struct rc_dev *dev)
dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp; dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
dev->sysfs_groups[attr++] = NULL; dev->sysfs_groups[attr++] = NULL;
if (dev->driver_type == RC_DRIVER_IR_RAW ||
dev->driver_type == RC_DRIVER_IR_RAW_TX) {
rc = ir_raw_event_prepare(dev);
if (rc < 0)
goto out_minor;
}
if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
rc = rc_prepare_rx_device(dev);
if (rc)
goto out_raw;
}
rc = device_add(&dev->dev); rc = device_add(&dev->dev);
if (rc) if (rc)
goto out_unlock; goto out_rx_free;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
dev_info(&dev->dev, "%s as %s\n", dev_info(&dev->dev, "%s as %s\n",
dev->input_name ?: "Unspecified device", path ?: "N/A"); dev->input_name ?: "Unspecified device", path ?: "N/A");
kfree(path); kfree(path);
if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
rc = rc_setup_rx_device(dev);
if (rc)
goto out_dev;
}
if (dev->driver_type == RC_DRIVER_IR_RAW || if (dev->driver_type == RC_DRIVER_IR_RAW ||
dev->driver_type == RC_DRIVER_IR_RAW_TX) { dev->driver_type == RC_DRIVER_IR_RAW_TX) {
if (!raw_init) {
request_module_nowait("ir-lirc-codec");
raw_init = true;
}
rc = ir_raw_event_register(dev); rc = ir_raw_event_register(dev);
if (rc < 0) if (rc < 0)
goto out_dev; goto out_rx;
}
if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
rc = rc_setup_rx_device(dev);
if (rc)
goto out_raw;
} }
/* Allow the RC sysfs nodes to be accessible */ /* Allow the RC sysfs nodes to be accessible */
...@@ -1811,11 +1828,15 @@ int rc_register_device(struct rc_dev *dev) ...@@ -1811,11 +1828,15 @@ int rc_register_device(struct rc_dev *dev)
return 0; return 0;
out_raw: out_rx:
ir_raw_event_unregister(dev); rc_free_rx_device(dev);
out_dev: out_dev:
device_del(&dev->dev); device_del(&dev->dev);
out_unlock: out_rx_free:
ir_free_table(&dev->rc_map);
out_raw:
ir_raw_event_free(dev);
out_minor:
ida_simple_remove(&rc_ida, minor); ida_simple_remove(&rc_ida, minor);
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment