# BRCM_VERSION=3
[bcm963xx.git] / bcmdrivers / opensource / char / board / bcm963xx / impl1 / board.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  * File Name  : board.c
21  *
22  * Description: This file contains Linux character device driver entry 
23  *              for the board related ioctl calls: flash, get free kernel
24  *              page and dump kernel memory, etc.
25  *
26  * Created on :  2/20/2002  seanl:  use cfiflash.c, cfliflash.h (AMD specific)
27  *
28  ***************************************************************************/
29
30
31 /* Includes. */
32 #include <linux/init.h>
33 #include <linux/fs.h>
34 #include <linux/interrupt.h>
35 #include <linux/capability.h>
36 #include <linux/slab.h>
37 #include <linux/errno.h>
38 #include <linux/module.h>
39 #include <linux/pagemap.h>
40 #include <asm/uaccess.h>
41
42 #include <bcm_map_part.h>
43 #include <board.h>
44 #include <bcmTag.h>
45 #include "boardparms.h"
46 #include "cfiflash.h"
47
48 /* Typedefs. */
49 #if defined (NON_CONSECUTIVE_MAC)
50 // used to be the last octet. Now changed to the first 5 bits of the the forth octet
51 // to reduced the duplicated MAC addresses.
52 #define CHANGED_OCTET   3
53 #define SHIFT_BITS      3
54 #else
55 #define CHANGED_OCTET   1
56 #define SHIFT_BITS      0
57 #endif
58
59 typedef struct
60 {
61     unsigned long ulId;
62     char chInUse;
63     char chReserved[3];
64 } MAC_ADDR_INFO, *PMAC_ADDR_INFO;
65
66 typedef struct
67 {
68     unsigned long ulSdramSize;
69     unsigned long ulPsiSize;
70     unsigned long ulNumMacAddrs;
71     unsigned long ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN];
72     MAC_ADDR_INFO MacAddrs[1];
73 } NVRAM_INFO, *PNVRAM_INFO;
74
75
76 static LED_MAP_PAIR LedMapping[] =
77 {   // led name     Initial state       physical pin (ledMask)
78     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
79     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
80     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
81     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
82     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
83     {kLedEnd,       kLedStateOff,       0, 0, 0, 0}, 
84     {kLedEnd,       kLedStateOff,       0, 0, 0, 0}, 
85     {kLedEnd,       kLedStateOff,       0, 0, 0, 0} // NOTE: kLedEnd has to be at the end.
86 };
87
88 /* Externs. */
89 extern unsigned int nr_free_pages (void);
90 extern const char *get_system_type(void);
91 extern void kerSysFlashInit(void);
92 extern unsigned long get_nvram_start_addr(void);
93 extern unsigned long get_scratch_pad_start_addr(void);
94 extern unsigned long getMemorySize(void);
95 extern void __init boardLedInit(PLED_MAP_PAIR);
96 extern void boardLedCtrl(BOARD_LED_NAME, BOARD_LED_STATE);
97 extern void kerSysLedRegisterHandler( BOARD_LED_NAME ledName,
98     HANDLE_LED_FUNC ledHwFunc, int ledFailType );
99
100 /* Prototypes. */
101 void __init InitNvramInfo( void );
102 static int board_open( struct inode *inode, struct file *filp );
103 static int board_ioctl( struct inode *inode, struct file *flip,
104                         unsigned int command, unsigned long arg );
105
106 static PNVRAM_INFO g_pNvramInfo = NULL;
107 static int g_ledInitialized = 0;
108
109 static struct file_operations board_fops =
110 {
111   open:       board_open,
112   ioctl:      board_ioctl,
113 };
114
115 uint32 board_major = 0;
116
117
118 #if defined(MODULE)
119 int init_module(void)
120 {
121     return( brcm_board_init() );              
122 }
123
124 void cleanup_module(void)
125 {
126     if (MOD_IN_USE)
127         printk("brcm flash: cleanup_module failed because module is in use\n");
128     else
129         brcm_board_cleanup();
130 }
131 #endif //MODULE 
132
133
134
135 static int __init brcm_board_init( void )
136 {
137     typedef int (*BP_LED_FUNC) (unsigned short *);
138     static struct BpLedInformation
139     {
140         BOARD_LED_NAME ledName;
141         BP_LED_FUNC bpFunc;
142         BP_LED_FUNC bpFuncFail;
143     } bpLedInfo[] =
144     {{kLedAdsl, BpGetAdslLedGpio, BpGetAdslFailLedGpio},
145      {kLedWireless, BpGetWirelessLedGpio, NULL},
146      {kLedUsb, BpGetUsbLedGpio, NULL},
147      {kLedHpna, BpGetHpnaLedGpio, NULL},
148      {kLedWanData, BpGetWanDataLedGpio, NULL},
149      {kLedPPP, BpGetPppLedGpio, BpGetPppFailLedGpio},
150      {kLedVoip, BpGetVoipLedGpio, NULL},
151      {kLedEnd, NULL, NULL}
152     };
153
154     int ret;
155         
156     ret = register_chrdev(BOARD_DRV_MAJOR, "bcrmboard", &board_fops );
157     if (ret < 0)
158         printk( "brcm_board_init(major %d): fail to register device.\n",BOARD_DRV_MAJOR);
159     else 
160     {
161         PLED_MAP_PAIR pLedMap = LedMapping;
162         unsigned short gpio;
163         struct BpLedInformation *pInfo;
164
165         printk("brcmboard: brcm_board_init entry\n");
166         board_major = BOARD_DRV_MAJOR;
167         InitNvramInfo();
168
169         for( pInfo = bpLedInfo; pInfo->ledName != kLedEnd; pInfo++ )
170         {
171             if( pInfo->bpFunc && (*pInfo->bpFunc) (&gpio) == BP_SUCCESS )
172             {
173                 pLedMap->ledName = pInfo->ledName;
174                 pLedMap->ledMask = GPIO_NUM_TO_MASK(gpio);
175                 pLedMap->ledActiveLow = (gpio & BP_ACTIVE_LOW) ? 1 : 0;
176             }
177             if( pInfo->bpFuncFail && (*pInfo->bpFuncFail) (&gpio) == BP_SUCCESS )
178             {
179                 pLedMap->ledName = pInfo->ledName;
180                 pLedMap->ledMaskFail = GPIO_NUM_TO_MASK(gpio);
181                 pLedMap->ledActiveLowFail = (gpio & BP_ACTIVE_LOW) ? 1 : 0;
182             }
183             if( pLedMap->ledName != kLedEnd )
184                 pLedMap++;
185         }
186
187         boardLedInit(LedMapping);
188         g_ledInitialized = 1;
189     }
190
191     return ret;
192
193
194 void __init InitNvramInfo( void )
195 {
196     PNVRAM_DATA pNvramData = (PNVRAM_DATA) get_nvram_start_addr();
197     unsigned long ulNumMacAddrs = pNvramData->ulNumMacAddrs;
198
199     if( ulNumMacAddrs > 0 && ulNumMacAddrs <= NVRAM_MAC_COUNT_MAX )
200     {
201         unsigned long ulNvramInfoSize =
202             sizeof(NVRAM_INFO) + ((sizeof(MAC_ADDR_INFO) - 1) * ulNumMacAddrs);
203
204         g_pNvramInfo = (PNVRAM_INFO) kmalloc( ulNvramInfoSize, GFP_KERNEL );
205
206         if( g_pNvramInfo )
207         {
208             unsigned long ulPsiSize;
209             if( BpGetPsiSize( &ulPsiSize ) != BP_SUCCESS )
210                 ulPsiSize = NVRAM_PSI_DEFAULT;
211             memset( g_pNvramInfo, 0x00, ulNvramInfoSize );
212             g_pNvramInfo->ulPsiSize = ulPsiSize * 1024;
213             g_pNvramInfo->ulNumMacAddrs = pNvramData->ulNumMacAddrs;
214             memcpy( g_pNvramInfo->ucaBaseMacAddr, pNvramData->ucaBaseMacAddr,
215                 NVRAM_MAC_ADDRESS_LEN );
216             g_pNvramInfo->ulSdramSize = getMemorySize();
217         }
218         else
219             printk("ERROR - Could not allocate memory for NVRAM data\n");
220     }
221     else
222         printk("ERROR - Invalid number of MAC addresses (%ld) is configured.\n",
223             ulNumMacAddrs);
224 }
225
226 void __exit brcm_board_cleanup( void )
227 {
228     printk("brcm_board_cleanup()\n");
229
230     if (board_major != -1) 
231     {
232         unregister_chrdev(board_major, "board_ioctl");
233     }
234
235
236 static int board_open( struct inode *inode, struct file *filp )
237 {
238     return( 0 );
239
240
241
242 //**************************************************************************************
243 // Utitlities for dump memory, free kernel pages, mips soft reset, etc.
244 //**************************************************************************************
245
246 /***********************************************************************
247  * Function Name: dumpaddr
248  * Description  : Display a hex dump of the specified address.
249  ***********************************************************************/
250 void dumpaddr( unsigned char *pAddr, int nLen )
251 {
252     static char szHexChars[] = "0123456789abcdef";
253     char szLine[80];
254     char *p = szLine;
255     unsigned char ch, *q;
256     int i, j;
257     unsigned long ul;
258
259     while( nLen > 0 )
260     {
261         sprintf( szLine, "%8.8lx: ", (unsigned long) pAddr );
262         p = szLine + strlen(szLine);
263
264         for(i = 0; i < 16 && nLen > 0; i += sizeof(long), nLen -= sizeof(long))
265         {
266             ul = *(unsigned long *) &pAddr[i];
267             q = (unsigned char *) &ul;
268             for( j = 0; j < sizeof(long); j++ )
269             {
270                 *p++ = szHexChars[q[j] >> 4];
271                 *p++ = szHexChars[q[j] & 0x0f];
272                 *p++ = ' ';
273             }
274         }
275
276         for( j = 0; j < 16 - i; j++ )
277             *p++ = ' ', *p++ = ' ', *p++ = ' ';
278
279         *p++ = ' ', *p++ = ' ', *p++ = ' ';
280
281         for( j = 0; j < i; j++ )
282         {
283             ch = pAddr[j];
284             *p++ = (ch > ' ' && ch < '~') ? ch : '.';
285         }
286
287         *p++ = '\0';
288         printk( "%s\r\n", szLine );
289
290         pAddr += i;
291     }
292     printk( "\r\n" );
293 } /* dumpaddr */
294
295
296 void kerSysMipsSoftReset(void)
297 {
298 #if defined(CONFIG_BCM96348)
299     if (PERF->RevID == 0x634800A1) {
300         typedef void (*FNPTR) (void);
301         FNPTR bootaddr = (FNPTR) FLASH_BASE;
302         int i;
303
304         /* Disable interrupts. */
305         cli();
306
307         /* Reset all blocks. */
308         PERF->BlockSoftReset &= ~BSR_ALL_BLOCKS;
309         for( i = 0; i < 1000000; i++ )
310             ;
311         PERF->BlockSoftReset |= BSR_ALL_BLOCKS;
312         /* Jump to the power on address. */
313         (*bootaddr) ();
314     }
315     else
316         PERF->pll_control |= SOFT_RESET;    // soft reset mips
317 #else
318     PERF->pll_control |= SOFT_RESET;    // soft reset mips
319 #endif
320 }
321
322
323 int kerSysGetMacAddress( unsigned char *pucaMacAddr, unsigned long ulId )
324 {
325     int nRet = 0;
326     PMAC_ADDR_INFO pMai = NULL;
327     PMAC_ADDR_INFO pMaiFreeNoId = NULL;
328     PMAC_ADDR_INFO pMaiFreeId = NULL;
329     unsigned long i = 0, ulIdxNoId = 0, ulIdxId = 0, shiftedIdx = 0;
330
331     for( i = 0, pMai = g_pNvramInfo->MacAddrs; i < g_pNvramInfo->ulNumMacAddrs;
332         i++, pMai++ )
333     {
334         if( ulId == pMai->ulId || ulId == MAC_ADDRESS_ANY )
335         {
336             /* This MAC address has been used by the caller in the past. */
337             memcpy( pucaMacAddr, g_pNvramInfo->ucaBaseMacAddr,
338                 NVRAM_MAC_ADDRESS_LEN );
339             shiftedIdx = i;
340             pucaMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET] += (shiftedIdx << SHIFT_BITS);
341             pMai->chInUse = 1;
342             pMaiFreeNoId = pMaiFreeId = NULL;
343             break;
344         }
345         else
346             if( pMai->chInUse == 0 )
347             {
348                 if( pMai->ulId == 0 && pMaiFreeNoId == NULL )
349                 {
350                     /* This is an available MAC address that has never been
351                      * used.
352                      */
353                     pMaiFreeNoId = pMai;
354                     ulIdxNoId = i;
355                 }
356                 else
357                     if( pMai->ulId != 0 && pMaiFreeId == NULL )
358                     {
359                         /* This is an available MAC address that has been used
360                          * before.  Use addresses that have never been used
361                          * first, before using this one.
362                          */
363                         pMaiFreeId = pMai;
364                         ulIdxId = i;
365                     }
366             }
367     }
368
369     if( pMaiFreeNoId || pMaiFreeId )
370     {
371         /* An available MAC address was found. */
372         memcpy(pucaMacAddr, g_pNvramInfo->ucaBaseMacAddr,NVRAM_MAC_ADDRESS_LEN);
373         if( pMaiFreeNoId )
374         {
375             shiftedIdx = ulIdxNoId;
376             pucaMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET] += (shiftedIdx << SHIFT_BITS);
377             pMaiFreeNoId->ulId = ulId;
378             pMaiFreeNoId->chInUse = 1;
379         }
380         else
381         {
382             shiftedIdx = ulIdxId;
383             pucaMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET] += (shiftedIdx << SHIFT_BITS);
384             pMaiFreeId->ulId = ulId;
385             pMaiFreeId->chInUse = 1;
386         }
387     }
388     else
389         if( i == g_pNvramInfo->ulNumMacAddrs )
390             nRet = -EADDRNOTAVAIL;
391
392     return( nRet );
393 } /* kerSysGetMacAddr */
394
395 int kerSysReleaseMacAddress( unsigned char *pucaMacAddr )
396 {
397     int nRet = -EINVAL;
398     unsigned long ulIdx = 0;
399     int idx = (pucaMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET] -
400         g_pNvramInfo->ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET]);
401
402     // if overflow 255 (negitive), add 256 to have the correct index
403     if (idx < 0)
404         idx += 256;
405     ulIdx = (unsigned long) (idx >> SHIFT_BITS);
406
407     if( ulIdx < g_pNvramInfo->ulNumMacAddrs )
408     {
409         PMAC_ADDR_INFO pMai = &g_pNvramInfo->MacAddrs[ulIdx];
410         if( pMai->chInUse == 1 )
411         {
412             pMai->chInUse = 0;
413             nRet = 0;
414         }
415     }
416
417     return( nRet );
418 } /* kerSysReleaseMacAddr */
419
420 int kerSysGetSdramSize( void )
421 {
422     return( (int) g_pNvramInfo->ulSdramSize );
423 } /* kerSysGetSdramSize */
424
425
426 void kerSysLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState)
427 {
428     if (g_ledInitialized)
429       boardLedCtrl(ledName, ledState);
430 }
431
432
433 //********************************************************************************************
434 // misc. ioctl calls come to here. (flash, led, reset, kernel memory access, etc.)
435 //********************************************************************************************
436 static int board_ioctl( struct inode *inode, struct file *flip,
437                         unsigned int command, unsigned long arg )
438 {
439     int ret = 0;
440     BOARD_IOCTL_PARMS ctrlParms;
441     unsigned char ucaMacAddr[NVRAM_MAC_ADDRESS_LEN];
442     int allowedSize;
443
444     switch (command) 
445     {
446         case BOARD_IOCTL_FLASH_INIT:
447             // not used for now.  kerSysBcmImageInit();
448             break;
449
450
451         case BOARD_IOCTL_FLASH_WRITE:
452             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0)
453             {
454                 NVRAM_DATA SaveNvramData;
455                 PNVRAM_DATA pNvramData = (PNVRAM_DATA) get_nvram_start_addr();
456
457                 switch (ctrlParms.action)
458                 {
459                     case SCRATCH_PAD:
460                         ret = kerSysScratchPadSet(ctrlParms.string, ctrlParms.buf, ctrlParms.offset);
461                         break;
462
463                     case PERSISTENT:
464                         ret = kerSysPersistentSet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset);
465                         break;
466                 
467                     case NVRAM:
468                         ret = kerSysNvRamSet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset);
469                         break;
470
471                     case BCM_IMAGE_CFE:
472                         if( ctrlParms.strLen <= 0 || ctrlParms.strLen > FLASH45_LENGTH_BOOT_ROM )
473                         {
474                             printk("Illegal CFE size [%d]. Size allowed: [%d]\n",
475                                 ctrlParms.strLen, FLASH45_LENGTH_BOOT_ROM);
476                             ret = -1;
477                             break;
478                         }
479
480                         // save NVRAM data into a local structure
481                         memcpy( &SaveNvramData, pNvramData, sizeof(NVRAM_DATA) );
482
483                         // set memory type field
484                         BpGetSdramSize( (unsigned long *) &ctrlParms.string[SDRAM_TYPE_ADDRESS_OFFSET] );
485
486                         ret = kerSysBcmImageSet(ctrlParms.offset, ctrlParms.string, ctrlParms.strLen);
487
488                         // if nvram is not valid, restore the current nvram settings
489                         if( BpSetBoardId( pNvramData->szBoardId ) != BP_SUCCESS &&
490                             *(unsigned long *) pNvramData == NVRAM_DATA_ID )
491                         {
492                             kerSysNvRamSet((char *) &SaveNvramData, sizeof(SaveNvramData), 0);
493                         }
494                         break;
495                         
496                     case BCM_IMAGE_FS:
497                         allowedSize = (int) flash_get_total_size() - \
498                             FLASH_RESERVED_AT_END - TAG_LEN - FLASH45_LENGTH_BOOT_ROM;
499                         if( ctrlParms.strLen <= 0 || ctrlParms.strLen > allowedSize)
500                         {
501                             printk("Illegal root file system size [%d]. Size allowed: [%d]\n",
502                                 ctrlParms.strLen,  allowedSize);
503                             ret = -1;
504                             break;
505                         }
506                         ret = kerSysBcmImageSet(ctrlParms.offset, ctrlParms.string, ctrlParms.strLen);
507                         kerSysMipsSoftReset();
508                         break;
509
510                     case BCM_IMAGE_TECOM: //tecom: to upload image by pieces
511                                         allowedSize = (int) flash_get_total_size() - \
512                             FLASH_RESERVED_AT_END - TAG_LEN - FLASH45_LENGTH_BOOT_ROM;
513                         if( ctrlParms.strLen <= 0 || ctrlParms.strLen > allowedSize)
514                         {
515                             printk("Illegal root file system size [%d]. Size allowed: [%d]\n",
516                                 ctrlParms.strLen,  allowedSize);
517                             ret = -1;
518                             break;
519                         }
520                         ret = kerSysBcmImageSet(ctrlParms.offset, ctrlParms.string, ctrlParms.strLen);
521                         /*kerSysMipsSoftReset();*/
522                         break;
523                     
524                     case BCM_IMAGE_KERNEL:  // not used for now.
525                         break;
526                     case BCM_IMAGE_WHOLE:
527                         if(ctrlParms.strLen <= 0)
528                         {
529                             printk("Illegal flash image size [%d].\n", ctrlParms.strLen);
530                             ret = -1;
531                             break;
532                         }
533
534                         // save NVRAM data into a local structure
535                         memcpy( &SaveNvramData, pNvramData, sizeof(NVRAM_DATA) );
536
537                         ret = kerSysBcmImageSet(ctrlParms.offset, ctrlParms.string, ctrlParms.strLen);
538
539                         // if nvram is not valid, restore the current nvram settings
540                         if( BpSetBoardId( pNvramData->szBoardId ) != BP_SUCCESS &&
541                             *(unsigned long *) pNvramData == NVRAM_DATA_ID )
542                         {
543                             kerSysNvRamSet((char *) &SaveNvramData, sizeof(SaveNvramData), 0);
544                         }
545
546                         kerSysMipsSoftReset();
547                         break;
548
549                     default:
550                         ret = -EINVAL;
551                         printk("flash_ioctl_command: invalid command %d\n", ctrlParms.action);
552                         break;
553                 }
554                 ctrlParms.result = ret;
555                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
556             }
557             else
558                 ret = -EFAULT;
559             break;
560
561         case BOARD_IOCTL_FLASH_READ:
562             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
563             {
564                 switch (ctrlParms.action)
565                 {
566                     case SCRATCH_PAD:
567                         ret = kerSysScratchPadGet(ctrlParms.string, ctrlParms.buf, ctrlParms.offset);
568                         break;
569
570                     case PERSISTENT:
571                         ret = kerSysPersistentGet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset);
572                         break;
573
574                     case NVRAM:
575                         ret = kerSysNvRamGet(ctrlParms.string, ctrlParms.strLen, ctrlParms.offset);
576                         break;
577
578                     case FLASH_SIZE:
579                         ret = kerSysFlashSizeGet();
580                         break;
581
582                     default:
583                         ret = -EINVAL;
584                         printk("Not supported.  invalid command %d\n", ctrlParms.action);
585                         break;
586                 }
587                 ctrlParms.result = ret;
588                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
589             }
590             else
591                 ret = -EFAULT;
592             break;
593
594         case BOARD_IOCTL_GET_NR_PAGES:
595             ctrlParms.result = nr_free_pages() + get_page_cache_size();
596             __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
597             ret = 0;
598             break;
599
600         case BOARD_IOCTL_DUMP_ADDR:
601             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
602             {
603                 dumpaddr( (unsigned char *) ctrlParms.string, ctrlParms.strLen );
604                 ctrlParms.result = 0;
605                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
606                 ret = 0;
607             }
608             else
609                 ret = -EFAULT;
610             break;
611
612         case BOARD_IOCTL_SET_MEMORY:
613             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
614             {
615                 unsigned long  *pul = (unsigned long *)  ctrlParms.string;
616                 unsigned short *pus = (unsigned short *) ctrlParms.string;
617                 unsigned char  *puc = (unsigned char *)  ctrlParms.string;
618                 switch( ctrlParms.strLen )
619                 {
620                     case 4:
621                         *pul = (unsigned long) ctrlParms.offset;
622                         break;
623                     case 2:
624                         *pus = (unsigned short) ctrlParms.offset;
625                         break;
626                     case 1:
627                         *puc = (unsigned char) ctrlParms.offset;
628                         break;
629                 }
630                 dumpaddr( (unsigned char *) ctrlParms.string, sizeof(long) );
631                 ctrlParms.result = 0;
632                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
633                 ret = 0;
634             }
635             else
636                 ret = -EFAULT;
637             break;
638       
639         case BOARD_IOCTL_MIPS_SOFT_RESET:
640             kerSysMipsSoftReset();
641             break;
642
643         case BOARD_IOCTL_LED_CTRL:
644             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
645             {
646                     kerSysLedCtrl((BOARD_LED_NAME)ctrlParms.strLen, (BOARD_LED_STATE)ctrlParms.offset);
647                     ret = 0;
648                 }
649             break;
650
651         case BOARD_IOCTL_GET_ID:
652             if (copy_from_user((void*)&ctrlParms, (void*)arg,
653                 sizeof(ctrlParms)) == 0) 
654             {
655                 if( ctrlParms.string )
656                 {
657                     char *p = (char *) get_system_type();
658                     if( strlen(p) + 1 < ctrlParms.strLen )
659                         ctrlParms.strLen = strlen(p) + 1;
660                     __copy_to_user(ctrlParms.string, p, ctrlParms.strLen);
661                 }
662
663                 ctrlParms.result = 0;
664                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms,
665                     sizeof(BOARD_IOCTL_PARMS));
666             }
667             break;
668
669         case BOARD_IOCTL_GET_MAC_ADDRESS:
670             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
671             {
672                 ctrlParms.result = kerSysGetMacAddress( ucaMacAddr,
673                     ctrlParms.offset );
674
675                 if( ctrlParms.result == 0 )
676                 {
677                     __copy_to_user(ctrlParms.string, ucaMacAddr,
678                         sizeof(ucaMacAddr));
679                 }
680
681                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms,
682                     sizeof(BOARD_IOCTL_PARMS));
683                 ret = 0;
684             }
685             else
686                 ret = -EFAULT;
687             break;
688
689         case BOARD_IOCTL_RELEASE_MAC_ADDRESS:
690             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
691             {
692                 if (copy_from_user((void*)ucaMacAddr, (void*)ctrlParms.string, \
693                      NVRAM_MAC_ADDRESS_LEN) == 0) 
694                 {
695                     ctrlParms.result = kerSysReleaseMacAddress( ucaMacAddr );
696                 }
697                 else
698                 {
699                     ctrlParms.result = -EACCES;
700                 }
701
702                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms,
703                     sizeof(BOARD_IOCTL_PARMS));
704                 ret = 0;
705             }
706             else
707                 ret = -EFAULT;
708             break;
709
710         case BOARD_IOCTL_GET_PSI_SIZE:
711             ctrlParms.result = (int) g_pNvramInfo->ulPsiSize;
712             __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
713             ret = 0;
714             break;
715
716         case BOARD_IOCTL_GET_SDRAM_SIZE:
717             ctrlParms.result = (int) g_pNvramInfo->ulSdramSize;
718             __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
719             ret = 0;
720             break;
721
722         case BOARD_IOCTL_GET_BASE_MAC_ADDRESS:
723             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
724             {
725                 __copy_to_user(ctrlParms.string, g_pNvramInfo->ucaBaseMacAddr, NVRAM_MAC_ADDRESS_LEN);
726                 ctrlParms.result = 0;
727
728                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms,
729                     sizeof(BOARD_IOCTL_PARMS));
730                 ret = 0;
731             }
732             else
733                 ret = -EFAULT;
734             break;
735
736         case BOARD_IOCTL_GET_CHIP_ID:
737             ctrlParms.result = (int) (PERF->RevID & 0xFFFF0000) >> 16;
738             __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
739             ret = 0;
740             break;
741
742         case BOARD_IOCTL_GET_NUM_ENET: {
743             ETHERNET_MAC_INFO EnetInfos[BP_MAX_ENET_MACS];
744             int i, numeth = 0;
745             if (BpGetEthernetMacInfo(EnetInfos, BP_MAX_ENET_MACS) == BP_SUCCESS) {
746             for( i = 0; i < BP_MAX_ENET_MACS; i++) {
747                 if (EnetInfos[i].ucPhyType != BP_ENET_NO_PHY) {
748                 numeth++;
749                 }
750             }
751             ctrlParms.result = numeth;
752             __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms,  sizeof(BOARD_IOCTL_PARMS));   
753             ret = 0;
754             }
755                 else {
756                     ret = -EFAULT;
757                 }
758                 break;
759             }
760
761         case BOARD_IOCTL_GET_CFE_VER:
762             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) {
763                 char *vertag =  (char *)(FLASH_BASE + CFE_VERSION_OFFSET);
764                 if (ctrlParms.strLen < CFE_VERSION_SIZE) {
765                     ctrlParms.result = 0;
766                     __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
767                     ret = -EFAULT;
768                 }
769                 else if (strncmp(vertag, "cfe-v", 5)) { // no tag info in flash
770                     ctrlParms.result = 0;
771                     __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
772                     ret = 0;
773                 }
774                 else {
775                     ctrlParms.result = 1;
776                     __copy_to_user(ctrlParms.string, vertag+CFE_VERSION_MARK_SIZE, CFE_VERSION_SIZE);
777                     __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
778                     ret = 0;
779                 }
780             }
781             else {
782                 ret = -EFAULT;
783             }
784             break;
785
786         case BOARD_IOCTL_GET_ENET_CFG:
787             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) {
788                 ETHERNET_MAC_INFO EnetInfos[BP_MAX_ENET_MACS];
789                 int i;
790                 if (BpGetEthernetMacInfo(EnetInfos, BP_MAX_ENET_MACS) == BP_SUCCESS) {
791                     if (ctrlParms.strLen == sizeof(EnetInfos)) {
792                         __copy_to_user(ctrlParms.string, EnetInfos, sizeof(EnetInfos));
793                         ctrlParms.result = 0;
794                         __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms,      sizeof(BOARD_IOCTL_PARMS));   
795                         ret = 0;
796                     } else
797                             ret = -EFAULT;
798                 }
799                     else {
800                         ret = -EFAULT;
801                     }
802                     break;
803             }
804
805         /* Tommy, add two functions */
806         case BOARD_IOCTL_GET_GPIO:
807             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
808             {
809                 int             i;
810                 uint32  j;
811                 
812                 //GPIO 32~36
813                 if (ctrlParms.strLen >= 32)
814                 {
815                         i = ctrlParms.strLen - 32;
816                         j = GPIO->GPIOio_high;
817                 }
818                 else
819                 {
820                         i = ctrlParms.strLen;
821                         j = GPIO->GPIOio;
822                 }
823                  j = (j >> i) & 1;
824                 *ctrlParms.buf = (char) (j?1:0);
825                 ctrlParms.result = 0;
826                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
827                 ret = 0;
828             }
829             else
830                 ret = -EFAULT;
831             break;
832
833         case BOARD_IOCTL_SET_GPIO:
834             if (copy_from_user((void*)&ctrlParms, (void*)arg, sizeof(ctrlParms)) == 0) 
835             {
836                 int    i;
837                 uint32 j;
838                 
839                 //GPIO 32~36
840                 if (ctrlParms.strLen >= 32)
841                 {
842                         i = ctrlParms.strLen - 32;
843                         j = 1;
844                         GPIO->GPIODir_high |= (1 << i);         //set to R/W pin
845                         if (ctrlParms.offset)
846                                 GPIO->GPIOio_high |= (1 << i);
847                         else
848                         {
849                                 j = (1 << i) ^ 0xffffffff;
850                                 GPIO->GPIOio_high &= j;
851                         }
852                 }
853                 else    //GPIO 0~31
854                 {
855                         i = ctrlParms.strLen;
856                         j = 1;
857                         GPIO->GPIODir |= (1 << i);                              //set to R/W pin
858                         if (ctrlParms.offset)
859                                 GPIO->GPIOio |= (1 << i);
860                         else
861                         {
862                                 j = (1 << i) ^ 0xffffffff;
863                         GPIO->GPIOio &= j;
864                         }
865                 }
866                 ctrlParms.result = 0;
867                 __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
868                 ret = 0;
869             }
870             else
871                 ret = -EFAULT;
872             break;
873       
874         case BOARD_IOCTL_GET_RESET_STATUS:
875             {
876                 unsigned short gpio;
877                 unsigned long gpio_mask;
878                 volatile unsigned long *gpio_reg;
879
880                 if( BpGetPressAndHoldResetGpio( &gpio ) == BP_SUCCESS )
881                 {
882                     gpio_mask = GPIO_NUM_TO_MASK(gpio);
883                     gpio_reg = &GPIO->GPIOio;
884
885                     if( (gpio & ~BP_ACTIVE_MASK) >= 32 )
886                     {
887                         gpio_mask = GPIO_NUM_TO_MASK_HIGH(gpio);
888                         gpio_reg = &GPIO->GPIOio_high;
889                     }
890
891                     ctrlParms.result = (int) *gpio_reg & gpio_mask;
892                     __copy_to_user((BOARD_IOCTL_PARMS*)arg, &ctrlParms, sizeof(BOARD_IOCTL_PARMS));
893                     ret = 0;
894                 }
895                 else
896                     ret = -EFAULT;
897             }
898             break;
899       
900         default:
901             ret = -EINVAL;
902             ctrlParms.result = 0;
903             printk("board_ioctl: invalid command %x, cmd %d .\n",command,_IOC_NR(command));
904             break;
905
906   } /* switch */
907
908   return (ret);
909
910 } /* board_ioctl */
911
912
913 /***************************************************************************
914  * MACRO to call driver initialization and cleanup functions.
915  ***************************************************************************/
916 module_init( brcm_board_init );
917 module_exit( brcm_board_cleanup );
918
919 EXPORT_SYMBOL(kerSysNvRamGet);
920 EXPORT_SYMBOL(dumpaddr);
921 EXPORT_SYMBOL(kerSysGetMacAddress);
922 EXPORT_SYMBOL(kerSysReleaseMacAddress);
923 EXPORT_SYMBOL(kerSysGetSdramSize);
924 EXPORT_SYMBOL(kerSysLedCtrl);
925 EXPORT_SYMBOL(kerSysLedRegisterHwHandler);
926 EXPORT_SYMBOL(BpGetBoardIds);
927 EXPORT_SYMBOL(BpGetSdramSize);
928 EXPORT_SYMBOL(BpGetPsiSize);
929 EXPORT_SYMBOL(BpGetEthernetMacInfo);
930 EXPORT_SYMBOL(BpGetRj11InnerOuterPairGpios);
931 EXPORT_SYMBOL(BpGetPressAndHoldResetGpio);
932 EXPORT_SYMBOL(BpGetVoipResetGpio);
933 EXPORT_SYMBOL(BpGetVoipIntrGpio);
934 EXPORT_SYMBOL(BpGetPcmciaResetGpio);
935 EXPORT_SYMBOL(BpGetRtsCtsUartGpios);
936 EXPORT_SYMBOL(BpGetAdslLedGpio);
937 EXPORT_SYMBOL(BpGetAdslFailLedGpio);
938 EXPORT_SYMBOL(BpGetWirelessLedGpio);
939 EXPORT_SYMBOL(BpGetUsbLedGpio);
940 EXPORT_SYMBOL(BpGetHpnaLedGpio);
941 EXPORT_SYMBOL(BpGetWanDataLedGpio);
942 EXPORT_SYMBOL(BpGetPppLedGpio);
943 EXPORT_SYMBOL(BpGetPppFailLedGpio);
944 EXPORT_SYMBOL(BpGetVoipLedGpio);
945 EXPORT_SYMBOL(BpGetWirelessExtIntr);
946 EXPORT_SYMBOL(BpGetAdslDyingGaspExtIntr);
947 EXPORT_SYMBOL(BpGetVoipExtIntr);
948 EXPORT_SYMBOL(BpGetHpnaExtIntr);
949 EXPORT_SYMBOL(BpGetHpnaChipSelect);
950 EXPORT_SYMBOL(BpGetVoipChipSelect);
951