Commit 022b660a authored by Ursula Braun's avatar Ursula Braun Committed by Jeff Garzik

ccwgroup: Unify parsing for group attribute.

Instead of having each driver for ccwgroup slave device parsing the
input itself and calling ccwgroup_create(), introduce a new function
ccwgroup_create_from_string() and handle parsing inside the ccwgroup
core.
Signed-off-by: default avatarUrsula Braun <braunu@de.ibm.com>
Signed-off-by: default avatarFrank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 8bbf8440
...@@ -153,44 +153,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) ...@@ -153,44 +153,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0; return 0;
} }
static int __get_next_bus_id(const char **buf, char *bus_id)
{
int rc, len;
char *start, *end;
start = (char *)*buf;
end = strchr(start, ',');
if (!end) {
/* Last entry. Strip trailing newline, if applicable. */
end = strchr(start, '\n');
if (end)
*end = '\0';
len = strlen(start) + 1;
} else {
len = end - start + 1;
end++;
}
if (len < BUS_ID_SIZE) {
strlcpy(bus_id, start, len);
rc = 0;
} else
rc = -EINVAL;
*buf = end;
return rc;
}
static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
{
int cssid, ssid, devno;
/* Must be of form %x.%x.%04x */
if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
return 0;
return 1;
}
/** /**
* ccwgroup_create() - create and register a ccw group device * ccwgroup_create_from_string() - create and register a ccw group device
* @root: parent device for the new device * @root: parent device for the new device
* @creator_id: identifier of creating driver * @creator_id: identifier of creating driver
* @cdrv: ccw driver of slave devices * @cdrv: ccw driver of slave devices
* @argc: number of slave devices * @num_devices: number of slave devices
* @argv: bus ids 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 @root. Slave * Create and register a new ccw group device as a child of @root. Slave
* devices are obtained from the list of bus ids given in @argv[] and must all * devices are obtained from the list of bus ids given in @buf and must all
* belong to @cdrv. * belong to @cdrv.
* Returns: * Returns:
* %0 on success and an error code on failure. * %0 on success and an error code on failure.
* Context: * Context:
* non-atomic * non-atomic
*/ */
int ccwgroup_create(struct device *root, unsigned int creator_id, int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
struct ccw_driver *cdrv, int argc, char *argv[]) struct ccw_driver *cdrv, int num_devices,
const char *buf)
{ {
struct ccwgroup_device *gdev; struct ccwgroup_device *gdev;
int i; int rc, i;
int rc; char tmp_bus_id[BUS_ID_SIZE];
const char *curr_buf;
if (argc > 256) /* disallow dumb users */ gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
return -EINVAL; GFP_KERNEL);
gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
if (!gdev) if (!gdev)
return -ENOMEM; return -ENOMEM;
atomic_set(&gdev->onoff, 0); atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex); mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex); mutex_lock(&gdev->reg_mutex);
for (i = 0; i < argc; i++) { curr_buf = buf;
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); for (i = 0; i < num_devices && curr_buf; i++) {
rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
/* all devices have to be of the same type in if (rc != 0)
* order to be grouped */ goto error;
if (!__is_valid_bus_id(tmp_bus_id)) {
rc = -EINVAL;
goto error;
}
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
/*
* All devices have to be of the same type in
* order to be grouped.
*/
if (!gdev->cdev[i] if (!gdev->cdev[i]
|| gdev->cdev[i]->id.driver_info != || gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) { gdev->cdev[0]->id.driver_info) {
...@@ -204,9 +249,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, ...@@ -204,9 +249,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
} }
dev_set_drvdata(&gdev->cdev[i]->dev, gdev); dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
} }
/* Check for sufficient number of bus ids. */
if (i < num_devices && !curr_buf) {
rc = -EINVAL;
goto error;
}
/* Check for trailing stuff. */
if (i == num_devices && strlen(curr_buf) > 0) {
rc = -EINVAL;
goto error;
}
gdev->creator_id = creator_id; gdev->creator_id = creator_id;
gdev->count = argc; gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type; gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = root; gdev->dev.parent = root;
gdev->dev.release = ccwgroup_release; gdev->dev.release = ccwgroup_release;
...@@ -234,7 +288,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, ...@@ -234,7 +288,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
device_remove_file(&gdev->dev, &dev_attr_ungroup); device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev); device_unregister(&gdev->dev);
error: error:
for (i = 0; i < argc; i++) for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) { if (gdev->cdev[i]) {
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL); dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
...@@ -244,6 +298,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, ...@@ -244,6 +298,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
put_device(&gdev->dev); put_device(&gdev->dev);
return rc; return rc;
} }
EXPORT_SYMBOL(ccwgroup_create_from_string);
static int __init static int __init
init_ccwgroup (void) init_ccwgroup (void)
...@@ -519,6 +574,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev) ...@@ -519,6 +574,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccwgroup_driver_register); EXPORT_SYMBOL(ccwgroup_driver_register);
EXPORT_SYMBOL(ccwgroup_driver_unregister); EXPORT_SYMBOL(ccwgroup_driver_unregister);
EXPORT_SYMBOL(ccwgroup_create);
EXPORT_SYMBOL(ccwgroup_probe_ccwdev); EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
EXPORT_SYMBOL(ccwgroup_remove_ccwdev); EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
...@@ -62,30 +62,14 @@ static struct device *cu3088_root_dev; ...@@ -62,30 +62,14 @@ static struct device *cu3088_root_dev;
static ssize_t static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count) 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; int ret;
struct ccwgroup_driver *cdrv; struct ccwgroup_driver *cdrv;
cdrv = to_ccwgroupdrv(drv); cdrv = to_ccwgroupdrv(drv);
if (!cdrv) if (!cdrv)
return -EINVAL; return -EINVAL;
start = buf; ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
for (i=0; i<2; i++) { &cu3088_driver, 2, buf);
static const char delim[] = {',', '\n'};
int len;
if (!(end = strchr(start, delim[i])))
return -EINVAL;
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; return (ret == 0) ? count : ret;
} }
......
...@@ -3827,27 +3827,8 @@ static struct ccw_driver qeth_ccw_driver = { ...@@ -3827,27 +3827,8 @@ static struct ccw_driver qeth_ccw_driver = {
static int qeth_core_driver_group(const char *buf, struct device *root_dev, static int qeth_core_driver_group(const char *buf, struct device *root_dev,
unsigned long driver_id) unsigned long driver_id)
{ {
const char *start, *end; return ccwgroup_create_from_string(root_dev, driver_id,
char bus_ids[3][BUS_ID_SIZE], *argv[3]; &qeth_ccw_driver, 3, buf);
int i;
start = buf;
for (i = 0; i < 3; i++) {
static const char delim[] = { ',', ',', '\n' };
int len;
end = strchr(start, delim[i]);
if (!end)
return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
strncpy(bus_ids[i], start, len);
bus_ids[i][len] = '\0';
start = end + 1;
argv[i] = bus_ids[i];
}
return (ccwgroup_create(root_dev, driver_id,
&qeth_ccw_driver, 3, argv));
} }
int qeth_core_hardsetup_card(struct qeth_card *card) int qeth_core_hardsetup_card(struct qeth_card *card)
......
...@@ -57,10 +57,9 @@ struct ccwgroup_driver { ...@@ -57,10 +57,9 @@ struct ccwgroup_driver {
extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver); extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
extern int ccwgroup_create (struct device *root, int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
unsigned int creator_id, struct ccw_driver *cdrv, int num_devices,
struct ccw_driver *gdrv, const char *buf);
int argc, char *argv[]);
extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev); extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev); extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment