Broadcom SDK and wireless driver: another attempt to update to ver. 5.10.147.0
[tomato.git] / release / src-rt / linux / linux-2.6 / arch / mips / brcm-boards / bcm947xx / nvram_linux.c
bloba64ccfd4de00ac2b1633e6b60d548d636f9ba0ca
1 /*
2 * NVRAM variable manipulation (Linux kernel half)
4 * All Rights Reserved.
5 *
6 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
7 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
8 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
9 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 * $Id: nvram_linux.c,v 1.8 2008/07/04 01:15:09 Exp $
14 #include <linux/config.h>
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/string.h>
19 #include <linux/interrupt.h>
20 #include <linux/spinlock.h>
21 #include <linux/slab.h>
22 #include <linux/bootmem.h>
23 #include <linux/fs.h>
24 #include <linux/miscdevice.h>
25 #include <linux/mtd/mtd.h>
26 //#include <mtd/mtd-user.h>
27 #include <asm/addrspace.h>
28 #include <asm/io.h>
29 #include <asm/uaccess.h>
30 #include <asm/cacheflush.h>
32 #include <typedefs.h>
33 #include <bcmendian.h>
34 #include <bcmnvram.h>
35 #include <bcmutils.h>
36 #include <bcmdefs.h>
37 #include <hndsoc.h>
38 #include <siutils.h>
39 #include <hndmips.h>
40 #include <sflash.h>
42 /* In BSS to minimize text size and page aligned so it can be mmap()-ed */
43 static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
44 static char *nvram_commit_buf = NULL;
46 #define CFE_UPDATE 1 // added by Chen-I for mac/regulation update
47 #ifdef CFE_UPDATE
48 //#include <sbextif.h>
50 extern void bcm947xx_watchdog_disable(void);
52 #define CFE_SPACE 256*1024
53 #define CFE_NVRAM_START 0x00000
54 #define CFE_NVRAM_END 0x01fff
55 #define CFE_NVRAM_SPACE 64*1024
56 static struct mtd_info *cfe_mtd = NULL;
57 static char *CFE_NVRAM_PREFIX="asuscfe";
58 static char *CFE_NVRAM_COMMIT="asuscfecommit";
59 static char *CFE_NVRAM_WATCHDOG="asuscfewatchdog";
60 char *cfe_buf;// = NULL;
61 struct nvram_header *cfe_nvram_header; // = NULL;
63 static u_int32_t cfe_offset;
64 static u_int32_t cfe_embedded_size;
65 static int get_embedded_block(struct mtd_info *mtd, char *buf, size_t erasesize,
66 u_int32_t *offset, struct nvram_header **header, u_int32_t *emb_size);
68 static int cfe_init(void);
69 static int cfe_update(const char *keyword, const char *value);
70 static int cfe_dump(void);
71 static int cfe_commit(void);
72 #endif
75 #define WPS 1
77 #ifdef MODULE
79 #define early_nvram_get(name) nvram_get(name)
81 #else /* !MODULE */
83 /* Global SB handle */
84 extern void *bcm947xx_sih;
85 extern spinlock_t bcm947xx_sih_lock;
87 /* Convenience */
88 #define sih bcm947xx_sih
89 #define sih_lock bcm947xx_sih_lock
90 #define KB * 1024
91 #define MB * 1024 * 1024
93 //#define NLS_XFR 1 /* added by Jiahao for WL500gP */
94 #ifdef NLS_XFR
96 #include <linux/nls.h>
98 static char *NLS_NVRAM_U2C="asusnlsu2c";
99 static char *NLS_NVRAM_C2U="asusnlsc2u";
100 __u16 unibuf[1024];
101 char codebuf[1024];
102 char tmpbuf[1024];
104 void
105 asusnls_u2c(char *name)
107 char *codepage;
108 char *xfrstr;
109 struct nls_table *nls;
110 int ret, len;
112 strcpy(codebuf, name);
113 codepage=codebuf+strlen(NLS_NVRAM_U2C);
114 if((xfrstr=strchr(codepage, '_')))
116 *xfrstr=NULL;
117 xfrstr++;
118 /* debug message, start */
120 printk("%s, xfr from utf8 to %s\n", xfrstr, codepage);
121 int j;
122 printk("utf8: %d, ", strlen(xfrstr));
123 for(j=0;j<strlen(xfrstr);j++)
124 printk("%X ", (unsigned char)xfrstr[j]);
125 printk("\n");
127 /* debug message, end */
129 nls=load_nls(codepage);
130 if(!nls)
132 printk("NLS table is null!!\n");
134 else {
135 len = 0;
136 if (ret=utf8_mbstowcs(unibuf, xfrstr, strlen(xfrstr)))
138 int i;
139 for (i = 0; (i < ret) && unibuf[i]; i++) {
140 int charlen;
141 charlen = nls->uni2char(unibuf[i], &name[len], NLS_MAX_CHARSET_SIZE);
142 if (charlen > 0) {
143 len += charlen;
145 else {
146 //name[len++] = '?';
147 strcpy(name, "");
148 unload_nls(nls);
149 return;
152 name[len] = 0;
154 unload_nls(nls);
155 /* debug message, start */
157 int i;
158 printk("unicode: %d, ", ret);
159 for (i=0;i<ret;i++)
160 printk("%X ", unibuf[i]);
161 printk("\n");
162 printk("local: %d, ", strlen(name));
163 for (i=0;i<strlen(name);i++)
164 printk("%X ", (unsigned char)name[i]);
165 printk("\n");
166 printk("local: %s\n", name);
168 /* debug message, end */
170 if(!len)
172 printk("can not xfr from utf8 to %s\n", codepage);
173 strcpy(name, "");
177 else
179 strcpy(name, "");
183 void
184 asusnls_c2u(char *name)
186 char *codepage;
187 char *xfrstr;
188 struct nls_table *nls;
189 int ret;
191 strcpy(codebuf, name);
192 codepage=codebuf+strlen(NLS_NVRAM_C2U);
193 if((xfrstr=strchr(codepage, '_')))
195 *xfrstr=NULL;
196 xfrstr++;
198 /* debug message, start */
200 printk("%s, xfr from %s to utf8\n", xfrstr, codepage);
201 printk("local: %d, ", strlen(xfrstr));
202 int j;
203 for (j=0;j<strlen(xfrstr);j++)
204 printk("%X ", (unsigned char)xfrstr[j]);
205 printk("\n");
206 printk("local: %s\n", xfrstr);
208 /* debug message, end */
210 strcpy(name, "");
211 nls=load_nls(codepage);
212 if(!nls)
214 printk("NLS table is null!!\n");
216 else
218 int charlen;
219 int i;
220 int len = strlen(xfrstr);
221 for (i = 0; len && *xfrstr; i++, xfrstr += charlen, len -= charlen) { /* string to unicode */
222 charlen = nls->char2uni(xfrstr, len, &unibuf[i]);
223 if (charlen < 1) {
224 //unibuf[i] = 0x003f; /* a question mark */
225 //charlen = 1;
226 strcpy(name ,"");
227 unload_nls(nls);
228 return;
231 unibuf[i] = 0;
232 ret=utf8_wcstombs(name, unibuf, 1024); /* unicode to utf-8, 1024 is size of array unibuf */
233 name[ret]=0;
234 unload_nls(nls);
235 /* debug message, start */
237 int k;
238 printk("unicode: %d, ", i);
239 for(k=0;k<i;k++)
240 printk("%X ", unibuf[k]);
241 printk("\n");
242 printk("utf-8: %s, %d, ", name, strlen(name));
243 for (i=0;i<strlen(name);i++)
244 printk("%X ", (unsigned char)name[i]);
245 printk("\n");
247 /* debug message, end */
248 if(!ret)
250 printk("can not xfr from %s to utf8\n", codepage);
251 strcpy(name, "");
255 else
257 strcpy(name, "");
261 /* Jiahao */
262 static int
263 nvram_xfr(char *buf)
265 char *name = tmpbuf;
266 ssize_t ret=0;
268 printk("nvram xfr 1: %s\n", buf);
269 if (copy_from_user(name, buf, strlen(buf)+1)) {
270 ret = -EFAULT;
271 goto done;
274 if (strncmp(tmpbuf, NLS_NVRAM_U2C, strlen(NLS_NVRAM_U2C))==0)
276 asusnls_u2c(tmpbuf);
278 else if (strncmp(buf, NLS_NVRAM_C2U, strlen(NLS_NVRAM_C2U))==0)
280 asusnls_c2u(tmpbuf);
282 else
284 strcpy(tmpbuf, "");
285 printk("nvram xfr 2: %s\n", tmpbuf);
288 if (copy_to_user(buf, tmpbuf, strlen(tmpbuf)+1))
290 ret = -EFAULT;
291 goto done;
293 printk("nvram xfr 3: %s\n", tmpbuf);
295 done:
296 return ret;
299 #endif
301 static int
302 nvram_valid(struct nvram_header *header)
304 return (header->magic == NVRAM_MAGIC) &&
305 (header->len >= sizeof(struct nvram_header)) && (header->len <= NVRAM_SPACE)
306 #if 0
307 && (nvram_calc_crc(header) == (uint8) header->crc_ver_init))
308 #endif
312 /* Probe for NVRAM header */
313 static int
314 early_nvram_init(void)
316 struct nvram_header *header;
317 chipcregs_t *cc;
318 struct sflash *info = NULL;
319 int i;
320 uint32 base, off, lim;
321 u32 *src, *dst;
323 if ((cc = si_setcore(sih, CC_CORE_ID, 0)) != NULL) {
324 base = KSEG1ADDR(SI_FLASH2);
325 switch (readl(&cc->capabilities) & CC_CAP_FLASH_MASK) {
326 case PFLASH:
327 lim = SI_FLASH2_SZ;
328 break;
330 case SFLASH_ST:
331 case SFLASH_AT:
332 if ((info = sflash_init(sih, cc)) == NULL)
333 return -1;
334 lim = info->size;
335 break;
337 case FLASH_NONE:
338 default:
339 return -1;
341 } else {
342 /* extif assumed, Stop at 4 MB */
343 base = KSEG1ADDR(SI_FLASH1);
344 lim = SI_FLASH1_SZ;
347 off = FLASH_MIN;
348 while (off <= lim) {
349 /* Windowed flash access */
350 header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
351 if (nvram_valid(header))
352 goto found;
353 off <<= 1;
356 /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
357 header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
358 if (nvram_valid(header))
359 goto found;
361 header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
362 if (nvram_valid(header))
363 goto found;
365 return -1;
367 found:
368 src = (u32 *) header;
369 dst = (u32 *) nvram_buf;
370 for (i = 0; i < sizeof(struct nvram_header); i += 4)
371 *dst++ = *src++;
372 for (; i < header->len && i < NVRAM_SPACE; i += 4)
373 *dst++ = ltoh32(*src++);
375 return 0;
378 /* Early (before mm or mtd) read-only access to NVRAM */
379 static char *
380 early_nvram_get(const char *name)
382 char *var, *value, *end, *eq;
384 if (!name)
385 return NULL;
387 /* Too early? */
388 if (sih == NULL)
389 return NULL;
391 if (!nvram_buf[0])
392 if (early_nvram_init() != 0) {
393 printk("early_nvram_get: Failed reading nvram var %s\n", name);
394 return NULL;
397 /* Look for name=value and return value */
398 var = &nvram_buf[sizeof(struct nvram_header)];
399 end = nvram_buf + sizeof(nvram_buf) - 2;
400 end[0] = end[1] = '\0';
401 for (; *var; var = value + strlen(value) + 1) {
402 if (!(eq = strchr(var, '=')))
403 break;
404 value = eq + 1;
405 if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
406 return value;
409 return NULL;
412 static int
413 early_nvram_getall(char *buf, int count)
415 char *var, *end;
416 int len = 0;
418 /* Too early? */
419 if (sih == NULL)
420 return -1;
422 if (!nvram_buf[0])
423 if (early_nvram_init() != 0) {
424 printk("early_nvram_getall: Failed reading nvram var\n");
425 return -1;
428 bzero(buf, count);
430 /* Write name=value\0 ... \0\0 */
431 var = &nvram_buf[sizeof(struct nvram_header)];
432 end = nvram_buf + sizeof(nvram_buf) - 2;
433 end[0] = end[1] = '\0';
434 for (; *var; var += strlen(var) + 1) {
435 if ((count - len) <= (strlen(var) + 1))
436 break;
437 len += sprintf(buf + len, "%s", var) + 1;
440 return 0;
442 #endif /* !MODULE */
444 extern char * _nvram_get(const char *name);
445 extern int _nvram_set(const char *name, const char *value);
446 extern int _nvram_unset(const char *name);
447 extern int _nvram_getall(char *buf, int count);
448 extern int _nvram_commit(struct nvram_header *header);
449 extern int _nvram_init(void *sih);
450 extern void _nvram_exit(void);
452 /* Globals */
453 static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
454 static struct semaphore nvram_sem;
455 static unsigned long nvram_offset = 0;
456 static int nvram_major = -1;
457 static struct class *nvram_class = NULL;
458 static struct mtd_info *nvram_mtd = NULL;
461 _nvram_read(char *buf)
463 struct nvram_header *header = (struct nvram_header *) buf;
464 size_t len;
466 if (!nvram_mtd ||
467 nvram_mtd->read(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) ||
468 len != NVRAM_SPACE ||
469 !nvram_valid(header)) {
470 /* Maybe we can recover some data from early initialization */
471 memcpy(buf, nvram_buf, NVRAM_SPACE);
474 return 0;
477 struct nvram_tuple *
478 _nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
480 if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
481 return NULL;
483 if (!t) {
484 if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
485 return NULL;
487 /* Copy name */
488 t->name = (char *) &t[1];
489 strcpy(t->name, name);
491 t->value = NULL;
494 /* Copy value */
495 if (!t->value || strcmp(t->value, value)) {
496 t->value = &nvram_buf[nvram_offset];
497 strcpy(t->value, value);
498 nvram_offset += strlen(value) + 1;
501 return t;
504 void
505 _nvram_free(struct nvram_tuple *t)
507 if (!t)
508 nvram_offset = 0;
509 else
510 kfree(t);
514 nvram_init(void *sih)
516 return 0;
520 nvram_set(const char *name, const char *value)
522 unsigned long flags;
523 int ret;
524 struct nvram_header *header;
525 char wps_name[32];
526 int wep_len;
528 spin_lock_irqsave(&nvram_lock, flags);
530 //printk("nvram_set: name = %s, value = %s!\n", name, value);
531 #ifdef CFE_UPDATE //write back to default sector as well, Chen-I
532 if(strncmp(name, CFE_NVRAM_PREFIX, strlen(CFE_NVRAM_PREFIX))==0)
534 if(strcmp(name, CFE_NVRAM_COMMIT)==0)
535 cfe_commit();
536 else if(strcmp(name, "asuscfe_dump") == 0)
537 ret = cfe_dump();
538 else if(strcmp(name, CFE_NVRAM_WATCHDOG)==0)
540 bcm947xx_watchdog_disable();
542 else
544 cfe_update(name+strlen(CFE_NVRAM_PREFIX), value);
545 _nvram_set(name+strlen(CFE_NVRAM_PREFIX), value);
548 else
549 #endif
551 #if WPS
552 if (strncmp(name, "wlx_", 4) == 0) {
553 memset(wps_name, 0, sizeof(wps_name));
554 sprintf(wps_name, "wl0_%s", name+4);
555 ret = _nvram_set(wps_name, value);
556 spin_unlock_irqrestore(&nvram_lock, flags);
557 return ret;
560 if (strncmp(name, "wl0_", 4) == 0)
562 /* Authentication mode */
563 if (strncmp(name, "wl0_akm", 7) == 0) {
564 if (strncmp(value, "psk2", 4) == 0) { // WPA2-Personal
565 _nvram_set("wl_auth_mode", "psk");
566 _nvram_set("wl_wpa_mode", "2");
568 else if (strncmp(value, "psk ", 4) == 0) { // WPA-Auto-Personal
569 _nvram_set("wl_auth_mode", "psk");
570 _nvram_set("wl_wpa_mode", "0");
572 else if (strncmp(value, "psk", 3) == 0) { // WPA-Personal
573 _nvram_set("wl_auth_mode", "psk");
574 _nvram_set("wl_wpa_mode", "1");
576 else if (strncmp(value, "wpa2", 4) == 0) { // WPA2-Enterprise
577 _nvram_set("wl_auth_mode", "wpa2");
579 else if (strncmp(value, "wpa ", 4) == 0) { // WPA-Auto-Enterprise
580 _nvram_set("wl_wpa_mode", "4");
581 _nvram_set("wl_auth_mode", "wpa");
583 else if (strncmp(value, "wpa", 3) == 0) { // WPA-Enterprise
584 _nvram_set("wl_wpa_mode", "3");
585 _nvram_set("wl_auth_mode", "wpa");
587 _nvram_set("wl_akm", value);
589 /* WPS KEY*/
590 else if (strcmp(name, "wl0_wpa_psk") == 0) {
591 _nvram_set("wl_wpa_psk", value);
593 /* WEP type */
594 #if 1
595 else if ((strncmp(name, "wl0_key", 7) == 0 )) {
597 wep_len = strlen (value);
598 memset(wps_name, 0, sizeof(wps_name));
600 if ((wep_len == 5) || (wep_len == 10)) { /* wl0_key1~4*/
601 // _nvram_set ("wl0_wep_x", "1");
602 _nvram_set ("wl_wep_x", "1");
603 sprintf(wps_name, "wl_%s", name+4);
605 else if ((wep_len == 13) || (wep_len == 26)) {
606 // _nvram_set ("wl0_wep_x", "2");
607 _nvram_set ("wl_wep_x", "2");
608 sprintf(wps_name, "wl_%s", name+4);
610 else { /* wl0_key index */
611 sprintf(wps_name, "wl_%s", name+4);
613 _nvram_set(wps_name, value);
615 #endif
616 else if (strcmp(name, "wl0_ssid") == 0) {
617 // _nvram_set("wl0_ssid2", value);
618 // _nvram_set("wl_ssid2", value);
619 _nvram_set("wl_ssid", value);
621 else if (strcmp(name, "wl0_crypto") == 0) {
622 _nvram_set("wl_crypto", value);
624 else if (strncmp(name, "wl0_wps", 7) == 0) {
625 memset(wps_name, 0, sizeof(wps_name));
626 sprintf(wps_name, "wl_%s", name+4);
627 _nvram_set(wps_name, value);
631 else if (strncmp(name, "wps_random_ssid_prefix", 22) == 0) {
632 memset(wps_name, 0, sizeof(wps_name));
633 sprintf(wps_name, "ASUS_");
634 ret = _nvram_set("wps_random_ssid_prefix", wps_name);
635 spin_unlock_irqrestore(&nvram_lock, flags);
636 return ret;
639 if (strcmp(name, "lan_wps_oob") == 0) {
640 if (strcmp(value, "disabled") == 0) {
641 _nvram_set("wps_config_state", "1");
642 _nvram_set("wl_wps_config_state", "1");
643 _nvram_set("wl0_wps_config_state", "1");
644 } else if (strcmp(value, "enabled") == 0) {
645 _nvram_set("wps_config_state", "0");
646 _nvram_set("wl_wps_config_state", "0");
647 _nvram_set("wl0_wps_config_state", "0");
651 if (strcmp(name, "wps_config_state") == 0) {
652 if (strcmp(value, "0") == 0)
653 _nvram_set("lan_wps_oob", "enabled");
654 else if (strcmp(value, "1") == 0)
655 _nvram_set("lan_wps_oob", "disabled");
658 if ((strcmp(name, "wl_wps_config_state") == 0) || (strcmp(name, "wl0_wps_config_state") == 0))
659 _nvram_set("wps_config_state", value);
662 // else if ((strncmp(name, "wps_proc_status", 15) == 0 ) && (strcmp(value, "4"))) /* WPS success*/
663 // _nvram_set("wps_config_state", "1");
665 #if 0
666 if(!strcmp(name, "wl0_ssid"))
667 _nvram_set("wl_ssid", value);
668 if(!strcmp(name, "wl0_ssid"))
669 _nvram_set("wl_ssid", value);
670 /* Set Wireless encryption */
671 if (!strcmp(name, "wl0_akm")) {
672 _nvram_set("wl_auth_mode", "psk");
673 _nvram_set("wl_wpa_mode", "1");
675 else if (!strcmp("wl0_akm", "psk2")) {
676 _nvram_set("wl_auth_mode", "psk");
677 _nvram_set("wl_wpa_mode", "2");
679 else if (nvram_match("wl0_akm", "wpa")) {
680 _nvram_set("wl_auth_mode", "wpa");
681 _nvram_set("wl_wpa_mode", "3");
683 else if (nvram_match("wl0_akm", "wpa2")) {
684 _nvram_set("wl_auth_mode", "wpa2");
686 else
687 _nvram_set("wl_auth_mode", nvram_get("wl0_auth_mode"));
688 #endif
689 #endif
691 if ((ret = _nvram_set(name, value))) {
692 /* Consolidate space and try again */
693 if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
694 if (_nvram_commit(header) == 0)
695 ret = _nvram_set(name, value);
696 kfree(header);
699 spin_unlock_irqrestore(&nvram_lock, flags);
701 return ret;
704 char *
705 real_nvram_get(const char *name)
707 unsigned long flags;
708 char *value;
710 spin_lock_irqsave(&nvram_lock, flags);
711 value = _nvram_get(name);
712 spin_unlock_irqrestore(&nvram_lock, flags);
714 return value;
717 char *
718 nvram_get(const char *name)
720 if (nvram_major >= 0)
721 return real_nvram_get(name);
722 else
723 return early_nvram_get(name);
727 nvram_unset(const char *name)
729 unsigned long flags;
730 int ret;
732 spin_lock_irqsave(&nvram_lock, flags);
733 #ifdef CFE_UPDATE //unset variable in embedded nvram
734 if(strncmp(name, CFE_NVRAM_PREFIX, strlen(CFE_NVRAM_PREFIX))==0)
736 if((ret = cfe_update(name+strlen(CFE_NVRAM_PREFIX), NULL)) == 0)
738 ret = _nvram_unset(name+strlen(CFE_NVRAM_PREFIX));
741 else
742 #endif
743 ret = _nvram_unset(name);
744 spin_unlock_irqrestore(&nvram_lock, flags);
746 return ret;
749 static void
750 erase_callback(struct erase_info *done)
752 wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
753 wake_up(wait_q);
757 nvram_commit(void)
759 #if 0
760 char *buf;
761 #endif
762 size_t erasesize, len, magic_len;
763 unsigned int i;
764 int ret;
765 struct nvram_header *header;
766 unsigned long flags;
767 u_int32_t offset;
768 DECLARE_WAITQUEUE(wait, current);
769 wait_queue_head_t wait_q;
770 struct erase_info erase;
771 u_int32_t magic_offset = 0; /* Offset for writing MAGIC # */
773 if (!nvram_mtd) {
774 printk("nvram_commit: NVRAM not found\n");
775 return -ENODEV;
778 if (in_interrupt()) {
779 printk("nvram_commit: not committing in interrupt\n");
780 return -EINVAL;
783 /* Backup sector blocks to be erased */
784 erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize);
785 #if 0
786 if (!(buf = kmalloc(erasesize, GFP_KERNEL))) {
787 printk("nvram_commit: out of memory\n");
788 return -ENOMEM;
790 #endif
791 down(&nvram_sem);
793 if ((i = erasesize - NVRAM_SPACE) > 0) {
794 offset = nvram_mtd->size - erasesize;
795 len = 0;
796 ret = nvram_mtd->read(nvram_mtd, offset, i, &len, nvram_commit_buf);
797 if (ret || len != i) {
798 printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
799 ret = -EIO;
800 goto done;
802 header = (struct nvram_header *)(nvram_commit_buf + i);
803 magic_offset = i + ((void *)&header->magic - (void *)header);
804 } else {
805 offset = nvram_mtd->size - NVRAM_SPACE;
806 magic_offset = ((void *)&header->magic - (void *)header);
807 header = (struct nvram_header *)nvram_commit_buf;
810 /* clear the existing magic # to mark the NVRAM as unusable
811 * we can pull MAGIC bits low without erase
813 header->magic = NVRAM_CLEAR_MAGIC; /* All zeros magic */
814 /* Unlock sector blocks */
815 if (nvram_mtd->unlock)
816 nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
817 ret = nvram_mtd->write(nvram_mtd, offset + magic_offset, sizeof(header->magic),
818 &magic_len, (char *)&header->magic);
819 if (ret || magic_len != sizeof(header->magic)) {
820 printk("nvram_commit: clear MAGIC error\n");
821 ret = -EIO;
822 goto done;
825 header->magic = NVRAM_MAGIC;
826 /* reset MAGIC before we regenerate the NVRAM,
827 * otherwise we'll have an incorrect CRC
829 /* Regenerate NVRAM */
830 spin_lock_irqsave(&nvram_lock, flags);
831 ret = _nvram_commit(header);
832 spin_unlock_irqrestore(&nvram_lock, flags);
833 if (ret)
834 goto done;
836 /* Erase sector blocks */
837 init_waitqueue_head(&wait_q);
838 for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len;
839 offset += nvram_mtd->erasesize) {
841 erase.mtd = nvram_mtd;
842 erase.addr = offset;
843 erase.len = nvram_mtd->erasesize;
844 erase.callback = erase_callback;
845 erase.priv = (u_long) &wait_q;
847 set_current_state(TASK_INTERRUPTIBLE);
848 add_wait_queue(&wait_q, &wait);
850 /* Unlock sector blocks */
851 if (nvram_mtd->unlock)
852 nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
854 if ((ret = nvram_mtd->erase(nvram_mtd, &erase))) {
855 set_current_state(TASK_RUNNING);
856 remove_wait_queue(&wait_q, &wait);
857 printk("nvram_commit: erase error\n");
858 goto done;
861 /* Wait for erase to finish */
862 schedule();
863 remove_wait_queue(&wait_q, &wait);
866 /* Write partition up to end of data area */
867 header->magic = NVRAM_INVALID_MAGIC; /* All ones magic */
868 offset = nvram_mtd->size - erasesize;
869 i = erasesize - NVRAM_SPACE + header->len;
870 ret = nvram_mtd->write(nvram_mtd, offset, i, &len, nvram_commit_buf);
871 if (ret || len != i) {
872 printk("nvram_commit: write error\n");
873 ret = -EIO;
874 goto done;
877 /* Now mark the NVRAM in flash as "valid" by setting the correct
878 * MAGIC #
880 header->magic = NVRAM_MAGIC;
881 ret = nvram_mtd->write(nvram_mtd, offset + magic_offset, sizeof(header->magic),
882 &magic_len, (char *)&header->magic);
883 if (ret || magic_len != sizeof(header->magic)) {
884 printk("nvram_commit: write MAGIC error\n");
885 ret = -EIO;
886 goto done;
889 offset = nvram_mtd->size - erasesize;
890 ret = nvram_mtd->read(nvram_mtd, offset, 4, &len, nvram_commit_buf);
892 done:
893 up(&nvram_sem);
894 #if 0
895 kfree(buf);
896 #endif
897 return ret;
901 nvram_getall(char *buf, int count)
903 unsigned long flags;
904 int ret;
906 spin_lock_irqsave(&nvram_lock, flags);
907 if (nvram_major >= 0)
908 ret = _nvram_getall(buf, count);
909 else
910 ret = early_nvram_getall(buf, count);
911 spin_unlock_irqrestore(&nvram_lock, flags);
913 return ret;
916 EXPORT_SYMBOL(nvram_init);
917 EXPORT_SYMBOL(nvram_get);
918 EXPORT_SYMBOL(nvram_getall);
919 EXPORT_SYMBOL(nvram_set);
920 EXPORT_SYMBOL(nvram_unset);
921 EXPORT_SYMBOL(nvram_commit);
923 /* User mode interface below */
925 static ssize_t
926 dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
928 char tmp[100], *name = tmp, *value;
929 ssize_t ret;
930 unsigned long off;
932 if (count > sizeof(tmp)) {
933 if (!(name = kmalloc(count, GFP_KERNEL)))
934 return -ENOMEM;
937 if (copy_from_user(name, buf, count)) {
938 ret = -EFAULT;
939 goto done;
942 if (*name == '\0') {
943 /* Get all variables */
944 ret = nvram_getall(name, count);
945 if (ret == 0) {
946 if (copy_to_user(buf, name, count)) {
947 ret = -EFAULT;
948 goto done;
950 ret = count;
952 } else {
953 if (!(value = nvram_get(name))) {
954 ret = 0;
955 goto done;
958 /* Provide the offset into mmap() space */
959 off = (unsigned long) value - (unsigned long) nvram_buf;
961 if (put_user(off, (unsigned long *) buf)) {
962 ret = -EFAULT;
963 goto done;
966 ret = sizeof(unsigned long);
969 flush_cache_all();
971 done:
972 if (name != tmp)
973 kfree(name);
975 return ret;
978 static ssize_t
979 dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
981 char tmp[100], *name = tmp, *value;
982 ssize_t ret;
984 if (count > sizeof(tmp)) {
985 if (!(name = kmalloc(count, GFP_KERNEL)))
986 return -ENOMEM;
989 if (copy_from_user(name, buf, count)) {
990 ret = -EFAULT;
991 goto done;
994 value = name;
995 name = strsep(&value, "=");
996 if (value)
997 ret = nvram_set(name, value) ? : count;
998 else
999 ret = nvram_unset(name) ? : count;
1001 done:
1002 if (name != tmp)
1003 kfree(name);
1005 return ret;
1008 static int
1009 dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
1011 if (cmd != NVRAM_MAGIC)
1012 return -EINVAL;
1014 #ifndef NLS_XFR
1015 return nvram_commit();
1016 #else
1017 if(arg == 0)
1018 return nvram_commit();
1019 else
1020 return nvram_xfr((char *)arg);
1021 #endif // NLS_XFR
1024 static int
1025 dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
1027 unsigned long offset = __pa(nvram_buf) >> PAGE_SHIFT;
1029 if (remap_pfn_range(vma, vma->vm_start, offset,
1030 vma->vm_end - vma->vm_start,
1031 vma->vm_page_prot))
1032 return -EAGAIN;
1034 return 0;
1037 static int
1038 dev_nvram_open(struct inode *inode, struct file * file)
1040 return 0;
1043 static int
1044 dev_nvram_release(struct inode *inode, struct file * file)
1046 return 0;
1049 static struct file_operations dev_nvram_fops = {
1050 owner: THIS_MODULE,
1051 open: dev_nvram_open,
1052 release: dev_nvram_release,
1053 read: dev_nvram_read,
1054 write: dev_nvram_write,
1055 ioctl: dev_nvram_ioctl,
1056 mmap: dev_nvram_mmap
1059 static void
1060 dev_nvram_exit(void)
1062 int order = 0;
1063 struct page *page, *end;
1065 if (nvram_class) {
1066 class_device_destroy(nvram_class, MKDEV(nvram_major, 0));
1067 class_destroy(nvram_class);
1070 if (nvram_major >= 0)
1071 unregister_chrdev(nvram_major, "nvram");
1073 if (nvram_mtd)
1074 put_mtd_device(nvram_mtd);
1076 while ((PAGE_SIZE << order) < NVRAM_SPACE)
1077 order++;
1078 end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
1079 for (page = virt_to_page(nvram_buf); page <= end; page++)
1080 ClearPageReserved(page);
1082 _nvram_exit();
1085 static int
1086 dev_nvram_init(void)
1088 int order = 0, ret = 0;
1089 struct page *page, *end;
1090 unsigned int i;
1091 osl_t *osh;
1093 /* Allocate and reserve memory to mmap() */
1094 while ((PAGE_SIZE << order) < NVRAM_SPACE)
1095 order++;
1096 end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
1097 for (page = virt_to_page(nvram_buf); page <= end; page++) {
1098 SetPageReserved(page);
1101 #if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
1102 /* Find associated MTD device */
1103 for (i = 0; i < MAX_MTD_DEVICES; i++) {
1104 nvram_mtd = get_mtd_device(NULL, i);
1105 if (!IS_ERR(nvram_mtd)) {
1106 if (!strcmp(nvram_mtd->name, "nvram") &&
1107 nvram_mtd->size >= NVRAM_SPACE) {
1108 break;
1110 put_mtd_device(nvram_mtd);
1113 if (i >= MAX_MTD_DEVICES)
1114 nvram_mtd = NULL;
1115 #endif
1117 /* Initialize hash table lock */
1118 spin_lock_init(&nvram_lock);
1120 /* Initialize commit semaphore */
1121 init_MUTEX(&nvram_sem);
1123 /* Register char device */
1124 if ((nvram_major = register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
1125 ret = nvram_major;
1126 goto err;
1129 if (si_osh(sih) == NULL) {
1130 osh = osl_attach(NULL, SI_BUS, FALSE);
1131 if (osh == NULL) {
1132 printk("Error allocating osh\n");
1133 unregister_chrdev(nvram_major, "nvram");
1134 goto err;
1136 si_setosh(sih, osh);
1139 /* Initialize hash table */
1140 _nvram_init(sih);
1142 /* Create /dev/nvram handle */
1143 nvram_class = class_create(THIS_MODULE, "nvram");
1144 if (IS_ERR(nvram_class)) {
1145 printk("Error creating nvram class\n");
1146 goto err;
1149 /* Add the device nvram0 */
1150 class_device_create(nvram_class, NULL, MKDEV(nvram_major, 0), NULL, "nvram");
1152 /* reserve commit read buffer */
1153 /* Backup sector blocks to be erased */
1154 if (!(nvram_commit_buf = kmalloc(ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize), GFP_KERNEL))) {
1155 printk("dev_nvram_init: nvram_commit_buf out of memory\n");
1156 goto err;
1159 /* Set the SDRAM NCDL value into NVRAM if not already done */
1160 if (getintvar(NULL, "sdram_ncdl") == 0) {
1161 unsigned int ncdl;
1162 char buf[] = "0x00000000";
1164 if ((ncdl = si_memc_get_ncdl(sih))) {
1165 sprintf(buf, "0x%08x", ncdl);
1166 nvram_set("sdram_ncdl", buf);
1167 nvram_commit();
1171 return 0;
1173 err:
1174 dev_nvram_exit();
1175 return ret;
1178 #ifdef CFE_UPDATE
1179 int get_embedded_block(struct mtd_info *mtd, char *buf, size_t erasesize,
1180 u_int32_t *offset, struct nvram_header **header, u_int32_t *emb_size)
1182 size_t len;
1183 struct nvram_header *nvh;
1185 #ifdef CONFIG_RTAN23 /*for AMCC RTAN23 */
1186 *offset = mtd->size - erasesize; /*/at the end of mtd */
1187 *emb_size = 8*1024 - 16; /*/8K - 16 byte */
1188 printk("get_embedded_block: mtd->size(%08x) erasesize(%08x) offset(%08x) emb_size(%08x)\n", mtd->size, erasesize, *offset, *emb_size);
1189 cfe_mtd->read(mtd, *offset, erasesize, &len, buf);
1190 if(len != erasesize)
1191 return -EIO;
1193 /* find nvram header */
1194 nvh = (struct nvram_header *)(buf + erasesize - 8*1024);
1195 if (nvh->magic == NVRAM_MAGIC)
1197 *header = nvh;
1198 return 0;
1201 #else /* for Broadcom WL500 serials */
1202 *offset = 0; /* from the mtd start */
1203 *emb_size = 4096; /* 1K byte */
1204 printk("get_embedded_block: mtd->size(%08x) erasesize(%08x) offset(%08x) emb_size(%08x)\n", mtd->size, erasesize, *offset, *emb_size);
1205 cfe_mtd->read(mtd, *offset, erasesize, &len, buf);
1206 if(len != erasesize)
1207 return -EIO;
1209 /* find nvram header */
1210 nvh = (struct nvram_header *)(buf + (4 * 1024));
1211 if (nvh->magic == NVRAM_MAGIC)
1213 *header = nvh;
1214 return 0;
1216 nvh = (struct nvram_header *)(buf + (1 * 1024));
1217 if (nvh->magic == NVRAM_MAGIC)
1219 *header = nvh;
1220 return 0;
1222 #endif
1223 printk("get_embedded_block: no nvram magic found\n");
1224 return -ENXIO;
1226 static int cfe_init(void)
1228 size_t erasesize;
1229 int i;
1230 int ret = 0;
1232 /* Find associated MTD device */
1233 for (i = 0; i < MAX_MTD_DEVICES; i++) {
1234 cfe_mtd = get_mtd_device(NULL, i);
1235 if (cfe_mtd != NULL) {
1236 printk("cfe_init: CFE MTD %x %s %x\n", i, cfe_mtd->name, cfe_mtd->size);
1237 if (!strcmp(cfe_mtd->name, "boot"))
1238 break;
1239 put_mtd_device(cfe_mtd);
1242 if (i >= MAX_MTD_DEVICES)
1244 printk("cfe_init: No CFE MTD\n");
1245 cfe_mtd = NULL;
1246 ret = -ENODEV;
1249 if(cfe_mtd == NULL) goto fail;
1251 /* sector blocks to be erased and backup */
1252 erasesize = ROUNDUP(CFE_NVRAM_SPACE, cfe_mtd->erasesize);
1254 //printk("cfe_init: block size %d\n", erasesize);
1255 cfe_buf = kmalloc(erasesize, GFP_KERNEL);
1257 if(cfe_buf == NULL)
1259 //printk("cfe_init: No CFE Memory\n");
1260 ret = -ENOMEM;
1261 goto fail;
1263 if((ret = get_embedded_block(cfe_mtd, cfe_buf, erasesize, &cfe_offset, &cfe_nvram_header, &cfe_embedded_size)))
1264 goto fail;
1266 printk("cfe_init: cfe_nvram_header(%08x)\n", (unsigned int) cfe_nvram_header);
1267 bcm947xx_watchdog_disable();
1269 return 0;
1271 fail:
1272 if (cfe_mtd != NULL)
1274 put_mtd_device(cfe_mtd);
1275 cfe_mtd=NULL;
1277 if(cfe_buf != NULL)
1279 kfree(cfe_buf);
1280 cfe_buf=NULL;
1282 return ret;
1284 static int cfe_update(const char *keyword, const char *value)
1286 struct nvram_header *header;
1287 uint8 crc;
1288 int ret;
1289 int found = 0;
1290 char *str, *end, *mv_target = NULL, *mv_start = NULL;
1292 if(keyword == NULL || *keyword == 0)
1293 return 0;
1295 if(cfe_buf == NULL||cfe_mtd == NULL)
1296 if((ret = cfe_init()))
1297 return ret;
1299 header = cfe_nvram_header;
1301 //printk("cfe_update: before %x %x\n", header->len, cfe_nvram_header->crc_ver_init&0xff);
1302 str = (char *) &header[1];
1303 end = (char *) header + cfe_embedded_size - 2;
1304 end[0] = end[1] = '\0';
1305 for (; *str; str += strlen(str) + 1)
1307 if(!found)
1309 if(strncmp(str, keyword, strlen(keyword)) == 0 && str[strlen(keyword)] == '=')
1311 printk("cfe_update: !!!! found !!!!\n");
1312 found = 1;
1313 if(value != NULL && strlen(str) == strlen(keyword) + 1 + strlen(value))
1314 {//string length is the same
1315 strcpy(str+strlen(keyword)+1, value);
1317 else
1319 mv_target = str;
1320 mv_start = str + strlen(str) + 1;
1325 /* str point to the end of all embedded nvram settings */
1327 if(mv_target != NULL)
1328 { /* need to move string */
1329 int str_len = strlen(mv_target);
1330 printk("cfe_update: mv_target(%08x) mv_start(%08x) str(%08x) str_len(%d)\n", (unsigned int)mv_target, (unsigned int)mv_start, (unsigned int)str, str_len);
1331 if(value != NULL && (str + strlen(keyword) + 1 + strlen(value) + 1 - (str_len + 1)) > end)
1332 return -ENOSPC;
1333 memmove(mv_target, mv_start, str - mv_start);
1334 printk("cfe_update: memmove done\n");
1335 str -= (str_len + 1); /* /set str to the end for placing incoming keyword and value there */
1338 if(value == NULL)
1340 printk("cfe_update: do unset\n");
1342 else if(!found || mv_target != NULL) /*new or movement */
1343 { /* append the keyword and value here */
1344 printk("cfe_update: str(%08x)\n", (unsigned int) str);
1345 if((str + strlen(keyword) + 1 + strlen(value) + 1) > end)
1346 return -ENOSPC;
1347 str += sprintf(str, "%s=%s", keyword, value) + 1;
1348 printk("cfe_update: append string\n");
1350 /* calc length */
1351 memset(str, 0, cfe_embedded_size+(char *)header - str);
1352 str += 2;
1353 header->len = ROUNDUP(str - (char *) header, 4);
1354 printk("cfe_update: header len: %x\n", header->len);
1355 /*/calc crc */
1356 crc = nvram_calc_crc(header);
1357 printk("cfe_update: nvram_calc_crc(header) = 0x%02x\n", crc);
1358 header->crc_ver_init = (header->crc_ver_init & NVRAM_CRC_VER_MASK)|crc;
1359 /*/printk("cfe_update: after %x %x\n", header->crc_ver_init&0xFF, crc); */
1360 return 0;
1362 static int cfe_dump(void)
1364 unsigned int i;
1365 int ret;
1366 unsigned char *ptr;
1368 if(cfe_buf == NULL||cfe_mtd == NULL)
1369 if((ret = cfe_init()))
1370 return ret;
1372 printk("cfe_dump: cfe_buf(%08x), dump 1024 byte\n", (unsigned int)cfe_buf);
1373 for(i=0, ptr=(unsigned char *)cfe_nvram_header - 1024; ptr < (unsigned char *)cfe_nvram_header; i++, ptr++)
1375 if(i%16==0) printk("%04x: %02x ", i, *ptr);
1376 else if(i%16==15) printk("%02x\n", *ptr);
1377 else if(i%16==7) printk("%02x - ", *ptr);
1378 else printk("%02x ", *ptr);
1381 printk("\ncfe_dump: cfe_nvram_header(%08x)\n", (unsigned int)cfe_nvram_header);
1382 printk("cfe_dump: cfe_nvram_header->len(0x%08x)\n", cfe_nvram_header->len);
1384 printk("\n####################\n");
1385 for(i=0, ptr=(unsigned char *)cfe_nvram_header; i< cfe_embedded_size; i++, ptr++)
1387 if(i%16==0) printk("%04x: %02x ", i, *ptr);
1388 else if(i%16==15) printk("%02x\n", *ptr);
1389 else if(i%16==7) printk("%02x - ", *ptr);
1390 else printk("%02x ", *ptr);
1392 printk("\n####################\n");
1393 ptr = (unsigned char *)&cfe_nvram_header[1];
1394 while(*ptr)
1396 printk("%s\n", ptr);
1397 ptr += strlen(ptr) + 1;
1399 printk("\n####################\n");
1400 for(i=0, ptr=((unsigned char *)cfe_nvram_header) + cfe_embedded_size; i<16; i++, ptr++)
1402 if(i%16==0) printk("%04x: %02x ", i, *ptr);
1403 else if(i%16==15) printk("%02x\n", *ptr);
1404 else if(i%16==7) printk("%02x - ", *ptr);
1405 else printk("%02x ", *ptr);
1407 return 0;
1410 static int cfe_commit(void)
1412 DECLARE_WAITQUEUE(wait, current);
1413 wait_queue_head_t wait_q;
1414 struct erase_info erase;
1415 int ret = 0;
1416 size_t erasesize, len=0;
1417 u_int32_t offset;
1419 if(cfe_mtd == NULL||cfe_buf == NULL)
1421 printk("cfe_commit: do nothing\n");
1422 return 0;
1425 #if 0
1426 ret = cfe_dump();
1427 return ret;
1428 #endif
1429 #if 1
1430 /* Backup sector blocks to be erased */
1431 erasesize = ROUNDUP(CFE_NVRAM_SPACE, cfe_mtd->erasesize);
1432 printk("cfe_commit: erasesize(%08x) cfe_offset(%08x)\n", erasesize, cfe_offset);
1434 /* Erase sector blocks */
1435 init_waitqueue_head(&wait_q);
1436 for (offset=cfe_offset;offset < cfe_offset+erasesize;offset += cfe_mtd->erasesize) {
1437 printk("cfe_commit: ERASE sector block offset(%08x) cfe_mtd->erasesize(%08x)\n", offset, cfe_mtd->erasesize);
1438 erase.mtd = cfe_mtd;
1439 erase.addr = offset;
1440 erase.len = cfe_mtd->erasesize;
1441 erase.callback = erase_callback;
1442 erase.priv = (u_long) &wait_q;
1444 set_current_state(TASK_INTERRUPTIBLE);
1445 add_wait_queue(&wait_q, &wait);
1446 /* Unlock sector blocks */
1447 if (cfe_mtd->unlock)
1448 cfe_mtd->unlock(cfe_mtd, offset, cfe_mtd->erasesize);
1450 if ((ret = cfe_mtd->erase(cfe_mtd, &erase))) {
1451 set_current_state(TASK_RUNNING);
1452 remove_wait_queue(&wait_q, &wait);
1453 printk("cfe_commit: erase error\n");
1454 ret = -EIO;
1455 goto done;
1458 /* Wait for erase to finish */
1459 schedule();
1460 remove_wait_queue(&wait_q, &wait);
1463 ret = cfe_mtd->write(cfe_mtd, cfe_offset, erasesize, &len, cfe_buf);
1464 printk("cfe_commit: MTD_WRITE cfe_offset(%08x) erasesize(%08x) len(%08x) ret(%08x)\n", cfe_offset, erasesize, len, ret);
1466 if (ret || len != erasesize) {
1467 printk("cfe_commit: write error\n");
1468 ret = -EIO;
1471 done:
1472 if (cfe_mtd != NULL)
1474 put_mtd_device(cfe_mtd);
1475 cfe_mtd=NULL;
1477 if(cfe_buf != NULL)
1479 kfree(cfe_buf);
1480 cfe_buf=NULL;
1482 //printk("commit: %d\n", ret);
1483 return ret;
1484 #endif
1486 #endif
1489 //#ifdef CFE_UPDATE
1490 #if 0
1491 void cfe_init(void)
1493 size_t erasesize, len;
1494 int i;
1496 /* Find associated MTD device */
1497 for (i = 0; i < MAX_MTD_DEVICES; i++) {
1498 cfe_mtd = get_mtd_device(NULL, i);
1499 if (cfe_mtd) {
1500 printk("CFE MTD: %x %s %x\n", i, cfe_mtd->name, cfe_mtd->size);
1501 if (!strcmp(cfe_mtd->name, "boot"))
1502 break;
1503 put_mtd_device(cfe_mtd);
1506 if (i >= MAX_MTD_DEVICES)
1508 printk("No CFE MTD\n");
1509 cfe_mtd = NULL;
1512 if(!cfe_mtd) goto fail;
1514 /* sector blocks to be erased and backup */
1515 erasesize = ROUNDUP(CFE_NVRAM_SPACE, cfe_mtd->erasesize);
1517 /* printk("block size %d\n", erasesize); */
1519 cfe_buf = kmalloc(erasesize, GFP_KERNEL);
1521 if(!cfe_buf)
1523 /* printk("No CFE Memory\n"); */
1524 goto fail;
1526 cfe_mtd->read(cfe_mtd, CFE_NVRAM_START, erasesize, &len, cfe_buf);
1528 /* find nvram header */
1529 for(i=0;i<len;i+=4)
1531 cfe_nvram_header=(struct nvram_header *)&cfe_buf[i];
1532 if (cfe_nvram_header->magic==NVRAM_MAGIC) break;
1535 bcm947xx_watchdog_disable(); /*disable watchdog as well */
1537 #if 0
1538 printf("read from nvram %d %s\n", i, cfe_buf);
1539 for(i=0;i<CFE_SPACE;i++)
1541 if(i%16) printk("\n");
1542 printk("%02x ", (unsigned char)cfe_buf[i]);
1544 #endif
1545 return;
1546 fail:
1547 if (cfe_mtd)
1549 put_mtd_device(cfe_mtd);
1550 cfe_mtd=NULL;
1552 if(cfe_buf)
1554 kfree(cfe_buf);
1555 cfe_buf=NULL;
1557 return;
1560 void cfe_update(const char *keyword, const char *value)
1562 unsigned long i, offset;
1563 struct nvram_header tmp, *header;
1564 uint8 crc;
1565 // int ret;
1566 int found = 0;
1568 if(!cfe_buf||!cfe_mtd)
1569 cfe_init();
1571 if (!cfe_buf||!cfe_mtd) return;
1573 header = cfe_nvram_header;
1575 printk("before: %x %x\n", header->len, cfe_nvram_header->crc_ver_init&0xff);
1577 for(i=CFE_NVRAM_START;i<=CFE_NVRAM_END;i++)
1579 if(strncmp(&cfe_buf[i], keyword, strlen(keyword))==0)
1581 printk("before: %s\n", cfe_buf+i);
1582 offset=strlen(keyword);
1583 memcpy(cfe_buf+i+offset+1, value, strlen(value));
1584 printk("after: %s\n", cfe_buf+i);
1585 found = 1;
1589 if(!found)
1591 char *tmp_buf = (char *)cfe_nvram_header;
1593 /* printk("header len: %x\n", header->len); */
1594 sprintf(tmp_buf+header->len, "%s=%s", keyword, value);
1595 header->len = header->len + strlen(keyword) + strlen(value) + 2;
1596 /* printk("header len: %x\n", header->len); */
1599 tmp.crc_ver_init = htol32(header->crc_ver_init);
1600 tmp.config_refresh = htol32(header->config_refresh);
1601 tmp.config_ncdl = htol32(header->config_ncdl);
1602 crc = hndcrc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
1604 /* Continue CRC8 over data bytes */
1605 crc = hndcrc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
1606 header->crc_ver_init = (header->crc_ver_init&0xFFFFFF00)|crc;
1607 printk("after: %x %x\n", header->crc_ver_init&0xFF, crc);
1610 int cfe_commit(void)
1612 DECLARE_WAITQUEUE(wait, current);
1613 wait_queue_head_t wait_q;
1614 struct erase_info erase;
1615 // unsigned int i;
1616 int ret;
1617 size_t erasesize, len;
1618 u_int32_t offset;
1619 // char *buf;
1621 if(!cfe_buf||!cfe_mtd) cfe_init();
1623 if(!cfe_mtd||!cfe_buf)
1625 ret = - ENOMEM;
1626 goto done;
1629 /* Backup sector blocks to be erased */
1630 erasesize = ROUNDUP(CFE_NVRAM_SPACE, cfe_mtd->erasesize);
1632 down(&nvram_sem);
1634 /* Erase sector blocks */
1635 init_waitqueue_head(&wait_q);
1638 for (offset=CFE_NVRAM_START;offset <= CFE_NVRAM_END;offset += cfe_mtd->erasesize) {
1639 erase.mtd = cfe_mtd;
1640 erase.addr = offset;
1641 erase.len = cfe_mtd->erasesize;
1642 erase.callback = erase_callback;
1643 erase.priv = (u_long) &wait_q;
1645 set_current_state(TASK_INTERRUPTIBLE);
1646 add_wait_queue(&wait_q, &wait);
1647 /* Unlock sector blocks */
1648 if (cfe_mtd->unlock)
1649 cfe_mtd->unlock(cfe_mtd, offset, cfe_mtd->erasesize);
1651 if ((ret = cfe_mtd->erase(cfe_mtd, &erase))) {
1652 set_current_state(TASK_RUNNING);
1653 remove_wait_queue(&wait_q, &wait);
1654 printk("cfe_commit: erase error\n");
1655 goto done;
1658 /* Wait for erase to finish */
1659 schedule();
1660 remove_wait_queue(&wait_q, &wait);
1663 ret = cfe_mtd->write(cfe_mtd, CFE_NVRAM_START, erasesize, &len, cfe_buf);
1664 /* printk("Write offset: %x %x %x\n", ret, len, erasesize); */
1666 if (ret || len != erasesize) {
1667 printk("cfe_commit: write error\n");
1668 ret = -EIO;
1671 done:
1672 up(&nvram_sem);
1673 if (cfe_mtd)
1675 put_mtd_device(cfe_mtd);
1676 cfe_mtd=NULL;
1678 if(cfe_buf)
1680 kfree(cfe_buf);
1681 cfe_buf=NULL;
1683 /* printk("commit: %d\n", ret); */
1684 return ret;
1687 #endif
1690 module_init(dev_nvram_init);
1691 module_exit(dev_nvram_exit);