Device management functions manage device drivers running on μT-Kernel.
A device driver is a program that is implemented independent from μT-Kernel itself to control a hardware device or perform I/O processing with the hardware device. Since the difference of specifications among individual devices is absorbed by the device driver when an application or middleware operates a device or performs I/O processing with the device via the device driver, the application or middleware can enhance its hardware independence and compatibility.
Device management functions include a function to define a device driver, or to register the device driver to μT-Kernel, and a function to use the registered device driver from an application or middleware.
While this registration of device drivers is mostly performed in the initialization at system startup, it can also be performed dynamically during the normal operation of the system. A device driver is registered in the device registration information (ddev
) that is one of parameters for the API, tk_def_dev, by specifying the set of functions (driver processing functions) of a program that actually implements device driver. These functions include the open function (openfn) that is called when a device is opened, the execute function (execfn) that is called when read or write processing starts, wait-for-completion function (waitfn) that waits for completion of read or write processing, etc. The actual operation of a device or I/O processing with the devices are performed in these driver processing functions.
As these driver execute functions are executed at protection level 0 as quasi-task portion, they can also access hardware directly. I/O processing with a device may be performed directly in these driver execute functions or may be performed in another task that runs based on the request from one of these driver execute functions. The specification of parameters, etc. when these driver execute functions are called is defined as part of the device driver interface. The device driver interface is an interface between a device driver and the μT-Kernel device management functions.
When a device driver program is implemented, it is recommended to separate three layers of interface, logical, and physical layers carefully in order to enhance their maintainability and portability. The interface layer is responsible for implementing an interface between the μT-Kernel device management functions and a device driver. The logical layer is responsible for performing a common processing according to the type of device. The physical layer is responsible for performing an operation dependent on the actual hardware or control chip. The interface specification, however, among the interface layer, logical layer, and physical layer is not specified in the μT-Kernel, so that the actual layer separation can be implemented appropriately in each device driver. Programs that process the interface layer may be provided as libraries since there are many common processing steps that are independent of individual devices in the physical layer.
APIs are provided such as open (tk_opn_dev), close (tk_cls_dev), read (tk_rea_dev), write (tk_wri_dev), etc. to use the registered device driver from an application or middleware. The specification of these APIs is called an application interface. For example, when an application executes tk_opn_dev to open a device, the μT-Kernel calls the open function (openfn) for the corresponding device driver to request the device open processing.
The positioning and structure of μT-Kernel device management functions are shown in Figure 1.
Additional Notes | |
---|---|
The device drivers have common features with the subsystems as being implemented independent from μT-Kernel itself and also being a system program to add or extend functions for μT-Kernel. Additionally, both are also same in that they operate at protection level 0, and can access a hardware. Notable differences between the two, is that while API for calling a device driver is limited to using open/close and read/write type, API for calling a subsystem can be defined without any restriction. Though μT-Kernel device drivers managed by device management functions are assumed to be drivers for physical devices or hardware, they are not necessarily required to handle real physical devices or hardware. Also, system program for operating a device could be implemented as a subsystem rather than a device driver if it is not compatible with open/close or read/write type APIs. |
In addition to a physical device that represents a device as a physical hardware, there is a logical device that represents a perceived unit of a device from the viewpoint of software.
Although both devices match for most devices, when partitions were created on a hard disk or any other storage type device (SD card, USB storage, etc.), entire device represents a physical device and each partition represents a logical device.
The physical devices of same type are identified by "unit" while logical devices in one physical device are identified by "subunit." For example, the information that distinguishes the first hard disk from the second is called "unit," and the information that distinguishes the first partition from the second within that first hard disk is called "subunit."
The data definitions used in device management functions are explained in the subsequent subsections.
In the following description, the references and mentions are made to particular types of devices and their names. These are not meant to be the part of μT-Kernel specification, but rather are offered as a common guideline for defining device driver specifications. Each device driver does not have to implement all the functions described here. However, each driver should be designed so that their behavior is compliant with the description in the following if applicable.
A device name is a string of up to eight characters that is given to each device. US-ASCII is the used character code. It consists of the following elements:
#define L_DEVNM 8 /* Device name length */
Name indicating the device type
Characters a to z and A to Z can be used.
One letter indicating a physical device
Each unit is assigned a letter from a to z in order starting from a.
One to three digits indicating a logical device
Each subunit is assigned a number from 0 to 254 in order starting from 0.
Device names take the format of type + unit + subunit. Some devices may not have a unit or subunit, in which case the corresponding field is omitted.
The subunit is usually used to distinguish partitions in a hard disk. In other devices also, it can be used to create multiple logical devices in one physical device.
A name consisting of type + unit is called a physical device name. A name consisting of type + unit + subunit is called a logical device name. If there is no subunit, the physical device name and logical device name are identical. The term "device name" by itself means the logical device name.
By registering a device (device driver) with μT-Kernel/SM, a device ID (> 0) is assigned to the device (physical device name). Device IDs are assigned to each physical device. The device ID of a logical device consists of the device ID assigned to the physical device to which is appended the subunit number + 1 (1 to 255).
devid: The device ID assigned at device registration devid Physical device devid + n+1 The nth subunit (logical device)
Device attributes are defined in order to represent a feature for each device and classify a device for each type. Device attributes should be specified when registering a device driver.
The specification method of device attributes is as follows:
IIII IIII IIII IIII PRxx xxxx KKKK KKKK
The high 16 bits are device-dependent attributes defined for each device. The low 16 bits are standard attributes defined as follows.
#define TD_PROTECT 0x8000 /* P: Write protected */ #define TD_REMOVABLE 0x4000 /* R: removable media */ #define TD_DEVKIND 0x00ff /* K: device/media kind */ #define TD_DEVTYPE 0x00f0 /* device type */ /* device type */ #define TDK_UNDEF 0x0000 /* undefined/unknown */ #define TDK_DISK 0x0010 /* disk device */
Within the realm of μT-Kernel, the device type other than disk type is not defined. Defining the device type other than disk type does not affect the behavior of μT-Kernel. Other devices are assigned to undefined type (TDK_UNDEF).
For the disk device, the disk kinds are additionally defined. The typical disk kinds are as follows:
/* disk kind */ #define TDK_DISK_UNDEF 0x0010 /* miscellaneous disk */ #define TDK_DISK_RAM 0x0011 /* RAM disk (used as main memory) */ #define TDK_DISK_ROM 0x0012 /* ROM disk (used as main memory) */ #define TDK_DISK_FLA 0x0013 /* Flash ROM or other silicon disk */ #define TDK_DISK_FD 0x0014 /* Floppy disk */ #define TDK_DISK_HD 0x0015 /* hard disk */ #define TDK_DISK_CDROM 0x0016 /* CD-ROM */
The definition of disk kinds does not affect the μT-Kernel behavior. These definitions are used only when they are required in a device driver or an application. For example, when an application must change its processing according to the kind of devices or media, the disk kind information is used. Devices or media that do not need such distinctions do not have to be assigned a device type.
A device descriptor is an identifier used to access a device.
The device descriptor is assigned a positive value (> 0) by the μT-Kernel/SM when a device is opened.
When an I/O request is made to a device, a request ID (> 0) is assigned identifying the request. This ID can be used to wait for I/O completion.
Data input/output from/to device is specified by a data number. Data is roughly classified into device-specific data and attribute data.
As device-specific data, the data numbers are defined separately for each device.
Attribute data specifies driver or device state acquisition and setting modes, and special functions, etc.
Data numbers common to devices are defined, but device-dependent attribute data can also be defined. For more details, see the Section called Attribute Data.
Attribute data are classified broadly into the following three types of data.
Attributes defined in common for all devices (device drivers).
Attributes defined in common for devices (device drivers) of the same kind.
Attributes defined individually for each device (device driver).
Device kind attributes and device-specific attributes are out of scope of this specification and defined in device driver's specifications. Only the common attributes are defined here.
Common attributes are assigned attribute data numbers in the range from -1 to -99. While common attribute data numbers are the same for all devices, not all devices necessarily support all the common attributes. If an unsupported data number is specified, error code E_PAR is returned.
The definition of common attributes is as follows:
#define TDN_EVENT (-1) /* RW: event notification message buffer ID */ #define TDN_DISKINFO (-2) /* R: disk information */ #define TDN_DISPSPEC (-3) /* reserved */ #define TDN_PCMCIAINFO (-4) /* reserved */ #define TDN_DISKINFO_D (-5) /* R: disk information (64-bit device) */
RW: read (tk_rea_dev)/write (tk_wri_dev) enabled |
R-: read (tk_rea_dev) only |
Event notification message buffer ID
The ID of the message buffer used for device event notification.
As a device is registered by tk_def_dev when a device driver is started and the system default event notification message buffer ID (evtmbfid
) is returned as this API return parameter, the value is held in the device driver and is used as the initial value of this attribute data.
If 0 is set, device events are not notified. For device event notification, see the Section called Device Event Notification.
32-bit device and disk information
typedef enum { DiskFmt_STD = 0, /* standard (HD, etc.) */ DiskFmt_CDROM = 4 /* CD-ROM 640MB */ } DiskFormat;
typedef struct { DiskFormat format; /* format */ UW protect:1; /* protected status */ UW removable:1; /* removable */ UW rsv:30; /* reserved (always 0) */ W blocksize; /* block size in bytes */ W blockcont; /* total block count */ } DiskInfo;
For definition of DiskFormat other than the above description, see the specification related to device drivers.
Display Device Specification
For the definition of DEV_SPEC, see the specification related to device drivers.
64-bit device and disk information
typedef struct diskinfo_d { DiskFormat format; /* format */ BOOL protect:1; /* protected status */ BOOL removable:1; /* removable */ UW rsv:30; /* reserved (0) */ W blocksize; /* block size in bytes */ D blockcont_d; /* total number of blocks in 64-bit */ } DiskInfo_D;
Difference between DiskInfo_D and DiskInfo is only the part of their names being blockcont
or blockcont_d
, and the data type.
μT-Kernel/SM does not convert a data between DiskInfo and DiskInfo_D. TDN_DISKINFO and TDN_DISKINFO_D just pass the request to device driver without any modification.
The disk device driver must support one of TDN_DISKINFO and TDN_DISKINFO_D, or both. It is recommended that TDN_DISKINFO is supported wherever possible.
Even if the total number of blocks of entire disk exceeds W, the number of blocks of individual partition may fit within W. In that case, the preferable implementation is such that a partitions fitting within W correspond to TDN_DISKINFO and partitions not fitting within W are determined to be an error (E_PAR) by TDN_DISKINFO. It is also preferable that TDN_DISKINFO_D is supported even if the number of blocks fit within W.
There is no direct dependency between the support for TDN_DISKINFO_D and the device driver attribute TDA_DEV_D. A device driver does not always have TDA_DEV_D attribute even if TDN_DISKINFO_D is supported. Also, TDN_DISKINFO_D is not always supported even if the device driver has TDA_DEV_D attribute.
As the definition of common attributes described above is a part of the specification of device driver rather than μT-Kernel, it does not directly affect the μT-Kernel behavior. Each device driver does not need to implement all the functions defined in the common attributes. However, as the definition of common attributes is applicable to all the device drivers, the specification of each device driver must be specified in a way that does not conflict with these definitions.
The application interface is used to make use of the registered device drivers from an application or middleware. API of μT-Kernel provides the following functions. These functions cannot be called from a task-independent portion or while dispatch or interrupts are disabled (E_CTX).
ID tk_opn_dev( CONST UB *devnm, UINT omode ) ER tk_cls_dev( ID dd, UINT option ) ID tk_rea_dev( ID dd, W start, void *buf, SZ size, TMO tmout ) ID tk_rea_dev_du( ID dd, D start_d, void *buf, SZ size, TMO_U tmout_u ) ER tk_srea_dev( ID dd, W start, void *buf, SZ size, SZ *asize ) ER tk_srea_dev_d( ID dd, D start_d, void *buf, SZ size, SZ *asize ) ID tk_wri_dev( ID dd, W start, CONST void *buf, SZ size, TMO tmout ) ID tk_wri_dev_du( ID dd, D start_d, CONST void *buf, SZ size, TMO_U tmout_u ) ER tk_swri_dev( ID dd, W start, CONST void *buf, SZ size, SZ *asize ) ER tk_swri_dev_d( ID dd, D start_d, CONST void *buf, SZ size, SZ *asize ) ID tk_wai_dev( ID dd, ID reqid, SZ *asize, ER *ioer, TMO tmout ) ID tk_wai_dev_u( ID dd, ID reqid, SZ *asize, ER *ioer, TMO_U tmout_u ) INT tk_sus_dev( UINT mode ) ID tk_get_dev( ID devid, UB *devnm ) ID tk_ref_dev( CONST UB *devnm, T_RDEV *rdev ) ID tk_oref_dev( ID dd, T_RDEV *rdev ) INT tk_lst_dev( T_LDEV *ldev, INT start, INT ndev ) INT tk_evt_dev( ID devid, INT evttyp, void *evtinf )
Opens the device specified in devnm
in the mode specified in omode
, and prepares for device access. The device descriptor is passed in the return code.
omode := (TD_READ || TD_WRITE || TD_UPDATE) | [TD_EXCL || TD_WEXCL || TD_REXCL]
#define TD_READ 0x0001 /* read only */ #define TD_WRITE 0x0002 /* write only */ #define TD_UPDATE 0x0003 /* read/write */ #define TD_EXCL 0x0100 /* exclusive */ #define TD_WEXCL 0x0200 /* exclusive write */ #define TD_REXCL 0x0400 /* exclusive read */
read only
Write only
Read/write
Sets the access mode.
When TD_READ is set, tk_wri_dev cannot be used.
When TD_WRITE is set, tk_rea_dev cannot be used.
Exclusive
Exclusive write
Exclusive read
Sets the exclusive mode.
When TD_EXCL is set, all concurrent opening is prohibited.
When TD_WEXCL is set, concurrent opening in write mode (TD_WRITE or TD_UPDATE) is prohibited.
When TD_REXCL is set, concurrent opening in read mode (TD_READ or TD_UPDATE) is prohibited.
Table 1. Whether Concurrent Open of Same Device is Allowed or NOT
Present Open Mode | Concurrent Open Mode | ||||||||||||
No exclusive mode | TD_WEXCL | TD_REXCL | TD_EXCL | ||||||||||
R | U | W | R | U | W | R | U | W | R | U | W | ||
No exclusive mode | R | YES | YES | YES | YES | YES | YES | NO | NO | NO | NO | NO | NO |
U | YES | YES | YES | NO | NO | NO | NO | NO | NO | NO | NO | NO | |
W | YES | YES | YES | NO | NO | NO | YES | YES | YES | NO | NO | NO | |
TD_WEXCL | R | YES | NO | NO | YES | NO | NO | NO | NO | NO | NO | NO | NO |
U | YES | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | |
W | YES | NO | NO | NO | NO | NO | YES | NO | NO | NO | NO | NO | |
TD_REXCL | R | NO | NO | YES | NO | NO | YES | NO | NO | NO | NO | NO | NO |
U | NO | NO | YES | NO | NO | NO | NO | NO | NO | NO | NO | NO | |
W | NO | NO | YES | NO | NO | NO | NO | NO | YES | NO | NO | NO | |
TD_EXCL | R | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO |
U | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | |
W | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO | NO |
R = TD_READ W = TD_WRITE U = TD_UPDATE YES = Yes, can be opened NO = No, cannot be opened (E_BUSY)
When a physical device is opened, the logical devices belonging to it are all treated as having been opened in the same mode, and are processed as exclusive open.
Closes device descriptor dd
. If a request is being processed, the processing is aborted and the device is closed.
option := [TD_EJECT]
#define TD_EJECT 0x0001 /* Eject media */
Eject media
If the same device has not been opened by another task, the media is ejected. In the case of devices that cannot eject their media, the request is ignored.
Initiates reading device-specific data or attribute data from the specified device. This function initiates reading only, returning to its caller without waiting for the read operation to finish. The space specified in buf
must be retained until the read operation completes. Read completion is waited for by tk_wai_dev. The time required for initiating read operation differs among device drivers; return of control is not necessarily immediate.
In the case of device-specific data, the start
and size
units are defined for each device. With attribute data, start
is an attribute data number and size
is in bytes. The attribute data of the data number specified in start
is read. Normally size
must be at least as large as the size of the attribute data to be read. Reading of multiple attribute data in one operation is not possible. When size
= 0 is specified, actual reading does not take place but the current size of data that can be read is checked.
Whether or not a new request can be accepted while a read or write operation is in progress depends on the device driver. If a new request cannot be accepted, the request is queued. The timeout for request waiting is set in tmout
. The TMO_POL or TMO_FEVR attribute can be specified in tmout
. Note that the timeout applies to the request acceptance. Once a request has been accepted, this function does not time out.
It is permissible to call this API to a driver that has TDA_DEV_D or TDA_TMO_U attribute. In that case, the parameters are converted appropriately by μT-Kernel/SM. For example, if the device driver has TDA_TMO_U attribute, the timeout interval (milliseconds) specified in tmout
of this API is converted to time in microseconds, and then passed to the driver with TDA_TMO_U attribute.
Only when all the service profile items below are set to be effective, this API can be used.
This API takes the parameters start_d
(64 bits) and tmout_u
(64-bit microseconds), instead of the parameters start
and tmout
of tk_rea_dev.
Its specification is the same as that of tk_rea_dev, except that the parameters are changed to start_d
and tmout_u
. For more details, see the description of tk_rea_dev.
If the corresponding device driver does not have the TDA_DEV_D attribute, the error code E_PAR is returned when specifying a value that is out of the range of W for the start position start_d
.
If the corresponding device driver does not have the TDA_TMO_U attribute (does not supports microseconds), it cannot handle the timeout in microseconds. In that case, the timeout (in microseconds) specified by this API in tmout_u
is rounded to the time in milliseconds and passed to the device driver.
Thus, the appropriate conversion of parameters is executed by μT-Kernel/SM. The application does not have to know whether the device driver has the TDA_DEV_D attribute or not, i.e. whether the device driver supports 64 bits or not.
Synchronous read. This is equivalent to the following.
ER tk_srea_dev( ID dd, W start, void *buf, SZ size, SZ *asize ) { ER er, ioer; er = tk_rea_dev(dd, start, buf, size, TMO_FEVR); if ( er > 0 ) { er = tk_wai_dev(dd, er, asize, &ioer, TMO_FEVR); if ( er > 0 ) er = ioer; } return er; }
This API can be used for a device driver that has the TDA_DEV_D attribute. In that case, the parameters are converted appropriately by μT-Kernel/SM.
Only when all the service profile items below are set to be effective, this API can be used.
This API takes the 64-bit parameter start_d
, instead of the parameter start
of tk_srea_dev.
Its specification is the same as that of tk_srea_dev, except that the parameter is changed to start_d
. For more details, see the description of tk_srea_dev.
If the corresponding device driver does not have the TDA_DEV_D attribute, the error code E_PAR is returned when specifying a value that is out of the range of W for the start position start_d
.
Thus, the appropriate conversion of parameters is executed by μT-Kernel/SM. The application does not have to know whether the device driver has the TDA_DEV_D attribute or not, i.e. whether the device driver supports 64 bits or not.
Initiates writing device-specific data or attribute data to a device. This function initiates writing only, returning to its caller without waiting for the write operation to finish. The space specified in buf
must be retained until the write operation completes. Write completion is waited for by tk_wai_dev. The time required for initiating write operation differs among device drivers; return of control is not necessarily immediate.
In the case of device-specific data, the start
and size
units are defined for each device. With attribute data, start
is an attribute data number and size
is in bytes. The attribute data of the data number specified in start
is written. Normally size
must be at least as large as the size of the attribute data to be written. Multiple attribute data cannot be written in one operation. When size
= 0 is specified, actual writing does not take place but the current size of data that can be written is checked.
Whether or not a new request can be accepted while a read or write operation is in progress depends on the device driver. If a new request cannot be accepted, the request is queued. The timeout for request waiting is set in tmout
. The TMO_POL or TMO_FEVR attribute can be specified in tmout
. Note that the timeout applies to the request acceptance. Once a request has been accepted, this function does not time out.
It is permissible to call this API to a driver that has TDA_DEV_D or TDA_TMO_U attribute. In that case, the parameters are converted appropriately by μT-Kernel/SM. For example, if the device driver has TDA_TMO_U attribute, the timeout interval ( milliseconds) specified in tmout
of this API is converted to time in microseconds, and then passed to the driver with TDA_TMO_U attribute.
ID |
dd
| Device Descriptor | Device descriptor |
D |
start_d
| Start Location | Write start location (64 bit, ≧ 0: Device-specific data, < 0: Attribute data) |
CONST void* |
buf
| Buffer | Buffer holding data to be written |
SZ |
size
| Write Size | Size of data to be written |
TMO_U |
tmout_u
| Timeout | Request acceptance timeout (in microseconds) |
Only when all the service profile items below are set to be effective, this API can be used.
This API takes the parameters start_d
(64 bits) and tmout_u
(64-bit microseconds), instead of the parameters start
and tmout
of tk_wri_dev.
Its specification is the same as that of tk_wri_dev, except that the parameters are changed to start_d
and tmout_u
. For more details, see the description of tk_wri_dev.
If the corresponding device driver does not have the TDA_DEV_D attribute, the error code E_PAR is returned when specifying a value that is out of the range of W for the start position start_d
.
If the corresponding device driver does not have the TDA_TMO_U attribute (does not supports microseconds), it cannot handle the timeout in microseconds. In that case, the timeout (in microseconds) specified by this API in tmout_u
is rounded to the time in milliseconds and passed to the device driver.
Thus, the appropriate conversion of parameters is executed by μT-Kernel/SM. The application does not have to know whether the device driver has the TDA_DEV_D attribute or not, i.e. whether the device driver supports 64 bits or not.
Synchronous write. This is equivalent to the following.
ER tk_swri_dev( ID dd, W start, void *buf, SZ size, SZ *asize ) { ER er, ioer; er = tk_wri_dev(dd, start, buf, size, TMO_FEVR); if ( er > 0 ) { er = tk_wai_dev(dd, er, asize, &ioer, TMO_FEVR); if ( er > 0 ) er = ioer; } return er; }
This API can be used for a device driver that has the TDA_DEV_D attribute. In that case, the parameters are converted appropriately by μT-Kernel/SM.
ID |
dd
| Device Descriptor | Device descriptor |
D |
start_d
| Start Location | Write start location (64 bit, ≧ 0: Device-specific data, < 0: Attribute data) |
CONST void* |
buf
| Buffer | Buffer holding data to be written |
SZ |
size
| Write Size | Size of data to be written |
SZ* |
asize
| Actual Size | Pointer to the area to return the written size |
Only when all the service profile items below are set to be effective, this API can be used.
This API takes the 64-bit parameter start_d
, instead of the parameter start
of tk_swri_dev.
Its specification is the same as that of tk_swri_dev, except that the parameter is changed to start_d
. For more details, see the description of tk_swri_dev.
If the corresponding device driver does not have the TDA_DEV_D attribute, the error code E_PAR is returned when specifying a value that is out of the range of W for the start position start_d
.
Thus, the appropriate conversion of parameters is executed by μT-Kernel/SM. The application does not have to know whether the device driver has the TDA_DEV_D attribute or not, i.e. whether the device driver supports 64 bits or not.
E_ID | dd is invalid or not opened, or reqid is invalid or not a request for dd |
E_OBJ | Another task is already waiting for request reqid |
E_NOEXS | No requests are being processed (only when reqid = 0) |
E_TMOUT | Timeout (processing continues) |
E_ABORT | Processing aborted |
Other | Error code returned by device driver |
Waits for completion of request reqid
for device dd
. If reqid
= 0 is set, this function waits for completion of any pending request to dd
. This function waits for completion only of requests currently processing when the function is called. A request issued after tk_wai_dev was called is not waited for.
When multiple requests are being processed concurrently, the order of their completion is not necessarily the same as the order of request but is dependent on the device driver. Processing is, however, guaranteed to be performed in a sequence such that the result is consistent with the order of requesting. When processing a read operation from a disk, for example, the sequence might be changed as follows.
1 4 3 2 5
1 2 3 4 5
Disk access can be made more efficient by changing the sequence as above with the aim of reducing seek time and spin wait time.
The timeout for waiting for completion is set in tmout
. The TMO_POL or TMO_FEVR attribute can be specified for tmout
. If a timeout error is returned (E_TMOUT), tk_wai_dev must be called again to wait for completion since the request processing is still ongoing. When reqid
> 0 and tmout
= TMO_FEVR are both set, the processing must be completed without timing out.
If the device driver returns a processing result error (such as I/O error) for the requested processing, the error code is stored in ioer
instead of the return code. Specifically, the error code, which is stored in error
of the request packet T_DEVREQ by the wait-for-completion function (waitfn) called for processing tk_wai_dev, is returned to ioer
as the processing result error.
On the other hand, the return code is used for errors when the wait request itself was not handled properly. When error is passed in the return code, ioer
has no meaning. Note also that if an error is passed in the return code, tk_wai_dev must be called again to wait for completion since the processing is still ongoing. For more details, see the Section called waitfn - Wait-for-completion function.
If a task exception is raised during completion waiting by tk_wai_dev, the request in reqid
is aborted and processing is completed. The result of aborting the requested processing is dependent on the device driver. When reqid
= 0 was set, however, requests are not aborted but are treated as timeout. In this case E_ABORT rather than E_TMOUT is returned.
It is not possible for multiple tasks to wait for completion of the same request ID at the same time. If there is a task waiting for request completion with reqid
= 0 set, another task cannot wait for completion for the same dd
. Similarly, if there is a task waiting for request completion with reqid
> 0 set, another task cannot wait for completion specifying reqid
= 0.
It is permissible to call this API to a driver with TDA_TMO_U attribute In such instances, μT-Kernel/SM converts the parameter(s) appropriately. For example, if the device driver has TDA_TMO_Uattribute, the timeout in milliseconds specified in tmout
of this API is converted to timeout value in microseconds, and is passed to the driver with TDA_TMO_U.
E_ID | dd is invalid or not opened, or reqid is invalid or not a request for dd |
E_OBJ | Another task is already waiting for request reqid |
E_NOEXS | No requests are being processed (only when reqid = 0) |
E_TMOUT | Timeout (processing continues) |
E_ABORT | Processing aborted |
Other | Error code returned by device driver |
Only when all the service profile items below are set to be effective, this API can be used.
This API takes the parameter tmout_u
(64-bit microseconds), instead of the parameter tmout
of tk_wai_dev.
Its specification is the same as that of tk_wai_dev, except that the parameter changed to tmout_u
. For more details, see the description of tk_wai_dev.
If the corresponding device driver does not have the TDA_TMO_U attribute (does not supports microseconds), it cannot handle the timeout in microseconds. In that case, the timeout (in microseconds) specified by this API in tmout_u
is rounded to the time in milliseconds and passed to the device driver.
Thus, the appropriate conversion of parameters is executed by μT-Kernel/SM. The application does not have to know whether the device driver has the TDA_TMO_U attribute or not, i.e., whether the device driver supports microseconds or not.
Only when all the service profile items below are set to be effective, this API can be used.
Performs the processing specified in mode
, then passes the resulting suspend disable request count in the return code.
mode := ( (TD_SUSPEND | [TD_FORCE]) || TD_DISSUS || TD_ENASUS || TD_CHECK)
#define TD_SUSPEND 0x0001 /* suspend */ #define TD_DISSUS 0x0002 /* disable suspension */ #define TD_ENASUS 0x0003 /* enable suspension */ #define TD_CHECK 0x0004 /* get suspend disable request count */ #define TD_FORCE 0x8000 /* forced suspend specification */
Suspend
If suspending is enabled, suspends processing.
If suspending is disabled, returns E_BUSY.
Forcibly suspend
Suspends even in suspend disabled state.
Disable suspension
Disables suspension.
Enable suspension
Enables suspension.
Get suspend disable count
Gets only the number of times suspend disable has been requested.
Suspension is performed in the following steps.
Processing prior to start of suspension in each subsystem
tk_evt_ssy(0, TSEVT_SUSPEND_BEGIN, 0)
Suspension processing in devices
Processing after completion of suspension in each subsystem
tk_evt_ssy(0, TSEVT_SUSPEND_DONE, 0)
Suspended state
tk_set_pow(TPW_DOSUSPEND)
Resumption from SUSPEND state is performed in the following steps.
Return from SUSPEND state
Return from tk_set_pow(TPW_DOSUSPEND)
Processing prior to start of resumption in each subsystem
tk_evt_ssy(0, TSEVT_RESUME_BEGIN, 0)
Resumption processing in devices
Processing after completion of resumption in each subsystem
tk_evt_ssy(0, TSEVT_RESUME_DONE, 0)
The number of suspend disable requests is counted. Suspension is enabled only if the same number of suspend enable requests is made. At system boot, the suspend disable count is 0 and suspension is enabled. The maximum suspend disable request count is implementation-dependent, but must be at least 255. When the upper limit is exceeded, E_QOVR is returned.
Gets the device name of the device specified in devid
and puts the result in devnm
.
devid
is the device ID of either a physical device or a logical device.
If devid
is a physical device, the physical device name is put in devnm
.
If devid
is a logical device, the logical device name is put in devnm
.
devnm
requires a space of L_DEVNM + 1 bytes or larger.
The device ID of the physical device to which device devid
belongs is passed in the return code.
rdev
Detail:
ATR |
devatr
| Device Attribute | Device attributes |
SZ |
blksz
| Block Size of Device-specific Data | Block size of device-specific data (-1: unknown) |
INT |
nsub
| Subunit Count | Number of subunits |
INT |
subno
| Subunit Number | 0: Physical device, 1 to nsub: Subunit number+1 |
(Other implementation-dependent parameters may be added beyond this point.) |
Gets device information about the device specified in devnm
, and puts the result in rdev
. If rdev
= NULL is set, the device information is not stored.
nsub
indicates the number of physical device subunits belonging to the device specified in devnm
.
The device ID of the device specified in devnm
is passed in the return code.
rdev
Detail:
ATR |
devatr
| Device Attribute | Device attributes |
SZ |
blksz
| Block Size of Device-specific Data | Block size of device-specific data (-1: unknown) |
INT |
nsub
| Subunit Count | Number of subunits |
INT |
subno
| Subunit Number | 0: Physical device, 1 to nsub: Subunit number+1 |
(Other implementation-dependent parameters may be added beyond this point.) |
Gets device information about the device specified in dd
, and puts the result in rdev
. If rdev
= NULL is set, the device information is not stored.
nsub
indicates the number of physical device subunits belonging to the device specified in dd
.
The device ID of the device specified in dd
is passed in the return code.
ldev
Detail:
ATR |
devatr
| Device Attribute | Device attributes |
SZ |
blksz
| Block Size of Device-specific Data | Block size of device-specific data (-1: unknown) |
INT |
nsub
| Subunit Count | Number of subunits |
UB |
devnm[L_DEVNM]
| Physical Device Name | Physical device name |
(Other implementation-dependent parameters may be added beyond this point.) |
Gets information about registered devices. Registered devices are managed per physical device. The registered device information is therefore also obtained per physical device.
When the number of registered devices is N, number are assigned serially to devices from 0 to N - 1. Starting from the number specified in start
in accordance with this scheme, the number of registrations specified in ndev
is acquired and put in ldev
. The space specified in ldev
must be large enough to hold ndev
registration information. The number of remaining registrations after start
(N-start
) is passed in the return code.
If the number of registrations from start
is fewer than ndev
, all remaining registrations are stored. A value passed in return code less than or equal to ndev
means all remaining registrations were obtained. Note that this numbering changes as devices are registered and deleted. For this reason, accurate information may not be always obtained if the acquisition is carried out over multiple operations.
INT |
retcode
| Return Code from eventfn | Return code passed by eventfn |
or | Error Code | Error code |
Sends a driver request event to the device (device driver) specified in devid
.
The functioning of driver request events and the contents of evtinf
are defined for each event type. For details on driver request event, see the Section called eventfn - Event function.
Device driver registration is performed for each physical device.
idev
Detail:
Registers a device (device driver) with the device name set in devnm
, and passes the device ID of the registered device in the return code. If a device with device name devnm
is already registered, the registration is updated with new information, in which case the device ID does not change.
ddev
specifies the device registration information. When ddev
= NULL is specified, device devnm
registration is deleted.
ddev
is a structure in the following format:
typedef struct t_ddev { void *exinf; /* extended information */ ATR drvatr; /* driver attributes */ ATR devatr; /* device attributes */ INT nsub; /* number of subunits */ SZ blksz; /* block size of device-specific data (-1: unknown) */ FP openfn; /* open function */ FP closefn; /* close function */ FP execfn; /* execute function */ FP waitfn; /* wait-for-completion function */ FP abortfn; /* abort function */ FP eventfn; /* event function */ /* Implementation-dependent information may be added beyond this point.*/ } T_DDEV;
exinf
is used to store any desired information. The value is passed to the processing functions. Device management pays no attention to the contents.
drvatr
sets device driver attribute information. The lower bits indicate system attributes, and the high bits are used for implementation-dependent attributes. The implementation-dependent attribute portion is used, for example, to define validity flags when implementation-dependent data is added to T_DDEV.
drvatr := [TDA_OPENREQ] | [TDA_TMO_U] | [TDA_DEV_D]
#define TDA_OPENREQ 0x0001 /* open/close each time */ #define TDA_TMO_U 0x0002 /* timeout in microseconds is used */ #define TDA_DEV_D 0x0004 /* 64 bit device */
drvatr
can be specified by combining the following driver attributes.
TDA_OPENREQ
When a device is opened multiple times, normally openfn is called only the first time it is opened and closefn the last time it is closed. If TDA_OPENREQ is specified, then openfn/closefn will be called for all open/close operations even in case of multiple openings.
TDA_TMO_U
Indicates that timeout in microseconds is used.
In this case, the timeout tmout
of driver processing functions is specified in the TMO_U format (microseconds).
TDA_DEV_D
Indicates that a 64-bit device is used. In this case, the type of the request packet devreq
of driver processing functions is T_DEVREQ_D.
If TDA_TMO_U or TDA_DEV_D is specified, type of some parameters of driver processing functions is changed. If a combination of multiple driver attributes that change the type of parameters is specified in a driver processing function, the type of all specified parameters of that function is changed.
Device attributes are specified in devatr
. The details of device attribute setting are as noted above.
The number of subunits is set in nsub
. If there are no subunits, 0 is specified.
blksz
sets the block size of device-specific data in bytes. In the case of a disk device, this is the physical block size. It is set to 1 byte for a serial port, etc. For a device with no device-specific data, it is set to 0. For an unformatted disk or other device whose block size is unknown, -1 is set. If blksz
≦ 0, device-specific data cannot be accessed. When device-specific data is accessed by tk_rea_dev or tk_wri_dev, size
* blksz
must be the size of the area being accessed, that is, the size of buf
.
openfn, closefn, execfn, waitfn, abortfn, and eventfn set the entry address of driver processing functions. For more details on driver processing functions, see the Section called Device Driver Interface.
The device initialization information is returned in idev
. This includes information set by default when the device driver is started, and can be used as necessary. When idev
= NULL is set, device initialization information is not stored.
evtmbfid
specifies the system default message buffer ID for event notification. If there is no system default event notification message buffer, 0 is set.
Notification like the following is made to each subsystem when a device is registered or deleted. devid
is the device ID of the registered or deleted physical device.
tk_evt_ssy(0, TSEVT_DEVICE_REGIST, devid
)
tk_evt_ssy(0, TSEVT_DEVICE_DELETE, devid
)
idev
Detail:
Gets device initialization information. The contents are the same as the information obtained by tk_def_dev.
The error code E_MACV is common to many system calls, and usually not included in the error code list of each system call. However, for this API, E_MACV is included in this error code list because it is the only typical error.
The device driver interface consists of processing functions (driver processing functions) specified when registering a device.
ER openfn(ID devid
, UINT omode
, void *exinf
);
ER closefn(ID devid
, UINT option
, void *exinf
);
ER execfn(T_DEVREQ *devreq
, TMO tmout
, void *exinf
);
INT waitfn(T_DEVREQ *devreq
, INT nreq
, TMO tmout
, void *exinf
);
ER abortfn(ID tskid
, T_DEVREQ *devreq
, INT nreq
, void *exinf
);
INT eventfn(INT evttyp
, void *evtinf
, void *exinf
);
If TDA_TMO_U is specified for a driver attribute, the timeout specification tmout
for the following driver processing functions is set to TMO_U type (in microseconds).
If TDA_DEV_D is specified for a driver attribute, the type of request packet devreq
for the following driver processing functions is set to T_DEVREQ_D.
If TDA_TMO_U and TDA_DEV_D are specified set a driver attribute, a driver processing function is set to the one that has parameters with all the specified types of changes were applied.
Driver processing functions are called by device management and run as a quasi-task portion. These driver processing functions must be reentrant. Calling of these driver processing functions in a mutually exclusive manner is not guaranteed. If, for example, there are simultaneous requests from multiple devices for the same device, different tasks might call the same driver processing function at the same time. The device driver must perform mutual exclusion control in such cases as necessary.
I/O requests to a device driver are made by means of the following request packet associated with a request ID.
/* * Device request packet: For 32-bit * In: Input parameter to driver processing function (set in μT-Kernel/SM device management) * Out: Output parameter from driver processing function (set in driver processing function) * X: Parameters other than input and output */ typedef struct t_devreq { struct t_devreq *next; /* In: Link to request packet (NULL: termination) */ void *exinf; /* X: Extended information */ ID devid; /* In: Target device ID */ INT cmd:4; /* In: Request command */ BOOL abort:1; /* In: TRUE if abort request */ W start; /* In: Starting data number */ SZ size; /* In: Request size */ void *buf; /* In: IO buffer address */ SZ asize; /* Out: Size of result */ ER error; /* Out: Error result */ /* Implementation-dependent information may be added beyond this point.*/ } T_DEVREQ;
/* * Device request packet: For 64-bit * In: Input parameter to driver processing function (set in μT-Kernel/SM device management) * Out: Output parameter from driver processing function (set in driver processing function) * X: Parameters other than input and output */ typedef struct t_devreq_d { struct t_devreq_d *next; /* In: Link to request packet (NULL: termination) */ void *exinf; /* X: Extended information */ ID devid; /* In: Target device ID */ INT cmd:4; /* In: Request command */ BOOL abort:1; /* In: TRUE if abort request */ D start_d; /* In: Starting data number, 64-bit */ SZ size; /* In: Request size */ void *buf; /* In: IO buffer address */ SZ asize; /* Out: Size of result */ ER error; /* Out: Error result */ /* Implementation-dependent information may be added beyond this point.*/ } T_DEVREQ_D;
In: Input parameter to the driver processing function is set in μT-Kernel/SM device management. Should not be changed on the device driver side. Parameters other than input parameters (In) are initially cleared to 0 by the device management. After that, device management does not modify them. Out: Output parameter returned from the driver execute function is set in the driver processing function.
next
is used to link the request packet. In addition to usage for keeping track of request packets in device management, it is used also by the completion wait function (waitfn) and abort function (abortfn).
exinf
can be used freely by the device driver. Device management does not pay attention to the contents.
The device ID of the device to which the request is issued is specified in devid
.
The request command is specified in cmd
as follows.
cmd := (TDC_READ || TDC_WRITE)
#define TDC_READ 1 /* read request */ #define TDC_WRITE 2 /* write request */
If abort processing is to be carried out, abort
is set to TRUE right before calling the abort function (abortfn). abort
is a flag indicating whether abort processing was requested, and does not indicate that processing was aborted. In some cases abort
is set to TRUE even when the abort function (abortfn) is not called. Abort processing is performed when a request with abort
set to TRUE is actually passed to the device driver.
start
, start_d
, and size
are just set as start
, start_d
, and size
specified in tk_rea_dev, tk_rea_dev_du, tk_wri_dev, and tk_wri_dev_du.
buf
is just set as buf
specified in tk_rea_dev, tk_rea_dev_du, tk_wri_dev, and tk_wri_dev_du. On systems that support virtual memory, the memory space specified in buf
may be nonresident or belong to task space, so care must be taken to handle such cases.
The device driver sets in asize
the value returned in asize
by tk_wai_dev.
The device driver sets in error
the error code passed by tk_wai_dev in its return code. E_OK indicates a normal result.
Difference between T_DEVREQ and T_DEVREQ_D is only the part of their names being start
or start_d
, and the data type.
The type of device request packet (T_DEVREQ or T_DEVREQ_D) is selected based on the driver attribute (TDA_DEV_D) at device registration. For this reason, T_DEVREQ and T_DEVRE do not co-exist in the request packet for one driver.
ID |
devid
| Device ID | Device ID of the device to open |
UINT |
omode
| Open Mode | Open mode (same as tk_opn_dev) |
void* |
exinf
| Extended Information | Extended information set at device registration |
The open function openfn is called when tk_opn_dev is invoked.
The function openfn performs processing to enable use of a device. Details of the processing are device-dependent; if no processing is needed, it does nothing. The device driver does not need to remember whether a device is open or not, nor is it necessary to treat as error the calling of another processing function simply because the device was not opened (openfn had not been called). If another processing function is called for a device that is not open, the necessary processing can be performed so long as there is no problem in device driver operation.
When openfn is used to perform device initialization or the like, in principle no processing should be performed that causes a wait. The processing and return from openfn must be as prompt as possible. In the case of a device such as a serial port for which it is necessary to set the communication mode, for example, the device can be initialized when the communication mode is set by tk_wri_dev. There is no need for openfn to initialize the device.
When the same device is opened multiple times, normally this function is called only for the first time. If, however, the driver attribute TDA_OPENREQ is specified in device registration, this function is called each time the device is opened.
The openfn function does not need to perform any processing with regard to multiple opening or open mode, which are handled by device management. Likewise, omode
is simply passed as reference information; no processing relating to omode
is required.
openfn runs as a quasi-task portion of the task that issued tk_opn_dev. That is, it is executed in the context of the quasi-task portion whose requesting task is the task that issued tk_opn_dev.
ID |
devid
| Device ID | Device ID of the device to close |
UINT |
option
| Close Option | Close option (same as tk_cls_dev) |
void* |
exinf
| Extended Information | Extended information set at device registration |
The close function closefn is called when tk_cls_dev is invoked.
The closefn function performs processing to end use of a device. Details of the processing are device-dependent; if no processing is needed, it does nothing.
If the device is capable of ejecting media and TD_EJECT is set in option
, media ejection is performed.
When closefn is used to perform device shutdown processing or media ejection, in principle no processing should be performed that causes a wait. The processing and return from closefn must be as prompt as possible. If media ejection takes time, it is permissible to return from closefn without waiting for the ejection to complete.
When the same device is opened multiple times, normally this function is called only the last time it is closed. If, however, the driver attribute TDA_OPENREQ is specified in device registration, this function is called each time the device is closed. In this case TD_EJECT is specified in option
only for the last time.
The closefn function does not need to perform any processing with regard to multiple opening or open mode, which are handled by device management.
closefn runs as a quasi-task portion of the task that issued tk_cls_dev.
/* Execute function (32-bit request packet, millisecond timeout) */
ER ercd = execfn
(T_DEVREQ *devreq, TMO tmout, void *exinf);
/* execute function (64-bit request packet, millisecond timeout) */
ER ercd = execfn
(T_DEVREQ_D *devreq_d, TMO tmout, void *exinf);
T_DEVREQ* |
devreq
| Device Request Packet | Request packet (32-bit) |
T_DEVREQ_D* |
devreq_d
| Device Request Packet | Request packet (64-bit) |
TMO |
tmout
| Timeout | Request acceptance timeout (ms) |
TMO_U |
tmout_u
| Timeout | Request acceptance timeout (in microseconds) |
void* |
exinf
| Extended Information | Extended information set at device registration |
The execute function execfn is called when tk_rea_dev or tk_wri_dev is invoked.
Initiates the processing requested in devreq
. This function initiates the requested processing only, returning to its caller without waiting for the processing to complete. The time required to initiate processing depends on the device driver; this function does not necessarily complete immediately.
When new processing cannot be accepted, this function goes to WAITING state for request acceptance. If the new request cannot be accepted within the time specified in tmout
, the function times out. The TMO_POL or TMO_FEVR attribute can be specified in tmout
. If the function times out, E_TMOUT is passed in the execfn return code. The request packet error
parameter does not change. Timeout applies to the request acceptance, not to the processing after acceptance.
When error is passed in the execfn return code, the request is considered not to have been accepted and the request packet is discarded.
If processing is aborted before the request is accepted (before the requested processing starts), E_ABORT is passed in the execfn return code. In this case, the request packet is discarded. If the abort occurs after the processing has been accepted, E_OK is returned for this function. The request packet is not discarded until waitfn is executed and processing completes.
When abort occurs, the important thing is to return from execfn as quickly as possible. If processing will end soon anyway without aborting, it is not necessary to abort.
execfn runs as a quasi-task portion of the task that issued tk_rea_dev, tk_wri_dev, tk_srea_dev, or tk_swri_dev.
In a device driver for which TDA_DEV_D is specified as an attribute at the time of registering the device, the execute function (64-bit request packet, millisecond timeout) execfn is called when tk_rea_dev or tk_wri_dev is invoked. In this case, the function specification is the same as that of 32-bit request packet, millisecond timeout execfn, except that the parameter request packet is a 64-bit T_DEVREQ_D* devreq_d
.
In a device driver for which TDA_TMO_U is specified as an attribute at the time of registering the device, the execute function (32-bit request packet, microsecond timeout) execfn is called when tk_rea_dev or tk_wri_dev is invoked. In this case, the function specification is the same as that of 32-bit request packet, millisecond timeout execfn, except that the parameter timeout specification is a microsecond TMO_U tmout_u
.
In a device driver for which both TDA_DEV_D and TDA_TMO_U are specified as an attribute at the time of registering the device, the execute function (64-bit request packet, microsecond timeout) execfn is called when tk_rea_dev or tk_wri_dev is invoked. In this case, the function specification is the same as that of 32-bit request packet, millisecond timeout execfn, except that the parameter request packet is a 64-bit T_DEVREQ_D* devreq_d
and the parameter timeout specification is a microsecond TMO_U tmout_u
.
/* wait-for-completion function (32-bit request packet, millisecond timeout) */
INT creqno = waitfn
(T_DEVREQ *devreq, INT nreq, TMO tmout, void *exinf);
/* wait-for-completion function (64-bit request packet, millisecond timeout) */
INT creqno = waitfn
(T_DEVREQ_D *devreq_d, INT nreq, TMO tmout, void *exinf);
T_DEVREQ* |
devreq
| Device Request Packet | Request packet list (32-bit) |
T_DEVREQ_D* |
devreq_d
| Device Request Packet | Request packet list (64-bit) |
INT |
nreq
| Number of Requests | Request packet count |
TMO |
tmout
| Timeout | Timeout (ms) |
TMO_U |
tmout_u
| Timeout | Timeout (in microseconds) |
void* |
exinf
| Extended Information | Extended information set at device registration |
The wait-for-completion function waitfn is called when tk_wai_dev is invoked.
devreq
is a list of request packets in a chain linked by devreq
->next
. This function waits for completion of any of the nreq
request packets starting from devreq
. The final next
is not necessarily NULL, so the nreq
must always be followed. The number of the completed request packet (which one after devreq
) is passed in the return code. The first one is numbered 0 and the last one is numbered nreq
- 1. Here completion means any of normal completion, abnormal (error) termination, or abort.
The timeout for waiting for completion is set in tmout
. The TMO_POL or TMO_FEVR attribute can be specified for tmout
. If the wait times out, the requested processing continues. The waitfn return code in case of timeout is E_TMOUT. The request packet error
parameter does not change. Note that if return from waitfn occurs while the requested processing continues, error must be returned in the waitfn return code; but the processing must not be completed when error is passed in the return code, and a value other than error must not be returned if processing is ongoing. As long as error is passed in the waitfn return code, the request is considered to be pending and no request packet is discarded. When the number of a request packet whose processing was completed is passed in the waitfn return code, the processing of that request is considered to be completed and that request packet is discarded.
I/O error and other device-related errors are stored in the request packet error
parameter. Error is passed in the waitfn return code when completion waiting did not take place properly. The waitfn return code is set in the tk_wai_dev return code, whereas the request packet error
value is returned in ioer
.
The abort processing when the abort function abortfn was executed during completion waiting by waitfn differs depending on whether to wait for completion of a single request (waitfn, nreq
= 1) or multiple requests (waitfn, nreq
> 1). When waiting for completion of a single request, the request currently processing is aborted. On the other hand, when waiting for completion of multiple requests, as a special handling, only the completion waiting by waitfn is released and the processing for the request itself is not aborted. It means that, even if the abort function abortfn is executed, the request packets' abort
remains FALSE and the processing for the requests continues. E_ABORT is passed in the return code from the released waitfn.
During a wait for request completion, an abort request may be set in the abort
parameter of a request packet. In such a case, if it is a single request, the request abort processing must be performed. If the wait is for multiple requests it is also preferable that abort processing be executed, but it is also possible to ignore the abort
flag.
When abort occurs, the important thing is to return from waitfn as quickly as possible. If processing will end soon anyway without aborting, it is not necessary to abort.
As a rule, E_ABORT is returned in the request packet error
parameter when processing is aborted; but a different error code than E_ABORT may be returned as appropriate based on the device properties. It is also permissible to return E_OK on the basis that the processing right up to the abort is valid. If processing completes normally to the end, E_OK is returned even if there was an abort request.
waitfn runs as a quasi-task portion of the task that issued tk_wai_dev, tk_srea_dev, or tk_swri_dev.
In a device driver for which TDA_DEV_D is specified as an attribute at the time of registering the device, the wait-for-completion function (64-bit request packet, millisecond timeout) waitfn is called when tk_wai_dev is invoked. In this case, the function specification is the same as that of 32-bit request packet, millisecond timeout waitfn, except that the parameter request packet is a 64-bit T_DEVREQ_D* devreq_d
.
In a device driver for which TDA_TMO_U is specified as an attribute at the time of registering the device, the wait-for-completion function (32-bit request packet, microsecond timeout) waitfn is called when tk_wai_dev is invoked. In this case, the function specification is the same as that of 32-bit request packet, millisecond timeout waitfn, except that the parameter timeout specification is a microsecond TMO_U tmout_u
.
In a device driver for which TDA_DEV_D and TDA_TMO_U are specified as an attribute at the time of registering the device, the wait-for-completion function (64-bit request packet, microsecond timeout) waitfn is called when tk_wai_dev is invoked. In this case, the function specification is the same as that of 32-bit request packet, millisecond timeout waitfn, except that the parameter request packet is a 64-bit T_DEVREQ_D* devreq_d
and the parameter timeout specification is a microsecond TMO_U tmout_u
.
ID |
tskid
| Task ID | Task ID of the task executing execfn or waitfn |
T_DEVREQ* |
devreq
| Device Request Packet | Request packet list (32-bit) |
T_DEVREQ_D* |
devreq_d
| Device Request Packet | Request packet list (64-bit) |
INT |
nreq
| Number of Requests | Request packet count |
void* |
exinf
| Extended Information | Extended information set at device registration |
The abort function abortfn is called when you want to promptly return from the currently running execute function execfn or wait-for-completion function waitfn. Normally this means the request being processed is aborted. If, however, the processing can be completed soon without aborting, it may not have to be aborted. The important thing is to return as quickly as possible from execfn or waitfn.
abortfn is called in the following cases.
When a break function is executing after a task exception and the task that raised the exception requests abort processing, abortfn is used to abort the request being processed by that task.
When a device is being closed by tk_cls_dev, and the device descriptor was processing a request, abortfn is used to abort the request being processed by the device descriptor.
tskid
indicates the task executing the request specified in devreq
. In other words, it is the task executing execfn or waitfn. devreq
and nreq
are the same as the parameters that were passed to execfn or waitfn. In the case of execfn , nreq
is always 1.
abortfn is called by a different task from the one executing execfn or waitfn. Since both tasks run concurrently, mutual exclusion control must be performed as necessary. It is possible that the abortfn function will be called immediately before calling execfn or waitfn, or during return from these functions. Measures must be taken to ensure proper operation in such cases. Before abortfn is called, the abort
flag in the request packet whose processing is to be aborted is set to TRUE, enabling execfn or waitfn to know whether there is going to be an abort request. Note also that abortfn can use tk_dis_wai for any object.
When waitfn is executing for multiple requests (nreq
> 1), this is treated as a special case differing as follows from other cases.
Only the completion wait is aborted (waited is released), not the requested processing.
The abort
flag is not set in the request packet (remains as abort
= FALSE).
Aborting a request when execfn and waitfn are not executing is done not by calling abortfn but by setting the request packet abort
flag. If execfn is called when the abort
flag is set, the request is not accepted. If waitfn is called, abort processing is the same as if abortfn is called.
If a request for which processing was started by execfn is aborted before waitfn was called to wait for its completion, the completion of the aborted processing is notified when waitfn is called later. Even though processing was aborted, the request itself is not discarded until its completion has been checked by waitfn.
abortfn initiates abort processing only, returning promptly without waiting for the abort to complete.
The abortfn that is executed on a task exception runs as a quasi-task portion of the task issuing tk_ras_tex that raised the task exception. The abortfn that is executed on a device close runs as a quasi-task portion of the task that issued tk_cls_dev.
In a device driver for which TDA_DEV_D is specified as an attribute at the time of registering the device, the abort function (64-bit request packet) abortfn is called when you want to promptly return from the currently running execute function execfn or wait-for-completion function waitfn. In this case, the function specification is the same as that of 32-bit request packet abortfn, except that the parameter request packet is a 64-bit T_DEVREQ_D* devreq_d
.
When a state change occurs in the device or system which is caused by a factor other than normal device I/O processing by an application interface, requiring some processing by the device driver, a driver request event is raised and then the event function eventfn is called.
The driver request event is raised when suspending or resuming a device for power control (see tk_sus_dev) or when connecting a removable device such as USB.
For example, when the system is suspended by tk_sus_dev, the driver request event for the suspend (TDV_SUSPEND) is raised in the μT-Kernel (during tk_sus_dev processing) and the event function for each device is called with evttyp
= TDV_SUSPEND. The event function called for each device performs necessary operations for suspend such as saving the state on receiving this driver request event.
The following driver request events are defined.
#define TDV_SUSPEND (-1) /* suspend */ #define TDV_RESUME (-2) /* resume */ #define TDV_CARDEVT 1 /* reserved */ #define TDV_USBEVT 2 /* USB event */
The driver request events with a negative value are called internally from the device management in the μT-Kernel/SM, for suspend or resume processing.
On the other hand, the driver request events with a positive value (TDV_USBEVT) are reference specifications which are not directly related to the μT-Kernel operation, and raised by calling tk_evt_dev. These driver request events are used as needed to implement a bus driver for USB or other device.
The processing performed by the event function is defined for each event type. For suspend and resume processings, see the Section called Device Suspend/Resume Processing.
When a device event is called by tk_evt_dev, the eventfn return code is set transparently as the tk_evt_dev return code.
Requests to event functions must be accepted even if another request is processed, and must be processed as quickly as possible.
The eventfn runs as a quasi-task portion of the task that issued tk_evt_dev or tk_sus_dev that caused the event.
The following behaviors are assumed for USB event.
Note that they describe implementation examples of device drivers that handle a device such as USB and are not part of the μT-Kernel specification.
When a USB device is connected, a class driver should dynamically be mapped to the USB device to perform an actual I/O processing.
For example, when a storage such as USB memory is connected, a device driver for the mass storage class handles the I/O for the device, or when a USB camera is connected, a device driver for the video class handles the I/O for the device. Which device driver should be used cannot be determined until the USB device is connected.
In this case, the driver request event for the USB connection and the event function for each device driver are used in order to map a class driver to the USB device. Specifically, when the USB bus driver (USB manager) monitoring the USB ports detects a newly connected USB device, it sends the driver request event for the USB connection (TDV_USBEVT) to each device driver which will be candidate of the class driver and then calls the event function for each device.
The event function for each device returns whether or not it can support the newly connected USB device in response to this TDV_USBEVT. The USB bus driver receives the return codes and determines the mapping to the actual class driver.
A device driver sends events that occur on each device to the specific message buffer (event notification message buffer) as device event notification messages. The event notification message buffer ID is referenced or set as an attribute data of TDN_EVENT for each device.
The system default event notification message buffer is used immediately after device registration. As a device is registered by tk_def_dev when a device driver is started, the system default event notification message buffer ID value is returned as this API's return parameter, the value is held in the device driver and is used as the initial value of this attribute data, TDN_EVENT.
The system default event notification message buffer is created at system startup. Its size and maximum message length are defined by TDEvtMbfSz in the system configuration information.
The message formats used in device event notification are as follows: The content and size of the event notification message vary depending on the event type.
typedef struct t_devevt { TDEvtTyp evttyp; /* event type */ /* Information specific to each event type is appended here. */ } T_DEVEVT;
typedef struct t_devevt_id { TDEvtTyp evttyp; /* event type */ ID devid; /* Device ID */ /* Information specific to each event type is appended here. */ } T_DEVEVT_ID;
typedef struct t_devevt_ex { TDEvtTyp evttyp; /* event type */ ID devid; /* Device ID */ UB exdat[16]; /* Extended information */ /* Information specific to each event type is appended here. */ } T_DEVEVT_EX;
The event type of a device event notification is classified as follows:
Basic event notification (event type: 0x0001 to 0x002F)
Basic event notification from a device
System event notification (event type: 0x0030 to 0x007F)
Event notification related to entire system such as power supply control
Event notification with extended information (event type: 0x0080 to 0x00FF)
Event notification from a device with extended information
User-defined event notification (event type: 0x0100 to 0xFFFF)
Notification of event that users can arbitrarily define
Typical event types are as follows:
typedef enum tdevttyp { TDE_unknown = 0, /* undefined */ TDE_MOUNT = 0x01, /* media insert */ TDE_EJECT = 0x02, /* Eject media */ TDE_POWEROFF = 0x31, /* power switch off */ TDE_POWERLOW = 0x32, /* low power alarm */ TDE_POWERFAIL = 0x33, /* abnormal power */ TDE_POWERSUS = 0x34 /* auto suspend */ } TDEvtTyp;
Measures must be taken so that if event notification cannot be sent because the message buffer is full, the lack of notification will not adversely affect operation on the receiving end. One option is to hold the notification until space becomes available in the message buffer, but in that case other device driver processing should not, as a rule, be allowed to fall behind as a result. Processing on the receiving end should be designed to avoid message buffer overflow as much as possible.
Device drivers perform suspend and resume operations in response to the issuing of suspend/resume events (TDV_SUSPEND/TDV_RESUME) to the event handling function (eventfn). Suspend and resume events are issued only to physical devices.
The event for starting suspend processing is as follows:
evttyp = TDV_SUSPEND evtinf = NULL (none)
By issuing suspend event (TDV_SUSPEND), suspend processing takes place as follows.
If there is a request being processed at the time, the device driver waits for it to complete, pauses it or aborts it. Which of these options to take depends on the device driver implementation. Since the suspension must be effected as quickly as possible, however, pause or abort should be chosen if completion of the request will take time.
Suspend events can be issued only for physical devices, but the same processing is applied to all logical devices included in the physical device.
Pause: Processing is suspended, then continues after the device resumes operation. |
Abort: Processing is aborted just as when the abort function (abortfn) is executed, and is not continued after the device resumes operation. |
New requests other than a resume event are not accepted.
The device power is cut off and other suspend operation is performed.
Abort should be avoided if possible because of its effects on applications. It should be used only in such cases as long input wait from a serial port, or when pause would be difficult. Normally it is best to wait for completion of a request or, if possible, choose pause (suspend and resume).
Requests arriving at the device driver in suspend state are made to wait until operation resumes, after which they are accepted for processing. If the request does not involve access to the device, however, or otherwise can be processed even during suspension, a request may be accepted without waiting for resumption.
The event for starting resume processing is as follows:
evttyp = TDV_RESUME evtinf = NULL (none)
By issuing resume event (TDV_RESUME), resume processing takes place as follows.
The device power is turned back on, the device states are restored and other device resume processing is performed.
Paused processing is resumed.
Accepting request is resumed.