*
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.173 2005/03/30 23:57:30 tpoynor Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.174 2005/04/01 01:59:52 nico Exp $
  *
  * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 #include <linux/mtd/xip.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #endif
 static int cfi_intelext_suspend (struct mtd_info *);
 static void cfi_intelext_resume (struct mtd_info *);
+static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *);
 
 static void cfi_intelext_destroy(struct mtd_info *);
 
        mtd->resume  = cfi_intelext_resume;
        mtd->flags   = MTD_CAP_NORFLASH;
        mtd->name    = map->name;
-       
+
+       mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
+
        if (cfi->cfi_mode == CFI_MODE_CFI) {
                /* 
                 * It's a real CFI chip, not one for which the probe
                goto setup_err;
 
        __module_get(THIS_MODULE);
+       register_reboot_notifier(&mtd->reboot_notifier);
        return mtd;
 
  setup_err:
        }
 }
 
+static int cfi_intelext_reset(struct mtd_info *mtd)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       int i, ret;
+
+       for (i=0; i < cfi->numchips; i++) {
+               struct flchip *chip = &cfi->chips[i];
+
+               /* force the completion of any ongoing operation
+                  and switch to array mode so any bootloader in 
+                  flash is accessible for soft reboot. */
+               spin_lock(chip->mutex);
+               ret = get_chip(map, chip, chip->start, FL_SYNCING);
+               if (!ret) {
+                       map_write(map, CMD(0xff), chip->start);
+                       chip->state = FL_READY;
+               }
+               spin_unlock(chip->mutex);
+       }
+
+       return 0;
+}
+
+static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,
+                              void *v)
+{
+       struct mtd_info *mtd;
+
+       mtd = container_of(nb, struct mtd_info, reboot_notifier);
+       cfi_intelext_reset(mtd);
+       return NOTIFY_DONE;
+}
+
 static void cfi_intelext_destroy(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
+       cfi_intelext_reset(mtd);
+       unregister_reboot_notifier(&mtd->reboot_notifier);
        kfree(cfi->cmdset_priv);
        kfree(cfi->cfiq);
        kfree(cfi->chips[0].priv);
 
 /* 
- * $Id: mtd.h,v 1.57 2005/02/08 17:11:15 nico Exp $
+ * $Id: mtd.h,v 1.58 2005/04/01 01:59:54 nico Exp $
  *
  * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
  *
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/uio.h>
+#include <linux/notifier.h>
 
 #include <linux/mtd/compatmac.h>
 #include <mtd/mtd-abi.h>
        int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
        int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
 
+       struct notifier_block reboot_notifier;  /* default mode before reboot */
+
        void *priv;
 
        struct module *owner;