static ssize_t group_write(struct device_driver *drv, const char *buf, size_t count) { const char *start, *end; char bus_ids[2][BUS_ID_SIZE], *argv[2]; int i; int ret; struct ccwgroup_driver *cdrv; cdrv = to_ccwgroupdrv(drv); if (!cdrv) return -EINVAL; start = buf; for (i=0; i<2; i++) { static const char delim[] = {',', '\n'}; int len; if (!(end = strchr(start, delim[i]))) return count; len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1); strlcpy (bus_ids[i], start, len); argv[i] = bus_ids[i]; start = end + 1; } ret = ccwgroup_create(&cu3088_root_dev, cdrv->driver_id, &cu3088_driver, 2, argv); return (ret == 0) ? count : ret; }
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_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 int ccwgroup_set_offline(struct ccwgroup_device *gdev) { struct ccwgroup_driver *gdrv; int ret; if (atomic_compare_and_swap(0, 1, &gdev->onoff)) return -EAGAIN; if (gdev->state == CCWGROUP_OFFLINE) { ret = 0; goto out; } if (!gdev->dev.driver) { ret = -EINVAL; goto out; } gdrv = to_ccwgroupdrv (gdev->dev.driver); if ((ret = gdrv->set_offline(gdev))) goto out; gdev->state = CCWGROUP_OFFLINE; out: atomic_set(&gdev->onoff, 0); return ret; }
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 int ccwgroup_set_online(struct ccwgroup_device *gdev) { struct ccwgroup_driver *gdrv; int ret; if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) return -EAGAIN; if (gdev->state == CCWGROUP_ONLINE) { ret = 0; goto out; } if (!gdev->dev.driver) { ret = -EINVAL; goto out; } gdrv = to_ccwgroupdrv (gdev->dev.driver); if ((ret = gdrv->set_online ? gdrv->set_online(gdev) : 0)) goto out; gdev->state = CCWGROUP_ONLINE; out: atomic_set(&gdev->onoff, 0); return ret; }
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 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 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 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 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; }
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; }
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; }
static int ccwgroup_set_offline(struct ccwgroup_device *gdev) { struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); int ret = 0; if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) return -EAGAIN; if (gdev->state == CCWGROUP_OFFLINE) goto out; if (gdrv->set_offline) ret = gdrv->set_offline(gdev); if (ret) goto out; gdev->state = CCWGROUP_OFFLINE; out: atomic_set(&gdev->onoff, 0); return ret; }
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; }