Chapter 8. Writing a device driver

Table of Contents
Interrupt handling
Input Output Request Blocks (IORBs)
Integrating a device driver with the Standard C Library

We now present procedures for writing device drivers, as well as some simple code samples.

Interrupt handling

The simplest device drivers install an interrupt handler using the facilities described in the section called Interrupt handling in Chapter 5. This involves defining two functions: an interrupt service routine and a delayed service routine and then using cyg_interrupt_create() and cyg_interrupt_attach() to install the handlers.

A very simple real-time clock driver which only keeps a system clock updated could be implemented by installing an interrupt handler for one of the timers.

Here is a small program with a driver for one of the timers. This program is really no more than a demonstration of how to install an interrupt handler that does something visible in response to hardware interrupts.

Caution

This example program will only work if you enable the configuration options CYGIMP_KERNEL_INTERRUPTS_CHAIN and CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN. It will hang otherwise.

Example 8-1. Simple clock driver


#include <cyg/kernel/kapi.h>
#include <stdio.h>

static volatile unsigned long n_timer_0_interrupts = 0;

/* this is the ISR for timer interrupts */
cyg_uint32 timer_0_handler(cyg_vector_t vector, cyg_addrword_t data)
{
  /* keep track of how many times that timer has interrupted us; this
     is basically all we do in this "driver" */
  ++n_timer_0_interrupts;
  /* ISRs must acknowledge the interrupt, or they might be invoked
     again */
  cyg_interrupt_acknowledge(vector);
  return CYG_ISR_HANDLED;
}

/* the main program here sits in an infinite loop seeing if
   n_timer_0_interrupts has changed, and printing the new values if it
   has changed */
int main( int argc, char *argv[] )
{
  cyg_handle_t timer_0_ISR_H;
  cyg_interrupt intr;
  unsigned long  previous_timer_0_count = 0;

   /* create an interrupt handler with timer_0_handler() as the ISR and
     no DSR.  A DSR is not needed here because the ISR simply
     increments a global variable and does not take much time or use
     any operating system services */

  cyg_interrupt_create(CYG_VECTOR_RTC, 0, 0, &timer_0_handler, NULL,
                       &timer_0_ISR_H, &intr);

  cyg_interrupt_attach(timer_0_ISR_H);


  for (;;) {
    if (n_timer_0_interrupts != previous_timer_0_count) {
      printf("new value of n_timer_0_interrupts: %lu\n",
             n_timer_0_interrupts);
      previous_timer_0_count = n_timer_0_interrupts;
    }
  }
}