/* In Linux 2.4, we had a channel device layer called "chandev" * that did all sorts of obscure stuff for networking devices. * This is another driver that serves as a replacement for just * one of its functions, namely the translation of single subchannels * to devices that use multiple subchannels.
*/
staticconststruct bus_type ccwgroup_bus_type;
staticvoid __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
{ int i; char str[16];
for (i = 0; i < gdev->count; i++) {
sprintf(str, "cdev%d", i);
sysfs_remove_link(&gdev->dev.kobj, str);
sysfs_remove_link(&gdev->cdev[i]->dev.kobj, "group_device");
}
}
/** * ccwgroup_set_online() - enable a ccwgroup device * @gdev: target ccwgroup device * * This function attempts to put the ccwgroup device into the online state. * Returns: * %0 on success and a negative error value on failure.
*/ int ccwgroup_set_online(struct ccwgroup_device *gdev)
{ struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); int ret = -EINVAL;
if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) return -EAGAIN; if (gdev->state == CCWGROUP_ONLINE) goto out; if (gdrv->set_online)
ret = gdrv->set_online(gdev); if (ret) goto out;
/** * ccwgroup_set_offline() - disable a ccwgroup device * @gdev: target ccwgroup device * @call_gdrv: Call the registered gdrv set_offline function * * This function attempts to put the ccwgroup device into the offline state. * Returns: * %0 on success and a negative error value on failure.
*/ int ccwgroup_set_offline(struct ccwgroup_device *gdev, bool call_gdrv)
{ struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); int ret = -EINVAL;
if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) return -EAGAIN; if (gdev->state == CCWGROUP_OFFLINE) goto out; if (!call_gdrv) {
ret = 0; goto offline;
} if (gdrv->set_offline)
ret = gdrv->set_offline(gdev); if (ret) goto out;
/* * Provide an 'ungroup' attribute so the user can remove group devices no * longer needed or accidentally created. Saves memory :)
*/ staticvoid ccwgroup_ungroup(struct ccwgroup_device *gdev)
{
mutex_lock(&gdev->reg_mutex); if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev);
device_unregister(&gdev->dev);
}
mutex_unlock(&gdev->reg_mutex);
}
/** * ccwgroup_create_dev() - create and register a ccw group device * @parent: parent device for the new device * @gdrv: driver for the new group device * @num_devices: number of slave devices * @buf: buffer containing comma separated bus ids of slave devices * * Create and register a new ccw group device as a child of @parent. Slave * devices are obtained from the list of bus ids given in @buf. * Returns: * %0 on success and an error code on failure. * Context: * non-atomic
*/ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, int num_devices, constchar *buf)
{ struct ccwgroup_device *gdev; struct ccw_dev_id dev_id; int rc, i;
if (num_devices < 1) return -EINVAL;
gdev = kzalloc(struct_size(gdev, cdev, num_devices), GFP_KERNEL); if (!gdev) return -ENOMEM;
for (i = 0; i < num_devices && buf; i++) {
rc = __get_next_id(&buf, &dev_id); if (rc != 0) goto error;
gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id); /* * All devices have to be of the same type in * order to be grouped.
*/ if (!gdev->cdev[i] || !gdev->cdev[i]->drv ||
gdev->cdev[i]->drv != gdev->cdev[0]->drv ||
gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
rc = -EINVAL; goto error;
} /* Don't allow a device to belong to more than one group. */
spin_lock_irq(gdev->cdev[i]->ccwlock); if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
spin_unlock_irq(gdev->cdev[i]->ccwlock);
rc = -EINVAL; goto error;
}
dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
spin_unlock_irq(gdev->cdev[i]->ccwlock);
} /* Check for sufficient number of bus ids. */ if (i < num_devices) {
rc = -EINVAL; goto error;
} /* Check for trailing stuff. */ if (i == num_devices && buf && strlen(buf) > 0) {
rc = -EINVAL; goto error;
} /* Check if the devices are bound to the required ccw driver. */ if (gdrv && gdrv->ccw_driver &&
gdev->cdev[0]->drv != gdrv->ccw_driver) {
rc = -EINVAL; goto error;
}
/** * ccwgroup_driver_register() - register a ccw group driver * @cdriver: driver to be registered * * This function is mainly a wrapper around driver_register().
*/ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
{ /* register our new driver with the core */
cdriver->driver.bus = &ccwgroup_bus_type;
/** * 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)
{
driver_unregister(&cdriver->driver);
}
EXPORT_SYMBOL(ccwgroup_driver_unregister);
/** * ccwgroup_probe_ccwdev() - probe function for slave devices * @cdev: ccw device to be probed * * This is a dummy probe function for ccw devices that are slave devices in * a ccw group device. * Returns: * always %0
*/ int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
{ return 0;
}
EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
/** * ccwgroup_remove_ccwdev() - remove function for slave devices * @cdev: ccw device to be removed * * This is a remove function for ccw devices that are slave devices in a ccw * group device. It sets the ccw device offline and also deregisters the * embedding ccw group device.
*/ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
{ struct ccwgroup_device *gdev;
/* Ignore offlining errors, device is gone anyway. */
ccw_device_set_offline(cdev); /* If one of its devices is gone, the whole group is done for. */
spin_lock_irq(cdev->ccwlock);
gdev = dev_get_drvdata(&cdev->dev); if (!gdev) {
spin_unlock_irq(cdev->ccwlock); return;
} /* Get ccwgroup device reference for local processing. */
get_device(&gdev->dev);
spin_unlock_irq(cdev->ccwlock); /* Unregister group device. */
ccwgroup_ungroup(gdev); /* Release ccwgroup device reference for local processing. */
put_device(&gdev->dev);
}
EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
MODULE_DESCRIPTION("ccwgroup bus driver");
MODULE_LICENSE("GPL");
Messung V0.5
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.