diff options
Diffstat (limited to 'drivers/ide/ide-scan-pci.c')
-rw-r--r-- | drivers/ide/ide-scan-pci.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c new file mode 100644 index 000000000000..7ffa332d77ce --- /dev/null +++ b/drivers/ide/ide-scan-pci.c @@ -0,0 +1,121 @@ +/* + * support for probing IDE PCI devices in the PCI bus order + * + * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (c) 1995-1998 Mark Lord + * + * May be copied or modified under the terms of the GNU General Public License + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ide.h> + +/* + * Module interfaces + */ + +static int pre_init = 1; /* Before first ordered IDE scan */ +static LIST_HEAD(ide_pci_drivers); + +/* + * __ide_pci_register_driver - attach IDE driver + * @driver: pci driver + * @module: owner module of the driver + * + * Registers a driver with the IDE layer. The IDE layer arranges that + * boot time setup is done in the expected device order and then + * hands the controllers off to the core PCI code to do the rest of + * the work. + * + * Returns are the same as for pci_register_driver + */ + +int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, + const char *mod_name) +{ + if (!pre_init) + return __pci_register_driver(driver, module, mod_name); + driver->driver.owner = module; + list_add_tail(&driver->node, &ide_pci_drivers); + return 0; +} +EXPORT_SYMBOL_GPL(__ide_pci_register_driver); + +/** + * ide_scan_pcidev - find an IDE driver for a device + * @dev: PCI device to check + * + * Look for an IDE driver to handle the device we are considering. + * This is only used during boot up to get the ordering correct. After + * boot up the pci layer takes over the job. + */ + +static int __init ide_scan_pcidev(struct pci_dev *dev) +{ + struct list_head *l; + struct pci_driver *d; + + list_for_each(l, &ide_pci_drivers) { + d = list_entry(l, struct pci_driver, node); + if (d->id_table) { + const struct pci_device_id *id = + pci_match_id(d->id_table, dev); + + if (id != NULL && d->probe(dev, id) >= 0) { + dev->driver = d; + pci_dev_get(dev); + return 1; + } + } + } + return 0; +} + +/** + * ide_scan_pcibus - perform the initial IDE driver scan + * + * Perform the initial bus rather than driver ordered scan of the + * PCI drivers. After this all IDE pci handling becomes standard + * module ordering not traditionally ordered. + */ + +int __init ide_scan_pcibus(void) +{ + struct pci_dev *dev = NULL; + struct pci_driver *d; + struct list_head *l, *n; + + pre_init = 0; + if (!ide_scan_direction) + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev))) + ide_scan_pcidev(dev); + else + while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, + dev))) + ide_scan_pcidev(dev); + + /* + * Hand the drivers over to the PCI layer now we + * are post init. + */ + + list_for_each_safe(l, n, &ide_pci_drivers) { + list_del(l); + d = list_entry(l, struct pci_driver, node); + if (__pci_register_driver(d, d->driver.owner, + d->driver.mod_name)) + printk(KERN_ERR "%s: failed to register %s driver\n", + __FUNCTION__, d->driver.mod_name); + } + + return 0; +} + +static int __init ide_scan_pci(void) +{ + return ide_scan_pcibus(); +} + +module_init(ide_scan_pci); |