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: Ursula Braun <braunu@de.ibm.com> Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
committed by
Jeff Garzik
parent
8bbf84404b
commit
022b660ae5
@@ -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,
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
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 @@ error:
|
|||||||
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)
|
|||||||
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;
|
|||||||
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 = {
|
|||||||
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 {
|
|||||||
|
|
||||||
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);
|
||||||
|
Reference in New Issue
Block a user