iio: core: implement devm_iio_device_alloc/devm_iio_device_free
authorGrygorii Strashko <grygorii.strashko@ti.com>
Thu, 18 Jul 2013 10:19:00 +0000 (11:19 +0100)
committerJonathan Cameron <jic23@kernel.org>
Sat, 3 Aug 2013 17:40:37 +0000 (18:40 +0100)
Add a resource managed devm_iio_device_alloc()/devm_iio_device_free()
to automatically clean up any allocations made by IIO drivers,
thus leading to simplified IIO drivers code.

In addition, this will allow IIO drivers to use other devm_*() API
(like devm_request_irq) and don't care about the race between
iio_device_free() and the release of resources by Device core
during driver removing.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Oleksandr Kravchenko <o.v.kravchenko@globallogic.com>
Tested-by: Oleksandr Kravchenko <o.v.kravchenko@globallogic.com>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/iio/industrialio-core.c
include/linux/iio/iio.h

index e145931ef1b82906478c5a32505cada2d8eb1547..d56d1229e2d6fe2dec77f42363798960ac66bffd 100644 (file)
@@ -912,6 +912,53 @@ void iio_device_free(struct iio_dev *dev)
 }
 EXPORT_SYMBOL(iio_device_free);
 
+static void devm_iio_device_release(struct device *dev, void *res)
+{
+       iio_device_free(*(struct iio_dev **)res);
+}
+
+static int devm_iio_device_match(struct device *dev, void *res, void *data)
+{
+       struct iio_dev **r = res;
+       if (!r || !*r) {
+               WARN_ON(!r || !*r);
+               return 0;
+       }
+       return *r == data;
+}
+
+struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv)
+{
+       struct iio_dev **ptr, *iio_dev;
+
+       ptr = devres_alloc(devm_iio_device_release, sizeof(*ptr),
+                          GFP_KERNEL);
+       if (!ptr)
+               return NULL;
+
+       /* use raw alloc_dr for kmalloc caller tracing */
+       iio_dev = iio_device_alloc(sizeof_priv);
+       if (iio_dev) {
+               *ptr = iio_dev;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return iio_dev;
+}
+EXPORT_SYMBOL_GPL(devm_iio_device_alloc);
+
+void devm_iio_device_free(struct device *dev, struct iio_dev *iio_dev)
+{
+       int rc;
+
+       rc = devres_release(dev, devm_iio_device_release,
+                           devm_iio_device_match, iio_dev);
+       WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_device_free);
+
 /**
  * iio_chrdev_open() - chrdev file open for buffer access and ioctls
  **/
index 3d35b7023591facc722dc58a22e9acbb44302726..61d220f89aca4c3a571246a2e94c748bc220ead3 100644 (file)
@@ -531,6 +531,31 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv)
  **/
 void iio_device_free(struct iio_dev *indio_dev);
 
+/**
+ * devm_iio_device_alloc - Resource-managed iio_device_alloc()
+ * @dev:               Device to allocate iio_dev for
+ * @sizeof_priv:       Space to allocate for private structure.
+ *
+ * Managed iio_device_alloc.  iio_dev allocated with this function is
+ * automatically freed on driver detach.
+ *
+ * If an iio_dev allocated with this function needs to be freed separately,
+ * devm_iio_device_free() must be used.
+ *
+ * RETURNS:
+ * Pointer to allocated iio_dev on success, NULL on failure.
+ */
+struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv);
+
+/**
+ * devm_iio_device_free - Resource-managed iio_device_free()
+ * @dev:               Device this iio_dev belongs to
+ * @indio_dev:                 the iio_dev associated with the device
+ *
+ * Free indio_dev allocated with devm_iio_device_alloc().
+ */
+void devm_iio_device_free(struct device *dev, struct iio_dev *iio_dev);
+
 /**
  * iio_buffer_enabled() - helper function to test if the buffer is enabled
  * @indio_dev:         IIO device structure for device