// SPDX-License-Identifier: GPL-2.0-or-later
/*
* drivers.c
*
* Copyright (c) 1999 The Puffin Group
* Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
* Copyright (c) 2001 Helge Deller <deller@gmx.de>
* Copyright (c) 2001,2002 Ryan Bradetich
* Copyright (c) 2004-2005 Thibaut VARENE <varenet@parisc-linux.org>
*
* The file handles registering devices and drivers, then matching them.
* It's the closest we get to a dating agency.
*
* If you're thinking about modifying this file, here are some gotchas to
* bear in mind:
* - 715/Mirage device paths have a dummy device between Lasi and its children
* - The EISA adapter may show up as a sibling or child of Wax
* - Dino has an optionally functional serial port. If firmware enables it,
* it shows up as a child of Dino. If firmware disables it, the buswalk
* finds it and it shows up as a child of Cujo
* - Dino has both parisc and pci devices as children
* - parisc devices are discovered in a random order, including children
* before parents in some cases.
*/
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/export.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/pdc.h>
#include <asm/parisc-device.h>
#include <asm/ropes.h>
/* See comments in include/asm-parisc/pci.h */
const struct dma_map_ops *hppa_dma_ops __ro_after_init;
EXPORT_SYMBOL(hppa_dma_ops);
static struct device root = {
.init_name = "parisc",
};
static inline int check_dev(struct device *dev)
{
if (dev->bus == &parisc_bus_type) {
struct parisc_device *pdev;
pdev = to_parisc_device(dev);
return pdev->id.hw_type != HPHW_FAULTY;
}
return 1;
}
static struct device *
parse_tree_node(struct device *parent, int index, struct hardware_path *modpath);
struct recurse_struct {
void * obj;
int (*fn)(struct device *, void *);
};
static int descend_children(struct device * dev, void * data)
{
struct recurse_struct * recurse_data = (struct recurse_struct *)data;
if (recurse_data->fn(dev, recurse_data->obj))
return 1;
else
return device_for_each_child(dev, recurse_data, descend_children);
}
/**
* for_each_padev - Iterate over all devices in the tree
* @fn: Function to call for each device.
* @data: Data to pass to the called function.
*
* This performs a depth-first traversal of the tree, calling the
* function passed for each node. It calls the function for parents
* before children.
*/
static int for_each_padev(int (*fn)(struct device *, void *), void * data)
{
struct recurse_struct recurse_data = {
.obj = data,
.fn = fn,
};
return device_for_each_child(&root, &recurse_data, descend_children);
}
/**
* match_device - Report whether this driver can handle this device
* @driver: the PA-RISC driver to try
* @dev: the PA-RISC device to try
*/
static int match_device(struct parisc_driver *driver, struct parisc_device *dev)
{
const struct parisc_device_id *ids;
for (ids = driver->id_table; ids->sversion; ids++) {
if ((ids->sversion != SVERSION_ANY_ID) &&
(ids->sversion != dev->id.sversion))
continue;
if ((ids->hw_type != HWTYPE_ANY_ID) &&
(ids->hw_type != dev->id.hw_type))
continue;
if ((ids->hversion != HVERSION_ANY_ID) &&
(ids->hversion != dev->id.hversion))
continue;
return 1;
}
return 0;
}
static int parisc_driver_probe(struct device *dev)
{
int rc;
struct parisc_device *pa_dev = to_parisc_device(dev);
struct parisc_driver *pa_drv = to_parisc_driver(dev->driver);
rc = pa_drv->probe(pa_dev);
if (!rc)
pa_dev->driver = pa_drv;
return rc;
}
static int __exit parisc_driver_remove(struct device *dev)
{
struct