Driver functionalities
1. Driver initialization
Initialize the actual hardware device
Initialize the internal data structres
2. Driver control
Run-time control of hardware device
e.g.: Change the baud rate of a serial device
3. Driver access
In applications where multiple threads need simultaneous driver acces - use semaphore
4. Driver input/output
How input/output is buffered and how threads wait on them
5. Driver interrupts
Interrupts notify the driver of device input,output, control & error events.
6. Driver status
Run time status & statistics associated with the drive operation.
7. Driver termination
If the driver and/or the physical hardware device need to be shut down.
Example: Simple serial hardware device with a configuration register, and input register and an output register
Initialization
Two counting semaphores are used to manage the driver's input and output operation.
Input semaphore: Set by input ISR when a character is received by the serial hardware device
Semaphore is created with an initial value of 0.
Output semaphore: Indicates availability of the serial hardware transmit register
Semaphore is created with an initial value of 1 to indicate availability.
void sdriver_initialize(void)
{
/* Initialize the two counting semaphores user to control the simple I/O */
tx_semaphore_create(&sdriver_input_semaphore,"Sdriver Input Semaphore",0);
tx_semaphore_create(&sdriver_output_semaphore,"Sdriver Output Semaphore",1);
/* Setup interrupt vectors for input and output ISRs.
The initial vector handling should call the ISRs
defined in this file.*/
/* Configure serial device hardware for RX/TX interrupt
generation, baud reate, stop bits, etc. */
}
Simple driver input:
When a serial device interrupt is received, the input semaphore is set.
If one or more threads are waiting for a character from the driver, the
thread waiting the longest is resumed.
Limitations: Dropping input characters
Handled by: Add input character buffer
unsigned char sdriver_input(void)
{
/*determine if there is a character waiting. If not, suspend */
tx_semaphore_get(&sdriver_input_semaphore, TX_WAIT_FOREVER);
/* Return character from serial RX hardware register */
return(*serial_hardware_input_ptr);
}
void sdriver_input_isr(void)
{
/* See if an input character notification is pending */
if(!sdriver_input_semaphore.tx_semaphore_count)
{
/* If not, notify thread of an input character */
tx_semaphore_put(&sdriver_input_semaphore);
}
}
Simple driver output:
Output semaphore is used to signal when the serial device's transmit register is free.
void sdriver_output(unsigned char alpha)
{
/* Determine if the hardware is ready to transmit a character.
If not, suspend until the previous output completes. */
tx_semaphore_get(&sdriver_output_semaphore, TX_WAIT_FOREVER);
/* Send the character through the hardware */
*serial_hardware_output_ptr = alpha;
}
void sdriver_output_isr(void)
{
/* Notify thread last character transmit is complete */
tx_semaphore_put(&sdriver_output_semaphore);
}
Shortcomings: Illustrates the basic idea of a simple driver.
Doesn't address data buff
Initialization
Two counting semaphores are used to manage the driver's input and output operation.
Input semaphore: Set by input ISR when a character is received by the serial hardware device
Semaphore is created with an initial value of 0.
Output semaphore: Indicates availability of the serial hardware transmit register
Semaphore is created with an initial value of 1 to indicate availability.
void sdriver_initialize(void)
{
/* Initialize the two counting semaphores user to control the simple I/O */
tx_semaphore_create(&sdriver_input_semaphore,"Sdriver Input Semaphore",0);
tx_semaphore_create(&sdriver_output_semaphore,"Sdriver Output Semaphore",1);
/* Setup interrupt vectors for input and output ISRs.
The initial vector handling should call the ISRs
defined in this file.*/
/* Configure serial device hardware for RX/TX interrupt
generation, baud reate, stop bits, etc. */
}
Simple driver input:
When a serial device interrupt is received, the input semaphore is set.
If one or more threads are waiting for a character from the driver, the
thread waiting the longest is resumed.
Limitations: Dropping input characters
Handled by: Add input character buffer
unsigned char sdriver_input(void)
{
/*determine if there is a character waiting. If not, suspend */
tx_semaphore_get(&sdriver_input_semaphore, TX_WAIT_FOREVER);
/* Return character from serial RX hardware register */
return(*serial_hardware_input_ptr);
}
void sdriver_input_isr(void)
{
/* See if an input character notification is pending */
if(!sdriver_input_semaphore.tx_semaphore_count)
{
/* If not, notify thread of an input character */
tx_semaphore_put(&sdriver_input_semaphore);
}
}
Simple driver output:
Output semaphore is used to signal when the serial device's transmit register is free.
void sdriver_output(unsigned char alpha)
{
/* Determine if the hardware is ready to transmit a character.
If not, suspend until the previous output completes. */
tx_semaphore_get(&sdriver_output_semaphore, TX_WAIT_FOREVER);
/* Send the character through the hardware */
*serial_hardware_output_ptr = alpha;
}
void sdriver_output_isr(void)
{
/* Notify thread last character transmit is complete */
tx_semaphore_put(&sdriver_output_semaphore);
}
Shortcomings: Illustrates the basic idea of a simple driver.
Doesn't address data buff
ering or any overhead issues.
Advanced driver issues:
1. Logic for Circular input buffer
unsigned char input_buffer[MAX_SIZE];
unsigned char *input_write_ptr;
unsigned char *input_read_ptr;
/* Initialization */
input_write_ptr = &input_buffer[0];
input_read_ptr = &input_buffer[0];
/* Input byte ISR... alpha has character from device */
save_ptr = input_write_ptr;
*input_write_ptr++ = alpha;
if(input_write_ptr > &input_buffer[MAX_SIZE-1])
input_write_ptr = &input_buffer[0]; /* Wrap */
if(input_write_ptr == input_read_ptr)
input_write_ptr = save_ptr; /* Buffer full */
/* Retrieve input byte from the buffer */
if(input_read_ptr != input_write_ptr)
{
alpha = *input_read_ptr++;
if(input_read_ptr > &input_buffer[MAX_SIZE -1 ])
input_read_ptr = &input_buffer[0];
}
2. Logic for Circular output buffer
unsigned char output_buffer[MAX_SIZE];
unsigned char *output_write_ptr;
unsinged char *output_read_ptr;
/* Initialization */
output_write_ptr = &output_buffer[0];
output_read_ptr = &output_buffer[0];
/* Transmit complete ISR... Device ready to send */
if(output_read_ptr != output_write_ptr)
{
*device_reg = *output_read_ptr++;
if(output_read_ptr > &output_buffer[MAX_SIZE-1])
output_read_ptr = &output_buffer[0];
}
/* Output drive buffer service. If device busy, buffer! */
save_ptr = output_write_ptr;
*output_write_ptr++ = alpha;
if(output_write_ptr > &output_buffer[MAX_SIZE -1 ] )
output_write_ptr = &output_buffer[0]; /* Wrap */
if(outpu_write_ptr == output_read_ptr)
output_write_ptr = save_ptr; /* Buffer full */
1. Logic for Circular input buffer
unsigned char input_buffer[MAX_SIZE];
unsigned char *input_write_ptr;
unsigned char *input_read_ptr;
/* Initialization */
input_write_ptr = &input_buffer[0];
input_read_ptr = &input_buffer[0];
/* Input byte ISR... alpha has character from device */
save_ptr = input_write_ptr;
*input_write_ptr++ = alpha;
if(input_write_ptr > &input_buffer[MAX_SIZE-1])
input_write_ptr = &input_buffer[0]; /* Wrap */
if(input_write_ptr == input_read_ptr)
input_write_ptr = save_ptr; /* Buffer full */
/* Retrieve input byte from the buffer */
if(input_read_ptr != input_write_ptr)
{
alpha = *input_read_ptr++;
if(input_read_ptr > &input_buffer[MAX_SIZE -1 ])
input_read_ptr = &input_buffer[0];
}
2. Logic for Circular output buffer
unsigned char output_buffer[MAX_SIZE];
unsigned char *output_write_ptr;
unsinged char *output_read_ptr;
/* Initialization */
output_write_ptr = &output_buffer[0];
output_read_ptr = &output_buffer[0];
/* Transmit complete ISR... Device ready to send */
if(output_read_ptr != output_write_ptr)
{
*device_reg = *output_read_ptr++;
if(output_read_ptr > &output_buffer[MAX_SIZE-1])
output_read_ptr = &output_buffer[0];
}
/* Output drive buffer service. If device busy, buffer! */
save_ptr = output_write_ptr;
*output_write_ptr++ = alpha;
if(output_write_ptr > &output_buffer[MAX_SIZE -1 ] )
output_write_ptr = &output_buffer[0]; /* Wrap */
if(outpu_write_ptr == output_read_ptr)
output_write_ptr = save_ptr; /* Buffer full */