summaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
authorHeiner Kallweit2016-09-30 22:42:07 +0200
committerMauro Carvalho Chehab2016-10-24 22:28:56 +0200
commitddbf7d5a698c4d8553ad2f77cb281d7b37898d34 (patch)
tree19a3fee248db10dea9c2eadaf9b3e4d1ca6714aa /drivers/media/rc
parent[media] stih-cec: remove unused including <linux/version.h> (diff)
downloadkernel-qcow2-linux-ddbf7d5a698c4d8553ad2f77cb281d7b37898d34.tar.gz
kernel-qcow2-linux-ddbf7d5a698c4d8553ad2f77cb281d7b37898d34.tar.xz
kernel-qcow2-linux-ddbf7d5a698c4d8553ad2f77cb281d7b37898d34.zip
[media] rc: core: add managed versions of rc_allocate_device and rc_register_device
Introduce managed versions of both functions. They allows to simplify the error path in the probe function of rc drivers, and usually also to simplify the remove function. New element managed_alloc in struct rc_dev is needed to correctly handle mixed use, e.g. managed version of rc_register_device and normal version of rc_allocate_device. In addition devm_rc_allocate_device sets rc->dev.parent as having a reference to the parent device might be useful for future extensions. Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/rc-main.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index b241e5f569ef..5087e76dfb03 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1402,6 +1402,34 @@ void rc_free_device(struct rc_dev *dev)
}
EXPORT_SYMBOL_GPL(rc_free_device);
+static void devm_rc_alloc_release(struct device *dev, void *res)
+{
+ rc_free_device(*(struct rc_dev **)res);
+}
+
+struct rc_dev *devm_rc_allocate_device(struct device *dev)
+{
+ struct rc_dev **dr, *rc;
+
+ dr = devres_alloc(devm_rc_alloc_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return NULL;
+
+ rc = rc_allocate_device();
+ if (!rc) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ rc->dev.parent = dev;
+ rc->managed_alloc = true;
+ *dr = rc;
+ devres_add(dev, dr);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(devm_rc_allocate_device);
+
int rc_register_device(struct rc_dev *dev)
{
static bool raw_init = false; /* raw decoders loaded? */
@@ -1530,6 +1558,33 @@ out_unlock:
}
EXPORT_SYMBOL_GPL(rc_register_device);
+static void devm_rc_release(struct device *dev, void *res)
+{
+ rc_unregister_device(*(struct rc_dev **)res);
+}
+
+int devm_rc_register_device(struct device *parent, struct rc_dev *dev)
+{
+ struct rc_dev **dr;
+ int ret;
+
+ dr = devres_alloc(devm_rc_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ ret = rc_register_device(dev);
+ if (ret) {
+ devres_free(dr);
+ return ret;
+ }
+
+ *dr = dev;
+ devres_add(parent, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_rc_register_device);
+
void rc_unregister_device(struct rc_dev *dev)
{
if (!dev)
@@ -1551,7 +1606,8 @@ void rc_unregister_device(struct rc_dev *dev)
ida_simple_remove(&rc_ida, dev->minor);
- rc_free_device(dev);
+ if (!dev->managed_alloc)
+ rc_free_device(dev);
}
EXPORT_SYMBOL_GPL(rc_unregister_device);