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 /drivers/s390/cio/ccwgroup.c | |
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>
Diffstat (limited to 'drivers/s390/cio/ccwgroup.c')
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 96 |
1 files changed, 75 insertions, 21 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); |