1/*
2 * NVRAM variable manipulation (Linux kernel half)
3 *
4 * Copyright 2006, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id: nvram_linux.c,v 1.1.1.1 2008/10/15 03:26:06 james26_jang Exp $
13 */
14
15#include <linux/config.h>
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/string.h>
20#include <linux/interrupt.h>
21#include <linux/spinlock.h>
22#include <linux/slab.h>
23#include <linux/bootmem.h>
24#include <linux/wrapper.h>
25#include <linux/fs.h>
26#include <linux/miscdevice.h>
27#include <linux/mtd/mtd.h>
28#include <asm/addrspace.h>
29#include <asm/io.h>
30#include <asm/uaccess.h>
31
32#include <typedefs.h>
33#include <bcmendian.h>
34#include <bcmnvram.h>
35#include <bcmutils.h>
36#include <bcmdefs.h>
37#include <sbconfig.h>
38#include <sbchipc.h>
39#include <sbutils.h>
40#include <hndmips.h>
41#include <sflash.h>
42
43/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
44static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
45
46
47#define CFE_UPDATE 1 // added by Chen-I for mac/regulation update
48#ifdef CFE_UPDATE
49#include <sbextif.h>
50
51extern void bcm947xx_watchdog_disable(void);
52
53#define CFE_SPACE       256*1024
54#define CFE_NVRAM_START 0x00000
55#define CFE_NVRAM_END   0x01fff
56#define CFE_NVRAM_SPACE 64*1024
57static struct mtd_info *cfe_mtd = NULL;
58static char *CFE_NVRAM_PREFIX="asuscfe";
59static char *CFE_NVRAM_COMMIT="asuscfecommit";
60static char *CFE_NVRAM_WATCHDOG="asuscfewatchdog";
61char *cfe_buf;// = NULL;
62struct nvram_header *cfe_nvram_header; // = NULL;
63#endif
64
65
66#ifdef MODULE
67
68#define early_nvram_get(name) nvram_get(name)
69
70#else /* !MODULE */
71
72/* Global SB handle */
73extern void *bcm947xx_sbh;
74extern spinlock_t bcm947xx_sbh_lock;
75
76/* Convenience */
77#define sbh bcm947xx_sbh
78#define sbh_lock bcm947xx_sbh_lock
79#define KB * 1024
80#define MB * 1024 * 1024
81
82#define NLS_XFR 1		/* added by Jiahao for WL500gP */
83#ifdef NLS_XFR
84
85#include <linux/nls.h>
86
87static char *NLS_NVRAM_U2C="asusnlsu2c";
88static char *NLS_NVRAM_C2U="asusnlsc2u";
89__u16 unibuf[1024];
90char codebuf[1024];
91char tmpbuf[1024];
92
93void
94asusnls_u2c(const char *name)
95{
96        char *codepage;
97        char *xfrstr;
98        struct nls_table *nls;
99        int ret, len;
100
101        strcpy(codebuf, name);
102        codepage=codebuf+strlen(NLS_NVRAM_U2C);
103        if((xfrstr=strchr(codepage, '_')))
104        {
105                *xfrstr=NULL;
106                xfrstr++;
107                /* debug message, start */
108/*
109                printk("%s, xfr from utf8 to %s\n", xfrstr, codepage);
110                int j;
111                printk("utf8:    %d, ", strlen(xfrstr));
112                for(j=0;j<strlen(xfrstr);j++)
113                        printk("%X ", (unsigned char)xfrstr[j]);
114                printk("\n");
115*/
116                /* debug message, end */
117                nls=load_nls(codepage);
118                if(!nls)
119                {
120                        printk("NLS table is null!!\n");
121                } else {
122                        if (ret=utf8_mbstowcs(unibuf, xfrstr, strlen(xfrstr)))
123                        {
124                                int i;
125                                len = 0;
126                                for (i = 0; (i < ret) && unibuf[i]; i++) {
127                                        int charlen;
128                                        charlen = nls->uni2char(unibuf[i], &name[len], NLS_MAX_CHARSET_SIZE);
129                                        if (charlen > 0) {
130                                                len += charlen;
131                                        } else {
132//                                              name[len++] = '?';
133                                                strcpy(name, "");
134                                                unload_nls(nls);
135                                                return;
136                                        }
137                                }
138                                name[len] = 0;
139                        }
140                        unload_nls(nls);
141                        /* debug message, start */
142/*
143                        int i;
144                        printk("unicode: %d, ", ret);
145                        for (i=0;i<ret;i++)
146                                printk("%X ", unibuf[i]);
147                        printk("\n");
148                        printk("local:   %d, ", strlen(name));
149                        for (i=0;i<strlen(name);i++)
150                                printk("%X ", (unsigned char)name[i]);
151                        printk("\n");
152                        printk("local:   %s\n", name);
153*/
154                        /* debug message, end */
155                        if(!len)
156                        {
157                                printk("can not xfr from utf8 to %s\n", codepage);
158                                strcpy(name, "");
159                        }
160                }
161        }
162        else
163        {
164                strcpy(name, "");
165        }
166}
167
168void
169asusnls_c2u(const char *name)
170{
171        char *codepage;
172        char *xfrstr;
173        struct nls_table *nls;
174        int ret;
175
176        strcpy(codebuf, name);
177        codepage=codebuf+strlen(NLS_NVRAM_C2U);
178        if((xfrstr=strchr(codepage, '_')))
179        {
180                *xfrstr=NULL;
181                xfrstr++;
182
183                /* debug message, start */
184/*
185                printk("%s, xfr from %s to utf8\n", xfrstr, codepage);
186                printk("local:   %d, ", strlen(xfrstr));
187                int j;
188                for (j=0;j<strlen(xfrstr);j++)
189                        printk("%X ", (unsigned char)xfrstr[j]);
190                printk("\n");
191                printk("local:   %s\n", xfrstr);
192*/
193                /* debug message, end */
194
195                strcpy(name, "");
196                nls=load_nls(codepage);
197                if(!nls)
198                {
199                        printk("NLS table is null!!\n");
200                } else
201                {
202                        int charlen;
203                        int i;
204                        int len = strlen(xfrstr);
205                        for (i = 0; len && *xfrstr; i++, xfrstr += charlen, len -= charlen) {   /* string to unicode */
206                                charlen = nls->char2uni(xfrstr, len, &unibuf[i]);
207                                if (charlen < 1) {
208//                                      unibuf[i] = 0x003f;     /* a question mark */
209//                                      charlen = 1;
210                                        strcpy(name ,"");
211                                        unload_nls(nls);
212                                        return;
213                                }
214                        }
215                        unibuf[i] = 0;
216                        ret=utf8_wcstombs(name, unibuf, 1024);  /* unicode to utf-8, 1024 is size of array unibuf */
217                        name[ret]=NULL;
218                        unload_nls(nls);
219                        /* debug message, start */
220/*
221                        int k;
222                        printk("unicode: %d, ", i);
223                        for(k=0;k<i;k++)
224                                printk("%X ", unibuf[k]);
225                        printk("\n");
226                        printk("utf-8:    %s, %d, ", name, strlen(name));
227                        for (i=0;i<strlen(name);i++)
228                                printk("%X ", (unsigned char)name[i]);
229                        printk("\n");
230*/
231                        /* debug message, end */
232                        if(!ret)
233                        {
234                                printk("can not xfr from %s to utf8\n", codepage);
235                                strcpy(name, "");
236                        }
237                }
238        }
239        else
240        {
241                strcpy(name, "");
242        }
243}
244
245#endif
246
247
248/* Probe for NVRAM header */
249static void __init
250early_nvram_init(void)
251{
252	struct nvram_header *header;
253	chipcregs_t *cc;
254	struct sflash *info = NULL;
255	int i;
256	uint32 base, off, lim;
257	u32 *src, *dst;
258
259	if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
260		base = KSEG1ADDR(SB_FLASH2);
261		switch (readl(&cc->capabilities) & CC_CAP_FLASH_MASK) {
262		case PFLASH:
263			lim = SB_FLASH2_SZ;
264			break;
265
266		case SFLASH_ST:
267		case SFLASH_AT:
268			if ((info = sflash_init(sbh, cc)) == NULL)
269				return;
270			lim = info->size;
271			break;
272
273		case FLASH_NONE:
274		default:
275			return;
276		}
277	} else {
278		/* extif assumed, Stop at 4 MB */
279		base = KSEG1ADDR(SB_FLASH1);
280		lim = SB_FLASH1_SZ;
281	}
282
283	off = FLASH_MIN;
284	while (off <= lim) {
285		/* Windowed flash access */
286		header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
287		if (header->magic == NVRAM_MAGIC)
288			if (nvram_calc_crc(header) == (uint8) header->crc_ver_init) {
289				goto found;
290			}
291		off <<= 1;
292	}
293
294	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
295	header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
296	if (header->magic == NVRAM_MAGIC)
297		if (nvram_calc_crc(header) == (uint8) header->crc_ver_init) {
298			goto found;
299		}
300
301	header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
302	if (header->magic == NVRAM_MAGIC)
303		if (nvram_calc_crc(header) == (uint8) header->crc_ver_init) {
304			goto found;
305		}
306
307	printk("early_nvram_init: NVRAM not found\n");
308	return;
309
310found:
311	src = (u32 *) header;
312	dst = (u32 *) nvram_buf;
313	for (i = 0; i < sizeof(struct nvram_header); i += 4)
314		*dst++ = *src++;
315	for (; i < header->len && i < NVRAM_SPACE; i += 4)
316		*dst++ = ltoh32(*src++);
317}
318
319/* Early (before mm or mtd) read-only access to NVRAM */
320static char * __init
321early_nvram_get(const char *name)
322{
323	char *var, *value, *end, *eq;
324
325	if (!name)
326		return NULL;
327
328	/* Too early? */
329	if (sbh == NULL)
330		return NULL;
331
332	if (!nvram_buf[0])
333		early_nvram_init();
334
335	/* Look for name=value and return value */
336	var = &nvram_buf[sizeof(struct nvram_header)];
337	end = nvram_buf + sizeof(nvram_buf) - 2;
338	end[0] = end[1] = '\0';
339	for (; *var; var = value + strlen(value) + 1) {
340		if (!(eq = strchr(var, '=')))
341			break;
342		value = eq + 1;
343		if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
344			return value;
345	}
346
347	return NULL;
348}
349
350static int __init
351early_nvram_getall(char *buf, int count)
352{
353	char *var, *end;
354	int len = 0;
355
356	/* Too early? */
357	if (sbh == NULL)
358		return -1;
359
360	if (!nvram_buf[0])
361		early_nvram_init();
362
363	bzero(buf, count);
364
365	/* Write name=value\0 ... \0\0 */
366	var = &nvram_buf[sizeof(struct nvram_header)];
367	end = nvram_buf + sizeof(nvram_buf) - 2;
368	end[0] = end[1] = '\0';
369	for (; *var; var += strlen(var) + 1) {
370		if ((count - len) <= (strlen(var) + 1))
371			break;
372		len += sprintf(buf + len, "%s", var) + 1;
373	}
374
375	return 0;
376}
377#endif /* !MODULE */
378
379extern char * _nvram_get(const char *name);
380extern int _nvram_set(const char *name, const char *value);
381extern int _nvram_unset(const char *name);
382extern int _nvram_getall(char *buf, int count);
383extern int _nvram_commit(struct nvram_header *header);
384extern int _nvram_init(void *sbh);
385extern void _nvram_exit(void);
386
387/* Globals */
388static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
389static struct semaphore nvram_sem;
390static unsigned long nvram_offset = 0;
391static int nvram_major = -1;
392static devfs_handle_t nvram_handle = NULL;
393static struct mtd_info *nvram_mtd = NULL;
394
395int
396_nvram_read(char *buf)
397{
398	struct nvram_header *header = (struct nvram_header *) buf;
399	size_t len;
400
401	if (!nvram_mtd ||
402	    MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) ||
403	    len != NVRAM_SPACE ||
404	    header->magic != NVRAM_MAGIC) {
405		/* Maybe we can recover some data from early initialization */
406		memcpy(buf, nvram_buf, NVRAM_SPACE);
407	}
408
409	return 0;
410}
411
412struct nvram_tuple *
413_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
414{
415	if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
416		return NULL;
417
418	if (!t) {
419		if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
420			return NULL;
421
422		/* Copy name */
423		t->name = (char *) &t[1];
424		strcpy(t->name, name);
425
426		t->value = NULL;
427	}
428
429	/* Copy value */
430	if (!t->value || strcmp(t->value, value)) {
431		t->value = &nvram_buf[nvram_offset];
432		strcpy(t->value, value);
433		nvram_offset += strlen(value) + 1;
434	}
435
436	return t;
437}
438
439void
440_nvram_free(struct nvram_tuple *t)
441{
442	if (!t)
443		nvram_offset = 0;
444	else
445		kfree(t);
446}
447
448int
449nvram_init(void *sbh)
450{
451	return 0;
452}
453
454int
455nvram_set(const char *name, const char *value)
456{
457	unsigned long flags;
458	int ret;
459	struct nvram_header *header;
460
461	spin_lock_irqsave(&nvram_lock, flags);
462#ifdef CFE_UPDATE //write back to default sector as well, Chen-I
463        if(strncmp(name, CFE_NVRAM_PREFIX, strlen(CFE_NVRAM_PREFIX))==0)
464        {
465                if(strcmp(name, CFE_NVRAM_COMMIT)==0)
466                        cfe_commit();
467                else if(strcmp(name, CFE_NVRAM_WATCHDOG)==0)
468                {
469                        bcm947xx_watchdog_disable();
470                }
471                else
472                {
473                        cfe_update(name+strlen(CFE_NVRAM_PREFIX), value);
474                        _nvram_set(name+strlen(CFE_NVRAM_PREFIX), value);
475                }
476        }
477        else
478#endif
479
480	if ((ret = _nvram_set(name, value))) {
481		/* Consolidate space and try again */
482		if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
483			if (_nvram_commit(header) == 0)
484				ret = _nvram_set(name, value);
485			kfree(header);
486		}
487	}
488	spin_unlock_irqrestore(&nvram_lock, flags);
489
490	return ret;
491}
492
493char *
494real_nvram_get(const char *name)
495{
496	unsigned long flags;
497	char *value;
498
499	spin_lock_irqsave(&nvram_lock, flags);
500	value = _nvram_get(name);
501	spin_unlock_irqrestore(&nvram_lock, flags);
502
503	return value;
504}
505
506char *
507nvram_get(const char *name)
508{
509	if (nvram_major >= 0)
510		return real_nvram_get(name);
511	else
512		return early_nvram_get(name);
513}
514
515int
516nvram_unset(const char *name)
517{
518	unsigned long flags;
519	int ret;
520
521	spin_lock_irqsave(&nvram_lock, flags);
522	ret = _nvram_unset(name);
523	spin_unlock_irqrestore(&nvram_lock, flags);
524
525	return ret;
526}
527
528static void
529erase_callback(struct erase_info *done)
530{
531	wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
532	wake_up(wait_q);
533}
534
535int
536nvram_commit(void)
537{
538	char *buf;
539	size_t erasesize, len, magic_len;
540	unsigned int i;
541	int ret;
542	struct nvram_header *header;
543	unsigned long flags;
544	u_int32_t offset;
545	DECLARE_WAITQUEUE(wait, current);
546	wait_queue_head_t wait_q;
547	struct erase_info erase;
548	u_int32_t magic_offset = 0; /* Offset for writing MAGIC # */
549
550	if (!nvram_mtd) {
551		printk("nvram_commit: NVRAM not found\n");
552		return -ENODEV;
553	}
554
555	if (in_interrupt()) {
556		printk("nvram_commit: not committing in interrupt\n");
557		return -EINVAL;
558	}
559
560	/* Backup sector blocks to be erased */
561	erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize);
562	if (!(buf = kmalloc(erasesize, GFP_KERNEL))) {
563		printk("nvram_commit: out of memory\n");
564		return -ENOMEM;
565	}
566
567	down(&nvram_sem);
568
569	if ((i = erasesize - NVRAM_SPACE) > 0) {
570		offset = nvram_mtd->size - erasesize;
571		len = 0;
572		ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
573		if (ret || len != i) {
574			printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
575			ret = -EIO;
576			goto done;
577		}
578		header = (struct nvram_header *)(buf + i);
579		magic_offset = i + ((void *)&header->magic - (void *)header);
580	} else {
581		offset = nvram_mtd->size - NVRAM_SPACE;
582		magic_offset = ((void *)&header->magic - (void *)header);
583		header = (struct nvram_header *)buf;
584	}
585
586	/* clear the existing magic # to mark the NVRAM as unusable
587	 * we can pull MAGIC bits low without erase
588	 */
589	header->magic = NVRAM_CLEAR_MAGIC; /* All zeros magic */
590	/* Unlock sector blocks */
591	if (nvram_mtd->unlock)
592		nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
593	ret = MTD_WRITE(nvram_mtd, offset + magic_offset, sizeof(header->magic),
594		&magic_len, (char *)&header->magic);
595	if (ret || magic_len != sizeof(header->magic)) {
596		printk("nvram_commit: clear MAGIC error\n");
597		ret = -EIO;
598		goto done;
599	}
600
601	header->magic = NVRAM_MAGIC;
602	/* reset MAGIC before we regenerate the NVRAM,
603	 * otherwise we'll have an incorrect CRC
604	 */
605	/* Regenerate NVRAM */
606	spin_lock_irqsave(&nvram_lock, flags);
607	ret = _nvram_commit(header);
608	spin_unlock_irqrestore(&nvram_lock, flags);
609	if (ret)
610		goto done;
611
612	/* Erase sector blocks */
613	init_waitqueue_head(&wait_q);
614	for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len;
615		offset += nvram_mtd->erasesize) {
616
617		erase.mtd = nvram_mtd;
618		erase.addr = offset;
619		erase.len = nvram_mtd->erasesize;
620		erase.callback = erase_callback;
621		erase.priv = (u_long) &wait_q;
622
623		set_current_state(TASK_INTERRUPTIBLE);
624		add_wait_queue(&wait_q, &wait);
625
626		/* Unlock sector blocks */
627		if (nvram_mtd->unlock)
628			nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
629
630		if ((ret = MTD_ERASE(nvram_mtd, &erase))) {
631			set_current_state(TASK_RUNNING);
632			remove_wait_queue(&wait_q, &wait);
633			printk("nvram_commit: erase error\n");
634			goto done;
635		}
636
637		/* Wait for erase to finish */
638		schedule();
639		remove_wait_queue(&wait_q, &wait);
640	}
641
642	/* Write partition up to end of data area */
643	header->magic = NVRAM_INVALID_MAGIC; /* All ones magic */
644	offset = nvram_mtd->size - erasesize;
645	i = erasesize - NVRAM_SPACE + header->len;
646	ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf);
647	if (ret || len != i) {
648		printk("nvram_commit: write error\n");
649		ret = -EIO;
650		goto done;
651	}
652
653	/* Now mark the NVRAM in flash as "valid" by setting the correct
654	 * MAGIC #
655	 */
656	header->magic = NVRAM_MAGIC;
657	ret = MTD_WRITE(nvram_mtd, offset + magic_offset, sizeof(header->magic),
658		&magic_len, (char *)&header->magic);
659	if (ret || magic_len != sizeof(header->magic)) {
660		printk("nvram_commit: write MAGIC error\n");
661		ret = -EIO;
662		goto done;
663	}
664
665	offset = nvram_mtd->size - erasesize;
666	ret = MTD_READ(nvram_mtd, offset, 4, &len, buf);
667
668done:
669	up(&nvram_sem);
670	kfree(buf);
671	return ret;
672}
673
674int
675nvram_getall(char *buf, int count)
676{
677	unsigned long flags;
678	int ret;
679
680	spin_lock_irqsave(&nvram_lock, flags);
681	if (nvram_major >= 0)
682		ret = _nvram_getall(buf, count);
683	else
684		ret = early_nvram_getall(buf, count);
685	spin_unlock_irqrestore(&nvram_lock, flags);
686
687	return ret;
688}
689
690EXPORT_SYMBOL(nvram_get);
691EXPORT_SYMBOL(nvram_getall);
692EXPORT_SYMBOL(nvram_set);
693EXPORT_SYMBOL(nvram_unset);
694EXPORT_SYMBOL(nvram_commit);
695
696/* User mode interface below */
697
698static ssize_t
699dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
700{
701	char tmp[100], *name = tmp, *value;
702	ssize_t ret;
703	unsigned long off;
704
705	if (count > sizeof(tmp)) {
706		if (!(name = kmalloc(count, GFP_KERNEL)))
707			return -ENOMEM;
708	}
709
710	if (copy_from_user(name, buf, count)) {
711		ret = -EFAULT;
712		goto done;
713	}
714
715	if (*name == '\0') {
716		/* Get all variables */
717		ret = nvram_getall(name, count);
718		if (ret == 0) {
719			if (copy_to_user(buf, name, count)) {
720				ret = -EFAULT;
721				goto done;
722			}
723			ret = count;
724		}
725	} else {
726		if (!(value = nvram_get(name))) {
727			ret = 0;
728			goto done;
729		}
730
731		/* Provide the offset into mmap() space */
732		off = (unsigned long) value - (unsigned long) nvram_buf;
733
734		if (put_user(off, (unsigned long *) buf)) {
735			ret = -EFAULT;
736			goto done;
737		}
738
739		ret = sizeof(unsigned long);
740	}
741
742	flush_cache_all();
743
744done:
745	if (name != tmp)
746		kfree(name);
747
748	return ret;
749}
750
751static ssize_t
752dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
753{
754	char tmp[100], *name = tmp, *value;
755	ssize_t ret;
756
757	if (count > sizeof(tmp)) {
758		if (!(name = kmalloc(count, GFP_KERNEL)))
759			return -ENOMEM;
760	}
761
762	if (copy_from_user(name, buf, count)) {
763		ret = -EFAULT;
764		goto done;
765	}
766
767	value = name;
768	name = strsep(&value, "=");
769	if (value)
770		ret = nvram_set(name, value) ? : count;
771	else
772		ret = nvram_unset(name) ? : count;
773
774done:
775	if (name != tmp)
776		kfree(name);
777
778	return ret;
779}
780
781/* Jiahao */
782static int
783nvram_xfr(char *buf)
784{
785        char *name = tmpbuf;
786        ssize_t ret=0;
787
788//      printk("nvram xfr 1: %s\n", buf);
789        if (copy_from_user(name, buf, strlen(buf)+1)) {
790                ret = -EFAULT;
791                goto done;
792        }
793
794        if (strncmp(tmpbuf, NLS_NVRAM_U2C, strlen(NLS_NVRAM_U2C))==0)
795        {
796                asusnls_u2c(tmpbuf);
797        }
798        else if (strncmp(buf, NLS_NVRAM_C2U, strlen(NLS_NVRAM_C2U))==0)
799        {
800                asusnls_c2u(tmpbuf);
801        }
802        else
803        {
804                strcpy(tmpbuf, "");
805//              printk("nvram xfr 2: %s\n", tmpbuf);
806        }
807
808        if (copy_to_user(buf, tmpbuf, strlen(tmpbuf)+1))
809        {
810                ret = -EFAULT;
811                goto done;
812        }
813//      printk("nvram xfr 3: %s\n", tmpbuf);
814
815done:
816        return ret;
817}
818
819
820static int
821dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
822{
823	if (cmd != NVRAM_MAGIC)
824		return -EINVAL;
825
826//	return nvram_commit();
827/* Jiahao */
828        if(arg==0)
829                return nvram_commit();
830        else return nvram_xfr((char *)arg);
831
832}
833
834static int
835dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
836{
837	unsigned long offset = virt_to_phys(nvram_buf);
838
839	if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
840		vma->vm_page_prot))
841		return -EAGAIN;
842
843	return 0;
844}
845
846static int
847dev_nvram_open(struct inode *inode, struct file * file)
848{
849	MOD_INC_USE_COUNT;
850	return 0;
851}
852
853static int
854dev_nvram_release(struct inode *inode, struct file * file)
855{
856	MOD_DEC_USE_COUNT;
857	return 0;
858}
859
860static struct file_operations dev_nvram_fops = {
861	owner:		THIS_MODULE,
862	open:		dev_nvram_open,
863	release:	dev_nvram_release,
864	read:		dev_nvram_read,
865	write:		dev_nvram_write,
866	ioctl:		dev_nvram_ioctl,
867	mmap:		dev_nvram_mmap,
868};
869
870static void
871dev_nvram_exit(void)
872{
873	int order = 0;
874	struct page *page, *end;
875
876	if (nvram_handle)
877		devfs_unregister(nvram_handle);
878
879	if (nvram_major >= 0)
880		devfs_unregister_chrdev(nvram_major, "nvram");
881
882	if (nvram_mtd)
883		put_mtd_device(nvram_mtd);
884
885	while ((PAGE_SIZE << order) < NVRAM_SPACE)
886		order++;
887	end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
888	for (page = virt_to_page(nvram_buf); page <= end; page++)
889		mem_map_unreserve(page);
890
891	_nvram_exit();
892}
893
894static int __init
895dev_nvram_init(void)
896{
897	int order = 0, ret = 0;
898	struct page *page, *end;
899	unsigned int i;
900	osl_t *osh;
901
902	/* Allocate and reserve memory to mmap() */
903	while ((PAGE_SIZE << order) < NVRAM_SPACE)
904		order++;
905	end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
906	for (page = virt_to_page(nvram_buf); page <= end; page++)
907		mem_map_reserve(page);
908
909#ifdef CONFIG_MTD
910	/* Find associated MTD device */
911	for (i = 0; i < MAX_MTD_DEVICES; i++) {
912		nvram_mtd = get_mtd_device(NULL, i);
913		if (nvram_mtd) {
914			if (!strcmp(nvram_mtd->name, "nvram") &&
915			    nvram_mtd->size >= NVRAM_SPACE)
916				break;
917			put_mtd_device(nvram_mtd);
918		}
919	}
920	if (i >= MAX_MTD_DEVICES)
921		nvram_mtd = NULL;
922#endif
923
924	/* Initialize hash table lock */
925	spin_lock_init(&nvram_lock);
926
927	/* Initialize commit semaphore */
928	init_MUTEX(&nvram_sem);
929
930	/* Register char device */
931	if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
932		ret = nvram_major;
933		goto err;
934	}
935
936	if (sb_osh(sbh) == NULL) {
937		osh = osl_attach(NULL, SB_BUS, FALSE);
938		if (osh == NULL) {
939			printk("Error allocating osh\n");
940			goto err;
941		}
942		sb_setosh(sbh, osh);
943	}
944
945	/* Initialize hash table */
946	_nvram_init(sbh);
947
948	/* Create /dev/nvram handle */
949	nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0,
950		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL);
951
952	/* Set the SDRAM NCDL value into NVRAM if not already done */
953	if (getintvar(NULL, "sdram_ncdl") == 0) {
954		unsigned int ncdl;
955		char buf[] = "0x00000000";
956
957		if ((ncdl = sb_memc_get_ncdl(sbh))) {
958			sprintf(buf, "0x%08x", ncdl);
959			nvram_set("sdram_ncdl", buf);
960			nvram_commit();
961		}
962	}
963
964	return 0;
965
966err:
967	dev_nvram_exit();
968	return ret;
969}
970
971#ifdef CFE_UPDATE
972void cfe_init(void)
973{
974        size_t erasesize, len;
975        int i;
976
977        /* Find associated MTD device */
978        for (i = 0; i < MAX_MTD_DEVICES; i++) {
979                cfe_mtd = get_mtd_device(NULL, i);
980                if (cfe_mtd) {
981                        printk("CFE MTD: %x %s %x\n", i, cfe_mtd->name, cfe_mtd->size);
982                        if (!strcmp(cfe_mtd->name, "boot"))
983                                break;
984                        put_mtd_device(cfe_mtd);
985                }
986        }
987        if (i >= MAX_MTD_DEVICES)
988        {
989                printk("No CFE MTD\n");
990                cfe_mtd = NULL;
991        }
992
993        if(!cfe_mtd) goto fail;
994
995        /* sector blocks to be erased and backup */
996        erasesize = ROUNDUP(CFE_NVRAM_SPACE, cfe_mtd->erasesize);
997
998        //printk("block size %d\n", erasesize);
999
1000        cfe_buf = kmalloc(erasesize, GFP_KERNEL);
1001
1002        if(!cfe_buf)
1003        {
1004                //printk("No CFE Memory\n");
1005                goto fail;
1006        }
1007        MTD_READ(cfe_mtd, CFE_NVRAM_START, erasesize, &len, cfe_buf);
1008
1009        // find nvram header
1010        for(i=0;i<len;i+=4)
1011        {
1012                cfe_nvram_header=(struct nvram_header *)&cfe_buf[i];
1013                if (cfe_nvram_header->magic==NVRAM_MAGIC) break;
1014        }
1015
1016        bcm947xx_watchdog_disable(); //disable watchdog as well
1017
1018        //printf("read from nvram %d %s\n", i, cfe_buf);
1019        //for(i=0;i<CFE_SPACE;i++)
1020        //{
1021        //      if(i%16) printk("\n");
1022        //      printk("%02x ", (unsigned char)cfe_buf[i]);
1023        //}
1024        return;
1025fail:
1026        if (cfe_mtd)
1027        {
1028                put_mtd_device(cfe_mtd);
1029                cfe_mtd=NULL;
1030        }
1031        if(cfe_buf)
1032        {
1033                kfree(cfe_buf);
1034                cfe_buf=NULL;
1035        }
1036        return;
1037}
1038
1039void cfe_update(char *keyword, char *value)
1040{
1041        unsigned long i, offset;
1042        struct nvram_header tmp, *header;
1043        uint8 crc;
1044        int ret;
1045        int found = 0;
1046
1047        if(!cfe_buf||!cfe_mtd)
1048                cfe_init();
1049
1050        if (!cfe_buf||!cfe_mtd) return;
1051
1052        header = cfe_nvram_header;
1053
1054        //printk("before: %x %x\n", header->len,  cfe_nvram_header->crc_ver_init&0xff);
1055
1056        for(i=CFE_NVRAM_START;i<=CFE_NVRAM_END;i++)
1057        {
1058                if(strncmp(&cfe_buf[i], keyword, strlen(keyword))==0)
1059                {
1060                        //printk("before: %s\n", cfe_buf+i);
1061                        offset=strlen(keyword);
1062                        memcpy(cfe_buf+i+offset+1, value, strlen(value));
1063                        //printk("after: %s\n", cfe_buf+i);
1064                        found = 1;
1065                }
1066        }
1067
1068        if(!found)
1069        {
1070                char *tmp_buf = (char *)cfe_nvram_header;
1071
1072                //printk("header len: %x\n", header->len);
1073                sprintf(tmp_buf+header->len, "%s=%s", keyword, value);
1074                header->len = header->len + strlen(keyword) + strlen(value) + 2;
1075                //printk("header len: %x\n", header->len);
1076        }
1077
1078        tmp.crc_ver_init = htol32(header->crc_ver_init);
1079        tmp.config_refresh = htol32(header->config_refresh);
1080        tmp.config_ncdl = htol32(header->config_ncdl);
1081        crc = hndcrc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
1082
1083        /* Continue CRC8 over data bytes */
1084        crc = hndcrc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
1085        header->crc_ver_init = (header->crc_ver_init&0xFFFFFF00)|crc;
1086        //printk("after: %x %x\n", header->crc_ver_init&0xFF, crc);
1087}
1088
1089int cfe_commit(void)
1090{
1091        DECLARE_WAITQUEUE(wait, current);
1092        wait_queue_head_t wait_q;
1093        struct erase_info erase;
1094        unsigned int i;
1095        int ret;
1096        size_t erasesize, len;
1097        u_int32_t offset;
1098        char *buf;
1099
1100        if(!cfe_buf||!cfe_mtd) cfe_init();
1101
1102        if(!cfe_mtd||!cfe_buf)
1103        {
1104                ret = - ENOMEM;
1105                goto done;
1106        }
1107
1108        /* Backup sector blocks to be erased */
1109        erasesize = ROUNDUP(CFE_NVRAM_SPACE, cfe_mtd->erasesize);
1110
1111        /* Erase sector blocks */
1112        init_waitqueue_head(&wait_q);
1113        for (offset=CFE_NVRAM_START;offset <= CFE_NVRAM_END;offset += cfe_mtd->erasesize) {
1114           erase.mtd = cfe_mtd;
1115           erase.addr = offset;
1116           erase.len = cfe_mtd->erasesize;
1117           erase.callback = erase_callback;
1118           erase.priv = (u_long) &wait_q;
1119
1120           set_current_state(TASK_INTERRUPTIBLE);
1121           add_wait_queue(&wait_q, &wait);
1122           /* Unlock sector blocks */
1123           if (cfe_mtd->unlock)
1124                   cfe_mtd->unlock(cfe_mtd, offset, cfe_mtd->erasesize);
1125
1126           if ((ret = MTD_ERASE(cfe_mtd, &erase))) {
1127                set_current_state(TASK_RUNNING);
1128                remove_wait_queue(&wait_q, &wait);
1129                printk("cfe_commit: erase error\n");
1130                goto done;
1131           }
1132
1133           /* Wait for erase to finish */
1134           schedule();
1135           remove_wait_queue(&wait_q, &wait);
1136        }
1137
1138        ret = MTD_WRITE(cfe_mtd, CFE_NVRAM_START, erasesize, &len, cfe_buf);
1139        //printk("Write offset: %x %x %x\n", ret, len, erasesize);
1140
1141        if (ret || len != erasesize) {
1142           printk("cfe_commit: write error\n");
1143           ret = -EIO;
1144        }
1145
1146done:
1147        if (cfe_mtd)
1148        {
1149                put_mtd_device(cfe_mtd);
1150                cfe_mtd=NULL;
1151        }
1152        if(cfe_buf)
1153        {
1154                kfree(cfe_buf);
1155                cfe_buf=NULL;
1156        }
1157        //printk("commit: %d\n", ret);
1158        return ret;
1159
1160}
1161#endif
1162
1163
1164module_init(dev_nvram_init);
1165module_exit(dev_nvram_exit);
1166