ACPI_MODULE_NAME("platform");
 
-struct resource_info {
-       struct device *dev;
-       struct resource *res;
-       size_t n, cur;
-};
-
-static acpi_status acpi_platform_count_resources(struct acpi_resource *res,
-                                                void *data)
-{
-       struct acpi_resource_extended_irq *acpi_xirq;
-       struct acpi_resource_irq *acpi_irq;
-       struct resource_info *ri = data;
-
-       switch (res->type) {
-       case ACPI_RESOURCE_TYPE_IRQ:
-               acpi_irq = &res->data.irq;
-               ri->n += acpi_irq->interrupt_count;
-               break;
-       case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-               acpi_xirq = &res->data.extended_irq;
-               ri->n += acpi_xirq->interrupt_count;
-               break;
-       default:
-               ri->n++;
-       }
-
-       return AE_OK;
-}
-
-static acpi_status acpi_platform_add_resources(struct acpi_resource *res,
-                                              void *data)
-{
-       struct resource_info *ri = data;
-       struct resource *r;
-
-       r = ri->res + ri->cur;
-       if (acpi_dev_resource_memory(res, r)
-           || acpi_dev_resource_io(res, r)
-           || acpi_dev_resource_address_space(res, r)
-           || acpi_dev_resource_ext_address_space(res, r)) {
-               ri->cur++;
-               return AE_OK;
-       }
-       if (acpi_dev_resource_interrupt(res, 0, r)) {
-               int i;
-
-               r++;
-               for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++)
-                       r++;
-
-               ri->cur += i;
-       }
-       return AE_OK;
-}
-
 /**
  * acpi_create_platform_device - Create platform device for ACPI device node
  * @adev: ACPI device node to create a platform device for.
        struct platform_device *pdev = NULL;
        struct acpi_device *acpi_parent;
        struct device *parent = NULL;
-       struct resource_info ri;
-       acpi_status status;
+       struct resource_list_entry *rentry;
+       struct list_head resource_list;
+       struct resource *resources;
+       int count;
 
        /* If the ACPI node already has a physical device attached, skip it. */
        if (adev->physical_node_count)
                return NULL;
 
-       memset(&ri, 0, sizeof(ri));
-       /* First, count the resources. */
-       status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
-                                    acpi_platform_count_resources, &ri);
-       if (ACPI_FAILURE(status) || !ri.n)
+       INIT_LIST_HEAD(&resource_list);
+       count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+       if (count <= 0)
                return NULL;
 
-       /* Next, allocate memory for all the resources and populate it. */
-       ri.dev = &adev->dev;
-       ri.res = kzalloc(ri.n * sizeof(struct resource), GFP_KERNEL);
-       if (!ri.res) {
-               dev_err(&adev->dev,
-                       "failed to allocate memory for resources\n");
+       resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
+       if (!resources) {
+               dev_err(&adev->dev, "No memory for resources\n");
+               acpi_dev_free_resource_list(&resource_list);
                return NULL;
        }
+       count = 0;
+       list_for_each_entry(rentry, &resource_list, node)
+               resources[count++] = rentry->res;
 
-       status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
-                                    acpi_platform_add_resources, &ri);
-       if (ACPI_FAILURE(status)) {
-               dev_err(&adev->dev, "failed to walk resources\n");
-               goto out;
-       }
+       acpi_dev_free_resource_list(&resource_list);
 
        /*
         * If the ACPI node has a parent and that parent has a physical device
                mutex_unlock(&acpi_parent->physical_node_lock);
        }
        pdev = platform_device_register_resndata(parent, dev_name(&adev->dev),
-                                                -1, ri.res, ri.cur, NULL, 0);
+                                                -1, resources, count, NULL, 0);
        if (IS_ERR(pdev)) {
                dev_err(&adev->dev, "platform device creation failed: %ld\n",
                        PTR_ERR(pdev));
                        dev_name(&pdev->dev));
        }
 
- out:
-       kfree(ri.res);
+       kfree(resources);
        return pdev;
 }
 
 
 #include <linux/device.h>
 #include <linux/export.h>
 #include <linux/ioport.h>
+#include <linux/slab.h>
 
 #ifdef CONFIG_X86
 #define valid_IRQ(i) (((i) != 0) && ((i) != 2))
        return true;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
+
+/**
+ * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
+ * @list: The head of the resource list to free.
+ */
+void acpi_dev_free_resource_list(struct list_head *list)
+{
+       struct resource_list_entry *rentry, *re;
+
+       list_for_each_entry_safe(rentry, re, list, node) {
+               list_del(&rentry->node);
+               kfree(rentry);
+       }
+}
+EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
+
+struct res_proc_context {
+       struct list_head *list;
+       int (*preproc)(struct acpi_resource *, void *);
+       void *preproc_data;
+       int count;
+       int error;
+};
+
+static acpi_status acpi_dev_new_resource_entry(struct resource *r,
+                                              struct res_proc_context *c)
+{
+       struct resource_list_entry *rentry;
+
+       rentry = kmalloc(sizeof(*rentry), GFP_KERNEL);
+       if (!rentry) {
+               c->error = -ENOMEM;
+               return AE_NO_MEMORY;
+       }
+       INIT_LIST_HEAD(&rentry->node);
+       rentry->res = *r;
+       list_add_tail(&rentry->node, c->list);
+       c->count++;
+       return AE_OK;
+}
+
+static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
+                                            void *context)
+{
+       struct res_proc_context *c = context;
+       struct resource r;
+       int i;
+
+       if (c->preproc) {
+               int ret;
+
+               ret = c->preproc(ares, c->preproc_data);
+               if (ret < 0) {
+                       c->error = ret;
+                       return AE_ABORT_METHOD;
+               } else if (ret > 0) {
+                       return AE_OK;
+               }
+       }
+
+       memset(&r, 0, sizeof(r));
+
+       if (acpi_dev_resource_memory(ares, &r)
+           || acpi_dev_resource_io(ares, &r)
+           || acpi_dev_resource_address_space(ares, &r)
+           || acpi_dev_resource_ext_address_space(ares, &r))
+               return acpi_dev_new_resource_entry(&r, c);
+
+       for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) {
+               acpi_status status;
+
+               status = acpi_dev_new_resource_entry(&r, c);
+               if (ACPI_FAILURE(status))
+                       return status;
+       }
+
+       return AE_OK;
+}
+
+/**
+ * acpi_dev_get_resources - Get current resources of a device.
+ * @adev: ACPI device node to get the resources for.
+ * @list: Head of the resultant list of resources (must be empty).
+ * @preproc: The caller's preprocessing routine.
+ * @preproc_data: Pointer passed to the caller's preprocessing routine.
+ *
+ * Evaluate the _CRS method for the given device node and process its output by
+ * (1) executing the @preproc() rountine provided by the caller, passing the
+ * resource pointer and @preproc_data to it as arguments, for each ACPI resource
+ * returned and (2) converting all of the returned ACPI resources into struct
+ * resource objects if possible.  If the return value of @preproc() in step (1)
+ * is different from 0, step (2) is not applied to the given ACPI resource and
+ * if that value is negative, the whole processing is aborted and that value is
+ * returned as the final error code.
+ *
+ * The resultant struct resource objects are put on the list pointed to by
+ * @list, that must be empty initially, as members of struct resource_list_entry
+ * objects.  Callers of this routine should use %acpi_dev_free_resource_list() to
+ * free that list.
+ *
+ * The number of resources in the output list is returned on success, an error
+ * code reflecting the error condition is returned otherwise.
+ */
+int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
+                          int (*preproc)(struct acpi_resource *, void *),
+                          void *preproc_data)
+{
+       struct res_proc_context c;
+       acpi_handle not_used;
+       acpi_status status;
+
+       if (!adev || !adev->handle || !list_empty(list))
+               return -EINVAL;
+
+       status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, ¬_used);
+       if (ACPI_FAILURE(status))
+               return 0;
+
+       c.list = list;
+       c.preproc = preproc;
+       c.preproc_data = preproc_data;
+       c.count = 0;
+       c.error = 0;
+       status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
+                                    acpi_dev_process_resource, &c);
+       if (ACPI_FAILURE(status)) {
+               acpi_dev_free_resource_list(list);
+               return c.error ? c.error : -EIO;
+       }
+
+       return c.count;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
 
 bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
                                 struct resource *res);
 
+struct resource_list_entry {
+       struct list_head node;
+       struct resource res;
+};
+
+void acpi_dev_free_resource_list(struct list_head *list);
+int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
+                          int (*preproc)(struct acpi_resource *, void *),
+                          void *preproc_data);
+
 int acpi_check_resource_conflict(const struct resource *res);
 
 int acpi_check_region(resource_size_t start, resource_size_t n,