NAME | SYNOPSIS | API RESTRICTIONS | FEATURES | DESCRIPTION | ATTRIBUTES | SEE ALSO
#include <ddi/flash/flash.h>
The function or functions documented here may not be used safely in all application contexts with all APIs provided in the ChorusOS 5.0 product.
See API(5FEA) for details.
DDI
The flash device operates asynchronously, as any other device may operate asynchronously. See section Asynchronous Operation for details (at the end of this man page). Note that the synchronous operation model is mappable to the asynchronous model.
Device properties are attached to the corresponding device node in a device tree. This tree stores device nodes for all devices. The device properties supply information to drivers and upper layer files. The generic flash device is defined by its properties. An important property in the flash device node is endurance. This property defines the media of the device, which specifies that one more translation layer must be used to organize media usage.
The flash device is defined as a variable block size access device. The block access functionality defines read/write and erase access properties. These properties define the block size and alignment for each kind of functionality. For example, the read block access only allows the flash device to provide minimal functionality. All other functionality is optional. Some flash devices use an erase-on-write method. For these devices, the erase block access property must not be specified. The absence of this property indicates to the upper layers the erase-on-write settings. Note that devices such as SRAM and ROM may also export the flash device interface in order to integrate with the upper layers. The absence of the block-write property indicates to the upper layers that the medium is read-only.
In order to have write()/erase() access to the flash media, the driver may need to use the services of another driver: the flash control device driver.
The flash driver may only establish communication with a flash control driver if the board provides a service able to manage write access for flash devices. To indicate to the flash driver that the board provides this service, a property must be attached to the device node. The value of this property must indicate the path of the flash control driver in the device tree. Refer to flashCtl(9DDI) for more information about this property.
Some flash devices are mapped to memory. Such devices may be accessed (or at least read) directly. For devices that are memory mapped, the flash interface defines a variable region size with lock()/unlock() functionality. Devices which allow execution in place (XIP) should specify region-exec properties.
All other device specifics, including board mounting issues, should be handled inside the flash device driver implementation.
The character string "flash" labels the flash device class. The device clients use the device class name to obtain the driver service routines from the device registry as described in svDeviceLookup(9DKI). Note that the flash device interface specifies flash as a single thread and as a single client device. This means that only one client thread, at a any given time, may have access to the device. It is a client's responsibility to avoid re-entrance of down-calls to the driver. Usually, this is a file or block translation layer agent.
Most functions within the flash device interface are base-level methods and cannot therefore be invoked from the interrupt level. Exceptions to this are asynchronous operations (read()/write()/erase()), which may be started in the context of a device asynchronous operation handler.
The FlashOps structure specifies the interface of the flash device driver:
typedef struct FlashOps { FlashVersion version; /* version number of the Flash driver API */ KnError (*open) (FlashId dev_id, /*registry device id*/ FlashAsync* async_tbl); /*async-io handlers*/ void (*close) (FlashId dev_id); void (*mask) (FlashId dev_id); void (*unmask) (FlashId dev_id); KnError (*set_verify)(FlashIoId dev_id, Bool f_on); KnError (*lock) (FlashId dev_id, /*device id */ FlashOffset offset, /*start offset (bytes)*/ FlashSize size, /*region size in bytes*/ FlashAsyncInfo* info, /*driver will fill it*/ FlashRgnId* flash_rgn_id,/*returned by driver*/ PhAddr* rgn_addr);/* returned phys. addr*/ void (*unlock) (FlashRgnId flash_rgn_id);/*locked region id*/ KnError (*read) (FlashId dev_id, /*device id */ FlashOffset offset, /*start offset (bytes)*/ FlashSize size, /*buffer size in bytes*/ FlashBuffer buff, /*buffer address */ void* io_cookie, /*user given cookie */ FlashIoId* flash_io_id);/*returned by driver*/ KnError (*write) (FlashId dev_id, /*device id */ FlashOffset offset, /*start offset (bytes)*/ FlashSize size, /*buffer size in bytes*/ FlashBuffer buff, /*buffer address */ void* io_cookie, /*user given cookie */ FlashIoId* flash_io_id);/*returned by driver*/ KnError (*erase) (FlashId dev_id, /*device id */ FlashOffset offset, /*start offset (bytes)*/ FlashSize size, /*buffer size in bytes*/ void* io_cookie, /*user given cookie */ FlashIoId* flash_io_id);/*returned by driver*/ KnError (*erase_media) (FlashId dev_id, /*device id */ void* io_cookie, /*user given cookie */ FlashIoId* flash_io_id);/*returned by driver*/ void (*abort_io) (FlashIoId io_id); } FlashOps;
A pointer to the FlashOps structure is exported by the driver via the svDeviceRegister() microkernel call. A driver client invokes the svDeviceLookup() and svDeviceEntry() microkernel calls in order to obtain a pointer to the device service routines table. Once a pointer is obtained, the driver client is able to invoke the driver service routines (via an indirect function call).
void (*open) (FlashId dev_id, /* registery device id */ FlashAsync* async_tbl); /* async-io handlers */
This call takes the following arguments:
Specifies the Flash device identifier.
Points to the FlashAsync structure, filled with asynchronous user callback handlers for each kind of operation.
The FlashAsync structure is shown below:
typedef struct FlashAsync /* the async-io handlers for flash device*/ AsyncIoHandler read_io; /* read-async io handler*/ AsyncIoHandler write_io; /* write-async io handler*/ AsyncIoHandler erase_io; /* erase-async io handler*/ FlashAsync;
The AsyncIoHandler
type is defined in <ddi/async.h>.
The open() function identifies the device and establishes a connection between device and device client. The open() function puts the device in a masked state. The unmask() down-call should be invoked in order to obtain device functionality.
The open() function returns the following results:
The device is identified and the connection is created.
The device cannot be identified and the connection is not created.
void (*close) (FlashId dev_id); /* registery device id */
This call takes the following argument:
Specifies the Flash device identifier.
The close() function terminates work with the device. Note that all started operations must be finished or cancelled before close() is called, and the device should be put in a masked state.
void (*mask) (FlashId dev_id); /* registery device id */
This call takes the following argument:
Specifies the Flash device identifier.
The mask() function disables the invocation of the asynchronous handler.
void (*ummask) (FlashId dev_id); /* registery device id */
This call takes the following argument:
Specifies the Flash device identifier.
The unmask() function enables the invocation of the asynchronous handler.
Typically, the mask()/unmask() pair is used by the device driver client to implement a critical section of code, which must be synchronized with asynchronous handlers.
void (*set_verify) (FlashId dev_id, Bool f_on);
This call takes the following arguments:
Specifies the Flash device identifier.
Zero value disables write()/erase() verification functionality.
The set_verify() function disables or enables the write()/erase() verification functionality. Note that devices that do not have built-in hardware verification should implement software verification. The default state of verification functionality for all flash devices is "on".
The set_verify() function returns the following results:
The verification functionality was successfully switched.
The verification functionality cannot be switched off.
KnError (*lock) (FlashId dev_id, /* device id */ FlashOffset offset, /* start offset (bytes)*/ FlashSize size, /* region size in bytes*/ FlashAsyncInfo* info, /* driver will fill it */ FlashRgnId* flash_rgn_id, /* returned by driver */ PhAddr* rgn_addr); /* returned phys. addr*/
This call takes the following arguments:
Specifies the Flash device identifier.
Byte offset of the region to lock.
Size of the region to lock in bytes.
Pointer to the structure, returned by the device driver in case of error.
Region ID returned by the device driver.
Physical address of the locked region returned by the device driver.
The lock() function can only be implemented for flash media that are mapped to memory. The flash region locked in memory should be mapped into virtual space by the device driver client, according to the device node properties. The lock() function hides the media implementation and board-mounting specifics, such as banking (layers) and interleaving.
The lock() function returns the following results:
The region was successfully locked.
Another region that is already locked is blocking the lock.
An asynchronous device operation is blocking the lock.
The device is not memory mapped media.
void (*unlock) (FlashRgnId flash_rgn_id);
This call takes the following argument:
The ID of the region to be unlocked. This region must have previously been locked.
The unlock() function frees a previously locked region. The device client should not access the region directly after it has been unlocked. All regions should be unlocked before closing the device.
KnError (*read) (FlashId dev_id, /* device id */ FlashOffset offset, /* start offset (bytes)*/ FlashSize size, /* buffer size in bytes*/ FlashBuffer buff, /* buffer address */ void* io_cookie, /* user given cookie */ FlashIoId* flash_io_id); /* returned by driver*/
This call takes the following arguments:
Specifies the flash device identifier.
Byte offset of the block of media.
Size of the block to read in bytes.
Pointer to the client buffer to fill, aligned as specified by the device properties .
Device client cookie; this value is passed to the asynchronous handler.
Device I/O operation identifier; transparent to the client.
The read() function is to be implemented by all kinds of flash devices. This is a minimal common functionality for all media types. The read() function either starts an asynchronous read operation on the device or fails if the device cannot accept more operations. Parameters (size and alignment) must respect the block-read property specified for the device node.
The read() function returns the following results:
The read operation has been started on the device.
The device cannot accept more asynchronous device operations.
The offset and, or the size parameters are wrong.
KnError (*write) (FlashId dev_id, /* device id */ FlashOffset offset, /* start offset (bytes)*/ FlashSize size, /* buffer size in bytes*/ FlashBuffer buff, /* buffer address */ void* io_cookie, /* user given cookie */ FlashIoId* flash_io_id); /* returned by driver*/
This call takes the following arguments:
Specifies the flash device identifier.
Byte offset of the block of media.
Size of the block to read in bytes.
Pointer to the client buffer to fill, aligned using the device property settings.
Device client cookie; this value is passed to the asynchronous handler.
Device I/O operation identifier; transparent to the client.
The write() function either starts an asynchronous write operation on the device or fails if the device cannot accept more operations. Parameters (size and alignment) must respect the block-write property specified for the device node. The write() function should not be implemented for read-only media. If it is, however, the block-write property must not be specified in the device node.
The write() function returns the following results:
The write operation has been started on the device.
The write operation cannot be started on the device.
The device cannot accept more asynchronous device operations.
The media is non-writable.
The offset and, or the size parameters are wrong.
KnError (*erase) (FlashId dev_id, /* device id */ FlashOffset offset, /* start offset (bytes)*/ FlashSize size, /* size in bytes*/ void* io_cookie, /* user given cookie */ FlashIoId* flash_io_id); /* returned by driver*/
This call takes the following arguments:
Specifies the Flash device identifier.
Byte offset of the block of media.
Size of the block to read in bytes.
Device client cookie; this value is passed to the asynchronous handler.
Device I/O operation identifier; transparent to the client.
The erase() function either starts an asynchronous partial erase operation on the device or fails if the device cannot accept more operations. Parameters (size and alignment) must respect the block-erase property specified for the device node. The erase() function should be not be implemented for read-only, write-once or erase-on-write media. If the media is non-erasable then the block-erase property should not be specified in the device node.
The erase() function returns the following results:
The erase operation has been started on the device.
The erase operation cannot be started on the device.
The device cannot accept more asynchronous device operations.
The media is non-erasable.
The offset and, or the size parameters are wrong.
KnError (*erase_media) (FlashId dev_id, /* device id */ void* io_cookie, /* user given cookie */ FlashIoId* flash_io_id); /* returned by driver*/
This call takes the following arguments:
Specifies the flash device identifier.
Device client cookie; this value is passed to the asynchronous handler.
Device I/O operation identifier; transparent to the client.
The erase_media() function either starts a full erase operation on the device or fails if the device cannot accept more operations. This operation is rarely used and should be used only when the upper logical layer cannot recover the logical structure. Normally, all erasable devices implement this function, even if it is emulated sector by sector. This function may not be implemented for read-only, write-once or erase-on-write media. If the media is non-erasable then the block-erase property should not be specified in the device node.
The erase_media() function returns the following results:
The erase operation has been started on the device.
The device cannot accept more asynchronous device operations.
The media is non-erasable.
The offset and, or the size parameters are wrong.
void (*abort_io) (FlashIoId io_id);
This call takes the following argument:
Identifies the asynchronous operation.
The abort_io() initiates cancellation of the specified asynchronous operation. The codetextio_id must be valid. The best way to ensure this is to call this function on a previously masked device. The function returns immediately and the device driver client is notified via an asynchronous I/O handler invocation. Note that the operation may return a successful notification even after abort_io() has been called.
The driver client up-call handlers are specified in the codetextFlashAsync structure and passed to the device driver as an argument of open(). All handlers are prototyped as:
typedef enum { FLASH_ERR_OK = 0, FLASH_ERR_READ, /*read errors (internal check) */ FLASH_ERR_WRITE, /*write errors (internal check) */ FLASH_ERR_NOT_ERASED, /*attempt to write '1' over '0' */ FLASH_ERR_PROTECTED, /*attempt to write/erase protected zone */ FLASH_ERR_ERASE, /*errors on erase */ FLASH_ERR_VERIFY, /*write/erase verify errors (hard- or software)*/ FLASH_ERR_LOCKED, /*another region locks the view */ FLASH_ERR_IO, /*concurrent I/O is in progress in same area */ FLASH_ERR_POWER /*no power to perform write/erase */ } FlashIoError; typedef struct FlashAsyncInfo { /*pointed by async_info parameter in async_io*/ FlashIoError error; /*enumerated error code (see above) */ uint32_f count; /*bytes transferred (proceed) so far */ void* id; /*either FlashIoId in progress or FlashRgnId */ void* cookie;/*user given cookie for blocking io_id or rgn_id*/ } FlashAsyncInfo; typedef void (*AsyncIoHandler) (void* io_cookie, KnError async_err, FlashAsyncIoInfo async_info);
This call takes the following arguments:
Device client cookie given at the start of the operation.
An error code having one of the following values:
Operation terminated successfully.
Operation has been cancelled.
Operation failed.
additional error information, given in cases of error when not NULL, points to the FlashAsyncInfo structure.
All up-call handlers are invoked in a masked state. Only interrupt level routines are available in the context of the up-call handlers, since an asynchronous I/O handler should be treated as an interrupt. However, the device driver client may try to start more asynchronous operations from the asynchronous I/O handler.
Most devices are asynchronous; their I/O operation is initiated by the direct invocation of one of the device driver routines. This type of execution, however, can take a considerable amount of time. It is the responsibility of the device to notify the end of an operation. This would normally be via an interrupt. The device driver interrupt routine can determine whether the operation has successfully terminated or failed. Another end-condition of an operation (usually fail) is a time-out, which is also an interrupt routine invocation.
The general asynchronous I/O handler is represented as:
typedef void* AsyncIoInfo; /* device dependent information structure */ typedef void (*AsyncIoHandler) (void* io_cookie, KnError async_err, AsyncIoInfo async_info);
A device client pointer that is given on the initiation of an operation.
An error code, which may have the following values:
The operation terminated successfully.
The operation has failed for some reason. Additional error information may be returned via the async_info structure, however this is device specific.
The operation was aborted (if possible) by the cancel() driver call.
A pointer to the device specific structure, filled by the device driver.
The asynchronous I/O execution model described above raises some synchronization principles.
Each asynchronous operation initiation returns an io_id reference which is valid until the operation returns from the asynchronous operation handler. The scope of AsyncIoHandler should be treated as an interrupt handler (which is usually the case). This means that only the interrupt-level routines are available in AsyncIoHandler. The device driver ensures no re-entry in each AsyncIoHandler that is specified in the device driver interface. The content of the async_info structure remains valid until an operation returns from the handler. Some devices, however, may allow the initiation of further operations from the handler. In this case, the other operation being initiated invalidates the content of the async_info structure, as well as the io_id which may be recycled by the device driver.
See attributes(5) for descriptions of the following attributes:
ATTRIBUTE TYPE | ATTRIBUTE VALUE |
---|---|
Interface Stability | Evolving |
flashCtl(9DDI), svDeviceRegister(9DKI), svDriverRegister(9DKI), svDeviceLookup(9DKI), svDeviceEntry(9DKI), svDeviceRelease(9DKI)
NAME | SYNOPSIS | API RESTRICTIONS | FEATURES | DESCRIPTION | ATTRIBUTES | SEE ALSO