From mboxrd@z Thu Jan 1 00:00:00 1970 From: Rolf Eike Beer Date: Thu, 04 Sep 2003 12:38:39 +0000 Subject: [ANN] dummyphp MIME-Version: 1 Content-Type: multipart/mixed; boundary="Boundary-00=_PJzV/OFxF4/L01l" Message-Id: List-Id: To: linux-hotplug@vger.kernel.org --Boundary-00=_PJzV/OFxF4/L01l Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi, I think it's time to announce my dummyphp patches to the public. Dummyphp adds a pseudo hotplug driver which allows to simulate hotplug events by writing 0 or 1 to the power files of the PCI slots. It claims all PCI slots it finds in the system, so it should not be used if any other hotplug driver is present in the system. Of course it's only a logical remove, the power to the device is still on so there is a great chance to destroy important things (hardware!) if you pull out a PCI board after disabling it. It's also possible to reactivate the board again and work with it as before. If you are using kernel 2.[56] and drivers using the new driver model it's not necessary to unload the driver of the card before, the kernel will tell the driver that the adapter has been removed and the driver will release his internal stuff. With kernel 2.4 it's not that easy, dummyphp will refuse to deactivate an adapter with loaded driver. It does the same as fakephp.c which is in 2.6 now, with 2 differences: -it does not remove the slot directory from sysfs on disable -you can reenable slots Any feedback welcome. Greg, it would be nice if you push this to Marcelo and Linus. Eike --Boundary-00=_PJzV/OFxF4/L01l Content-Type: text/x-diff; charset="us-ascii"; name="2.4.22-pre8-dummyphp.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="2.4.22-pre8-dummyphp.diff" diff -Nau -x .depend -x '*vmlinux*' linux-2.4.22-pre8-diff/drivers/hotplug/Config.in linux-2.4.22-pre8-caliban/drivers/hotplug/Config.in --- linux-2.4.22-pre8-diff/drivers/hotplug/Config.in 2003-07-26 22:01:18.000000000 +0200 +++ linux-2.4.22-pre8-caliban/drivers/hotplug/Config.in 2003-07-25 14:56:14.000000000 +0200 @@ -6,6 +6,8 @@ dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_EXPERIMENTAL $CONFIG_PCI +dep_tristate ' Dummy PCI Hotplug driver' CONFIG_HOTPLUG_PCI_DUMMY $CONFIG_HOTPLUG_PCI + dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86 dep_mbool ' Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ if [ "$CONFIG_X86_IO_APIC" = "y" ]; then diff -Nau -x .depend -x '*vmlinux*' linux-2.4.22-pre8-diff/drivers/hotplug/Makefile linux-2.4.22-pre8-caliban/drivers/hotplug/Makefile --- linux-2.4.22-pre8-diff/drivers/hotplug/Makefile 2003-07-26 22:01:18.000000000 +0200 +++ linux-2.4.22-pre8-caliban/drivers/hotplug/Makefile 2003-07-25 14:56:14.000000000 +0200 @@ -4,11 +4,12 @@ O_TARGET := vmlinux-obj.o -list-multi := cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o +list-multi := cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o dummyphp.o export-objs := pci_hotplug_core.o pci_hotplug_util.o obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o +obj-$(CONFIG_HOTPLUG_PCI_DUMMY) += dummyphp.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o @@ -32,6 +33,8 @@ acpiphp_pci.o \ acpiphp_res.o +dummyphp_objs := dummyphp_core.o + ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) cpqphp-objs += cpqphp_nvram.o endif @@ -50,3 +53,6 @@ acpiphp.o: $(acpiphp_objs) $(LD) -r -o $@ $(acpiphp_objs) + +dummyphp.o: $(dummyphp_objs) + $(LD) -r -o $@ $(dummyphp_objs) diff -Nau -x .depend -x '*vmlinux*' linux-2.4.22-pre8-diff/drivers/hotplug/dummyphp_core.c linux-2.4.22-pre8-caliban/drivers/hotplug/dummyphp_core.c --- linux-2.4.22-pre8-diff/drivers/hotplug/dummyphp_core.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.22-pre8-caliban/drivers/hotplug/dummyphp_core.c 2003-07-26 22:00:46.000000000 +0200 @@ -0,0 +1,379 @@ +/* + * Dummy PCI Hot Plug Controller Driver + * + * Copyright (c) 2003 Rolf Eike Beer + * + * Based on code from: + * Vladimir Kondratiev + * Greg Kroah-Hartman + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * Send feedback to + */ + +/* + * + * This driver will "emulate" removing PCI devices from the system. If + * the "power" file is written to with "0" then the specified PCI device + * will be completely removed from the kernel. + * + * WARNING, this does NOT turn off the power to the PCI device. This is + * a "logical" removal, not a physical or electrical removal. + * + * Use this module at your own risk, you have been warned! + * + */ +#include +#include +#include +#include +#include +#include "pci_hotplug.h" + +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "%s: " format, \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) + +/* name size which is used for entries in pcihpfs */ +#define SLOT_NAME_SIZE 16 /* DUMMY-{BUS}:{DEV} */ + +struct dummy_slot { + struct list_head node; + struct pci_bus *bus; + int devfn; + struct pci_dev *dev; + struct hotplug_slot *slot; +}; + +#ifndef CONFIG_HOTPLUG_PCI_DUMMY_MODULE + #define MY_NAME "dummyphp" +#else + #define MY_NAME THIS_MODULE->name +#endif + +static int debug; +static LIST_HEAD(slot_list); + +#define DRIVER_VERSION "0.1" +#define DRIVER_AUTHOR "Rolf Eike Beer " +#define DRIVER_DESC "Dummy Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); + +static struct hotplug_slot_ops dummy_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, +}; + +/** + * configure_visit_pci_dev - callback to configure new discovered devices + * @wrapped_dev: the device + * @wrapped_bus: the bus of the device + */ +static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + + /* Create /proc/bus/pci proc entry for this device and bus device is on + Notify the drivers of the change */ + dbg("%s - starting\n", __FUNCTION__); + if (dev) { + pci_proc_attach_device(dev); + pci_announce_device_to_drivers(dev); + } + + return 0; +} + +static struct pci_visit configure_functions = { + visit_pci_dev: configure_visit_pci_dev, +}; + +/** + * enable_slot - power on and enable a slot + * @hotplug_slot: slot to enable + */ +static int +enable_slot(struct hotplug_slot *hotplug_slot) +{ + struct pci_dev dev0; + struct dummy_slot *slot; + struct pci_bus *child; + unsigned char bus; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + int rc = 0; + + if (!hotplug_slot) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* enable the specified slot */ + slot = (struct dummy_slot *) hotplug_slot->private; + slot->dev = pci_find_slot(slot->bus->number, slot->devfn); + + /* Still NULL ? Well then scan for it ! */ + if (slot->dev == NULL) { + dbg("INFO: pci_dev still null\n"); + memset(&dev0, 0, sizeof(struct pci_dev)); + dev0.bus = slot->bus; + dev0.devfn = slot->devfn; + dev0.sysdata = slot->bus->sysdata; + + /* this will generate pci_dev structures for all functions, + but we will only call this case when lookup fails */ + slot->dev = pci_scan_slot(&dev0); + if (slot->dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return -ENODEV; + } + } + + if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(slot->dev->bus, + (slot->dev), bus); + pci_do_scan_bus(child); + + } + + if (slot->dev) { + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + wrapped_dev.dev = slot->dev; + wrapped_bus.bus = slot->dev->bus; + rc = pci_visit_dev(&configure_functions, &wrapped_dev, + &wrapped_bus); + } + return rc; +} + +/** + * is_pci_dev_in_use - check if a driver uses a pci device + * @dev: the device to check + */ +static int +is_pci_dev_in_use(struct pci_dev* dev) +{ + /* + * dev->driver will be set if the device is in use by a new-style + * driver -- otherwise, check the device's regions to see if any + * driver has claimed them + */ + + int i, inuse = 0; + + if (dev->driver) + return 1; /* assume driver feels responsible */ + + for (i = 0; !dev->driver && !inuse && (i < 6); i++) { + if (!pci_resource_start(dev, i)) + continue; + + if (pci_resource_flags(dev, i) & IORESOURCE_IO) + inuse = check_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + inuse = check_mem_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + } + + return inuse; + +} + +/** + * disable_slot - disable any adapter in this slot + * @hotplug_slot: slot to disable + */ +static int +disable_slot(struct hotplug_slot *hotplug_slot) +{ + struct pci_dev* old_dev; + int func; + struct dummy_slot *slot; + + if (!hotplug_slot) + return -ENODEV; + + slot = (struct dummy_slot *) hotplug_slot->private; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* assume the driver feels responsible if dev->driver is set */ + if (is_pci_dev_in_use(slot->dev)) { + if (slot->dev->driver) { + err("Can't disable slot %x:%x, driver %s still holds reference to it!", + slot->bus->number, PCI_SLOT(slot->devfn), + slot->dev->driver->name); + } else { + err("Can't disable slot %x:%x, a driver still holds reference to it!", + slot->bus->number, PCI_SLOT(slot->devfn)); + } + return -EBUSY; + } + + /* disable the specified slot */ + + for (func = 0; func < 8; func++) { + old_dev = pci_find_slot(slot->bus->number, slot->devfn+func); + if (old_dev) { + printk(KERN_INFO "Slot %s Removed <%s>\n", + old_dev->slot_name, old_dev->name); + pci_remove_device(old_dev); + } + } + hotplug_slot->info->power_status = 0; + slot->dev = NULL; + + return 0; +} + +/** + * scan_pci_bus - add an entry for every slot on this bus + * @bus: bus to scan + */ +static int __init +scan_pci_bus(const struct pci_bus *bus) +{ + struct dummy_slot *dslot; + struct hotplug_slot *hp; + int retval = -ENOMEM; + unsigned int devfn; + struct pci_dev dev0; + + memset(&dev0, 0, sizeof(dev0)); + dev0.bus = (struct pci_bus*)bus; + dev0.sysdata = bus->sysdata; + for (devfn = 0; devfn < 0x100; devfn += 8) { + hp = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!hp) + goto error; + + memset(hp, 0, sizeof(struct hotplug_slot)); + + hp->info = kmalloc(sizeof(struct hotplug_slot_info), + GFP_KERNEL); + if (!hp->info) + goto error_info; + + memset(hp->info, 0, sizeof(struct hotplug_slot_info)); + + hp->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); + if ( !hp->name ) + goto error_name; + + dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); + if ( !dslot ) + goto error_slot; + + dslot->bus = (struct pci_bus *) bus; + dslot->devfn = devfn; + dslot->slot = hp; + + hp->ops = &dummy_hotplug_slot_ops; + hp->private = (void *) dslot; + + dslot->dev = pci_find_slot(dslot->bus->number, dslot->devfn); + hp->info->power_status = (dslot->dev != NULL); + + hp->info->cur_bus_speed = PCI_SPEED_UNKNOWN; + hp->info->max_bus_speed = PCI_SPEED_UNKNOWN; + + snprintf(hp->name, SLOT_NAME_SIZE, "DUMMY-%02x:%02x", + dslot->bus->number, PCI_SLOT(dslot->devfn)); + + retval = pci_hp_register(hp); + if (retval) { + err("pci_hp_register failed with error %d\n", retval); + goto error_register; + } + list_add(&dslot->node, &slot_list); + } + return 0; + +error_register: + kfree(dslot); +error_slot: + kfree(hp->name); +error_name: + kfree(hp->info); +error_info: + kfree(hp); +error: + return retval; +} + +/** + * scan_pci_buses - scan this bus and all child buses for slots + * @list: list of buses to scan + */ +static int __init +pci_scan_buses(const struct list_head *list) +{ + int retval; + const struct list_head *l; + + list_for_each(l,list) { + const struct pci_bus *b = pci_bus_b(l); + retval = scan_pci_bus(b); + if (retval) + return retval; + retval = pci_scan_buses(&b->children); + if (retval) + return retval; + } + return 0; +} + +static void __exit +cleanup_slots (void) +{ + struct list_head *tmp; + struct list_head *next; + struct dummy_slot *dslot; + + list_for_each_safe (tmp, next, &slot_list) { + dslot = list_entry (tmp, struct dummy_slot, node); + pci_hp_deregister(dslot->slot); + } +} + + +static int __init +dummyphp_init(void) +{ + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + + return pci_scan_buses(&pci_root_buses); +} + + +static void __exit +dummyphp_exit(void) +{ + cleanup_slots(); +} + +module_init(dummyphp_init); +module_exit(dummyphp_exit); --Boundary-00=_PJzV/OFxF4/L01l Content-Type: text/x-diff; charset="us-ascii"; name="2.6.0-test4-dummyphp.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="2.6.0-test4-dummyphp.diff" diff -Nau linux-2.6.0-test1/drivers/pci/hotplug/Kconfig linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Kconfig --- linux-2.6.0-test1/drivers/pci/hotplug/Kconfig 2003-07-14 05:33:13.000000000 +0200 +++ linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Kconfig 2003-07-21 18:11:26.000000000 +0200 @@ -46,6 +46,25 @@ When in doubt, say N. +config HOTPLUG_PCI_DUMMY + tristate "Dummy PCI Hotplug driver" + depends on HOTPLUG_PCI + help + Say Y here if you want to use the dummy PCI hotplug driver. It can + be used to simulate PCI hotplug events if even if your system not + hotplug capable. + + Be careful: it claims all PCI slots in the system. There may be + side effects on other hotplug drivers, so only use one hotplug driver + at the same time. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpqphp. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + config HOTPLUG_PCI_COMPAQ tristate "Compaq PCI Hotplug driver" depends on HOTPLUG_PCI && X86 diff -Nau linux-2.6.0-test1/drivers/pci/hotplug/Makefile linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Makefile --- linux-2.6.0-test1/drivers/pci/hotplug/Makefile 2003-07-14 05:36:33.000000000 +0200 +++ linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Makefile 2003-07-21 18:11:26.000000000 +0200 @@ -9,6 +9,7 @@ obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o +obj-$(CONFIG_HOTPLUG_PCI_DUMMY) += dummyphp.o pci_hotplug-objs := pci_hotplug_core.o @@ -33,6 +34,8 @@ acpiphp_pci.o \ acpiphp_res.o +dummyphp-objs := dummyphp_core.o + ifdef CONFIG_HOTPLUG_PCI_ACPI EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi ifdef CONFIG_ACPI_DEBUG diff -Nau linux-2.6.0-test1/drivers/pci/hotplug/dummyphp_core.c linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/dummyphp_core.c --- linux-2.6.0-test1/drivers/pci/hotplug/dummyphp_core.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/dummyphp_core.c 2003-07-21 18:11:26.000000000 +0200 @@ -0,0 +1,331 @@ +/* + * Dummy PCI Hot Plug Controller Driver + * + * Copyright (c) 2003 Rolf Eike Beer + * + * Based on code from: + * Vladimir Kondratiev + * Greg Kroah-Hartman + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * Send feedback to + */ + +/* + * + * This driver will "emulate" removing PCI devices from the system. If + * the "power" file is written to with "0" then the specified PCI device + * will be completely removed from the kernel. + * + * WARNING, this does NOT turn off the power to the PCI device. This is + * a "logical" removal, not a physical or electrical removal. + * + * Use this module at your own risk, you have been warned! + * + */ +#include +#include +#include +#include +#include +#include "pci_hotplug.h" +#include "../pci.h" + +#ifndef CONFIG_HOTPLUG_PCI_DUMMY_MODULE + #define MY_NAME "dummyphp" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "%s: " format, \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) + +#define DRIVER_AUTHOR "Rolf Eike Beer " +#define DRIVER_DESC "Dummy PCI Hot Plug Controller Driver" + +/* name size which is used for entries in pcihpfs */ +#define SLOT_NAME_SIZE 20 /* DUMMY-{DOMAIN}-{BUS}:{DEV} */ + +struct dummy_slot { + struct list_head node; + struct hotplug_slot *slot; + struct pci_dev *dev; + struct pci_bus *bus; + int devfn; +}; + +static int debug; +static LIST_HEAD(slot_list); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); + +static struct hotplug_slot_ops dummy_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, +}; + +/** + * dummy_release - free the memory of a slot + * @slot: slot pointer to remove + */ +static void dummy_release(struct hotplug_slot *slot) +{ + struct dummy_slot *dslot = slot->private; + + list_del(&dslot->node); + kfree(dslot->slot->info); + kfree(dslot->slot); + if (dslot->dev) + pci_dev_put(dslot->dev); + kfree(dslot); +} + +/** + * add_slot - add a new "hotplug" slot + * @dev - a struct pci_dev describing this slot (regardless if + * there is actually a device in this slot or not) + */ +static inline int __init +add_slot(const struct pci_dev *dev) +{ + struct dummy_slot *dslot; + struct hotplug_slot *slot; + struct pci_dev *tmp_dev; + int retval = -ENOMEM; + + slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!slot) + goto error; + + memset(slot, 0, sizeof(*slot)); + + slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); + if (!slot->info) + goto error_slot; + + memset(slot->info, 0, sizeof(struct hotplug_slot_info)); + + slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; + slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; + + slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); + if (!slot->name) + goto error_info; + dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); + if (!dslot) + goto error_name; + + dslot->bus = dev->bus; + dslot->devfn = dev->devfn; + + tmp_dev = pci_find_slot(dslot->bus->number, dslot->devfn); + slot->info->power_status = (tmp_dev != NULL); + + slot->ops = &dummy_hotplug_slot_ops; + slot->release = &dummy_release; + slot->private = (void *) dslot; + + snprintf(slot->name, SLOT_NAME_SIZE, "DUMMY-%04x:%02x:%02x", + pci_domain_nr(dev->bus), dslot->bus->number, + PCI_SLOT(dslot->devfn)); + + retval = pci_hp_register(slot); + if (retval) { + err("pci_hp_register failed with error %d\n", retval); + goto error_dslot; + } + + dslot->slot = slot; + if (slot->info->power_status) { + dslot->dev = pci_dev_get(tmp_dev); + } else { + dslot->dev = NULL; + } + list_add(&dslot->node, &slot_list); + + return retval; + +error_dslot: + kfree(dslot); +error_name: + kfree(slot->name); +error_info: + kfree(slot->info); +error_slot: + kfree(slot); +error: + return retval; +} + +/** + * scan_pci_bus - add an entry for every slot on this bus + * @bus: bus to scan + */ +static inline int __init +scan_pci_bus(const struct pci_bus *bus) +{ + int retval; + struct pci_dev dev0; + + memset(&dev0, 0, sizeof(struct pci_dev)); + dev0.bus = (struct pci_bus*) bus; + dev0.sysdata = bus->sysdata; + for (dev0.devfn = 0; dev0.devfn < 0x100; dev0.devfn += 8) { + retval = add_slot(&dev0); + if (retval) + break; + } + return retval; +} + +/** + * enable_slot - power on and enable a slot + * @hotplug_slot: slot to enable + */ +static int +enable_slot(struct hotplug_slot *hotplug_slot) +{ + struct dummy_slot *dslot; + struct pci_dev *dev; + int num; + + if (!hotplug_slot) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* enable the specified slot */ + dslot = (struct dummy_slot *) hotplug_slot->private; + + dev = dslot->dev; + if (dev == NULL) + dev = pci_find_slot(dslot->bus->number, dslot->devfn); + + /* No pci device, we need to create it then */ + if (dev == NULL) { + dbg("INFO: pci_dev still null\n"); + + num = pci_scan_slot(dslot->bus, dslot->devfn); + if (num) + pci_bus_add_devices(dslot->bus); + + dev = pci_find_slot(dslot->bus->number, dslot->devfn); + if (dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return -ENODEV; + } + dslot->dev = pci_dev_get(dev); + } + + return 0; +} + +/** + * disable_slot - disable any adapter in this slot + * @slot: slot to disable + */ +static int +disable_slot(struct hotplug_slot *slot) +{ + struct dummy_slot *dslot; + + if (!slot) + return -ENODEV; + + dslot = (struct dummy_slot *) slot->private; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, slot->name); + + /* don't disable bridged devices just yet, we can't handle them easily... */ + if (dslot->dev->subordinate) { + err("Can't remove PCI devices with other PCI devices behind it yet.\n"); + return -EPERM; + } + + if (!dslot->dev) { + dbg("No device in slot, exiting"); + return -ENODEV; + } + pci_dev_put(dslot->dev); + + /* remove the device from the pci core */ + info("Slot %s removed\n", pci_name(dslot->dev)); + pci_remove_bus_device(dslot->dev); + + dslot->dev = NULL; + + slot->info->power_status = 0; + + return 0; +} + +/** + * pci_scan_buses - scan this bus and all child buses for slots + * @list: list of buses to scan + */ +static int __init +pci_scan_buses(const struct list_head *list) +{ + int retval; + const struct list_head *l; + + list_for_each(l,list) { + const struct pci_bus *b = pci_bus_b(l); + retval = scan_pci_bus(b); + if (retval) + return retval; + retval = pci_scan_buses(&b->children); + if (retval) + return retval; + } + return 0; +} + +static inline void __exit +cleanup_slots(void) +{ + struct list_head *tmp; + struct list_head *next; + struct dummy_slot *dslot; + + list_for_each_safe (tmp, next, &slot_list) { + dslot = list_entry (tmp, struct dummy_slot, node); + pci_hp_deregister(dslot->slot); + } +} + +static int __init +dummyphp_init(void) +{ + info(DRIVER_DESC "\n"); + + return pci_scan_buses(&pci_root_buses); +} + +static void __exit +dummyphp_exit(void) +{ + cleanup_slots(); +} + +module_init(dummyphp_init); +module_exit(dummyphp_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); --Boundary-00=_PJzV/OFxF4/L01l-- ------------------------------------------------------- This sf.net email is sponsored by:ThinkGeek Welcome to geek heaven. http://thinkgeek.com/sf _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel