#include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
+#include <linux/list.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
 static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
 static uint log            = CONFIG_NANDSIM_LOG;
 static uint dbg            = CONFIG_NANDSIM_DBG;
+static unsigned long parts[MAX_MTD_DEVICES];
+static unsigned int parts_num;
 
 module_param(first_id_byte,  uint, 0400);
 module_param(second_id_byte, uint, 0400);
 module_param(do_delays,      uint, 0400);
 module_param(log,            uint, 0400);
 module_param(dbg,            uint, 0400);
+module_param_array(parts, ulong, &parts_num, 0400);
 
 MODULE_PARM_DESC(first_id_byte,  "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
 MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
 MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
 MODULE_PARM_DESC(log,            "Perform logging if not zero");
 MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
+MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
 
 /* The largest possible page size */
 #define NS_LARGEST_PAGE_SIZE   2048
 #define NS_DBG(args...) \
        do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
 #define NS_WARN(args...) \
-       do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0)
+       do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
 #define NS_ERR(args...) \
-       do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0)
+       do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
 
 /* Busy-wait delay macros (microseconds, milliseconds) */
 #define NS_UDELAY(us) \
  * The structure which describes all the internal simulator data.
  */
 struct nandsim {
-       struct mtd_partition part;
+       struct mtd_partition partitions[MAX_MTD_DEVICES];
+       unsigned int nbparts;
 
        uint busw;              /* flash chip bus width (8 or 16) */
        u_char ids[4];          /* chip's ID bytes */
        }
 }
 
+static char *get_partition_name(int i)
+{
+       char buf[64];
+       sprintf(buf, "NAND simulator partition %d", i);
+       return kstrdup(buf, GFP_KERNEL);
+}
+
 /*
  * Initialize the nandsim structure.
  *
 {
        struct nand_chip *chip = (struct nand_chip *)mtd->priv;
        struct nandsim   *ns   = (struct nandsim *)(chip->priv);
-       int i;
+       int i, ret = 0;
+       u_int32_t remains;
+       u_int32_t next_offset;
 
        if (NS_IS_INITIALIZED(ns)) {
                NS_ERR("init_nandsim: nandsim is already initialized\n");
                }
        }
 
+       /* Fill the partition_info structure */
+       if (parts_num > ARRAY_SIZE(ns->partitions)) {
+               NS_ERR("too many partitions.\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       remains = ns->geom.totsz;
+       next_offset = 0;
+       for (i = 0; i < parts_num; ++i) {
+               unsigned long part = parts[i];
+               if (!part || part > remains / ns->geom.secsz) {
+                       NS_ERR("bad partition size.\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               ns->partitions[i].name   = get_partition_name(i);
+               ns->partitions[i].offset = next_offset;
+               ns->partitions[i].size   = part * ns->geom.secsz;
+               next_offset += ns->partitions[i].size;
+               remains -= ns->partitions[i].size;
+       }
+       ns->nbparts = parts_num;
+       if (remains) {
+               if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
+                       NS_ERR("too many partitions.\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               ns->partitions[i].name   = get_partition_name(i);
+               ns->partitions[i].offset = next_offset;
+               ns->partitions[i].size   = remains;
+               ns->nbparts += 1;
+       }
+
        /* Detect how many ID bytes the NAND chip outputs */
         for (i = 0; nand_flash_ids[i].name != NULL; i++) {
                 if (second_id_byte != nand_flash_ids[i].id)
        printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
        printk("options: %#x\n",                ns->options);
 
-       if (alloc_device(ns) != 0)
+       if ((ret = alloc_device(ns)) != 0)
                goto error;
 
        /* Allocate / initialize the internal buffer */
        if (!ns->buf.byte) {
                NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
                        ns->geom.pgszoob);
+               ret = -ENOMEM;
                goto error;
        }
        memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
 
-       /* Fill the partition_info structure */
-       ns->part.name   = "NAND simulator partition";
-       ns->part.offset = 0;
-       ns->part.size   = ns->geom.totsz;
-
        return 0;
 
 error:
        free_device(ns);
 
-       return -ENOMEM;
+       return ret;
 }
 
 /*
 {
        struct nand_chip *chip;
        struct nandsim *nand;
-       int retval = -ENOMEM;
+       int retval = -ENOMEM, i;
 
        if (bus_width != 8 && bus_width != 16) {
                NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
                goto error;
        }
 
-       if ((retval = init_nandsim(nsmtd)) != 0) {
-               NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
-               goto error;
-       }
+       if ((retval = init_nandsim(nsmtd)) != 0)
+               goto err_exit;
 
-       if ((retval = nand_default_bbt(nsmtd)) != 0) {
-               free_nandsim(nand);
-               goto error;
-       }
+       if ((retval = nand_default_bbt(nsmtd)) != 0)
+               goto err_exit;
 
-       /* Register NAND as one big partition */
-       add_mtd_partitions(nsmtd, &nand->part, 1);
+       /* Register NAND partitions */
+       if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0)
+               goto err_exit;
 
         return 0;
 
+err_exit:
+       free_nandsim(nand);
+       nand_release(nsmtd);
+       for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
+               kfree(nand->partitions[i].name);
 error:
        kfree(nsmtd);
 
 static void __exit ns_cleanup_module(void)
 {
        struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv);
+       int i;
 
        free_nandsim(ns);    /* Free nandsim private resources */
-       nand_release(nsmtd); /* Unregisterd drived */
+       nand_release(nsmtd); /* Unregister driver */
+       for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
+               kfree(ns->partitions[i].name);
        kfree(nsmtd);        /* Free other structures */
 }
 
 MODULE_LICENSE ("GPL");
 MODULE_AUTHOR ("Artem B. Bityuckiy");
 MODULE_DESCRIPTION ("The NAND flash simulator");
-