diff options
-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); |