/*
    SimOSConsole.c, Copyright  (c) by 
    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/mips/Drivers/SimOSConsole.c,v $
 	Author(s):             
 	Affiliation:           ETH Zuerich, TIK
 	Version:               $Revision: 2922 $
 	Creation Date:         
 	Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $      by: $Author: baderma $
	
	
	$Log: SimOSConsole.c,v $
	Revision 1.2  2001/01/10 11:10:40  cjeker
	added dynamic IODevice structure
	
	Revision 1.1  2000/11/15 10:02:48  ruf
	IO Directory structure change
	
	Revision 1.4  1999/12/13 21:48:26  ruf
	GNU General Public Licence Update
	
	Revision 1.3  1999/10/31 14:42:45  jeker
	first fixes for SimOS
	
	Revision 1.2  1999/10/23 14:19:44  jeker
	first cleanup for R4k support
 
*/

#include "Drivers/SimOSConsole.h"
#include "Messages.h"
#include "IODevice.h"

#define CONSOLE_BUFFER_SIZE 128

IODeviceDesc simosConsDesc = {
                               NULL, NULL,              /* pointers for doubly linked list */
                               "tty",                   /* device name */
                               (Address)0,              /* device base address */
                               NULL,                    /* buffer must be allocated by driver */
                               DUARTINT,                /* interrupt */
                               (InterruptHandler)simos_console_handler,
                               /* interrupt handling routine */
                               0,                       /* thread id filled in after start */
                               simos_console_read,      /* device read function */
                               simos_console_write,     /* device write function */
                               simos_console_close,     /* device close function */
                               simos_console_init,      /* device init function */
                               NULL,                    /* private msg handler */
                               FALSE,                   /* initialisation state, normally FALSE */
                               NULL                     /* data extension */
                             };

/* There is no reason why this should not be static. BTW, read_pos and
 * write_pos store the total number of characters read/written, which,
 * theoretically, is a bug (as they may overflow), but, in practice, I
 * doubt anyone is going to ever send 2GB of characters in a single session,
 * and the code is much cleaner this way. -- PZ */
static char console_buffer[CONSOLE_BUFFER_SIZE];
static int  read_pos = 0, write_pos = 0;

/* Interrupt handler. */
void simos_console_handler(IODevice this)
{
  if (write_pos - read_pos >= CONSOLE_BUFFER_SIZE)
    WARNING("Console buffer overflow\n");
  else
  {
    console_buffer[write_pos++ % CONSOLE_BUFFER_SIZE]
    = _SIMOS_CONSOLE->data;
  }
}

/* Initialization routine. */
Error simos_console_init(IODevice this)
{
  _SIMOS_CONSOLE->intr_status = CONS_INT_RX; /* Enable console interrupts. */
  return IO_INITOK;
}

/* Read data from the buffer. */
Error simos_console_read(IODevice this, ThreadId threadId,
                         char* buffer, long int* size)
{
  int i = 0;

  while (read_pos < write_pos && write_pos - read_pos < *size)
    buffer[i++] = console_buffer[read_pos++ % CONSOLE_BUFFER_SIZE];
  *size = i;
  return IO_READOK;
}


Error simos_console_write(IODevice this, ThreadId threadId,
                          char* buffer, long int* size)
{
  while ((*size) > 0)
  {
    _SIMOS_CONSOLE->data = *buffer++;
    --*size;
  }
  return IO_WRITEOK;
}

Error simos_console_close(IODevice this)
{
  /* this message is forwarded from ioThread */

  /* release buffers if any */

  /* disable console interrupts */
  _SIMOS_CONSOLE->intr_status = 0;

  return IO_CLOSEOK;
}
