allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
        $< --$@ $(Kconfig)
 
-PHONY += listnewconfig oldnoconfig defconfig
+PHONY += listnewconfig oldnoconfig savedefconfig defconfig
 
 listnewconfig oldnoconfig: $(obj)/conf
        $< --$@ $(Kconfig)
 
+savedefconfig: $(obj)/conf
+       $< --$@=defconfig $(Kconfig)
+
 defconfig: $(obj)/conf
 ifeq ($(KBUILD_DEFCONFIG),)
        $< --defconfig $(Kconfig)
        @echo  '  localyesconfig  - Update current config converting local mods to core'
        @echo  '  silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
        @echo  '  defconfig       - New config with default from ARCH supplied defconfig'
+       @echo  '  savedefconfig   - Save current config as ./defconfig (minimal config)'
        @echo  '  allnoconfig     - New config where all options are answered with no'
        @echo  '  allyesconfig    - New config where all options are accepted with yes'
        @echo  '  allmodconfig    - New config selecting modules when possible'
 
        alldefconfig,
        randconfig,
        defconfig,
+       savedefconfig,
        listnewconfig,
        oldnoconfig,
 } input_mode = oldaskconfig;
        {"oldconfig",       no_argument,       NULL, oldconfig},
        {"silentoldconfig", no_argument,       NULL, silentoldconfig},
        {"defconfig",       optional_argument, NULL, defconfig},
+       {"savedefconfig",   required_argument, NULL, savedefconfig},
        {"allnoconfig",     no_argument,       NULL, allnoconfig},
        {"allyesconfig",    no_argument,       NULL, allyesconfig},
        {"allmodconfig",    no_argument,       NULL, allmodconfig},
                        sync_kconfig = 1;
                        break;
                case defconfig:
+               case savedefconfig:
                        defconfig_file = optarg;
                        break;
                case randconfig:
                        exit(1);
                }
                break;
+       case savedefconfig:
+               conf_read(NULL);
+               break;
        case silentoldconfig:
        case oldaskconfig:
        case oldconfig:
        case defconfig:
                conf_set_all_new_symbols(def_default);
                break;
+       case savedefconfig:
+               break;
        case oldconfig:
        case oldaskconfig:
                rootEntry = &rootmenu;
                        fprintf(stderr, _("\n*** Error during update of the kernel configuration.\n\n"));
                        return 1;
                }
+       } else if (input_mode == savedefconfig) {
+               if (conf_write_defconfig(defconfig_file)) {
+                       fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+                               defconfig_file);
+                       return 1;
+               }
        } else if (input_mode != listnewconfig) {
                if (conf_write(NULL)) {
                        fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
 
        }
 }
 
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+       struct symbol *sym;
+       struct menu *menu;
+       FILE *out;
+
+       out = fopen(filename, "w");
+       if (!out)
+               return 1;
+
+       sym_clear_all_valid();
+
+       /* Traverse all menus to find all relevant symbols */
+       menu = rootmenu.list;
+
+       while (menu != NULL)
+       {
+               sym = menu->sym;
+               if (sym == NULL) {
+                       if (!menu_is_visible(menu))
+                               goto next_menu;
+               } else if (!sym_is_choice(sym)) {
+                       sym_calc_value(sym);
+                       if (!(sym->flags & SYMBOL_WRITE))
+                               goto next_menu;
+                       sym->flags &= ~SYMBOL_WRITE;
+                       /* If we cannot change the symbol - skip */
+                       if (!sym_is_changable(sym))
+                               goto next_menu;
+                       /* If symbol equals to default value - skip */
+                       if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+                               goto next_menu;
+
+                       /*
+                        * If symbol is a choice value and equals to the
+                        * default for a choice - skip.
+                        * But only if value equal to "y".
+                        */
+                       if (sym_is_choice_value(sym)) {
+                               struct symbol *cs;
+                               struct symbol *ds;
+
+                               cs = prop_get_symbol(sym_get_choice_prop(sym));
+                               ds = sym_choice_default(cs);
+                               if (sym == ds) {
+                                       if ((sym->type == S_BOOLEAN ||
+                                       sym->type == S_TRISTATE) &&
+                                       sym_get_tristate_value(sym) == yes)
+                                               goto next_menu;
+                               }
+                       }
+                       conf_write_symbol(sym, sym->type, out, true);
+               }
+next_menu:
+               if (menu->list != NULL) {
+                       menu = menu->list;
+               }
+               else if (menu->next != NULL) {
+                       menu = menu->next;
+               } else {
+                       while ((menu = menu->parent)) {
+                               if (menu->next != NULL) {
+                                       menu = menu->next;
+                                       break;
+                               }
+                       }
+               }
+       }
+       fclose(out);
+       return 0;
+}
+
 int conf_write(const char *name)
 {
        FILE *out;
 
 void sym_set_all_changed(void);
 void sym_set_changed(struct symbol *sym);
 struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
 struct symbol *sym_check_deps(struct symbol *sym);
 struct property *prop_alloc(enum prop_type type, struct symbol *sym);
 struct symbol *prop_get_symbol(struct property *prop);
 
 P(conf_parse,void,(const char *name));
 P(conf_read,int,(const char *name));
 P(conf_read_simple,int,(const char *name, int));
+P(conf_write_defconfig,int,(const char *name));
 P(conf_write,int,(const char *name));
 P(conf_write_autoconf,int,(void));
 P(conf_get_changed,bool,(void));
 
        return true;
 }
 
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+       struct property *prop;
+       struct symbol *ds;
+       const char *str;
+       tristate val;
+
+       sym_calc_visibility(sym);
+       sym_calc_value(modules_sym);
+       val = symbol_no.curr.tri;
+       str = symbol_empty.curr.val;
+
+       /* If symbol has a default value look it up */
+       prop = sym_get_default_prop(sym);
+       if (prop != NULL) {
+               switch (sym->type) {
+               case S_BOOLEAN:
+               case S_TRISTATE:
+                       /* The visibility imay limit the value from yes => mod */
+                       val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+                       break;
+               default:
+                       /*
+                        * The following fails to handle the situation
+                        * where a default value is further limited by
+                        * the valid range.
+                        */
+                       ds = prop_get_symbol(prop);
+                       if (ds != NULL) {
+                               sym_calc_value(ds);
+                               str = (const char *)ds->curr.val;
+                       }
+               }
+       }
+
+       /* Handle select statements */
+       val = EXPR_OR(val, sym->rev_dep.tri);
+
+       /* transpose mod to yes if modules are not enabled */
+       if (val == mod)
+               if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+                       val = yes;
+
+       /* transpose mod to yes if type is bool */
+       if (sym->type == S_BOOLEAN && val == mod)
+               val = yes;
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (val) {
+               case no: return "n";
+               case mod: return "m";
+               case yes: return "y";
+               }
+       case S_INT:
+       case S_HEX:
+               return str;
+       case S_STRING:
+               return str;
+       case S_OTHER:
+       case S_UNKNOWN:
+               break;
+       }
+       return "";
+}
+
 const char *sym_get_string_value(struct symbol *sym)
 {
        tristate val;