Sie sind auf Seite 1von 41

Architecture of Device I/O

Drivers

Introduction
Device driver consists of a lot of "bit-bashing and registertwiddling" to convince some ornery unit of hardware to
submit to the control of driver software.
You've got to get every one of a myriad of details right the
bits, the sequences, the timing -- or else that chunk of
hardware will just refuse to do its thing.
A device driver can be organized as a collection of "chunks"
of concurrent software.
The RTOS is involved in both scheduling the "chunks" and
allowing them to communicate cleanly with one another.
In different operating systems, the concurrent "chunks" of
software might be given different names like 'threads' or
'tasks'.
For example, in the pSOSystem RTOS they are called 'tasks'
and 'Interrupt Service Routines' (ISRs).

Introduction
A device driver itself is a collection of functions that are
programmed to make a hardware device perform some
input/output-related ("I/O") activities.
A driver might contain an "initialization" function, a "read"
function, a "write" function, etc.
Device drivers that work with hardware devices that deliver
interrupts
also
include
the
ISRs
for
those
interrupts as an additional component of the device driver.
The functions of a device driver can be called by
application software tasks that would like to get some
hardware I/O-related activities to happen.

Issues in Architectural Design

Low level Issues Automation


Organization of a Device Driver
Device I/O Supervisors
Basic Design Decisions Checklist
Mutual Exclusion for Device Access

Low-level Device Driver Issues


Interdisciplinary: Software + Hardware
Knowledge
Complex, Tedious
Hard to debug
One bit programmed wrong Device wont
work

Automation to the rescue !

The Role of Device Drivers


Information Hiding for Hardware Devices
That Interface to an Embedded Processor

Make Hardware Respond to an Application


Programming Interface
Using calls that are Standardized for Many
Devices and Drivers
Application Software
Device Driver

ECU

Application Software
RTOS
Device
Driver

Driver Upper Half


Hardware Specific Driver

Device Hardware

Tasks, Processes,
Threads
RTOS Interface
(Optional)
Device-Independent
Services
Example:
Synchronization to
Application

Hardware
Abstraction Layer

Whats Done at Each Driver Layer?

Application Software
RTOS
Device
Driver

Driver Upper Half


Hardware Specific Driver

Device Hardware

Driver Upper Half


Re-useable for Many Devices
Defines an I/O Model
Example: Byte I/O, Blockoriented I/O
Application Interface
Interaction with Operating
System
Hardware-Specific Driver
Standard Interface to Upper
Halfof Driver
Device Configuration and
Initialization
Data Input/Output
Device-Specific Control
Examples: Reset, Change
Scale

Components of a Driver

Collection of Functions
That Make Useful Things Happen to an Input/Output (I/O) Device
Callable from Application Code, Tasks
Each Function may be structured as 1 or 2 Layers
Provide Mechanism to Operate I/O Device, Not Policy
Interrupt Service Routine(s)
To Handle Interrupt(s) from the I/O Device

Device Interrupt
Service

Device
Init.

Device
Start.

Device
Open

Device
Close

Device
Read

Device
Hardware

Device
Device Device Device Device
Device
Simulate
Get
Get
Set
Abort
Write
Interrupt Info
Config Config. Read

Device
Abort
Write

The Most Popular Driver Functions


Device Initialize
Device Open
Device Close
Device Read
Device Write
Device Control

This Model is Not Appropriate for All Devices


Device Control is usually by far the Largest
Function
Example: MPEG Device Driver

Device I/O Supervisor


In Addition to Programming Interface for Operating a
Driver
for Processors with Many Drivers, you may need
To Organize Large Sets of Drivers
Manages a set of Encapsulated Tables
Dynamically Load, Unload Drivers (?)
Serial Device Driver

User
Application

Ethernet Device Driver


Other Device Driver

User Mode

Device I/O Supervisor Supervisor Mode

Checklist: Basic Decisions in Driver


Design
Layered Driver ?
Assembler Coding or High-Level Language ?
Source of Low-Level Bit-Bashing Code ?
Automated Code-Generation Tool
Chip Manufacturers Free Driver
Hand-Coding

Which Driver Functions to Implement ?


Do I Need a Device I/O Supervisor ?
Mutual Exclusion Requirement ?
Synchronous or Asynchronous Driver ?

Mutual Exclusion for Device


Access?
Device Driver may need to ensure use by No More than 1
Task at a time can request an input or output operation on a
specific device
Use a Mutex
Alternatives: Semaphore, Mailbox or Message Queue

Print
Im TSK1
Print
Im TSK2

Im TSK1 Im TSK2

Mutual Exclusion Unnecessary?


Reentrancy !
Special Discipline Required to Write Reentrant
Code
No Static Variables
Put all Variables on Stack
Or Stack of Caller
No Self-Modifying Code

Beware: Libraries

MUTUAL EXCLUSION OF DEVICE


ACCESS
For devices that may be thought of as "session-oriented",
exclusive access must be granted for an entire "session"
which may consist of many individual I/O operations.
Example, a single task might want to print an entire page
of text, whereas the printer driver's output function can
print only a single line of text.
In such a case, a driver's 'open session' operation would
request the semaphore token.
And a 'close session' operation would return the semaphore
token.
Any other task attempting to 'open session' while the
semaphore's token is unavailable, would be denied access
to the driver software.

Models for Device Drivers

Synchronous vs. Asynchronous Drivers


Synchronous I/O Models
Asynchronous I/O Models
Latest Input Only Drivers (Asynchronous)
Simple Asynchronous Output Driver

Synchronous Vs. Asynchronous I/O Models

A much larger question in structuring a


device driver, is the question of synchronous
versus asynchronous driver operation.
To put it another way: Do you want the
application task that called the device driver
to wait for the result of the I/O operation
that it asked for? ... Or do you want the
application task to continue to run while the
device driver is doing its I/O operation?

Synchronous or Asynchronous Driver ?


Synchronous Driver
Requesting Task waits for Driver I/O operation to
complete
RTOS: Blocked state, Waiting state, Suspended state
Other tasks can continue to execute
ISRs can continue to execute

Asynchronous Driver
Requesting Task continues to execute, while Driver I/O
operation is underway
Issue: Whats it going to do at that time?
Example: Input device: Task can not yet process the Input it
Requested

Categories of I/O
Passive I/O
On-Demand or Polled

Interrupt-Driven I/O
Input: Interrupt -> New input
ready to be processed
Output: Interrupt -> Finished
with previous output
Ready for next output data

DMA Direct Memory


Access
Transfer of a Complete Large
Buffer of Data
1 Interrupt at the End of
Transfer

Most I/O Hardware is


Asynchronous

Device
DevRead()
Device
Interrupt
Service

Device
Hardware

Device
Hardware

DMA
Device
Interrupt
Service

Device
Hardware

Design Model 1: Synchronous I/O


Driver for Passive Device
Passive == No Interrupts associated with device
Example without Mutual Exclusion, without Control
Function
Application Task
dv_init()

Driver
DevInit()

Application Task
dv_read()

Driver
DevRead()

Application Task
dv_write()

RTOS

Driver
DevWrite()

Device
Hardware

Design Model 2: Synchronous I/O


Driver for an Interrupt Device
Using Semaphore DONE to synchronize
with ISR
DevInit() creates Semaphore DONE
Initial value 0 (No IO complete yet)

Application Task
dv_read()

RTOS

Driver
DevRead()

Semaphore

Device
Interrupt
Service

Device
Hard
ware

Design Model 2: Synchronous I/O


Driver for an Interrupt Device
The requesting task is shown on the left as a light blue rectangle with
rounded corners. It calls the driver's "read" function, shown as a yellow
rectangle (named "DevRead()").
This call can be either through the RTOS, or bypassing the RTOS (shown
as a black-dotted rectangle).
The driver's "read" function will request the device hardware to perform a
"read" operation, and then it will attempt to get a token from the
semaphore to its right.
Since the semaphore initially has no tokens, the driver "read" function,
and hence the task to its left, will become blocked To the right of the
semaphore, is a pink ellipse representing an ISR.
The "lightning" symbol represents the hardware interrupt that triggers
execution of the ISR.
When device hardware completes the requested "read" operation, it will
deliver an interrupt that triggers this ISR, that will put a token into the
semaphore.
This is the semaphore token for which the entire left side of the diagram is
waiting, so the left side of the diagram will then become un-blocked and
will proceed to fetch the newly-read data from the hardware.

Design Model 2: Synchronous I/O


Driver for an Interrupt Device

Design Model 2(Continued) :


Synchronous Driver for an Interrupt
Device
DevRead()[ and/or DevWrite()]
ServiceSYNC_OP:
BEGIN
Start IO Device Operation;
semaphore_get ( DONE, Wait);
/* Wait for Signal */
Get Device Status/Data;
END
Application Task
dv_read()

RTOS

Driver
DevRead()

Device_Interrupt Service
DEVICE_ISR:
BEGIN
Handle Hardware Data/Status;
semaphore_release (DONE);
/* Signal Completion */
END

Semaphore

Device
Interrupt
Service

Device
Hard
ware

Design Model 2(Continued) : Synchronous


Driver for an Interrupt Device
The driver function, does the logic described in the following
pseudocode when called by a task:
DevRead_function:
BEGIN
Start IO Device Read Operation;
Get Synchronizer Semaphore Token (Waiting OK);
/* Wait for Semaphore Token */
Get Device Status and Data;
Give Device Information to Requesting Task;
END
The ISR has very simple logic:
DevRead_ISR:
BEGIN
Calm down the hardware device;
Put a Token into Synchronizer Semaphore;
END

Design Model 3: Basic


Asynchronous Input Driver
Concept:
Requesting Task processes Previous Input
At the same time as Hardware is working on New Input
Calling Task is not blocked while I/O is taking place
I/O Overlaps with execution of This Task as well as other tasks

Mailbox or short Message Queue D_IN


Holds Message (previous input data) from ISR
DevInit() contains mailbox_create(D_IN); or queue_create (D_IN);
Supplies initial (bogus) Message of input data

Application Task
dv_read()

RTOS

Driver
DevRead()

Mail Box

Device
Interrupt
Service

Device
Hard
ware

Design Model 3(Continued) :


Asynchronous Input
DevRead()

Device_Interrupt Service

ASYNC_OP:
BEGIN
rc= mailbox_pend( D_IN, Q_NOWAIT);
if (rc!= 0) .../* Error */
Start next Input Operation at H/W;
Process D_IN Status/Data;
END

Application Task
dv_read()

RTOS

Driver
DevRead()

DEVICE_ISR:
BEGIN
Transfer Data/Status from H/W;
mailbox_post (D_IN);
/* Send new data */
END

Mail Box

Food for Thought: What if Hardware Delivers New Input Data


Unrequested ?

Device
Interrupt
Service

Device
Hard
ware

Design Model 4: Free-Running


Asynchronous Input Driver
Limitation of Model 3:Cant Handle a Free-Running Hardware
Device
Calling Task is not blocked while I/O is taking place
BUT: Some Hardware can Interrupt Repeatedly without
software request
Each time with New Input Data

Solution: Use long Message Queue D_IN to deliver


messages from ISR
Device
Application Task
dv_read()

RTOS

Driver
DevRead()

QUEUE

Interrupt
Service

Device
Hard
ware

Design Model 4(Continued) :


Free Running Input
DevRead()

Device_Interrupt Service

ASYNC_OP:
BEGIN
rc= queue_receive ( D_IN, Q_WAIT);
if (rc!= 0) .../* Error */
Process D_IN Status/Data;
END

Application Task
dv_read()

RTOS

Driver
DevRead()

DEVICE_ISR:
BEGIN
Transfer Data/Status from H/W;
queue_send (D_IN); /*New data*/
END

QUEUE

Device
Interrupt
Service

Food for Thought:


What should be the Length of the Message Queue ?
Will the Application Task first receive the oldest or newest Data in Queue?

Device
Hard
ware

Design Model 5 :
Latest Input Only

Limitation of Model 4: Always saving unread Incoming Data

Very old data can get Queued up

A Solution: Set up a Protected Shared Data Area

Protect from Access Collisions using a Binary Semaphore (Initial


Value 1)
Data Area contains Latest Measured Value only. Old data
Overwritten.

Destructive Write, Non-Destructive Read

Input Device Hardware can be free-running, giving Interrupts


whenever

Application Task
dv_read()

RTOS

Driver
DevRead()

Semaphore
Shared
Data Area

Device
Interrupt
Service

Device
Hard
ware

Design Model 5(Continued) :


Latest Input Only

Gain access to shared data


/* semaphore_get(WAIT) */
Read data from shared data area
End access /* semaphore_release() */

/* Interrupt -> New data available */


Gain access to shared data
/* semaphore_get (NO_WAIT) */
IF semaphore OKs access
THEN
Write to shared data area
End access /* semaphore_release() */
ELSE ...
ENDIF
Semaphore

Application Task
dv_read()

RTOS

Driver
DevRead()

Shared
Data
Area

Device
Interrupt
Service

Food for Thought:


What if the ISR is refused the Semaphore ?
What if youre Not Using an Operating System, or Dont Have Semaphores?

Device
Hard
ware

Design Model 6 : Latest Input Only


But No Semaphore
Limitation: ISRsCant do Semaphore_Get()
Some RTOSs Dont Allow It
Even if its semaphore_get (NO_WAIT)!

Solution(?): Driver Function (DevRead) Turns


Off InterrupT
when Accessing Shared Data Area
Application Task
dv_read()

RTOS

Driver
DevRead()

Shared
Data
Area

Device
Interrupt
Service

Device
Hard
ware

Design Model 6(Continued) :


Latest Input, No Semaphore

Prepare to access to shared data


/* Interrupt_OFF */
Read data from shared data area
End access /* Interrupt_ON */

Application Task
dv_read()

RTOS

/* Interrupt -> New data available */


Write to shared data area

Driver
DevRead()

Shared
Data
Area

Food for Thought:


What if Interrupts Arrive when Interrupts are Disabled?

Device
Interrupt
Service

Device
Hard
ware

Design Model 7 :
Latest Input But No RTOS (Way #2)

Limitation: RTOS services Illegal?, Too Slow?,


or there is No RTOS?
Solution(?): ISR increments an Update Count in Shared Data
Area
Driver Function (DevRead) Compares the Update Count
Before & After Reading the Shared Data Area
Update
Count

Application Task
dv_read()

RTOS

Driver
DevRead()

Shared
Data
Area

Device
Interrupt
Service

Device
Hard
ware

Design Model 7(Continued) :


Latest Input, No RTOS
/* Leave Interrupts On */
/* Interrupt -> New data available */
DO_UNTIL the 2 Update Counts match
Read Update Count before Fetch
Fetch data from shared data area
Read Update Count after Fetch
END_D0

Application Task
dv_read()

RTOS

Increment the Update Count


Write into shared data area/*

Driver
DevRead()

Food for Thought:


What if the Update Count Rolls Over ?
What if the Update Count is OK by Coincidence?

Update
Count
Shared
Data
Area

Device
Interrupt
Service

Device
Hard
ware

Design Model 8 :
Latest Input But No RTOS (Way #3)

Limitation: RTOS services Illegal?, Too Slow?,


or there is No RTOS?
Solution(?): ISR Sets an Update Bit in Shared Data Area

Driver Function (ADevRead) first Zeros the Update Bit,

Then Reads from the Shared Data Area


And Checks for Zero After Reading

Update
Bit
Application Task
dv_read()

RTOS

Driver
DevRead()

Shared
Data
Area

Device
Interrupt
Service

Device
Hard
ware

Design Model 8(Continued) :


Latest Input, No RTOS
/* Leave Interrupts On */
DO_UNTIL Update Bit stays at 0
Zero the Update Bit
Fetch data from shared data area
Check that Update Bit still 0
END_D0

Application Task
dv_read()

RTOS

/* Interrupt -> New data available */


Set the Update Bit to 1
Write into shared data area/*

Driver
DevRead()

Food for Thought:


What if the Driver is Invoked by 2 or more Tasks ?
Solution: Set Up Mutual Exclusion!

Update
Bit
Shared
Data
Area

Device
Interrupt
Service

Device
Hard
ware

Design Model 9 :
Simple Asynchronous Output Driver

Use Mailbox or short Message Queue STAT

To deliver hardware status messages from ISR

DevInit() creates STAT and sends first (dummy) message to it


Multiple tasks can call dv_write()

Theyll wait in the Task Waiting Queue of queue_receive()

Most RTOSs automatically create a Task Waiting Queue for


each Message Queue

Application
Task
dv_write()

RTOS

Driver
DevWrite()

Task
Message
Waiting
Queue
Queue

Device
Interrupt
Service

Device
Hard
ware

Design Model 9(Continued) :


Asynch. Output Driver
DevWrite()

Device Interrupt Service

ASYNC_OP:
BEGIN
queue_receive ( STAT, Wait);
Wait for H/W done/status */
IF( STAT is O.K. )
Start next Output Operation;
ELSE ...
END

Application Task
dv_write()

RTOS

Driver
DevWrite()

Food for Thought:


What happens after a Device Error?
Answer: This Driver can "Die"

DEVICE_ISR:
BEGIN
Fetch Status from H/W;/*
queue_send (STAT);
/* Send new status */
END

Task
Message
Waiting
Queue
Queue

Device
Interrupt
Service

Device
Hard
ware

Meaning of an Interrupt is Different


in Output Devices vs. Input Devices
Interrupt from Input Device Ive Got an
Input Ready for Software
Interrupt from Output Device
Means Hardware Finished Outputting the
Previously Requested Output
And Also Hardware is Now Ready for the
Next Output Request

Further Reading

Architecture of Device I/O Drivers by Prof. David Kalinsky

Das könnte Ihnen auch gefallen