diff options
| author | Ursula Braun <braunu@de.ibm.com> | 2008-04-24 04:15:20 -0400 |
|---|---|---|
| committer | Jeff Garzik <jgarzik@redhat.com> | 2008-04-29 01:56:29 -0400 |
| commit | 022b660ae5d075ed9eaddef6f6fb7abb48bdf63b (patch) | |
| tree | 9520e014a156da3d70f26e859d4e9b838602f79b | |
| parent | 8bbf84404b02f193c5422c252264d7b82ffe4443 (diff) | |
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>
| -rw-r--r-- | drivers/s390/cio/ccwgroup.c | 96 | ||||
| -rw-r--r-- | drivers/s390/net/cu3088.c | 20 | ||||
| -rw-r--r-- | drivers/s390/net/qeth_core_main.c | 23 | ||||
| -rw-r--r-- | include/asm-s390/ccwgroup.h | 7 |
4 files changed, 82 insertions, 64 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 03914fa81174..f38923e38e92 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
| @@ -153,44 +153,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) | |||
| 153 | return 0; | 153 | return 0; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | static int __get_next_bus_id(const char **buf, char *bus_id) | ||
| 157 | { | ||
| 158 | int rc, len; | ||
| 159 | char *start, *end; | ||
| 160 | |||
| 161 | start = (char *)*buf; | ||
| 162 | end = strchr(start, ','); | ||
| 163 | if (!end) { | ||
| 164 | /* Last entry. Strip trailing newline, if applicable. */ | ||
| 165 | end = strchr(start, '\n'); | ||
| 166 | if (end) | ||
| 167 | *end = '\0'; | ||
| 168 | len = strlen(start) + 1; | ||
| 169 | } else { | ||
| 170 | len = end - start + 1; | ||
| 171 | end++; | ||
| 172 | } | ||
| 173 | if (len < BUS_ID_SIZE) { | ||
| 174 | strlcpy(bus_id, start, len); | ||
| 175 | rc = 0; | ||
| 176 | } else | ||
| 177 | rc = -EINVAL; | ||
| 178 | *buf = end; | ||
| 179 | return rc; | ||
| 180 | } | ||
| 181 | |||
| 182 | static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE]) | ||
| 183 | { | ||
| 184 | int cssid, ssid, devno; | ||
| 185 | |||
| 186 | /* Must be of form %x.%x.%04x */ | ||
| 187 | if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) | ||
| 188 | return 0; | ||
| 189 | return 1; | ||
| 190 | } | ||
| 191 | |||
| 156 | /** | 192 | /** |
| 157 | * ccwgroup_create() - create and register a ccw group device | 193 | * ccwgroup_create_from_string() - create and register a ccw group device |
| 158 | * @root: parent device for the new device | 194 | * @root: parent device for the new device |
| 159 | * @creator_id: identifier of creating driver | 195 | * @creator_id: identifier of creating driver |
| 160 | * @cdrv: ccw driver of slave devices | 196 | * @cdrv: ccw driver of slave devices |
| 161 | * @argc: number of slave devices | 197 | * @num_devices: number of slave devices |
| 162 | * @argv: bus ids of slave devices | 198 | * @buf: buffer containing comma separated bus ids of slave devices |
| 163 | * | 199 | * |
| 164 | * Create and register a new ccw group device as a child of @root. Slave | 200 | * Create and register a new ccw group device as a child of @root. Slave |
| 165 | * devices are obtained from the list of bus ids given in @argv[] and must all | 201 | * devices are obtained from the list of bus ids given in @buf and must all |
| 166 | * belong to @cdrv. | 202 | * belong to @cdrv. |
| 167 | * Returns: | 203 | * Returns: |
| 168 | * %0 on success and an error code on failure. | 204 | * %0 on success and an error code on failure. |
| 169 | * Context: | 205 | * Context: |
| 170 | * non-atomic | 206 | * non-atomic |
| 171 | */ | 207 | */ |
| 172 | int ccwgroup_create(struct device *root, unsigned int creator_id, | 208 | int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, |
| 173 | struct ccw_driver *cdrv, int argc, char *argv[]) | 209 | struct ccw_driver *cdrv, int num_devices, |
| 210 | const char *buf) | ||
| 174 | { | 211 | { |
| 175 | struct ccwgroup_device *gdev; | 212 | struct ccwgroup_device *gdev; |
| 176 | int i; | 213 | int rc, i; |
| 177 | int rc; | 214 | char tmp_bus_id[BUS_ID_SIZE]; |
| 215 | const char *curr_buf; | ||
| 178 | 216 | ||
| 179 | if (argc > 256) /* disallow dumb users */ | 217 | gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), |
| 180 | return -EINVAL; | 218 | GFP_KERNEL); |
| 181 | |||
| 182 | gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL); | ||
| 183 | if (!gdev) | 219 | if (!gdev) |
| 184 | return -ENOMEM; | 220 | return -ENOMEM; |
| 185 | 221 | ||
| 186 | atomic_set(&gdev->onoff, 0); | 222 | atomic_set(&gdev->onoff, 0); |
| 187 | mutex_init(&gdev->reg_mutex); | 223 | mutex_init(&gdev->reg_mutex); |
| 188 | mutex_lock(&gdev->reg_mutex); | 224 | mutex_lock(&gdev->reg_mutex); |
| 189 | for (i = 0; i < argc; i++) { | 225 | curr_buf = buf; |
| 190 | gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); | 226 | for (i = 0; i < num_devices && curr_buf; i++) { |
| 191 | 227 | rc = __get_next_bus_id(&curr_buf, tmp_bus_id); | |
| 192 | /* all devices have to be of the same type in | 228 | if (rc != 0) |
| 193 | * order to be grouped */ | 229 | goto error; |
| 230 | if (!__is_valid_bus_id(tmp_bus_id)) { | ||
| 231 | rc = -EINVAL; | ||
| 232 | goto error; | ||
| 233 | } | ||
| 234 | gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id); | ||
| 235 | /* | ||
| 236 | * All devices have to be of the same type in | ||
| 237 | * order to be grouped. | ||
| 238 | */ | ||
| 194 | if (!gdev->cdev[i] | 239 | if (!gdev->cdev[i] |
| 195 | || gdev->cdev[i]->id.driver_info != | 240 | || gdev->cdev[i]->id.driver_info != |
| 196 | gdev->cdev[0]->id.driver_info) { | 241 | gdev->cdev[0]->id.driver_info) { |
| @@ -204,9 +249,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, | |||
| 204 | } | 249 | } |
| 205 | dev_set_drvdata(&gdev->cdev[i]->dev, gdev); | 250 | dev_set_drvdata(&gdev->cdev[i]->dev, gdev); |
| 206 | } | 251 | } |
| 207 | 252 | /* Check for sufficient number of bus ids. */ | |
| 253 | if (i < num_devices && !curr_buf) { | ||
| 254 | rc = -EINVAL; | ||
| 255 | goto error; | ||
| 256 | } | ||
| 257 | /* Check for trailing stuff. */ | ||
| 258 | if (i == num_devices && strlen(curr_buf) > 0) { | ||
| 259 | rc = -EINVAL; | ||
| 260 | goto error; | ||
| 261 | } | ||
| 208 | gdev->creator_id = creator_id; | 262 | gdev->creator_id = creator_id; |
| 209 | gdev->count = argc; | 263 | gdev->count = num_devices; |
| 210 | gdev->dev.bus = &ccwgroup_bus_type; | 264 | gdev->dev.bus = &ccwgroup_bus_type; |
| 211 | gdev->dev.parent = root; | 265 | gdev->dev.parent = root; |
| 212 | gdev->dev.release = ccwgroup_release; | 266 | gdev->dev.release = ccwgroup_release; |
| @@ -234,7 +288,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, | |||
| 234 | device_remove_file(&gdev->dev, &dev_attr_ungroup); | 288 | device_remove_file(&gdev->dev, &dev_attr_ungroup); |
| 235 | device_unregister(&gdev->dev); | 289 | device_unregister(&gdev->dev); |
| 236 | error: | 290 | error: |
| 237 | for (i = 0; i < argc; i++) | 291 | for (i = 0; i < num_devices; i++) |
| 238 | if (gdev->cdev[i]) { | 292 | if (gdev->cdev[i]) { |
| 239 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) | 293 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) |
| 240 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); | 294 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); |
| @@ -244,6 +298,7 @@ error: | |||
| 244 | put_device(&gdev->dev); | 298 | put_device(&gdev->dev); |
| 245 | return rc; | 299 | return rc; |
| 246 | } | 300 | } |
| 301 | EXPORT_SYMBOL(ccwgroup_create_from_string); | ||
| 247 | 302 | ||
| 248 | static int __init | 303 | static int __init |
| 249 | init_ccwgroup (void) | 304 | init_ccwgroup (void) |
| @@ -519,6 +574,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev) | |||
| 519 | MODULE_LICENSE("GPL"); | 574 | MODULE_LICENSE("GPL"); |
| 520 | EXPORT_SYMBOL(ccwgroup_driver_register); | 575 | EXPORT_SYMBOL(ccwgroup_driver_register); |
| 521 | EXPORT_SYMBOL(ccwgroup_driver_unregister); | 576 | EXPORT_SYMBOL(ccwgroup_driver_unregister); |
| 522 | EXPORT_SYMBOL(ccwgroup_create); | ||
| 523 | EXPORT_SYMBOL(ccwgroup_probe_ccwdev); | 577 | EXPORT_SYMBOL(ccwgroup_probe_ccwdev); |
| 524 | EXPORT_SYMBOL(ccwgroup_remove_ccwdev); | 578 | EXPORT_SYMBOL(ccwgroup_remove_ccwdev); |
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c index 76728ae4b843..8e7697305a4c 100644 --- a/drivers/s390/net/cu3088.c +++ b/drivers/s390/net/cu3088.c | |||
| @@ -62,30 +62,14 @@ static struct device *cu3088_root_dev; | |||
| 62 | static ssize_t | 62 | static ssize_t |
| 63 | group_write(struct device_driver *drv, const char *buf, size_t count) | 63 | group_write(struct device_driver *drv, const char *buf, size_t count) |
| 64 | { | 64 | { |
| 65 | const char *start, *end; | ||
| 66 | char bus_ids[2][BUS_ID_SIZE], *argv[2]; | ||
| 67 | int i; | ||
| 68 | int ret; | 65 | int ret; |
| 69 | struct ccwgroup_driver *cdrv; | 66 | struct ccwgroup_driver *cdrv; |
| 70 | 67 | ||
| 71 | cdrv = to_ccwgroupdrv(drv); | 68 | cdrv = to_ccwgroupdrv(drv); |
| 72 | if (!cdrv) | 69 | if (!cdrv) |
| 73 | return -EINVAL; | 70 | return -EINVAL; |
| 74 | start = buf; | 71 | ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id, |
| 75 | for (i=0; i<2; i++) { | 72 | &cu3088_driver, 2, buf); |
| 76 | static const char delim[] = {',', '\n'}; | ||
| 77 | int len; | ||
| 78 | |||
| 79 | if (!(end = strchr(start, delim[i]))) | ||
| 80 | return -EINVAL; | ||
| 81 | len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1); | ||
| 82 | strlcpy (bus_ids[i], start, len); | ||
| 83 | argv[i] = bus_ids[i]; | ||
| 84 | start = end + 1; | ||
| 85 | } | ||
| 86 | |||
| 87 | ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id, | ||
| 88 | &cu3088_driver, 2, argv); | ||
| 89 | 73 | ||
| 90 | return (ret == 0) ? count : ret; | 74 | return (ret == 0) ? count : ret; |
| 91 | } | 75 | } |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 055f5c3e7b56..231d18c3b6f7 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
| @@ -3827,27 +3827,8 @@ static struct ccw_driver qeth_ccw_driver = { | |||
| 3827 | static int qeth_core_driver_group(const char *buf, struct device *root_dev, | 3827 | static int qeth_core_driver_group(const char *buf, struct device *root_dev, |
| 3828 | unsigned long driver_id) | 3828 | unsigned long driver_id) |
| 3829 | { | 3829 | { |
| 3830 | const char *start, *end; | 3830 | return ccwgroup_create_from_string(root_dev, driver_id, |
| 3831 | char bus_ids[3][BUS_ID_SIZE], *argv[3]; | 3831 | &qeth_ccw_driver, 3, buf); |
| 3832 | int i; | ||
| 3833 | |||
| 3834 | start = buf; | ||
| 3835 | for (i = 0; i < 3; i++) { | ||
| 3836 | static const char delim[] = { ',', ',', '\n' }; | ||
| 3837 | int len; | ||
| 3838 | |||
| 3839 | end = strchr(start, delim[i]); | ||
| 3840 | if (!end) | ||
| 3841 | return -EINVAL; | ||
| 3842 | len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start); | ||
| 3843 | strncpy(bus_ids[i], start, len); | ||
| 3844 | bus_ids[i][len] = '\0'; | ||
| 3845 | start = end + 1; | ||
| 3846 | argv[i] = bus_ids[i]; | ||
| 3847 | } | ||
| 3848 | |||
| 3849 | return (ccwgroup_create(root_dev, driver_id, | ||
| 3850 | &qeth_ccw_driver, 3, argv)); | ||
| 3851 | } | 3832 | } |
| 3852 | 3833 | ||
| 3853 | int qeth_core_hardsetup_card(struct qeth_card *card) | 3834 | int qeth_core_hardsetup_card(struct qeth_card *card) |
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h index 289053ef5e60..a27f68985a79 100644 --- a/include/asm-s390/ccwgroup.h +++ b/include/asm-s390/ccwgroup.h | |||
| @@ -57,10 +57,9 @@ struct ccwgroup_driver { | |||
| 57 | 57 | ||
| 58 | extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); | 58 | extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); |
| 59 | extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver); | 59 | extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver); |
| 60 | extern int ccwgroup_create (struct device *root, | 60 | int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, |
| 61 | unsigned int creator_id, | 61 | struct ccw_driver *cdrv, int num_devices, |
| 62 | struct ccw_driver *gdrv, | 62 | const char *buf); |
| 63 | int argc, char *argv[]); | ||
| 64 | 63 | ||
| 65 | extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev); | 64 | extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev); |
| 66 | extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev); | 65 | extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev); |
