+/**
+ * match_pci_device - Matches a pci device against a given hardware path
+ * entry.
+ * @dev: the generic device (known to be contained by a pci_dev).
+ * @index: the current BC index
+ * @modpath: the hardware path.
+ * @return: true if the device matches the hardware path.
+ */
+static int match_pci_device(struct device *dev, int index,
+ struct hardware_path *modpath)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int id;
+
+ if (index == 5) {
+ /* we are at the end of the path, and on the actual device */
+ unsigned int devfn = pdev->devfn;
+ return ((modpath->bc[5] == PCI_SLOT(devfn)) &&
+ (modpath->mod == PCI_FUNC(devfn)));
+ }
+
+ id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5);
+ return (modpath->bc[index] == id);
+}
+
+/**
+ * match_parisc_device - Matches a parisc device against a given hardware
+ * path entry.
+ * @dev: the generic device (known to be contained by a parisc_device).
+ * @index: the current BC index
+ * @modpath: the hardware path.
+ * @return: true if the device matches the hardware path.
+ */
+static int match_parisc_device(struct device *dev, int index,
+ struct hardware_path *modpath)
+{
+ struct parisc_device *curr = to_parisc_device(dev);
+ char id = (index == 6) ? modpath->mod : modpath->bc[index];
+
+ return (curr->hw_path == id);
+}
+
+struct parse_tree_data {
+ int index;
+ struct hardware_path * modpath;
+ struct device * dev;
+};
+
+static int check_parent(struct device * dev, void * data)
+{
+ struct parse_tree_data * d = data;
+
+ if (check_dev(dev)) {
+ if (dev->bus == &parisc_bus_type) {
+ if (match_parisc_device(dev, d->index, d->modpath))
+ d->dev = dev;
+ } else if (is_pci_dev(dev)) {
+ if (match_pci_device(dev, d->index, d->modpath))
+ d->dev = dev;
+ } else if (dev->bus == NULL) {
+ /* we are on a bus bridge */
+ struct device *new = parse_tree_node(dev, d->index, d->modpath);
+ if (new)
+ d->dev = new;
+ }
+ }
+ return d->dev != NULL;
+}
+
+/**
+ * parse_tree_node - returns a device entry in the iotree
+ * @parent: the parent node in the tree
+ * @index: the current BC index
+ * @modpath: the hardware_path struct to match a device against
+ * @return: The corresponding device if found, NULL otherwise.
+ *
+ * Checks all the children of @parent for a matching @id. If none
+ * found, it returns NULL.
+ */
+static struct device *
+parse_tree_node(struct device *parent, int index, struct hardware_path *modpath)
+{
+ struct parse_tree_data d = {
+ .index = index,
+ .modpath = modpath,
+ };
+
+ struct recurse_struct recurse_data = {
+ .obj = &d,
+ .fn = check_parent,
+ };
+
+ device_for_each_child(parent, &recurse_data, descend_children);
+ return d.dev;
+}
+
+/**
+ * hwpath_to_device - Finds the generic device corresponding to a given hardware path.
+ * @modpath: the hardware path.
+ * @return: The target device, NULL if not found.
+ */
+struct device *hwpath_to_device(struct hardware_path *modpath)
+{
+ int i;
+ struct device *parent = &root;
+ for (i = 0; i < 6; i++) {
+ if (modpath->bc[i] == -1)
+ continue;
+ parent = parse_tree_node(parent, i, modpath);
+ if (!parent)
+ return NULL;
+ }
+ if (is_pci_dev(parent)) /* pci devices already parse MOD */
+ return parent;
+ else
+ return parse_tree_node(parent, 6, modpath);
+}
+EXPORT_SYMBOL(hwpath_to_device);
+
+/**
+ * device_to_hwpath - Populates the hwpath corresponding to the given device.
+ * @param dev the target device
+ * @param path pointer to a previously allocated hwpath struct to be filled in
+ */
+void device_to_hwpath(struct device *dev, struct hardware_path *path)
+{
+ struct parisc_device *padev;
+ if (dev->bus == &parisc_bus_type) {
+ padev = to_parisc_device(dev);
+ get_node_path(dev->parent, path);
+ path->mod = padev->hw_path;
+ } else if (is_pci_dev(dev)) {
+ get_node_path(dev, path);
+ }
+}
+EXPORT_SYMBOL(device_to_hwpath);
+