/*
    Loopback.c, Copyright  (c) by George Fankhauser,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public Licence.
 
    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/
/*
	
	File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/IO/Drivers/Loopback.c,v $
 	Author(s):             George Fankhauser
 	Affiliation:           ETH Zuerich, TIK
 	Version:               $Revision: 2936 $
 	Creation Date:         
 	Last Date of Change:   $Date: 2007-03-21 15:23:42 +0100 (Mit, 21 Mär 2007) $      by: $Author: baderma $
	
	
	$Log: Loopback.c,v $
	Revision 1.5  2001/01/10 11:10:36  cjeker
	added dynamic IODevice structure
	
	Revision 1.4  2000/11/15 09:50:04  ruf
	IO/Drivers: Directory Cleaning
	
	Revision 1.3  1999/12/13 21:48:26  ruf
	GNU General Public Licence Update
	
	Revision 1.2  1999/01/06 17:47:34  cjeker
	code cleaning
	
	Revision 1.1  1997/05/30 18:03:30  gfa
	Initial revision
	
*/

#include "Drivers/Loopback.h"
#include "Messages.h"

IODeviceDesc loopbackDesc = {
                              NULL, NULL,              /* pointers for doubly linked list */
                              "loopback",              /* device name */
                              (Address)0,              /* device base address */
                              NULL,                    /* buffer must be allocated by driver */
                              -1,                      /* interrupt */
                              NULL,                    /* interrupt handling function */
                              0,                       /* thread id filled in after start */
                              devLoopback_read,        /* device read function */
                              devLoopback_write,       /* device write function */
                              devLoopback_close,       /* device close function */
                              devLoopback_init,        /* device init function */
                              NULL,                    /* private msg handler */
                              FALSE,                   /* initialisation state, normally FALSE */
                              NULL                     /* data extension */
                            };


Error devLoopback_init(IODevice this)
{
  devLoopback loopback;

  /* buffers init - be careful to check for existing buffers */
  if (!this->isInitialised)
  {
    hmAlloc((Address*)&(this->buffer), LOOPBACK_BUFSIZE);
    hmAlloc(&(this->extension), sizeof(devLoopbackDesc));
    loopback = (devLoopback)this->extension;

    this->isInitialised = TRUE;
  }
  else
  {
    loopback = (devLoopback)this->extension;
  }
  loopback->in = 0;
  loopback->out = 0;
  loopback->count = 0;

  return IO_INITOK;
}

Error devLoopback_read(IODevice this, ThreadId threadId, char* buffer,
                       long int* size)
{
  long int i = 0;
  devLoopback lb;
  lb = (devLoopback)this->extension;

  for (i = 0; i < *size; i++)
  {

    if (lb->count == 0)
      break;

    buffer[i] = this->buffer[lb->out];
    lb->out = (lb->out + 1) % LOOPBACK_BUFSIZE;
    lb->count--;
  }
  *size = i;
  return IO_READOK;
}

Error devLoopback_write(IODevice this, ThreadId threadId, char* buffer,
                        long int* size)
{
  long int i = 0;
  devLoopback lb;
  lb = (devLoopback)this->extension;

  for (i = 0; i < *size; i++)
  {

    if (lb->count == LOOPBACK_BUFSIZE)
      break;

    this->buffer[lb->in] = buffer[i];
    lb->in = (lb->in + 1) % LOOPBACK_BUFSIZE;
    lb->count++;
  }
  *size = i;
  return IO_WRITEOK;
}

Error devLoopback_close(IODevice this)
{
  /* this message is forwarded from ioThread */
  /* release buffers if any */


  if (this->isInitialised)
  {

    hmFree((Address)this->buffer);      /* Deallocate buffer space */
    hmFree((Address)this->extension);   /* Deallocate descriptor space */

    this->isInitialised = FALSE;        /* Set Initialized flag */
  }

  return IO_CLOSEOK;
}
