3.3   Writing a Socket Component Driver

At start up, TrueFFS for Tornado creates a socket component driver for each flash device you want to support on your BSP. As shown in Figure 3-1, a call to tffsDrv( ) eventually results in a call to sysTffsInit( ). This routine must do all that is necessary to register a socket component driver for each flash device attached to your embedded system.

For the most part, this means appropriating an FLSocket structure (previously allocated internally to TrueFFS for Tornado) and installing pointers to functions in your socket component driver. The details of how you handle this are up to you. Strictly speaking, there is no organization imposed on the internals of sysTffsInit( ). However, to allow for scalability, the details specific to each flash device are typically isolated to xxxRegister( ) functions, one for each flash device on your system.

Finally, your socket component driver must provide two global functions: flFitInSocketWindow( ) and flDelayLoop( ). These functions are global in the sense that they must be externally callable (and thus must not be declared as LOCAL or any other equivalent to static).

The flFitInSocketWindow( )routine returns the size (in bytes) of an individual chip in the flash array. TrueFFS uses this value to determine whether its socket window is big enough. The flDelayLoop( )routine gives TrueFFS a hardware-appropriate way to wait for a specific number of milliseconds.

3.3.1   Writing a sysTffsInit( ) Routine

The sysTffsInit( )function takes no arguments and returns void. Internally, it must, at a minimum, call the socket registration routine for each flash device you want registered. For an example of the simplest possible sysTffsInit( ), consider the sysTffsInit( )defined in the sysTffs.c for the mv177 BSP:

LOCAL void sysTffsInit (void)  
    {  
    rfaRegister ();  
    }

This BSP supports only one flash device. Thus, its sysTffsInit( ) contains only a call to rfaRegister( ), a registration routine for a resident flash array, an on-board non-removable flash device. Other BSPs define slightly more complicated sysTffsInit( ) routines. For example, the sysTffsInit( ) routine in the pc486 BSP makes three xxxRegister( ) calls:

#ifdef  INCLUDE_SOCKET_DOC  
    (void) docRegister ();                   /* Disk On Chip */  
#endif  /* INCLUDE_SOCKET_DOC */  
 
#ifdef  INCLUDE_SOCKET_PCIC0  
    (void) pcRegister (0, PC_BASE_ADRS_0);   /* flash card on socket 0 */ 
#endif  /* INCLUDE_SOCKET_PCIC0 */ 
 
#ifdef  INCLUDE_SOCKET_PCIC1 
    (void) pcRegister (1, PC_BASE_ADRS_1);   /* flash card on socket 1 */ 
#endif  /* INCLUDE_SOCKET_PCIC1 */ 

Note that each xxxRegister( ) call is encapsulated in pre-processor conditional statements. The constants that control these statements are defined in the BSP's config.h. Using these constants, you can selectively control which calls are included in sysTffsInit( ) at compile time.

3.3.2   Writing an xxxRegister( ) Routine

Internally, TrueFFS allocates an array of FLSocket structures. TrueFFS uses these structures to find the socket component driver functions (and other information) that it needs to interact with the flash hardware. Within your xxxRegister( )routine, you must appropriate one of these FLSocket structures and initialize its members appropriately. To appropriate an FLSocket structure from TrueFFS, call flSocketOf( ):

FLSocket *flSocketOf(unsigned volNo)

As input, this function expects a drive number (valid values range from 0 to 4, inclusive). Upon completion, this function returns a pointer to an FLSocket structure as its value. Consider the following code fragment:

FLSocket vol = flSocketOf (noOfDrives); 
if (noOfDrives >= DRIVES) return (flTooManyComponents); 
tffsSocket[noOfDrives] = "RFA"; 
noOfDrives++;

Both noOfDrives and tffsSocket[ ] are global. DRIVES is a symbolic constant set to the maximum number of drivers (currently 5, do not attempt to change this value). In your call to flSocketOf( ), you must use noOfDrives the global variable for the volNo parameter, and you must update it after successfully appropriating an FLSocket structure. This global variable is used internally by TrueFFS for Tornado to keep count of the flash memory logical devices it has created.

Likewise, you should update the noOfDrives element of the tffsSocket[ ] global array to contain a label for the drive you just created (this label is used in the output from the tffsShow( ) and tffsShowAll( ) routines).

After retrieving this FLSocket pointer, your xxxRegister( )routine must set the values of the following members:

window.baseAddress

cardDetected

VccOn
See VccOn.

VccOff
See VccOff.

VppOn
See VppOn.

VppOff
See VppOff.

initSocket

setWindow

setMappingContext

getAndClearCardChangeIndicator

writeProtected

freeSocket

3.3.3   Writing an flDelayLoop( )Routine( )

TrueFFS uses flDelayLoop( )to handle the timing needs of interacting with the flash hardware. The purpose of this function is simply to wait for the number of cycles requested. This function must be of the form:

void flDelayLoop(int)

For the mv177 BSP, flDelayLoop( )is defined as followed:

void flDelayLoop 
    ( 
    int cycles                  /* loop count to be consumed */ 
    ) 
    { 
        while (--cycles); 
    }

3.3.4   Writing an flFitInSocketWindow( ) Routine

TrueFFS uses flFitInSocketWindow( )to make sure that chipSize is never larger than windowSize. Your flFitInSocketWindow( ) must be of the form:

long int flFitInSocketWindow 
    ( 
    long int chipSize,          /* size of single physical chip in bytes */ 
    int      interleaving,      /* flash chip interleaving (1,2,4 etc) */ 
    long int windowSize         /* socket window size in bytes */ 
    )

If your BSP uses a sliding window or if it maps all the flash into the window, your definition for this function can simply return chipSize as its function value.

If your BSP uses a fixed window that is not large enough to map the entire flash medium into host memory, your flFitInSocketWindow( )function must compare chipSize and the windowSize. If chipSize is smaller than or equal to windowSize, this function can return chipSize as its function value. If chipSize is larger than windowSize, this function should return a size that fits within windowSize.

The MTD mapping function uses the returned value of the flFitInSocketWindow( )function to adjust the value of FLSocket.chipSize. For an example of a BSP that defines a non-trivial flFitInSocketWindow( )function, look at the mv177 BSP.