OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [powerpc/] [shared/] [console/] [uart.c] - Rev 30

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * This software is Copyright (C) 1998 by T.sqware - all rights limited
 * It is provided in to the public domain "as is", can be freely modified
 * as far as this copyight notice is kept unchanged, but does not imply
 * an endorsement by T.sqware of the product in which it is included.
 *
 *  $Id: uart.c,v 1.2 2001-09-27 12:01:06 chris Exp $
 */
 
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/uart.h>
#include <rtems/libio.h>
#include <assert.h>
 
/*
 * Basic 16552 driver
 */
 
struct uart_data
{
  int hwFlow;
  int baud;
};
 
static struct uart_data uart_data[2];
 
/* 
 * Macros to read/wirte register of uart, if configuration is
 * different just rewrite these macros
 */ 
 
static inline unsigned char
uread(int uart, unsigned int reg)
{
  register unsigned char val;
 
  if(uart == 0)
    {
      inport_byte(COM1_BASE_IO+reg, val);
    }
  else
    {
      inport_byte(COM2_BASE_IO+reg, val);
    }
 
  return val;
}
 
static inline void      
uwrite(int uart, int reg, unsigned int val)
{
  if(uart == 0)
    {
      outport_byte(COM1_BASE_IO+reg, val);
    } 
  else
    {
      outport_byte(COM2_BASE_IO+reg, val);
    }
}
 
#ifdef UARTDEBUG
    static void
uartError(int uart)
{
  unsigned char uartStatus, dummy;
 
  uartStatus = uread(uart, LSR);
  dummy = uread(uart, RBR);
 
  if (uartStatus & OE)
    printk("********* Over run Error **********\n");
  if (uartStatus & PE)
    printk("********* Parity Error   **********\n");
  if (uartStatus & FE)
    printk("********* Framing Error  **********\n");
  if (uartStatus & BI)
    printk("********* Parity Error   **********\n");
  if (uartStatus & ERFIFO)
    printk("********* Error receive Fifo **********\n");
 
}
#else
inline void uartError(int uart)
{
  unsigned char uartStatus;
 
  uartStatus = uread(uart, LSR);
  uartStatus = uread(uart, RBR);
}
#endif
 
/* 
 * Uart initialization, it is hardcoded to 8 bit, no parity,
 * one stop bit, FIFO, things to be changed
 * are baud rate and nad hw flow control,
 * and longest rx fifo setting
 */
void
BSP_uart_init(int uart, int baud, int hwFlow)
{
  unsigned char tmp;
 
  /* Sanity check */
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  switch(baud)
    {
    case 50:
    case 75:
    case 110:
    case 134:
    case 300:
    case 600:
    case 1200:
    case 2400:
    case 9600:
    case 19200:
    case 38400:
    case 57600:
    case 115200:
      break;
    default:
      assert(0);
      return;
    }
 
  /* Set DLAB bit to 1 */
  uwrite(uart, LCR, DLAB);
 
  /* Set baud rate */
  uwrite(uart, DLL,  (BSPBaseBaud/baud) & 0xff); 
  uwrite(uart, DLM,  ((BSPBaseBaud/baud) >> 8) & 0xff); 
 
  /* 8-bit, no parity , 1 stop */
  uwrite(uart, LCR, CHR_8_BITS);
 
 
  /* Set DTR, RTS and OUT2 high */
  uwrite(uart, MCR, DTR | RTS | OUT_2);
 
  /* Enable FIFO */
  uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12); 
 
  /* Disable Interrupts */
  uwrite(uart, IER, 0);
 
  /* Read status to clear them */
  tmp = uread(uart, LSR);
  tmp = uread(uart, RBR);
  tmp = uread(uart, MSR);
 
  /* Remember state */
  uart_data[uart].hwFlow     = hwFlow;
  uart_data[uart].baud       = baud;
  return;
}
 
/* 
 * Set baud
 */
void
BSP_uart_set_baud(int uart, int baud)
{
  unsigned char mcr, ier;
 
  /* Sanity check */
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  /* 
   * This function may be called whenever TERMIOS parameters
   * are changed, so we have to make sire that baud change is 
   * indeed required
   */
 
  if(baud == uart_data[uart].baud)
    {
      return;
    }
 
  mcr = uread(uart, MCR);
  ier = uread(uart, IER);
 
  BSP_uart_init(uart, baud, uart_data[uart].hwFlow);
 
  uwrite(uart, MCR, mcr);
  uwrite(uart, IER, ier);
 
  return;
}
 
/*
 * Enable/disable interrupts 
 */
void 
BSP_uart_intr_ctrl(int uart, int cmd)
{
 
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  switch(cmd)
    {
    case BSP_UART_INTR_CTRL_DISABLE:
      uwrite(uart, IER, INTERRUPT_DISABLE);
      break;
    case BSP_UART_INTR_CTRL_ENABLE:
      if(uart_data[uart].hwFlow)
	{
	  uwrite(uart, IER,
		 (RECEIVE_ENABLE  |
		  TRANSMIT_ENABLE |
		  RECEIVER_LINE_ST_ENABLE |
		  MODEM_ENABLE
		 )
		);
	}
      else
	{
	  uwrite(uart, IER,
		 (RECEIVE_ENABLE  |
		  TRANSMIT_ENABLE |
		  RECEIVER_LINE_ST_ENABLE
		 )
		);
	}
      break;
    case BSP_UART_INTR_CTRL_TERMIOS:
      if(uart_data[uart].hwFlow)
	{
	  uwrite(uart, IER,
		 (RECEIVE_ENABLE  |
		  RECEIVER_LINE_ST_ENABLE |
		  MODEM_ENABLE
		 )
		);
	}
      else
	{
	  uwrite(uart, IER,
		 (RECEIVE_ENABLE  |
		  RECEIVER_LINE_ST_ENABLE
		 )
		);
	}
      break;
    case BSP_UART_INTR_CTRL_GDB:
      uwrite(uart, IER, RECEIVE_ENABLE);
      break;
    default:
      assert(0);
      break;
    }
 
  return;
}
 
void
BSP_uart_throttle(int uart)
{
  unsigned int mcr;
 
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  if(!uart_data[uart].hwFlow)
    {
      /* Should not happen */
      assert(0);
      return;
    }
  mcr = uread (uart, MCR);
  /* RTS down */
  mcr &= ~RTS;
  uwrite(uart, MCR, mcr);
 
  return;
}
 
void
BSP_uart_unthrottle(int uart)
{
  unsigned int mcr;
 
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  if(!uart_data[uart].hwFlow)
    {
      /* Should not happen */
      assert(0);
      return;
    }
  mcr = uread (uart, MCR);
  /* RTS up */
  mcr |= RTS;
  uwrite(uart, MCR, mcr);
 
  return;
}
 
/*
 * Status function, -1 if error
 * detected, 0 if no received chars available,
 * 1 if received char available, 2 if break
 * is detected, it will eat break and error 
 * chars. It ignores overruns - we cannot do 
 * anything about - it execpt count statistics
 * and we are not counting it.
 */
int 
BSP_uart_polled_status(int uart)
{
  unsigned char val;
 
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  val = uread(uart, LSR);
 
  if(val & BI)
    {
      /* BREAK found, eat character */
      uread(uart, RBR);
      return BSP_UART_STATUS_BREAK;
    }
 
  if((val & (DR | OE | FE)) ==  1)
    {
      /* No error, character present */ 
      return BSP_UART_STATUS_CHAR;
    }
 
  if((val & (DR | OE | FE)) == 0)
    {
      /* Nothing */
      return BSP_UART_STATUS_NOCHAR;
    }
 
  /* 
   * Framing or parity error
   * eat character
   */
  uread(uart, RBR);
 
  return BSP_UART_STATUS_ERROR;
}
 
 
/*
 * Polled mode write function
 */
void 
BSP_uart_polled_write(int uart, int val)
{
  unsigned char val1;
 
  /* Sanity check */
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  for(;;)
    {
      if((val1=uread(uart, LSR)) & THRE)
	{
	  break;
	}
    }
 
  if(uart_data[uart].hwFlow)
    {
      for(;;)
	{
	  if(uread(uart, MSR) & CTS)
	    {
	      break;
	    }
	}
    }
 
  uwrite(uart, THR, val & 0xff);
 
  return;
}
 
void
BSP_output_char_via_serial(int val)
{
  BSP_uart_polled_write(BSPConsolePort, val);
  if (val == '\n') BSP_uart_polled_write(BSPConsolePort,'\r');
}
 
/* 
 * Polled mode read function
 */
int 
BSP_uart_polled_read(int uart)
{
  unsigned char val;
 
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  for(;;)
    {
      if(uread(uart, LSR) & DR)
	{
	  break;
	}
    }
 
  val = uread(uart, RBR);
 
  return (int)(val & 0xff);
}
 
unsigned 
BSP_poll_char_via_serial()
{
	return BSP_uart_polled_read(BSPConsolePort);
}
 
 
/* ================ Termios support  =================*/
 
static volatile int  termios_stopped_com1        = 0;
static volatile int  termios_tx_active_com1      = 0;
static void*	     termios_ttyp_com1           = NULL;
static char          termios_tx_hold_com1        = 0;
static volatile char termios_tx_hold_valid_com1  = 0;
 
static volatile int  termios_stopped_com2        = 0;
static volatile int  termios_tx_active_com2      = 0;
static void*	     termios_ttyp_com2           = NULL;
static char          termios_tx_hold_com2        = 0;
static volatile char termios_tx_hold_valid_com2  = 0;
 
/*
 * Set channel parameters 
 */
void
BSP_uart_termios_set(int uart, void *ttyp)
{
  unsigned char val;
  assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
 
  if(uart == BSP_UART_COM1)
    {
      if(uart_data[uart].hwFlow)
	{
	  val = uread(uart, MSR);
 
	  termios_stopped_com1   = (val & CTS) ? 0 : 1;
	}
      else
	{
	  termios_stopped_com1 = 0;
	}
      termios_tx_active_com1      = 0;
      termios_ttyp_com1           = ttyp;
      termios_tx_hold_com1        = 0; 
      termios_tx_hold_valid_com1  = 0;
    }
  else
    {
      if(uart_data[uart].hwFlow)
	{
	  val = uread(uart, MSR);
 
	  termios_stopped_com2   = (val & CTS) ? 0 : 1;
	}
      else
	{
	  termios_stopped_com2 = 0;
	}
      termios_tx_active_com2      = 0;
      termios_ttyp_com2           = ttyp;
      termios_tx_hold_com2        = 0; 
      termios_tx_hold_valid_com2  = 0;
    }
 
  return;
}
 
int
BSP_uart_termios_write_com1(int minor, const char *buf, int len)
{
  assert(buf != NULL);
 
  if(len <= 0)
    {
      return 0;
    }
 
  /* If there TX buffer is busy - something is royally screwed up */
  /*   assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */
 
 
  if(termios_stopped_com1)
    {
      /* CTS low */
      termios_tx_hold_com1       = *buf;
      termios_tx_hold_valid_com1 = 1;
      return 0;
    }
 
  /* Write character */
  uwrite(BSP_UART_COM1, THR, *buf & 0xff);
 
  /* Enable interrupts if necessary */
  if(!termios_tx_active_com1 && uart_data[BSP_UART_COM1].hwFlow)
    {
      termios_tx_active_com1 = 1;
      uwrite(BSP_UART_COM1, IER,
	     (RECEIVE_ENABLE  |
	      TRANSMIT_ENABLE |
	      RECEIVER_LINE_ST_ENABLE |
	      MODEM_ENABLE
	     )
	    );
    }
  else if(!termios_tx_active_com1)
    {
      termios_tx_active_com1 = 1;
      uwrite(BSP_UART_COM1, IER, 
	     (RECEIVE_ENABLE  |
	      TRANSMIT_ENABLE |
	      RECEIVER_LINE_ST_ENABLE
	     )
	    );
    }
 
  return 0;
}
 
int
BSP_uart_termios_write_com2(int minor, const char *buf, int len)
{
  assert(buf != NULL);
 
  if(len <= 0)
    {
      return 0;
    }
 
 
  /* If there TX buffer is busy - something is royally screwed up */
  assert((uread(BSP_UART_COM2, LSR) & THRE) != 0);
 
  if(termios_stopped_com2)
    {
      /* CTS low */
      termios_tx_hold_com2       = *buf;
      termios_tx_hold_valid_com2 = 1;
      return 0;
    }
 
  /* Write character */
 
  uwrite(BSP_UART_COM2, THR, *buf & 0xff);
 
  /* Enable interrupts if necessary */
  if(!termios_tx_active_com2 && uart_data[BSP_UART_COM2].hwFlow)
    {
      termios_tx_active_com2 = 1;
      uwrite(BSP_UART_COM2, IER,
	     (RECEIVE_ENABLE  |
	      TRANSMIT_ENABLE |
	      RECEIVER_LINE_ST_ENABLE |
	      MODEM_ENABLE
	     )
	    );
    }
  else if(!termios_tx_active_com2)
    {
      termios_tx_active_com2 = 1;
      uwrite(BSP_UART_COM2, IER,
	     (RECEIVE_ENABLE  |
	      TRANSMIT_ENABLE |
	      RECEIVER_LINE_ST_ENABLE
	     )
	    );
    }
 
  return 0;
}
 
 
void
BSP_uart_termios_isr_com1(void)
{
  unsigned char buf[40];
  unsigned char val;
  int      off, ret, vect;
 
  off = 0;
 
  for(;;)
    {
      vect = uread(BSP_UART_COM1, IIR) & 0xf;
 
      switch(vect)
	{
	case MODEM_STATUS :
	  val = uread(BSP_UART_COM1, MSR);
	  if(uart_data[BSP_UART_COM1].hwFlow)
	    {
	      if(val & CTS)
		{
		  /* CTS high */
		  termios_stopped_com1 = 0;
		  if(termios_tx_hold_valid_com1)
		    {
		      termios_tx_hold_valid_com1 = 0;
		      BSP_uart_termios_write_com1(0, &termios_tx_hold_com1,
						    1);
		    }
		}
	      else
		{
		  /* CTS low */
		  termios_stopped_com1 = 1;
		}
	    }
	  break;
	case NO_MORE_INTR :
	  /* No more interrupts */
	  if(off != 0)
	    {
	      /* Update rx buffer */
	      rtems_termios_enqueue_raw_characters(termios_ttyp_com1,
						   (char *)buf,
						   off);
	    }
	  return;
	case TRANSMITTER_HODING_REGISTER_EMPTY :
	  /* 
	   * TX holding empty: we have to disable these interrupts 
	   * if there is nothing more to send. 
	   */
 
	  ret = rtems_termios_dequeue_characters(termios_ttyp_com1, 1);
 
	  /* If nothing else to send disable interrupts */
	  if(ret == 0 && uart_data[BSP_UART_COM1].hwFlow)
	    {
	      uwrite(BSP_UART_COM1, IER,
		     (RECEIVE_ENABLE  |
		      RECEIVER_LINE_ST_ENABLE |
		      MODEM_ENABLE
		     )
		    );
              termios_tx_active_com1 = 0;
	    }
	  else if(ret == 0)
	    {
	      uwrite(BSP_UART_COM1, IER,
		     (RECEIVE_ENABLE  |
		      RECEIVER_LINE_ST_ENABLE
		     )
		    );
              termios_tx_active_com1 = 0;
	    }
	  break;
	case RECEIVER_DATA_AVAIL :
	case CHARACTER_TIMEOUT_INDICATION:
	  /* RX data ready */
	  assert(off < sizeof(buf));
	  buf[off++] = uread(BSP_UART_COM1, RBR);
	  break;
	case RECEIVER_ERROR:
	  /* RX error: eat character */
	   uartError(BSP_UART_COM1);
	  break;
	default:
	  /* Should not happen */
	  assert(0);
	  return;
	}
    }
}
 
void
BSP_uart_termios_isr_com2()
{
  unsigned char buf[40];
  unsigned char val;
  int      off, ret, vect;
 
  off = 0;
 
  for(;;)
    {
      vect = uread(BSP_UART_COM2, IIR) & 0xf;
 
      switch(vect)
	{
	case MODEM_STATUS :
	  val = uread(BSP_UART_COM2, MSR);
	  if(uart_data[BSP_UART_COM2].hwFlow)
	    {
	      if(val & CTS)
		{
		  /* CTS high */
		  termios_stopped_com2 = 0;
		  if(termios_tx_hold_valid_com2)
		    {
		      termios_tx_hold_valid_com2 = 0;
		      BSP_uart_termios_write_com2(0, &termios_tx_hold_com2,
						    1);
		    }
		}
	      else
		{
		  /* CTS low */
		  termios_stopped_com2 = 1;
		}
	    }
	  break;
	case NO_MORE_INTR :
	  /* No more interrupts */
	  if(off != 0)
	    {
	      /* Update rx buffer */
	      rtems_termios_enqueue_raw_characters(termios_ttyp_com2,
						   (char *)buf,
						   off);
	    }
	  return;
	case TRANSMITTER_HODING_REGISTER_EMPTY :
	  /* 
	   * TX holding empty: we have to disable these interrupts 
	   * if there is nothing more to send.
	   */
 
	  ret = rtems_termios_dequeue_characters(termios_ttyp_com2, 1);
 
	  /* If nothing else to send disable interrupts */
	  if(ret == 0 && uart_data[BSP_UART_COM2].hwFlow)
	    {
	      uwrite(BSP_UART_COM2, IER,
		     (RECEIVE_ENABLE  |
		      RECEIVER_LINE_ST_ENABLE |
		      MODEM_ENABLE
		     )
		    );
              termios_tx_active_com2 = 0;
	    }
	  else if(ret == 0)
	    {
	      uwrite(BSP_UART_COM2, IER,
		     (RECEIVE_ENABLE  |
		      RECEIVER_LINE_ST_ENABLE
		     )
		    );
              termios_tx_active_com2 = 0;
	    }
	  break;
	case RECEIVER_DATA_AVAIL :
	case CHARACTER_TIMEOUT_INDICATION:
	  /* RX data ready */
	  assert(off < sizeof(buf));
	  buf[off++] = uread(BSP_UART_COM2, RBR);
	  break;
	case RECEIVER_ERROR:
	  /* RX error: eat character */
	   uartError(BSP_UART_COM2);
	  break;
	default:
	  /* Should not happen */
	  assert(0);
	  return;
	}
    }
}
 
 
 
 
 
 
 
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.