summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/rc/rc-main.c58
-rw-r--r--include/media/rc-core.h18
2 files changed, 75 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);
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 40188d362486..55281b92105a 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -68,6 +68,7 @@ enum rc_filter_type {
  * struct rc_dev - represents a remote control device
  * @dev: driver model's view of this device
  * @initialized: 1 if the device init has completed, 0 otherwise
+ * @managed_alloc: devm_rc_allocate_device was used to create rc_dev
  * @sysfs_groups: sysfs attribute groups
  * @input_name: name of the input child device
  * @input_phys: physical path to the input child device
@@ -131,6 +132,7 @@ enum rc_filter_type {
 struct rc_dev {
 	struct device			dev;
 	atomic_t			initialized;
+	bool				managed_alloc;
 	const struct attribute_group	*sysfs_groups[5];
 	const char			*input_name;
 	const char			*input_phys;
@@ -203,6 +205,14 @@ struct rc_dev {
 struct rc_dev *rc_allocate_device(void);
 
 /**
+ * devm_rc_allocate_device - Managed RC device allocation
+ *
+ * @dev: pointer to struct device
+ * returns a pointer to struct rc_dev.
+ */
+struct rc_dev *devm_rc_allocate_device(struct device *dev);
+
+/**
  * rc_free_device - Frees a RC device
  *
  * @dev: pointer to struct rc_dev.
@@ -217,6 +227,14 @@ void rc_free_device(struct rc_dev *dev);
 int rc_register_device(struct rc_dev *dev);
 
 /**
+ * devm_rc_register_device - Manageded registering of a RC device
+ *
+ * @parent: pointer to struct device.
+ * @dev: pointer to struct rc_dev.
+ */
+int devm_rc_register_device(struct device *parent, struct rc_dev *dev);
+
+/**
  * rc_unregister_device - Unregisters a RC device
  *
  * @dev: pointer to struct rc_dev.