Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+75 −21
Original line number Diff line number Diff line
@@ -153,44 +153,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
	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
 * @creator_id: identifier of creating driver
 * @cdrv: ccw driver of slave devices
 * @argc: number of slave devices
 * @argv: bus ids of slave devices
 * @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 @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.
 * Returns:
 *  %0 on success and an error code on failure.
 * Context:
 *  non-atomic
 */
int ccwgroup_create(struct device *root, unsigned int creator_id,
		    struct ccw_driver *cdrv, int argc, char *argv[])
int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
				struct ccw_driver *cdrv, int num_devices,
				const char *buf)
{
	struct ccwgroup_device *gdev;
	int i;
	int rc;

	if (argc > 256) /* disallow dumb users */
		return -EINVAL;
	int rc, i;
	char tmp_bus_id[BUS_ID_SIZE];
	const char *curr_buf;

	gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
	gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
		       GFP_KERNEL);
	if (!gdev)
		return -ENOMEM;

	atomic_set(&gdev->onoff, 0);
	mutex_init(&gdev->reg_mutex);
	mutex_lock(&gdev->reg_mutex);
	for (i = 0; i < argc; i++) {
		gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);

		/* all devices have to be of the same type in
		 * order to be grouped */
	curr_buf = buf;
	for (i = 0; i < num_devices && curr_buf; i++) {
		rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
		if (rc != 0)
			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]
		    || gdev->cdev[i]->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);
	}

	/* 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->count = argc;
	gdev->count = num_devices;
	gdev->dev.bus = &ccwgroup_bus_type;
	gdev->dev.parent = root;
	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_unregister(&gdev->dev);
error:
	for (i = 0; i < argc; i++)
	for (i = 0; i < num_devices; i++)
		if (gdev->cdev[i]) {
			if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
				dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
@@ -244,6 +298,7 @@ error:
	put_device(&gdev->dev);
	return rc;
}
EXPORT_SYMBOL(ccwgroup_create_from_string);

static int __init
init_ccwgroup (void)
@@ -519,6 +574,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccwgroup_driver_register);
EXPORT_SYMBOL(ccwgroup_driver_unregister);
EXPORT_SYMBOL(ccwgroup_create);
EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
+2 −18
Original line number Diff line number Diff line
@@ -62,30 +62,14 @@ static struct device *cu3088_root_dev;
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 -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);
	ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
					  &cu3088_driver, 2, buf);

	return (ret == 0) ? count : ret;
}
+2 −21
Original line number Diff line number Diff line
@@ -3827,27 +3827,8 @@ static struct ccw_driver qeth_ccw_driver = {
static int qeth_core_driver_group(const char *buf, struct device *root_dev,
				unsigned long driver_id)
{
	const char *start, *end;
	char bus_ids[3][BUS_ID_SIZE], *argv[3];
	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));
	return ccwgroup_create_from_string(root_dev, driver_id,
					   &qeth_ccw_driver, 3, buf);
}

int qeth_core_hardsetup_card(struct qeth_card *card)
+3 −4
Original line number Diff line number Diff line
@@ -57,10 +57,9 @@ struct ccwgroup_driver {

extern int  ccwgroup_driver_register   (struct ccwgroup_driver *cdriver);
extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
extern int ccwgroup_create (struct device *root,
			    unsigned int creator_id,
			    struct ccw_driver *gdrv,
			    int argc, char *argv[]);
int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
				struct ccw_driver *cdrv, int num_devices,
				const char *buf);

extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);