The minidriver handler function

The prototype for the minidriver handler function is as follows:

int mdriver_handler(int state, void *data);

The state value informs the handler function where in the boot process it's being called from. See the mdriver_add() documentation in the API and Datatypes chapter of this guide. The data parameter is a virtual pointer to the minidriver's allocated data area. For this sample driver, the source code for the handler function would look like this:

struct mserial_data
{
   uintptr_t	port;
   uintptr_t	port_k;
   uint16_t	intr_calls;
   uint16_t	ncalls;
   uint16_t	errors;
   uint16_t	err;
   uint16_t	last_count;
   uint16_t 	data_len;
};


void Delay(int n)
{
   unsigned int i;
   for(i=0;i<n;i++);
}

uintptr_t
init_hw()
{
   int 	cnt; 
   uint64_t	base = SH_SCIF_BASE;
   int		baud = 14400;
   int		clk = 33333333;
   unsigned port;
	
   if ((port = startup_io_map(120, base)) == NULL)
       return (NULL);
	
    cnt = clk / (baud * 64 / 2) - 1;  // assumes SCSMR1.CKS = 0

    //	set clock selection
    out16(port + SH_SCIF_SCSCR_OFF, 0x0);
    Delay(1);

    // Enable reset state of the FIFO register
    out16(port + SH_SCIF_SCFCR_OFF, SH_SCIF_SCFCR_TFRST | SH_SCIF_SCFCR_RFRST);

    // data transfer format
    // 8 bits no parity
    // CKS = 0
    out16(port + SH_SCIF_SCSMR_OFF,0);
    Delay(1);

    // baud rate
    out8(port + SH_SCIF_SCBRR_OFF,cnt);
    Delay(1);

    //Disable the reset state of the fifo
    set_port16(port + SH_SCIF_SCFCR_OFF, SH_SCIF_SCFCR_TFRST | SH_SCIF_SCFCR_RFRST, 0);

    // FIFO control
    out16(port + SH_SCIF_SCFCR_OFF + 4, 0x0);
    Delay(1);

    out8(port + SH_SCIF_SCFTDR_OFF, 0);
    Delay(1);

    out16(port + SH_SCIF_SCSPTR_OFF + 4, 0x41);

    out16(port + SH_SCIF_SCFCR_OFF, 0x30 | 0x200 | SH_SCIF_SCFCR_MCE);
	
    out16(port + SH_SCIF_SCSCR_OFF, SH_SCIF_SCSCR_RE | SH_SCIF_SCSCR_TE |
                                  SH_SCIF_SCSCR_TIE | SH_SCIF_SCSCR_RIE);
    Delay(1);	
    out16(port + SH7760_SCIF_SCSPTR_OFF, SH_SCIF_SCSPTR_RTSIO);

    out16(port + SH_SCIF_SCSCR_OFF, SH_SCIF_SCSCR_RE | SH_SCIF_SCSCR_RIE);

    return (port);
}


int 
mini_serial(int state, void *data)
{
   uint8_t	   	*bp = 0;
   uint16_t	count;
   uint8_t		*dptr, c;
   struct mserial_data	*mdata;
   int num, i;
   int          pending_interrupts;

   mdata = (struct mserial_data *) data;
   dptr = (uint8_t *) (mdata + 1);

   if (state == MDRIVER_INTR_ATTACH)
   {
      /* disable the serial interrupt */
      set_port16(mdata->port + SH_SCIF_SCSCR_OFF, SH_SCIF_SCSCR_RE | SH_SCIF_SCSCR_RIE, 0);
	    	return (1);
   }
   else if (state == MDRIVER_INIT)
   {
      /* the first time called initialize the hardware and do data setup */
      mdata->port = init_hw();
      if (mdata->port == 0)
	 return (1);
      mdata->intr_calls = 0;
      mdata->ncalls = 0;
      mdata->errors = 0;
      mdata->data_len = 0;
   }
   else if (state == MDRIVER_STARTUP_PREPARE)
   {
      /* once we are out of startup use callout_io_map */
      if ((mdata->port_k = callout_io_map(0x120, SH_SCIF_BASE)) == 0)
      {
	 /* something bad so disable the driver */
	 set_port16(mdata->port + SH_SCIF_SCSCR_OFF, SH_SCIF_SCSCR_RE | SH_SCIF_SCSCR_RIE, 0);
	 return (1);
       }
   }

   /* count the number of times the mini-driver is called */
   count = mdata->ncalls + 1;
   mdata->ncalls = count;
   if (state == MDRIVER_PROCESS)
   {
      /* called because of an interrupt */
      count = mdata->intr_calls + 1;
      mdata->intr_calls = count;
   }	

   /* get the data from the serial port and clear any errors */

   // Handle the error messages: Overrun, Framing, Parity
   pending_interrupts = in16(mdata->port + SH_SCIF_SCFSR_OFF);
   if (in8(mdata->port + SH7760_SCIF_SCLSR_OFF) & SH_SCIF_SCLSR_ORER) 
   {
      set_port16(mdata->port + SH7760_SCIF_SCLSR_OFF, SH_SCIF_SCLSR_ORER, 0);
   }
   if ((pending_interrupts & SH_SCIF_SCFSR_PER)) 
   {
      set_port16(mdata->port + SH_SCIF_SCFSR_OFF, SH_SCIF_SCFSR_PER | 
          SH_SCIF_SCFSR_ER | SH_SCIF_SCFSR_DR, 0);
   }
   if (pending_interrupts & SH_SCIF_SCFSR_FER) 
   {
      set_port16(mdata->port + SH_SCIF_SCFSR_OFF, 
          SH_SCIF_SCFSR_FER | SH_SCIF_SCFSR_ER | SH_SCIF_SCFSR_DR, 0);
   }
   if (pending_interrupts & SH_SCIF_SCFSR_BRK ) 
   {
      set_port16(mdata->port + SH_SCIF_SCFSR_OFF, SH_SCIF_SCFSR_BRK | SH_SCIF_SCFSR_DR, 0);
   }

   /* grab data */
   if (in16(mdata->port + SH7760_SCIF_SCRFDR_OFF)	)
   {
      c = in8(mdata->port + SH_SCIF_SCFRDR_OFF);
      set_port16(mdata->port + SH_SCIF_SCFSR_OFF, SH_SCIF_SCFSR_RDF, 0);
	    
      dptr[mdata->data_len] = c;
      mdata->data_len = mdata->data_len + 1;
   }
			        
   if (pending_interrupts & (SH_SCIF_SCFSR_TDFE|SH_SCIF_SCFSR_TEND) )
   {
      set_port16(mdata->port + SH_SCIF_SCSCR_OFF, SH_SCIF_SCSCR_TIE,0);
   }
		
   //Clear all the interrupts
   set_port16(mdata->port + SH7760_SCIF_SCLSR_OFF, SH_SCIF_SCLSR_ORER, 0);
   set_port16(mdata->port + SH_SCIF_SCFSR_OFF, 0xff, 0);

   if (state == MDRIVER_STARTUP_FINI)
      mdata->port = mdata->port_k;	
	
   return (0);
}

In this example, the handler function stores call information, so a structure has been created to allow easier access to the data area. The data area is filled with the received characters.

During the MDRIVER_INIT state, the data area is initialized and the serial hardware is set up; this is called only once. At this time, the startup_io_map() is called to map in the hardware registers, and the pointer is stored in the data area.

This pointer is used for hardware access until the handler is called with a state of STARTUP_MDRIVER_PREPARE. At this time, callout_io_map() is called and the pointer is stored in the data area, however the startup_io_map() pointer should still be used. Once the handler is called with a state of MDRIVER_STARTUP_FINI, the handler starts using the pointer returned by callout_io_map() for all hardware access. This pointer is then used for all further invocations of the minidriver handler.

When the handler is called with a state of MDRIVER_INTR_ATTACH; it disables the device interrupt and returns a value of 1 requesting an exit of the handler.