/*
* drivers/s390/cio/ccwgroup.c
* bus driver for ccwgroup
- * $Revision: 1.27 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
* Author(s): Arnd Bergmann (arndb@de.ibm.com)
- * Cornelia Huck (cohuck@de.ibm.com)
+ * Cornelia Huck (cornelia.huck@de.ibm.com)
*/
#include <linux/module.h>
#include <linux/errno.h>
return 0;
}
static int
-ccwgroup_hotplug (struct device *dev, char **envp, int num_envp, char *buffer,
+ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
int buffer_size)
{
/* TODO */
return 0;
}
-static struct bus_type ccwgroup_bus_type = {
- .name = "ccwgroup",
- .match = ccwgroup_bus_match,
- .hotplug = ccwgroup_hotplug,
-};
+static struct bus_type ccwgroup_bus_type;
static inline void
__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
* longer needed or accidentially created. Saves memory :)
*/
static ssize_t
-ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count)
+ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ccwgroup_device *gdev;
|| gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
rc = -EINVAL;
- goto error;
+ goto free_dev;
}
/* Don't allow a device to belong to more than one group. */
if (gdev->cdev[i]->dev.driver_data) {
rc = -EINVAL;
- goto error;
+ goto free_dev;
}
}
for (i = 0; i < argc; i++)
gdev->cdev[i]->dev.driver_data = gdev;
del_drvdata = 1;
- *gdev = (struct ccwgroup_device) {
- .creator_id = creator_id,
- .count = argc,
- .dev = {
- .bus = &ccwgroup_bus_type,
- .parent = root,
- .release = ccwgroup_release,
- },
+ gdev->creator_id = creator_id;
+ gdev->count = argc;
+ gdev->dev = (struct device ) {
+ .bus = &ccwgroup_bus_type,
+ .parent = root,
+ .release = ccwgroup_release,
};
snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s",
rc = device_register(&gdev->dev);
if (rc)
- goto error;
-
+ goto free_dev;
+ get_device(&gdev->dev);
rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
if (rc) {
}
rc = __ccwgroup_create_symlinks(gdev);
- if (!rc)
+ if (!rc) {
+ put_device(&gdev->dev);
return 0;
-
+ }
device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev);
error:
+ for (i = 0; i < argc; i++)
+ if (gdev->cdev[i]) {
+ put_device(&gdev->cdev[i]->dev);
+ gdev->cdev[i]->dev.driver_data = NULL;
+ }
+ put_device(&gdev->dev);
+ return rc;
+free_dev:
for (i = 0; i < argc; i++)
if (gdev->cdev[i]) {
put_device(&gdev->cdev[i]->dev);
gdev->cdev[i]->dev.driver_data = NULL;
}
kfree(gdev);
-
return rc;
}
struct ccwgroup_driver *gdrv;
int ret;
- if (atomic_compare_and_swap(0, 1, &gdev->onoff))
+ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0)
return -EAGAIN;
if (gdev->state == CCWGROUP_ONLINE) {
ret = 0;
goto out;
}
gdrv = to_ccwgroupdrv (gdev->dev.driver);
- if ((ret = gdrv->set_online(gdev)))
+ if ((ret = gdrv->set_online ? gdrv->set_online(gdev) : 0))
goto out;
gdev->state = CCWGROUP_ONLINE;
struct ccwgroup_driver *gdrv;
int ret;
- if (atomic_compare_and_swap(0, 1, &gdev->onoff))
+ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0)
return -EAGAIN;
if (gdev->state == CCWGROUP_OFFLINE) {
ret = 0;
goto out;
}
gdrv = to_ccwgroupdrv (gdev->dev.driver);
- if ((ret = gdrv->set_offline(gdev)))
+ if ((ret = gdrv->set_offline ? gdrv->set_offline(gdev) : 0))
goto out;
gdev->state = CCWGROUP_OFFLINE;
}
static ssize_t
-ccwgroup_online_store (struct device *dev, const char *buf, size_t count)
+ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ccwgroup_device *gdev;
struct ccwgroup_driver *gdrv;
}
static ssize_t
-ccwgroup_online_show (struct device *dev, char *buf)
+ccwgroup_online_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int online;
return 0;
}
+static struct bus_type ccwgroup_bus_type = {
+ .name = "ccwgroup",
+ .match = ccwgroup_bus_match,
+ .uevent = ccwgroup_uevent,
+ .probe = ccwgroup_probe,
+ .remove = ccwgroup_remove,
+};
+
int
ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
{
cdriver->driver = (struct device_driver) {
.bus = &ccwgroup_bus_type,
.name = cdriver->name,
- .probe = ccwgroup_probe,
- .remove = ccwgroup_remove,
};
return driver_register(&cdriver->driver);
}
-static inline struct device *
-__get_next_ccwgroup_device(struct device_driver *drv)
+static int
+__ccwgroup_driver_unregister_device(struct device *dev, void *data)
{
- struct device *dev, *d;
-
- down_read(&drv->bus->subsys.rwsem);
- dev = NULL;
- list_for_each_entry(d, &drv->devices, driver_list) {
- dev = get_device(d);
- if (dev)
- break;
- }
- up_read(&drv->bus->subsys.rwsem);
- return dev;
+ __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+ device_unregister(dev);
+ put_device(dev);
+ return 0;
}
void
ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
{
- struct device *dev;
-
/* We don't want ccwgroup devices to live longer than their driver. */
get_driver(&cdriver->driver);
- while ((dev = __get_next_ccwgroup_device(&cdriver->driver))) {
- __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
- device_unregister(dev);
- put_device(dev);
- };
+ driver_for_each_device(&cdriver->driver, NULL, NULL,
+ __ccwgroup_driver_unregister_device);
put_driver(&cdriver->driver);
driver_unregister(&cdriver->driver);
}
if (cdev->dev.driver_data) {
gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
if (get_device(&gdev->dev)) {
- if (!list_empty(&gdev->dev.node))
+ if (device_is_registered(&gdev->dev))
return gdev;
put_device(&gdev->dev);
}