nfsd: move most of nfsfh.h to fs/nfsd
[safe/jmp/linux-2.6] / drivers / pci / hotplug / pci_hotplug_core.c
index c802f62..0325d98 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Send feedback to <greg@kroah.com>
- *
- * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs
+ * Send feedback to <kristen.c.accardi@intel.com>
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
+#include <linux/pci_hotplug.h>
 #include <asm/uaccess.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include "pci_hotplug.h"
-
+#include "../pci.h"
 
 #define MY_NAME        "pci_hotplug"
 
-#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
+#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __func__ , ## 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 warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
@@ -65,43 +62,7 @@ static int debug;
 //////////////////////////////////////////////////////////////////
 
 static LIST_HEAD(pci_hotplug_slot_list);
-
-struct subsystem pci_hotplug_slots_subsys;
-
-static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
-               struct attribute *attr, char *buf)
-{
-       struct hotplug_slot *slot = to_hotplug_slot(kobj);
-       struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
-       return attribute->show ? attribute->show(slot, buf) : 0;
-}
-
-static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
-               struct attribute *attr, const char *buf, size_t len)
-{
-       struct hotplug_slot *slot = to_hotplug_slot(kobj);
-       struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
-       return attribute->store ? attribute->store(slot, buf, len) : 0;
-}
-
-static struct sysfs_ops hotplug_slot_sysfs_ops = {
-       .show = hotplug_slot_attr_show,
-       .store = hotplug_slot_attr_store,
-};
-
-static void hotplug_slot_release(struct kobject *kobj)
-{
-       struct hotplug_slot *slot = to_hotplug_slot(kobj);
-       if (slot->release)
-               slot->release(slot);
-}
-
-static struct kobj_type hotplug_slot_ktype = {
-       .sysfs_ops = &hotplug_slot_sysfs_ops,
-       .release = &hotplug_slot_release,
-};
-
-decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
+static DEFINE_MUTEX(pci_hp_mutex);
 
 /* these strings match up with the values in pci_bus_speed */
 static char *pci_bus_speed_strings[] = {
@@ -125,7 +86,8 @@ static char *pci_bus_speed_strings[] = {
        "66 MHz PCIX 533",      /* 0x11 */
        "100 MHz PCIX 533",     /* 0x12 */
        "133 MHz PCIX 533",     /* 0x13 */
-       "25 GBps PCI-E",        /* 0x14 */
+       "2.5 GT/s PCI-E",       /* 0x14 */
+       "5.0 GT/s PCI-E",       /* 0x15 */
 };
 
 #ifdef CONFIG_HOTPLUG_PCI_CPCI
@@ -142,13 +104,13 @@ static int get_##name (struct hotplug_slot *slot, type *value)            \
 {                                                                      \
        struct hotplug_slot_ops *ops = slot->ops;                       \
        int retval = 0;                                                 \
-       if (try_module_get(ops->owner)) {                               \
-               if (ops->get_##name)                                    \
-                       retval = ops->get_##name (slot, value);         \
-               else                                                    \
-                       *value = slot->info->name;                      \
-               module_put(ops->owner);                                 \
-       }                                                               \
+       if (!try_module_get(ops->owner))                                \
+               return -ENODEV;                                         \
+       if (ops->get_##name)                                            \
+               retval = ops->get_##name(slot, value);                  \
+       else                                                            \
+               *value = slot->info->name;                              \
+       module_put(ops->owner);                                         \
        return retval;                                                  \
 }
 
@@ -156,16 +118,15 @@ GET_STATUS(power_status, u8)
 GET_STATUS(attention_status, u8)
 GET_STATUS(latch_status, u8)
 GET_STATUS(adapter_status, u8)
-GET_STATUS(address, u32)
 GET_STATUS(max_bus_speed, enum pci_bus_speed)
 GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
-static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t power_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_power_status (slot, &value);
+       retval = get_power_status(slot->hotplug, &value);
        if (retval)
                goto exit;
        retval = sprintf (buf, "%d\n", value);
@@ -173,9 +134,10 @@ exit:
        return retval;
 }
 
-static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
+static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
                size_t count)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        unsigned long lpower;
        u8 power;
        int retval = 0;
@@ -211,29 +173,30 @@ exit:
        return count;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_power = {
+static struct pci_slot_attribute hotplug_slot_attr_power = {
        .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
        .show = power_read_file,
        .store = power_write_file
 };
 
-static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t attention_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_attention_status (slot, &value);
+       retval = get_attention_status(slot->hotplug, &value);
        if (retval)
                goto exit;
-       retval = sprintf (buf, "%d\n", value);
+       retval = sprintf(buf, "%d\n", value);
 
 exit:
        return retval;
 }
 
-static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
+static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
                size_t count)
 {
+       struct hotplug_slot_ops *ops = slot->hotplug->ops;
        unsigned long lattention;
        u8 attention;
        int retval = 0;
@@ -242,13 +205,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
        attention = (u8)(lattention & 0xff);
        dbg (" - attention = %d\n", attention);
 
-       if (!try_module_get(slot->ops->owner)) {
+       if (!try_module_get(ops->owner)) {
                retval = -ENODEV;
                goto exit;
        }
-       if (slot->ops->set_attention_status)
-               retval = slot->ops->set_attention_status(slot, attention);
-       module_put(slot->ops->owner);
+       if (ops->set_attention_status)
+               retval = ops->set_attention_status(slot->hotplug, attention);
+       module_put(ops->owner);
 
 exit:  
        if (retval)
@@ -256,18 +219,18 @@ exit:
        return count;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
+static struct pci_slot_attribute hotplug_slot_attr_attention = {
        .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
        .show = attention_read_file,
        .store = attention_write_file
 };
 
-static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t latch_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_latch_status (slot, &value);
+       retval = get_latch_status(slot->hotplug, &value);
        if (retval)
                goto exit;
        retval = sprintf (buf, "%d\n", value);
@@ -276,17 +239,17 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
+static struct pci_slot_attribute hotplug_slot_attr_latch = {
        .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
        .show = latch_read_file,
 };
 
-static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t presence_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_adapter_status (slot, &value);
+       retval = get_adapter_status(slot->hotplug, &value);
        if (retval)
                goto exit;
        retval = sprintf (buf, "%d\n", value);
@@ -295,42 +258,20 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
+static struct pci_slot_attribute hotplug_slot_attr_presence = {
        .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
        .show = presence_read_file,
 };
 
-static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
-{
-       int retval;
-       u32 address;
-
-       retval = get_address (slot, &address);
-       if (retval)
-               goto exit;
-       retval = sprintf (buf, "%04x:%02x:%02x\n",
-                         (address >> 16) & 0xffff,
-                         (address >> 8) & 0xff,
-                         address & 0xff);
-
-exit:
-       return retval;
-}
-
-static struct hotplug_slot_attribute hotplug_slot_attr_address = {
-       .attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
-       .show = address_read_file,
-};
-
 static char *unknown_speed = "Unknown bus speed";
 
-static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf)
 {
        char *speed_string;
        int retval;
        enum pci_bus_speed value;
        
-       retval = get_max_bus_speed (slot, &value);
+       retval = get_max_bus_speed(slot->hotplug, &value);
        if (retval)
                goto exit;
 
@@ -345,18 +286,18 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
+static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = {
        .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
        .show = max_bus_speed_read_file,
 };
 
-static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf)
 {
        char *speed_string;
        int retval;
        enum pci_bus_speed value;
 
-       retval = get_cur_bus_speed (slot, &value);
+       retval = get_cur_bus_speed(slot->hotplug, &value);
        if (retval)
                goto exit;
 
@@ -371,14 +312,15 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
+static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = {
        .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
        .show = cur_bus_speed_read_file,
 };
 
-static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
+static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
                size_t count)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        unsigned long ltest;
        u32 test;
        int retval = 0;
@@ -401,140 +343,198 @@ exit:
        return count;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_test = {
+static struct pci_slot_attribute hotplug_slot_attr_test = {
        .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
        .store = test_write_file
 };
 
-static int has_power_file (struct hotplug_slot *slot)
+static bool has_power_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
-               return -ENODEV;
+               return false;
        if ((slot->ops->enable_slot) ||
            (slot->ops->disable_slot) ||
            (slot->ops->get_power_status))
-               return 0;
-       return -ENOENT;
+               return true;
+       return false;
 }
 
-static int has_attention_file (struct hotplug_slot *slot)
+static bool has_attention_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
-               return -ENODEV;
+               return false;
        if ((slot->ops->set_attention_status) ||
            (slot->ops->get_attention_status))
-               return 0;
-       return -ENOENT;
+               return true;
+       return false;
 }
 
-static int has_latch_file (struct hotplug_slot *slot)
+static bool has_latch_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
-               return -ENODEV;
+               return false;
        if (slot->ops->get_latch_status)
-               return 0;
-       return -ENOENT;
+               return true;
+       return false;
 }
 
-static int has_adapter_file (struct hotplug_slot *slot)
+static bool has_adapter_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
-               return -ENODEV;
+               return false;
        if (slot->ops->get_adapter_status)
-               return 0;
-       return -ENOENT;
-}
-
-static int has_address_file (struct hotplug_slot *slot)
-{
-       if ((!slot) || (!slot->ops))
-               return -ENODEV;
-       if (slot->ops->get_address)
-               return 0;
-       return -ENOENT;
+               return true;
+       return false;
 }
 
-static int has_max_bus_speed_file (struct hotplug_slot *slot)
+static bool has_max_bus_speed_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
-               return -ENODEV;
+               return false;
        if (slot->ops->get_max_bus_speed)
-               return 0;
-       return -ENOENT;
+               return true;
+       return false;
 }
 
-static int has_cur_bus_speed_file (struct hotplug_slot *slot)
+static bool has_cur_bus_speed_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
-               return -ENODEV;
+               return false;
        if (slot->ops->get_cur_bus_speed)
-               return 0;
-       return -ENOENT;
+               return true;
+       return false;
 }
 
-static int has_test_file (struct hotplug_slot *slot)
+static bool has_test_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
-               return -ENODEV;
+               return false;
        if (slot->ops->hardware_test)
-               return 0;
-       return -ENOENT;
+               return true;
+       return false;
 }
 
-static int fs_add_slot (struct hotplug_slot *slot)
+static int fs_add_slot(struct pci_slot *slot)
 {
-       if (has_power_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+       int retval = 0;
 
-       if (has_attention_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+       /* Create symbolic link to the hotplug driver module */
+       pci_hp_create_module_link(slot);
 
-       if (has_latch_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+       if (has_power_file(slot)) {
+               retval = sysfs_create_file(&slot->kobj,
+                                          &hotplug_slot_attr_power.attr);
+               if (retval)
+                       goto exit_power;
+       }
 
-       if (has_adapter_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+       if (has_attention_file(slot)) {
+               retval = sysfs_create_file(&slot->kobj,
+                                          &hotplug_slot_attr_attention.attr);
+               if (retval)
+                       goto exit_attention;
+       }
 
-       if (has_address_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+       if (has_latch_file(slot)) {
+               retval = sysfs_create_file(&slot->kobj,
+                                          &hotplug_slot_attr_latch.attr);
+               if (retval)
+                       goto exit_latch;
+       }
 
-       if (has_max_bus_speed_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+       if (has_adapter_file(slot)) {
+               retval = sysfs_create_file(&slot->kobj,
+                                          &hotplug_slot_attr_presence.attr);
+               if (retval)
+                       goto exit_adapter;
+       }
 
-       if (has_cur_bus_speed_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+       if (has_max_bus_speed_file(slot)) {
+               retval = sysfs_create_file(&slot->kobj,
+                                       &hotplug_slot_attr_max_bus_speed.attr);
+               if (retval)
+                       goto exit_max_speed;
+       }
 
-       if (has_test_file(slot) == 0)
-               sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr);
+       if (has_cur_bus_speed_file(slot)) {
+               retval = sysfs_create_file(&slot->kobj,
+                                       &hotplug_slot_attr_cur_bus_speed.attr);
+               if (retval)
+                       goto exit_cur_speed;
+       }
 
-       return 0;
+       if (has_test_file(slot)) {
+               retval = sysfs_create_file(&slot->kobj,
+                                          &hotplug_slot_attr_test.attr);
+               if (retval)
+                       goto exit_test;
+       }
+
+       goto exit;
+
+exit_test:
+       if (has_cur_bus_speed_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_cur_bus_speed.attr);
+exit_cur_speed:
+       if (has_max_bus_speed_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_max_bus_speed.attr);
+exit_max_speed:
+       if (has_adapter_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_presence.attr);
+exit_adapter:
+       if (has_latch_file(slot))
+               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+exit_latch:
+       if (has_attention_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_attention.attr);
+exit_attention:
+       if (has_power_file(slot))
+               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+exit_power:
+       pci_hp_remove_module_link(slot);
+exit:
+       return retval;
 }
 
-static void fs_remove_slot (struct hotplug_slot *slot)
+static void fs_remove_slot(struct pci_slot *slot)
 {
-       if (has_power_file(slot) == 0)
+       if (has_power_file(slot))
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
 
-       if (has_attention_file(slot) == 0)
-               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+       if (has_attention_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_attention.attr);
 
-       if (has_latch_file(slot) == 0)
+       if (has_latch_file(slot))
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
 
-       if (has_adapter_file(slot) == 0)
-               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
-
-       if (has_address_file(slot) == 0)
-               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+       if (has_adapter_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_presence.attr);
 
-       if (has_max_bus_speed_file(slot) == 0)
-               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+       if (has_max_bus_speed_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_max_bus_speed.attr);
 
-       if (has_cur_bus_speed_file(slot) == 0)
-               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+       if (has_cur_bus_speed_file(slot))
+               sysfs_remove_file(&slot->kobj,
+                                 &hotplug_slot_attr_cur_bus_speed.attr);
 
-       if (has_test_file(slot) == 0)
+       if (has_test_file(slot))
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
+
+       pci_hp_remove_module_link(slot);
 }
 
 static struct hotplug_slot *get_slot_from_name (const char *name)
@@ -544,82 +544,112 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
 
        list_for_each (tmp, &pci_hotplug_slot_list) {
                slot = list_entry (tmp, struct hotplug_slot, slot_list);
-               if (strcmp(slot->name, name) == 0)
+               if (strcmp(hotplug_slot_name(slot), name) == 0)
                        return slot;
        }
        return NULL;
 }
 
 /**
- * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
+ * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
+ * @bus: bus this slot is on
  * @slot: pointer to the &struct hotplug_slot to register
+ * @devnr: device number
+ * @name: name registered with kobject core
+ * @owner: caller module owner
+ * @mod_name: caller module name
  *
  * Registers a hotplug slot with the pci hotplug subsystem, which will allow
  * userspace interaction to the slot.
  *
  * Returns 0 if successful, anything else for an error.
  */
-int pci_hp_register (struct hotplug_slot *slot)
+int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus,
+                     int devnr, const char *name,
+                     struct module *owner, const char *mod_name)
 {
        int result;
+       struct pci_slot *pci_slot;
 
        if (slot == NULL)
                return -ENODEV;
        if ((slot->info == NULL) || (slot->ops == NULL))
                return -EINVAL;
        if (slot->release == NULL) {
-               dbg("Why are you trying to register a hotplug slot"
+               dbg("Why are you trying to register a hotplug slot "
                    "without a proper release function?\n");
                return -EINVAL;
        }
 
-       kobject_set_name(&slot->kobj, "%s", slot->name);
-       kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
+       slot->ops->owner = owner;
+       slot->ops->mod_name = mod_name;
 
-       /* this can fail if we have already registered a slot with the same name */
-       if (kobject_register(&slot->kobj)) {
-               err("Unable to register kobject");
-               return -EINVAL;
+       mutex_lock(&pci_hp_mutex);
+       /*
+        * No problems if we call this interface from both ACPI_PCI_SLOT
+        * driver and call it here again. If we've already created the
+        * pci_slot, the interface will simply bump the refcount.
+        */
+       pci_slot = pci_create_slot(bus, devnr, name, slot);
+       if (IS_ERR(pci_slot)) {
+               result = PTR_ERR(pci_slot);
+               goto out;
        }
-               
-       list_add (&slot->slot_list, &pci_hotplug_slot_list);
 
-       result = fs_add_slot (slot);
-       dbg ("Added slot %s to the list\n", slot->name);
+       slot->pci_slot = pci_slot;
+       pci_slot->hotplug = slot;
+
+       list_add(&slot->slot_list, &pci_hotplug_slot_list);
+
+       result = fs_add_slot(pci_slot);
+       kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
+       dbg("Added slot %s to the list\n", name);
+out:
+       mutex_unlock(&pci_hp_mutex);
        return result;
 }
 
 /**
  * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
- * @slot: pointer to the &struct hotplug_slot to deregister
+ * @hotplug: pointer to the &struct hotplug_slot to deregister
  *
  * The @slot must have been registered with the pci hotplug subsystem
  * previously with a call to pci_hp_register().
  *
  * Returns 0 if successful, anything else for an error.
  */
-int pci_hp_deregister (struct hotplug_slot *slot)
+int pci_hp_deregister(struct hotplug_slot *hotplug)
 {
        struct hotplug_slot *temp;
+       struct pci_slot *slot;
 
-       if (slot == NULL)
+       if (!hotplug)
                return -ENODEV;
 
-       temp = get_slot_from_name (slot->name);
-       if (temp != slot) {
+       mutex_lock(&pci_hp_mutex);
+       temp = get_slot_from_name(hotplug_slot_name(hotplug));
+       if (temp != hotplug) {
+               mutex_unlock(&pci_hp_mutex);
                return -ENODEV;
        }
-       list_del (&slot->slot_list);
 
-       fs_remove_slot (slot);
-       dbg ("Removed slot %s from the list\n", slot->name);
-       kobject_unregister(&slot->kobj);
+       list_del(&hotplug->slot_list);
+
+       slot = hotplug->pci_slot;
+       fs_remove_slot(slot);
+       dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug));
+
+       hotplug->release(hotplug);
+       slot->hotplug = NULL;
+       pci_destroy_slot(slot);
+       mutex_unlock(&pci_hp_mutex);
+
        return 0;
 }
 
 /**
  * pci_hp_change_slot_info - changes the slot's information structure in the core
- * @slot: pointer to the slot whose info has changed
+ * @hotplug: pointer to the slot whose info has changed
  * @info: pointer to the info copy into the slot's info structure
  *
  * @slot must have been registered with the pci 
@@ -627,44 +657,15 @@ int pci_hp_deregister (struct hotplug_slot *slot)
  *
  * Returns 0 if successful, anything else for an error.
  */
-int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info)
+int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
+                                        struct hotplug_slot_info *info)
 {
-       if ((slot == NULL) || (info == NULL))
+       struct pci_slot *slot;
+       if (!hotplug || !info)
                return -ENODEV;
+       slot = hotplug->pci_slot;
 
-       /*
-       * check all fields in the info structure, and update timestamps
-       * for the files referring to the fields that have now changed.
-       */
-       if ((has_power_file(slot) == 0) &&
-           (slot->info->power_status != info->power_status))
-               sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr);
-
-       if ((has_attention_file(slot) == 0) &&
-           (slot->info->attention_status != info->attention_status))
-               sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
-
-       if ((has_latch_file(slot) == 0) &&
-           (slot->info->latch_status != info->latch_status))
-               sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
-
-       if ((has_adapter_file(slot) == 0) &&
-           (slot->info->adapter_status != info->adapter_status))
-               sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
-
-       if ((has_address_file(slot) == 0) &&
-           (slot->info->address != info->address))
-               sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr);
-
-       if ((has_max_bus_speed_file(slot) == 0) &&
-           (slot->info->max_bus_speed != info->max_bus_speed))
-               sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
-
-       if ((has_cur_bus_speed_file(slot) == 0) &&
-           (slot->info->cur_bus_speed != info->cur_bus_speed))
-               sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
-
-       memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
+       memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));
 
        return 0;
 }
@@ -673,31 +674,21 @@ static int __init pci_hotplug_init (void)
 {
        int result;
 
-       kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
-       result = subsystem_register(&pci_hotplug_slots_subsys);
-       if (result) {
-               err("Register subsys with error %d\n", result);
-               goto exit;
-       }
        result = cpci_hotplug_init(debug);
        if (result) {
                err ("cpci_hotplug_init with error %d\n", result);
-               goto err_subsys;
+               goto err_cpci;
        }
 
        info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
-       goto exit;
-       
-err_subsys:
-       subsystem_unregister(&pci_hotplug_slots_subsys);
-exit:
+
+err_cpci:
        return result;
 }
 
 static void __exit pci_hotplug_exit (void)
 {
        cpci_hotplug_exit();
-       subsystem_unregister(&pci_hotplug_slots_subsys);
 }
 
 module_init(pci_hotplug_init);
@@ -709,7 +700,6 @@ MODULE_LICENSE("GPL");
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
 
-EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
-EXPORT_SYMBOL_GPL(pci_hp_register);
+EXPORT_SYMBOL_GPL(__pci_hp_register);
 EXPORT_SYMBOL_GPL(pci_hp_deregister);
 EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);