![]() |
|
||||
Writing Device Drivers for LynxOS |
Writing Flash Memory Technology Drivers (MTDs)
Access to a linear flash device in LynxOS is implemented through a two layer model. The upper layer, flash_mgr(4), implements the user interface and encompasses all common algorithms required to access any linear flash device. This includes argument checking, memory mapping (if required) and adjustments, synchronization, and so on. The lower layer is a Memory Technology Driver (MTD), which is a device driver responsible for implementing hardware-specific details of programming a particular flash device.
The MTD does not interface directly with user applications. It interacts with the flash_mgr module, through an interface defined by a set of entry points and data structures, described in the following sections.
This two layer model provides a unified interface to any flash device and removes the need for redundant algorithms within MTD modules.
![]()
Flash Manager & MTD Overview
Cache Management
The cache of a flash device can be managed by either the MTD or flash_mgr. For a flash device with unequal segment sizes, the MTD must mange the cache. flash_mgr requires that the sector sizes beof equal size.
Interface Overview
An MTD is implemented as a character device driver. From the point of view of the device driver structure, an MTD is very simple - there are only two entry points required by the LynxOS character device interface that are used in an MTD. These are install and uninstall.
In the install routine, an MTD registers a callback routine, along with some related data, with the flash_mgr module. The callback routine is responsible for implementing a fixed set of flash memory operations for the particular flash device. flash_mgr invokes the callback routine any time there is the need to access the flash device at the physical level.
In the uninstall routine, the MTD deregisters the callback, thus notifying the flash_mgr that the MTD is no longer available for device accesses.
While there is the single flash_mgr component in the kernel, there may be multiple active (registered) MTDs, each implementing access to its own flash device. flash_mgr supports multiple opens to different flash devices and concurrent I/O operations for them. The Flash ID, passed by an MTD to flash_mgr at registration time, is used as a key for mapping application requests to a particular MTD.
The following sections provide a detailed description of the interface between the flash_mgr module and an MTD. All entry points and data structures are defined in the header file $ENV_PREFIX/sys/dheaders/flash_mtd.h.
Registering with flash_mgr
An MTD registers with flash_mgr by invoking the flash_mtd_register entry point. A pointer to the MTD registration data is passed as the only parameter to the routine.
MTD Registration Data
The MTD registration data, as passed by an MTD to flash_mgr, is described by the following data structures:
To register with flash_mgr, an MTD must fill in a structure of type flash_mtd_register_t with the registration data. The various fields in the structure should be initialized to appropriate values. Once the structure has been initialized, the MTD makes itself known to flash_mgr by calling flash_mtd_register and passing the address of the structure as the parameter. If registration is successful, flash_mtd_register returns zero. For example:
The following provides example registration code for the Intel i28F400 flash device.
Flash ID
The Flash ID is one of the most important elements of the registration data. It is an integer key used by flash_mgr to identify a particular MTD among all the MTD modules installed in the kernel. The flash ID number is also used to generate the minor number for the flash device. All flash devices use the same major number. To access a flash device, the application opens a corresponding device special file. The Flash ID is encoded into a 4 bit field within the minor device number. flash_mgr extracts it and uses it as a key to map application requests to a particular MTD module.
The following describes the minor number layout for flash device nodes:
- V specifies the verification mode. If this bit is set, driver operates in the transparent verification-on-write-and-erase mode. Otherwise, driver operates in the no-verification mode.
- P is a 3-bit field specifying the partition number. A value of 0 corresonds to the entire flash device; any other value (1 to 7) defines the partition number. The partition information is passed to flash_mgr by the MTD at the registration time.
- D is a 4-bit field specifying the Flash ID. The Flash ID can range from 0 to 15. The Flash ID is used by the flash_mgr to map a request to the corresponding MTD. MTD passes its Flash ID to flash_mgr at registration time.
The Flash ID number is chosen by the developer, and set by the MTD at registration time. A Flash ID number must be unique for each MTD configured into the kernel. The 4 bit Flash ID field in the minor number allows you to install up to 16 MTDs simultaneously, with Flash IDs ranging from 0 to 15. For an easier configuration, it is recommended that the Flash ID be copied from the device information block, as shown in the example below:
Note that once you modify the Flash ID of an MTD, you have to change the minor numbers for all corresponding device nodes accordingly. By default, special nodes for the flash devices are installed in the configuration file $ENV_PREFIX/sys/cfg/flash.cfg.
Device Info String
The info_str field is a pointer to the device information string. This is an arbitrary character string describing the flash device. flash_mgr returns this string as a part of the flash information block whenever an application issues a FLASH_GET_INFO ioctl command. The string must be contained in a nonautomatic variable. For example:
Flash Size
The size of the flash memory is passed to flash_mgr through the flash_size field. Size is specified in bytes:
Sector Size
The size of the flash device sector is passed to flash_mgr through the sector_size field. The sector size should be the smallest sector size of a device, specified in bytes:
Registration Attributes
The registration attributes are passed to flash_mgr through the mtd_attr field as a bitwise combination of the following logical flags:
The following example shows how the mtd_attr field can be initialized for the registration:
Flash Base Address
The flash_base field is used to pass the base address of the flash memory to flash_mgr. Interpretation of this field depends on whether the FLASH_MTD_ATTR_NO_MAP flag is set in the mtd_attr field.
If the flag is set, flash_mgr interprets the base address as a virtual address in the kernel memory map and relies on the entire flash memory to be already mapped into the kernel space. flash_base in this case contains a starting address of the flash memory in the virtual space. In the following example MTD uses the permap(9) kernel service to map the entire flash into the kernel space:
If the flag is not set, flash_mgr interprets the base address as a physical address of the flash memory in the system memory map. In this case, flash_mgr takes over the burden of mapping the flash memory and guarantees that whenever the MTD callback routine is invoked, part of flash memory on which the operation is executed is mapped into the kernel virtual space. The following example illustrates this approach:
Device Control Registers
An MTD is allowed to register up to three control register windows. A control register window is an address range within the flash memory that is used to access hardware control and status registers. Usually, an MTD needs to be able to access the control and status registers in order to program certain operations of the flash device (for example, flash erase).
Note that registration of control registers windows is needed only if an MTD does not use the FLASH_MTD_ATTR_NO_MAP attribute to register with the flash_mgr module. In this case flash_mgr takes over the responsibility of mapping the hardware registers and guarantees that any time the MTD callback routine is invoked, all registered control registers windows are mapped into the kernel virtual space.
Because the hardware control registers are located within the flash memory address range, there is no need to define control registers windows for an MTD that uses the FLASH_MTD_ATTR_NO_MAP attribute for the registration. As soon as the MTD creates the mapping for the entire flash memory, the control registers windows become mapped automatically.
The control registers windows are created by initializing the spec_locs array. If a window is unused, the corresponding size field should be set to zero.
The following example shows registration of two control registers windows:
Partition Information
A flash memory device can be divided in up to seven possible overlapping partitions. Unlike a conventional disk, there is no partition table or a similar partition descriptor maintained in flash memory. Instead, the partitions data is maintained in the software tables of flash_mgr on a per-device basis. Device partition information is passed by an MTD to the flash_mtd module at registration time and is effective until the MTD is deregistered.
Device partition information is passed to the flash_mgr through the parts field, which is a 7 entry table of partition descriptors. Each entry of the table contains information about one partition of the flash device. The entry with index 0 defines partition number 1, the entry with index 1 partition number 2, and so on. If an entry has the size field set to zero, the corresponding partition is undefined and cannot be accessed from user applications.
To get access to a flash partition, an application opens a corresponding device special node. The partition number is encoded as a 3 bit field into the device minor number. A value of 0 corresponds to the entire flash device; any other value (1 to 7) defines the partition number.
Other than passing the partition information to flash_mgr at the registration time, an MTD is insensitive to device partitions. Flash addresses and sector numbers passed to the MTD callback routine by flash_mgr are relative to the flash memory base.
To allow for easy partitioning of a flash device, it is recommended that the partitions information be copied from the device information block, as shown in the example below:
The user can change the device partitions by modifying the device information block and rebuilding the kernel. Shown below is a sample device block for the above example:
Callback Routine
A pointer to the callback routine is passed to flash_mgr through the callback field. Pointer to MTD specific data is passed through the user_param field. This pointer is passed back to the callback routine any time the callback is invoked by flash_mgr.
The following example shows registration of a callback routine. A pointer to the MTD statics structure is registered as the MTD specific data:
Deregistering from flash_mgr
An MTD deregisters from flash_mgr by invoking the flash_mtd_deregister entry point. The Flash ID is passed as the only parameter to the routine. For example:
Writing Callback Routines
The MTD callback routine is invoked by the flash_mgr module with the following syntax:
Operation Code
The first parameter contains an operation code, which can be any of the following:
Flash Virtual Base
The second parameter contains an address of the flash memory base in the kernel virtual space. The MTD should use it to convert relative flash addresses to absolute addresses in the kernel space. For example:
Operation Parameter
The third parameter is supplementary to the operation code parameter and contains a description of the requested operation. The following type is used:
The rw structure is used when the operation code is equal to either FLASH_MTD_REQ_READ or FLASH_MTD_REQ_WRITE. The buf pointer specifies a data buffer in memory. The area structure specifies an area in flash. Offset is relative to the flash base.
The erase structure is used when the operation code is equal to FLASH_MTD_REQ_ERASE. The start_sector field specifies the first sector to erase. The sectors_num field specifies number of sectors to erase.
The specific structure is used when the operation code is equal to FLASH_MTD_REQ_SPECIFIC. The req_code field contains an MTD-specific operation code. The req_param field is a pointer to an operation specific parameters area.
FLASH_MTD_REQ_OPEN and FLASH_MTD_REQ_CLOSE do not use this argument.
MTD-Specific Data
The fourth parameter is a pointer to the MTD specific data. flash_mgr sets this parameter to the value passed by the MTD through the user_param field of the MTD registration data.
Return Code
If an operation completes successfully, the callback routine returns zero. Any other value indicates a failure.
Synchronization
The flash_mgr layer resolves all synchronization issues prior to invoking an MTD callback routine. An MTD is guaranteed that:
- Invocation of FLASH_MTD_REQ_WRITE is delayed until the MTD has finished all operations in progress.
- Invocation of FLASH_MTD_REQ_ERASE or FLASH_MTD_REQ_ERASE_ALL is delayed until the MTD has finished all operations in progress.
- Invocation of FLASH_MTD_REQ_SPECIFIC is delayed until the MTD has finished all operations in progress.
- Invocation of FLASH_MTD_REQ_READ is delayed until the MTD has finished write, erase or device-specific operations in progress.
![]() LynuxWorks, Inc. 855 Branham Lane East San Jose, CA 95138 http://www.lynuxworks.com 1.800.255.5969 |
![]() |
![]() |
![]() |
![]() |