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