http://downloads.netgear.com/files/GPL/DM111PSP_v3.61d_GPL.tar.gz
[bcm963xx.git] / bcmdrivers / opensource / char / board / bcm963xx / impl1 / bcm63xx_flash.c
1 /*
2 <:copyright-gpl
3  Copyright 2002 Broadcom Corp. All Rights Reserved.
4
5  This program is free software; you can distribute it and/or modify it
6  under the terms of the GNU General Public License (Version 2) as
7  published by the Free Software Foundation.
8
9  This program is distributed in the hope it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  for more details.
13
14  You should have received a copy of the GNU General Public License along
15  with this program; if not, write to the Free Software Foundation, Inc.,
16  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 :>
18 */
19 /*
20  ***************************************************************************
21  * File Name  : bcm63xx_flash.c
22  *
23  * Description: This file contains the flash device driver APIs for bcm63xx board. 
24  *
25  * Created on :  8/10/2002  seanl:  use cfiflash.c, cfliflash.h (AMD specific)
26  *
27  ***************************************************************************/
28
29
30 /* Includes. */
31 #include <linux/fs.h>
32 #include <linux/capability.h>
33 #include <linux/slab.h>
34 #include <linux/errno.h>
35 #include <linux/module.h>
36 #include <linux/interrupt.h>
37 #include <asm/uaccess.h>
38
39 #include <bcm_map_part.h>
40 #include <board.h>
41 #define  BCMTAG_EXE_USE
42 #include <bcmTag.h>
43 #include "flash_api.h"
44 #include "boardparms.h"
45
46 //#define DEBUG_FLASH
47
48 extern PFILE_TAG kerSysImageTagGet(void);
49
50 static FLASH_ADDR_INFO fInfo;
51 static int flashInitialized = 0;
52
53 void *retriedKmalloc(size_t size)
54 {
55         void *pBuf;
56     int tryCount = 0;
57     int allocType = GFP_KERNEL;
58
59     if( in_interrupt() )
60     {
61         allocType = GFP_ATOMIC;
62         tryCount = 999;
63     }
64
65     // try 1000 times before quit
66     while (((pBuf = kmalloc(size, allocType)) == NULL) && (++tryCount < 1000))
67     {
68                 current->state   = TASK_INTERRUPTIBLE;
69                 schedule_timeout(HZ/10);
70         }
71     if (tryCount >= 1000)
72         pBuf = NULL;
73     else
74             memset(pBuf, 0, size);
75
76     return pBuf;
77 }
78
79 void retriedKfree(void *pBuf)
80 {
81         kfree(pBuf);
82 }
83
84 /***************************************************************************
85 // Function Name: getCrc32
86 // Description  : caculate the CRC 32 of the given data.
87 // Parameters   : pdata - array of data.
88 //                size - number of input data bytes.
89 //                crc - either CRC32_INIT_VALUE or previous return value.
90 // Returns      : crc.
91 ****************************************************************************/
92 UINT32 getCrc32(byte *pdata, UINT32 size, UINT32 crc) 
93 {
94     while (size-- > 0)
95         crc = (crc >> 8) ^ Crc32_table[(crc ^ *pdata++) & 0xff];
96
97     return crc;
98 }
99
100 // get the nvram start addr
101 //
102 unsigned long get_nvram_start_addr(void)
103 {
104     return ((unsigned long) 
105         (flash_get_memptr(fInfo.flash_nvram_start_blk) + fInfo.flash_nvram_blk_offset));
106 }
107
108 // get the scratch_pad start addr
109 //
110 unsigned long get_scratch_pad_start_addr(void)
111 {
112     return ((unsigned long) 
113         (flash_get_memptr(fInfo.flash_scratch_pad_start_blk) + fInfo.flash_scratch_pad_blk_offset));
114 }
115
116 // Initialize the flash and fill out the fInfo structure
117 void kerSysFlashInit( void )
118 {
119     int i = 0;
120     int totalBlks = 0;
121     int totalSize = 0;
122     int startAddr = 0;
123     int usedBlkSize = 0;
124     NVRAM_DATA nvramData;
125     UINT32 crc = CRC32_INIT_VALUE, savedCrc;
126     PFILE_TAG pTag = NULL;
127     unsigned long kernelEndAddr = 0;
128     unsigned long spAddr = 0;
129
130     if (flashInitialized)
131         return;
132
133     flashInitialized = 1;
134     flash_init();
135
136     totalBlks = flash_get_numsectors();
137     totalSize = flash_get_total_size();
138
139     printk("Total Flash size: %dK with %d sectors\n", totalSize/1024, totalBlks);
140
141     /* nvram is always at the end of flash */
142     fInfo.flash_nvram_length = NVRAM_LENGTH;
143     fInfo.flash_nvram_start_blk = 0;  /* always the first block */
144     fInfo.flash_nvram_number_blk = 1; /*always fits in the first block */
145     fInfo.flash_nvram_blk_offset = NVRAM_DATA_OFFSET;
146  
147     // check nvram CRC
148     memcpy((char *)&nvramData, (char *)get_nvram_start_addr(), sizeof(NVRAM_DATA));
149     savedCrc = nvramData.ulCheckSum;
150     nvramData.ulCheckSum = 0;
151     crc = getCrc32((char *)&nvramData, (UINT32) sizeof(NVRAM_DATA), crc);   
152
153     BpSetBoardId( nvramData.szBoardId );
154
155     fInfo.flash_persistent_length = NVRAM_PSI_DEFAULT;
156     if (savedCrc != crc)
157     {
158         printk("***Board is not initialized****: Using the default PSI size: %d\n",
159             fInfo.flash_persistent_length);
160     }
161     else
162     {
163         unsigned long ulPsiSize;
164         if( BpGetPsiSize( &ulPsiSize ) == BP_SUCCESS )
165             fInfo.flash_persistent_length = ulPsiSize;
166         else
167         {
168             printk("***Board id is not set****: Using the default PSI size: %d\n",
169                 fInfo.flash_persistent_length);
170         }
171     }
172
173     fInfo.flash_persistent_length *= ONEK;
174     startAddr = totalSize - fInfo.flash_persistent_length;
175     fInfo.flash_persistent_start_blk = flash_get_blk(startAddr+FLASH_BASE);
176     fInfo.flash_persistent_number_blk = totalBlks - fInfo.flash_persistent_start_blk;
177     // save abs SP address (Scratch Pad). it is before PSI 
178     spAddr = startAddr - SP_MAX_LEN ;
179     // find out the offset in the start_blk
180     usedBlkSize = 0;
181     for (i = fInfo.flash_persistent_start_blk; 
182         i < (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk); i++)
183     {
184         usedBlkSize += flash_get_sector_size((unsigned short) i);
185     }
186     fInfo.flash_persistent_blk_offset =  usedBlkSize - fInfo.flash_persistent_length;
187
188     // get the info for sp
189     if (!(pTag = kerSysImageTagGet()))
190     {
191         printk("Failed to read image tag from flash\n");
192         return;
193     }
194     kernelEndAddr = (unsigned long)simple_strtoul(pTag->kernelAddress,NULL,10)+ \
195         (unsigned long) simple_strtoul(pTag->kernelLen, NULL, 10) + BOOT_OFFSET;
196
197     // make suer sp does not share kernel block
198     fInfo.flash_scratch_pad_start_blk = flash_get_blk(spAddr+FLASH_BASE);
199     if (fInfo.flash_scratch_pad_start_blk != flash_get_blk(kernelEndAddr))
200     {
201         fInfo.flash_scratch_pad_length = SP_MAX_LEN;
202         if (fInfo.flash_persistent_start_blk == fInfo.flash_scratch_pad_start_blk)  // share blk
203         {
204 #if 0 /* do not used scratch pad unless it's in its own sector */
205             printk("Scratch pad is not used for this flash part.\n");  
206             fInfo.flash_scratch_pad_length = 0;     // no sp
207 #else /* allow scratch pad to share a sector with another section such as PSI */
208             fInfo.flash_scratch_pad_number_blk = 1;
209             fInfo.flash_scratch_pad_blk_offset = fInfo.flash_persistent_blk_offset - fInfo.flash_scratch_pad_length;
210 #endif
211         }
212         else // on different blk
213         {
214             fInfo.flash_scratch_pad_number_blk = fInfo.flash_persistent_start_blk\
215                 - fInfo.flash_scratch_pad_start_blk;
216             // find out the offset in the start_blk
217             usedBlkSize = 0;
218             for (i = fInfo.flash_scratch_pad_start_blk; 
219                 i < (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk); i++)
220                 usedBlkSize += flash_get_sector_size((unsigned short) i);
221                 fInfo.flash_scratch_pad_blk_offset =  usedBlkSize - fInfo.flash_scratch_pad_length;
222         }
223     }
224     else
225     {
226         printk("No flash for scratch pad!\n");  
227         fInfo.flash_scratch_pad_length = 0;     // no sp
228     }
229
230 #if defined(DEBUG_FLASH)
231     printk("fInfo.flash_scratch_pad_start_blk = %d\n", fInfo.flash_scratch_pad_start_blk);
232     printk("fInfo.flash_scratch_pad_number_blk = %d\n", fInfo.flash_scratch_pad_number_blk);
233     printk("fInfo.flash_scratch_pad_length = 0x%x\n", fInfo.flash_scratch_pad_length);
234     printk("fInfo.flash_scratch_pad_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_scratch_pad_blk_offset);
235
236     printk("fInfo.flash_nvram_start_blk = %d\n", fInfo.flash_nvram_start_blk);
237     printk("fInfo.flash_nvram_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_nvram_blk_offset);
238     printk("fInfo.flash_nvram_number_blk = %d\n", fInfo.flash_nvram_number_blk);
239
240     printk("psi startAddr = %x\n", startAddr+FLASH_BASE);
241     printk("fInfo.flash_persistent_start_blk = %d\n", fInfo.flash_persistent_start_blk);
242     printk("fInfo.flash_persistent_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_persistent_blk_offset);
243     printk("fInfo.flash_persistent_number_blk = %d\n", fInfo.flash_persistent_number_blk);
244 #endif
245
246 }
247
248
249
250 /***********************************************************************
251  * Function Name: kerSysFlashAddrInfoGet
252  * Description  : Fills in a structure with information about the NVRAM
253  *                and persistent storage sections of flash memory.  
254  *                Fro physmap.c to mount the fs vol.
255  * Returns      : None.
256  ***********************************************************************/
257 void kerSysFlashAddrInfoGet(PFLASH_ADDR_INFO pflash_addr_info)
258 {
259     pflash_addr_info->flash_nvram_blk_offset = fInfo.flash_nvram_blk_offset;
260     pflash_addr_info->flash_nvram_length = fInfo.flash_nvram_length;
261     pflash_addr_info->flash_nvram_number_blk = fInfo.flash_nvram_number_blk;
262     pflash_addr_info->flash_nvram_start_blk = fInfo.flash_nvram_start_blk;
263     pflash_addr_info->flash_persistent_blk_offset = fInfo.flash_persistent_blk_offset;
264     pflash_addr_info->flash_persistent_length = fInfo.flash_persistent_length;
265     pflash_addr_info->flash_persistent_number_blk = fInfo.flash_persistent_number_blk;
266     pflash_addr_info->flash_persistent_start_blk = fInfo.flash_persistent_start_blk;
267 }
268
269
270 // get shared blks into *** pTempBuf *** which has to be released bye the caller!
271 // return: if pTempBuf != NULL, poits to the data with the dataSize of the buffer
272 // !NULL -- ok
273 // NULL  -- fail
274 static char *getSharedBlks(int start_blk, int end_blk)
275 {
276     int i = 0;
277     int usedBlkSize = 0;
278     int sect_size = 0;
279     char *pTempBuf = NULL;
280     char *pBuf = NULL;
281
282     for (i = start_blk; i < end_blk; i++)
283         usedBlkSize += flash_get_sector_size((unsigned short) i);
284
285 #if defined(DEBUG_FLASH)
286     printk("usedBlkSize = %d\n", usedBlkSize);
287 #endif
288
289     if ((pTempBuf = (char *) retriedKmalloc(usedBlkSize)) == NULL)
290     {
291         printk("failed to allocate memory with size: %d\n", usedBlkSize);
292         return pTempBuf;
293     }
294     
295     pBuf = pTempBuf;
296     for (i = start_blk; i < end_blk; i++)
297     {
298         sect_size = flash_get_sector_size((unsigned short) i);
299
300 #if defined(DEBUG_FLASH)
301         printk("i = %d, sect_size = %d, end_blk = %d\n", i, sect_size, end_blk);
302 #endif
303         flash_read_buf((unsigned short)i, 0, pBuf, sect_size);
304         pBuf += sect_size;
305     }
306     
307     return pTempBuf;
308 }
309
310
311
312 // Set the pTempBuf to flash from start_blk to end_blk
313 // return:
314 // 0 -- ok
315 // -1 -- fail
316 static int setSharedBlks(int start_blk, int end_blk, char *pTempBuf)
317 {
318     int i = 0;
319     int sect_size = 0;
320     int sts = 0;
321     char *pBuf = pTempBuf;
322
323     for (i = start_blk; i < end_blk; i++)
324     {
325         sect_size = flash_get_sector_size((unsigned short) i);
326         flash_sector_erase_int(i);
327         if (flash_write_buf(i, 0, pBuf, sect_size) != sect_size)
328         {
329             printk("Error writing flash sector %d.", i);
330             sts = -1;
331             break;
332         }
333         pBuf += sect_size;
334     }
335
336     return sts;
337 }
338
339
340
341 /*******************************************************************************
342  * NVRAM functions
343  *******************************************************************************/
344
345 // get nvram data
346 // return:
347 //  0 - ok
348 //  -1 - fail
349 int kerSysNvRamGet(char *string, int strLen, int offset)
350 {
351     char *pBuf = NULL;
352
353     if (!flashInitialized)
354         kerSysFlashInit();
355
356     if (strLen > NVRAM_LENGTH)
357         return -1;
358
359     if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
360         (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
361         return -1;
362
363     // get string off the memory buffer
364     memcpy(string, (pBuf + fInfo.flash_nvram_blk_offset + offset), strLen);
365
366     retriedKfree(pBuf);
367
368     return 0;
369 }
370
371
372 // set nvram 
373 // return:
374 //  0 - ok
375 //  -1 - fail
376 int kerSysNvRamSet(char *string, int strLen, int offset)
377 {
378     int sts = 0;
379     char *pBuf = NULL;
380
381     if (strLen > NVRAM_LENGTH)
382         return -1;
383
384     if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
385         (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
386         return -1;
387
388     // set string to the memory buffer
389     memcpy((pBuf + fInfo.flash_nvram_blk_offset + offset), string, strLen);
390
391     if (setSharedBlks(fInfo.flash_nvram_start_blk, 
392         (fInfo.flash_nvram_number_blk + fInfo.flash_nvram_start_blk), pBuf) != 0)
393         sts = -1;
394     
395     retriedKfree(pBuf);
396
397     return sts;
398 }
399
400
401 /***********************************************************************
402  * Function Name: kerSysEraseNvRam
403  * Description  : Erase the NVRAM storage section of flash memory.
404  * Returns      : 1 -- ok, 0 -- fail
405  ***********************************************************************/
406 int kerSysEraseNvRam(void)
407 {
408     int sts = 1;
409     char *tempStorage = retriedKmalloc(NVRAM_LENGTH);
410     
411     // just write the whole buf with '0xff' to the flash
412     if (!tempStorage)
413         sts = 0;
414     else
415     {
416         memset(tempStorage, 0xff, NVRAM_LENGTH);
417         if (kerSysNvRamSet(tempStorage, NVRAM_LENGTH, 0) != 0)
418             sts = 0;
419         retriedKfree(tempStorage);
420     }
421
422     return sts;
423 }
424
425
426 /*******************************************************************************
427  * PSI functions
428  *******************************************************************************/
429 // get psi data
430 // return:
431 //  0 - ok
432 //  -1 - fail
433 int kerSysPersistentGet(char *string, int strLen, int offset)
434 {
435     char *pBuf = NULL;
436
437     if (strLen > fInfo.flash_persistent_length)
438         return -1;
439
440     if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
441         (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
442         return -1;
443
444     // get string off the memory buffer
445     memcpy(string, (pBuf + fInfo.flash_persistent_blk_offset + offset), strLen);
446
447     retriedKfree(pBuf);
448
449     return 0;
450 }
451
452
453 // set psi 
454 // return:
455 //  0 - ok
456 //  -1 - fail
457 int kerSysPersistentSet(char *string, int strLen, int offset)
458 {
459     int sts = 0;
460     char *pBuf = NULL;
461
462     if (strLen > fInfo.flash_persistent_length)
463         return -1;
464
465     if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
466         (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
467         return -1;
468
469     // set string to the memory buffer
470     memcpy((pBuf + fInfo.flash_persistent_blk_offset + offset), string, strLen);
471
472     if (setSharedBlks(fInfo.flash_persistent_start_blk, 
473         (fInfo.flash_persistent_number_blk + fInfo.flash_persistent_start_blk), pBuf) != 0)
474         sts = -1;
475     
476     retriedKfree(pBuf);
477
478     return sts;
479 }
480
481
482 // flash bcm image 
483 // return: 
484 // 0 - ok
485 // !0 - the sector number fail to be flashed (should not be 0)
486 int kerSysBcmImageSet( int flash_start_addr, char *string, int size)
487 {
488     int sts;
489     int sect_size;
490     int blk_start;
491     int i;
492     char *pTempBuf = NULL;
493     int whole_image = 0;
494
495     blk_start = flash_get_blk(flash_start_addr);
496     if( blk_start < 0 )
497         return( -1 );
498
499     if (flash_start_addr == FLASH_BASE && size > FLASH_LENGTH_BOOT_ROM)
500         whole_image = 1;
501
502    /* write image to flash memory */
503     do 
504     {
505         sect_size = flash_get_sector_size(blk_start);
506 // NOTE: for memory problem in multiple PVC configuration, temporary get rid of kmalloc this 64K for now.
507 //        if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
508 //        {
509 //            printk("Failed to allocate memory with size: %d.  Reset the router...\n", sect_size);
510 //            kerSysMipsSoftReset();     // reset the board right away.
511 //        }
512         // for whole image, no check on psi
513         if (!whole_image && blk_start == fInfo.flash_persistent_start_blk)  // share the blk with psi
514         {
515             if (size > (sect_size - fInfo.flash_persistent_length))
516             {
517                 printk("Image is too big\n");
518                 break;          // image is too big. Can not overwrite to nvram
519             }
520             if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
521             {
522                printk("Failed to allocate memory with size: %d.  Reset the router...\n", sect_size);
523                kerSysMipsSoftReset();     // reset the board right away.
524             }
525             flash_read_buf((unsigned short)blk_start, 0, pTempBuf, sect_size);
526             if (copy_from_user((void *)pTempBuf,(void *)string, size) != 0)
527                 break;  // failed ?
528             flash_sector_erase_int(blk_start);     // erase blk before flash
529             if (flash_write_buf(blk_start, 0, pTempBuf, sect_size) == sect_size) 
530                 size = 0;   // break out and say all is ok
531             retriedKfree(pTempBuf);
532             break;
533         }
534         
535         flash_sector_erase_int(blk_start);     // erase blk before flash
536
537         if (sect_size > size) 
538         {
539             if (size & 1) 
540                 size++;
541             sect_size = size;
542         }
543         
544         if ((i = flash_write_buf(blk_start, 0, string, sect_size)) != sect_size) {
545             break;
546         }
547         blk_start++;
548         string += sect_size;
549         size -= sect_size; 
550     } while (size > 0);
551
552     if (whole_image)  
553     {
554         // If flashing a whole image, erase to end of flash.
555         int total_blks = flash_get_numsectors();
556         while( blk_start < total_blks )
557         {
558             flash_sector_erase_int(blk_start);
559             blk_start++;
560         }
561     }
562     if (pTempBuf)
563         retriedKfree(pTempBuf);
564
565     if( size == 0 ) 
566         sts = 0;  // ok
567     else  
568         sts = blk_start;    // failed to flash this sector
569
570     return sts;
571 }
572
573 /*******************************************************************************
574  * SP functions
575  *******************************************************************************/
576 // get sp data.  NOTE: memcpy work here -- not using copy_from/to_user
577 // return:
578 //  >0 - number of bytes copied to tokBuf
579 //  -1 - fail
580 int kerSysScratchPadGet(char *tokenId, char *tokBuf, int bufLen)
581 {
582     PSP_TOKEN pToken = NULL;
583     char *pBuf = NULL;
584     char *pShareBuf = NULL;
585     char *startPtr = NULL;
586     int usedLen;
587     int sts = -1;
588
589     if (fInfo.flash_scratch_pad_length == 0)
590         return sts;
591
592     if( bufLen >= (fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
593         sizeof(SP_TOKEN)) ) 
594     {
595         printk("Exceed scratch pad space by %d\n", bufLen -
596             fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
597             sizeof(SP_TOKEN));
598         return sts;
599     }
600
601     if( (pShareBuf = getSharedBlks(fInfo.flash_scratch_pad_start_blk,
602         (fInfo.flash_scratch_pad_start_blk +
603         fInfo.flash_scratch_pad_number_blk))) == NULL )
604     {
605         return sts;
606     }
607
608     // pBuf points to SP buf
609     pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;  
610
611     if(memcmp(((PSP_HEADER)pBuf)->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0) 
612     {
613         printk("Scratch pad is not initialized.\n");
614         retriedKfree(pShareBuf);
615         return sts;
616     }
617
618     // search for the token
619     usedLen = sizeof(SP_HEADER);
620     startPtr = pBuf + sizeof(SP_HEADER);
621     pToken = (PSP_TOKEN) startPtr;
622     while( pToken->tokenName[0] != '\0' && pToken->tokenLen > 0 &&
623         pToken->tokenLen < fInfo.flash_scratch_pad_length &&
624         usedLen < fInfo.flash_scratch_pad_length )
625     {
626
627         if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
628         {
629             if ( pToken->tokenLen > bufLen )
630             {
631                 printk("The length %d of token %s is greater than buffer len %d.\n", pToken->tokenLen, pToken->tokenName, bufLen);
632                 break;
633             } else             
634                 sts = pToken->tokenLen;
635             memcpy(tokBuf, startPtr + sizeof(SP_TOKEN), sts);
636             break;
637         }
638
639         usedLen += ((pToken->tokenLen + 0x03) & ~0x03);
640         startPtr += sizeof(SP_TOKEN) + ((pToken->tokenLen + 0x03) & ~0x03);
641         pToken = (PSP_TOKEN) startPtr;
642     }
643
644     retriedKfree(pShareBuf);
645
646     return sts;
647 }
648
649
650 // set sp.  NOTE: memcpy work here -- not using copy_from/to_user
651 // return:
652 //  0 - ok
653 //  -1 - fail
654 int kerSysScratchPadSet(char *tokenId, char *tokBuf, int bufLen)
655 {
656     PSP_TOKEN pToken = NULL;
657     char *pShareBuf = NULL;
658     char *pBuf = NULL;
659     SP_HEADER SPHead;
660     SP_TOKEN SPToken;
661     char *curPtr;
662     int sts = -1;
663
664     if (fInfo.flash_scratch_pad_length == 0)
665         return sts;
666
667     if( bufLen >= fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
668         sizeof(SP_TOKEN) )
669     {
670         printk("Scratch pad overflow by %d bytes.  Information not saved.\n",
671             bufLen  - fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
672             sizeof(SP_TOKEN));
673         return sts;
674     }
675
676     if( (pShareBuf = getSharedBlks( fInfo.flash_scratch_pad_start_blk,
677         (fInfo.flash_scratch_pad_start_blk +
678         fInfo.flash_scratch_pad_number_blk) )) == NULL )
679     {
680         return sts;
681     }
682
683     // pBuf points to SP buf
684     pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;  
685
686     // form header info.
687     memset((char *)&SPHead, 0, sizeof(SP_HEADER));
688     memcpy(SPHead.SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN);
689     SPHead.SPVersion = SP_VERSION;
690
691     // form token info.
692     memset((char*)&SPToken, 0, sizeof(SP_TOKEN));
693     strncpy(SPToken.tokenName, tokenId, TOKEN_NAME_LEN - 1);
694     SPToken.tokenLen = bufLen;
695
696     if(memcmp(((PSP_HEADER)pBuf)->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0)
697     {
698         // new sp, so just flash the token
699         printk("No scratch pad found.  Initialize scratch pad...\n");
700         memcpy(pBuf, (char *)&SPHead, sizeof(SP_HEADER));
701         curPtr = pBuf + sizeof(SP_HEADER);
702         memcpy(curPtr, (char *)&SPToken, sizeof(SP_TOKEN));
703         curPtr += sizeof(SP_TOKEN);
704         if( tokBuf )
705             memcpy(curPtr, tokBuf, bufLen);
706     }
707     else  
708     {
709         int putAtEnd = 1;
710         int curLen;
711         int usedLen;
712         int skipLen;
713
714         /* Calculate the used length. */
715         usedLen = sizeof(SP_HEADER);
716         curPtr = pBuf + sizeof(SP_HEADER);
717         pToken = (PSP_TOKEN) curPtr;
718         skipLen = (pToken->tokenLen + 0x03) & ~0x03;
719         while( pToken->tokenName[0] >= 'A' && pToken->tokenName[0] <= 'z' &&
720             strlen(pToken->tokenName) < TOKEN_NAME_LEN &&
721             pToken->tokenLen > 0 &&
722             pToken->tokenLen < fInfo.flash_scratch_pad_length &&
723             usedLen < fInfo.flash_scratch_pad_length )
724         {
725             usedLen += sizeof(SP_TOKEN) + skipLen;
726             curPtr += sizeof(SP_TOKEN) + skipLen;
727             pToken = (PSP_TOKEN) curPtr;
728             skipLen = (pToken->tokenLen + 0x03) & ~0x03;
729         }
730
731         if( usedLen + SPToken.tokenLen + sizeof(SP_TOKEN) >
732             fInfo.flash_scratch_pad_length )
733         {
734             printk("Scratch pad overflow by %d bytes.  Information not saved.\n",
735                 (usedLen + SPToken.tokenLen + sizeof(SP_TOKEN)) -
736                 fInfo.flash_scratch_pad_length);
737             return sts;
738         }
739
740         curPtr = pBuf + sizeof(SP_HEADER);
741         curLen = sizeof(SP_HEADER);
742         while( curLen < usedLen )
743         {
744             pToken = (PSP_TOKEN) curPtr;
745             skipLen = (pToken->tokenLen + 0x03) & ~0x03;
746             if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
747             {
748                 // The token id already exists.
749                 if( tokBuf && pToken->tokenLen == bufLen )
750                 {
751                     // The length of the new data and the existing data is the
752                     // same.  Overwrite the existing data.
753                     memcpy((curPtr+sizeof(SP_TOKEN)), tokBuf, bufLen);
754                     putAtEnd = 0;
755                 }
756                 else
757                 {
758                     // The length of the new data and the existing data is
759                     // different.  Shift the rest of the scratch pad to this
760                     // token's location and put this token's data at the end.
761                     char *nextPtr = curPtr + sizeof(SP_TOKEN) + skipLen;
762                     int copyLen = usedLen - (curLen+sizeof(SP_TOKEN) + skipLen);
763                     memcpy( curPtr, nextPtr, copyLen );
764                     memset( curPtr + copyLen, 0x00, 
765                         fInfo.flash_scratch_pad_length - (curLen + copyLen) );
766                     usedLen -= sizeof(SP_TOKEN) + skipLen;
767                 }
768                 break;
769             }
770
771             // get next token
772             curPtr += sizeof(SP_TOKEN) + skipLen;
773             curLen += sizeof(SP_TOKEN) + skipLen;
774         } // end while
775
776         if( putAtEnd )
777         {
778             if( tokBuf )
779             {
780                 memcpy( pBuf + usedLen, &SPToken, sizeof(SP_TOKEN) );
781                 memcpy( pBuf + usedLen + sizeof(SP_TOKEN), tokBuf, bufLen );
782             }
783             memcpy( pBuf, &SPHead, sizeof(SP_HEADER) );
784         }
785
786     } // else if not new sp
787
788     sts = setSharedBlks(fInfo.flash_scratch_pad_start_blk, 
789         (fInfo.flash_scratch_pad_number_blk + fInfo.flash_scratch_pad_start_blk),
790         pShareBuf);
791     
792     retriedKfree(pShareBuf);
793
794     return sts;
795
796     
797 }
798
799 // wipe out the scratchPad
800 // return:
801 //  0 - ok
802 //  -1 - fail
803 int kerSysScratchPadClearAll(void)
804
805     int sts = -1;
806     char *pShareBuf = NULL;
807     char *pBuf = NULL;
808         
809
810     if (fInfo.flash_scratch_pad_length == 0)
811         return sts;
812     if( (pShareBuf = getSharedBlks( fInfo.flash_scratch_pad_start_blk,
813         (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk) )) == NULL )
814         return sts;
815     pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;  
816     memset(pBuf, 0x00,  fInfo.flash_scratch_pad_length);
817     sts = setSharedBlks(fInfo.flash_scratch_pad_start_blk,    
818                 (fInfo.flash_scratch_pad_number_blk + fInfo.flash_scratch_pad_start_blk),  pBuf);
819
820    retriedKfree(pShareBuf);
821         
822    return sts;
823 }
824
825 int kerSysFlashSizeGet(void)
826 {
827    return flash_get_total_size();
828 }
829
830 int kerSysMemoryMappedFlashSizeGet(void)
831 {
832     return( flash_get_total_memory_mapped_size() );
833 }
834
835 unsigned long kerSysReadFromFlash( void *toaddr, unsigned long fromaddr,
836     unsigned long len )
837 {
838     int sect = flash_get_blk((int) fromaddr);
839     unsigned char *start = flash_get_memptr(sect);
840     flash_read_buf( sect, (int) fromaddr - (int) start, toaddr, len );
841
842     return( len );
843 }
844