5.3.4 Device Driver Interface
The device driver interface consists of processing functions specified when registering a device. These functions are called by device management and run as a quasi-task portion. They must be reentrant. The mutually exclusive calling of these processing functions is not guaranteed. If, for example, there are simultaneous requests from multiple devices for the same device, di.erent tasks might call the same processing function at the same time. The device driver must apply mutual exclusion control in such cases as necessary.
IO requests to a device driver are made by means of the following request packet mapped to a request ID.
typedef struct t_devreq {
struct t_devreq *next; /* I: Link to request packet (NULL: termination) */
VP exinf; /* X: Extended information */
ID devid; /* I: Target device ID */
INT cmd:4; /* I: Request command */
BOOL abort:1; /* I: TRUE if abort request */
BOOL nolock:1; /* I: TRUE if lock (making resident) not needed */
INT rsv:26; /* I: reserved (always 0) */
T_TSKSPC tskspc; /* I: Task space of requesting task */
INT start; /* I: Starting data number */
INT size; /* I: Request size */
VP buf; /* I: IO buffer address */
INT asize; /* O: Size of result */
ER error; /* O: Error result */
/* Implementation-dependent information may be added beyond this point. */
} T_DEVREQ;
I indicates an input parameter and O an output parameter. Input parameters must not be changed by the device driver. Parameters other than input parameters (I) are initially cleared to 0 by device management. After that, device management does not modify them. next is used to link the request packet. In addition to use 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 .ag 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. nolock indicates that the memory space specified in buf has already been locked (made resident) and does not need to be locked by the device driver. In this case the device driver must not lock the memory space. (nolock is specified when there is a possibility of wrong operation if the device driver performs a lock. Accordingly, when nolock = TRUE, the device driver must not lock the space.)
tskspc sets the task space of the requesting task. Since processing functions are called in the context of the requesting task, tskspc is the same as the task space of the processing function. If, however, the actual IO processing (read/write in the space specified in buf) is performed by a separate task in the device driver, it is necessary to switch the task space of the task performing the IO processing to the task space of the requesting task.
The start and sizeparameters specified with tk_rea_dev or tk_wri_dev are set transparently in start and size here. The buf parameter specified with tk_rea_dev or tk_wri_dev is set in buf here.
The memory space specified in buf may be nonresident in some cases or task space in others. Care must therefore be taken regarding the following points.
- Nonresident memory cannot be accessed from a task-independent portion or while dispatching or interrupts are disabled.
- Task space memory cannot be accessed from another task space.
For these reasons, switching of task space or making memory space resident must be performed as necessary. Special attention is needed when access is made by an interrupt handler. Generally it is best not to access buf directly from an interrupt handler.
Before accessing the buf memory space, the validity of buf must be checked using an address space check function (ChkSpace., described later below).
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.
- Open Function: ER openfn( ID devid, UINT omode, VP exinf )
devid Device ID of the device to open
omode Open mode (same as tk_opn_dev)
exinf Extended information set at device registration
return code Error
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 state. 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 .rst 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.
- Close Function: ER closefn( ID devid, UINT option, VP exinf )
devid Device ID of the device to close
option Close option (same as tk_cls_dev)
exinf Extended information set at device registration
return code Error
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 state. 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 TDA 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.
- Processing Start Function: ER execfn( T_DEVREQ *devreq, TMO tmout, VP exinf )
devreq Request packet
tmout Request acceptance timeout (ms)
exinf Extended information set at device registration
return code Error
The execfn function is called when tk_rea_dev or tk_wri_dev is invoked, and starts the processing requested in devreq. This function starts the requested processing only, returning to its caller without waiting for the processing to complete. The time required to start processing depends on the device driver; this function does not necessarily complete immediately.
When new processing cannot be accepted, this function goes to WAIT state for request acceptance. If the new request cannot be accepted within the time specified in tmout, the function times out.
The attribute TMO_POL or TMO_FEVR can be specified in tmout. If the function times out, E_TMOUT is passed in the execfn return code. 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 and 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.
- Completion Wait Function: INT waitfn( T_DEVREQ *devreq, INT nreq, TMO tmout, VP exinf )
devreq Request packet list
nreq Request packet count
tmout Timeout (ms)
exinf Extended information set at device registration
return code Completed request packet number or error
The waitfn function 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 .nal next is not neces sarily 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 .rst 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 time to wait until completion is set in tmout. TMO_POL or TMO_FEVR can be specified as the
tmout attribute. 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 be completed even 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 not 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.
IO 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.
Abort processing di.ers depending on whether the wait is for completion of a single request (nreq = 1) or multiple requests (nreq > 1). When completion of a single request is being waited for, the request currently processing is aborted. When waiting for completion of multiple requests, only the wait is aborted (wait release), not the requested processing itself. When a wait for multiple requests is aborted (wait release), E_ABORT is passed in the waitfn return code.
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 di.erent error code 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.
- Abort Function: ER abortfn( ID tskid, T_DEVREQ *devreq, INT nreq, VP exinf )
tskid Task ID of the task executing execfn or waitfn
devreq Request packet list
nreq Request packet count
exinf Extended information set at device registration
return code Error
The function abortfn causes execfn or waitfn to return promptly when the specified request is being executed. 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.
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 di.erent 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 .ag 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 make use of tk_dis_wai for any object.
When waitfn is executing for multiple requests (nreq > 1), this is treated as a special case di.ering as follows from other cases.
— Only the completion wait is aborted (wait release), not the requested processing.
— The abort .ag 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 .ag. If execfn is called when the abort .ag is set, the request is not accepted. If waitfn is called, abort processing is the same as that when 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 noti.ed when waitfn is called. Even though processing was aborted, the request itself is not discarded until its completion has been con.rmed by waitfn.
abortfn starts abort processing only, returning promptly without waiting for the abort to com plete.
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 by subsystem cleanup processing, and a device descriptor was processing a request, abortfn is used to abort the request being processed by that device descriptor.
- Event Handling Function: INT eventfn( INT evttyp, VP evtinf, VP exinf )
evttyp Driver request event type
evtinf Information for each event type
exinf Extended information set at device registration
return code Return code defined for each event type or error
The following driver request event types are defined. Those with positive values are called by tk_evt_dev, and those with negative values are called inside device management.
#define TDV_SUSPEND (-1) /* suspend */
#define TDV_RESUME (-2) /* resume */
#define TDV_CARDEVT 1 /* PC Card event (see Card Manager */
#define TDV_USBEVT 2 /* USB event (see USB Manager) */
p
The processing performed by an event function is defined for each event type. Suspend and resume processing are discussed later below.
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 processing and must be processed as quickly as possible.

Comments