Beispiel #1
0
void env_relocate(void){
	DEBUGF("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__, gd->reloc_off);

#if defined(ENV_IS_EMBEDDED)
	/*
	 * The environment buffer is embedded with the text segment,
	 * just relocate the environment pointer
	 */
	env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
	DEBUGF("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
	/*
	 * We must allocate a buffer for the environment
	 */
	env_ptr = (env_t *)malloc(CFG_ENV_SIZE);
	DEBUGF("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif

	/*
	 * After relocation to RAM, we can always use the "memory" functions
	 */
	env_get_char = env_get_char_memory;

	if(gd->env_valid == 0){
#if defined(CFG_ENV_IS_NOWHERE)	/* Environment not changable */
		//puts("Using default environment\n\n");
#else
		puts("** Warning: bad env CRC, using default,\n"
			 "   use 'saveenv' to save it in flash\n\n");
#endif

		if(sizeof(default_environment) > ENV_SIZE){
			puts("## Error: default environment is too large\n");
			return;
		}

		memset(env_ptr, 0, sizeof(env_t));
		memcpy(env_ptr->data, default_environment, sizeof(default_environment));
#ifdef CFG_REDUNDAND_ENVIRONMENT
		env_ptr->flags = 0xFF;
#endif
		env_crc_update();
		gd->env_valid = 1;
	} else {
		env_relocate_spec();
	}
	gd->env_addr = (ulong)&(env_ptr->data);
}
Beispiel #2
0
void set_default_env(void)
{
	if (sizeof(default_environment) > ENV_SIZE) {
		puts ("*** Error - default environment is too large\n\n");
		return;
	}

	memset(env_ptr, 0, sizeof(env_t));
	memcpy(env_ptr->data, default_environment,
	       sizeof(default_environment));
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
	env_ptr->flags = 0xFF;
#endif
	env_crc_update ();
	gd->env_valid = 1;
}
void default_env(void)
{
	if (sizeof(default_environment) > ENV_SIZE)
	{
		puts ("*** Error - default environment is too large\n\n");
		return;
	}

	memset (env_ptr, 0, sizeof(env_t));
	memcpy (env_ptr->data,
		default_environment,
		sizeof(default_environment));

#ifdef CFG_ENV_OVERRIDE
	if (env_override)
		memcpy(env_ptr->data, env_override, ENV_SIZE);
#endif

#ifdef CFG_REDUNDAND_ENVIRONMENT
	env_ptr->flags = 0xFF;
#endif
	env_crc_update ();
	gd->env_valid = 1;
}
Beispiel #4
0
void env_relocate (void)
{
	DECLARE_GLOBAL_DATA_PTR;

	DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
		gd->reloc_off);

#ifdef CONFIG_AMIGAONEG3SE
	enable_nvram();
#endif

#ifdef ENV_IS_EMBEDDED
	/*
	 * The environment buffer is embedded with the text segment,
	 * just relocate the environment pointer
	 */
	env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
	DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
	/*
	 * We must allocate a buffer for the environment
	 */
	env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
	DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif

	/*
	 * After relocation to RAM, we can always use the "memory" functions
	 */
	env_get_char = env_get_char_memory;

	if (gd->env_valid == 0) {
#if defined(CONFIG_GTH)	|| defined(CFG_ENV_IS_NOWHERE)	/* Environment not changable */
		puts ("Using default environment\n\n");
#else
		puts ("*** Warning - bad CRC, using default environment\n\n");
		SHOW_BOOT_PROGRESS (-1);
#endif

		if (sizeof(default_environment) > ENV_SIZE)
		{
			puts ("*** Error - default environment is too large\n\n");
			return;
		}

		memset (env_ptr, 0, sizeof(env_t));
		memcpy (env_ptr->data,
			default_environment,
			sizeof(default_environment));
#ifdef CFG_REDUNDAND_ENVIRONMENT
		env_ptr->flags = 0xFF;
#endif
		env_crc_update ();
		gd->env_valid = 1;
	}
	else {
		env_relocate_spec ();
	}
	gd->env_addr = (ulong)&(env_ptr->data);

#ifdef CONFIG_AMIGAONEG3SE
	disable_nvram();
#endif
}
Beispiel #5
0
int _do_setenv (int flag, int argc, char *argv[])
{
	int   i, len, oldval;
	int   console = -1;
	uchar *env, *nxt = NULL;
	char *name;
	bd_t *bd = gd->bd;

	uchar *env_data = env_get_addr(0);

	if (!env_data)	/* need copy in RAM */
		return 1;

	name = argv[1];

	if (strchr(name, '=')) {
		printf ("## Error: illegal character '=' in variable name \"%s\"\n", name);
		return 1;
	}

	/*
	 * search if variable with this name already exists
	 */
	oldval = -1;
	for (env=env_data; *env; env=nxt+1) {
		for (nxt=env; *nxt; ++nxt)
			;
		if ((oldval = envmatch((uchar *)name, env-env_data)) >= 0)
			break;
	}

	/*
	 * Delete any existing definition
	 */
	if (oldval >= 0) {
#ifndef CONFIG_ENV_OVERWRITE

		/*
		 * Ethernet Address and serial# can be set only once,
		 * ver is readonly.
		 */
		if (
#ifdef CONFIG_HAS_UID
		/* Allow serial# forced overwrite with 0xdeaf4add flag */
		    ((strcmp (name, "serial#") == 0) && (flag != 0xdeaf4add)) ||
#else
		    (strcmp (name, "serial#") == 0) ||
#endif
		    ((strcmp (name, "ethaddr") == 0)
#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
		     && (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
#endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
		    ) ) {
			printf ("Can't overwrite \"%s\"\n", name);
			return 1;
		}
#endif

		/* Check for console redirection */
		if (strcmp(name,"stdin") == 0) {
			console = stdin;
		} else if (strcmp(name,"stdout") == 0) {
			console = stdout;
		} else if (strcmp(name,"stderr") == 0) {
			console = stderr;
		}

		if (console != -1) {
			if (argc < 3) {		/* Cannot delete it! */
				printf("Can't delete \"%s\"\n", name);
				return 1;
			}

#ifdef CONFIG_CONSOLE_MUX
			i = iomux_doenv(console, argv[2]);
			if (i)
				return i;
#else
			/* Try assigning specified device */
			if (console_assign (console, argv[2]) < 0)
				return 1;

#ifdef CONFIG_SERIAL_MULTI
			if (serial_assign (argv[2]) < 0)
				return 1;
#endif
#endif /* CONFIG_CONSOLE_MUX */
		}

		/*
		 * Switch to new baudrate if new baudrate is supported
		 */
		if (strcmp(argv[1],"baudrate") == 0) {
			int baudrate = simple_strtoul(argv[2], NULL, 10);
			int i;
			for (i=0; i<N_BAUDRATES; ++i) {
				if (baudrate == baudrate_table[i])
					break;
			}
			if (i == N_BAUDRATES) {
				printf ("## Baudrate %d bps not supported\n",
					baudrate);
				return 1;
			}
			printf ("## Switch baudrate to %d bps and press ENTER ...\n",
				baudrate);
			udelay(50000);
			gd->baudrate = baudrate;
#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
			gd->bd->bi_baudrate = baudrate;
#endif

			serial_setbrg ();
			udelay(50000);
			for (;;) {
				if (getc() == '\r')
				      break;
			}
		}

		if (*++nxt == '\0') {
			if (env > env_data) {
				env--;
			} else {
				*env = '\0';
			}
		} else {
			for (;;) {
				*env = *nxt++;
				if ((*env == '\0') && (*nxt == '\0'))
					break;
				++env;
			}
		}
		*++env = '\0';
	}

#ifdef CONFIG_NET_MULTI
	if (strncmp(name, "eth", 3) == 0) {
		char *end;
		int   num = simple_strtoul(name+3, &end, 10);

		if (strcmp(end, "addr") == 0) {
			eth_set_enetaddr(num, argv[2]);
		}
	}
#endif


	/* Delete only ? */
	if ((argc < 3) || argv[2] == NULL) {
		env_crc_update ();
		return 0;
	}

	/*
	 * Append new definition at the end
	 */
	for (env=env_data; *env || *(env+1); ++env)
		;
	if (env > env_data)
		++env;
	/*
	 * Overflow when:
	 * "name" + "=" + "val" +"\0\0"  > ENV_SIZE - (env-env_data)
	 */
	len = strlen(name) + 2;
	/* add '=' for first arg, ' ' for all others */
	for (i=2; i<argc; ++i) {
		len += strlen(argv[i]) + 1;
	}
	if (len > (&env_data[ENV_SIZE]-env)) {
		printf ("## Error: environment overflow, \"%s\" deleted\n", name);
		return 1;
	}
	while ((*env = *name++) != '\0')
		env++;
	for (i=2; i<argc; ++i) {
		char *val = argv[i];

		*env = (i==2) ? '=' : ' ';
		while ((*++env = *val++) != '\0')
			;
	}

	/* end is marked with double '\0' */
	*++env = '\0';

	/* Update CRC */
	env_crc_update ();

	/*
	 * Some variables should be updated when the corresponding
	 * entry in the enviornment is changed
	 */

	if (strcmp(argv[1],"ethaddr") == 0) {
		char *s = argv[2];	/* always use only one arg */
		char *e;
		for (i=0; i<6; ++i) {
			bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
			if (s) s = (*e) ? e+1 : e;
		}
#ifdef CONFIG_NET_MULTI
		eth_set_enetaddr(0, argv[2]);
#endif
		return 0;
	}

	if (strcmp(argv[1],"ipaddr") == 0) {
		char *s = argv[2];	/* always use only one arg */
		char *e;
		unsigned long addr;
		bd->bi_ip_addr = 0;
		for (addr=0, i=0; i<4; ++i) {
			ulong val = s ? simple_strtoul(s, &e, 10) : 0;
			addr <<= 8;
			addr  |= (val & 0xFF);
			if (s) s = (*e) ? e+1 : e;
		}
		bd->bi_ip_addr = htonl(addr);
		return 0;
	}
	if (strcmp(argv[1],"loadaddr") == 0) {
		load_addr = simple_strtoul(argv[2], NULL, 16);
		return 0;
	}
#if defined(CONFIG_CMD_NET)
	if (strcmp(argv[1],"bootfile") == 0) {
		copy_filename (BootFile, argv[2], sizeof(BootFile));
		return 0;
	}
#endif

#ifdef CONFIG_AMIGAONEG3SE
	if (strcmp(argv[1], "vga_fg_color") == 0 ||
	    strcmp(argv[1], "vga_bg_color") == 0 ) {
		extern void video_set_color(unsigned char attr);
		extern unsigned char video_get_attr(void);

		video_set_color(video_get_attr());
		return 0;
	}
#endif	/* CONFIG_AMIGAONEG3SE */

	return 0;
}
Beispiel #6
0
/************************************************************************
 * Set a new environment variable,
 * or replace or delete an existing one.
 *
 * This function will ONLY work with a in-RAM copy of the environment
 */
int _do_setenv(int flag, int argc, char *argv[]){
	int i, len, oldval;
	int console = -1;
	uchar *env, *nxt = NULL;
	char *name;
	bd_t *bd = gd->bd;

	uchar *env_data = env_get_addr(0);

	if(!env_data){ /* need copy in RAM */
		return(1);
	}

	name = argv[1];

	/*
	 * search if variable with this name already exists
	 */
	oldval = -1;

	for(env = env_data; *env; env = nxt + 1){
		for(nxt = env; *nxt; ++nxt);

		if((oldval = envmatch((uchar *)name, env - env_data)) >= 0){
			break;
		}
	}

	/*
	 * Delete any existing definition
	 */
	if(oldval >= 0){
		/* Check for console redirection */
		if(strcmp(name, "stdin") == 0){
			console = stdin;
		} else if(strcmp(name, "stdout") == 0){
			console = stdout;
		} else if(strcmp(name, "stderr") == 0){
			console = stderr;
		}

		if(console != -1){
			if(argc < 3){ /* Cannot delete it! */
				printf("## Error: can't delete \"%s\"\n", name);
				return(1);
			}

			/* Try assigning specified device */
			if(console_assign(console, argv[2]) < 0){
				return(1);
			}

#ifdef CONFIG_SERIAL_MULTI
			if(serial_assign(argv[2]) < 0){
				return(1);
			}
#endif
		}

		/*
		 * Switch to new baudrate if new baudrate is supported
		 */
		if(strcmp(argv[1], "baudrate") == 0){
			int baudrate = simple_strtoul(argv[2], NULL, 10);
			int i;

			for(i = 0; i < N_BAUDRATES; ++i){
				if(baudrate == baudrate_table[i]){
					break;
				}
			}

			if(i == N_BAUDRATES){
				printf("## Error: baudrate %d bps is not supported,\n", baudrate);
				printf("          choose one from the list:\n\n");
				for(i = 0; i < N_BAUDRATES; ++i){
					printf("- %7d bps%s\n", baudrate_table[i], baudrate_table[i] == gd->baudrate ? " [current]" : "");
				}
				printf("\n");
				return(1);
			}

			printf("Switch baudrate to %d bps and press ENTER...\n", baudrate);
			udelay(50000);

			gd->baudrate = baudrate;

			serial_setbrg();

			udelay(50000);

			for(;;){
				if(getc() == '\r'){
					break;
				}
			}
		}

		if(*++nxt == '\0'){
			if(env > env_data){
				env--;
			} else {
				*env = '\0';
			}
		} else {
			for(;;){
				*env = *nxt++;

				if((*env == '\0') && (*nxt == '\0')){
					break;
				}

				++env;
			}
		}
		*++env = '\0';
	}

#ifdef CONFIG_NET_MULTI
	if(strncmp(name, "eth", 3) == 0){
		char *end;
		int num = simple_strtoul(name + 3, &end, 10);

		if(strcmp(end, "addr") == 0){
			eth_set_enetaddr(num, argv[2]);
		}
	}
#endif

	/* Delete only ? */
	if((argc < 3) || argv[2] == NULL){
		env_crc_update();
		return(0);
	}

	/*
	 * Append new definition at the end
	 */
	for(env = env_data; *env || *(env + 1); ++env);

	if(env > env_data){
		++env;
	}
	/*
	 * Overflow when:
	 * "name" + "=" + "val" +"\0\0"  > ENV_SIZE - (env-env_data)
	 */
	len = strlen(name) + 2;

	/* add '=' for first arg, ' ' for all others */
	for(i = 2; i < argc; ++i){
		len += strlen(argv[i]) + 1;
	}

	if(len > (&env_data[ENV_SIZE] - env)){
		printf("## Error: environment overflow, \"%s\" deleted\n", name);
		return(1);
	}

	while((*env = *name++) != '\0'){
		env++;
	}

	for(i = 2; i < argc; ++i){
		char *val = argv[i];

		*env = (i == 2) ? '=' : ' ';
		while((*++env = *val++) != '\0');
	}

	/* end is marked with double '\0' */
	*++env = '\0';

	/* Update CRC */
	env_crc_update();

	/*
	 * Some variables should be updated when the corresponding
	 * entry in the enviornment is changed
	 */
	if(strcmp(argv[1], "ethaddr") == 0){
		char *s = argv[2]; /* always use only one arg */
		char *e;

		for(i = 0; i < 6; ++i){
			bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
			if(s){
				s = (*e) ? e + 1 : e;
			}
		}
#ifdef CONFIG_NET_MULTI
		eth_set_enetaddr(0, argv[2]);
#endif
		return(0);
	}

	if(strcmp(argv[1], "ipaddr") == 0){
		char *s = argv[2]; /* always use only one arg */
		char *e;
		unsigned long addr;

		bd->bi_ip_addr = 0;

		for(addr = 0, i = 0; i < 4; ++i){
			ulong val = s ? simple_strtoul(s, &e, 10) : 0;
			addr <<= 8;
			addr |= (val & 0xFF);
			if(s){
				s = (*e) ? e + 1 : e;
			}
		}

		bd->bi_ip_addr = htonl(addr);
		return(0);
	}

	if(strcmp(argv[1], "loadaddr") == 0){
		load_addr = simple_strtoul(argv[2], NULL, 16);
		return(0);
	}

#if (CONFIG_COMMANDS & CFG_CMD_NET)
	if(strcmp(argv[1], "bootfile") == 0){
		copy_filename(BootFile, argv[2], sizeof(BootFile));
		return(0);
	}
#endif	/* CFG_CMD_NET */

	return(0);
}
        /* ed is not valid anymore! */
        return 0;
    } else {
        printk(KERN_ERR\
            "%s: Cannot find a valid env!\n",\
            __func__);
        return -1;
    }
#ifdef DEBUGME
    printk(KERN_ERR\
        "%s: All done, exiting!\n",\
        __func__);
#endif /*DEBUGME*/
    return 0;
}
#else /*CONFIG_CIRRUS_DUAL_MTD_ENV*/
int rtcnvet_do_setenv(char *name, char *val)
{
    int len, oldval;
    unsigned char *env, *nxt = NULL;
    unsigned char *env_data = NULL;

    rtcnvet_reload_env();
    env_data = (unsigned char *)&env_buf[0];

    if (!env_valid)
        return -1;

    if (strchr(name, '=')) {
        printk(KERN_ERR \
        "Illegal character '=' in variable name \"%s\"\n", name);
        return -2;
    }

    /*
     * search if variable with this name already exists
     */
    oldval = -1;
    for (env = env_data; *env; env = nxt+1) {
        for (nxt = env; *nxt; ++nxt)
            ;
        oldval = envmatch((unsigned char *)name, env-env_data);
        if (oldval >= 0)
            break;
    }


    /*
     * Delete any existing definition
     */
    if (oldval >= 0) {
        if (*++nxt == '\0')
            if (env > env_data) {
                env--;
            } else {
                *env = '\0';
        } else {
            for (;;) {
                *env = *nxt++;
                if ((*env == '\0') && (*nxt == '\0'))
                    break;
                ++env;
            }
        }
        *++env = '\0';
    }

    /*
     * Append new definition at the end
     */
    for (env = env_data; *env || *(env+1); ++env)
        ;
    if (env > env_data)
        ++env;
    /*
     * Overflow when:
     * "name" + "=" + "val" +"\0\0"  > ENV_SIZE - (env-env_data)
     */
    len = strlen(name) + 2;
    /* add '=' for first arg, ' ' for all others */
    len += strlen(val) + 1;
    if (len > (&env_data[env_size]-env)) {
        printk(KERN_ERR \
        "Environment overflow, \"%s\" deleted\n", name);
        return 1;
    }
    while ((*env = *name++) != '\0')
        env++;

    *env = '=';
    while ((*++env = *val++) != '\0')
        ;

    /* end is marked with double '\0' */
    *++env = '\0';

    /* Update CRC */
    env_crc_update();

    /* save every time */
    env_save();

    return 0;
}
/*
 * The legacy NAND code saved the environment in the first NAND device i.e.,
 * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
 */
int writeenv(size_t offset, u_char *buf)
{
	struct mtd_info *mtd;
	struct env_oobinfo_t *env_oobinfo;
	int error = 0;
	size_t addr = 0;
	size_t amount_saved = 0;
	size_t len;
	struct mtd_oob_ops aml_oob_ops;
	unsigned char *data_buf;
	unsigned char env_oob_buf[sizeof(struct env_oobinfo_t)];

	mtd = nand_info[nand_curr_device];
	if (mtd == NULL)
		return 1;

	struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
	data_buf = kzalloc(mtd->writesize, GFP_KERNEL);
	if (data_buf == NULL)
		return -ENOMEM;

	addr = offset;
	env_oobinfo = (struct env_oobinfo_t *)env_oob_buf;
	memcpy(env_oobinfo->name, ENV_NAND_MAGIC, 4);
	env_oobinfo->ec = aml_chip->aml_nandenv_info->env_valid_node->ec;
	env_oobinfo->timestamp = aml_chip->aml_nandenv_info->env_valid_node->timestamp;
	env_oobinfo->status_page = 1;

	while (amount_saved < CONFIG_ENV_SIZE ) {

		aml_oob_ops.mode = MTD_OOB_AUTO;
		aml_oob_ops.len = mtd->writesize;
		aml_oob_ops.ooblen = sizeof(struct env_oobinfo_t);
		aml_oob_ops.ooboffs = mtd->ecclayout->oobfree[0].offset;
		aml_oob_ops.datbuf = data_buf;
		aml_oob_ops.oobbuf = env_oob_buf;

		memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
		len = min(mtd->writesize, CONFIG_ENV_SIZE - amount_saved);
		memcpy((unsigned char *)aml_oob_ops.datbuf, buf + amount_saved, len);

		error = mtd->write_oob(mtd, addr, &aml_oob_ops);
		if (error) {
			printf("blk check good but write failed: %llx, %d\n", offset, error);
			return 1;
		}

		addr += mtd->writesize;;
		amount_saved += mtd->writesize;
	}
	if (amount_saved < CONFIG_ENV_SIZE)
		return 1;

	kfree(data_buf);
	return 0;
}
#ifdef CONFIG_ENV_OFFSET_REDUND
int saveenv(void)
{
	struct mtd_info * mtd=get_mtd_device_nm(NAND_NORMAL_NAME);
	if (IS_ERR(mtd))
		return 1;
	struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
	size_t total;
	size_t offset = CONFIG_ENV_OFFSET;
	int ret = 0;
	nand_erase_options_t nand_erase_options;

	offset = (1024 * aml_chip->page_size * (mtd->writesize / (aml_chip->plane_num * aml_chip->page_size)));
	if (CONFIG_ENV_OFFSET < offset)
		_debug ("env define offset must larger than 1024 page size: %d \n", mtd->writesize);
	else
		offset = CONFIG_ENV_OFFSET;

	env_ptr->flags++;
	total = CONFIG_ENV_SIZE;

	nand_erase_options.length = CONFIG_ENV_RANGE;
	nand_erase_options.quiet = 0;
	nand_erase_options.jffs2 = 0;
	nand_erase_options.scrub = 0;

	if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
		return 1;
	if(gd->env_valid == 1) {
		puts ("Erasing redundant Nand...\n");
		nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
		if (nand_erase_opts(mtd, &nand_erase_options))
			return 1;

		puts ("Writing to redundant Nand... ");
		ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr);
	} else {
		puts ("Erasing Nand...\n");
		nand_erase_options.offset = CONFIG_ENV_OFFSET;
		if (nand_erase_opts(mtd, &nand_erase_options))
			return 1;

		puts ("Writing to Nand... ");
		ret = writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
	}
	if (ret) {
		puts("FAILED!\n");
		return 1;
	}

	puts ("done\n");
	gd->env_valid = (gd->env_valid == 2 ? 1 : 2);
	return ret;
}
#else /* ! CONFIG_ENV_OFFSET_REDUND */
int saveenv(void)
{
	struct mtd_info *mtd;
	struct aml_nand_bbt_info *nand_bbt_info;
	struct env_free_node_t *env_free_node, *env_tmp_node;
	int error = 0, pages_per_blk, i = 1;
	size_t addr = 0;
	struct erase_info aml_env_erase_info;

	mtd = nand_info[nand_curr_device];
	if (mtd == NULL)
		return 1;

	struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
	if (!aml_chip->aml_nandenv_info->env_init) 
		return 1;

	pages_per_blk = mtd->erasesize / mtd->writesize;
	if ((mtd->writesize < CONFIG_ENV_SIZE) && (aml_chip->aml_nandenv_info->env_valid == 1))
		i = (CONFIG_ENV_SIZE + mtd->writesize - 1) / mtd->writesize;
	
	if (aml_chip->aml_nandenv_info->env_valid) {
		aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr += i;
		if ((aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr + i) > pages_per_blk) {

			env_free_node = kzalloc(sizeof(struct env_free_node_t), GFP_KERNEL);
			if (env_free_node == NULL)
				return -ENOMEM;

			env_free_node->phy_blk_addr = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
			env_free_node->ec = aml_chip->aml_nandenv_info->env_valid_node->ec;
			env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
			while (env_tmp_node->next != NULL) {
				env_tmp_node = env_tmp_node->next;
			}
			env_tmp_node->next = env_free_node;

			env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
			aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr = env_tmp_node->phy_blk_addr;
			aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr = 0;
			aml_chip->aml_nandenv_info->env_valid_node->ec = env_tmp_node->ec;
			aml_chip->aml_nandenv_info->env_valid_node->timestamp += 1;
			aml_chip->aml_nandenv_info->env_free_node = env_tmp_node->next;
			kfree(env_tmp_node);
		}
	}
	else {

		env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
		aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr = env_tmp_node->phy_blk_addr;
		aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr = 0;
		aml_chip->aml_nandenv_info->env_valid_node->ec = env_tmp_node->ec;
		aml_chip->aml_nandenv_info->env_valid_node->timestamp += 1;
		aml_chip->aml_nandenv_info->env_free_node = env_tmp_node->next;
		kfree(env_tmp_node);
	}

	addr = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
	addr *= mtd->erasesize;
	addr += aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr * mtd->writesize;
	if (aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr == 0) {

		memset(&aml_env_erase_info, 0, sizeof(struct erase_info));
		aml_env_erase_info.mtd = mtd;
		aml_env_erase_info.addr = addr;
		aml_env_erase_info.len = mtd->erasesize;

		error = mtd->erase(mtd, &aml_env_erase_info);
		if (error) {
			printf("env free blk erase failed %d\n", error);
			mtd->block_markbad(mtd, addr);
			return error;
		}
		aml_chip->aml_nandenv_info->env_valid_node->ec++;
	}

	nand_bbt_info = &aml_chip->aml_nandenv_info->nand_bbt_info;
	if ((!memcmp(nand_bbt_info->bbt_head_magic, BBT_HEAD_MAGIC, 4)) && (!memcmp(nand_bbt_info->bbt_tail_magic, BBT_TAIL_MAGIC, 4))) {
		memcpy(env_ptr->data + default_environment_size, aml_chip->aml_nandenv_info->nand_bbt_info.bbt_head_magic, sizeof(struct aml_nand_bbt_info));
		env_crc_update ();
	}
	printf("Writing to Nand... \n");
	if (writeenv(addr, (u_char *) env_ptr)) {
		printf("FAILED!\n");
		return 1;
	}

	printf("Successful!\n");	
	return error;
}
Beispiel #9
0
int saveenv(void)
{
	env_t	env_new;
	ssize_t	len;
	char	*saved_data = NULL;
	char	*res;
	int	rc = 1;
	char	flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
	ulong	up_data = 0;
#endif

	debug("Protect off %08lX ... %08lX\n",
		(ulong)flash_addr, end_addr);

	if (flash_sect_protect(0, (ulong)flash_addr, end_addr)) {
		goto done;
	}

	debug("Protect off %08lX ... %08lX\n",
		(ulong)flash_addr_new, end_addr_new);

	if (flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new)) {
		goto done;
	}

	res = (char *)&env_new.data;
	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
	if (len < 0) {
		error("Cannot export environment: errno = %d\n", errno);
		goto done;
	}
	env_new.crc   = crc32(0, env_new.data, ENV_SIZE);
	env_new.flags = new_flag;

	env_crc_update();

#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
	up_data = (end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE));
	debug("Data to save 0x%lX\n", up_data);
	if (up_data) {
		if ((saved_data = malloc(up_data)) == NULL) {
			printf("Unable to save the rest of sector (%ld)\n",
				up_data);
			goto done;
		}
		memcpy(saved_data,
			(void *)((long)flash_addr_new + CONFIG_ENV_SIZE), up_data);
		debug("Data (start 0x%lX, len 0x%lX) saved at 0x%p\n",
			(long)flash_addr_new + CONFIG_ENV_SIZE,
			up_data, saved_data);
	}
#endif
	puts("Erasing Flash...");
	debug(" %08lX ... %08lX ...",
		(ulong)flash_addr_new, end_addr_new);

	if (flash_sect_erase((ulong)flash_addr_new, end_addr_new)) {
		goto done;
	}

	puts("Writing to Flash... ");
	debug(" %08lX ... %08lX ...",
		(ulong)&(flash_addr_new->data),
		sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
	if ((rc = flash_write((char *)&env_new,
			(ulong)flash_addr_new,
			sizeof(env_new))) ||
	    (rc = flash_write(&flag,
			(ulong)&(flash_addr->flags),
			sizeof(flash_addr->flags))) ) {
		flash_perror(rc);
		goto done;
	}

#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
	if (up_data) { /* restore the rest of sector */
		debug("Restoring the rest of data to 0x%lX len 0x%lX\n",
			(long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
		if (flash_write(saved_data,
				(long)flash_addr_new + CONFIG_ENV_SIZE,
				up_data)) {
			flash_perror(rc);
			goto done;
		}
	}
#endif
	puts("done\n");

	{
		env_t * etmp = flash_addr;
		ulong ltmp = end_addr;

		flash_addr = flash_addr_new;
		flash_addr_new = etmp;

		end_addr = end_addr_new;
		end_addr_new = ltmp;
	}

	rc = 0;
done:
	if (saved_data)
		free(saved_data);
	/* try to re-protect */
	(void) flash_sect_protect(1, (ulong)flash_addr, end_addr);
	(void) flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);

	return rc;
}