diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/base/cpu.c | 46 | ||||
| -rw-r--r-- | drivers/base/memblk.c | 31 | ||||
| -rw-r--r-- | drivers/base/node.c | 41 | ||||
| -rw-r--r-- | drivers/base/power.c | 43 | ||||
| -rw-r--r-- | drivers/base/sys.c | 467 | ||||
| -rw-r--r-- | drivers/s390/block/xpram.c | 23 |
6 files changed, 476 insertions, 175 deletions
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 78a9f57e48f3..4456bceabeaf 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -2,23 +2,18 @@ * drivers/base/cpu.c - basic CPU class support */ -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/module.h> #include <linux/init.h> #include <linux/cpu.h> #include <linux/topology.h> -struct class cpu_class = { - .name = "cpu", +struct sysdev_class cpu_sysdev_class = { + set_kset_name("cpu"), }; -struct device_driver cpu_driver = { - .name = "cpu", - .bus = &system_bus_type, -}; - /* * register_cpu - Setup a driverfs device for a CPU. * @num - CPU number to use when creating the device. @@ -27,42 +22,15 @@ struct device_driver cpu_driver = { */ int __init register_cpu(struct cpu *cpu, int num, struct node *root) { - int retval; - cpu->node_id = cpu_to_node(num); - cpu->sysdev.name = "cpu"; cpu->sysdev.id = num; - if (root) - cpu->sysdev.root = &root->sysroot; - snprintf(cpu->sysdev.dev.name, DEVICE_NAME_SIZE, "CPU %u", num); - cpu->sysdev.dev.driver = &cpu_driver; - retval = sys_device_register(&cpu->sysdev); - if (retval) - return retval; - memset(&cpu->sysdev.class_dev, 0x00, sizeof(struct class_device)); - cpu->sysdev.class_dev.dev = &cpu->sysdev.dev; - cpu->sysdev.class_dev.class = &cpu_class; - snprintf(cpu->sysdev.class_dev.class_id, BUS_ID_SIZE, "cpu%d", num); - retval = class_device_register(&cpu->sysdev.class_dev); - if (retval) { - sys_device_unregister(&cpu->sysdev); - return retval; - } - return 0; + cpu->sysdev.cls = &cpu_sysdev_class; + return sys_device_register(&cpu->sysdev); } + int __init cpu_dev_init(void) { - int error; - - error = class_register(&cpu_class); - if (error) - goto out; - - error = driver_register(&cpu_driver); - if (error) - class_unregister(&cpu_class); -out: - return error; + return sysdev_class_register(&cpu_sysdev_class); } diff --git a/drivers/base/memblk.c b/drivers/base/memblk.c index cbaa98b3dce1..f3f3fdf7292c 100644 --- a/drivers/base/memblk.c +++ b/drivers/base/memblk.c @@ -2,7 +2,6 @@ * drivers/base/memblk.c - basic Memory Block class support */ -#include <linux/device.h> #include <linux/module.h> #include <linux/init.h> #include <linux/memblk.h> @@ -10,8 +9,8 @@ #include <linux/topology.h> -static struct class memblk_class = { - .name = "memblk", +static struct sysdev_class memblk_class = { + set_kset_name("memblk"), }; @@ -29,27 +28,23 @@ static struct device_driver memblk_driver = { */ int __init register_memblk(struct memblk *memblk, int num, struct node *root) { + int error; + memblk->node_id = memblk_to_node(num); - memblk->sysdev.name = "memblk"; + memblk->sysdev.cls = &memblk_class, memblk->sysdev.id = num; - if (root) - memblk->sysdev.root = &root->sysroot; - snprintf(memblk->sysdev.dev.name, DEVICE_NAME_SIZE, "Memory Block %u", num); - memblk->sysdev.dev.driver = &memblk_driver; - return sys_device_register(&memblk->sysdev); + + error = sys_device_register(&memblk->sysdev); + if (!error) + error = sysfs_create_link(&root->sysdev.kobj, + &memblk->sysdev,kobj, + memblk->sysdev.kobj.name); + return error; } int __init register_memblk_type(void) { - int error; - - error = class_register(&memblk_class); - if (!error) { - error = driver_register(&memblk_driver); - if (error) - class_unregister(&memblk_class); - } - return error; + return sysdev_class_register(&memblk_class); } postcore_initcall(register_memblk_type); diff --git a/drivers/base/node.c b/drivers/base/node.c index 2f77b0afb862..08e7c52c68e6 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -9,15 +9,8 @@ #include <linux/node.h> #include <linux/topology.h> - -static struct class node_class = { - .name = "node", -}; - - -static struct device_driver node_driver = { - .name = "node", - .bus = &system_bus_type, +static struct sysdev_class node_class = { + set_kset_name("node"), }; @@ -26,7 +19,7 @@ static ssize_t node_read_cpumap(struct device * dev, char * buf) struct node *node_dev = to_node(to_root(dev)); return sprintf(buf,"%lx\n",node_dev->cpumap); } -static DEVICE_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL); +static SYSDEV_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL); #define K(x) ((x) << (PAGE_SHIFT - 10)) static ssize_t node_read_meminfo(struct device * dev, char * buf) @@ -52,7 +45,7 @@ static ssize_t node_read_meminfo(struct device * dev, char * buf) nid, K(i.freeram-i.freehigh)); } #undef K -static DEVICE_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL); +static SYSDEV_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL); /* @@ -66,17 +59,13 @@ int __init register_node(struct node *node, int num, struct node *parent) int error; node->cpumap = node_to_cpumask(num); - node->sysroot.id = num; - if (parent) - node->sysroot.dev.parent = &parent->sysroot.sysdev; - snprintf(node->sysroot.dev.name, DEVICE_NAME_SIZE, "Node %u", num); - snprintf(node->sysroot.dev.bus_id, BUS_ID_SIZE, "node%u", num); - node->sysroot.dev.driver = &node_driver; - node->sysroot.dev.bus = &system_bus_type; - error = sys_register_root(&node->sysroot); + node->sysdev.id = num; + node->sysdev.cls = &node_class; + error = sys_device_register(&node->sysdev); + if (!error){ - device_create_file(&node->sysroot.dev, &dev_attr_cpumap); - device_create_file(&node->sysroot.dev, &dev_attr_meminfo); + sys_device_create_file(&node->sysroot.dev, &attr_cpumap); + sys_device_create_file(&node->sysroot.dev, &attr_meminfo); } return error; } @@ -84,14 +73,6 @@ int __init register_node(struct node *node, int num, struct node *parent) int __init register_node_type(void) { - int error; - - error = class_register(&node_class); - if (!error) { - error = driver_register(&node_driver); - if (error) - class_unregister(&node_class); - } - return error; + return sysdev_class_register(&node_class); } postcore_initcall(register_node_type); diff --git a/drivers/base/power.c b/drivers/base/power.c index e389891c574d..7f5a6abc4e00 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -22,6 +22,21 @@ extern struct subsystem devices_subsys; /** + * We handle system devices differently - we suspend and shut them + * down first and resume them first. That way, we do anything stupid like + * shutting down the interrupt controller before any devices.. + * + * Note that there are not different stages for power management calls - + * they only get one called once when interrupts are disabled. + */ + +extern int sysdev_shutdown(void); +extern int sysdev_save(u32 state); +extern int sysdev_suspend(u32 state); +extern int sysdev_resume(void); +extern int sysdev_restore(void); + +/** * device_suspend - suspend/remove all devices on the device ree * @state: state we're entering * @level: what stage of the suspend process we're at @@ -50,6 +65,21 @@ int device_suspend(u32 state, u32 level) } } up_write(&devices_subsys.rwsem); + + /* + * Make sure system devices are suspended. + */ + switch(level) { + case SUSPEND_SAVE_STATE: + sysdev_save(state); + break; + case SUSPEND_POWER_DOWN: + sysdev_suspend(state); + break; + default: + break; + } + return error; } @@ -65,6 +95,17 @@ void device_resume(u32 level) { struct list_head * node; + switch (level) { + case RESUME_POWER_ON: + sysdev_resume(); + break; + case RESUME_RESTORE_STATE: + sysdev_restore(); + break; + default: + break; + } + down_write(&devices_subsys.rwsem); list_for_each_prev(node,&devices_subsys.kset.list) { struct device * dev = to_dev(node); @@ -98,6 +139,8 @@ void device_shutdown(void) pr_debug("Ignored.\n"); } up_write(&devices_subsys.rwsem); + + sysdev_shutdown(); } EXPORT_SYMBOL(device_suspend); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 5ae457170548..34001cb52fa1 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -12,9 +12,9 @@ * add themselves as children of the system bus. */ -#undef DEBUG +#define DEBUG -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/err.h> #include <linux/module.h> #include <linux/kernel.h> @@ -22,130 +22,435 @@ #include <linux/slab.h> #include <linux/string.h> -/* The default system device parent. */ -static struct device system_bus = { - .name = "System Bus", - .bus_id = "sys", + +extern struct subsystem devices_subsys; + +#define to_sysdev(k) container_of(k,struct sys_device,kobj) +#define to_sysdev_attr(a) container_of(a,struct sysdev_attribute,attr) + + +static ssize_t +sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer) +{ + struct sys_device * sysdev = to_sysdev(kobj); + struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); + + if (sysdev_attr->show) + return sysdev_attr->show(sysdev,buffer); + return 0; +} + + +static ssize_t +sysdev_store(struct kobject * kobj, struct attribute * attr, + const char * buffer, size_t count) +{ + struct sys_device * sysdev = to_sysdev(kobj); + struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); + + if (sysdev_attr->store) + return sysdev_attr->store(sysdev,buffer,count); + return 0; +} + +static struct sysfs_ops sysfs_ops = { + .show = sysdev_show, + .store = sysdev_store, +}; + +static struct kobj_type ktype_sysdev = { + .sysfs_ops = &sysfs_ops, }; +/* + * declare system_subsys + */ +decl_subsys(system,&ktype_sysdev,NULL); + +int sysdev_class_register(struct sysdev_class * cls) +{ + pr_debug("Registering sysdev class '%s'\n",cls->kset.kobj.name); + INIT_LIST_HEAD(&cls->drivers); + cls->kset.subsys = &system_subsys; + kset_set_kset_s(cls,system_subsys); + return kset_register(&cls->kset); +} + +void sysdev_class_unregister(struct sysdev_class * cls) +{ + pr_debug("Unregistering sysdev class '%s'\n",cls->kset.kobj.name); + kset_unregister(&cls->kset); +} + +EXPORT_SYMBOL(sysdev_class_register); +EXPORT_SYMBOL(sysdev_class_unregister); + + +static LIST_HEAD(global_drivers); /** - * sys_register_root - add a subordinate system root - * @root: new root - * - * This is for NUMA-like systems so they can accurately - * represent the topology of the entire system. - * As boards are discovered, a new struct sys_root should - * be allocated and registered. - * The discovery mechanism should initialize the id field - * of the struture, as well as much of the embedded device - * structure as possible, inlcuding the name, the bus_id - * and parent fields. + * sysdev_driver_register - Register auxillary driver + * @cls: Device class driver belongs to. + * @drv: Driver. * - * This simply calls device_register on the embedded device. - * On success, it will use the struct @root->sysdev - * device to create a pseudo-parent for system devices - * on that board. + * If @cls is valid, then @drv is inserted into @cls->drivers to be + * called on each operation on devices of that class. The refcount + * of @cls is incremented. + * Otherwise, @drv is inserted into global_drivers, and called for + * each device. + */ + +int sysdev_driver_register(struct sysdev_class * cls, + struct sysdev_driver * drv) +{ + down_write(&system_subsys.rwsem); + if (cls && kset_get(&cls->kset)) + list_add_tail(&drv->entry,&cls->drivers); + else + list_add_tail(&drv->entry,&global_drivers); + up_write(&system_subsys.rwsem); + return 0; +} + + +/** + * sysdev_driver_unregister - Remove an auxillary driver. + * @cls: Class driver belongs to. + * @drv: Driver. + */ +void sysdev_driver_unregister(struct sysdev_class * cls, + struct sysdev_driver * drv) +{ + down_write(&system_subsys.rwsem); + list_del_init(&drv->entry); + if (cls) + kset_put(&cls->kset); + up_write(&system_subsys.rwsem); +} + + +/** + * sys_device_register - add a system device to the tree + * @sysdev: device in question * - * The platform code can then use @root to specifiy the - * controlling board when discovering and registering - * system devices. */ -int sys_register_root(struct sys_root * root) +int sys_device_register(struct sys_device * sysdev) { - int error = 0; + int error; + struct sysdev_class * cls = sysdev->cls; - if (!root) + if (!cls) return -EINVAL; - if (!root->dev.parent) - root->dev.parent = &system_bus; + /* Make sure the kset is set */ + sysdev->kobj.kset = &cls->kset; + + /* set the kobject name */ + snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d", + cls->kset.kobj.name,sysdev->id); - pr_debug("Registering system board %d\n",root->id); + pr_debug("Registering sys device '%s'\n",sysdev->kobj.name); + + /* Register the object */ + error = kobject_register(&sysdev->kobj); - error = device_register(&root->dev); if (!error) { - strlcpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE); - strlcpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE); - root->sysdev.parent = &root->dev; - error = device_register(&root->sysdev); - }; + struct sysdev_driver * drv; + + down_read(&system_subsys.rwsem); + /* Generic notification is implicit, because it's that + * code that should have called us. + */ + /* Notify global drivers */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->add) + drv->add(sysdev); + } + + /* Notify class auxillary drivers */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->add) + drv->add(sysdev); + } + up_read(&system_subsys.rwsem); + } return error; } +void sys_device_unregister(struct sys_device * sysdev) +{ + struct sysdev_driver * drv; + + down_read(&system_subsys.rwsem); + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->remove) + drv->remove(sysdev); + } + + list_for_each_entry(drv,&sysdev->cls->drivers,entry) { + if (drv->remove) + drv->remove(sysdev); + } + up_read(&system_subsys.rwsem); + + kobject_unregister(&sysdev->kobj); +} + + + /** - * sys_unregister_root - remove subordinate root from tree - * @root: subordinate root in question. + * sysdev_shutdown - Shut down all system devices. + * + * Loop over each class of system devices, and the devices in each + * of those classes. For each device, we call the shutdown method for + * each driver registered for the device - the globals, the auxillaries, + * and the class driver. * - * We only decrement the reference count on @root->sysdev - * and @root->dev. - * If both are 0, they will be cleaned up by the core. + * Note: The list is iterated in reverse order, so that we shut down + * child devices before we shut down thier parents. The list ordering + * is guaranteed by virtue of the fact that child devices are registered + * after their parents. */ -void sys_unregister_root(struct sys_root *root) + +void sysdev_shutdown(void) { - device_unregister(&root->sysdev); - device_unregister(&root->dev); + struct sysdev_class * cls; + + pr_debug("Shutting Down System Devices\n"); + + down_write(&system_subsys.rwsem); + list_for_each_entry_reverse(cls,&system_subsys.kset.list, + kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Shutting down type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); + + /* Call global drivers first. */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->shutdown) + drv->shutdown(sysdev); + } + + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->shutdown) + drv->shutdown(sysdev); + } + + /* Now call the generic one */ + if (cls->shutdown) + cls->shutdown(sysdev); + } + } + up_write(&system_subsys.rwsem); } + /** - * sys_device_register - add a system device to the tree - * @sysdev: device in question + * sysdev_save - Save system device state + * @state: Power state we're entering. * - * The hardest part about this is getting the ancestry right. - * If the device has a parent - super! We do nothing. - * If the device doesn't, but @dev->root is set, then we're - * dealing with a NUMA like architecture where each root - * has a system pseudo-bus to foster the device. - * If not, then we fallback to system_bus (at the top of - * this file). + * This is called when the system is going to sleep, but before interrupts + * have been disabled. This allows system device drivers to allocate and + * save device state, including sleeping during the process.. + */ + +int sysdev_save(u32 state) +{ + struct sysdev_class * cls; + + pr_debug("Saving System Device State\n"); + + down_write(&system_subsys.rwsem); + + list_for_each_entry_reverse(cls,&system_subsys.kset.list, + kset.kobj.entry) { + struct sys_device * sysdev; + pr_debug("Saving state for type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + + pr_debug(" %s\n",sysdev->kobj.name); + + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->save) + drv->save(sysdev,state); + } + + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->save) + drv->save(sysdev,state); + } + + if (cls->save) + cls->save(sysdev,state); + } + } + up_write(&system_subsys.rwsem); + return 0; +} + + +/** + * sysdev_suspend - Suspend all system devices. + * @state: Power state to enter. * - * One way or another, we call device_register() on it and - * are done. + * We perform an almost identical operation as sys_device_shutdown() + * above, though calling ->suspend() instead. * - * The caller is also responsible for initializing the bus_id - * and name fields of @sysdev->dev. + * Note: Interrupts are disabled when called, so we can't sleep when + * trying to get the subsystem's rwsem. If that happens, print a nasty + * warning and return an error. */ -int sys_device_register(struct sys_device * sysdev) + +int sysdev_suspend(u32 state) { - if (!sysdev) - return -EINVAL; + struct sysdev_class * cls; + + pr_debug("Suspending System Devices\n"); - if (!sysdev->dev.parent) { - if (sysdev->root) - sysdev->dev.parent = &sysdev->root->sysdev; - else - sysdev->dev.parent = &system_bus; + if (!down_write_trylock(&system_subsys.rwsem)) { + printk("%s: Cannot acquire semaphore; Failing\n",__FUNCTION__); + return -EFAULT; } - /* make sure bus type is set */ - if (!sysdev->dev.bus) - sysdev->dev.bus = &system_bus_type; + list_for_each_entry_reverse(cls,&system_subsys.kset.list, + kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Suspending type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); - /* construct bus_id */ - snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id); + /* Call global drivers first. */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->suspend) + drv->suspend(sysdev,state); + } - pr_debug("Registering system device %s\n", sysdev->dev.bus_id); + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->suspend) + drv->suspend(sysdev,state); + } - return device_register(&sysdev->dev); + /* Now call the generic one */ + if (cls->suspend) + cls->suspend(sysdev,state); + } + } + up_write(&system_subsys.rwsem); + + return 0; } -void sys_device_unregister(struct sys_device * sysdev) + +/** + * sysdev_resume - Bring system devices back to life. + * + * Similar to sys_device_suspend(), but we iterate the list forwards + * to guarantee that parent devices are resumed before their children. + * + * Note: Interrupts are disabled when called. + */ + +int sysdev_resume(void) { - if (sysdev) - device_unregister(&sysdev->dev); + struct sysdev_class * cls; + + pr_debug("Resuming System Devices\n"); + + if(!down_write_trylock(&system_subsys.rwsem)) + return -EFAULT; + + list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Resuming type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); + + /* First, call the class-specific one */ + if (cls->resume) + cls->resume(sysdev); + + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->resume) + drv->resume(sysdev); + } + + /* Call global drivers. */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->resume) + drv->resume(sysdev); + } + + } + } + up_write(&system_subsys.rwsem); + return 0; +} + + +/** + * sysdev_restore - Restore system device state + * + * This is called during a suspend/resume cycle last, after interrupts + * have been re-enabled. This is intended for auxillary drivers, etc, + * that may sleep when restoring state. + */ + +int sysdev_restore(void) +{ + struct sysdev_class * cls; + + down_write(&system_subsys.rwsem); + pr_debug("Restoring System Device State\n"); + + list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Restoring state for type '%s':\n",cls->kset.kobj.name); + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); + + if (cls->restore) + cls->restore(sysdev); + + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->restore) + drv->restore(sysdev); + } + + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->restore) + drv->restore(sysdev); + } + } + } + + up_write(&system_subsys.rwsem); + return 0; } -struct bus_type system_bus_type = { - .name = "system", -}; int __init sys_bus_init(void) { - bus_register(&system_bus_type); - return device_register(&system_bus); + system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj; + return subsystem_register(&system_subsys); } -EXPORT_SYMBOL(system_bus_type); EXPORT_SYMBOL(sys_device_register); EXPORT_SYMBOL(sys_device_unregister); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index fbb02dd40042..486e0111891d 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -34,7 +34,7 @@ #include <linux/blk.h> #include <linux/blkpg.h> #include <linux/hdreg.h> /* HDIO_GETGEO */ -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/bio.h> #include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> @@ -48,12 +48,14 @@ #define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x) #define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) + +static struct sysdev_class xpram_sysclass = { + set_kset_name("xpram"), +}; + static struct sys_device xpram_sys_device = { - .name = "S/390 expanded memory RAM disk", - .dev = { - .name = "S/390 expanded memory RAM disk", - .bus_id = "xpram", - }, + .id = 0, + .cls = &xpram_sysclass, }; typedef struct { @@ -485,6 +487,7 @@ static void __exit xpram_exit(void) unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); devfs_remove("slram"); sys_device_unregister(&xpram_sys_device); + sysdev_class_unregister(&xpram_sys_class); } static int __init xpram_init(void) @@ -502,9 +505,15 @@ static int __init xpram_init(void) rc = xpram_setup_sizes(xpram_pages); if (rc) return rc; - rc = sys_device_register(&xpram_sys_device); + rc = sysdev_class_register(&xpram_sysclass); if (rc) return rc; + + rc = sys_device_register(&xpram_sys_device); + if (rc) { + sysdev_class_unregister(&xpram_syclass); + return rc; + } rc = xpram_setup_blkdev(); if (rc) sys_device_unregister(&xpram_sys_device); |
