Commit 5d3c500b authored by Russell King's avatar Russell King Committed by Linus Torvalds

[PATCH] Update MTD concatenating driver

This patch updates the MTD concatenating driver from MTD CVS, which
fixes issues found with this driver which concatenates multiple MTD
devices into one MTD device.

From David Woodhouse, through CVS:

	revision 1.8
	date: 2003/06/30 11:01:26;  author: dwmw2;  state: Exp;  lines: +5 -5
	I will not commit stuff whilst pissed
	I will not commit stuff whilst pissed

	revision 1.7
	date: 2003/06/29 21:26:34;  author: dwmw2;  state: Exp;  lines: +9 -9
	Fix ecc/oob subdev comparisions

	revision 1.6
	date: 2003/06/25 12:37:50;  author: dwmw2;  state: Exp;  lines: +14 -6
	Don't pretend to have {read,write}_{oob,ecc} functions if subdevices don't

	revision 1.5
	date: 2003/06/25 12:21:16;  author: dwmw2;  state: Exp;  lines: +390 -397
	coding style cleanup
parent 791c0db5
......@@ -7,7 +7,7 @@
*
* This code is GPL
*
* $Id: mtdconcat.c,v 1.4 2003/03/07 17:44:59 rkaiser Exp $
* $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $
*/
#include <linux/module.h>
......@@ -37,21 +37,20 @@ struct mtd_concat {
#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \
((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
/*
* Given a pointer to the MTD object in the mtd_concat structure,
* we can retrieve the pointer to that structure with this macro.
*/
#define CONCAT(x) ((struct mtd_concat *)(x))
/*
* MTD methods which look up the relevant subdevice, translate the
* effective address and pass through to the subdevice.
*/
static int concat_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
static int
concat_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
......@@ -59,43 +58,43 @@ static int concat_read (struct mtd_info *mtd, loff_t from, size_t len,
*retlen = 0;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (from >= subdev->size)
{ /* Not destined for this subdev */
if (from >= subdev->size) {
/* Not destined for this subdev */
size = 0;
from -= subdev->size;
continue;
}
else
{
if (from + len > subdev->size)
size = subdev->size - from; /* First part goes into this subdev */
/* First part goes into this subdev */
size = subdev->size - from;
else
size = len; /* Entire transaction goes into this subdev */
/* Entire transaction goes into this subdev */
size = len;
err = subdev->read(subdev, from, size, &retsize, buf);
if(err)
if (err)
break;
*retlen += retsize;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
buf += size;
from = 0;
}
}
return err;
}
static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
static int
concat_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
......@@ -106,18 +105,15 @@ static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
*retlen = 0;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (to >= subdev->size)
{
if (to >= subdev->size) {
size = 0;
to -= subdev->size;
continue;
}
else
{
if (to + len > subdev->size)
size = subdev->size - to;
else
......@@ -128,24 +124,25 @@ static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
else
err = subdev->write(subdev, to, size, &retsize, buf);
if(err)
if (err)
break;
*retlen += retsize;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
buf += size;
to = 0;
}
}
return err;
}
static int concat_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
static int
concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * eccbuf,
struct nand_oobinfo *oobsel)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
......@@ -153,53 +150,56 @@ static int concat_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
*retlen = 0;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (from >= subdev->size)
{ /* Not destined for this subdev */
if (from >= subdev->size) {
/* Not destined for this subdev */
size = 0;
from -= subdev->size;
continue;
}
else
{
if (from + len > subdev->size)
size = subdev->size - from; /* First part goes into this subdev */
/* First part goes into this subdev */
size = subdev->size - from;
else
size = len; /* Entire transaction goes into this subdev */
/* Entire transaction goes into this subdev */
size = len;
if (subdev->read_ecc)
err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel);
err = subdev->read_ecc(subdev, from, size,
&retsize, buf, eccbuf, oobsel);
else
err = -EINVAL;
if(err)
if (err)
break;
*retlen += retsize;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
buf += size;
if (eccbuf)
{
if (eccbuf) {
eccbuf += subdev->oobsize;
/* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus',
we must account for these */
eccbuf += 2 * (sizeof(int));
/* in nand.c at least, eccbufs are
tagged with 2 (int)eccstatus'; we
must account for these */
eccbuf += 2 * (sizeof (int));
}
from = 0;
}
}
return err;
}
static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
static int
concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf, u_char * eccbuf,
struct nand_oobinfo *oobsel)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
......@@ -210,18 +210,15 @@ static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
*retlen = 0;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (to >= subdev->size)
{
if (to >= subdev->size) {
size = 0;
to -= subdev->size;
continue;
}
else
{
if (to + len > subdev->size)
size = subdev->size - to;
else
......@@ -230,16 +227,17 @@ static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
if (!(subdev->flags & MTD_WRITEABLE))
err = -EROFS;
else if (subdev->write_ecc)
err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel);
err = subdev->write_ecc(subdev, to, size,
&retsize, buf, eccbuf, oobsel);
else
err = -EINVAL;
if(err)
if (err)
break;
*retlen += retsize;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
......@@ -248,12 +246,12 @@ static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
eccbuf += subdev->oobsize;
to = 0;
}
}
return err;
}
static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
static int
concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
......@@ -261,46 +259,47 @@ static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
*retlen = 0;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (from >= subdev->size)
{ /* Not destined for this subdev */
if (from >= subdev->size) {
/* Not destined for this subdev */
size = 0;
from -= subdev->size;
continue;
}
else
{
if (from + len > subdev->size)
size = subdev->size - from; /* First part goes into this subdev */
/* First part goes into this subdev */
size = subdev->size - from;
else
size = len; /* Entire transaction goes into this subdev */
/* Entire transaction goes into this subdev */
size = len;
if (subdev->read_oob)
err = subdev->read_oob(subdev, from, size, &retsize, buf);
err = subdev->read_oob(subdev, from, size,
&retsize, buf);
else
err = -EINVAL;
if(err)
if (err)
break;
*retlen += retsize;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
buf += size;
from = 0;
}
}
return err;
}
static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
static int
concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
......@@ -311,18 +310,15 @@ static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
*retlen = 0;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (to >= subdev->size)
{
if (to >= subdev->size) {
size = 0;
to -= subdev->size;
continue;
}
else
{
if (to + len > subdev->size)
size = subdev->size - to;
else
......@@ -331,30 +327,29 @@ static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
if (!(subdev->flags & MTD_WRITEABLE))
err = -EROFS;
else if (subdev->write_oob)
err = subdev->write_oob(subdev, to, size, &retsize, buf);
err = subdev->write_oob(subdev, to, size, &retsize,
buf);
else
err = -EINVAL;
if(err)
if (err)
break;
*retlen += retsize;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
buf += size;
to = 0;
}
}
return err;
}
static void concat_erase_callback (struct erase_info *instr)
static void concat_erase_callback(struct erase_info *instr)
{
wake_up((wait_queue_head_t *)instr->priv);
wake_up((wait_queue_head_t *) instr->priv);
}
static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
......@@ -370,18 +365,18 @@ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
erase->mtd = mtd;
erase->callback = concat_erase_callback;
erase->priv = (unsigned long)&waitq;
erase->priv = (unsigned long) &waitq;
/*
* FIXME: Allow INTERRUPTIBLE. Which means
* not having the wait_queue head on the stack.
*/
err = mtd->erase(mtd, erase);
if (!err)
{
if (!err) {
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&waitq, &wait);
if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
if (erase->state != MTD_ERASE_DONE
&& erase->state != MTD_ERASE_FAILED)
schedule();
remove_wait_queue(&waitq, &wait);
set_current_state(TASK_RUNNING);
......@@ -391,7 +386,7 @@ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
return err;
}
static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct mtd_concat *concat = CONCAT(mtd);
struct mtd_info *subdev;
......@@ -402,10 +397,10 @@ static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if(instr->addr > concat->mtd.size)
if (instr->addr > concat->mtd.size)
return -EINVAL;
if(instr->len + instr->addr > concat->mtd.size)
if (instr->len + instr->addr > concat->mtd.size)
return -EINVAL;
/*
......@@ -414,23 +409,22 @@ static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
* region info rather than looking at each particular sub-device
* in turn.
*/
if (!concat->mtd.numeraseregions)
{ /* the easy case: device has uniform erase block size */
if(instr->addr & (concat->mtd.erasesize - 1))
if (!concat->mtd.numeraseregions) {
/* the easy case: device has uniform erase block size */
if (instr->addr & (concat->mtd.erasesize - 1))
return -EINVAL;
if(instr->len & (concat->mtd.erasesize - 1))
if (instr->len & (concat->mtd.erasesize - 1))
return -EINVAL;
}
else
{ /* device has variable erase size */
struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
} else {
/* device has variable erase size */
struct mtd_erase_region_info *erase_regions =
concat->mtd.eraseregions;
/*
* Find the erase region where the to-be-erased area begins:
*/
for(i = 0; i < concat->mtd.numeraseregions &&
instr->addr >= erase_regions[i].offset; i++)
;
for (i = 0; i < concat->mtd.numeraseregions &&
instr->addr >= erase_regions[i].offset; i++) ;
--i;
/*
......@@ -438,25 +432,26 @@ static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
* to-be-erased area begins. Verify that the starting
* offset is aligned to this region's erase size:
*/
if (instr->addr & (erase_regions[i].erasesize-1))
if (instr->addr & (erase_regions[i].erasesize - 1))
return -EINVAL;
/*
* now find the erase region where the to-be-erased area ends:
*/
for(; i < concat->mtd.numeraseregions &&
(instr->addr + instr->len) >= erase_regions[i].offset ; ++i)
;
for (; i < concat->mtd.numeraseregions &&
(instr->addr + instr->len) >= erase_regions[i].offset;
++i) ;
--i;
/*
* check if the ending offset is aligned to this region's erase size
*/
if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
if ((instr->addr + instr->len) & (erase_regions[i].erasesize -
1))
return -EINVAL;
}
/* make a local copy of instr to avoid modifying the caller's struct */
erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
if (!erase)
return -ENOMEM;
......@@ -468,39 +463,40 @@ static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
* find the subdevice where the to-be-erased area begins, adjust
* starting offset to be relative to the subdevice start
*/
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
subdev = concat->subdev[i];
if(subdev->size <= erase->addr)
if (subdev->size <= erase->addr)
erase->addr -= subdev->size;
else
break;
}
if(i >= concat->num_subdev) /* must never happen since size */
BUG(); /* limit has been verified above */
/* must never happen since size limit has been verified above */
if (i >= concat->num_subdev)
BUG();
/* now do the erase: */
err = 0;
for(;length > 0; i++) /* loop for all subevices affected by this request */
{
for (; length > 0; i++) {
/* loop for all subdevices affected by this request */
subdev = concat->subdev[i]; /* get current subdevice */
/* limit length to subdevice's size: */
if(erase->addr + length > subdev->size)
if (erase->addr + length > subdev->size)
erase->len = subdev->size - erase->addr;
else
erase->len = length;
if (!(subdev->flags & MTD_WRITEABLE))
{
if (!(subdev->flags & MTD_WRITEABLE)) {
err = -EROFS;
break;
}
length -= erase->len;
if ((err = concat_dev_erase(subdev, erase)))
{
if(err == -EINVAL) /* sanity check: must never happen since */
BUG(); /* block alignment has been checked above */
if ((err = concat_dev_erase(subdev, erase))) {
/* sanity check: should never happen since
* block alignment has been checked above */
if (err == -EINVAL)
BUG();
break;
}
/*
......@@ -523,7 +519,7 @@ static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
return 0;
}
static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
struct mtd_concat *concat = CONCAT(mtd);
int i, err = -EINVAL;
......@@ -531,18 +527,15 @@ static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
if ((len + ofs) > mtd->size)
return -EINVAL;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size;
if (ofs >= subdev->size)
{
if (ofs >= subdev->size) {
size = 0;
ofs -= subdev->size;
continue;
}
else
{
if (ofs + len > subdev->size)
size = subdev->size - ofs;
else
......@@ -550,21 +543,21 @@ static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
err = subdev->lock(subdev, ofs, size);
if(err)
if (err)
break;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
ofs = 0;
}
}
return err;
}
static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
struct mtd_concat *concat = CONCAT(mtd);
int i, err = 0;
......@@ -572,18 +565,15 @@ static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
if ((len + ofs) > mtd->size)
return -EINVAL;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size;
if (ofs >= subdev->size)
{
if (ofs >= subdev->size) {
size = 0;
ofs -= subdev->size;
continue;
}
else
{
if (ofs + len > subdev->size)
size = subdev->size - ofs;
else
......@@ -591,17 +581,17 @@ static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
err = subdev->unlock(subdev, ofs, size);
if(err)
if (err)
break;
len -= size;
if(len == 0)
if (len == 0)
break;
err = -EINVAL;
ofs = 0;
}
}
return err;
}
......@@ -610,8 +600,7 @@ static void concat_sync(struct mtd_info *mtd)
struct mtd_concat *concat = CONCAT(mtd);
int i;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
subdev->sync(subdev);
}
......@@ -622,10 +611,9 @@ static int concat_suspend(struct mtd_info *mtd)
struct mtd_concat *concat = CONCAT(mtd);
int i, rc = 0;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
if((rc = subdev->suspend(subdev)) < 0)
if ((rc = subdev->suspend(subdev)) < 0)
return rc;
}
return rc;
......@@ -636,8 +624,7 @@ static void concat_resume(struct mtd_info *mtd)
struct mtd_concat *concat = CONCAT(mtd);
int i;
for(i = 0; i < concat->num_subdev; i++)
{
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
subdev->resume(subdev);
}
......@@ -649,11 +636,10 @@ static void concat_resume(struct mtd_info *mtd)
* stored to *new_dev upon success. This function does _not_
* register any devices: this is the caller's responsibility.
*/
struct mtd_info *mtd_concat_create(
struct mtd_info *subdev[], /* subdevices to concatenate */
struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */
int num_devs, /* number of subdevices */
char *name) /* name for the new device */
{
char *name)
{ /* name for the new device */
int i;
size_t size;
struct mtd_concat *concat;
......@@ -661,21 +647,21 @@ struct mtd_info *mtd_concat_create(
int num_erase_region;
printk(KERN_NOTICE "Concatenating MTD devices:\n");
for(i = 0; i < num_devs; i++)
for (i = 0; i < num_devs; i++)
printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
printk(KERN_NOTICE "into device \"%s\"\n", name);
/* allocate the device structure */
size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
concat = kmalloc (size, GFP_KERNEL);
if(!concat)
{
printk ("memory allocation error while creating concatenated device \"%s\"\n",
concat = kmalloc(size, GFP_KERNEL);
if (!concat) {
printk
("memory allocation error while creating concatenated device \"%s\"\n",
name);
return NULL;
}
memset(concat, 0, size);
concat->subdev = (struct mtd_info **)(concat + 1);
concat->subdev = (struct mtd_info **) (concat + 1);
/*
* Set up the new "super" device's MTD object structure, check for
......@@ -689,39 +675,53 @@ struct mtd_info *mtd_concat_create(
concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.ecctype = subdev[0]->ecctype;
concat->mtd.eccsize = subdev[0]->eccsize;
if (subdev[0]->read_ecc)
concat->mtd.read_ecc = concat_read_ecc;
if (subdev[0]->write_ecc)
concat->mtd.write_ecc = concat_write_ecc;
if (subdev[0]->read_oob)
concat->mtd.read_oob = concat_read_oob;
if (subdev[0]->write_oob)
concat->mtd.write_oob = concat_write_oob;
concat->subdev[0] = subdev[0];
for(i = 1; i < num_devs; i++)
{
if(concat->mtd.type != subdev[i]->type)
{
for (i = 1; i < num_devs; i++) {
if (concat->mtd.type != subdev[i]->type) {
kfree(concat);
printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
printk("Incompatible device type on \"%s\"\n",
subdev[i]->name);
return NULL;
}
if(concat->mtd.flags != subdev[i]->flags)
{ /*
* Expect all flags except MTD_WRITEABLE to be equal on
* all subdevices.
if (concat->mtd.flags != subdev[i]->flags) {
/*
* Expect all flags except MTD_WRITEABLE to be
* equal on all subdevices.
*/
if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
{
if ((concat->mtd.flags ^ subdev[i]->
flags) & ~MTD_WRITEABLE) {
kfree(concat);
printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
printk("Incompatible device flags on \"%s\"\n",
subdev[i]->name);
return NULL;
}
else /* if writeable attribute differs, make super device writeable */
concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
} else
/* if writeable attribute differs,
make super device writeable */
concat->mtd.flags |=
subdev[i]->flags & MTD_WRITEABLE;
}
concat->mtd.size += subdev[i]->size;
if(concat->mtd.oobblock != subdev[i]->oobblock ||
if (concat->mtd.oobblock != subdev[i]->oobblock ||
concat->mtd.oobsize != subdev[i]->oobsize ||
concat->mtd.ecctype != subdev[i]->ecctype ||
concat->mtd.eccsize != subdev[i]->eccsize)
{
concat->mtd.eccsize != subdev[i]->eccsize ||
!concat->mtd.read_ecc != !subdev[i]->read_ecc ||
!concat->mtd.write_ecc != !subdev[i]->write_ecc ||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
kfree(concat);
printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
printk("Incompatible OOB or ECC data on \"%s\"\n",
subdev[i]->name);
return NULL;
}
concat->subdev[i] = subdev[i];
......@@ -739,17 +739,12 @@ struct mtd_info *mtd_concat_create(
concat->mtd.erase = concat_erase;
concat->mtd.read = concat_read;
concat->mtd.write = concat_write;
concat->mtd.read_ecc = concat_read_ecc;
concat->mtd.write_ecc = concat_write_ecc;
concat->mtd.read_oob = concat_read_oob;
concat->mtd.write_oob = concat_write_oob;
concat->mtd.sync = concat_sync;
concat->mtd.lock = concat_lock;
concat->mtd.unlock = concat_unlock;
concat->mtd.suspend = concat_suspend;
concat->mtd.resume = concat_resume;
/*
* Combine the erase block size info of the subdevices:
*
......@@ -758,44 +753,44 @@ struct mtd_info *mtd_concat_create(
*/
max_erasesize = curr_erasesize = subdev[0]->erasesize;
num_erase_region = 1;
for(i = 0; i < num_devs; i++)
{
if(subdev[i]->numeraseregions == 0)
{ /* current subdevice has uniform erase size */
if(subdev[i]->erasesize != curr_erasesize)
{ /* if it differs from the last subdevice's erase size, count it */
for (i = 0; i < num_devs; i++) {
if (subdev[i]->numeraseregions == 0) {
/* current subdevice has uniform erase size */
if (subdev[i]->erasesize != curr_erasesize) {
/* if it differs from the last subdevice's erase size, count it */
++num_erase_region;
curr_erasesize = subdev[i]->erasesize;
if(curr_erasesize > max_erasesize)
if (curr_erasesize > max_erasesize)
max_erasesize = curr_erasesize;
}
}
else
{ /* current subdevice has variable erase size */
} else {
/* current subdevice has variable erase size */
int j;
for(j = 0; j < subdev[i]->numeraseregions; j++)
{ /* walk the list of erase regions, count any changes */
if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
{
for (j = 0; j < subdev[i]->numeraseregions; j++) {
/* walk the list of erase regions, count any changes */
if (subdev[i]->eraseregions[j].erasesize !=
curr_erasesize) {
++num_erase_region;
curr_erasesize = subdev[i]->eraseregions[j].erasesize;
if(curr_erasesize > max_erasesize)
curr_erasesize =
subdev[i]->eraseregions[j].
erasesize;
if (curr_erasesize > max_erasesize)
max_erasesize = curr_erasesize;
}
}
}
}
if(num_erase_region == 1)
{ /*
if (num_erase_region == 1) {
/*
* All subdevices have the same uniform erase size.
* This is easy:
*/
concat->mtd.erasesize = curr_erasesize;
concat->mtd.numeraseregions = 0;
}
else
{ /*
} else {
/*
* erase block size varies across the subdevices: allocate
* space to store the data describing the variable erase regions
*/
......@@ -804,12 +799,13 @@ struct mtd_info *mtd_concat_create(
concat->mtd.erasesize = max_erasesize;
concat->mtd.numeraseregions = num_erase_region;
concat->mtd.eraseregions = erase_region_p = kmalloc (
num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
if(!erase_region_p)
{
concat->mtd.eraseregions = erase_region_p =
kmalloc(num_erase_region *
sizeof (struct mtd_erase_region_info), GFP_KERNEL);
if (!erase_region_p) {
kfree(concat);
printk ("memory allocation error while creating erase region list"
printk
("memory allocation error while creating erase region list"
" for device \"%s\"\n", name);
return NULL;
}
......@@ -820,41 +816,48 @@ struct mtd_info *mtd_concat_create(
*/
curr_erasesize = subdev[0]->erasesize;
begin = position = 0;
for(i = 0; i < num_devs; i++)
{
if(subdev[i]->numeraseregions == 0)
{ /* current subdevice has uniform erase size */
if(subdev[i]->erasesize != curr_erasesize)
{ /*
for (i = 0; i < num_devs; i++) {
if (subdev[i]->numeraseregions == 0) {
/* current subdevice has uniform erase size */
if (subdev[i]->erasesize != curr_erasesize) {
/*
* fill in an mtd_erase_region_info structure for the area
* we have walked so far:
*/
erase_region_p->offset = begin;
erase_region_p->erasesize = curr_erasesize;
erase_region_p->numblocks = (position - begin) / curr_erasesize;
erase_region_p->erasesize =
curr_erasesize;
erase_region_p->numblocks =
(position - begin) / curr_erasesize;
begin = position;
curr_erasesize = subdev[i]->erasesize;
++erase_region_p;
}
position += subdev[i]->size;
}
else
{ /* current subdevice has variable erase size */
} else {
/* current subdevice has variable erase size */
int j;
for(j = 0; j < subdev[i]->numeraseregions; j++)
{ /* walk the list of erase regions, count any changes */
if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
{
for (j = 0; j < subdev[i]->numeraseregions; j++) {
/* walk the list of erase regions, count any changes */
if (subdev[i]->eraseregions[j].
erasesize != curr_erasesize) {
erase_region_p->offset = begin;
erase_region_p->erasesize = curr_erasesize;
erase_region_p->numblocks = (position - begin) / curr_erasesize;
erase_region_p->erasesize =
curr_erasesize;
erase_region_p->numblocks =
(position -
begin) / curr_erasesize;
begin = position;
curr_erasesize = subdev[i]->eraseregions[j].erasesize;
curr_erasesize =
subdev[i]->eraseregions[j].
erasesize;
++erase_region_p;
}
position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
position +=
subdev[i]->eraseregions[j].
numblocks * curr_erasesize;
}
}
}
......@@ -874,16 +877,14 @@ struct mtd_info *mtd_concat_create(
void mtd_concat_destroy(struct mtd_info *mtd)
{
struct mtd_concat *concat = CONCAT(mtd);
if(concat->mtd.numeraseregions)
if (concat->mtd.numeraseregions)
kfree(concat->mtd.eraseregions);
kfree(concat);
}
EXPORT_SYMBOL(mtd_concat_create);
EXPORT_SYMBOL(mtd_concat_destroy);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment