bk://kernel.bkbits.net/gregkh/linux/driver-2.6
gregkh@suse.de|ChangeSet|20050326044355|49769 gregkh

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/30 17:16:36-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core
# 
# include/linux/usb.h
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/serial/visor.c
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/host/ohci-dbg.c
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/core/hcd.c
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/scsi/scsi_transport_spi.c
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/scsi/scsi_sysfs.c
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/scsi/osst.c
#   2005/03/30 17:16:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/30 12:21:44-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core
# 
# include/linux/device.h
#   2005/03/30 12:21:39-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/base/power/suspend.c
#   2005/03/30 12:21:39-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/28 22:33:15-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core
# 
# drivers/video/fbmem.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/media/dvb/dvb-core/dvbdev.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ieee1394/video1394.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ieee1394/raw1394.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ieee1394/nodemgr.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ieee1394/dv1394.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/tty_io.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/stallion.c
#   2005/03/28 22:33:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/mem.c
#   2005/03/28 22:33:09-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/block/Kconfig
#   2005/03/28 22:33:09-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/27 16:41:05-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core
# 
# BitKeeper/deleted/.del-netlink_dev.c~9601d74e9c777959
#   2005/03/27 16:41:00-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# BitKeeper/deleted/.del-netlink_dev.c~9601d74e9c777959
#   2005/03/27 16:41:00-08:00 akpm@bix.(none) +0 -0
#   Merge rename: net/netlink/netlink_dev.c -> BitKeeper/deleted/.del-netlink_dev.c~9601d74e9c777959
# 
# ChangeSet
#   2005/03/25 20:43:55-08:00 gregkh@suse.de 
#   [pcie] use device_for_each_child() to properly access child devices.
#     
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/pci/pcie/portdrv_core.c
#   2005/03/25 20:43:29-08:00 gregkh@suse.de +45 -61
#   [pcie] use device_for_each_child() to properly access child devices.
#     
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/25 15:52:00-08:00 gregkh@suse.de 
#   [scsi] use device_for_each_child() to properly access child devices.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/scsi/scsi_transport_spi.c
#   2005/03/25 15:51:47-08:00 gregkh@suse.de +10 -6
#   [scsi] use device_for_each_child() to properly access child devices.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/25 11:45:31-08:00 gregkh@suse.de 
#   [ieee1394] Use device_for_each_child() to unregister devices in nodemgr_remove_host_dev()
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/ieee1394/nodemgr.c
#   2005/03/25 11:45:04-08:00 gregkh@suse.de +6 -5
#   [ieee1394] Use device_for_each_child() to unregister devices in nodemgr_remove_host_dev()
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/25 09:26:50-08:00 gregkh@suse.de 
#   Merge bk://kernel.bkbits.net//home/mochel/linux-2.6-core
#   into suse.de:/home/greg/linux/BK/driver-2.6
# 
# include/linux/device.h
#   2005/03/25 09:26:47-08:00 gregkh@suse.de +0 -0
#   Auto merged
# 
# drivers/usb/core/usb.c
#   2005/03/25 09:26:47-08:00 gregkh@suse.de +0 -0
#   Auto merged
# 
# drivers/base/driver.c
#   2005/03/25 09:26:47-08:00 gregkh@suse.de +0 -0
#   Auto merged
# 
# drivers/base/dd.c
#   2005/03/25 09:26:47-08:00 gregkh@suse.de +0 -1
#   Auto merged
# 
# drivers/base/core.c
#   2005/03/25 09:26:47-08:00 gregkh@suse.de +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/24 22:02:52-08:00 mochel@digitalimplant.org 
#   [PATCH] Driver core: fix remove module bug
#   
#   On Thu, 24 Mar 2005, Andrew Morton wrote:
#   
#   > Laurent Riffard <laurent.riffard@free.fr> wrote:
#   > >
#   > > hello,
#   > >
#   > > Same kinds of problem here. It depends on the removed module. I mean:
#   > > "rmmod loop" or "rmmod pcspkr" works. But "rmmod snd_ens1371" or "rmmod
#   > > ohci1394" hangs.
#   > >
#   > > Sysrq-T when rmmoding snd_ens1371 :
#   
#   <snip>
#   
#   > It looks like we're getting stuck in the wait_for_completion() in the new
#   > klist_remove().
#   
#   D'oh! It's getting hung while waiting to remove the current node from the
#   list (which it can't remove because it's being used). The patch below
#   should fix it.
#   
#   From: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/dd.c
#   2005/03/24 16:55:21-08:00 mochel@digitalimplant.org +1 -1
#   Driver core: fix remove module bug
# 
# ChangeSet
#   2005/03/24 20:08:04-08:00 mochel@digitalimplant.org 
#   [driver core] Fix up bogus comment.
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/driver.c
#   2005/03/24 20:07:38-08:00 mochel@digitalimplant.org +1 -2
#   [driver core] Fix up bogus comment.
# 
# ChangeSet
#   2005/03/24 19:08:30-08:00 mochel@digitalimplant.org 
#   [driver core] Use a klist for device child lists.
#   
#   - Use klist iterator in device_for_each_child(), making it safe to use for 
#     removing devices. 
#   - Remove unused list_to_dev() function.
#   - Kills all usage of devices_subsys.rwsem.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/24 19:07:33-08:00 mochel@digitalimplant.org +2 -8
#   [driver core] Use a klist for device child lists.
# 
# drivers/base/core.c
#   2005/03/24 19:07:33-08:00 mochel@digitalimplant.org +15 -15
#   [driver core] Use a klist for device child lists.
# 
# ChangeSet
#   2005/03/24 19:03:59-08:00 mochel@digitalimplant.org 
#   [scsi] Use device_for_each_child() to unregister devices in scsi_remove_target().
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/scsi/scsi_sysfs.c
#   2005/03/24 19:02:55-08:00 mochel@digitalimplant.org +9 -5
#   [scsi] Use device_for_each_child() to unregister devices in scsi_remove_target().
# 
# ChangeSet
#   2005/03/24 18:59:59-08:00 mochel@digitalimplant.org 
#   [klist] Don't reference NULL klist pointer in klist_remove().
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# lib/klist.c
#   2005/03/24 18:59:33-08:00 mochel@digitalimplant.org +3 -2
#   [klist] Don't reference NULL klist pointer in klist_remove().
# 
# ChangeSet
#   2005/03/24 18:58:45-08:00 mochel@digitalimplant.org 
#   [driver core] Call klist_del() instead of klist_remove().
#   
#   - Can't wait on removing the current item in the list (the positive refcount *because*
#     we are using it causes it to deadlock).
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/dd.c
#   2005/03/24 18:58:24-08:00 mochel@digitalimplant.org +1 -1
#   [driver core] Call klist_del() instead of klist_remove().
# 
# ChangeSet
#   2005/03/24 13:42:57-08:00 elenstev@mesatop.com 
#   [PATCH] patch to fix build error In function `zft_init'
#   
#   Steven Cole wrote:
#   > I'm getting the following build error with 2.6.12-rc1-mm2:
#   >
#   >   CC      init/version.o
#   >   LD      init/built-in.o
#   >   LD      .tmp_vmlinux1
#   > drivers/built-in.o(.init.text+0x4323): In function `zft_init':
#   > : undefined reference to `class_device_creat'
#   > make: *** [.tmp_vmlinux1] Error 1
#   >
#   
#   I glanced at the code, and this little patch fixes the problem:
#   
#   
#   Signed-off by: Steven Cole <elenstev@mesatop.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/ftape/zftape/zftape-init.c
#   2005/03/24 07:43:56-08:00 elenstev@mesatop.com +1 -1
#   patch to fix build error In function `zft_init'
# 
# ChangeSet
#   2005/03/24 13:08:05-08:00 mochel@digitalimplant.org 
#   [driver core] Remove struct device::driver_list.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/24 13:07:56-08:00 mochel@digitalimplant.org +0 -1
#   [driver core] Remove struct device::driver_list.
# 
# drivers/base/core.c
#   2005/03/24 13:07:56-08:00 mochel@digitalimplant.org +0 -1
#   [driver core] Remove struct device::driver_list.
# 
# ChangeSet
#   2005/03/24 13:03:35-08:00 mochel@digitalimplant.org 
#   [driver core] Remove struct device::bus_list.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/24 13:03:26-08:00 mochel@digitalimplant.org +0 -1
#   [driver core] Remove struct device::bus_list.
# 
# drivers/base/core.c
#   2005/03/24 13:03:26-08:00 mochel@digitalimplant.org +0 -1
#   [driver core] Remove struct device::bus_list.
# 
# ChangeSet
#   2005/03/24 13:02:28-08:00 mochel@digitalimplant.org 
#   [driver core] Fix up bus code and remove use of rwsem.
#   
#   - Don't add devices to bus's embedded kset, since it's not used by anyone anymore.
#   - Don't need to take the bus rwsem when calling {device,driver}_attach(), since
#     those functions use the klists and the klists' spinlocks.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/bus.c
#   2005/03/24 13:02:19-08:00 mochel@digitalimplant.org +0 -12
#   [driver core] Fix up bus code and remove use of rwsem.
# 
# ChangeSet
#   2005/03/24 13:00:16-08:00 mochel@digitalimplant.org 
#   [usb] Fix up USB to use klist_node_attached() instead of list_empty() on lists that will go away.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/usb/core/usb.c
#   2005/03/24 13:00:07-08:00 mochel@digitalimplant.org +2 -2
#   [usb] Fix up USB to use klist_node_attached() instead of list_empty() on lists that will go away.
# 
# ChangeSet
#   2005/03/24 12:58:57-08:00 mochel@digitalimplant.org 
#   [klist] add klist_node_attached() to determine if a node is on a list or not.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# lib/klist.c
#   2005/03/24 12:58:47-08:00 mochel@digitalimplant.org +16 -0
#   [klist] add klist_node_attached() to determine if a node is on a list or not.
# 
# include/linux/klist.h
#   2005/03/24 12:58:47-08:00 mochel@digitalimplant.org +2 -0
#   [klist] add klist_node_attached() to determine if a node is on a list or not.
# 
# ChangeSet
#   2005/03/24 10:50:24-08:00 mochel@digitalimplant.org 
#   [driver core] Use bus_for_each_{dev,drv} for driver binding.
#   
#   - Now possible, since the lists are locked using the klist lock and not the 
#     global rwsem.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/dd.c
#   2005/03/24 10:50:14-08:00 mochel@digitalimplant.org +41 -34
#   [driver core] Use bus_for_each_{dev,drv} for driver binding.
# 
# ChangeSet
#   2005/03/24 10:48:35-08:00 mochel@digitalimplant.org 
#   [driver core] Remove the unused device_find().
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/24 10:48:27-08:00 mochel@digitalimplant.org +0 -1
#   [driver core] Remove the unused device_find().
# 
# drivers/base/core.c
#   2005/03/24 10:48:26-08:00 mochel@digitalimplant.org +0 -19
#   [driver core] Remove the unused device_find().
# 
# ChangeSet
#   2005/03/24 00:44:28-08:00 gregkh@suse.de 
#   USB: fix build warning in usb core as pointed out by Andrew.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/usb/core/usb.c
#   2005/03/24 00:43:59-08:00 gregkh@suse.de +1 -1
#   USB: fix build warning in usb core as pointed out by Andrew.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 16:12:04-08:00 gregkh@suse.de 
#   class: fix typo in previous isdn class conversion patch.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/isdn/capi/capi.c
#   2005/03/23 16:11:47-08:00 gregkh@suse.de +1 -1
#   class: fix typo in previous isdn class conversion patch.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 15:17:47-08:00 gregkh@suse.de 
#   [PATCH] class: convert drivers/* to use the new class api instead of class_simple
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/video/fbmem.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/usb/core/file.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +6 -6
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/s390/char/vmlogrdr.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/s390/char/tape_class.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/net/wan/cosa.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +6 -6
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/net/ppp_generic.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +7 -7
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/media/dvb/dvb-core/dvbdev.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +6 -7
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/macintosh/adb.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +4 -5
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# drivers/isdn/capi/capi.c
#   2005/03/23 14:23:39-08:00 gregkh@suse.de +7 -7
#   class: convert drivers/* to use the new class api instead of class_simple
# 
# ChangeSet
#   2005/03/23 14:46:44-08:00 gregkh@suse.de 
#   Cset exclude: gregkh@suse.de|ChangeSet|20050323180141|56555
# 
# drivers/video/fbmem.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/usb/serial/visor.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/usb/core/file.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/s390/char/vmlogrdr.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/s390/char/tape_class.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/net/wan/cosa.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/net/ppp_generic.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/media/dvb/dvb-core/dvbdev.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/macintosh/adb.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# drivers/isdn/capi/capi.c
#   2005/03/23 14:46:32-08:00 gregkh@suse.de +0 -0
#   Exclude
# 
# ChangeSet
#   2005/03/23 13:40:55-08:00 kay.sievers@vrfy.org 
#   [PATCH] kobject/hotplug split - net bridge
#   
#   kobject_add() and kobject_del() don't emit hotplug events anymore.
#   We need to do it ourselves now.
#   
#   Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# net/bridge/br_sysfs_if.c
#   2005/03/17 17:17:18-08:00 kay.sievers@vrfy.org +2 -0
#   kobject/hotplug split - net bridge
# 
# ChangeSet
#   2005/03/23 13:40:37-08:00 kay.sievers@vrfy.org 
#   [PATCH] kobject/hotplug split - usb cris
#   
#   kobject_add() and kobject_del() don't emit hotplug events anymore.
#   We need to do it ourselves now.
#   
#   Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/usb/host/hc_crisv10.c
#   2005/03/17 17:17:17-08:00 kay.sievers@vrfy.org +1 -0
#   kobject/hotplug split - usb cris
# 
# ChangeSet
#   2005/03/23 13:40:20-08:00 kay.sievers@vrfy.org 
#   [PATCH] kobject/hotplug split - devices core
#   
#   kobject_add() and kobject_del() don't emit hotplug events anymore. Do it
#   ourselves if we are finished populating the device directory.
#   
#   Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/core.c
#   2005/03/17 17:17:17-08:00 kay.sievers@vrfy.org +3 -0
#   kobject/hotplug split - devices core
# 
# ChangeSet
#   2005/03/23 13:40:02-08:00 kay.sievers@vrfy.org 
#   [PATCH] kobject/hotplug split - block core
#   
#   kobject_add() and kobject_del() don't emit hotplug events anymore. Do it
#   ourselves if we are finished populating the device directory.
#   
#   Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# fs/partitions/check.c
#   2005/03/17 17:17:18-08:00 kay.sievers@vrfy.org +2 -0
#   kobject/hotplug split - block core
# 
# ChangeSet
#   2005/03/23 13:39:45-08:00 kay.sievers@vrfy.org 
#   [PATCH] kobject/hotplug split - class core
#   
#   kobject_add() and kobject_del() don't emit hotplug events anymore. Do it
#   ourselves if we are finished populating the device directory.
#   
#   Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/class.c
#   2005/03/17 17:17:17-08:00 kay.sievers@vrfy.org +2 -0
#   kobject/hotplug split - class core
# 
# ChangeSet
#   2005/03/23 13:39:27-08:00 kay.sievers@vrfy.org 
#   [PATCH] kobject/hotplug split - kobject add/remove
#   
#   kobject_add() and kobject_del() don't emit hotplug events anymore.
#   The user should do it itself if it has finished populating the device
#   directory.
#   
#   Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# lib/kobject.c
#   2005/03/17 17:17:18-08:00 kay.sievers@vrfy.org +3 -4
#   kobject/hotplug split - kobject add/remove
# 
# ChangeSet
#   2005/03/23 11:12:38-08:00 gregkh@suse.de 
#   class: remove class_simple code, as no one in the tree is using it anymore.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/23 11:11:39-08:00 gregkh@suse.de +0 -10
#   class: remove class_simple code, as no one in the tree is using it anymore.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/Makefile
#   2005/03/23 11:11:39-08:00 gregkh@suse.de +1 -1
#   class: remove class_simple code, as no one in the tree is using it anymore.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# BitKeeper/deleted/.del-class_simple.c~7ed076a8f6b7d046
#   2005/03/23 11:12:13-08:00 gregkh@suse.de +0 -0
#   Delete: drivers/base/class_simple.c
# 
# ChangeSet
#   2005/03/23 10:02:56-08:00 gregkh@suse.de 
#   class: add kerneldoc for the new class functions.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/class.c
#   2005/03/23 10:02:38-08:00 gregkh@suse.de +43 -0
#   class: add kerneldoc for the new class functions.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 10:02:26-08:00 gregkh@suse.de 
#   class: convert the remaining class_simple users in the kernel to usee the new class api
#         
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# net/netlink/netlink_dev.c
#   2005/03/23 10:02:09-08:00 gregkh@suse.de +7 -7
#   class: convert the remaining class_simple users in the kernel to usee the new class api
#         
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# fs/coda/psdev.c
#   2005/03/23 10:02:09-08:00 gregkh@suse.de +9 -9
#   class: convert the remaining class_simple users in the kernel to usee the new class api
#         
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 09:56:34-08:00 gregkh@suse.de 
#   class: convert arch/* to use the new class api instead of class_simple
#         
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# arch/i386/kernel/msr.c
#   2005/03/23 09:56:17-08:00 gregkh@suse.de +11 -11
#   class: convert arch/* to use the new class api instead of class_simple
#         
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# arch/i386/kernel/cpuid.c
#   2005/03/23 09:56:17-08:00 gregkh@suse.de +11 -11
#   class: convert arch/* to use the new class api instead of class_simple
#         
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 09:55:22-08:00 gregkh@suse.de 
#   class: convert drivers/scsi/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/scsi/st.c
#   2005/03/23 09:55:04-08:00 gregkh@suse.de +15 -13
#   class: convert drivers/scsi/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/scsi/sg.c
#   2005/03/23 09:55:04-08:00 gregkh@suse.de +7 -7
#   class: convert drivers/scsi/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/scsi/osst.c
#   2005/03/23 09:55:04-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/scsi/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 09:53:36-08:00 gregkh@suse.de 
#   class: convert drivers/ieee1394/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/ieee1394/video1394.c
#   2005/03/23 09:53:18-08:00 gregkh@suse.de +2 -2
#   class: convert drivers/ieee1394/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/ieee1394/raw1394.c
#   2005/03/23 09:53:18-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/ieee1394/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/ieee1394/ieee1394_core.h
#   2005/03/23 09:53:18-08:00 gregkh@suse.de +2 -1
#   class: convert drivers/ieee1394/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/ieee1394/ieee1394_core.c
#   2005/03/23 09:53:18-08:00 gregkh@suse.de +4 -4
#   class: convert drivers/ieee1394/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/ieee1394/dv1394.c
#   2005/03/23 09:53:18-08:00 gregkh@suse.de +3 -3
#   class: convert drivers/ieee1394/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 09:53:09-08:00 gregkh@suse.de 
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/viotape.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +8 -8
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/vc_screen.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +8 -8
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/tipar.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +7 -7
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/stallion.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/snsc.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +4 -3
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/raw.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +9 -9
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/ppdev.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +6 -6
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/misc.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +8 -8
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/mem.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +3 -4
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/lp.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +6 -6
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/istallion.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/ip2main.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +12 -12
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/ftape/zftape/zftape-init.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +15 -15
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/dsp56k.c
#   2005/03/23 09:52:51-08:00 gregkh@suse.de +7 -7
#   class: convert drivers/char/* to use the new class api instead of class_simple
#       
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 09:52:10-08:00 gregkh@suse.de 
#   class: convert drivers/block/* to use the new class api instead of class_simple
#     
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/paride/pt.c
#   2005/03/23 09:51:52-08:00 gregkh@suse.de +10 -10
#   class: convert drivers/block/* to use the new class api instead of class_simple
#     
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/paride/pg.c
#   2005/03/23 09:51:52-08:00 gregkh@suse.de +7 -7
#   class: convert drivers/block/* to use the new class api instead of class_simple
#     
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoechr.c
#   2005/03/23 09:51:52-08:00 gregkh@suse.de +5 -5
#   class: convert drivers/block/* to use the new class api instead of class_simple
#     
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/23 09:51:41-08:00 gregkh@suse.de 
#   class: convert sound/* to use the new class api instead of class_simple
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# sound/sound_core.c
#   2005/03/23 09:51:19-08:00 gregkh@suse.de +5 -5
#   class: convert sound/* to use the new class api instead of class_simple
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# sound/oss/soundcard.c
#   2005/03/23 09:51:19-08:00 gregkh@suse.de +9 -10
#   class: convert sound/* to use the new class api instead of class_simple
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# sound/core/sound.c
#   2005/03/23 09:51:19-08:00 gregkh@suse.de +3 -3
#   class: convert sound/* to use the new class api instead of class_simple
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/22 15:45:57-08:00 gregkh@suse.de 
#   driver core: put proper __attribute_ on class_device_create()
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/22 15:45:32-08:00 gregkh@suse.de +2 -1
#   driver core: put proper __attribute_ on class_device_create()
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/22 12:17:13-08:00 gregkh@suse.de 
#   driver core: change export symbol for driver_for_each_device()
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/driver.c
#   2005/03/22 12:13:56-08:00 gregkh@suse.de +1 -1
#   driver core: change export symbol for driver_for_each_device()
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# ChangeSet
#   2005/03/22 11:17:55-08:00 gregkh@suse.de 
#   Merge bk://kernel.bkbits.net//home/mochel/linux-2.6-core
#   into suse.de:/home/greg/linux/BK/driver-2.6
# 
# include/linux/device.h
#   2005/03/22 11:17:52-08:00 gregkh@suse.de +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/21 12:25:36-08:00 mochel@digitalimplant.org 
#   [driver core] Add a klist to struct device_driver for the devices bound to it.
#   
#   - Use it in driver_for_each_device() instead of the regular list_head and stop using
#     the bus's rwsem for protection.
#   - Use driver_for_each_device() in driver_detach() so we don't deadlock on the
#     bus's rwsem.
#   - Remove ->devices.
#   - Move klist access and sysfs link access out from under device's semaphore, since 
#     they're synchronized through other means. 
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/21 12:25:04-08:00 mochel@digitalimplant.org +2 -1
#   [driver core] Add a klist to struct device_driver for the devices bound to it.
# 
# drivers/base/driver.c
#   2005/03/21 12:25:04-08:00 mochel@digitalimplant.org +15 -12
#   [driver core] Add a klist to struct device_driver for the devices bound to it.
# 
# drivers/base/dd.c
#   2005/03/21 12:25:04-08:00 mochel@digitalimplant.org +20 -17
#   [driver core] Add a klist to struct device_driver for the devices bound to it.
# 
# drivers/base/core.c
#   2005/03/21 12:25:04-08:00 mochel@digitalimplant.org +1 -1
#   [driver core] Add a klist to struct device_driver for the devices bound to it.
# 
# ChangeSet
#   2005/03/21 12:00:18-08:00 mochel@digitalimplant.org 
#   [driver core] Add a klist to struct bus_type for its drivers.
#   
#   - Use it in bus_for_each_drv().
#   - Use the klist spinlock instead of the bus rwsem.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/21 11:59:55-08:00 mochel@digitalimplant.org +2 -0
#   [driver core] Add a klist to struct bus_type for its drivers.
# 
# drivers/base/bus.c
#   2005/03/21 11:59:55-08:00 mochel@digitalimplant.org +23 -29
#   [driver core] Add a klist to struct bus_type for its drivers.
# 
# ChangeSet
#   2005/03/21 11:49:14-08:00 mochel@digitalimplant.org 
#   [driver core] Add a klist to struct bus_type for its devices.
#   
#   - Use it for bus_for_each_dev().
#   - Use the klist spinlock instead of the bus rwsem.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/21 11:48:43-08:00 mochel@digitalimplant.org +3 -0
#   [driver core] Add a klist to struct bus_type for its devices.
# 
# drivers/base/bus.c
#   2005/03/21 11:48:43-08:00 mochel@digitalimplant.org +24 -30
#   [driver core] Add a klist to struct bus_type for its devices.
# 
# ChangeSet
#   2005/03/21 11:45:16-08:00 mochel@digitalimplant.org 
#   [klist] Add initial implementation of klist helpers.
#   
#   This klist interface provides a couple of structures that wrap around 
#   struct list_head to provide explicit list "head" (struct klist) and 
#   list "node" (struct klist_node) objects. For struct klist, a spinlock
#   is included that protects access to the actual list itself. struct 
#   klist_node provides a pointer to the klist that owns it and a kref
#   reference count that indicates the number of current users of that node
#   in the list.
#   
#   The entire point is to provide an interface for iterating over a list
#   that is safe and allows for modification of the list during the
#   iteration (e.g. insertion and removal), including modification of the
#   current node on the list.
#   
#   It works using a 3rd object type - struct klist_iter - that is declared
#   and initialized before an iteration. klist_next() is used to acquire the
#   next element in the list. It returns NULL if there are no more items.
#   This klist interface provides a couple of structures that wrap around 
#   struct list_head to provide explicit list "head" (struct klist) and 
#   list "node" (struct klist_node) objects. For struct klist, a spinlock
#   is included that protects access to the actual list itself. struct 
#   klist_node provides a pointer to the klist that owns it and a kref
#   reference count that indicates the number of current users of that node
#   in the list.
#   
#   The entire point is to provide an interface for iterating over a list
#   that is safe and allows for modification of the list during the
#   iteration (e.g. insertion and removal), including modification of the
#   current node on the list.
#   
#   It works using a 3rd object type - struct klist_iter - that is declared
#   and initialized before an iteration. klist_next() is used to acquire the
#   next element in the list. It returns NULL if there are no more items.
#   Internally, that routine takes the klist's lock, decrements the reference
#   count of the previous klist_node and increments the count of the next
#   klist_node. It then drops the lock and returns.
#   
#   There are primitives for adding and removing nodes to/from a klist. 
#   When deleting, klist_del() will simply decrement the reference count. 
#   Only when the count goes to 0 is the node removed from the list. 
#   klist_remove() will try to delete the node from the list and block
#   until it is actually removed. This is useful for objects (like devices)
#   that have been removed from the system and must be freed (but must wait
#   until all accessors have finished).
#   
#   Internally, that routine takes the klist's lock, decrements the reference
#   count of the previous klist_node and increments the count of the next
#   klist_node. It then drops the lock and returns.
#   
#   There are primitives for adding and removing nodes to/from a klist. 
#   When deleting, klist_del() will simply decrement the reference count. 
#   Only when the count goes to 0 is the node removed from the list. 
#   klist_remove() will try to delete the node from the list and block
#   until it is actually removed. This is useful for objects (like devices)
#   that have been removed from the system and must be freed (but must wait
#   until all accessors have finished).
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# lib/klist.c
#   2005/03/21 11:44:43-08:00 mochel@digitalimplant.org +248 -0
#   [klist] Add initial implementation of klist helpers.
# 
# lib/Makefile
#   2005/03/21 11:44:43-08:00 mochel@digitalimplant.org +4 -3
#   [klist] Add initial implementation of klist helpers.
# 
# include/linux/klist.h
#   2005/03/21 11:44:43-08:00 mochel@digitalimplant.org +53 -0
#   [klist] Add initial implementation of klist helpers.
# 
# include/linux/klist.h
#   2005/03/21 11:11:36-08:00 mochel@digitalimplant.org +0 -0
# 
# include/linux/klist.h
#   2005/03/21 11:11:36-08:00 mochel@digitalimplant.org +0 -0
#   BitKeeper file /home/mochel/src/linux-2.6-core/include/linux/klist.h
# 
# lib/klist.c
#   2005/03/21 11:11:31-08:00 mochel@digitalimplant.org +0 -0
# 
# lib/klist.c
#   2005/03/21 11:11:31-08:00 mochel@digitalimplant.org +0 -0
#   BitKeeper file /home/mochel/src/linux-2.6-core/lib/klist.c
# 
# ChangeSet
#   2005/03/21 11:09:40-08:00 mochel@digitalimplant.org 
#   [usb] Use driver_for_each_device() instead of manually walking list.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/usb/core/usb.c
#   2005/03/21 11:09:29-08:00 mochel@digitalimplant.org +24 -19
#   [usb] Use driver_for_each_device() instead of manually walking list.
# 
# ChangeSet
#   2005/03/21 11:07:54-08:00 mochel@digitalimplant.org 
#   [pnp] Use driver_for_each_device() in drivers/pnp/driver.c instead of manually walking list.
#   
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/pnp/driver.c
#   2005/03/21 11:07:42-08:00 mochel@digitalimplant.org +8 -4
#   [pnp] Use driver_for_each_device() in drivers/pnp/driver.c instead of manually walking list.
# 
# ChangeSet
#   2005/03/21 10:59:56-08:00 mochel@digitalimplant.org 
#   [driver core] Add driver_for_each_device().
#   
#   Now there's an iterator for accessing each device bound to a driver.
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/21 10:59:45-08:00 mochel@digitalimplant.org +3 -0
#   [driver core] Add driver_for_each_device().
# 
# drivers/base/driver.c
#   2005/03/21 10:59:45-08:00 mochel@digitalimplant.org +35 -0
#   [driver core] Add driver_for_each_device().
# 
# ChangeSet
#   2005/03/21 10:52:54-08:00 mochel@digitalimplant.org 
#   [driver core] Move device/driver code to drivers/base/dd.c
#   
#   This relocates the driver binding/unbinding code to drivers/base/dd.c. This is done
#   for two reasons: One, it's not code related to the bus_type itself; it uses some from
#   that, some from devices, and some from drivers. And Two, it will make it easier to do
#   some of the upcoming lock removal on that code..
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/dd.c
#   2005/03/21 10:52:43-08:00 mochel@digitalimplant.org +209 -0
#   [driver core] Move device/driver code to drivers/base/dd.c
# 
# drivers/base/bus.c
#   2005/03/21 10:52:43-08:00 mochel@digitalimplant.org +0 -183
#   [driver core] Move device/driver code to drivers/base/dd.c
# 
# drivers/base/base.h
#   2005/03/21 10:52:43-08:00 mochel@digitalimplant.org +2 -0
#   [driver core] Move device/driver code to drivers/base/dd.c
# 
# drivers/base/Makefile
#   2005/03/21 10:52:43-08:00 mochel@digitalimplant.org +1 -1
#   [driver core] Move device/driver code to drivers/base/dd.c
# 
# drivers/base/dd.c
#   2005/03/21 10:43:20-08:00 mochel@digitalimplant.org +0 -0
# 
# drivers/base/dd.c
#   2005/03/21 10:43:20-08:00 mochel@digitalimplant.org +0 -0
#   BitKeeper file /home/mochel/src/linux-2.6-core/drivers/base/dd.c
# 
# ChangeSet
#   2005/03/21 10:41:04-08:00 mochel@digitalimplant.org 
#   [driver core] Add a semaphore to struct device to synchronize calls to its driver.
#   
#   This adds a per-device semaphore that is taken before every call from the core to a 
#   driver method. This prevents e.g. simultaneous calls to the ->suspend() or ->resume()
#   and ->probe() or ->release(), potentially saving a whole lot of headaches. 
#   
#   It also moves us a step closer to removing the bus rwsem, since it protects the fields
#   in struct device that are modified by the core.
#   
#   Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/21 10:40:48-08:00 mochel@digitalimplant.org +4 -0
#   [driver core] Add a semaphore to struct device to synchronize calls to its driver.
# 
# drivers/base/power/suspend.c
#   2005/03/21 10:40:48-08:00 mochel@digitalimplant.org +2 -2
#   [driver core] Add a semaphore to struct device to synchronize calls to its driver.
# 
# drivers/base/power/resume.c
#   2005/03/21 10:40:48-08:00 mochel@digitalimplant.org +6 -2
#   [driver core] Add a semaphore to struct device to synchronize calls to its driver.
# 
# drivers/base/core.c
#   2005/03/21 10:40:47-08:00 mochel@digitalimplant.org +1 -0
#   [driver core] Add a semaphore to struct device to synchronize calls to its driver.
# 
# drivers/base/bus.c
#   2005/03/21 10:40:47-08:00 mochel@digitalimplant.org +11 -3
#   [driver core] Add a semaphore to struct device to synchronize calls to its driver.
# 
# ChangeSet
#   2005/03/17 16:33:54-08:00 kay.sievers@vrfy.org 
#   [PATCH] add TIMEOUT to firmware_class hotplug event
#   
#   On Tue, 2005-03-15 at 09:25 +0100, Hannes Reinecke wrote:
#   > The current implementation of the firmware class breaks a fundamental
#   > assumption in udevd: that the physical device can be initialised fully
#   > prior to executing the next event for that device.
#   
#   Here we add a TIMEOUT value to the hotplug environment of the firmware
#   requesting event. I will adapt udevd not to wait for anything else, if
#   it finds a TIMEOUT key.
#   
#   Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/base/firmware_class.c
#   2005/03/16 18:22:37-08:00 kay.sievers@vrfy.org +3 -0
#   add TIMEOUT to firmware_class hotplug event
# 
# ChangeSet
#   2005/03/17 15:38:05-08:00 ecashin@coraid.com 
#   [PATCH] aoe 12/12: send outgoing packets in order
#   
#   I can't use list.h, since sk_buff doesn't have a list_head but instead
#   has two struct sk_buff pointers, and I want to avoid any extra memory
#   allocation.
#   
#   send outgoing packets in order
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoecmd.c
#   2005/03/10 09:20:04-08:00 ecashin@coraid.com +17 -9
#   aoe 12/12: send outgoing packets in order
# 
# drivers/block/aoe/aoeblk.c
#   2005/03/10 09:20:04-08:00 ecashin@coraid.com +2 -2
#   aoe 12/12: send outgoing packets in order
# 
# drivers/block/aoe/aoe.h
#   2005/03/10 09:20:04-08:00 ecashin@coraid.com +2 -1
#   aoe 12/12: send outgoing packets in order
# 
# ChangeSet
#   2005/03/17 15:24:31-08:00 ecashin@coraid.com 
#   [PATCH] aoe 11/12: add support for disk statistics
#   
#   add support for disk statistics
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoecmd.c
#   2005/03/10 09:20:02-08:00 ecashin@coraid.com +14 -0
#   aoe 11/12: add support for disk statistics
# 
# drivers/block/aoe/aoeblk.c
#   2005/03/10 09:20:02-08:00 ecashin@coraid.com +1 -0
#   aoe 11/12: add support for disk statistics
# 
# drivers/block/aoe/aoe.h
#   2005/03/10 09:20:02-08:00 ecashin@coraid.com +1 -0
#   aoe 11/12: add support for disk statistics
# 
# ChangeSet
#   2005/03/17 15:24:12-08:00 ecashin@coraid.com 
#   [PATCH] aoe 9/12: add note about the need for
#   
#   add note about the need for deadlock-free sk_buff allocation
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/aoe/todo.txt
#   2005/03/10 09:19:57-08:00 ecashin@coraid.com +14 -0
#   aoe 9/12: add note about the need for
# 
# Documentation/aoe/todo.txt
#   2005/03/10 09:19:57-08:00 ecashin@coraid.com +0 -0
#   BitKeeper file /home/greg/linux/BK/driver-2.6/Documentation/aoe/todo.txt
# 
# ChangeSet
#   2005/03/17 15:23:51-08:00 ecashin@coraid.com 
#   [PATCH] aoe 8/12: document env var for specifying number
#   
#   document env var for specifying number of partitions per dev
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/aoe/mkshelf.sh
#   2005/03/10 09:19:56-08:00 ecashin@coraid.com +1 -0
#   aoe 8/12: document env var for specifying number
# 
# Documentation/aoe/mkdevs.sh
#   2005/03/10 09:19:56-08:00 ecashin@coraid.com +1 -0
#   aoe 8/12: document env var for specifying number
# 
# ChangeSet
#   2005/03/17 15:23:25-08:00 ecashin@coraid.com 
#   [PATCH] aoe 7/12: support configuration of AOE_PARTITIONS
#   
#   support configuration of AOE_PARTITIONS from Kconfig
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoe.h
#   2005/03/10 09:19:54-08:00 ecashin@coraid.com +3 -2
#   aoe 7/12: support configuration of AOE_PARTITIONS
# 
# drivers/block/Kconfig
#   2005/03/10 09:19:54-08:00 ecashin@coraid.com +15 -0
#   aoe 7/12: support configuration of AOE_PARTITIONS
# 
# ChangeSet
#   2005/03/17 15:23:00-08:00 ecashin@coraid.com 
#   [PATCH] aoe 6/12: Alexey Dobriyan sparse cleanup
#   
#   Alexey Dobriyan sparse cleanup
#   
#   Signed-off-by: Alexey Dobriyan <adobriyan@mail.ru>
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoenet.c
#   2005/03/10 09:19:27-08:00 ecashin@coraid.com +4 -4
#   aoe 6/12: Alexey Dobriyan sparse cleanup
# 
# drivers/block/aoe/aoecmd.c
#   2005/03/10 09:19:27-08:00 ecashin@coraid.com +23 -29
#   aoe 6/12: Alexey Dobriyan sparse cleanup
# 
# drivers/block/aoe/aoe.h
#   2005/03/10 09:19:27-08:00 ecashin@coraid.com +5 -5
#   aoe 6/12: Alexey Dobriyan sparse cleanup
# 
# ChangeSet
#   2005/03/17 15:21:48-08:00 ecashin@coraid.com 
#   [PATCH] aoe 5/12: don't try to free null bufpool
#   
#   don't try to free null bufpool
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoedev.c
#   2005/03/10 09:19:25-08:00 ecashin@coraid.com +2 -1
#   aoe 5/12: don't try to free null bufpool
# 
# ChangeSet
#   2005/03/17 15:21:30-08:00 ecashin@coraid.com 
#   [PATCH] aoe 4/12: handle distros that have a udev rules
#   
#   handle distros that have a udev rules file instead of dir
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/aoe/udev-install.sh
#   2005/03/10 09:19:18-08:00 ecashin@coraid.com +5 -1
#   aoe 4/12: handle distros that have a udev rules
# 
# ChangeSet
#   2005/03/17 15:21:12-08:00 ecashin@coraid.com 
#   [PATCH] aoe 3/12: update driver version to 6
#   
#   update driver version to 6
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoe.h
#   2005/03/10 09:19:14-08:00 ecashin@coraid.com +1 -1
#   aoe 3/12: update driver version to 6
# 
# ChangeSet
#   2005/03/17 15:20:51-08:00 ecashin@coraid.com 
#   [PATCH] aoe 2/12: allow multiple aoe devices with same MAC
#   
#   allow multiple aoe devices with same MAC addr
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoedev.c
#   2005/03/10 09:19:11-08:00 ecashin@coraid.com +2 -3
#   aoe 2/12: allow multiple aoe devices with same MAC
# 
# drivers/block/aoe/aoecmd.c
#   2005/03/10 09:19:11-08:00 ecashin@coraid.com +5 -4
#   aoe 2/12: allow multiple aoe devices with same MAC
# 
# drivers/block/aoe/aoe.h
#   2005/03/10 09:19:11-08:00 ecashin@coraid.com +1 -1
#   aoe 2/12: allow multiple aoe devices with same MAC
# 
# ChangeSet
#   2005/03/17 15:20:32-08:00 ecashin@coraid.com 
#   [PATCH] aoe 1/12: remove too-low cap on minor number
#   
#   remove too-low cap on minor number
#   
#   Signed-off-by: Ed L. Cashin <ecashin@coraid.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/block/aoe/aoecmd.c
#   2005/03/10 09:19:04-08:00 ecashin@coraid.com +5 -4
#   aoe 1/12: remove too-low cap on minor number
# 
# drivers/block/aoe/aoe.h
#   2005/03/10 09:19:04-08:00 ecashin@coraid.com +5 -0
#   aoe 1/12: remove too-low cap on minor number
# 
# ChangeSet
#   2005/03/16 23:22:27-08:00 gregkh@suse.de 
#   [PATCH] kref: add link to original documentation to the kref documentation.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/kref.txt
#   2005/03/16 23:21:28-08:00 gregkh@suse.de +6 -1
#   kref: add link to original documentation to the kref documentation.
# 
# ChangeSet
#   2005/03/16 23:22:04-08:00 minyard@acm.org 
#   [PATCH] kref: add documentation
#   
#   Add some documentation for krefs.
#   
#   Signed-off-by: Corey Minyard <minyard@acm.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/kref.txt
#   2005/03/16 16:00:00-08:00 minyard@acm.org +211 -0
#   kref: add documentation
# 
# Documentation/kref.txt
#   2005/03/16 16:00:00-08:00 minyard@acm.org +0 -0
#   BitKeeper file /home/greg/linux/BK/driver-2.6/Documentation/kref.txt
# 
# ChangeSet
#   2005/03/15 15:10:13-08:00 gregkh@suse.de 
#   [PATCH] USB: move the usb hcd code to use the new class code.
#   
#   This moves a kref into the main hcd structure, which detaches it from
#   the class device structure.
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/usb.h
#   2005/03/15 14:44:25-08:00 gregkh@suse.de +2 -3
#   USB: move the usb hcd code to use the new class code.
# 
# drivers/usb/host/ohci-dbg.c
#   2005/03/15 14:44:25-08:00 gregkh@suse.de +5 -5
#   USB: move the usb hcd code to use the new class code.
# 
# drivers/usb/host/ehci-dbg.c
#   2005/03/15 14:44:25-08:00 gregkh@suse.de +5 -5
#   USB: move the usb hcd code to use the new class code.
# 
# drivers/usb/core/hcd.c
#   2005/03/15 14:50:06-08:00 gregkh@suse.de +27 -34
#   USB: move the usb hcd code to use the new class code.
# 
# ChangeSet
#   2005/03/15 14:26:30-08:00 gregkh@suse.de 
#   [PATCH] INPUT: move to use the new class code, instead of class_simple
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/input.h
#   2005/03/15 08:54:28-08:00 gregkh@suse.de +1 -1
#   INPUT: move to use the new class code, instead of class_simple
# 
# drivers/input/tsdev.c
#   2005/03/15 08:54:28-08:00 gregkh@suse.de +5 -4
#   INPUT: move to use the new class code, instead of class_simple
# 
# drivers/input/mousedev.c
#   2005/03/15 08:54:28-08:00 gregkh@suse.de +9 -7
#   INPUT: move to use the new class code, instead of class_simple
# 
# drivers/input/joydev.c
#   2005/03/15 08:54:28-08:00 gregkh@suse.de +4 -4
#   INPUT: move to use the new class code, instead of class_simple
# 
# drivers/input/input.c
#   2005/03/15 08:54:28-08:00 gregkh@suse.de +5 -5
#   INPUT: move to use the new class code, instead of class_simple
# 
# drivers/input/evdev.c
#   2005/03/15 08:54:28-08:00 gregkh@suse.de +5 -4
#   INPUT: move to use the new class code, instead of class_simple
# 
# ChangeSet
#   2005/03/15 14:23:15-08:00 gregkh@suse.de 
#   [PATCH] tty: move to use the new class code, instead of class_simple
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/char/tty_io.c
#   2005/03/15 08:54:22-08:00 gregkh@suse.de +8 -8
#   tty: move to use the new class code, instead of class_simple
# 
# ChangeSet
#   2005/03/15 11:54:21-08:00 gregkh@suse.de 
#   [PATCH] CLASS: move a "simple" class logic into the class core.
#   
#   One step on improving the class api so that it can not be used incorrectly.
#   This also fixes the module owner issue with the dev files that happened when
#   the devt logic moved to the class core.
#   
#   Based on a patch originally written by Kay Sievers <kay.sievers@vrfy.org>
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/device.h
#   2005/03/15 08:52:00-08:00 gregkh@suse.de +8 -0
#   CLASS: move a "simple" class logic into the class core.
# 
# drivers/base/class.c
#   2005/03/15 08:52:00-08:00 gregkh@suse.de +133 -10
#   CLASS: move a "simple" class logic into the class core.
# 
diff -Nru a/Documentation/aoe/mkdevs.sh b/Documentation/aoe/mkdevs.sh
--- a/Documentation/aoe/mkdevs.sh	2005-03-30 17:18:11 -08:00
+++ b/Documentation/aoe/mkdevs.sh	2005-03-30 17:18:11 -08:00
@@ -5,6 +5,7 @@
 
 if test "$#" != "1"; then
 	echo "Usage: sh `basename $0` {dir}" 1>&2
+	echo "       n_partitions=16 sh `basename $0` {dir}" 1>&2
 	exit 1
 fi
 dir=$1
diff -Nru a/Documentation/aoe/mkshelf.sh b/Documentation/aoe/mkshelf.sh
--- a/Documentation/aoe/mkshelf.sh	2005-03-30 17:18:12 -08:00
+++ b/Documentation/aoe/mkshelf.sh	2005-03-30 17:18:12 -08:00
@@ -2,6 +2,7 @@
 
 if test "$#" != "2"; then
 	echo "Usage: sh `basename $0` {dir} {shelfaddress}" 1>&2
+	echo "       n_partitions=16 sh `basename $0` {dir} {shelfaddress}" 1>&2
 	exit 1
 fi
 n_partitions=${n_partitions:-16}
diff -Nru a/Documentation/aoe/todo.txt b/Documentation/aoe/todo.txt
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/aoe/todo.txt	2005-03-30 17:18:12 -08:00
@@ -0,0 +1,14 @@
+There is a potential for deadlock when allocating a struct sk_buff for
+data that needs to be written out to aoe storage.  If the data is
+being written from a dirty page in order to free that page, and if
+there are no other pages available, then deadlock may occur when a
+free page is needed for the sk_buff allocation.  This situation has
+not been observed, but it would be nice to eliminate any potential for
+deadlock under memory pressure.
+
+Because ATA over Ethernet is not fragmented by the kernel's IP code,
+the destructore member of the struct sk_buff is available to the aoe
+driver.  By using a mempool for allocating all but the first few
+sk_buffs, and by registering a destructor, we should be able to
+efficiently allocate sk_buffs without introducing any potential for
+deadlock.
diff -Nru a/Documentation/aoe/udev-install.sh b/Documentation/aoe/udev-install.sh
--- a/Documentation/aoe/udev-install.sh	2005-03-30 17:18:12 -08:00
+++ b/Documentation/aoe/udev-install.sh	2005-03-30 17:18:12 -08:00
@@ -23,4 +23,8 @@
 # /etc/udev/rules.d
 #
 rules_d="`sed -n '/^udev_rules=/{ s!udev_rules=!!; s!\"!!g; p; }' $conf`"
-test "$rules_d" && sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules"
+if test -z "$rules_d" || test ! -d "$rules_d"; then
+	echo "$me Error: cannot find udev rules directory" 1>&2
+	exit 1
+fi
+sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules"
diff -Nru a/Documentation/kref.txt b/Documentation/kref.txt
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/kref.txt	2005-03-30 17:18:12 -08:00
@@ -0,0 +1,216 @@
+
+krefs allow you to add reference counters to your objects.  If you
+have objects that are used in multiple places and passed around, and
+you don't have refcounts, your code is almost certainly broken.  If
+you want refcounts, krefs are the way to go.
+
+To use a kref, add one to your data structures like:
+
+struct my_data
+{
+	.
+	.
+	struct kref refcount;
+	.
+	.
+};
+
+The kref can occur anywhere within the data structure.
+
+You must initialize the kref after you allocate it.  To do this, call
+kref_init as so:
+
+     struct my_data *data;
+
+     data = kmalloc(sizeof(*data), GFP_KERNEL);
+     if (!data)
+            return -ENOMEM;
+     kref_init(&data->refcount);
+
+This sets the refcount in the kref to 1.
+
+Once you have an initialized kref, you must follow the following
+rules:
+
+1) If you make a non-temporary copy of a pointer, especially if
+   it can be passed to another thread of execution, you must
+   increment the refcount with kref_get() before passing it off:
+       kref_get(&data->refcount);
+   If you already have a valid pointer to a kref-ed structure (the
+   refcount cannot go to zero) you may do this without a lock.
+
+2) When you are done with a pointer, you must call kref_put():
+       kref_put(&data->refcount, data_release);
+   If this is the last reference to the pointer, the release
+   routine will be called.  If the code never tries to get
+   a valid pointer to a kref-ed structure without already
+   holding a valid pointer, it is safe to do this without
+   a lock.
+
+3) If the code attempts to gain a reference to a kref-ed structure
+   without already holding a valid pointer, it must serialize access
+   where a kref_put() cannot occur during the kref_get(), and the
+   structure must remain valid during the kref_get().
+
+For example, if you allocate some data and then pass it to another
+thread to process:
+
+void data_release(struct kref *ref)
+{
+	struct my_data *data = container_of(ref, struct my_data, refcount);
+	kfree(data);
+}
+
+void more_data_handling(void *cb_data)
+{
+	struct my_data *data = cb_data;
+	.
+	. do stuff with data here
+	.
+	kref_put(data, data_release);
+}
+
+int my_data_handler(void)
+{
+	int rv = 0;
+	struct my_data *data;
+	struct task_struct *task;
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	kref_init(&data->refcount);
+
+	kref_get(&data->refcount);
+	task = kthread_run(more_data_handling, data, "more_data_handling");
+	if (task == ERR_PTR(-ENOMEM)) {
+		rv = -ENOMEM;
+	        kref_put(&data->refcount, data_release);
+		goto out;
+	}
+
+	.
+	. do stuff with data here
+	.
+ out:
+	kref_put(&data->refcount, data_release);
+	return rv;
+}
+
+This way, it doesn't matter what order the two threads handle the
+data, the kref_put() handles knowing when the data is not referenced
+any more and releasing it.  The kref_get() does not require a lock,
+since we already have a valid pointer that we own a refcount for.  The
+put needs no lock because nothing tries to get the data without
+already holding a pointer.
+
+Note that the "before" in rule 1 is very important.  You should never
+do something like:
+
+	task = kthread_run(more_data_handling, data, "more_data_handling");
+	if (task == ERR_PTR(-ENOMEM)) {
+		rv = -ENOMEM;
+		goto out;
+	} else
+		/* BAD BAD BAD - get is after the handoff */
+		kref_get(&data->refcount);
+
+Don't assume you know what you are doing and use the above construct.
+First of all, you may not know what you are doing.  Second, you may
+know what you are doing (there are some situations where locking is
+involved where the above may be legal) but someone else who doesn't
+know what they are doing may change the code or copy the code.  It's
+bad style.  Don't do it.
+
+There are some situations where you can optimize the gets and puts.
+For instance, if you are done with an object and enqueuing it for
+something else or passing it off to something else, there is no reason
+to do a get then a put:
+
+	/* Silly extra get and put */
+	kref_get(&obj->ref);
+	enqueue(obj);
+	kref_put(&obj->ref, obj_cleanup);
+
+Just do the enqueue.  A comment about this is always welcome:
+
+	enqueue(obj);
+	/* We are done with obj, so we pass our refcount off
+	   to the queue.  DON'T TOUCH obj AFTER HERE! */
+
+The last rule (rule 3) is the nastiest one to handle.  Say, for
+instance, you have a list of items that are each kref-ed, and you wish
+to get the first one.  You can't just pull the first item off the list
+and kref_get() it.  That violates rule 3 because you are not already
+holding a valid pointer.  You must add locks or semaphores.  For
+instance:
+
+static DECLARE_MUTEX(sem);
+static LIST_HEAD(q);
+struct my_data
+{
+	struct kref      refcount;
+	struct list_head link;
+};
+
+static struct my_data *get_entry()
+{
+	struct my_data *entry = NULL;
+	down(&sem);
+	if (!list_empty(&q)) {
+		entry = container_of(q.next, struct my_q_entry, link);
+		kref_get(&entry->refcount);
+	}
+	up(&sem);
+	return entry;
+}
+
+static void release_entry(struct kref *ref)
+{
+	struct my_data *entry = container_of(ref, struct my_data, refcount);
+
+	list_del(&entry->link);
+	kfree(entry);
+}
+
+static void put_entry(struct my_data *entry)
+{
+	down(&sem);
+	kref_put(&entry->refcount, release_entry);
+	up(&sem);
+}
+
+The kref_put() return value is useful if you do not want to hold the
+lock during the whole release operation.  Say you didn't want to call
+kfree() with the lock held in the example above (since it is kind of
+pointless to do so).  You could use kref_put() as follows:
+
+static void release_entry(struct kref *ref)
+{
+	/* All work is done after the return from kref_put(). */
+}
+
+static void put_entry(struct my_data *entry)
+{
+	down(&sem);
+	if (kref_put(&entry->refcount, release_entry)) {
+		list_del(&entry->link);
+		up(&sem);
+		kfree(entry);
+	} else
+		up(&sem);
+}
+
+This is really more useful if you have to call other routines as part
+of the free operations that could take a long time or might claim the
+same lock.  Note that doing everything in the release routine is still
+preferred as it is a little neater.
+
+
+Corey Minyard <minyard@acm.org>
+
+A lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and
+presentation on krefs, which can be found at:
+  http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf
+and:
+  http://www.kroah.com/linux/talks/ols_2004_kref_talk/
+
diff -Nru a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
--- a/arch/i386/kernel/cpuid.c	2005-03-30 17:18:12 -08:00
+++ b/arch/i386/kernel/cpuid.c	2005-03-30 17:18:12 -08:00
@@ -45,7 +45,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-static struct class_simple *cpuid_class;
+static struct class *cpuid_class;
 
 #ifdef CONFIG_SMP
 
@@ -158,12 +158,12 @@
 	.open = cpuid_open,
 };
 
-static int cpuid_class_simple_device_add(int i) 
+static int cpuid_class_device_create(int i) 
 {
 	int err = 0;
 	struct class_device *class_err;
 
-	class_err = class_simple_device_add(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i);
+	class_err = class_device_create(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i);
 	if (IS_ERR(class_err))
 		err = PTR_ERR(class_err);
 	return err;
@@ -175,10 +175,10 @@
 
 	switch (action) {
 	case CPU_ONLINE:
-		cpuid_class_simple_device_add(cpu);
+		cpuid_class_device_create(cpu);
 		break;
 	case CPU_DEAD:
-		class_simple_device_remove(MKDEV(CPUID_MAJOR, cpu));
+		class_device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
 		break;
 	}
 	return NOTIFY_OK;
@@ -200,13 +200,13 @@
 		err = -EBUSY;
 		goto out;
 	}
-	cpuid_class = class_simple_create(THIS_MODULE, "cpuid");
+	cpuid_class = class_create(THIS_MODULE, "cpuid");
 	if (IS_ERR(cpuid_class)) {
 		err = PTR_ERR(cpuid_class);
 		goto out_chrdev;
 	}
 	for_each_online_cpu(i) {
-		err = cpuid_class_simple_device_add(i);
+		err = cpuid_class_device_create(i);
 		if (err != 0) 
 			goto out_class;
 	}
@@ -218,9 +218,9 @@
 out_class:
 	i = 0;
 	for_each_online_cpu(i) {
-		class_simple_device_remove(MKDEV(CPUID_MAJOR, i));
+		class_device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, i));
 	}
-	class_simple_destroy(cpuid_class);
+	class_destroy(cpuid_class);
 out_chrdev:
 	unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");	
 out:
@@ -232,8 +232,8 @@
 	int cpu = 0;
 
 	for_each_online_cpu(cpu)
-		class_simple_device_remove(MKDEV(CPUID_MAJOR, cpu));
-	class_simple_destroy(cpuid_class);
+		class_device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
+	class_destroy(cpuid_class);
 	unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
 	unregister_cpu_notifier(&cpuid_class_cpu_notifier);
 }
diff -Nru a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
--- a/arch/i386/kernel/msr.c	2005-03-30 17:18:12 -08:00
+++ b/arch/i386/kernel/msr.c	2005-03-30 17:18:12 -08:00
@@ -44,7 +44,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-static struct class_simple *msr_class;
+static struct class *msr_class;
 
 /* Note: "err" is handled in a funny way below.  Otherwise one version
    of gcc or another breaks. */
@@ -260,12 +260,12 @@
 	.open = msr_open,
 };
 
-static int msr_class_simple_device_add(int i)
+static int msr_class_device_create(int i)
 {
 	int err = 0;
 	struct class_device *class_err;
 
-	class_err = class_simple_device_add(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i);
+	class_err = class_device_create(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i);
 	if (IS_ERR(class_err)) 
 		err = PTR_ERR(class_err);
 	return err;
@@ -277,10 +277,10 @@
 
 	switch (action) {
 	case CPU_ONLINE:
-		msr_class_simple_device_add(cpu);
+		msr_class_device_create(cpu);
 		break;
 	case CPU_DEAD:
-		class_simple_device_remove(MKDEV(MSR_MAJOR, cpu));	
+		class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));	
 		break;
 	}
 	return NOTIFY_OK;
@@ -302,13 +302,13 @@
 		err = -EBUSY;
 		goto out;
 	}
-	msr_class = class_simple_create(THIS_MODULE, "msr");
+	msr_class = class_create(THIS_MODULE, "msr");
 	if (IS_ERR(msr_class)) {
 		err = PTR_ERR(msr_class);
 		goto out_chrdev;
 	}
 	for_each_online_cpu(i) {
-		err = msr_class_simple_device_add(i);
+		err = msr_class_device_create(i);
 		if (err != 0)
 			goto out_class;
 	}
@@ -320,8 +320,8 @@
 out_class:
 	i = 0;
 	for_each_online_cpu(i)
-		class_simple_device_remove(MKDEV(MSR_MAJOR, i));
-	class_simple_destroy(msr_class);
+		class_device_destroy(msr_class, MKDEV(MSR_MAJOR, i));
+	class_destroy(msr_class);
 out_chrdev:
 	unregister_chrdev(MSR_MAJOR, "cpu/msr");
 out:
@@ -332,8 +332,8 @@
 {
 	int cpu = 0;
 	for_each_online_cpu(cpu)
-		class_simple_device_remove(MKDEV(MSR_MAJOR, cpu));
-	class_simple_destroy(msr_class);
+		class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
+	class_destroy(msr_class);
 	unregister_chrdev(MSR_MAJOR, "cpu/msr");
 	unregister_cpu_notifier(&msr_class_cpu_notifier);
 }
diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile	2005-03-30 17:18:12 -08:00
+++ b/drivers/base/Makefile	2005-03-30 17:18:12 -08:00
@@ -1,7 +1,7 @@
 # Makefile for the Linux device tree
 
-obj-y			:= core.o sys.o interface.o bus.o \
-			   driver.o class.o class_simple.o platform.o \
+obj-y			:= core.o sys.o interface.o bus.o dd.o \
+			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o map.o dmapool.o \
 			   attribute_container.o transport_class.o
 obj-y			+= power/
diff -Nru a/drivers/base/base.h b/drivers/base/base.h
--- a/drivers/base/base.h	2005-03-30 17:18:12 -08:00
+++ b/drivers/base/base.h	2005-03-30 17:18:12 -08:00
@@ -4,6 +4,8 @@
 extern int bus_add_driver(struct device_driver *);
 extern void bus_remove_driver(struct device_driver *);
 
+extern void driver_detach(struct device_driver * drv);
+
 static inline struct class_device *to_class_dev(struct kobject *obj)
 {
 	return container_of(obj, struct class_device, kobj);
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/base/bus.c	2005-03-30 17:18:11 -08:00
@@ -17,9 +17,6 @@
 #include "base.h"
 #include "power/power.h"
 
-#define to_dev(node) container_of(node, struct device, bus_list)
-#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
-
 #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
 #define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj)
 
@@ -135,50 +132,11 @@
 
 decl_subsys(bus, &ktype_bus, NULL);
 
-static int __bus_for_each_dev(struct bus_type *bus, struct device *start,
-			      void *data, int (*fn)(struct device *, void *))
-{
-	struct list_head *head;
-	struct device *dev;
-	int error = 0;
 
-	if (!(bus = get_bus(bus)))
-		return -EINVAL;
-
-	head = &bus->devices.list;
-	dev = list_prepare_entry(start, head, bus_list);
-	list_for_each_entry_continue(dev, head, bus_list) {
-		get_device(dev);
-		error = fn(dev, data);
-		put_device(dev);
-		if (error)
-			break;
-	}
-	put_bus(bus);
-	return error;
-}
-
-static int __bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
-			      void * data, int (*fn)(struct device_driver *, void *))
+static struct device * next_device(struct klist_iter * i)
 {
-	struct list_head *head;
-	struct device_driver *drv;
-	int error = 0;
-
-	if (!(bus = get_bus(bus)))
-		return -EINVAL;
-
-	head = &bus->drivers.list;
-	drv = list_prepare_entry(start, head, kobj.entry);
-	list_for_each_entry_continue(drv, head, kobj.entry) {
-		get_driver(drv);
-		error = fn(drv, data);
-		put_driver(drv);
-		if (error)
-			break;
-	}
-	put_bus(bus);
-	return error;
+	struct klist_node * n = klist_next(i);
+	return n ? container_of(n, struct device, knode_bus) : NULL;
 }
 
 /**
@@ -204,12 +162,27 @@
 int bus_for_each_dev(struct bus_type * bus, struct device * start,
 		     void * data, int (*fn)(struct device *, void *))
 {
-	int ret;
+	struct klist_iter i;
+	struct device * dev;
+	int error = 0;
 
-	down_read(&bus->subsys.rwsem);
-	ret = __bus_for_each_dev(bus, start, data, fn);
-	up_read(&bus->subsys.rwsem);
-	return ret;
+	if (!bus)
+		return -EINVAL;
+
+	klist_iter_init_node(&bus->klist_devices, &i, 
+			     (start ? &start->knode_bus : NULL));
+	while ((dev = next_device(&i)) && !error)
+		error = fn(dev, data);
+	klist_iter_exit(&i);
+	return error;
+}
+
+
+
+static struct device_driver * next_driver(struct klist_iter * i)
+{
+	struct klist_node * n = klist_next(i);
+	return n ? container_of(n, struct device_driver, knode_bus) : NULL;
 }
 
 /**
@@ -235,183 +208,22 @@
 int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
 		     void * data, int (*fn)(struct device_driver *, void *))
 {
-	int ret;
-
-	down_read(&bus->subsys.rwsem);
-	ret = __bus_for_each_drv(bus, start, data, fn);
-	up_read(&bus->subsys.rwsem);
-	return ret;
-}
-
-/**
- *	device_bind_driver - bind a driver to one device.
- *	@dev:	device.
- *
- *	Allow manual attachment of a driver to a device.
- *	Caller must have already set @dev->driver.
- *
- *	Note that this does not modify the bus reference count
- *	nor take the bus's rwsem. Please verify those are accounted
- *	for before calling this. (It is ok to call with no other effort
- *	from a driver's probe() method.)
- */
-
-void device_bind_driver(struct device * dev)
-{
-	pr_debug("bound device '%s' to driver '%s'\n",
-		 dev->bus_id, dev->driver->name);
-	list_add_tail(&dev->driver_list, &dev->driver->devices);
-	sysfs_create_link(&dev->driver->kobj, &dev->kobj,
-			  kobject_name(&dev->kobj));
-	sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
-}
-
-
-/**
- *	driver_probe_device - attempt to bind device & driver.
- *	@drv:	driver.
- *	@dev:	device.
- *
- *	First, we call the bus's match function, if one present, which
- *	should compare the device IDs the driver supports with the
- *	device IDs of the device. Note we don't do this ourselves
- *	because we don't know the format of the ID structures, nor what
- *	is to be considered a match and what is not.
- *
- *	If we find a match, we call @drv->probe(@dev) if it exists, and
- *	call device_bind_driver() above.
- */
-int driver_probe_device(struct device_driver * drv, struct device * dev)
-{
-	if (drv->bus->match && !drv->bus->match(dev, drv))
-		return -ENODEV;
-
-	dev->driver = drv;
-	if (drv->probe) {
-		int error = drv->probe(dev);
-		if (error) {
-			dev->driver = NULL;
-			return error;
-		}
-	}
-
-	device_bind_driver(dev);
-	return 0;
-}
-
-
-/**
- *	device_attach - try to attach device to a driver.
- *	@dev:	device.
- *
- *	Walk the list of drivers that the bus has and call
- *	driver_probe_device() for each pair. If a compatible
- *	pair is found, break out and return.
- */
-int device_attach(struct device * dev)
-{
- 	struct bus_type * bus = dev->bus;
-	struct list_head * entry;
-	int error;
-
-	if (dev->driver) {
-		device_bind_driver(dev);
-		return 1;
-	}
-
-	if (bus->match) {
-		list_for_each(entry, &bus->drivers.list) {
-			struct device_driver * drv = to_drv(entry);
-			error = driver_probe_device(drv, dev);
-			if (!error)
-				/* success, driver matched */
-				return 1;
-			if (error != -ENODEV && error != -ENXIO)
-				/* driver matched but the probe failed */
-				printk(KERN_WARNING
-				    "%s: probe of %s failed with error %d\n",
-				    drv->name, dev->bus_id, error);
-		}
-	}
-
-	return 0;
-}
-
-
-/**
- *	driver_attach - try to bind driver to devices.
- *	@drv:	driver.
- *
- *	Walk the list of devices that the bus has on it and try to
- *	match the driver with each one.  If driver_probe_device()
- *	returns 0 and the @dev->driver is set, we've found a
- *	compatible pair.
- *
- *	Note that we ignore the -ENODEV error from driver_probe_device(),
- *	since it's perfectly valid for a driver not to bind to any devices.
- */
-void driver_attach(struct device_driver * drv)
-{
-	struct bus_type * bus = drv->bus;
-	struct list_head * entry;
-	int error;
-
-	if (!bus->match)
-		return;
-
-	list_for_each(entry, &bus->devices.list) {
-		struct device * dev = container_of(entry, struct device, bus_list);
-		if (!dev->driver) {
-			error = driver_probe_device(drv, dev);
-			if (error && (error != -ENODEV))
-				/* driver matched but the probe failed */
-				printk(KERN_WARNING
-				    "%s: probe of %s failed with error %d\n",
-				    drv->name, dev->bus_id, error);
-		}
-	}
-}
-
+	struct klist_iter i;
+	struct device_driver * drv;
+	int error = 0;
 
-/**
- *	device_release_driver - manually detach device from driver.
- *	@dev:	device.
- *
- *	Manually detach device from driver.
- *	Note that this is called without incrementing the bus
- *	reference count nor taking the bus's rwsem. Be sure that
- *	those are accounted for before calling this function.
- */
+	if (!bus)
+		return -EINVAL;
 
-void device_release_driver(struct device * dev)
-{
-	struct device_driver * drv = dev->driver;
-	if (drv) {
-		sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
-		sysfs_remove_link(&dev->kobj, "driver");
-		list_del_init(&dev->driver_list);
-		device_detach_shutdown(dev);
-		if (drv->remove)
-			drv->remove(dev);
-		dev->driver = NULL;
-	}
+	klist_iter_init_node(&bus->klist_drivers, &i, 
+			     start ? &start->knode_bus : NULL);
+	while ((drv = next_driver(&i)) && !error)
+		error = fn(drv, data);
+	klist_iter_exit(&i);
+	return error;
 }
 
 
-/**
- *	driver_detach - detach driver from all devices it controls.
- *	@drv:	driver.
- */
-
-static void driver_detach(struct device_driver * drv)
-{
-	struct list_head * entry, * next;
-	list_for_each_safe(entry, next, &drv->devices) {
-		struct device * dev = container_of(entry, struct device, driver_list);
-		device_release_driver(dev);
-	}
-}
-
 static int device_add_attrs(struct bus_type * bus, struct device * dev)
 {
 	int error = 0;
@@ -458,11 +270,9 @@
 	int error = 0;
 
 	if (bus) {
-		down_write(&dev->bus->subsys.rwsem);
 		pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
-		list_add_tail(&dev->bus_list, &dev->bus->devices.list);
 		device_attach(dev);
-		up_write(&dev->bus->subsys.rwsem);
+		klist_add_tail(&bus->klist_devices, &dev->knode_bus);
 		device_add_attrs(bus, dev);
 		sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
 		sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
@@ -485,11 +295,9 @@
 		sysfs_remove_link(&dev->kobj, "bus");
 		sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
 		device_remove_attrs(dev->bus, dev);
-		down_write(&dev->bus->subsys.rwsem);
+		klist_remove(&dev->knode_bus);
 		pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
 		device_release_driver(dev);
-		list_del_init(&dev->bus_list);
-		up_write(&dev->bus->subsys.rwsem);
 		put_bus(dev->bus);
 	}
 }
@@ -549,9 +357,8 @@
 			return error;
 		}
 
-		down_write(&bus->subsys.rwsem);
 		driver_attach(drv);
-		up_write(&bus->subsys.rwsem);
+		klist_add_tail(&bus->klist_drivers, &drv->knode_bus);
 		module_add_driver(drv->owner, drv);
 
 		driver_add_attrs(bus, drv);
@@ -573,10 +380,9 @@
 {
 	if (drv->bus) {
 		driver_remove_attrs(drv->bus, drv);
-		down_write(&drv->bus->subsys.rwsem);
+		klist_remove(&drv->knode_bus);
 		pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
 		driver_detach(drv);
-		up_write(&drv->bus->subsys.rwsem);
 		module_remove_driver(drv);
 		kobject_unregister(&drv->kobj);
 		put_bus(drv->bus);
@@ -609,9 +415,7 @@
 {
 	int count = 0;
 
-	down_write(&bus->subsys.rwsem);
-	__bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper);
-	up_write(&bus->subsys.rwsem);
+	bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper);
 
 	return count;
 }
@@ -712,6 +516,9 @@
 	retval = kset_register(&bus->drivers);
 	if (retval)
 		goto bus_drivers_fail;
+
+	klist_init(&bus->klist_devices);
+	klist_init(&bus->klist_drivers);
 	bus_add_attrs(bus);
 
 	pr_debug("bus type '%s' registered\n", bus->name);
@@ -750,12 +557,6 @@
 
 EXPORT_SYMBOL_GPL(bus_for_each_dev);
 EXPORT_SYMBOL_GPL(bus_for_each_drv);
-
-EXPORT_SYMBOL_GPL(driver_probe_device);
-EXPORT_SYMBOL_GPL(device_bind_driver);
-EXPORT_SYMBOL_GPL(device_release_driver);
-EXPORT_SYMBOL_GPL(device_attach);
-EXPORT_SYMBOL_GPL(driver_attach);
 
 EXPORT_SYMBOL_GPL(bus_add_device);
 EXPORT_SYMBOL_GPL(bus_remove_device);
diff -Nru a/drivers/base/class.c b/drivers/base/class.c
--- a/drivers/base/class.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/base/class.c	2005-03-30 17:18:12 -08:00
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/kdev_t.h>
+#include <linux/err.h>
 #include "base.h"
 
 #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
@@ -162,6 +163,69 @@
 	subsystem_unregister(&cls->subsys);
 }
 
+static void class_create_release(struct class *cls)
+{
+	kfree(cls);
+}
+
+static void class_device_create_release(struct class_device *class_dev)
+{
+	kfree(class_dev);
+}
+
+/**
+ * class_create - create a struct class structure
+ * @owner: pointer to the module that is to "own" this struct class
+ * @name: pointer to a string for the name of this class.
+ *
+ * This is used to create a struct class pointer that can then be used
+ * in calls to class_device_create().
+ *
+ * Note, the pointer created here is to be destroyed when finished by
+ * making a call to class_destroy().
+ */
+struct class *class_create(struct module *owner, char *name)
+{
+	struct class *cls;
+	int retval;
+
+	cls = kmalloc(sizeof(struct class), GFP_KERNEL);
+	if (!cls) {
+		retval = -ENOMEM;
+		goto error;
+	}
+	memset(cls, 0x00, sizeof(struct class));
+
+	cls->name = name;
+	cls->owner = owner;
+	cls->class_release = class_create_release;
+	cls->release = class_device_create_release;
+
+	retval = class_register(cls);
+	if (retval)
+		goto error;
+
+	return cls;
+
+error:
+	kfree(cls);
+	return ERR_PTR(retval);
+}
+
+/**
+ * class_destroy - destroys a struct class structure
+ * @cs: pointer to the struct class that is to be destroyed
+ *
+ * Note, the pointer to be destroyed must have been created with a call
+ * to class_create().
+ */
+void class_destroy(struct class *cls)
+{
+	if ((cls == NULL) || (IS_ERR(cls)))
+		return;
+
+	class_unregister(cls);
+}
 
 /* Class Device Stuff */
 
@@ -375,7 +439,6 @@
 {
 	return print_dev_t(buf, class_dev->devt);
 }
-static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
 
 void class_device_initialize(struct class_device *class_dev)
 {
@@ -412,7 +475,31 @@
 	if ((error = kobject_add(&class_dev->kobj)))
 		goto register_done;
 
-	/* now take care of our own registration */
+	/* add the needed attributes to this device */
+	if (MAJOR(class_dev->devt)) {
+		struct class_device_attribute *attr;
+		attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+		if (!attr) {
+			error = -ENOMEM;
+			kobject_del(&class_dev->kobj);
+			goto register_done;
+		}
+		memset(attr, sizeof(*attr), 0x00);
+		attr->attr.name = "dev";
+		attr->attr.mode = S_IRUGO;
+		attr->attr.owner = parent->owner;
+		attr->show = show_dev;
+		attr->store = NULL;
+		class_device_create_file(class_dev, attr);
+		class_dev->devt_attr = attr;
+	}
+
+	class_device_add_attrs(class_dev);
+	if (class_dev->dev)
+		sysfs_create_link(&class_dev->kobj,
+				  &class_dev->dev->kobj, "device");
+
+	/* notify any interfaces this device is now here */
 	if (parent) {
 		down(&parent->sem);
 		list_add_tail(&class_dev->node, &parent->children);
@@ -422,14 +509,7 @@
 		up(&parent->sem);
 	}
 
-	if (MAJOR(class_dev->devt))
-		class_device_create_file(class_dev, &class_device_attr_dev);
-
-	class_device_add_attrs(class_dev);
-	if (class_dev->dev)
-		sysfs_create_link(&class_dev->kobj,
-				  &class_dev->dev->kobj, "device");
-
+	kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
  register_done:
 	if (error && parent)
 		class_put(parent);
@@ -443,6 +523,58 @@
 	return class_device_add(class_dev);
 }
 
+/**
+ * class_device_create - creates a class device and registers it with sysfs
+ * @cs: pointer to the struct class that this device should be registered to.
+ * @dev: the dev_t for the char device to be added.
+ * @device: a pointer to a struct device that is assiociated with this class device.
+ * @fmt: string for the class device's name
+ *
+ * This function can be used by char device classes.  A struct
+ * class_device will be created in sysfs, registered to the specified
+ * class.  A "dev" file will be created, showing the dev_t for the
+ * device.  The pointer to the struct class_device will be returned from
+ * the call.  Any further sysfs files that might be required can be
+ * created using this pointer.  
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
+struct class_device *class_device_create(struct class *cls, dev_t devt,
+					 struct device *device, char *fmt, ...)
+{
+	va_list args;
+	struct class_device *class_dev = NULL;
+	int retval = -ENODEV;
+
+	if (cls == NULL || IS_ERR(cls))
+		goto error;
+
+	class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
+	if (!class_dev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+	memset(class_dev, 0x00, sizeof(struct class_device));
+
+	class_dev->devt = devt;
+	class_dev->dev = device;
+	class_dev->class = cls;
+
+	va_start(args, fmt);
+	vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
+	va_end(args);
+	retval = class_device_register(class_dev);
+	if (retval)
+		goto error;
+
+	return class_dev;
+
+error:
+	kfree(class_dev);
+	return ERR_PTR(retval);
+}
+
 void class_device_del(struct class_device *class_dev)
 {
 	struct class * parent = class_dev->class;
@@ -459,8 +591,14 @@
 
 	if (class_dev->dev)
 		sysfs_remove_link(&class_dev->kobj, "device");
+	if (class_dev->devt_attr) {
+		class_device_remove_file(class_dev, class_dev->devt_attr);
+		kfree(class_dev->devt_attr);
+		class_dev->devt_attr = NULL;
+	}
 	class_device_remove_attrs(class_dev);
 
+	kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
 	kobject_del(&class_dev->kobj);
 
 	if (parent)
@@ -475,6 +613,32 @@
 	class_device_put(class_dev);
 }
 
+/**
+ * class_device_destroy - removes a class device that was created with class_device_create()
+ * @cls: the pointer to the struct class that this device was registered * with.
+ * @dev: the dev_t of the device that was previously registered.
+ *
+ * This call unregisters and cleans up a class device that was created with a
+ * call to class_device_create()
+ */
+void class_device_destroy(struct class *cls, dev_t devt)
+{
+	struct class_device *class_dev = NULL;
+	struct class_device *class_dev_tmp;
+
+	down(&cls->sem);
+	list_for_each_entry(class_dev_tmp, &cls->children, node) {
+		if (class_dev_tmp->devt == devt) {
+			class_dev = class_dev_tmp;
+			break;
+		}
+	}
+	up(&cls->sem);
+
+	if (class_dev)
+		class_device_unregister(class_dev);
+}
+
 int class_device_rename(struct class_device *class_dev, char *new_name)
 {
 	int error = 0;
@@ -574,6 +738,8 @@
 EXPORT_SYMBOL_GPL(class_unregister);
 EXPORT_SYMBOL_GPL(class_get);
 EXPORT_SYMBOL_GPL(class_put);
+EXPORT_SYMBOL_GPL(class_create);
+EXPORT_SYMBOL_GPL(class_destroy);
 
 EXPORT_SYMBOL_GPL(class_device_register);
 EXPORT_SYMBOL_GPL(class_device_unregister);
@@ -582,6 +748,8 @@
 EXPORT_SYMBOL_GPL(class_device_del);
 EXPORT_SYMBOL_GPL(class_device_get);
 EXPORT_SYMBOL_GPL(class_device_put);
+EXPORT_SYMBOL_GPL(class_device_create);
+EXPORT_SYMBOL_GPL(class_device_destroy);
 EXPORT_SYMBOL_GPL(class_device_create_file);
 EXPORT_SYMBOL_GPL(class_device_remove_file);
 EXPORT_SYMBOL_GPL(class_device_create_bin_file);
diff -Nru a/drivers/base/class_simple.c b/drivers/base/class_simple.c
--- a/drivers/base/class_simple.c	2005-03-30 17:18:12 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,199 +0,0 @@
-/*
- * class_simple.c - a "simple" interface for classes for simple char devices.
- *
- * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (c) 2003-2004 IBM Corp.
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/config.h>
-#include <linux/device.h>
-#include <linux/err.h>
-
-struct class_simple {
-	struct class class;
-};
-#define to_class_simple(d) container_of(d, struct class_simple, class)
-
-struct simple_dev {
-	struct list_head node;
-	struct class_device class_dev;
-};
-#define to_simple_dev(d) container_of(d, struct simple_dev, class_dev)
-
-static LIST_HEAD(simple_dev_list);
-static DEFINE_SPINLOCK(simple_dev_list_lock);
-
-static void release_simple_dev(struct class_device *class_dev)
-{
-	struct simple_dev *s_dev = to_simple_dev(class_dev);
-	kfree(s_dev);
-}
-
-static void class_simple_release(struct class *class)
-{
-	struct class_simple *cs = to_class_simple(class);
-	kfree(cs);
-}
-
-/**
- * class_simple_create - create a struct class_simple structure
- * @owner: pointer to the module that is to "own" this struct class_simple
- * @name: pointer to a string for the name of this class.
- *
- * This is used to create a struct class_simple pointer that can then be used
- * in calls to class_simple_device_add().  This is used when you do not wish to
- * create a full blown class support for a type of char devices.
- *
- * Note, the pointer created here is to be destroyed when finished by making a
- * call to class_simple_destroy().
- */
-struct class_simple *class_simple_create(struct module *owner, char *name)
-{
-	struct class_simple *cs;
-	int retval;
-
-	cs = kmalloc(sizeof(*cs), GFP_KERNEL);
-	if (!cs) {
-		retval = -ENOMEM;
-		goto error;
-	}
-	memset(cs, 0x00, sizeof(*cs));
-
-	cs->class.name = name;
-	cs->class.class_release = class_simple_release;
-	cs->class.release = release_simple_dev;
-
-	retval = class_register(&cs->class);
-	if (retval)
-		goto error;
-
-	return cs;
-
-error:
-	kfree(cs);
-	return ERR_PTR(retval);
-}
-EXPORT_SYMBOL(class_simple_create);
-
-/**
- * class_simple_destroy - destroys a struct class_simple structure
- * @cs: pointer to the struct class_simple that is to be destroyed
- *
- * Note, the pointer to be destroyed must have been created with a call to
- * class_simple_create().
- */
-void class_simple_destroy(struct class_simple *cs)
-{
-	if ((cs == NULL) || (IS_ERR(cs)))
-		return;
-
-	class_unregister(&cs->class);
-}
-EXPORT_SYMBOL(class_simple_destroy);
-
-/**
- * class_simple_device_add - adds a class device to sysfs for a character driver
- * @cs: pointer to the struct class_simple that this device should be registered to.
- * @dev: the dev_t for the device to be added.
- * @device: a pointer to a struct device that is assiociated with this class device.
- * @fmt: string for the class device's name
- *
- * This function can be used by simple char device classes that do not
- * implement their own class device registration.  A struct class_device will
- * be created in sysfs, registered to the specified class.  A "dev" file will
- * be created, showing the dev_t for the device.  The pointer to the struct
- * class_device will be returned from the call.  Any further sysfs files that
- * might be required can be created using this pointer.
- * Note: the struct class_simple passed to this function must have previously been
- * created with a call to class_simple_create().
- */
-struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...)
-{
-	va_list args;
-	struct simple_dev *s_dev = NULL;
-	int retval;
-
-	if ((cs == NULL) || (IS_ERR(cs))) {
-		retval = -ENODEV;
-		goto error;
-	}
-
-	s_dev = kmalloc(sizeof(*s_dev), GFP_KERNEL);
-	if (!s_dev) {
-		retval = -ENOMEM;
-		goto error;
-	}
-	memset(s_dev, 0x00, sizeof(*s_dev));
-
-	s_dev->class_dev.devt = dev;
-	s_dev->class_dev.dev = device;
-	s_dev->class_dev.class = &cs->class;
-
-	va_start(args, fmt);
-	vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args);
-	va_end(args);
-	retval = class_device_register(&s_dev->class_dev);
-	if (retval)
-		goto error;
-
-	spin_lock(&simple_dev_list_lock);
-	list_add(&s_dev->node, &simple_dev_list);
-	spin_unlock(&simple_dev_list_lock);
-
-	return &s_dev->class_dev;
-
-error:
-	kfree(s_dev);
-	return ERR_PTR(retval);
-}
-EXPORT_SYMBOL(class_simple_device_add);
-
-/**
- * class_simple_set_hotplug - set the hotplug callback in the embedded struct class
- * @cs: pointer to the struct class_simple to hold the pointer
- * @hotplug: function pointer to the hotplug function
- *
- * Implement and set a hotplug function to add environment variables specific to this
- * class on the hotplug event.
- */
-int class_simple_set_hotplug(struct class_simple *cs,
-	int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size))
-{
-	if ((cs == NULL) || (IS_ERR(cs)))
-		return -ENODEV;
-	cs->class.hotplug = hotplug;
-	return 0;
-}
-EXPORT_SYMBOL(class_simple_set_hotplug);
-
-/**
- * class_simple_device_remove - removes a class device that was created with class_simple_device_add()
- * @dev: the dev_t of the device that was previously registered.
- *
- * This call unregisters and cleans up a class device that was created with a
- * call to class_device_simple_add()
- */
-void class_simple_device_remove(dev_t dev)
-{
-	struct simple_dev *s_dev = NULL;
-	int found = 0;
-
-	spin_lock(&simple_dev_list_lock);
-	list_for_each_entry(s_dev, &simple_dev_list, node) {
-		if (s_dev->class_dev.devt == dev) {
-			found = 1;
-			break;
-		}
-	}
-	if (found) {
-		list_del(&s_dev->node);
-		spin_unlock(&simple_dev_list_lock);
-		class_device_unregister(&s_dev->class_dev);
-	} else {
-		spin_unlock(&simple_dev_list_lock);
-	}
-}
-EXPORT_SYMBOL(class_simple_device_remove);
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/base/core.c	2005-03-30 17:18:11 -08:00
@@ -210,11 +210,9 @@
 {
 	kobj_set_kset_s(dev, devices_subsys);
 	kobject_init(&dev->kobj);
-	INIT_LIST_HEAD(&dev->node);
-	INIT_LIST_HEAD(&dev->children);
-	INIT_LIST_HEAD(&dev->driver_list);
-	INIT_LIST_HEAD(&dev->bus_list);
+	klist_init(&dev->klist_children);
 	INIT_LIST_HEAD(&dev->dma_pools);
+	init_MUTEX(&dev->sem);
 }
 
 /**
@@ -252,14 +250,14 @@
 		goto PMError;
 	if ((error = bus_add_device(dev)))
 		goto BusError;
-	down_write(&devices_subsys.rwsem);
 	if (parent)
-		list_add_tail(&dev->node, &parent->children);
-	up_write(&devices_subsys.rwsem);
+		klist_add_tail(&parent->klist_children, &dev->knode_parent);
 
 	/* notify platform of device entry */
 	if (platform_notify)
 		platform_notify(dev);
+
+	kobject_hotplug(&dev->kobj, KOBJ_ADD);
  Done:
 	put_device(dev);
 	return error;
@@ -337,10 +335,8 @@
 {
 	struct device * parent = dev->parent;
 
-	down_write(&devices_subsys.rwsem);
 	if (parent)
-		list_del_init(&dev->node);
-	up_write(&devices_subsys.rwsem);
+		klist_remove(&dev->knode_parent);
 
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
@@ -349,6 +345,7 @@
 		platform_notify_remove(dev);
 	bus_remove_device(dev);
 	device_pm_remove(dev);
+	kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
 	if (parent)
 		put_device(parent);
@@ -373,6 +370,12 @@
 }
 
 
+static struct device * next_device(struct klist_iter * i)
+{
+	struct klist_node * n = klist_next(i);
+	return n ? container_of(n, struct device, knode_parent) : NULL;
+}
+
 /**
  *	device_for_each_child - device child iterator.
  *	@dev:	parent struct device.
@@ -385,39 +388,20 @@
  *	We check the return of @fn each time. If it returns anything
  *	other than 0, we break out and return that value.
  */
-int device_for_each_child(struct device * dev, void * data,
+int device_for_each_child(struct device * parent, void * data,
 		     int (*fn)(struct device *, void *))
 {
+	struct klist_iter i;
 	struct device * child;
 	int error = 0;
 
-	down_read(&devices_subsys.rwsem);
-	list_for_each_entry(child, &dev->children, node) {
-		if((error = fn(child, data)))
-			break;
-	}
-	up_read(&devices_subsys.rwsem);
+	klist_iter_init(&parent->klist_children, &i);
+	while ((child = next_device(&i)) && !error)
+		error = fn(child, data);
+	klist_iter_exit(&i);
 	return error;
 }
 
-/**
- *	device_find - locate device on a bus by name.
- *	@name:	name of the device.
- *	@bus:	bus to scan for the device.
- *
- *	Call kset_find_obj() to iterate over list of devices on
- *	a bus to find device by name. Return device if found.
- *
- *	Note that kset_find_obj increments device's reference count.
- */
-struct device *device_find(const char *name, struct bus_type *bus)
-{
-	struct kobject *k = kset_find_obj(&bus->devices, name);
-	if (k)
-		return to_dev(k);
-	return NULL;
-}
-
 int __init devices_init(void)
 {
 	return subsystem_register(&devices_subsys);
@@ -433,7 +417,6 @@
 EXPORT_SYMBOL_GPL(device_unregister);
 EXPORT_SYMBOL_GPL(get_device);
 EXPORT_SYMBOL_GPL(put_device);
-EXPORT_SYMBOL_GPL(device_find);
 
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
diff -Nru a/drivers/base/dd.c b/drivers/base/dd.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/base/dd.c	2005-03-30 17:18:12 -08:00
@@ -0,0 +1,219 @@
+/*
+ *	drivers/base/dd.c - The core device/driver interactions.
+ *
+ * 	This file contains the (sometimes tricky) code that controls the 
+ *	interactions between devices and drivers, which primarily includes
+ *	driver binding and unbinding.
+ *
+ *	All of this code used to exist in drivers/base/bus.c, but was 
+ *	relocated to here in the name of compartmentalization (since it wasn't
+ *	strictly code just for the 'struct bus_type'.
+ *
+ *	Copyright (c) 2002-5 Patrick Mochel
+ *	Copyright (c) 2002-3 Open Source Development Labs
+ *
+ *	This file is released under the GPLv2
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include "base.h"
+#include "power/power.h"
+
+#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
+
+
+/**
+ *	device_bind_driver - bind a driver to one device.
+ *	@dev:	device.
+ *
+ *	Allow manual attachment of a driver to a device.
+ *	Caller must have already set @dev->driver.
+ *
+ *	Note that this does not modify the bus reference count
+ *	nor take the bus's rwsem. Please verify those are accounted
+ *	for before calling this. (It is ok to call with no other effort
+ *	from a driver's probe() method.)
+ */
+
+void device_bind_driver(struct device * dev)
+{
+	pr_debug("bound device '%s' to driver '%s'\n",
+		 dev->bus_id, dev->driver->name);
+	klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver);
+	sysfs_create_link(&dev->driver->kobj, &dev->kobj,
+			  kobject_name(&dev->kobj));
+	sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
+}
+
+
+/**
+ *	driver_probe_device - attempt to bind device & driver.
+ *	@drv:	driver.
+ *	@dev:	device.
+ *
+ *	First, we call the bus's match function, if one present, which
+ *	should compare the device IDs the driver supports with the
+ *	device IDs of the device. Note we don't do this ourselves
+ *	because we don't know the format of the ID structures, nor what
+ *	is to be considered a match and what is not.
+ *
+ *	If we find a match, we call @drv->probe(@dev) if it exists, and
+ *	call device_bind_driver() above.
+ */
+int driver_probe_device(struct device_driver * drv, struct device * dev)
+{
+	int error = 0;
+
+	if (drv->bus->match && !drv->bus->match(dev, drv))
+		return -ENODEV;
+
+	down(&dev->sem);
+	dev->driver = drv;
+	if (drv->probe) {
+		error = drv->probe(dev);
+		if (error) {
+			dev->driver = NULL;
+			up(&dev->sem);
+			return error;
+		}
+	}
+	up(&dev->sem);
+	device_bind_driver(dev);
+	return 0;
+}
+
+
+static int __device_attach(struct device_driver * drv, void * data)
+{
+	struct device * dev = data;
+	int error;
+
+	error = driver_probe_device(drv, dev);
+
+	if (error == -ENODEV && error == -ENXIO) {
+		/* Driver matched, but didn't support device 
+		 * or device not found.
+		 * Not an error; keep going.
+		 */
+		error = 0;
+	} else {
+		/* driver matched but the probe failed */
+		printk(KERN_WARNING
+		       "%s: probe of %s failed with error %d\n",
+		       drv->name, dev->bus_id, error);
+	}
+	return 0;
+}
+
+
+/**
+ *	device_attach - try to attach device to a driver.
+ *	@dev:	device.
+ *
+ *	Walk the list of drivers that the bus has and call
+ *	driver_probe_device() for each pair. If a compatible
+ *	pair is found, break out and return.
+ */
+int device_attach(struct device * dev)
+{
+	if (dev->driver) {
+		device_bind_driver(dev);
+		return 1;
+	}
+
+	return bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+}
+
+
+static int __driver_attach(struct device * dev, void * data)
+{
+	struct device_driver * drv = data;
+	int error = 0;
+
+	if (!dev->driver) {
+		error = driver_probe_device(drv, dev);
+		if (error) {
+			if (error != -ENODEV) {
+				/* driver matched but the probe failed */
+				printk(KERN_WARNING
+				       "%s: probe of %s failed with error %d\n",
+				       drv->name, dev->bus_id, error);
+			} else
+				error = 0;
+		}
+	}
+	return 0;
+}
+
+/**
+ *	driver_attach - try to bind driver to devices.
+ *	@drv:	driver.
+ *
+ *	Walk the list of devices that the bus has on it and try to
+ *	match the driver with each one.  If driver_probe_device()
+ *	returns 0 and the @dev->driver is set, we've found a
+ *	compatible pair.
+ *
+ *	Note that we ignore the -ENODEV error from driver_probe_device(),
+ *	since it's perfectly valid for a driver not to bind to any devices.
+ */
+void driver_attach(struct device_driver * drv)
+{
+	bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
+}
+
+
+/**
+ *	device_release_driver - manually detach device from driver.
+ *	@dev:	device.
+ *
+ *	Manually detach device from driver.
+ *	Note that this is called without incrementing the bus
+ *	reference count nor taking the bus's rwsem. Be sure that
+ *	those are accounted for before calling this function.
+ */
+
+void device_release_driver(struct device * dev)
+{
+	struct device_driver * drv = dev->driver;
+
+	if (!drv)
+		return;
+
+	sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+	sysfs_remove_link(&dev->kobj, "driver");
+	klist_del(&dev->knode_driver);
+
+	down(&dev->sem);
+	device_detach_shutdown(dev);
+	if (drv->remove)
+		drv->remove(dev);
+	dev->driver = NULL;
+	up(&dev->sem);
+}
+
+
+static int __remove_driver(struct device * dev, void * unused)
+{
+	device_release_driver(dev);
+	return 0;
+}
+
+/**
+ *	driver_detach - detach driver from all devices it controls.
+ *	@drv:	driver.
+ */
+
+void driver_detach(struct device_driver * drv)
+{
+	driver_for_each_device(drv, NULL, NULL, __remove_driver);
+}
+
+EXPORT_SYMBOL_GPL(driver_probe_device);
+EXPORT_SYMBOL_GPL(device_bind_driver);
+EXPORT_SYMBOL_GPL(device_release_driver);
+EXPORT_SYMBOL_GPL(device_attach);
+EXPORT_SYMBOL_GPL(driver_attach);
+
diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c
--- a/drivers/base/driver.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/base/driver.c	2005-03-30 17:18:12 -08:00
@@ -18,6 +18,43 @@
 #define to_dev(node) container_of(node, struct device, driver_list)
 #define to_drv(obj) container_of(obj, struct device_driver, kobj)
 
+
+static struct device * next_device(struct klist_iter * i)
+{
+	struct klist_node * n = klist_next(i);
+	return n ? container_of(n, struct device, knode_driver) : NULL;
+}
+
+/**
+ *	driver_for_each_device - Iterator for devices bound to a driver.
+ *	@drv:	Driver we're iterating.
+ *	@data:	Data to pass to the callback.
+ *	@fn:	Function to call for each device.
+ *
+ *	Iterate over the @drv's list of devices calling @fn for each one.
+ */
+
+int driver_for_each_device(struct device_driver * drv, struct device * start, 
+			   void * data, int (*fn)(struct device *, void *))
+{
+	struct klist_iter i;
+	struct device * dev;
+	int error = 0;
+
+	if (!drv)
+		return -EINVAL;
+
+	klist_iter_init_node(&drv->klist_devices, &i,
+			     start ? &start->knode_driver : NULL);
+	while ((dev = next_device(&i)) && !error)
+		error = fn(dev, data);
+	klist_iter_exit(&i);
+	return error;
+}
+
+EXPORT_SYMBOL_GPL(driver_for_each_device);
+
+
 /**
  *	driver_create_file - create sysfs file for driver.
  *	@drv:	driver.
@@ -85,7 +122,7 @@
  */
 int driver_register(struct device_driver * drv)
 {
-	INIT_LIST_HEAD(&drv->devices);
+	klist_init(&drv->klist_devices);
 	init_completion(&drv->unloaded);
 	return bus_add_driver(drv);
 }
diff -Nru a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
--- a/drivers/base/firmware_class.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/base/firmware_class.c	2005-03-30 17:18:12 -08:00
@@ -102,6 +102,9 @@
 	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
 			"FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
+	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			"TIMEOUT=%i", loading_timeout))
+		return -ENOMEM;
 
 	envp[i] = NULL;
 
diff -Nru a/drivers/base/power/resume.c b/drivers/base/power/resume.c
--- a/drivers/base/power/resume.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/base/power/resume.c	2005-03-30 17:18:12 -08:00
@@ -22,9 +22,13 @@
 
 int resume_device(struct device * dev)
 {
+	int error = 0;
+
+	down(&dev->sem);
 	if (dev->bus && dev->bus->resume)
-		return dev->bus->resume(dev);
-	return 0;
+		error = dev->bus->resume(dev);
+	up(&dev->sem);
+	return error;
 }
 
 
diff -Nru a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
--- a/drivers/base/power/suspend.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/base/power/suspend.c	2005-03-30 17:18:12 -08:00
@@ -41,11 +41,11 @@
 
 	dev_dbg(dev, "suspending\n");
 
+	down(&dev->sem);
 	dev->power.prev_state = dev->power.power_state;
-
 	if (dev->bus && dev->bus->suspend && !dev->power.power_state)
 		error = dev->bus->suspend(dev, state);
-
+	up(&dev->sem);
 	return error;
 }
 
diff -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig
--- a/drivers/block/Kconfig	2005-03-30 17:18:11 -08:00
+++ b/drivers/block/Kconfig	2005-03-30 17:18:11 -08:00
@@ -506,4 +506,19 @@
 	This driver provides Support for ATA over Ethernet block
 	devices like the Coraid EtherDrive (R) Storage Blade.
 
+config AOE_PARTITIONS
+	int "Partitions per AoE device" if ATA_OVER_ETH
+	default "16"
+	help
+	  The default is to support 16 partitions per aoe device. Some
+	  systems lack good support for devices with large minor
+	  numbers.
+
+	  Such systems will be able to use more aoe disks when
+	  AOE_PARTITIONS is set to one, but you won't be able to
+	  partition the disks, and you must make sure your device
+	  nodes are created to work with the value you select.
+
+	  If unsure, use 16.
+
 endmenu
diff -Nru a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
--- a/drivers/block/aoe/aoe.h	2005-03-30 17:18:12 -08:00
+++ b/drivers/block/aoe/aoe.h	2005-03-30 17:18:12 -08:00
@@ -1,10 +1,16 @@
 /* Copyright (c) 2004 Coraid, Inc.  See COPYING for GPL terms. */
-#define VERSION "5"
+#define VERSION "6"
 #define AOE_MAJOR 152
 #define DEVICE_NAME "aoe"
-#ifndef AOE_PARTITIONS
-#define AOE_PARTITIONS 16
+
+/* set AOE_PARTITIONS to 1 to use whole-disks only
+ * default is 16, which is 15 partitions plus the whole disk
+ */
+#define AOE_PARTITIONS CONFIG_AOE_PARTITIONS
+#if AOE_PARTITIONS < 1
+#error AOE_PARTITIONS less than one
 #endif
+
 #define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * 10 + (aoeminor))
 #define AOEMAJOR(sysminor) ((sysminor) / 10)
 #define AOEMINOR(sysminor) ((sysminor) % 10)
@@ -34,13 +40,13 @@
 struct aoe_hdr {
 	unsigned char dst[6];
 	unsigned char src[6];
-	unsigned char type[2];
+	__be16 type;
 	unsigned char verfl;
 	unsigned char err;
-	unsigned char major[2];
+	__be16 major;
 	unsigned char minor;
 	unsigned char cmd;
-	unsigned char tag[4];
+	__be32 tag;
 };
 
 struct aoe_atahdr {
@@ -58,8 +64,8 @@
 };
 
 struct aoe_cfghdr {
-	unsigned char bufcnt[2];
-	unsigned char fwver[2];
+	__be16 bufcnt;
+	__be16 fwver;
 	unsigned char res;
 	unsigned char aoeccmd;
 	unsigned char cslen[2];
@@ -85,6 +91,7 @@
 
 struct buf {
 	struct list_head bufs;
+	ulong start_time;	/* for disk stats */
 	ulong flags;
 	ulong nframesout;
 	char *bufaddr;
@@ -125,7 +132,8 @@
 	struct timer_list timer;
 	spinlock_t lock;
 	struct net_device *ifp;	/* interface ed is attached to */
-	struct sk_buff *skblist;/* packets needing to be sent */
+	struct sk_buff *sendq_hd; /* packets needing to be sent, list head */
+	struct sk_buff *sendq_tl;
 	mempool_t *bufpool;	/* for deadlock-free Buf allocation */
 	struct list_head bufq;	/* queue of bios to work on */
 	struct buf *inprocess;	/* the one we're currently working on */
@@ -151,7 +159,7 @@
 
 int aoedev_init(void);
 void aoedev_exit(void);
-struct aoedev *aoedev_bymac(unsigned char *);
+struct aoedev *aoedev_by_aoeaddr(int maj, int min);
 void aoedev_downdev(struct aoedev *d);
 struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong);
 int aoedev_busy(void);
diff -Nru a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
--- a/drivers/block/aoe/aoeblk.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/block/aoe/aoeblk.c	2005-03-30 17:18:12 -08:00
@@ -125,6 +125,7 @@
 	}
 	memset(buf, 0, sizeof(*buf));
 	INIT_LIST_HEAD(&buf->bufs);
+	buf->start_time = jiffies;
 	buf->bio = bio;
 	buf->resid = bio->bi_size;
 	buf->sector = bio->bi_sector;
@@ -146,8 +147,8 @@
 	list_add_tail(&buf->bufs, &d->bufq);
 	aoecmd_work(d);
 
-	sl = d->skblist;
-	d->skblist = NULL;
+	sl = d->sendq_hd;
+	d->sendq_hd = d->sendq_tl = NULL;
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
diff -Nru a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
--- a/drivers/block/aoe/aoechr.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/block/aoe/aoechr.c	2005-03-30 17:18:12 -08:00
@@ -36,7 +36,7 @@
 static struct semaphore emsgs_sema;
 static spinlock_t emsgs_lock;
 static int nblocked_emsgs_readers;
-static struct class_simple *aoe_class;
+static struct class *aoe_class;
 static struct aoe_chardev chardevs[] = {
 	{ MINOR_ERR, "err" },
 	{ MINOR_DISCOVER, "discover" },
@@ -218,13 +218,13 @@
 	}
 	sema_init(&emsgs_sema, 0);
 	spin_lock_init(&emsgs_lock);
-	aoe_class = class_simple_create(THIS_MODULE, "aoe");
+	aoe_class = class_create(THIS_MODULE, "aoe");
 	if (IS_ERR(aoe_class)) {
 		unregister_chrdev(AOE_MAJOR, "aoechr");
 		return PTR_ERR(aoe_class);
 	}
 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
-		class_simple_device_add(aoe_class,
+		class_device_create(aoe_class,
 					MKDEV(AOE_MAJOR, chardevs[i].minor),
 					NULL, chardevs[i].name);
 
@@ -237,8 +237,8 @@
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
-		class_simple_device_remove(MKDEV(AOE_MAJOR, chardevs[i].minor));
-	class_simple_destroy(aoe_class);
+		class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
+	class_destroy(aoe_class);
 	unregister_chrdev(AOE_MAJOR, "aoechr");
 }
 
diff -Nru a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
--- a/drivers/block/aoe/aoecmd.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/block/aoe/aoecmd.c	2005-03-30 17:18:12 -08:00
@@ -90,19 +90,16 @@
 static int
 aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h)
 {
-	u16 type = __constant_cpu_to_be16(ETH_P_AOE);
-	u16 aoemajor = __cpu_to_be16(d->aoemajor);
 	u32 host_tag = newtag(d);
-	u32 tag = __cpu_to_be32(host_tag);
 
 	memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
 	memcpy(h->dst, d->addr, sizeof h->dst);
-	memcpy(h->type, &type, sizeof type);
+	h->type = __constant_cpu_to_be16(ETH_P_AOE);
 	h->verfl = AOE_HVER;
-	memcpy(h->major, &aoemajor, sizeof aoemajor);
+	h->major = cpu_to_be16(d->aoemajor);
 	h->minor = d->aoeminor;
 	h->cmd = AOECMD_ATA;
-	memcpy(h->tag, &tag, sizeof tag);
+	h->tag = cpu_to_be32(host_tag);
 
 	return host_tag;
 }
@@ -181,8 +178,12 @@
 
 	skb = skb_prepare(d, f);
 	if (skb) {
-		skb->next = d->skblist;
-		d->skblist = skb;
+		skb->next = NULL;
+		if (d->sendq_hd)
+			d->sendq_tl->next = skb;
+		else
+			d->sendq_hd = skb;
+		d->sendq_tl = skb;
 	}
 }
 
@@ -215,7 +216,6 @@
 	struct aoe_hdr *h;
 	char buf[128];
 	u32 n;
-	u32 net_tag;
 
 	n = newtag(d);
 
@@ -227,13 +227,16 @@
 
 	h = (struct aoe_hdr *) f->data;
 	f->tag = n;
-	net_tag = __cpu_to_be32(n);
-	memcpy(h->tag, &net_tag, sizeof net_tag);
+	h->tag = cpu_to_be32(n);
 
 	skb = skb_prepare(d, f);
 	if (skb) {
-		skb->next = d->skblist;
-		d->skblist = skb;
+		skb->next = NULL;
+		if (d->sendq_hd)
+			d->sendq_tl->next = skb;
+		else
+			d->sendq_hd = skb;
+		d->sendq_tl = skb;
 	}
 }
 
@@ -285,8 +288,8 @@
 		}
 	}
 
-	sl = d->skblist;
-	d->skblist = NULL;
+	sl = d->sendq_hd;
+	d->sendq_hd = d->sendq_tl = NULL;
 	if (sl) {
 		n = d->rttavg <<= 1;
 		if (n > MAXTIMER)
@@ -308,16 +311,16 @@
 	u16 n;
 
 	/* word 83: command set supported */
-	n = __le16_to_cpu(*((u16 *) &id[83<<1]));
+	n = le16_to_cpup((__le16 *) &id[83<<1]);
 
 	/* word 86: command set/feature enabled */
-	n |= __le16_to_cpu(*((u16 *) &id[86<<1]));
+	n |= le16_to_cpup((__le16 *) &id[86<<1]);
 
 	if (n & (1<<10)) {	/* bit 10: LBA 48 */
 		d->flags |= DEVFL_EXT;
 
 		/* word 100: number lba48 sectors */
-		ssize = __le64_to_cpu(*((u64 *) &id[100<<1]));
+		ssize = le64_to_cpup((__le64 *) &id[100<<1]);
 
 		/* set as in ide-disk.c:init_idedisk_capacity */
 		d->geo.cylinders = ssize;
@@ -328,12 +331,12 @@
 		d->flags &= ~DEVFL_EXT;
 
 		/* number lba28 sectors */
-		ssize = __le32_to_cpu(*((u32 *) &id[60<<1]));
+		ssize = le32_to_cpup((__le32 *) &id[60<<1]);
 
 		/* NOTE: obsolete in ATA 6 */
-		d->geo.cylinders = __le16_to_cpu(*((u16 *) &id[54<<1]));
-		d->geo.heads = __le16_to_cpu(*((u16 *) &id[55<<1]));
-		d->geo.sectors = __le16_to_cpu(*((u16 *) &id[56<<1]));
+		d->geo.cylinders = le16_to_cpup((__le16 *) &id[54<<1]);
+		d->geo.heads = le16_to_cpup((__le16 *) &id[55<<1]);
+		d->geo.sectors = le16_to_cpup((__le16 *) &id[56<<1]);
 	}
 	d->ssize = ssize;
 	d->geo.start = 0;
@@ -380,29 +383,30 @@
 	register long n;
 	ulong flags;
 	char ebuf[128];
-	
+	u16 aoemajor;
+
 	hin = (struct aoe_hdr *) skb->mac.raw;
-	d = aoedev_bymac(hin->src);
+	aoemajor = be16_to_cpu(hin->major);
+	d = aoedev_by_aoeaddr(aoemajor, hin->minor);
 	if (d == NULL) {
 		snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
 			"for unknown device %d.%d\n",
-			 __be16_to_cpu(*((u16 *) hin->major)),
-			hin->minor);
+			 aoemajor, hin->minor);
 		aoechr_error(ebuf);
 		return;
 	}
 
 	spin_lock_irqsave(&d->lock, flags);
 
-	f = getframe(d, __be32_to_cpu(*((u32 *) hin->tag)));
+	f = getframe(d, be32_to_cpu(hin->tag));
 	if (f == NULL) {
 		spin_unlock_irqrestore(&d->lock, flags);
 		snprintf(ebuf, sizeof ebuf,
 			"%15s e%d.%d    tag=%08x@%08lx\n",
 			"unexpected rsp",
-			__be16_to_cpu(*((u16 *) hin->major)),
+			be16_to_cpu(hin->major),
 			hin->minor,
-			__be32_to_cpu(*((u32 *) hin->tag)),
+			be32_to_cpu(hin->tag),
 			jiffies);
 		aoechr_error(ebuf);
 		return;
@@ -452,7 +456,7 @@
 			printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
 			       "outbound ata command %2.2Xh for %d.%d\n", 
 			       ahout->cmdstat,
-			       __be16_to_cpu(*((u16 *) hin->major)),
+			       be16_to_cpu(hin->major),
 			       hin->minor);
 		}
 	}
@@ -460,6 +464,20 @@
 	if (buf) {
 		buf->nframesout -= 1;
 		if (buf->nframesout == 0 && buf->resid == 0) {
+			unsigned long duration = jiffies - buf->start_time;
+			unsigned long n_sect = buf->bio->bi_size >> 9;
+			struct gendisk *disk = d->gd;
+
+			if (bio_data_dir(buf->bio) == WRITE) {
+				disk_stat_inc(disk, writes);
+				disk_stat_add(disk, write_ticks, duration);
+				disk_stat_add(disk, write_sectors, n_sect);
+			} else {
+				disk_stat_inc(disk, reads);
+				disk_stat_add(disk, read_ticks, duration);
+				disk_stat_add(disk, read_sectors, n_sect);
+			}
+			disk_stat_add(disk, io_ticks, duration);
 			n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
 			bio_endio(buf->bio, buf->bio->bi_size, n);
 			mempool_free(buf, d->bufpool);
@@ -471,8 +489,8 @@
 
 	aoecmd_work(d);
 
-	sl = d->skblist;
-	d->skblist = NULL;
+	sl = d->sendq_hd;
+	d->sendq_hd = d->sendq_tl = NULL;
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
@@ -486,8 +504,6 @@
 	struct aoe_cfghdr *ch;
 	struct sk_buff *skb, *sl;
 	struct net_device *ifp;
-	u16 aoe_type = __constant_cpu_to_be16(ETH_P_AOE);
-	u16 net_aoemajor = __cpu_to_be16(aoemajor);
 
 	sl = NULL;
 
@@ -507,9 +523,9 @@
 
 		memset(h->dst, 0xff, sizeof h->dst);
 		memcpy(h->src, ifp->dev_addr, sizeof h->src);
-		memcpy(h->type, &aoe_type, sizeof aoe_type);
+		h->type = __constant_cpu_to_be16(ETH_P_AOE);
 		h->verfl = AOE_HVER;
-		memcpy(h->major, &net_aoemajor, sizeof net_aoemajor);
+		h->major = cpu_to_be16(aoemajor);
 		h->minor = aoeminor;
 		h->cmd = AOECMD_CFG;
 
@@ -523,7 +539,7 @@
  
 /*
  * Since we only call this in one place (and it only prepares one frame)
- * we just return the skb.  Usually we'd chain it up to the d->skblist.
+ * we just return the skb.  Usually we'd chain it up to the aoedev sendq.
  */
 static struct sk_buff *
 aoecmd_ata_id(struct aoedev *d)
@@ -575,9 +591,10 @@
 	struct aoedev *d;
 	struct aoe_hdr *h;
 	struct aoe_cfghdr *ch;
-	ulong flags, bufcnt, sysminor, aoemajor;
+	ulong flags, sysminor, aoemajor;
+	u16 bufcnt;
 	struct sk_buff *sl;
-	enum { MAXFRAMES = 8, MAXSYSMINOR = 255 };
+	enum { MAXFRAMES = 8 };
 
 	h = (struct aoe_hdr *) skb->mac.raw;
 	ch = (struct aoe_cfghdr *) (h+1);
@@ -586,7 +603,7 @@
 	 * Enough people have their dip switches set backwards to
 	 * warrant a loud message for this special case.
 	 */
-	aoemajor = __be16_to_cpu(*((u16 *) h->major));
+	aoemajor = be16_to_cpu(h->major);
 	if (aoemajor == 0xfff) {
 		printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf "
 			"address is all ones.  Check shelf dip switches\n");
@@ -594,13 +611,14 @@
 	}
 
 	sysminor = SYSMINOR(aoemajor, h->minor);
-	if (sysminor > MAXSYSMINOR) {
-		printk(KERN_INFO "aoe: aoecmd_cfg_rsp: sysminor %ld too "
-			"large\n", sysminor);
+	if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
+		printk(KERN_INFO
+			"aoe: e%ld.%d: minor number too large\n", 
+			aoemajor, (int) h->minor);
 		return;
 	}
 
-	bufcnt = __be16_to_cpu(*((u16 *) ch->bufcnt));
+	bufcnt = be16_to_cpu(ch->bufcnt);
 	if (bufcnt > MAXFRAMES)	/* keep it reasonable */
 		bufcnt = MAXFRAMES;
 
@@ -617,7 +635,7 @@
 		return;
 	}
 
-	d->fw_ver = __be16_to_cpu(*((u16 *) ch->fwver));
+	d->fw_ver = be16_to_cpu(ch->fwver);
 
 	/* we get here only if the device is new */
 	sl = aoecmd_ata_id(d);
diff -Nru a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
--- a/drivers/block/aoe/aoedev.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/block/aoe/aoedev.c	2005-03-30 17:18:11 -08:00
@@ -13,7 +13,7 @@
 static spinlock_t devlist_lock;
 
 struct aoedev *
-aoedev_bymac(unsigned char *macaddr)
+aoedev_by_aoeaddr(int maj, int min)
 {
 	struct aoedev *d;
 	ulong flags;
@@ -21,7 +21,7 @@
 	spin_lock_irqsave(&devlist_lock, flags);
 
 	for (d=devlist; d; d=d->next)
-		if (!memcmp(d->addr, macaddr, 6))
+		if (d->aoemajor == maj && d->aoeminor == min)
 			break;
 
 	spin_unlock_irqrestore(&devlist_lock, flags);
@@ -125,7 +125,6 @@
 	d->ifp = ifp;
 
 	if (d->sysminor != sysminor
-	|| memcmp(d->addr, addr, sizeof d->addr)
 	|| (d->flags & DEVFL_UP) == 0) {
 		aoedev_downdev(d); /* flushes outstanding frames */
 		memcpy(d->addr, addr, sizeof d->addr);
@@ -147,7 +146,8 @@
 		put_disk(d->gd);
 	}
 	kfree(d->frames);
-	mempool_destroy(d->bufpool);
+	if (d->bufpool)
+		mempool_destroy(d->bufpool);
 	kfree(d);
 }
 
diff -Nru a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
--- a/drivers/block/aoe/aoenet.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/block/aoe/aoenet.c	2005-03-30 17:18:12 -08:00
@@ -69,7 +69,7 @@
 u64
 mac_addr(char addr[6])
 {
-	u64 n = 0;
+	__be64 n = 0;
 	char *p = (char *) &n;
 
 	memcpy(p + 2, addr, 6);	/* (sizeof addr != 6) */
@@ -108,7 +108,7 @@
 aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt)
 {
 	struct aoe_hdr *h;
-	ulong n;
+	u32 n;
 
 	skb = skb_check(skb);
 	if (!skb)
@@ -121,7 +121,7 @@
 	skb_push(skb, ETH_HLEN);	/* (1) */
 
 	h = (struct aoe_hdr *) skb->mac.raw;
-	n = __be32_to_cpu(*((u32 *) h->tag));
+	n = be32_to_cpu(h->tag);
 	if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
 		goto exit;
 
@@ -132,7 +132,7 @@
 		if (net_ratelimit())
 			printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; "
 			       "ecode=%d '%s'\n",
-			       __be16_to_cpu(*((u16 *) h->major)), h->minor, 
+			       be16_to_cpu(h->major), h->minor, 
 			       h->err, aoe_errlist[n]);
 		goto exit;
 	}
diff -Nru a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
--- a/drivers/block/paride/pg.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/block/paride/pg.c	2005-03-30 17:18:12 -08:00
@@ -222,7 +222,7 @@
 
 static char pg_scratch[512];	/* scratch block buffer */
 
-static struct class_simple *pg_class;
+static struct class *pg_class;
 
 /* kernel glue structures */
 
@@ -666,7 +666,7 @@
 		err = -1;
 		goto out;
 	}
-	pg_class = class_simple_create(THIS_MODULE, "pg");
+	pg_class = class_create(THIS_MODULE, "pg");
 	if (IS_ERR(pg_class)) {
 		err = PTR_ERR(pg_class);
 		goto out_chrdev;
@@ -675,7 +675,7 @@
 	for (unit = 0; unit < PG_UNITS; unit++) {
 		struct pg *dev = &devices[unit];
 		if (dev->present) {
-			class_simple_device_add(pg_class, MKDEV(major, unit), 
+			class_device_create(pg_class, MKDEV(major, unit), 
 					NULL, "pg%u", unit);
 			err = devfs_mk_cdev(MKDEV(major, unit),
 				      S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u",
@@ -688,8 +688,8 @@
 	goto out;
 
 out_class:
-	class_simple_device_remove(MKDEV(major, unit));
-	class_simple_destroy(pg_class);
+	class_device_destroy(pg_class, MKDEV(major, unit));
+	class_destroy(pg_class);
 out_chrdev:
 	unregister_chrdev(major, "pg");
 out:
@@ -703,11 +703,11 @@
 	for (unit = 0; unit < PG_UNITS; unit++) {
 		struct pg *dev = &devices[unit];
 		if (dev->present) {
-			class_simple_device_remove(MKDEV(major, unit));
+			class_device_destroy(pg_class, MKDEV(major, unit));
 			devfs_remove("pg/%u", unit);
 		}
 	}
-	class_simple_destroy(pg_class);
+	class_destroy(pg_class);
 	devfs_remove("pg");
 	unregister_chrdev(major, name);
 
diff -Nru a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
--- a/drivers/block/paride/pt.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/block/paride/pt.c	2005-03-30 17:18:11 -08:00
@@ -242,7 +242,7 @@
 };
 
 /* sysfs class support */
-static struct class_simple *pt_class;
+static struct class *pt_class;
 
 static inline int status_reg(struct pi_adapter *pi)
 {
@@ -963,7 +963,7 @@
 		err = -1;
 		goto out;
 	}
-	pt_class = class_simple_create(THIS_MODULE, "pt");
+	pt_class = class_create(THIS_MODULE, "pt");
 	if (IS_ERR(pt_class)) {
 		err = PTR_ERR(pt_class);
 		goto out_chrdev;
@@ -972,29 +972,29 @@
 	devfs_mk_dir("pt");
 	for (unit = 0; unit < PT_UNITS; unit++)
 		if (pt[unit].present) {
-			class_simple_device_add(pt_class, MKDEV(major, unit), 
+			class_device_create(pt_class, MKDEV(major, unit), 
 					NULL, "pt%d", unit);
 			err = devfs_mk_cdev(MKDEV(major, unit),
 				      S_IFCHR | S_IRUSR | S_IWUSR,
 				      "pt/%d", unit);
 			if (err) {
-				class_simple_device_remove(MKDEV(major, unit));
+				class_device_destroy(pt_class, MKDEV(major, unit));
 				goto out_class;
 			}
-			class_simple_device_add(pt_class, MKDEV(major, unit + 128),
+			class_device_create(pt_class, MKDEV(major, unit + 128),
 					NULL, "pt%dn", unit);
 			err = devfs_mk_cdev(MKDEV(major, unit + 128),
 				      S_IFCHR | S_IRUSR | S_IWUSR,
 				      "pt/%dn", unit);
 			if (err) {
-				class_simple_device_remove(MKDEV(major, unit + 128));
+				class_device_destroy(pt_class, MKDEV(major, unit + 128));
 				goto out_class;
 			}
 		}
 	goto out;
 
 out_class:
-	class_simple_destroy(pt_class);
+	class_destroy(pt_class);
 out_chrdev:
 	unregister_chrdev(major, "pt");
 out:
@@ -1006,12 +1006,12 @@
 	int unit;
 	for (unit = 0; unit < PT_UNITS; unit++)
 		if (pt[unit].present) {
-			class_simple_device_remove(MKDEV(major, unit));
+			class_device_destroy(pt_class, MKDEV(major, unit));
 			devfs_remove("pt/%d", unit);
-			class_simple_device_remove(MKDEV(major, unit + 128));
+			class_device_destroy(pt_class, MKDEV(major, unit + 128));
 			devfs_remove("pt/%dn", unit);
 		}
-	class_simple_destroy(pt_class);
+	class_destroy(pt_class);
 	devfs_remove("pt");
 	unregister_chrdev(major, name);
 	for (unit = 0; unit < PT_UNITS; unit++)
diff -Nru a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
--- a/drivers/char/dsp56k.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/dsp56k.c	2005-03-30 17:18:12 -08:00
@@ -144,7 +144,7 @@
 	int tx_wsize, rx_wsize;
 } dsp56k;
 
-static struct class_simple *dsp56k_class;
+static struct class *dsp56k_class;
 
 static int dsp56k_reset(void)
 {
@@ -510,12 +510,12 @@
 		printk("DSP56k driver: Unable to register driver\n");
 		return -ENODEV;
 	}
-	dsp56k_class = class_simple_create(THIS_MODULE, "dsp56k");
+	dsp56k_class = class_create(THIS_MODULE, "dsp56k");
 	if (IS_ERR(dsp56k_class)) {
 		err = PTR_ERR(dsp56k_class);
 		goto out_chrdev;
 	}
-	class_simple_device_add(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
+	class_device_create(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
 
 	err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0),
 		      S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k");
@@ -526,8 +526,8 @@
 	goto out;
 
 out_class:
-	class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0));
-	class_simple_destroy(dsp56k_class);
+	class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+	class_destroy(dsp56k_class);
 out_chrdev:
 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
 out:
@@ -537,8 +537,8 @@
 
 static void __exit dsp56k_cleanup_driver(void)
 {
-	class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0));
-	class_simple_destroy(dsp56k_class);
+	class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+	class_destroy(dsp56k_class);
 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
 	devfs_remove("dsp56k");
 }
diff -Nru a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
--- a/drivers/char/ftape/zftape/zftape-init.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/ftape/zftape/zftape-init.c	2005-03-30 17:18:12 -08:00
@@ -99,7 +99,7 @@
 	.release	= zft_close,
 };
 
-static struct class_simple *zft_class;
+static struct class *zft_class;
 
 /*      Open floppy tape device
  */
@@ -329,29 +329,29 @@
 	      "installing zftape VFS interface for ftape driver ...");
 	TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
 
-	zft_class = class_simple_create(THIS_MODULE, "zft");
+	zft_class = class_create(THIS_MODULE, "zft");
 	for (i = 0; i < 4; i++) {
-		class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i);
+		class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i);
 		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i),
 				S_IFCHR | S_IRUSR | S_IWUSR,
 				"qft%i", i);
-		class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i);
+		class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i);
 		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4),
 				S_IFCHR | S_IRUSR | S_IWUSR,
 				"nqft%i", i);
-		class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i);
+		class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i);
 		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16),
 				S_IFCHR | S_IRUSR | S_IWUSR,
 				"zqft%i", i);
-		class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i);
+		class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i);
 		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20),
 				S_IFCHR | S_IRUSR | S_IWUSR,
 				"nzqft%i", i);
-		class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i);
+		class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i);
 		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32),
 				S_IFCHR | S_IRUSR | S_IWUSR,
 				"rawqft%i", i);
-		class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i);
+		class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i);
 		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36),
 				S_IFCHR | S_IRUSR | S_IWUSR,
 				"nrawqft%i", i);
@@ -381,19 +381,19 @@
 	}
         for (i = 0; i < 4; i++) {
 		devfs_remove("qft%i", i);
-		class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i));
+		class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i));
 		devfs_remove("nqft%i", i);
-		class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 4));
+		class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4));
 		devfs_remove("zqft%i", i);
-		class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 16));
+		class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16));
 		devfs_remove("nzqft%i", i);
-		class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 20));
+		class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20));
 		devfs_remove("rawqft%i", i);
-		class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 32));
+		class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32));
 		devfs_remove("nrawqft%i", i);
-		class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 36));
+		class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36));
 	}
-	class_simple_destroy(zft_class);
+	class_destroy(zft_class);
 	zft_uninit_mem(); /* release remaining memory, if any */
         printk(KERN_INFO "zftape successfully unloaded.\n");
 	TRACE_EXIT;
diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c
--- a/drivers/char/ip2main.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/ip2main.c	2005-03-30 17:18:12 -08:00
@@ -302,7 +302,7 @@
 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
 
 /* for sysfs class support */
-static struct class_simple *ip2_class;
+static struct class *ip2_class;
 
 // Some functions to keep track of what irq's we have
 
@@ -414,9 +414,9 @@
 			iiResetDelay( i2BoardPtrTable[i] );
 			/* free io addresses and Tibet */
 			release_region( ip2config.addr[i], 8 );
-			class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i)); 
+			class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); 
 			devfs_remove("ip2/ipl%d", i);
-			class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+			class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
 			devfs_remove("ip2/stat%d", i);
 		}
 		/* Disable and remove interrupt handler. */
@@ -425,7 +425,7 @@
 			clear_requested_irq( ip2config.irq[i]);
 		}
 	}
-	class_simple_destroy(ip2_class);
+	class_destroy(ip2_class);
 	devfs_remove("ip2");
 	if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
 		printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
@@ -700,7 +700,7 @@
 		printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
 	} else {
 		/* create the sysfs class */
-		ip2_class = class_simple_create(THIS_MODULE, "ip2");
+		ip2_class = class_create(THIS_MODULE, "ip2");
 		if (IS_ERR(ip2_class)) {
 			err = PTR_ERR(ip2_class);
 			goto out_chrdev;	
@@ -722,25 +722,25 @@
 			}
 
 			if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-				class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR, 
+				class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, 
 						4 * i), NULL, "ipl%d", i);
 				err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i),
 						S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
 						"ip2/ipl%d", i);
 				if (err) {
-					class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 
-						4 * i));
+					class_device_destroy(ip2_class, 
+						MKDEV(IP2_IPL_MAJOR, 4 * i));
 					goto out_class;
 				}
 
-				class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR, 
+				class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, 
 						4 * i + 1), NULL, "stat%d", i);
 				err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
 						S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
 						"ip2/stat%d", i);
 				if (err) {
-					class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 
-						4 * i + 1));
+					class_device_destroy(ip2_class,
+						MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
 					goto out_class;
 				}
 
@@ -798,7 +798,7 @@
 	goto out;
 
 out_class:
-	class_simple_destroy(ip2_class);
+	class_destroy(ip2_class);
 out_chrdev:
 	unregister_chrdev(IP2_IPL_MAJOR, "ip2");
 out:
diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c
--- a/drivers/char/istallion.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/istallion.c	2005-03-30 17:18:12 -08:00
@@ -792,7 +792,7 @@
 
 /*****************************************************************************/
 
-static struct class_simple *istallion_class;
+static struct class *istallion_class;
 
 #ifdef MODULE
 
@@ -854,10 +854,10 @@
 	put_tty_driver(stli_serial);
 	for (i = 0; i < 4; i++) {
 		devfs_remove("staliomem/%d", i);
-		class_simple_device_remove(MKDEV(STL_SIOMEMMAJOR, i));
+		class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i));
 	}
 	devfs_remove("staliomem");
-	class_simple_destroy(istallion_class);
+	class_destroy(istallion_class);
 	if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
 		printk("STALLION: failed to un-register serial memory device, "
 			"errno=%d\n", -i);
@@ -5242,12 +5242,12 @@
 				"device\n");
 
 	devfs_mk_dir("staliomem");
-	istallion_class = class_simple_create(THIS_MODULE, "staliomem");
+	istallion_class = class_create(THIS_MODULE, "staliomem");
 	for (i = 0; i < 4; i++) {
 		devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
 			       S_IFCHR | S_IRUSR | S_IWUSR,
 			       "staliomem/%d", i);
-		class_simple_device_add(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), 
+		class_device_create(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), 
 				NULL, "staliomem%d", i);
 	}
 
diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c
--- a/drivers/char/lp.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/char/lp.c	2005-03-30 17:18:11 -08:00
@@ -146,7 +146,7 @@
 static struct lp_struct lp_table[LP_NO];
 
 static unsigned int lp_count = 0;
-static struct class_simple *lp_class;
+static struct class *lp_class;
 
 #ifdef CONFIG_LP_CONSOLE
 static struct parport *console_registered; // initially NULL
@@ -804,7 +804,7 @@
 	if (reset)
 		lp_reset(nr);
 
-	class_simple_device_add(lp_class, MKDEV(LP_MAJOR, nr), NULL,
+	class_device_create(lp_class, MKDEV(LP_MAJOR, nr), NULL,
 				"lp%d", nr);
 	devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO,
 			"printers/%d", nr);
@@ -907,7 +907,7 @@
 	}
 
 	devfs_mk_dir("printers");
-	lp_class = class_simple_create(THIS_MODULE, "printer");
+	lp_class = class_create(THIS_MODULE, "printer");
 	if (IS_ERR(lp_class)) {
 		err = PTR_ERR(lp_class);
 		goto out_devfs;
@@ -930,7 +930,7 @@
 	return 0;
 
 out_class:
-	class_simple_destroy(lp_class);
+	class_destroy(lp_class);
 out_devfs:
 	devfs_remove("printers");
 	unregister_chrdev(LP_MAJOR, "lp");
@@ -981,10 +981,10 @@
 			continue;
 		parport_unregister_device(lp_table[offset].dev);
 		devfs_remove("printers/%d", offset);
-		class_simple_device_remove(MKDEV(LP_MAJOR, offset));
+		class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
 	}
 	devfs_remove("printers");
-	class_simple_destroy(lp_class);
+	class_destroy(lp_class);
 }
 
 __setup("lp=", lp_setup);
diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c
--- a/drivers/char/mem.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/mem.c	2005-03-30 17:18:12 -08:00
@@ -849,7 +849,7 @@
 	{11,"kmsg",    S_IRUGO | S_IWUSR,           &kmsg_fops},
 };
 
-static struct class_simple *mem_class;
+static struct class *mem_class;
 
 static int __init chr_dev_init(void)
 {
@@ -858,10 +858,9 @@
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 
-	mem_class = class_simple_create(THIS_MODULE, "mem");
+	mem_class = class_create(THIS_MODULE, "mem");
 	for (i = 0; i < ARRAY_SIZE(devlist); i++) {
-		class_simple_device_add(mem_class,
-					MKDEV(MEM_MAJOR, devlist[i].minor),
+		class_device_create(mem_class, MKDEV(MEM_MAJOR, devlist[i].minor),
 					NULL, devlist[i].name);
 		devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor),
 				S_IFCHR | devlist[i].mode, devlist[i].name);
diff -Nru a/drivers/char/misc.c b/drivers/char/misc.c
--- a/drivers/char/misc.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/misc.c	2005-03-30 17:18:12 -08:00
@@ -177,10 +177,10 @@
 
 /* 
  * TODO for 2.7:
- *  - add a struct class_device to struct miscdevice and make all usages of
+ *  - add a struct kref to struct miscdevice and make all usages of
  *    them dynamic.
  */
-static struct class_simple *misc_class;
+static struct class *misc_class;
 
 static struct file_operations misc_fops = {
 	.owner		= THIS_MODULE,
@@ -238,8 +238,8 @@
 	}
 	dev = MKDEV(MISC_MAJOR, misc->minor);
 
-	misc->class = class_simple_device_add(misc_class, dev,
-					      misc->dev, misc->name);
+	misc->class = class_device_create(misc_class, dev, misc->dev,
+					  "%s", misc->name);
 	if (IS_ERR(misc->class)) {
 		err = PTR_ERR(misc->class);
 		goto out;
@@ -248,7 +248,7 @@
 	err = devfs_mk_cdev(dev, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, 
 			    misc->devfs_name);
 	if (err) {
-		class_simple_device_remove(dev);
+		class_device_destroy(misc_class, dev);
 		goto out;
 	}
 
@@ -281,7 +281,7 @@
 
 	down(&misc_sem);
 	list_del(&misc->list);
-	class_simple_device_remove(MKDEV(MISC_MAJOR, misc->minor));
+	class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
 	devfs_remove(misc->devfs_name);
 	if (i < DYNAMIC_MINORS && i>0) {
 		misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
@@ -302,7 +302,7 @@
 	if (ent)
 		ent->proc_fops = &misc_proc_fops;
 #endif
-	misc_class = class_simple_create(THIS_MODULE, "misc");
+	misc_class = class_create(THIS_MODULE, "misc");
 	if (IS_ERR(misc_class))
 		return PTR_ERR(misc_class);
 #ifdef CONFIG_MVME16x
@@ -323,7 +323,7 @@
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
 		       MISC_MAJOR);
-		class_simple_destroy(misc_class);
+		class_destroy(misc_class);
 		return -EIO;
 	}
 	return 0;
diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c
--- a/drivers/char/ppdev.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/ppdev.c	2005-03-30 17:18:12 -08:00
@@ -737,7 +737,7 @@
 	return mask;
 }
 
-static struct class_simple *ppdev_class;
+static struct class *ppdev_class;
 
 static struct file_operations pp_fops = {
 	.owner		= THIS_MODULE,
@@ -752,13 +752,13 @@
 
 static void pp_attach(struct parport *port)
 {
-	class_simple_device_add(ppdev_class, MKDEV(PP_MAJOR, port->number),
+	class_device_create(ppdev_class, MKDEV(PP_MAJOR, port->number),
 			NULL, "parport%d", port->number);
 }
 
 static void pp_detach(struct parport *port)
 {
-	class_simple_device_remove(MKDEV(PP_MAJOR, port->number));
+	class_device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
 }
 
 static struct parport_driver pp_driver = {
@@ -776,7 +776,7 @@
 			PP_MAJOR);
 		return -EIO;
 	}
-	ppdev_class = class_simple_create(THIS_MODULE, CHRDEV);
+	ppdev_class = class_create(THIS_MODULE, CHRDEV);
 	if (IS_ERR(ppdev_class)) {
 		err = PTR_ERR(ppdev_class);
 		goto out_chrdev;
@@ -798,7 +798,7 @@
 	for (i = 0; i < PARPORT_MAX; i++)
 		devfs_remove("parports/%d", i);
 	devfs_remove("parports");
-	class_simple_destroy(ppdev_class);
+	class_destroy(ppdev_class);
 out_chrdev:
 	unregister_chrdev(PP_MAJOR, CHRDEV);
 out:
@@ -813,7 +813,7 @@
 		devfs_remove("parports/%d", i);
 	parport_unregister_driver(&pp_driver);
 	devfs_remove("parports");
-	class_simple_destroy(ppdev_class);
+	class_destroy(ppdev_class);
 	unregister_chrdev (PP_MAJOR, CHRDEV);
 }
 
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/raw.c	2005-03-30 17:18:12 -08:00
@@ -27,7 +27,7 @@
 	int inuse;
 };
 
-static struct class_simple *raw_class;
+static struct class *raw_class;
 static struct raw_device_data raw_devices[MAX_RAW_MINORS];
 static DECLARE_MUTEX(raw_mutex);
 static struct file_operations raw_ctl_fops;	     /* forward declaration */
@@ -127,8 +127,8 @@
 
 static void bind_device(struct raw_config_request *rq)
 {
-	class_simple_device_remove(MKDEV(RAW_MAJOR, rq->raw_minor));
-	class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor),
+	class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor));
+	class_device_create(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor),
 				      NULL, "raw%d", rq->raw_minor);
 }
 
@@ -200,8 +200,8 @@
 			if (rq.block_major == 0 && rq.block_minor == 0) {
 				/* unbind */
 				rawdev->binding = NULL;
-				class_simple_device_remove(MKDEV(RAW_MAJOR,
-								rq.raw_minor));
+				class_device_destroy(raw_class,
+						MKDEV(RAW_MAJOR, rq.raw_minor));
 			} else {
 				rawdev->binding = bdget(dev);
 				if (rawdev->binding == NULL)
@@ -300,14 +300,14 @@
 		goto error;
 	}
 
-	raw_class = class_simple_create(THIS_MODULE, "raw");
+	raw_class = class_create(THIS_MODULE, "raw");
 	if (IS_ERR(raw_class)) {
 		printk(KERN_ERR "Error creating raw class.\n");
 		cdev_del(&raw_cdev);
 		unregister_chrdev_region(dev, MAX_RAW_MINORS);
 		goto error;
 	}
-	class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
+	class_device_create(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
 
 	devfs_mk_cdev(MKDEV(RAW_MAJOR, 0),
 		      S_IFCHR | S_IRUGO | S_IWUGO,
@@ -331,8 +331,8 @@
 		devfs_remove("raw/raw%d", i);
 	devfs_remove("raw/rawctl");
 	devfs_remove("raw");
-	class_simple_device_remove(MKDEV(RAW_MAJOR, 0));
-	class_simple_destroy(raw_class);
+	class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
+	class_destroy(raw_class);
 	cdev_del(&raw_cdev);
 	unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS);
 }
diff -Nru a/drivers/char/snsc.c b/drivers/char/snsc.c
--- a/drivers/char/snsc.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/snsc.c	2005-03-30 17:18:12 -08:00
@@ -357,6 +357,8 @@
 	.release =	scdrv_release,
 };
 
+static struct class *snsc_class;
+
 /*
  * scdrv_init
  *
@@ -372,7 +374,6 @@
 	char *devnamep;
 	struct sysctl_data_s *scd;
 	void *salbuf;
-	struct class_simple *snsc_class;
 	dev_t first_dev, dev;
 
 	if (alloc_chrdev_region(&first_dev, 0, numionodes,
@@ -381,7 +382,7 @@
 		       __FUNCTION__);
 		return -ENODEV;
 	}
-	snsc_class = class_simple_create(THIS_MODULE, SYSCTL_BASENAME);
+	snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
 
 	for (cnode = 0; cnode < numionodes; cnode++) {
 			geoid = cnodeid_get_geoid(cnode);
@@ -435,7 +436,7 @@
 				continue;
 			}
 
-			class_simple_device_add(snsc_class, dev, NULL,
+			class__device_create(snsc_class, dev, NULL,
 						"%s", devname);
 
 			ia64_sn_irtr_intr_enable(scd->scd_nasid,
diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c
--- a/drivers/char/stallion.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/stallion.c	2005-03-30 17:18:12 -08:00
@@ -719,7 +719,7 @@
 
 /*****************************************************************************/
 
-static struct class_simple *stallion_class;
+static struct class *stallion_class;
 
 /*
  *	Loadable module initialization stuff.
@@ -777,13 +777,13 @@
 	}
 	for (i = 0; i < 4; i++) {
 		devfs_remove("staliomem/%d", i);
-		class_simple_device_remove(MKDEV(STL_SIOMEMMAJOR, i));
+		class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
 	}
 	devfs_remove("staliomem");
 	if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
 		printk("STALLION: failed to un-register serial memory device, "
 			"errno=%d\n", -i);
-	class_simple_destroy(stallion_class);
+	class_destroy(stallion_class);
 
 	if (stl_tmpwritebuf != (char *) NULL)
 		kfree(stl_tmpwritebuf);
@@ -3090,12 +3090,12 @@
 		printk("STALLION: failed to register serial board device\n");
 	devfs_mk_dir("staliomem");
 
-	stallion_class = class_simple_create(THIS_MODULE, "staliomem");
+	stallion_class = class_create(THIS_MODULE, "staliomem");
 	for (i = 0; i < 4; i++) {
 		devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
 				S_IFCHR|S_IRUSR|S_IWUSR,
 				"staliomem/%d", i);
-		class_simple_device_add(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i);
+		class_device_create(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i);
 	}
 
 	stl_serial->owner = THIS_MODULE;
diff -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c
--- a/drivers/char/tipar.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/tipar.c	2005-03-30 17:18:12 -08:00
@@ -90,7 +90,7 @@
 static unsigned int tp_count;	/* tipar count */
 static unsigned long opened;	/* opened devices */
 
-static struct class_simple *tipar_class;
+static struct class *tipar_class;
 
 /* --- macros for parport access -------------------------------------- */
 
@@ -436,7 +436,7 @@
 		goto out;
 	}
 
-	class_simple_device_add(tipar_class, MKDEV(TIPAR_MAJOR,
+	class_device_create(tipar_class, MKDEV(TIPAR_MAJOR,
 			TIPAR_MINOR + nr), NULL, "par%d", nr);
 	/* Use devfs, tree: /dev/ticables/par/[0..2] */
 	err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr),
@@ -458,8 +458,8 @@
 	goto out;
 
 out_class:
-	class_simple_device_remove(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr));
-	class_simple_destroy(tipar_class);
+	class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr));
+	class_destroy(tipar_class);
 out:
 	return err;
 }
@@ -505,7 +505,7 @@
 	/* Use devfs with tree: /dev/ticables/par/[0..2] */
 	devfs_mk_dir("ticables/par");
 
-	tipar_class = class_simple_create(THIS_MODULE, "ticables");
+	tipar_class = class_create(THIS_MODULE, "ticables");
 	if (IS_ERR(tipar_class)) {
 		err = PTR_ERR(tipar_class);
 		goto out_chrdev;
@@ -539,10 +539,10 @@
 		if (table[i].dev == NULL)
 			continue;
 		parport_unregister_device(table[i].dev);
-		class_simple_device_remove(MKDEV(TIPAR_MAJOR, i));
+		class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
 		devfs_remove("ticables/par/%d", i);
 	}
-	class_simple_destroy(tipar_class);
+	class_destroy(tipar_class);
 	devfs_remove("ticables/par");
 
 	pr_info("tipar: module unloaded\n");
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/tty_io.c	2005-03-30 17:18:12 -08:00
@@ -2654,7 +2654,7 @@
 	tty->driver->write(tty, &ch, 1);
 }
 
-static struct class_simple *tty_class;
+static struct class *tty_class;
 
 /**
  * tty_register_device - register a tty device
@@ -2687,7 +2687,7 @@
 		pty_line_name(driver, index, name);
 	else
 		tty_line_name(driver, index, name);
-	class_simple_device_add(tty_class, dev, device, name);
+	class_device_create(tty_class, dev, device, name);
 }
 
 /**
@@ -2701,7 +2701,7 @@
 void tty_unregister_device(struct tty_driver *driver, unsigned index)
 {
 	devfs_remove("%s%d", driver->devfs_name, index + driver->name_base);
-	class_simple_device_remove(MKDEV(driver->major, driver->minor_start) + index);
+	class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index);
 }
 
 EXPORT_SYMBOL(tty_register_device);
@@ -2918,7 +2918,7 @@
 
 static int __init tty_class_init(void)
 {
-	tty_class = class_simple_create(THIS_MODULE, "tty");
+	tty_class = class_create(THIS_MODULE, "tty");
 	if (IS_ERR(tty_class))
 		return PTR_ERR(tty_class);
 	return 0;
@@ -2947,14 +2947,14 @@
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
 		panic("Couldn't register /dev/tty driver\n");
 	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty");
-	class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
+	class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
 
 	cdev_init(&console_cdev, &console_fops);
 	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
 		panic("Couldn't register /dev/console driver\n");
 	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console");
-	class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
+	class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
 
 #ifdef CONFIG_UNIX98_PTYS
 	cdev_init(&ptmx_cdev, &ptmx_fops);
@@ -2962,7 +2962,7 @@
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
 		panic("Couldn't register /dev/ptmx driver\n");
 	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx");
-	class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
+	class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 #endif
 
 #ifdef CONFIG_VT
@@ -2971,7 +2971,7 @@
 	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
 		panic("Couldn't register /dev/tty0 driver\n");
 	devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0");
-	class_simple_device_add(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+	class_device_create(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
 
 	vty_init();
 #endif
diff -Nru a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
--- a/drivers/char/vc_screen.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/char/vc_screen.c	2005-03-30 17:18:11 -08:00
@@ -474,7 +474,7 @@
 	.open		= vcs_open,
 };
 
-static struct class_simple *vc_class;
+static struct class *vc_class;
 
 void vcs_make_devfs(struct tty_struct *tty)
 {
@@ -484,26 +484,26 @@
 	devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129),
 			S_IFCHR|S_IRUSR|S_IWUSR,
 			"vcc/a%u", tty->index + 1);
-	class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1);
-	class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1);
+	class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1);
+	class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1);
 }
 void vcs_remove_devfs(struct tty_struct *tty)
 {
 	devfs_remove("vcc/%u", tty->index + 1);
 	devfs_remove("vcc/a%u", tty->index + 1);
-	class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 1));
-	class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 129));
+	class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
+	class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
 }
 
 int __init vcs_init(void)
 {
 	if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
 		panic("unable to get major %d for vcs device", VCS_MAJOR);
-	vc_class = class_simple_create(THIS_MODULE, "vc");
+	vc_class = class_create(THIS_MODULE, "vc");
 
 	devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0");
 	devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0");
-	class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
-	class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
+	class_device_create(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
+	class_device_create(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
 	return 0;
 }
diff -Nru a/drivers/char/viotape.c b/drivers/char/viotape.c
--- a/drivers/char/viotape.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/char/viotape.c	2005-03-30 17:18:12 -08:00
@@ -237,7 +237,7 @@
 
 static struct mtget viomtget[VIOTAPE_MAX_TAPE];
 
-static struct class_simple *tape_class;
+static struct class *tape_class;
 
 static struct device *tape_device[VIOTAPE_MAX_TAPE];
 
@@ -956,9 +956,9 @@
 	state[i].cur_part = 0;
 	for (j = 0; j < MAX_PARTITIONS; ++j)
 		state[i].part_stat_rwi[j] = VIOT_IDLE;
-	class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL,
+	class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL,
 			"iseries!vt%d", i);
-	class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+	class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80),
 			NULL, "iseries!nvt%d", i);
 	devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR,
 			"iseries/vt%d", i);
@@ -980,8 +980,8 @@
 	devfs_remove("iseries/nvt%d", i);
 	devfs_remove("iseries/vt%d", i);
 	devfs_unregister_tape(state[i].dev_handle);
-	class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80));
-	class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i));
+	class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
+	class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
 	return 0;
 }
 
@@ -1045,7 +1045,7 @@
 		goto clear_handler;
 	}
 
-	tape_class = class_simple_create(THIS_MODULE, "tape");
+	tape_class = class_create(THIS_MODULE, "tape");
 	if (IS_ERR(tape_class)) {
 		printk(VIOTAPE_KERN_WARN "Unable to allocat class\n");
 		ret = PTR_ERR(tape_class);
@@ -1070,7 +1070,7 @@
 	return 0;
 
 unreg_class:
-	class_simple_destroy(tape_class);
+	class_destroy(tape_class);
 unreg_chrdev:
 	unregister_chrdev(VIOTAPE_MAJOR, "viotape");
 clear_handler:
@@ -1110,7 +1110,7 @@
 
 	remove_proc_entry("iSeries/viotape", NULL);
 	vio_unregister_driver(&viotape_driver);
-	class_simple_destroy(tape_class);
+	class_destroy(tape_class);
 	ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");
 	if (ret < 0)
 		printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n",
diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/ieee1394/dv1394.c	2005-03-30 17:18:12 -08:00
@@ -2343,8 +2343,8 @@
 			dv1394_un_init(video);
 	} while (video != NULL);
 
-	class_simple_device_remove(MKDEV(
-		IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
+	class_device_destroy(hpsb_protocol_class,
+		MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
 	devfs_remove("ieee1394/dv/host%d/NTSC", id);
 	devfs_remove("ieee1394/dv/host%d/PAL", id);
 	devfs_remove("ieee1394/dv/host%d", id);
@@ -2361,7 +2361,7 @@
 
 	ohci = (struct ti_ohci *)host->hostdata;
 
-	class_simple_device_add(hpsb_protocol_class, MKDEV(
+	class_device_create(hpsb_protocol_class, MKDEV(
 		IEEE1394_MAJOR,	IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), 
 		NULL, "dv1394-%d", id);
 	devfs_mk_dir("ieee1394/dv/host%d", id);
diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/ieee1394/ieee1394_core.c	2005-03-30 17:18:11 -08:00
@@ -67,7 +67,7 @@
 
 /* Some globals used */
 const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
-struct class_simple *hpsb_protocol_class;
+struct class *hpsb_protocol_class;
 
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 static void dump_packet(const char *text, quadlet_t *data, int size)
@@ -1121,7 +1121,7 @@
 	if (ret < 0)
 		goto release_all_bus;
 
-	hpsb_protocol_class = class_simple_create(THIS_MODULE, "ieee1394_protocol");
+	hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol");
 	if (IS_ERR(hpsb_protocol_class)) {
 		ret = PTR_ERR(hpsb_protocol_class);
 		goto release_class_host;
@@ -1159,7 +1159,7 @@
 cleanup_csr:
 	cleanup_csr();
 release_class_protocol:
-	class_simple_destroy(hpsb_protocol_class);
+	class_destroy(hpsb_protocol_class);
 release_class_host:
 	class_unregister(&hpsb_host_class);
 release_all_bus:
@@ -1189,7 +1189,7 @@
 
 	cleanup_csr();
 
-	class_simple_destroy(hpsb_protocol_class);
+	class_destroy(hpsb_protocol_class);
 	class_unregister(&hpsb_host_class);
 	for (i = 0; fw_bus_attrs[i]; i++)
 		bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
diff -Nru a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
--- a/drivers/ieee1394/ieee1394_core.h	2005-03-30 17:18:11 -08:00
+++ b/drivers/ieee1394/ieee1394_core.h	2005-03-30 17:18:11 -08:00
@@ -223,6 +223,7 @@
 /* Our sysfs bus entry */
 extern struct bus_type ieee1394_bus_type;
 extern struct class hpsb_host_class;
-extern struct class_simple *hpsb_protocol_class;
+extern struct class *hpsb_protocol_class;
 
 #endif /* _IEEE1394_CORE_H */
+
diff -Nru a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
--- a/drivers/ieee1394/nodemgr.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/ieee1394/nodemgr.c	2005-03-30 17:18:12 -08:00
@@ -695,14 +695,15 @@
 	put_device(dev);
 }
 
+static int __nodemgr_remove_host_dev(struct device *dev, void *data)
+{
+	nodemgr_remove_ne(container_of(dev, struct node_entry, device));
+	return 0;
+}
 
 static void nodemgr_remove_host_dev(struct device *dev)
 {
-	struct device *ne_dev, *next;
-
-	list_for_each_entry_safe(ne_dev, next, &dev->children, node)
-		nodemgr_remove_ne(container_of(ne_dev, struct node_entry, device));
-
+	device_for_each_child(dev, NULL, __nodemgr_remove_host_dev);
 	sysfs_remove_link(&dev->kobj, "irm_id");
 	sysfs_remove_link(&dev->kobj, "busmgr_id");
 	sysfs_remove_link(&dev->kobj, "host_id");
diff -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
--- a/drivers/ieee1394/raw1394.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/ieee1394/raw1394.c	2005-03-30 17:18:11 -08:00
@@ -2901,7 +2901,7 @@
 
 	hpsb_register_highlevel(&raw1394_highlevel);
 
-	if (IS_ERR(class_simple_device_add(hpsb_protocol_class, MKDEV(
+	if (IS_ERR(class_device_create(hpsb_protocol_class, MKDEV(
 		IEEE1394_MAJOR,	IEEE1394_MINOR_BLOCK_RAW1394 * 16), 
 		NULL, RAW1394_DEVICE_NAME))) {
 		ret = -EFAULT;
@@ -2934,8 +2934,8 @@
 
 out_dev:
 	devfs_remove(RAW1394_DEVICE_NAME);
-	class_simple_device_remove(MKDEV(
-		IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16));
+	class_device_destroy(hpsb_protocol_class, 
+		MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16));
 out_unreg:
 	hpsb_unregister_highlevel(&raw1394_highlevel);
 out:
@@ -2944,8 +2944,8 @@
 
 static void __exit cleanup_raw1394(void)
 {
-	class_simple_device_remove(MKDEV(
-		IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16));
+	class_device_destroy(hpsb_protocol_class,
+		MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16));
 	cdev_del(&raw1394_cdev);
 	devfs_remove(RAW1394_DEVICE_NAME);
 	hpsb_unregister_highlevel(&raw1394_highlevel);
diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/ieee1394/video1394.c	2005-03-30 17:18:11 -08:00
@@ -1323,7 +1323,7 @@
 	hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
 
 	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
-	class_simple_device_add(hpsb_protocol_class, MKDEV(
+	class_device_create(hpsb_protocol_class, MKDEV(
 		IEEE1394_MAJOR,	minor), 
 		NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
 	devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor),
@@ -1337,7 +1337,7 @@
 	struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
 
 	if (ohci) {
-		class_simple_device_remove(MKDEV(IEEE1394_MAJOR, 
+		class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR, 
 			IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
 		devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
 	}
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/input/evdev.c	2005-03-30 17:18:12 -08:00
@@ -431,9 +431,9 @@
 
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor);
-	class_simple_device_add(input_class,
-				MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
-				dev->dev, "event%d", minor);
+	class_device_create(input_class,
+			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
+			dev->dev, "event%d", minor);
 
 	return &evdev->handle;
 }
@@ -443,7 +443,8 @@
 	struct evdev *evdev = handle->private;
 	struct evdev_list *list;
 
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
+	class_device_destroy(input_class,
+			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
 	devfs_remove("input/event%d", evdev->minor);
 	evdev->exist = 0;
 
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/input/input.c	2005-03-30 17:18:12 -08:00
@@ -702,13 +702,13 @@
 static inline int input_proc_init(void) { return 0; }
 #endif
 
-struct class_simple *input_class;
+struct class *input_class;
 
 static int __init input_init(void)
 {
 	int retval = -ENOMEM;
 
-	input_class = class_simple_create(THIS_MODULE, "input");
+	input_class = class_create(THIS_MODULE, "input");
 	if (IS_ERR(input_class))
 		return PTR_ERR(input_class);
 	input_proc_init();
@@ -718,7 +718,7 @@
 		remove_proc_entry("devices", proc_bus_input_dir);
 		remove_proc_entry("handlers", proc_bus_input_dir);
 		remove_proc_entry("input", proc_bus);
-		class_simple_destroy(input_class);
+		class_destroy(input_class);
 		return retval;
 	}
 
@@ -728,7 +728,7 @@
 		remove_proc_entry("handlers", proc_bus_input_dir);
 		remove_proc_entry("input", proc_bus);
 		unregister_chrdev(INPUT_MAJOR, "input");
-		class_simple_destroy(input_class);
+		class_destroy(input_class);
 	}
 	return retval;
 }
@@ -741,7 +741,7 @@
 
 	devfs_remove("input");
 	unregister_chrdev(INPUT_MAJOR, "input");
-	class_simple_destroy(input_class);
+	class_destroy(input_class);
 }
 
 subsys_initcall(input_init);
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/input/joydev.c	2005-03-30 17:18:12 -08:00
@@ -452,9 +452,9 @@
 
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor);
-	class_simple_device_add(input_class,
-				MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
-				dev->dev, "js%d", minor);
+	class_device_create(input_class,
+			MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
+			dev->dev, "js%d", minor);
 
 	return &joydev->handle;
 }
@@ -464,7 +464,7 @@
 	struct joydev *joydev = handle->private;
 	struct joydev_list *list;
 
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
+	class_device_destroy(input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
 	devfs_remove("input/js%d", joydev->minor);
 	joydev->exist = 0;
 
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/input/mousedev.c	2005-03-30 17:18:12 -08:00
@@ -642,9 +642,9 @@
 
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor);
-	class_simple_device_add(input_class,
-				MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
-				dev->dev, "mouse%d", minor);
+	class_device_create(input_class,
+			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
+			dev->dev, "mouse%d", minor);
 
 	return &mousedev->handle;
 }
@@ -654,7 +654,8 @@
 	struct mousedev *mousedev = handle->private;
 	struct mousedev_list *list;
 
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
+	class_device_destroy(input_class,
+			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
 	devfs_remove("input/mouse%d", mousedev->minor);
 	mousedev->exist = 0;
 
@@ -730,8 +731,8 @@
 
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/mice");
-	class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
-				NULL, "mice");
+	class_device_create(input_class,
+			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice");
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
 	if (!(psaux_registered = !misc_register(&psaux_mouse)))
@@ -750,7 +751,8 @@
 		misc_deregister(&psaux_mouse);
 #endif
 	devfs_remove("input/mice");
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX));
+	class_device_destroy(input_class,
+			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX));
 	input_unregister_handler(&mousedev_handler);
 }
 
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/input/tsdev.c	2005-03-30 17:18:12 -08:00
@@ -414,9 +414,9 @@
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor);
-	class_simple_device_add(input_class,
-				MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
-				dev->dev, "ts%d", minor);
+	class_device_create(input_class,
+			MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
+			dev->dev, "ts%d", minor);
 
 	return &tsdev->handle;
 }
@@ -426,7 +426,8 @@
 	struct tsdev *tsdev = handle->private;
 	struct tsdev_list *list;
 
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
+	class_device_destroy(input_class,
+			MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
 	devfs_remove("input/ts%d", tsdev->minor);
 	devfs_remove("input/tsraw%d", tsdev->minor);
 	tsdev->exist = 0;
diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
--- a/drivers/isdn/capi/capi.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/isdn/capi/capi.c	2005-03-30 17:18:12 -08:00
@@ -58,7 +58,7 @@
 
 /* -------- driver information -------------------------------------- */
 
-static struct class_simple *capi_class;
+static struct class *capi_class;
 
 int capi_major = 68;		/* allocated */
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -1499,20 +1499,20 @@
 		return -EIO;
 	}
 
-	capi_class = class_simple_create(THIS_MODULE, "capi");
+	capi_class = class_create(THIS_MODULE, "capi");
 	if (IS_ERR(capi_class)) {
 		unregister_chrdev(capi_major, "capi20");
 		return PTR_ERR(capi_class);
 	}
 
-	class_simple_device_add(capi_class, MKDEV(capi_major, 0), NULL, "capi");
+	class_device_create(capi_class, MKDEV(capi_major, 0), NULL, "capi");
 	devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
 			"isdn/capi20");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 	if (capinc_tty_init() < 0) {
-		class_simple_device_remove(MKDEV(capi_major, 0));
-		class_simple_destroy(capi_class);
+		class_device_destroy(capi_class, MKDEV(capi_major, 0));
+		class_destroy(capi_class);
 		unregister_chrdev(capi_major, "capi20");
 		return -ENOMEM;
 	}
@@ -1539,8 +1539,8 @@
 {
 	proc_exit();
 
-	class_simple_device_remove(MKDEV(capi_major, 0));
-	class_simple_destroy(capi_class);
+	class_device_destroy(capi_class, MKDEV(capi_major, 0));
+	class_destroy(capi_class);
 	unregister_chrdev(capi_major, "capi20");
 	devfs_remove("isdn/capi20");
 
diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
--- a/drivers/macintosh/adb.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/macintosh/adb.c	2005-03-30 17:18:12 -08:00
@@ -77,7 +77,7 @@
 	NULL
 };
 
-static struct class_simple *adb_dev_class;
+static struct class *adb_dev_class;
 
 struct adb_driver *adb_controller;
 struct notifier_block *adb_client_list = NULL;
@@ -902,9 +902,8 @@
 
 	devfs_mk_cdev(MKDEV(ADB_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "adb");
 
-	adb_dev_class = class_simple_create(THIS_MODULE, "adb");
-	if (IS_ERR(adb_dev_class)) {
+	adb_dev_class = class_create(THIS_MODULE, "adb");
+	if (IS_ERR(adb_dev_class))
 		return;
-	}
-	class_simple_device_add(adb_dev_class, MKDEV(ADB_MAJOR, 0), NULL, "adb");
+	class_device_create(adb_dev_class, MKDEV(ADB_MAJOR, 0), NULL, "adb");
 }
diff -Nru a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
--- a/drivers/media/dvb/dvb-core/dvbdev.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/media/dvb/dvb-core/dvbdev.c	2005-03-30 17:18:11 -08:00
@@ -56,8 +56,7 @@
 #define nums2minor(num,type,id)	((num << 6) | (id << 4) | type)
 #define MAX_DVB_MINORS		(DVB_MAX_ADAPTERS*64)
 
-struct class_simple *dvb_class;
-EXPORT_SYMBOL(dvb_class);
+static struct class *dvb_class;
 
 static struct dvb_device* dvbdev_find_device (int minor)
 {
@@ -236,8 +235,8 @@
 			S_IFCHR | S_IRUSR | S_IWUSR,
 			"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
 
-	class_simple_device_add(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-				NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+	class_device_create(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+			    NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
 
 	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
 		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
@@ -256,7 +255,7 @@
 	devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
 			dnames[dvbdev->type], dvbdev->id);
 
-	class_simple_device_remove(MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
+	class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
 					dvbdev->type, dvbdev->id)));
 
 	list_del (&dvbdev->list_head);
@@ -419,7 +418,7 @@
 
 	devfs_mk_dir("dvb");
 
-	dvb_class = class_simple_create(THIS_MODULE, "dvb");
+	dvb_class = class_create(THIS_MODULE, "dvb");
 	if (IS_ERR(dvb_class)) {
 		retval = PTR_ERR(dvb_class);
 		goto error;
@@ -436,7 +435,7 @@
 static void __exit exit_dvbdev(void)
 {
         devfs_remove("dvb");
-	class_simple_destroy(dvb_class);
+	class_destroy(dvb_class);
 	cdev_del(&dvb_device_cdev);
         unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
 }
diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
--- a/drivers/net/ppp_generic.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/net/ppp_generic.c	2005-03-30 17:18:12 -08:00
@@ -273,7 +273,7 @@
 static int ppp_disconnect_channel(struct channel *pch);
 static void ppp_destroy_channel(struct channel *pch);
 
-static struct class_simple *ppp_class;
+static struct class *ppp_class;
 
 /* Translates a PPP protocol number to a NP index (NP == network protocol) */
 static inline int proto_to_npindex(int proto)
@@ -858,12 +858,12 @@
 	printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n");
 	err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
 	if (!err) {
-		ppp_class = class_simple_create(THIS_MODULE, "ppp");
+		ppp_class = class_create(THIS_MODULE, "ppp");
 		if (IS_ERR(ppp_class)) {
 			err = PTR_ERR(ppp_class);
 			goto out_chrdev;
 		}
-		class_simple_device_add(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
+		class_device_create(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
 		err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0),
 				S_IFCHR|S_IRUSR|S_IWUSR, "ppp");
 		if (err)
@@ -876,8 +876,8 @@
 	return err;
 
 out_class:
-	class_simple_device_remove(MKDEV(PPP_MAJOR,0));
-	class_simple_destroy(ppp_class);
+	class_device_destroy(ppp_class, MKDEV(PPP_MAJOR,0));
+	class_destroy(ppp_class);
 out_chrdev:
 	unregister_chrdev(PPP_MAJOR, "ppp");
 	goto out;
@@ -2615,8 +2615,8 @@
 	if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
 		printk(KERN_ERR "PPP: failed to unregister PPP device\n");
 	devfs_remove("ppp");
-	class_simple_device_remove(MKDEV(PPP_MAJOR, 0));
-	class_simple_destroy(ppp_class);
+	class_device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
+	class_destroy(ppp_class);
 }
 
 /*
diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
--- a/drivers/net/wan/cosa.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/net/wan/cosa.c	2005-03-30 17:18:11 -08:00
@@ -235,7 +235,7 @@
 static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };
 
 /* for class stuff*/
-static struct class_simple *cosa_class;
+static struct class *cosa_class;
 
 #ifdef MODULE
 module_param_array(io, int, NULL, 0);
@@ -394,19 +394,19 @@
 		goto out;
 	}
 	devfs_mk_dir("cosa");
-	cosa_class = class_simple_create(THIS_MODULE, "cosa");
+	cosa_class = class_create(THIS_MODULE, "cosa");
 	if (IS_ERR(cosa_class)) {
 		err = PTR_ERR(cosa_class);
 		goto out_chrdev;
 	}
 	for (i=0; i<nr_cards; i++) {
-		class_simple_device_add(cosa_class, MKDEV(cosa_major, i),
+		class_device_create(cosa_class, MKDEV(cosa_major, i),
 				NULL, "cosa%d", i);
 		err = devfs_mk_cdev(MKDEV(cosa_major, i),
 				S_IFCHR|S_IRUSR|S_IWUSR,
 				"cosa/%d", i);
 		if (err) {
-			class_simple_device_remove(MKDEV(cosa_major, i));
+			class_device_destroy(cosa_class, MKDEV(cosa_major, i));
 			goto out_chrdev;		
 		}
 	}
@@ -427,10 +427,10 @@
 	printk(KERN_INFO "Unloading the cosa module\n");
 
 	for (i=0; i<nr_cards; i++) {
-		class_simple_device_remove(MKDEV(cosa_major, i));
+		class_device_destroy(cosa_class, MKDEV(cosa_major, i));
 		devfs_remove("cosa/%d", i);
 	}
-	class_simple_destroy(cosa_class);
+	class_destroy(cosa_class);
 	devfs_remove("cosa");
 	for (cosa=cosa_cards; nr_cards--; cosa++) {
 		/* Clean up the per-channel data */
diff -Nru a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
--- a/drivers/pci/pcie/portdrv_core.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/pci/pcie/portdrv_core.c	2005-03-30 17:18:12 -08:00
@@ -232,9 +232,6 @@
 	/* Initialize generic device interface */
 	device = &dev->device;
 	memset(device, 0, sizeof(struct device));
-	INIT_LIST_HEAD(&device->node);
-	INIT_LIST_HEAD(&device->children);
-	INIT_LIST_HEAD(&device->bus_list);
 	device->bus = &pcie_port_bus_type;
 	device->driver = NULL;
 	device->driver_data = NULL; 
@@ -317,84 +314,71 @@
 }
 
 #ifdef CONFIG_PM
-int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
+
+static int suspend_iter(struct device *dev, void *data)
 {
-	struct list_head 		*head, *tmp;
-	struct device 			*parent, *child;
-	struct device_driver 		*driver;
 	struct pcie_port_service_driver *service_driver;
+	u32 state = (u32)data;
 
-	parent = &dev->dev;
-	head = &parent->children;
-	tmp = head->next;
-	while (head != tmp) {
-		child = container_of(tmp, struct device, node);
-		tmp = tmp->next;
-		if (child->bus != &pcie_port_bus_type)
-			continue;
-		driver = child->driver;
-		if (!driver)
-			continue;
-		service_driver = to_service_driver(driver);
-		if (service_driver->suspend)  
-			service_driver->suspend(to_pcie_device(child), state);
+	if ((dev->bus == &pcie_port_bus_type) && 
+	    (dev->driver)) {
+		service_driver = to_service_driver(dev->driver);
+		if (service_driver->suspend)
+			service_driver->suspend(to_pcie_device(dev), state);
 	}
+	return 0;
+}
+
+int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
+{
+	device_for_each_child(&dev->dev, (void *)state, suspend_iter);
 	return 0; 
 }
 
-int pcie_port_device_resume(struct pci_dev *dev) 
-{ 
-	struct list_head 		*head, *tmp;
-	struct device 			*parent, *child;
-	struct device_driver 		*driver;
+static int resume_iter(struct device *dev, void *data)
+{
 	struct pcie_port_service_driver *service_driver;
 
-	parent = &dev->dev;
-	head = &parent->children;
-	tmp = head->next;
-	while (head != tmp) {
-		child = container_of(tmp, struct device, node);
-		tmp = tmp->next;
-		if (child->bus != &pcie_port_bus_type)
-			continue;
-		driver = child->driver;
-		if (!driver)
-			continue;
-		service_driver = to_service_driver(driver);
-		if (service_driver->resume)  
-			service_driver->resume(to_pcie_device(child));
+	if ((dev->bus == &pcie_port_bus_type) && 
+	    (dev->driver)) {
+		service_driver = to_service_driver(dev->driver);
+		if (service_driver->resume)
+			service_driver->resume(to_pcie_device(dev));
 	}
-	return 0; 
+	return 0;
+}
 
+int pcie_port_device_resume(struct pci_dev *dev) 
+{ 
+	device_for_each_child(&dev->dev, NULL, resume_iter);
+	return 0; 
 }
 #endif
 
-void pcie_port_device_remove(struct pci_dev *dev)
+static int remove_iter(struct device *dev, void *data)
 {
-	struct list_head 		*head, *tmp;
-	struct device 			*parent, *child;
-	struct device_driver 		*driver;
 	struct pcie_port_service_driver *service_driver;
-	int interrupt_mode = PCIE_PORT_INTx_MODE;
+	int *interrupt_mode = data;
 
-	parent = &dev->dev;
-	head = &parent->children;
-	tmp = head->next;
-	while (head != tmp) {
-		child = container_of(tmp, struct device, node);
-		tmp = tmp->next;
-		if (child->bus != &pcie_port_bus_type)
-			continue;
-		driver = child->driver;
-		if (driver) { 
-			service_driver = to_service_driver(driver);
+	if (dev->bus == &pcie_port_bus_type) {
+		if (dev->driver) {
+			service_driver = to_service_driver(dev->driver);
 			if (service_driver->remove)  
-				service_driver->remove(to_pcie_device(child));
+				service_driver->remove(to_pcie_device(dev));
 		}
-		interrupt_mode = (to_pcie_device(child))->interrupt_mode;
-		put_device(child);
-		device_unregister(child);
+		*interrupt_mode = (to_pcie_device(dev))->interrupt_mode;
+		put_device(dev);
+		device_unregister(dev);
 	}
+	return 0;
+}
+
+void pcie_port_device_remove(struct pci_dev *dev)
+{
+	int interrupt_mode = PCIE_PORT_INTx_MODE;
+
+	device_for_each_child(&dev->dev, &interrupt_mode, remove_iter);
+
 	/* Switch to INTx by default if MSI enabled */
 	if (interrupt_mode == PCIE_PORT_MSIX_MODE)
 		pci_disable_msix(dev);
diff -Nru a/drivers/pnp/driver.c b/drivers/pnp/driver.c
--- a/drivers/pnp/driver.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/pnp/driver.c	2005-03-30 17:18:12 -08:00
@@ -160,10 +160,16 @@
 };
 
 
+static int count_devices(struct device * dev, void * c)
+{
+	int * count = c;
+	(*count)++;
+	return 0;
+}
+
 int pnp_register_driver(struct pnp_driver *drv)
 {
 	int count;
-	struct list_head *pos;
 
 	pnp_dbg("the driver '%s' has been registered", drv->name);
 
@@ -177,9 +183,7 @@
 	/* get the number of initial matches */
 	if (count >= 0){
 		count = 0;
-		list_for_each(pos,&drv->driver.devices){
-			count++;
-		}
+		driver_for_each_device(&drv->driver, NULL, &count, count_devices);
 	}
 	return count;
 }
diff -Nru a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
--- a/drivers/s390/char/tape_class.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/s390/char/tape_class.c	2005-03-30 17:18:12 -08:00
@@ -16,7 +16,7 @@
 );
 MODULE_LICENSE("GPL");
 
-struct class_simple *tape_class;
+static struct class *tape_class;
 
 /*
  * Register a tape device and return a pointer to the cdev structure.
@@ -70,7 +70,7 @@
 	if (rc)
 		goto fail_with_cdev;
 
-	tcd->class_device = class_simple_device_add(
+	tcd->class_device = class_device_create(
 				tape_class,
 				tcd->char_device->dev,
 				device,
@@ -101,7 +101,7 @@
 			&tcd->class_device->dev->kobj,
 			tcd->mode_name
 		);
-		class_simple_device_remove(tcd->char_device->dev);
+		class_device_destroy(tape_class, tcd->char_device->dev);
 		cdev_del(tcd->char_device);
 		kfree(tcd);
 	}
@@ -111,14 +111,14 @@
 
 static int __init tape_init(void)
 {
-	tape_class = class_simple_create(THIS_MODULE, "tape390");
+	tape_class = class_create(THIS_MODULE, "tape390");
 
 	return 0;
 }
 
 static void __exit tape_exit(void)
 {
-	class_simple_destroy(tape_class);
+	class_destroy(tape_class);
 	tape_class = NULL;
 }
 
diff -Nru a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
--- a/drivers/s390/char/vmlogrdr.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/s390/char/vmlogrdr.c	2005-03-30 17:18:12 -08:00
@@ -703,7 +703,7 @@
 	.attrs = vmlogrdr_attrs,
 };
 
-static struct class_simple *vmlogrdr_class;
+static struct class *vmlogrdr_class;
 static struct device_driver vmlogrdr_driver = {
 	.name = "vmlogrdr",
 	.bus  = &iucv_bus,
@@ -727,7 +727,7 @@
 		goto unregdriver;
 	}
 
-	vmlogrdr_class = class_simple_create(THIS_MODULE, "vmlogrdr");
+	vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
 	if (IS_ERR(vmlogrdr_class)) {
 		printk(KERN_ERR "vmlogrdr: failed to create class.\n");
 		ret=PTR_ERR(vmlogrdr_class);
@@ -746,7 +746,7 @@
 
 static void
 vmlogrdr_unregister_driver(void) {
-	class_simple_destroy(vmlogrdr_class);
+	class_destroy(vmlogrdr_class);
 	vmlogrdr_class = NULL;
 	driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
 	driver_unregister(&vmlogrdr_driver);
@@ -786,7 +786,7 @@
 		device_unregister(dev);
 		return ret;
 	}
-	priv->class_device = class_simple_device_add(
+	priv->class_device = class_device_create(
 				vmlogrdr_class,
 				MKDEV(vmlogrdr_major, priv->minor_num),
 				dev,
@@ -806,7 +806,7 @@
 
 static int
 vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
-	class_simple_device_remove(MKDEV(vmlogrdr_major, priv->minor_num));
+	class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
 	if (priv->device != NULL) {
 		sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
 		device_unregister(priv->device);
diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c
--- a/drivers/scsi/osst.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/scsi/osst.c	2005-03-30 17:18:12 -08:00
@@ -5608,13 +5608,13 @@
 
 CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
 
-static struct class_simple * osst_sysfs_class;
+static struct class *osst_sysfs_class;
 
 static int osst_sysfs_valid = 0;
 
 static void osst_sysfs_init(void)
 {
-	osst_sysfs_class = class_simple_create(THIS_MODULE, "onstream_tape");
+	osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
 	if ( IS_ERR(osst_sysfs_class) )
 		printk(KERN_WARNING "osst :W: Unable to register sysfs class\n");
 	else
@@ -5627,7 +5627,7 @@
 
 	if (!osst_sysfs_valid) return;
 
-	osst_class_member = class_simple_device_add(osst_sysfs_class, dev, device, "%s", name);
+	osst_class_member = class_device_create(osst_sysfs_class, dev, device, "%s", name);
 	if (IS_ERR(osst_class_member)) {
 		printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
 		return;
@@ -5645,13 +5645,13 @@
 {
 	if (!osst_sysfs_valid) return; 
 
-	class_simple_device_remove(dev);
+	class_device_destroy(osst_sysfs_class, dev);
 }
 
 static void osst_sysfs_cleanup(void)
 {
 	if (osst_sysfs_valid) {
-		class_simple_destroy(osst_sysfs_class);
+		class_destroy(osst_sysfs_class);
 		osst_sysfs_valid = 0;
 	}
 }
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/scsi/scsi_sysfs.c	2005-03-30 17:18:11 -08:00
@@ -666,6 +666,13 @@
 	scsi_target_reap(starget);
 }
 
+static int __remove_child (struct device * dev, void * data)
+{
+	if (scsi_is_target_device(dev))
+		__scsi_remove_target(to_scsi_target(dev));
+	return 0;
+}
+
 /**
  * scsi_remove_target - try to remove a target and all its devices
  * @dev: generic starget or parent of generic stargets to be removed
@@ -676,7 +683,7 @@
  */
 void scsi_remove_target(struct device *dev)
 {
-	struct device *rdev, *idev, *next;
+	struct device *rdev;
 
 	if (scsi_is_target_device(dev)) {
 		__scsi_remove_target(to_scsi_target(dev));
@@ -684,10 +691,7 @@
 	}
 
 	rdev = get_device(dev);
-	list_for_each_entry_safe(idev, next, &dev->children, node) {
-		if (scsi_is_target_device(idev))
-			__scsi_remove_target(to_scsi_target(idev));
-	}
+	device_for_each_child(dev, NULL, __remove_child);
 	put_device(rdev);
 }
 EXPORT_SYMBOL(scsi_remove_target);
diff -Nru a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
--- a/drivers/scsi/scsi_transport_spi.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/scsi/scsi_transport_spi.c	2005-03-30 17:18:12 -08:00
@@ -254,17 +254,21 @@
 spi_transport_rd_attr(rti, "%d\n");
 spi_transport_rd_attr(pcomp_en, "%d\n");
 
+/* we only care about the first child device so we return 1 */
+static int child_iter(struct device *dev, void *data)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+
+	spi_dv_device(sdev);
+	return 1;
+}
+
 static ssize_t
 store_spi_revalidate(struct class_device *cdev, const char *buf, size_t count)
 {
 	struct scsi_target *starget = transport_class_to_starget(cdev);
 
-	/* FIXME: we're relying on an awful lot of device internals
-	 * here.  We really need a function to get the first available
-	 * child */
-	struct device *dev = container_of(starget->dev.children.next, struct device, node);
-	struct scsi_device *sdev = to_scsi_device(dev);
-	spi_dv_device(sdev);
+	device_for_each_child(&starget->dev, NULL, child_iter);
 	return count;
 }
 static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate);
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/scsi/sg.c	2005-03-30 17:18:12 -08:00
@@ -1372,7 +1372,7 @@
 	.fasync = sg_fasync,
 };
 
-static struct class_simple * sg_sysfs_class;
+static struct class *sg_sysfs_class;
 
 static int sg_sysfs_valid = 0;
 
@@ -1493,13 +1493,13 @@
 	if (sg_sysfs_valid) {
 		struct class_device * sg_class_member;
 
-		sg_class_member = class_simple_device_add(sg_sysfs_class, 
+		sg_class_member = class_device_create(sg_sysfs_class, 
 				MKDEV(SCSI_GENERIC_MAJOR, k), 
 				cl_dev->dev, "%s", 
 				disk->disk_name);
 		if (IS_ERR(sg_class_member))
 			printk(KERN_WARNING "sg_add: "
-				"class_simple_device_add failed\n");
+				"class_device_create failed\n");
 		class_set_devdata(sg_class_member, sdp);
 		error = sysfs_create_link(&scsidp->sdev_gendev.kobj, 
 					  &sg_class_member->kobj, "generic");
@@ -1578,7 +1578,7 @@
 
 	if (sdp) {
 		sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
-		class_simple_device_remove(MKDEV(SCSI_GENERIC_MAJOR, k));
+		class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k));
 		cdev_del(sdp->cdev);
 		sdp->cdev = NULL;
 		devfs_remove("%s/generic", scsidp->devfs_name);
@@ -1619,7 +1619,7 @@
 				    SG_MAX_DEVS, "sg");
 	if (rc)
 		return rc;
-        sg_sysfs_class = class_simple_create(THIS_MODULE, "scsi_generic");
+        sg_sysfs_class = class_create(THIS_MODULE, "scsi_generic");
         if ( IS_ERR(sg_sysfs_class) ) {
 		rc = PTR_ERR(sg_sysfs_class);
 		goto err_out;
@@ -1632,7 +1632,7 @@
 #endif				/* CONFIG_SCSI_PROC_FS */
 		return 0;
 	}
-	class_simple_destroy(sg_sysfs_class);
+	class_destroy(sg_sysfs_class);
 err_out:
 	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS);
 	return rc;
@@ -1645,7 +1645,7 @@
 	sg_proc_cleanup();
 #endif				/* CONFIG_SCSI_PROC_FS */
 	scsi_unregister_interface(&sg_interface);
-	class_simple_destroy(sg_sysfs_class);
+	class_destroy(sg_sysfs_class);
 	sg_sysfs_valid = 0;
 	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
 				 SG_MAX_DEVS);
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/scsi/st.c	2005-03-30 17:18:12 -08:00
@@ -82,7 +82,7 @@
 static int st_dev_max;
 static int st_nr_dev;
 
-static struct class_simple *st_sysfs_class;
+static struct class *st_sysfs_class;
 
 MODULE_AUTHOR("Kai Makisara");
 MODULE_DESCRIPTION("SCSI Tape Driver");
@@ -4017,8 +4017,9 @@
 			if (STm->cdevs[j]) {
 				if (cdev == STm->cdevs[j])
 					cdev = NULL;
-				class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR,
-								 TAPE_MINOR(i, mode, j)));
+				class_device_destroy(st_sysfs_class, 
+						     MKDEV(SCSI_TAPE_MAJOR,
+							   TAPE_MINOR(i, mode, j)));
 				cdev_del(STm->cdevs[j]);
 			}
 		}
@@ -4061,8 +4062,9 @@
 				devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]);
 				devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]);
 				for (j=0; j < 2; j++) {
-					class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR,
-									 TAPE_MINOR(i, mode, j)));
+					class_device_destroy(st_sysfs_class,
+							     MKDEV(SCSI_TAPE_MAJOR,
+								   TAPE_MINOR(i, mode, j)));
 					cdev_del(tpnt->modes[mode].cdevs[j]);
 					tpnt->modes[mode].cdevs[j] = NULL;
 				}
@@ -4127,7 +4129,7 @@
 		"st: Version %s, fixed bufsize %d, s/g segs %d\n",
 		verstr, st_fixed_buffer_size, st_max_sg_segs);
 
-	st_sysfs_class = class_simple_create(THIS_MODULE, "scsi_tape");
+	st_sysfs_class = class_create(THIS_MODULE, "scsi_tape");
 	if (IS_ERR(st_sysfs_class)) {
 		st_sysfs_class = NULL;
 		printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n");
@@ -4141,7 +4143,7 @@
 			return 0;
 		}
 		if (st_sysfs_class)
-			class_simple_destroy(st_sysfs_class);		
+			class_destroy(st_sysfs_class);		
 		unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
 
 					 ST_MAX_TAPE_ENTRIES);
@@ -4154,7 +4156,7 @@
 static void __exit exit_st(void)
 {
 	if (st_sysfs_class)
-		class_simple_destroy(st_sysfs_class);
+		class_destroy(st_sysfs_class);
 	st_sysfs_class = NULL;
 	do_remove_driverfs_files();
 	scsi_unregister_driver(&st_template.gendrv);
@@ -4277,12 +4279,12 @@
 		snprintf(name, 10, "%s%s%s", rew ? "n" : "",
 			 STp->disk->disk_name, st_formats[i]);
 		st_class_member =
-			class_simple_device_add(st_sysfs_class,
-						MKDEV(SCSI_TAPE_MAJOR,
-						      TAPE_MINOR(dev_num, mode, rew)),
-						&STp->device->sdev_gendev, "%s", name);
+			class_device_create(st_sysfs_class,
+					    MKDEV(SCSI_TAPE_MAJOR,
+						  TAPE_MINOR(dev_num, mode, rew)),
+					    &STp->device->sdev_gendev, "%s", name);
 		if (IS_ERR(st_class_member)) {
-			printk(KERN_WARNING "st%d: class_simple_device_add failed\n",
+			printk(KERN_WARNING "st%d: class_device_create failed\n",
 			       dev_num);
 			goto out;
 		}
diff -Nru a/drivers/usb/core/file.c b/drivers/usb/core/file.c
--- a/drivers/usb/core/file.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/usb/core/file.c	2005-03-30 17:18:12 -08:00
@@ -66,7 +66,7 @@
 	.open =		usb_open,
 };
 
-static struct class_simple *usb_class;
+static struct class *usb_class;
 
 int usb_major_init(void)
 {
@@ -78,9 +78,9 @@
 		goto out;
 	}
 
-	usb_class = class_simple_create(THIS_MODULE, "usb");
+	usb_class = class_create(THIS_MODULE, "usb");
 	if (IS_ERR(usb_class)) {
-		err("class_simple_create failed for usb devices");
+		err("class_create failed for usb devices");
 		unregister_chrdev(USB_MAJOR, "usb");
 		goto out;
 	}
@@ -93,7 +93,7 @@
 
 void usb_major_cleanup(void)
 {
-	class_simple_destroy(usb_class);
+	class_destroy(usb_class);
 	devfs_remove("usb");
 	unregister_chrdev(USB_MAJOR, "usb");
 }
@@ -169,7 +169,7 @@
 		++temp;
 	else
 		temp = name;
-	intf->class_dev = class_simple_device_add(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp);
+	intf->class_dev = class_device_create(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp);
 	if (IS_ERR(intf->class_dev)) {
 		spin_lock (&minor_lock);
 		usb_minors[intf->minor] = NULL;
@@ -218,7 +218,7 @@
 
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
 	devfs_remove (name);
-	class_simple_device_remove(MKDEV(USB_MAJOR, intf->minor));
+	class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor));
 	intf->class_dev = NULL;
 	intf->minor = -1;
 }
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/usb/core/hcd.c	2005-03-30 17:18:12 -08:00
@@ -651,50 +651,45 @@
 /*-------------------------------------------------------------------------*/
 
 /* exported only within usbcore */
-struct usb_bus *usb_bus_get (struct usb_bus *bus)
+struct usb_bus *usb_bus_get(struct usb_bus *bus)
 {
-	struct class_device *tmp;
+	if (bus)
+		kref_get(&bus->kref);
+	return bus;
+}
 
-	if (!bus)
-		return NULL;
+static void usb_host_release(struct kref *kref)
+{
+	struct usb_bus *bus = container_of(kref, struct usb_bus, kref);
 
-	tmp = class_device_get(&bus->class_dev);
-	if (tmp)        
-		return to_usb_bus(tmp);
-	else
-		return NULL;
+	if (bus->release)
+		bus->release(bus);
 }
 
 /* exported only within usbcore */
-void usb_bus_put (struct usb_bus *bus)
+void usb_bus_put(struct usb_bus *bus)
 {
 	if (bus)
-		class_device_put(&bus->class_dev);
+		kref_put(&bus->kref, usb_host_release);
 }
 
 /*-------------------------------------------------------------------------*/
 
-static void usb_host_release(struct class_device *class_dev)
-{
-	struct usb_bus *bus = to_usb_bus(class_dev);
-
-	if (bus->release)
-		bus->release(bus);
-}
-
-static struct class usb_host_class = {
-	.name		= "usb_host",
-	.release	= &usb_host_release,
-};
+static struct class *usb_host_class;
 
 int usb_host_init(void)
 {
-	return class_register(&usb_host_class);
+	int retval = 0;
+
+	usb_host_class = class_create(THIS_MODULE, "usb_host");
+	if (IS_ERR(usb_host_class))
+		retval = PTR_ERR(usb_host_class);
+	return retval;
 }
 
 void usb_host_cleanup(void)
 {
-	class_unregister(&usb_host_class);
+	class_destroy(usb_host_class);
 }
 
 /**
@@ -719,8 +714,7 @@
 
 	INIT_LIST_HEAD (&bus->bus_list);
 
-	class_device_initialize(&bus->class_dev);
-	bus->class_dev.class = &usb_host_class;
+	kref_init(&bus->kref);
 }
 
 /**
@@ -761,7 +755,6 @@
 static int usb_register_bus(struct usb_bus *bus)
 {
 	int busnum;
-	int retval;
 
 	down (&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
@@ -774,15 +767,15 @@
 		return -E2BIG;
 	}
 
-	snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum);
-	bus->class_dev.dev = bus->controller;
-	retval = class_device_add(&bus->class_dev);
-	if (retval) {
+	bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum);
+	if (IS_ERR(bus->class_dev)) {
 		clear_bit(busnum, busmap.busmap);
 		up(&usb_bus_list_lock);
-		return retval;
+		return PTR_ERR(bus->class_dev);
 	}
 
+	class_set_devdata(bus->class_dev, bus);
+	
 	/* Add it to the local list of buses */
 	list_add (&bus->bus_list, &usb_bus_list);
 	up (&usb_bus_list_lock);
@@ -820,7 +813,7 @@
 
 	clear_bit (bus->busnum, busmap.busmap);
 
-	class_device_del(&bus->class_dev);
+	class_device_unregister(bus->class_dev);
 }
 
 /**
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/usb/core/usb.c	2005-03-30 17:18:12 -08:00
@@ -300,7 +300,7 @@
 	/* if interface was already added, bind now; else let
 	 * the future device_add() bind it, bypassing probe()
 	 */
-	if (!list_empty (&dev->bus_list))
+	if (!klist_node_attached (&dev->knode_bus))
 		device_bind_driver(dev);
 
 	return 0;
@@ -330,7 +330,7 @@
 		return;
 
 	/* don't disconnect from disconnect(), or before dev_add() */
-	if (!list_empty (&dev->driver_list) && !list_empty (&dev->bus_list))
+	if (!klist_node_attached(&dev->knode_driver) && !klist_node_attached(&dev->knode_bus))
 		device_release_driver(dev);
 
 	dev->driver = NULL;
@@ -469,6 +469,25 @@
 	return NULL;
 }
 
+
+static int __find_interface(struct device * dev, void * data)
+{
+	struct usb_interface ** ret = (struct usb_interface **)data;
+	struct usb_interface * intf = *ret;
+	int *minor = (int *)data;
+
+	/* can't look at usb devices, only interfaces */
+	if (dev->driver == &usb_generic_driver)
+		return 0;
+
+	intf = to_usb_interface(dev);
+	if (intf->minor != -1 && intf->minor == *minor) {
+		*ret = intf;
+		return 1;
+	}
+	return 0;
+}
+
 /**
  * usb_find_interface - find usb_interface pointer for driver and device
  * @drv: the driver whose current configuration is considered
@@ -480,26 +499,12 @@
  */
 struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
 {
-	struct list_head *entry;
-	struct device *dev;
-	struct usb_interface *intf;
+	struct usb_interface *intf = (struct usb_interface *)(long)minor;
+	int ret;
 
-	list_for_each(entry, &drv->driver.devices) {
-		dev = container_of(entry, struct device, driver_list);
-
-		/* can't look at usb devices, only interfaces */
-		if (dev->driver == &usb_generic_driver)
-			continue;
-
-		intf = to_usb_interface(dev);
-		if (intf->minor == -1)
-			continue;
-		if (intf->minor == minor)
-			return intf;
-	}
+	ret = driver_for_each_device(&drv->driver, NULL, &intf, __find_interface);
 
-	/* no device found that matches */
-	return NULL;	
+	return ret ? intf : NULL;
 }
 
 static int usb_device_match (struct device *dev, struct device_driver *drv)
diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/usb/host/ehci-dbg.c	2005-03-30 17:18:12 -08:00
@@ -450,7 +450,7 @@
 
 	*buf = 0;
 
-	bus = to_usb_bus(class_dev);
+	bus = class_get_devdata(class_dev);
 	hcd = bus->hcpriv;
 	ehci = hcd_to_ehci (hcd);
 	next = buf;
@@ -496,7 +496,7 @@
 		return 0;
 	seen_count = 0;
 
-	bus = to_usb_bus(class_dev);
+	bus = class_get_devdata(class_dev);
 	hcd = bus->hcpriv;
 	ehci = hcd_to_ehci (hcd);
 	next = buf;
@@ -633,7 +633,7 @@
 	static char		fmt [] = "%*s\n";
 	static char		label [] = "";
 
-	bus = to_usb_bus(class_dev);
+	bus = class_get_devdata(class_dev);
 	hcd = bus->hcpriv;
 	ehci = hcd_to_ehci (hcd);
 	next = buf;
@@ -735,7 +735,7 @@
 
 static inline void create_debug_files (struct ehci_hcd *ehci)
 {
-	struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev;
+	struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
 
 	class_device_create_file(cldev, &class_device_attr_async);
 	class_device_create_file(cldev, &class_device_attr_periodic);
@@ -744,7 +744,7 @@
 
 static inline void remove_debug_files (struct ehci_hcd *ehci)
 {
-	struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev;
+	struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
 
 	class_device_remove_file(cldev, &class_device_attr_async);
 	class_device_remove_file(cldev, &class_device_attr_periodic);
diff -Nru a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
--- a/drivers/usb/host/hc_crisv10.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/usb/host/hc_crisv10.c	2005-03-30 17:18:12 -08:00
@@ -4396,6 +4396,7 @@
         device_initialize(&fake_device);
         kobject_set_name(&fake_device.kobj, "etrax_usb");
         kobject_add(&fake_device.kobj);
+        kobject_hotplug(&fake_device.kobj, KOBJ_ADD);
         hc->bus->controller = &fake_device;
 	usb_register_bus(hc->bus);
 
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	2005-03-30 17:18:12 -08:00
+++ b/drivers/usb/host/ohci-dbg.c	2005-03-30 17:18:12 -08:00
@@ -481,7 +481,7 @@
 	size_t			temp;
 	unsigned long		flags;
 
-	bus = to_usb_bus(class_dev);
+	bus = class_get_devdata(class_dev);
 	hcd = bus->hcpriv;
 	ohci = hcd_to_ohci(hcd);
 
@@ -514,7 +514,7 @@
 		return 0;
 	seen_count = 0;
 
-	bus = to_usb_bus(class_dev);
+	bus = class_get_devdata(class_dev);
 	hcd = bus->hcpriv;
 	ohci = hcd_to_ohci(hcd);
 	next = buf;
@@ -611,7 +611,7 @@
 	char			*next;
 	u32			rdata;
 
-	bus = to_usb_bus(class_dev);
+	bus = class_get_devdata(class_dev);
 	hcd = bus->hcpriv;
 	ohci = hcd_to_ohci(hcd);
 	regs = ohci->regs;
@@ -684,7 +684,7 @@
 
 static inline void create_debug_files (struct ohci_hcd *ohci)
 {
-	struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev;
+	struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
 
 	class_device_create_file(cldev, &class_device_attr_async);
 	class_device_create_file(cldev, &class_device_attr_periodic);
@@ -694,7 +694,7 @@
 
 static inline void remove_debug_files (struct ohci_hcd *ohci)
 {
-	struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev;
+	struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
 
 	class_device_remove_file(cldev, &class_device_attr_async);
 	class_device_remove_file(cldev, &class_device_attr_periodic);
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-03-30 17:18:11 -08:00
+++ b/drivers/video/fbmem.c	2005-03-30 17:18:11 -08:00
@@ -1043,7 +1043,7 @@
 #endif
 };
 
-static struct class_simple *fb_class;
+static struct class *fb_class;
 
 /**
  *	register_framebuffer - registers a frame buffer device
@@ -1069,7 +1069,7 @@
 			break;
 	fb_info->node = i;
 
-	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+	fb_info->class_device = class_device_create(fb_class, MKDEV(FB_MAJOR, i),
 				    fb_info->device, "fb%d", i);
 	if (IS_ERR(fb_info->class_device)) {
 		/* Not fatal */
@@ -1137,7 +1137,7 @@
 	registered_fb[i]=NULL;
 	num_registered_fb--;
 	fb_cleanup_class_device(fb_info);
-	class_simple_device_remove(MKDEV(FB_MAJOR, i));
+	class_device_destroy(fb_class, MKDEV(FB_MAJOR, i));
 	return 0;
 }
 
@@ -1200,7 +1200,7 @@
 	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
 		printk("unable to get major %d for fb devs\n", FB_MAJOR);
 
-	fb_class = class_simple_create(THIS_MODULE, "graphics");
+	fb_class = class_create(THIS_MODULE, "graphics");
 	if (IS_ERR(fb_class)) {
 		printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
 		fb_class = NULL;
@@ -1213,7 +1213,7 @@
 static void __exit
 fbmem_exit(void)
 {
-	class_simple_destroy(fb_class);
+	class_destroy(fb_class);
 }
 
 module_exit(fbmem_exit);
diff -Nru a/fs/coda/psdev.c b/fs/coda/psdev.c
--- a/fs/coda/psdev.c	2005-03-30 17:18:12 -08:00
+++ b/fs/coda/psdev.c	2005-03-30 17:18:12 -08:00
@@ -61,7 +61,7 @@
 
 
 struct venus_comm coda_comms[MAX_CODADEVS];
-static struct class_simple *coda_psdev_class;
+static struct class *coda_psdev_class;
 
 /*
  * Device operations
@@ -363,14 +363,14 @@
 		     CODA_PSDEV_MAJOR);
               return -EIO;
 	}
-	coda_psdev_class = class_simple_create(THIS_MODULE, "coda");
+	coda_psdev_class = class_create(THIS_MODULE, "coda");
 	if (IS_ERR(coda_psdev_class)) {
 		err = PTR_ERR(coda_psdev_class);
 		goto out_chrdev;
 	}		
 	devfs_mk_dir ("coda");
 	for (i = 0; i < MAX_CODADEVS; i++) {
-		class_simple_device_add(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i), 
+		class_device_create(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i), 
 				NULL, "cfs%d", i);
 		err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i),
 				S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i);
@@ -382,8 +382,8 @@
 
 out_class:
 	for (i = 0; i < MAX_CODADEVS; i++) 
-		class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i));
-	class_simple_destroy(coda_psdev_class);
+		class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
+	class_destroy(coda_psdev_class);
 out_chrdev:
 	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
 out:
@@ -425,10 +425,10 @@
 	return 0;
 out:
 	for (i = 0; i < MAX_CODADEVS; i++) {
-		class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i));
+		class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
 		devfs_remove("coda/%d", i);
 	}
-	class_simple_destroy(coda_psdev_class);
+	class_destroy(coda_psdev_class);
 	devfs_remove("coda");
 	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
 	coda_sysctl_clean();
@@ -447,10 +447,10 @@
                 printk("coda: failed to unregister filesystem\n");
         }
 	for (i = 0; i < MAX_CODADEVS; i++) {
-		class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i));
+		class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
 		devfs_remove("coda/%d", i);
 	}
-	class_simple_destroy(coda_psdev_class);
+	class_destroy(coda_psdev_class);
 	devfs_remove("coda");
 	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
 	coda_sysctl_clean();
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	2005-03-30 17:18:12 -08:00
+++ b/fs/partitions/check.c	2005-03-30 17:18:12 -08:00
@@ -337,6 +337,7 @@
 	if ((err = kobject_add(&disk->kobj)))
 		return;
 	disk_sysfs_symlinks(disk);
+	kobject_hotplug(&disk->kobj, KOBJ_ADD);
 
 	/* No minors to use for partitions */
 	if (disk->minors == 1) {
@@ -441,5 +442,6 @@
 		sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
 		put_device(disk->driverfs_dev);
 	}
+	kobject_hotplug(&disk->kobj, KOBJ_REMOVE);
 	kobject_del(&disk->kobj);
 }
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	2005-03-30 17:18:12 -08:00
+++ b/include/linux/device.h	2005-03-30 17:18:12 -08:00
@@ -14,6 +14,7 @@
 #include <linux/config.h>
 #include <linux/ioport.h>
 #include <linux/kobject.h>
+#include <linux/klist.h>
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/module.h>
@@ -44,7 +45,6 @@
 struct device_driver;
 struct class;
 struct class_device;
-struct class_simple;
 
 struct bus_type {
 	char			* name;
@@ -52,6 +52,8 @@
 	struct subsystem	subsys;
 	struct kset		drivers;
 	struct kset		devices;
+	struct klist		klist_devices;
+	struct klist		klist_drivers;
 
 	struct bus_attribute	* bus_attrs;
 	struct device_attribute	* dev_attrs;
@@ -103,7 +105,8 @@
 
 	struct completion	unloaded;
 	struct kobject		kobj;
-	struct list_head	devices;
+	struct klist		klist_devices;
+	struct klist_node	knode_bus;
 
 	struct module 		* owner;
 
@@ -137,12 +140,16 @@
 extern int driver_create_file(struct device_driver *, struct driver_attribute *);
 extern void driver_remove_file(struct device_driver *, struct driver_attribute *);
 
+extern int driver_for_each_device(struct device_driver * drv, struct device * start,
+				  void * data, int (*fn)(struct device *, void *));
+
 
 /*
  * device classes
  */
 struct class {
 	char			* name;
+	struct module		* owner;
 
 	struct subsystem	subsys;
 	struct list_head	children;
@@ -185,6 +192,7 @@
 	struct kobject		kobj;
 	struct class		* class;	/* required */
 	dev_t			devt;		/* dev_t, creates the sysfs "dev" */
+	struct class_device_attribute *devt_attr;
 	struct device		* dev;		/* not necessary, but nice to have */
 	void			* class_data;	/* class-specific data */
 
@@ -245,26 +253,28 @@
 extern int class_interface_register(struct class_interface *);
 extern void class_interface_unregister(struct class_interface *);
 
-/* interface for class simple stuff */
-extern struct class_simple *class_simple_create(struct module *owner, char *name);
-extern void class_simple_destroy(struct class_simple *cs);
-extern struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...)
-	__attribute__((format(printf,4,5)));
-extern int class_simple_set_hotplug(struct class_simple *, 
-	int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size));
-extern void class_simple_device_remove(dev_t dev);
+extern struct class *class_create(struct module *owner, char *name);
+extern void class_destroy(struct class *cls);
+extern struct class_device *class_device_create(struct class *cls, dev_t devt,
+						struct device *device, char *fmt, ...)
+					__attribute__((format(printf,4,5)));
+extern void class_device_destroy(struct class *cls, dev_t devt);
 
 
 struct device {
-	struct list_head node;		/* node in sibling list */
-	struct list_head bus_list;	/* node in bus's list */
-	struct list_head driver_list;
-	struct list_head children;
+	struct klist		klist_children;
+	struct klist_node	knode_parent;		/* node in sibling list */
+	struct klist_node	knode_driver;
+	struct klist_node	knode_bus;
 	struct device 	* parent;
 
 	struct kobject kobj;
 	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
 
+	struct semaphore	sem;	/* semaphore to synchronize calls to
+					 * its driver.
+					 */
+
 	struct bus_type	* bus;		/* type of bus device is on */
 	struct device_driver *driver;	/* which driver has allocated this
 					   device */
@@ -291,12 +301,6 @@
 	void	(*release)(struct device * dev);
 };
 
-static inline struct device *
-list_to_dev(struct list_head *node)
-{
-	return list_entry(node, struct device, node);
-}
-
 static inline void *
 dev_get_drvdata (struct device *dev)
 {
@@ -363,7 +367,6 @@
  */
 extern struct device * get_device(struct device * dev);
 extern void put_device(struct device * dev);
-extern struct device *device_find(const char *name, struct bus_type *bus);
 
 
 /* drivers/base/platform.c */
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	2005-03-30 17:18:12 -08:00
+++ b/include/linux/input.h	2005-03-30 17:18:12 -08:00
@@ -1010,7 +1010,7 @@
 	dev->absbit[LONG(axis)] |= BIT(axis);
 }
 
-extern struct class_simple *input_class;
+extern struct class *input_class;
 
 #endif
 #endif
diff -Nru a/include/linux/klist.h b/include/linux/klist.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/klist.h	2005-03-30 17:18:12 -08:00
@@ -0,0 +1,55 @@
+/*
+ *	klist.h - Some generic list helpers, extending struct list_head a bit.
+ *
+ *	Implementations are found in lib/klist.c
+ *
+ *
+ *	Copyright (C) 2005 Patrick Mochel
+ *
+ *	This file is rleased under the GPL v2.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+
+
+struct klist {
+	spinlock_t		k_lock;
+	struct list_head	k_list;
+};
+
+
+extern void klist_init(struct klist * k);
+
+
+struct klist_node {
+	struct klist		* n_klist;
+	struct list_head	n_node;
+	struct kref		n_ref;
+	struct completion	n_removed;
+};
+
+extern void klist_add_tail(struct klist * k, struct klist_node * n);
+extern void klist_add_head(struct klist * k, struct klist_node * n);
+
+extern void klist_del(struct klist_node * n);
+extern void klist_remove(struct klist_node * n);
+
+extern int klist_node_attached(struct klist_node * n);
+
+
+struct klist_iter {
+	struct klist		* i_klist;
+	struct list_head	* i_head;
+	struct klist_node	* i_cur;
+};
+
+
+extern void klist_iter_init(struct klist * k, struct klist_iter * i);
+extern void klist_iter_init_node(struct klist * k, struct klist_iter * i, 
+				 struct klist_node * n);
+extern void klist_iter_exit(struct klist_iter * i);
+extern struct klist_node * klist_next(struct klist_iter * i);
+
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	2005-03-30 17:18:12 -08:00
+++ b/include/linux/usb.h	2005-03-30 17:18:12 -08:00
@@ -287,15 +287,14 @@
 
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the bus */
 
-	struct class_device class_dev;	/* class device for this bus */
+	struct class_device *class_dev;	/* class device for this bus */
+	struct kref kref;		/* handles reference counting this bus */
 	void (*release)(struct usb_bus *bus);	/* function to destroy this bus's memory */
 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
 	struct mon_bus *mon_bus;	/* non-null when associated */
 	int monitored;			/* non-zero when monitored */
 #endif
 };
-#define	to_usb_bus(d) container_of(d, struct usb_bus, class_dev)
-
 
 /* -------------------------------------------------------------------------- */
 
diff -Nru a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile	2005-03-30 17:18:11 -08:00
+++ b/lib/Makefile	2005-03-30 17:18:11 -08:00
@@ -4,9 +4,10 @@
 
 lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
 	 bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
-	 kobject.o kref.o idr.o div64.o int_sqrt.o \
-	 bitmap.o extable.o kobject_uevent.o prio_tree.o sha1.o \
-	 halfmd4.o
+	 idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \
+	 sha1.o halfmd4.o
+
+lib-y	+= kobject.o kref.o kobject_uevent.o klist.o
 
 obj-y += sort.o parser.o
 
diff -Nru a/lib/klist.c b/lib/klist.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/lib/klist.c	2005-03-30 17:18:12 -08:00
@@ -0,0 +1,265 @@
+/*
+ *	klist.c - Routines for manipulating klists.
+ *
+ *
+ *	This klist interface provides a couple of structures that wrap around 
+ *	struct list_head to provide explicit list "head" (struct klist) and 
+ *	list "node" (struct klist_node) objects. For struct klist, a spinlock
+ *	is included that protects access to the actual list itself. struct 
+ *	klist_node provides a pointer to the klist that owns it and a kref
+ *	reference count that indicates the number of current users of that node
+ *	in the list.
+ *
+ *	The entire point is to provide an interface for iterating over a list
+ *	that is safe and allows for modification of the list during the
+ *	iteration (e.g. insertion and removal), including modification of the
+ *	current node on the list.
+ *
+ *	It works using a 3rd object type - struct klist_iter - that is declared
+ *	and initialized before an iteration. klist_next() is used to acquire the
+ *	next element in the list. It returns NULL if there are no more items.
+ *	Internally, that routine takes the klist's lock, decrements the reference
+ *	count of the previous klist_node and increments the count of the next
+ *	klist_node. It then drops the lock and returns.
+ *
+ *	There are primitives for adding and removing nodes to/from a klist. 
+ *	When deleting, klist_del() will simply decrement the reference count. 
+ *	Only when the count goes to 0 is the node removed from the list. 
+ *	klist_remove() will try to delete the node from the list and block
+ *	until it is actually removed. This is useful for objects (like devices)
+ *	that have been removed from the system and must be freed (but must wait
+ *	until all accessors have finished).
+ *
+ *	Copyright (C) 2005 Patrick Mochel
+ *
+ *	This file is released under the GPL v2.
+ */
+
+#include <linux/klist.h>
+#include <linux/module.h>
+
+
+/**
+ *	klist_init - Initialize a klist structure. 
+ *	@k:	The klist we're initializing.
+ */
+
+void klist_init(struct klist * k)
+{
+	INIT_LIST_HEAD(&k->k_list);
+	spin_lock_init(&k->k_lock);
+}
+
+EXPORT_SYMBOL_GPL(klist_init);
+
+
+static void add_head(struct klist * k, struct klist_node * n)
+{
+	spin_lock(&k->k_lock);
+	list_add(&n->n_node, &k->k_list);
+	spin_unlock(&k->k_lock);
+}
+
+static void add_tail(struct klist * k, struct klist_node * n)
+{
+	spin_lock(&k->k_lock);
+	list_add_tail(&n->n_node, &k->k_list);
+	spin_unlock(&k->k_lock);
+}
+
+
+static void klist_node_init(struct klist * k, struct klist_node * n)
+{
+	INIT_LIST_HEAD(&n->n_node);
+	init_completion(&n->n_removed);
+	kref_init(&n->n_ref);
+	n->n_klist = k;
+}
+
+
+/**
+ *	klist_add_head - Initialize a klist_node and add it to front.
+ *	@k:	klist it's going on.
+ *	@n:	node we're adding.
+ */
+
+void klist_add_head(struct klist * k, struct klist_node * n)
+{
+	klist_node_init(k, n);
+	add_head(k, n);
+}
+
+EXPORT_SYMBOL_GPL(klist_add_head);
+
+
+/**
+ *	klist_add_tail - Initialize a klist_node and add it to back.
+ *	@k:	klist it's going on.
+ *	@n:	node we're adding.
+ */
+
+void klist_add_tail(struct klist * k, struct klist_node * n)
+{
+	klist_node_init(k, n);
+	add_tail(k, n);
+}
+
+EXPORT_SYMBOL_GPL(klist_add_tail);
+
+
+static void klist_release(struct kref * kref)
+{
+	struct klist_node * n = container_of(kref, struct klist_node, n_ref);
+	list_del(&n->n_node);
+	complete(&n->n_removed);
+	n->n_klist = NULL;
+}
+
+static int klist_dec_and_del(struct klist_node * n)
+{
+	return kref_put(&n->n_ref, klist_release);
+}
+
+
+/**
+ *	klist_del - Decrement the reference count of node and try to remove.
+ *	@n:	node we're deleting.
+ */
+
+void klist_del(struct klist_node * n)
+{
+	struct klist * k = n->n_klist;
+
+	spin_lock(&k->k_lock);
+	klist_dec_and_del(n);
+	spin_unlock(&k->k_lock);
+}
+
+EXPORT_SYMBOL_GPL(klist_del);
+
+
+/**
+ *	klist_remove - Decrement the refcount of node and wait for it to go away.
+ *	@n:	node we're removing.
+ */
+
+void klist_remove(struct klist_node * n)
+{
+	struct klist * k = n->n_klist;
+	spin_lock(&k->k_lock);
+	klist_dec_and_del(n);
+	spin_unlock(&k->k_lock);
+	wait_for_completion(&n->n_removed);
+}
+
+EXPORT_SYMBOL_GPL(klist_remove);
+
+
+/**
+ *	klist_node_attached - Say whether a node is bound to a list or not.
+ *	@n:	Node that we're testing.
+ */
+
+int klist_node_attached(struct klist_node * n)
+{
+	return (n->n_klist != NULL);
+}
+
+EXPORT_SYMBOL_GPL(klist_node_attached);
+
+
+/**
+ *	klist_iter_init_node - Initialize a klist_iter structure.
+ *	@k:	klist we're iterating.
+ *	@i:	klist_iter we're filling.
+ *	@n:	node to start with.
+ *
+ *	Similar to klist_iter_init(), but starts the action off with @n, 
+ *	instead of with the list head.
+ */
+
+void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
+{
+	i->i_klist = k;
+	i->i_head = &k->k_list;
+	i->i_cur = n;
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_init_node);
+
+
+/**
+ *	klist_iter_init - Iniitalize a klist_iter structure.
+ *	@k:	klist we're iterating.
+ *	@i:	klist_iter structure we're filling.
+ *
+ *	Similar to klist_iter_init_node(), but start with the list head.
+ */
+
+void klist_iter_init(struct klist * k, struct klist_iter * i)
+{
+	klist_iter_init_node(k, i, NULL);
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_init);
+
+
+/**
+ *	klist_iter_exit - Finish a list iteration.
+ *	@i:	Iterator structure.
+ *
+ *	Must be called when done iterating over list, as it decrements the 
+ *	refcount of the current node. Necessary in case iteration exited before
+ *	the end of the list was reached, and always good form.
+ */
+
+void klist_iter_exit(struct klist_iter * i)
+{
+	if (i->i_cur) {
+		klist_del(i->i_cur);
+		i->i_cur = NULL;
+	}
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_exit);
+
+
+static struct klist_node * to_klist_node(struct list_head * n)
+{
+	return container_of(n, struct klist_node, n_node);
+}
+
+
+/**
+ *	klist_next - Ante up next node in list.
+ *	@i:	Iterator structure.
+ *
+ *	First grab list lock. Decrement the reference count of the previous
+ *	node, if there was one. Grab the next node, increment its reference 
+ *	count, drop the lock, and return that next node.
+ */
+
+struct klist_node * klist_next(struct klist_iter * i)
+{
+	struct list_head * next;
+	struct klist_node * knode = NULL;
+
+	spin_lock(&i->i_klist->k_lock);
+	if (i->i_cur) {
+		next = i->i_cur->n_node.next;
+		klist_dec_and_del(i->i_cur);
+	} else
+		next = i->i_head->next;
+
+	if (next != i->i_head) {
+		knode = to_klist_node(next);
+		kref_get(&knode->n_ref);
+	}
+	i->i_cur = knode;
+	spin_unlock(&i->i_klist->k_lock);
+	return knode;
+}
+
+EXPORT_SYMBOL_GPL(klist_next);
+
+
diff -Nru a/lib/kobject.c b/lib/kobject.c
--- a/lib/kobject.c	2005-03-30 17:18:12 -08:00
+++ b/lib/kobject.c	2005-03-30 17:18:12 -08:00
@@ -184,8 +184,6 @@
 		unlink(kobj);
 		if (parent)
 			kobject_put(parent);
-	} else {
-		kobject_hotplug(kobj, KOBJ_ADD);
 	}
 
 	return error;
@@ -207,7 +205,8 @@
 			printk("kobject_register failed for %s (%d)\n",
 			       kobject_name(kobj),error);
 			dump_stack();
-		}
+		} else
+			kobject_hotplug(kobj, KOBJ_ADD);
 	} else
 		error = -EINVAL;
 	return error;
@@ -301,7 +300,6 @@
 
 void kobject_del(struct kobject * kobj)
 {
-	kobject_hotplug(kobj, KOBJ_REMOVE);
 	sysfs_remove_dir(kobj);
 	unlink(kobj);
 }
@@ -314,6 +312,7 @@
 void kobject_unregister(struct kobject * kobj)
 {
 	pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
+	kobject_hotplug(kobj, KOBJ_REMOVE);
 	kobject_del(kobj);
 	kobject_put(kobj);
 }
diff -Nru a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
--- a/net/bridge/br_sysfs_if.c	2005-03-30 17:18:12 -08:00
+++ b/net/bridge/br_sysfs_if.c	2005-03-30 17:18:12 -08:00
@@ -248,6 +248,7 @@
 	if (err)
 		goto out2;
 
+	kobject_hotplug(&p->kobj, KOBJ_ADD);
 	return 0;
  out2:
 	kobject_del(&p->kobj);
@@ -259,6 +260,7 @@
 {
 	pr_debug("br_sysfs_removeif\n");
 	sysfs_remove_link(&p->br->ifobj, p->dev->name);
+	kobject_hotplug(&p->kobj, KOBJ_REMOVE);
 	kobject_del(&p->kobj);
 }
 
diff -Nru a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c	2005-03-30 17:18:12 -08:00
+++ b/sound/core/sound.c	2005-03-30 17:18:12 -08:00
@@ -64,7 +64,7 @@
 
 static DECLARE_MUTEX(sound_mutex);
 
-extern struct class_simple *sound_class;
+extern struct class *sound_class;
 
 
 #ifdef CONFIG_KMOD
@@ -231,7 +231,7 @@
 		devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name);
 	if (card)
 		device = card->dev;
-	class_simple_device_add(sound_class, MKDEV(major, minor), device, name);
+	class_device_create(sound_class, MKDEV(major, minor), device, "%s", name);
 
 	up(&sound_mutex);
 	return 0;
@@ -263,7 +263,7 @@
 
 	if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) /* created in sound.c */
 		devfs_remove("snd/%s", mptr->name);
-	class_simple_device_remove(MKDEV(major, minor));
+	class_device_destroy(sound_class, MKDEV(major, minor));
 
 	list_del(&mptr->list);
 	up(&sound_mutex);
diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c
--- a/sound/oss/soundcard.c	2005-03-30 17:18:12 -08:00
+++ b/sound/oss/soundcard.c	2005-03-30 17:18:12 -08:00
@@ -73,7 +73,7 @@
 
 
 unsigned long seq_time = 0;	/* Time for /dev/sequencer */
-extern struct class_simple *sound_class;
+extern struct class *sound_class;
 
 /*
  * Table for configurable mixer volume handling
@@ -567,9 +567,9 @@
 		devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor),
 				S_IFCHR | dev_list[i].mode,
 				"sound/%s", dev_list[i].name);
-		class_simple_device_add(sound_class, 
-					MKDEV(SOUND_MAJOR, dev_list[i].minor),
-					NULL, "%s", dev_list[i].name);
+		class_device_create(sound_class,
+				    MKDEV(SOUND_MAJOR, dev_list[i].minor),
+				    NULL, "%s", dev_list[i].name);
 
 		if (!dev_list[i].num)
 			continue;
@@ -579,10 +579,9 @@
 						dev_list[i].minor + (j*0x10)),
 					S_IFCHR | dev_list[i].mode,
 					"sound/%s%d", dev_list[i].name, j);
-			class_simple_device_add(sound_class,
-					MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)),
-					NULL,
-					"%s%d", dev_list[i].name, j);
+			class_device_create(sound_class,
+					    MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)),
+					    NULL, "%s%d", dev_list[i].name, j);
 		}
 	}
 
@@ -598,12 +597,12 @@
 
 	for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) {
 		devfs_remove("sound/%s", dev_list[i].name);
-		class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor));
+		class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor));
 		if (!dev_list[i].num)
 			continue;
 		for (j = 1; j < *dev_list[i].num; j++) {
 			devfs_remove("sound/%s%d", dev_list[i].name, j);
-			class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)));
+			class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)));
 		}
 	}
 	
diff -Nru a/sound/sound_core.c b/sound/sound_core.c
--- a/sound/sound_core.c	2005-03-30 17:18:12 -08:00
+++ b/sound/sound_core.c	2005-03-30 17:18:12 -08:00
@@ -65,7 +65,7 @@
 extern int msnd_pinnacle_init(void);
 #endif
 
-struct class_simple *sound_class;
+struct class *sound_class;
 EXPORT_SYMBOL(sound_class);
 
 /*
@@ -174,7 +174,7 @@
 
 	devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
 			S_IFCHR | mode, s->name);
-	class_simple_device_add(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor),
+	class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor),
 				NULL, s->name+6);
 	return r;
 
@@ -198,7 +198,7 @@
 	spin_unlock(&sound_loader_lock);
 	if (p) {
 		devfs_remove(p->name);
-		class_simple_device_remove(MKDEV(SOUND_MAJOR, p->unit_minor));
+		class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
 		kfree(p);
 	}
 }
@@ -562,7 +562,7 @@
 	   empty */
 	unregister_chrdev(SOUND_MAJOR, "sound");
 	devfs_remove("sound");
-	class_simple_destroy(sound_class);
+	class_destroy(sound_class);
 }
 
 static int __init init_soundcore(void)
@@ -572,7 +572,7 @@
 		return -EBUSY;
 	}
 	devfs_mk_dir ("sound");
-	sound_class = class_simple_create(THIS_MODULE, "sound");
+	sound_class = class_create(THIS_MODULE, "sound");
 	if (IS_ERR(sound_class))
 		return PTR_ERR(sound_class);