static int ccwgroup_probe(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); return gdrv->probe ? gdrv->probe(gdev) : -ENODEV; }
static ssize_t ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); int rc; /* Prevent concurrent online/offline processing and ungrouping. */ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) return -EAGAIN; if (gdev->state != CCWGROUP_OFFLINE) { rc = -EINVAL; goto out; } if (device_remove_file_self(dev, attr)) ccwgroup_ungroup(gdev); out: if (rc) { if (rc != -EAGAIN) /* Release onoff "lock" when ungrouping failed. */ atomic_set(&gdev->onoff, 0); return rc; } return count; }
static ssize_t ccwgroup_online_store (struct device *dev, const char *buf, size_t count) { struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; unsigned int value; int ret; gdev = to_ccwgroupdev(dev); if (!dev->driver) return count; gdrv = to_ccwgroupdrv (gdev->dev.driver); if (!try_module_get(gdrv->owner)) return -EINVAL; value = simple_strtoul(buf, 0, 0); ret = count; if (value == 1) ccwgroup_set_online(gdev); else if (value == 0) ccwgroup_set_offline(gdev); else ret = -EINVAL; module_put(gdrv->owner); return ret; }
static ssize_t ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev; int rc; gdev = to_ccwgroupdev(dev); /* Prevent concurrent online/offline processing and ungrouping. */ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) return -EAGAIN; if (gdev->state != CCWGROUP_OFFLINE) { rc = -EINVAL; goto out; } /* Note that we cannot unregister the device from one of its * attribute methods, so we have to use this roundabout approach. */ rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); out: if (rc) { if (rc != -EAGAIN) /* Release onoff "lock" when ungrouping failed. */ atomic_set(&gdev->onoff, 0); return rc; } return count; }
static ssize_t ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; unsigned long value; int ret; if (!dev->driver) return -ENODEV; gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); if (!try_module_get(gdrv->owner)) return -EINVAL; ret = strict_strtoul(buf, 0, &value); if (ret) goto out; if (value == 1) ret = ccwgroup_set_online(gdev); else if (value == 0) ret = ccwgroup_set_offline(gdev); else ret = -EINVAL; out: module_put(gdrv->owner); return (ret == 0) ? count : ret; }
static ssize_t ccwgroup_online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); unsigned long value; int ret; device_lock(dev); if (!dev->driver) { ret = -EINVAL; goto out; } ret = kstrtoul(buf, 0, &value); if (ret) goto out; if (value == 1) ret = ccwgroup_set_online(gdev); else if (value == 0) ret = ccwgroup_set_offline(gdev); else ret = -EINVAL; out: device_unlock(dev); return (ret == 0) ? count : ret; }
/* * Provide an 'ungroup' attribute so the user can remove group devices no * longer needed or accidentially created. Saves memory :) */ static void ccwgroup_ungroup_callback(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); mutex_lock(&gdev->reg_mutex); __ccwgroup_remove_symlinks(gdev); device_unregister(dev); mutex_unlock(&gdev->reg_mutex); }
static ssize_t ccwgroup_online_show (struct device *dev, char *buf) { int online; online = (to_ccwgroupdev(dev)->state == CCWGROUP_ONLINE); return sprintf(buf, online ? "1\n" : "0\n"); }
static void ccwgroup_shutdown(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); if (!dev->driver) return; if (gdrv->shutdown) gdrv->shutdown(gdev); }
/* a device matches a driver if all its slave devices match the same * entry of the driver */ static int ccwgroup_bus_match(struct device *dev, struct device_driver * drv) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ccwgroup_driver *gdrv = to_ccwgroupdrv(drv); if (gdev->creator_id == gdrv->driver_id) return 1; return 0; }
static int ccwgroup_pm_restore(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) return 0; return gdrv->restore ? gdrv->restore(gdev) : 0; }
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, void *data) { struct ccwgroup_device *gdev = to_ccwgroupdev(data); if (action == BUS_NOTIFY_UNBIND_DRIVER) schedule_work(&gdev->ungroup_work); return NOTIFY_OK; }
static void ccwgroup_pm_complete(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) return; if (gdrv->complete) gdrv->complete(gdev); }
static ssize_t ccwgroup_online_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); int online; online = (gdev->state == CCWGROUP_ONLINE) ? 1 : 0; return scnprintf(buf, PAGE_SIZE, "%d\n", online); }
static ssize_t stats_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ctcm_priv *priv = dev_get_drvdata(dev); if (!priv || gdev->state != CCWGROUP_ONLINE) return -ENODEV; ctcm_print_statistics(priv); return sprintf(buf, "0\n"); }
static int ccwgroup_remove(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); if (!dev->driver) return 0; if (gdrv->remove) gdrv->remove(gdev); return 0; }
static ssize_t ctcm_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ccwgroup_device *cgdev; cgdev = to_ccwgroupdev(dev); if (!cgdev) return -ENODEV; return sprintf(buf, "%s\n", ctcm_type[cgdev->cdev[0]->id.driver_info]); }
static void ccwgroup_release (struct device *dev) { struct ccwgroup_device *gdev; int i; gdev = to_ccwgroupdev(dev); for (i = 0; i < gdev->count; i++) { gdev->cdev[i]->dev.driver_data = NULL; put_device(&gdev->cdev[i]->dev); } kfree(gdev); }
static int ccwgroup_pm_prepare(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); /* Fail while device is being set online/offline. */ if (atomic_read(&gdev->onoff)) return -EAGAIN; if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) return 0; return gdrv->prepare ? gdrv->prepare(gdev) : 0; }
/* * Provide an 'ungroup' attribute so the user can remove group devices no * longer needed or accidentially created. Saves memory :) */ static ssize_t ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count) { struct ccwgroup_device *gdev; gdev = to_ccwgroupdev(dev); if (gdev->state != CCWGROUP_OFFLINE) return -EINVAL; __ccwgroup_remove_symlinks(gdev); device_unregister(dev); return count; }
static int ccwgroup_remove (struct device *dev) { struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); device_remove_file(dev, &dev_attr_online); if (gdrv && gdrv->remove) gdrv->remove(gdev); 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 = driver_find_device(&cdriver->driver, NULL, NULL, __ccwgroup_match_all))) { __ccwgroup_remove_symlinks(to_ccwgroupdev(dev)); device_unregister(dev); put_device(dev); } put_driver(&cdriver->driver); driver_unregister(&cdriver->driver); }
static void ccwgroup_release (struct device *dev) { struct ccwgroup_device *gdev; int i; gdev = to_ccwgroupdev(dev); for (i = 0; i < gdev->count; i++) { if (gdev->cdev[i]) { if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) dev_set_drvdata(&gdev->cdev[i]->dev, NULL); put_device(&gdev->cdev[i]->dev); } } kfree(gdev); }
static int ccwgroup_remove (struct device *dev) { struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); pr_debug("%s: device %s\n", __func__, gdev->dev.bus_id); device_remove_file(dev, &dev_attr_online); if (gdrv && gdrv->remove) gdrv->remove(gdev); return 0; }
/** * ccwgroup_driver_unregister() - deregister a ccw group driver * @cdriver: driver to be deregistered * * This function is mainly a wrapper around driver_unregister(). */ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) { struct device *dev; /* We don't want ccwgroup devices to live longer than their driver. */ while ((dev = driver_find_device(&cdriver->driver, NULL, NULL, __ccwgroup_match_all))) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); mutex_lock(&gdev->reg_mutex); __ccwgroup_remove_symlinks(gdev); device_unregister(dev); __ccwgroup_remove_cdev_refs(gdev); mutex_unlock(&gdev->reg_mutex); put_device(dev); } driver_unregister(&cdriver->driver); }
static ssize_t ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev; int rc; gdev = to_ccwgroupdev(dev); if (gdev->state != CCWGROUP_OFFLINE) return -EINVAL; /* Note that we cannot unregister the device from one of its * attribute methods, so we have to use this roundabout approach. */ rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); if (rc) count = rc; return count; }
/* * Provide an 'ungroup' attribute so the user can remove group devices no * longer needed or accidentially created. Saves memory :) */ static ssize_t ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count) { struct ccwgroup_device *gdev; gdev = to_ccwgroupdev(dev); /* Prevent concurrent online/offline processing and ungrouping. */ if (atomic_compare_and_swap(0, 1, &gdev->onoff)) return -EAGAIN; if (gdev->state != CCWGROUP_OFFLINE) { /* Release onoff "lock" when ungrouping failed. */ atomic_set(&gdev->onoff, 0); return -EINVAL; } __ccwgroup_remove_symlinks(gdev); device_unregister(dev); return count; }
static int ccwgroup_probe (struct device *dev) { struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; int ret; gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); if ((ret = device_create_file(dev, &dev_attr_online))) return ret; ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV; if (ret) device_remove_file(dev, &dev_attr_online); return ret; }
static void ccwgroup_release (struct device *dev) { kfree(to_ccwgroupdev(dev)); }