diff options
Diffstat (limited to 'drivers/mtd/mtdconcat.c')
-rw-r--r-- | drivers/mtd/mtdconcat.c | 90 |
1 files changed, 37 insertions, 53 deletions
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index ec15abcdbdfa..38151b8e6631 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -231,101 +231,85 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, | |||
231 | } | 231 | } |
232 | 232 | ||
233 | static int | 233 | static int |
234 | concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | 234 | concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) |
235 | size_t * retlen, u_char * buf) | ||
236 | { | 235 | { |
237 | struct mtd_concat *concat = CONCAT(mtd); | 236 | struct mtd_concat *concat = CONCAT(mtd); |
238 | int err = -EINVAL; | 237 | struct mtd_oob_ops devops = *ops; |
239 | int i; | 238 | int i, err; |
240 | 239 | ||
241 | *retlen = 0; | 240 | ops->retlen = 0; |
242 | 241 | ||
243 | for (i = 0; i < concat->num_subdev; i++) { | 242 | for (i = 0; i < concat->num_subdev; i++) { |
244 | struct mtd_info *subdev = concat->subdev[i]; | 243 | struct mtd_info *subdev = concat->subdev[i]; |
245 | size_t size, retsize; | ||
246 | 244 | ||
247 | if (from >= subdev->size) { | 245 | if (from >= subdev->size) { |
248 | /* Not destined for this subdev */ | ||
249 | size = 0; | ||
250 | from -= subdev->size; | 246 | from -= subdev->size; |
251 | continue; | 247 | continue; |
252 | } | 248 | } |
253 | if (from + len > subdev->size) | ||
254 | /* First part goes into this subdev */ | ||
255 | size = subdev->size - from; | ||
256 | else | ||
257 | /* Entire transaction goes into this subdev */ | ||
258 | size = len; | ||
259 | 249 | ||
260 | if (subdev->read_oob) | 250 | /* partial read ? */ |
261 | err = subdev->read_oob(subdev, from, size, | 251 | if (from + devops.len > subdev->size) |
262 | &retsize, buf); | 252 | devops.len = subdev->size - from; |
263 | else | ||
264 | err = -EINVAL; | ||
265 | 253 | ||
254 | err = subdev->read_oob(subdev, from, &devops); | ||
255 | ops->retlen += devops.retlen; | ||
266 | if (err) | 256 | if (err) |
267 | break; | 257 | return err; |
268 | 258 | ||
269 | *retlen += retsize; | 259 | devops.len = ops->len - ops->retlen; |
270 | len -= size; | 260 | if (!devops.len) |
271 | if (len == 0) | 261 | return 0; |
272 | break; | 262 | |
263 | if (devops.datbuf) | ||
264 | devops.datbuf += devops.retlen; | ||
265 | if (devops.oobbuf) | ||
266 | devops.oobbuf += devops.ooblen; | ||
273 | 267 | ||
274 | err = -EINVAL; | ||
275 | buf += size; | ||
276 | from = 0; | 268 | from = 0; |
277 | } | 269 | } |
278 | return err; | 270 | return -EINVAL; |
279 | } | 271 | } |
280 | 272 | ||
281 | static int | 273 | static int |
282 | concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | 274 | concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) |
283 | size_t * retlen, const u_char * buf) | ||
284 | { | 275 | { |
285 | struct mtd_concat *concat = CONCAT(mtd); | 276 | struct mtd_concat *concat = CONCAT(mtd); |
286 | int err = -EINVAL; | 277 | struct mtd_oob_ops devops = *ops; |
287 | int i; | 278 | int i, err; |
288 | 279 | ||
289 | if (!(mtd->flags & MTD_WRITEABLE)) | 280 | if (!(mtd->flags & MTD_WRITEABLE)) |
290 | return -EROFS; | 281 | return -EROFS; |
291 | 282 | ||
292 | *retlen = 0; | 283 | ops->retlen = 0; |
293 | 284 | ||
294 | for (i = 0; i < concat->num_subdev; i++) { | 285 | for (i = 0; i < concat->num_subdev; i++) { |
295 | struct mtd_info *subdev = concat->subdev[i]; | 286 | struct mtd_info *subdev = concat->subdev[i]; |
296 | size_t size, retsize; | ||
297 | 287 | ||
298 | if (to >= subdev->size) { | 288 | if (to >= subdev->size) { |
299 | size = 0; | ||
300 | to -= subdev->size; | 289 | to -= subdev->size; |
301 | continue; | 290 | continue; |
302 | } | 291 | } |
303 | if (to + len > subdev->size) | ||
304 | size = subdev->size - to; | ||
305 | else | ||
306 | size = len; | ||
307 | 292 | ||
308 | if (!(subdev->flags & MTD_WRITEABLE)) | 293 | /* partial write ? */ |
309 | err = -EROFS; | 294 | if (to + devops.len > subdev->size) |
310 | else if (subdev->write_oob) | 295 | devops.len = subdev->size - to; |
311 | err = subdev->write_oob(subdev, to, size, &retsize, | ||
312 | buf); | ||
313 | else | ||
314 | err = -EINVAL; | ||
315 | 296 | ||
297 | err = subdev->write_oob(subdev, to, &devops); | ||
298 | ops->retlen += devops.retlen; | ||
316 | if (err) | 299 | if (err) |
317 | break; | 300 | return err; |
318 | 301 | ||
319 | *retlen += retsize; | 302 | devops.len = ops->len - ops->retlen; |
320 | len -= size; | 303 | if (!devops.len) |
321 | if (len == 0) | 304 | return 0; |
322 | break; | ||
323 | 305 | ||
324 | err = -EINVAL; | 306 | if (devops.datbuf) |
325 | buf += size; | 307 | devops.datbuf += devops.retlen; |
308 | if (devops.oobbuf) | ||
309 | devops.oobbuf += devops.ooblen; | ||
326 | to = 0; | 310 | to = 0; |
327 | } | 311 | } |
328 | return err; | 312 | return -EINVAL; |
329 | } | 313 | } |
330 | 314 | ||
331 | static void concat_erase_callback(struct erase_info *instr) | 315 | static void concat_erase_callback(struct erase_info *instr) |