The execution model
When a device driver is loaded and a channel is opened to it, it is ready to handle requests. EKA2 provides two device driver models, which are distinguished by the execution context used to process requests from userside clients. In the first model, requests from user-side clients are executed in the context of these clients, in privileged mode. This functionality is provided by the DLogicalChannelBase class, as shown in Figure 12.4.
|
user |
i |
User Thread l (Running user-side) | ||
|
kernel |
(Running kernel-side) |
Figure 12.4 Requests handled in user thread context
Figure 12.4 Requests handled in user thread context
Alternatively, the DLogicalChannel class provides a framework that allows user-side requests to be executed in the context of a kernel thread, as shown in Figure 12.5.
|
user |
User Thread | ||||
|
kernel | |||||
|
-► Driver Thread | |||||
Figure 12.5 Requests handled in kernel thread context
Figure 12.5 Requests handled in kernel thread context
In the latter model, a call to a device driver goes through the following steps:
1. The user-side client uses an executive call to request a service from a driver
2. The kernel blocks the client thread and sends a kernel-side message to the kernel thread handling requests for this driver
3. When the kernel thread is scheduled to run, it processes the request and sends back a result
4. The kernel unblocks the client thread when the result is received.
This model makes device-driver programming easier because the same kernel thread can be used to process requests from many user-side clients and DFCs, thus serializing access to the device driver and eliminating thread-related issues. Several drivers can use the same request/DFC kernel thread to reduce resource usage.
There are two kinds of request: synchronous and asynchronous.
12.4.3.1 Synchronous requests
You would typically use a synchronous request to set or retrieve some state information. Such a request may access the hardware itself, but usually completes relatively quickly. Synchronous requests are initiated by a call to RBusLogicalChannel::DoControl (), which does not return until the request has fully completed.
12.4.3.2 Asynchronous requests
An asynchronous request is one which you would typically use to perform a potentially long running operation - for example, one that transmits or receives a block of data from the hardware when it becomes available. The time taken for such a request to complete depends on the operation performed, and during this time the client user-side thread may be able to continue with some other processing. Asynchronous requests are initiated by a call to RBusLogicalChannel::DoRequest(), which takes a TRequestStatus object as an argument and normally returns control to the user as soon as the request has been issued. Typically, hardware will indicate completion of an operation by generating an interrupt, which is handled by an interrupt service routine (ISR) provided by the driver. This in turn schedules a DFC, which runs at some later time in the context of a kernel-side thread and signals the client user-side thread, marking the asynchronous request as complete.
More than one asynchronous request can be outstanding at the same time, each one associated with its own TRequestStatus object, and each identified by a specific request number. The device driver framework puts no explicit limit on the number of concurrent outstanding asynchronous requests; any limit must be enforced by the driver itself. However, the API to cancel a request uses a TUint3 2 bit mask to specify the operations to be cancelled, which implicitly prevents you from uniquely identifying more than 32 concurrent request types.
Post a comment