summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/uart
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2007-09-06 13:27:25 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2007-09-06 13:27:25 +0000
commit226455f9fffef4c88b67aeef113a97dcaabd4b00 (patch)
tree8771eee8053655a1c09977a68efd2ba35ee173c5 /c/src/lib/libbsp/sparc/shared/uart
parent2007-09-06 Daniel Hellstrom <daniel@gaisler.com> (diff)
downloadrtems-226455f9fffef4c88b67aeef113a97dcaabd4b00.tar.bz2
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
New drivers: PCI, b1553BRM, SpaceWire(GRSPW), CAN (GRCAN,OC_CAN), Raw UART. * shared/1553/b1553brm.c, shared/1553/b1553brm_pci.c, shared/1553/b1553brm_rasta.c, shared/can/grcan.c, shared/can/grcan_rasta.c, shared/can/occan.c, shared/can/occan_pci.c, shared/spw/grspw.c, shared/spw/grspw_pci.c, shared/spw/grspw_rasta.c, shared/uart/apbuart.c, shared/uart/apbuart_pci.c, shared/uart/apbuart_rasta.c: New files missed in previous commit.
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/uart')
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart.c885
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c42
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c42
3 files changed, 969 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart.c
new file mode 100644
index 0000000000..f204d96162
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart.c
@@ -0,0 +1,885 @@
+/*
+ * This file contains the driver for the APBUART serial port.
+ * No console driver, only char driver.
+ *
+ * COPYRIGHT (c) 2007.
+ * Gaisler Research.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ *
+ * 2007-07-11, Daniel Hellstrom <daniel@gaisler.com>
+ * Added ioctl command APBUART_CLR_STATS
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+
+#include <ambapp.h>
+#include <apbuart.h>
+
+#ifndef DEFAULT_TXBUF_SIZE
+ #define DEFAULT_TXBUF_SIZE 32
+#endif
+#ifndef DEFAULT_RXBUF_SIZE
+ #define DEFAULT_RXBUF_SIZE 32
+#endif
+
+#ifndef APBUART_PREFIX
+ #define APBUART_PREFIX(name) apbuart##name
+#endif
+
+#if !defined(APBUART_DEVNAME) || !defined(APBUART_DEVNAME_NO)
+ #undef APBUART_DEVNAME
+ #undef APBUART_DEVNAME_NO
+ #define APBUART_DEVNAME "/dev/apbuart0"
+ #define APBUART_DEVNAME_NO(devstr,no) ((devstr)[12]='0'+(no))
+#endif
+
+#ifndef APBUART_REG_INT
+ #define APBUART_REG_INT(handler,irq,arg) set_vector(handler,irq+0x10,1)
+#endif
+
+/* Default to 40MHz system clock */
+/*#ifndef SYS_FREQ_HZ
+ #define SYS_FREQ_HZ 40000000
+#endif*/
+
+typedef struct {
+ int size;
+ unsigned char *buf,
+ *tail,
+ *head,
+ *max;
+ int full; /* no more place in fifo */
+} apbuart_fifo;
+
+static apbuart_fifo *apbuart_fifo_create(int size);
+static void apbuart_fifo_free(apbuart_fifo *fifo);
+static inline int apbuart_fifo_isFull(apbuart_fifo *fifo);
+static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo);
+static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c);
+static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c);
+static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c);
+static void inline apbuart_fifo_skip(apbuart_fifo *fifo);
+
+static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+typedef struct {
+ ambapp_apb_uart *regs;
+ int irq;
+ int minor;
+ int scaler;
+ unsigned int baud;
+
+ int txblk; /* Make write block until at least 1 char has
+ * been put into software send fifo
+ */
+ int tx_flush; /* Set this to block until all data has
+ * placed into the hardware send fifo
+ */
+ int rxblk; /* Make read block until at least 1 char has
+ * been received (or taken from software fifo).
+ */
+ int started; /* Set to 1 when in running mode */
+
+ int ascii_mode; /* Set to 1 to make \n be printed as \r\n */
+
+ /* TX/RX software FIFO Buffers */
+ apbuart_fifo *txfifo;
+ apbuart_fifo *rxfifo;
+
+ apbuart_stats stats;
+
+ rtems_id dev_sem;
+ rtems_id rx_sem;
+ rtems_id tx_sem;
+} apbuart_priv;
+
+static int dev_cnt;
+static apbuart_priv *apbuarts;
+static unsigned int sys_freq_hz;
+
+#define APBUART_DRIVER_TABLE_ENTRY { apbuart_initialize, apbuart_open, apbuart_close, apbuart_read, apbuart_write, apbuart_control }
+
+static rtems_driver_address_table apbuart_driver = APBUART_DRIVER_TABLE_ENTRY;
+static amba_confarea_type *amba_bus;
+
+static void apbuart_interrupt(apbuart_priv *uart);
+static void apbuart_interrupt_handler(rtems_vector_number v);
+static void apbuart_hw_close(apbuart_priv *uart);
+static void apbuart_hw_open(apbuart_priv *uart);
+
+/* Uncomment for debug output */
+/* #define DEBUG 1
+ #define FUNCDEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+#ifdef FUNCDEBUG
+#define FUNCDBG(x...) printk(x)
+#else
+#define FUNCDBG(x...)
+#endif
+
+#ifndef READ_REG
+ #define READ_REG(address) _APBUART_READ_REG((unsigned int)(address))
+ static __inline__ unsigned int _APBUART_READ_REG(unsigned int addr) {
+ unsigned int tmp;
+ asm(" lda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
+ }
+#endif
+
+#if 0
+static int apbuart_outbyte_try(ambapp_apb_uart *regs, unsigned char ch)
+{
+ if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_THE) == 0 )
+ return -1; /* Failed */
+
+ /* There is room in fifo, put ch in it */
+ regs->data = (unsigned int) ch;
+ return 0;
+}
+
+
+static int apbuart_inbyte_try(ambapp_apb_uart *regs)
+{
+ unsigned int status;
+ /* Clear errors if any */
+ if ( (status=READ_REG(&regs->status)) & LEON_REG_UART_STATUS_ERR) {
+ regs->status = status & ~LEON_REG_UART_STATUS_ERR;
+ }
+
+ /* Is Data available? */
+ if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_DR) == 0 )
+ return -1; /* No data avail */
+
+ /* Return Data */
+ return (int)READ_REG(&regs->data);
+}
+
+static int apbuart_write_support(apbuart_priv *uart, const char *buf, int len)
+{
+ int nwrite = 0;
+
+ while (nwrite < len) {
+ if ( apbuart_outbyte_try(minor, *buf++) ){
+ /* TX Fifo full */
+
+ }
+ nwrite++;
+ }
+ return nwrite;
+}
+#endif
+
+static void apbuart_hw_open(apbuart_priv *uart){
+ unsigned int scaler;
+
+ /* Calculate Baudrate */
+ if ( uart->scaler > 0 ) {
+ scaler = uart->scaler;
+ }else{
+ scaler = (((sys_freq_hz*10)/(uart->baud*8))-5)/10;
+ }
+
+ /* Set new baud rate */
+ uart->regs->scaler = scaler;
+
+ /* Enable receiver & Transmitter */
+ uart->regs->ctrl = APBUART_CTRL_RE | APBUART_CTRL_RF | APBUART_CTRL_RI | APBUART_CTRL_TI;
+}
+
+static void apbuart_hw_close(apbuart_priv *uart){
+ /* disable receiver & transmitter & all IRQs */
+ uart->regs->ctrl = 0;
+}
+
+/* interrupt handler */
+static void apbuart_interrupt_handler(rtems_vector_number v){
+ int minor;
+
+ /* convert to */
+ for(minor = 0; minor < dev_cnt; minor++) {
+ if ( v == (apbuarts[minor].irq+0x10) ) {
+ apbuart_interrupt(&apbuarts[minor]);
+ return;
+ }
+ }
+}
+
+/* The interrupt handler, taking care of the
+ * APBUART hardware
+ */
+static void apbuart_interrupt(apbuart_priv *uart){
+ unsigned int status;
+ int empty;
+ unsigned char c, *next_char;
+ int signal;
+
+ /* Clear & record any error */
+ status = READ_REG(&uart->regs->status);
+ if ( status & (APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE) ){
+ /* Data overrun */
+ if ( status & APBUART_STATUS_OV ){
+ uart->stats.hw_dovr++;
+ }
+ /* Parity error */
+ if ( status & APBUART_STATUS_PE ){
+ uart->stats.hw_parity++;
+ }
+ /* Framing error */
+ if ( status & APBUART_STATUS_FE ){
+ uart->stats.hw_frame++;
+ }
+ uart->regs->status = status & ~(APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE);
+ }
+
+ /* Empty RX fifo into software fifo */
+ signal = 0;
+ while ( (status=READ_REG(&uart->regs->status)) & APBUART_STATUS_DR ){
+ c = READ_REG(&uart->regs->data);
+ if ( apbuart_fifo_isFull(uart->rxfifo) ){
+ uart->stats.sw_dovr++;
+ DBG("]");
+ break;
+ }
+ /* put into fifo */
+ apbuart_fifo_put(uart->rxfifo,c);
+
+ /* bump RX counter */
+ uart->stats.rx_cnt++;
+
+ signal = 1;
+ }
+
+ /* Wake RX thread if any */
+ if ( signal )
+ rtems_semaphore_release(uart->rx_sem);
+
+ /* If room in HW fifo and we got more chars to be sent */
+ if ( !(status & APBUART_STATUS_TF) ){
+
+ if ( apbuart_fifo_isEmpty(uart->txfifo) ){
+ /* Turn off TX interrupt when no data is to be sent */
+ if ( status & APBUART_STATUS_TE ){
+ uart->regs->ctrl = READ_REG(&uart->regs->ctrl) & ~APBUART_CTRL_TF;
+ DBG("?");
+ }
+ return;
+ }
+
+ /* signal when there will be more room in SW fifo */
+ if ( apbuart_fifo_isFull(uart->txfifo) )
+ signal = 1;
+
+ do{
+ /* Put data into HW TX fifo */
+ apbuart_fifo_peek(uart->txfifo,&next_char);
+ c = *next_char;
+ if ( uart->ascii_mode && ( c == '\n') ){
+ uart->regs->data = '\n';
+ *next_char = '\r'; /* avoid sending mutiple '\n' or '\r' */
+ }else{
+ uart->regs->data = c;
+ apbuart_fifo_skip(uart->txfifo); /* remove sent char from fifo */
+ }
+ uart->regs->ctrl = READ_REG(&uart->regs->ctrl) | APBUART_CTRL_TE | APBUART_CTRL_TF;
+ DBG("!");
+ }while(!(empty=apbuart_fifo_isEmpty(uart->txfifo)) &&
+ !((status=READ_REG(&uart->regs->status))&APBUART_STATUS_TF) );
+
+ /* Wake userspace thread, on empty or full fifo
+ * This makes tx_flush and block work.
+ */
+ if ( signal || empty ){
+ rtems_semaphore_release(uart->tx_sem);
+ }
+ }
+}
+
+int APBUART_PREFIX(_register)(amba_confarea_type *bus) {
+ rtems_status_code r;
+ rtems_device_major_number m;
+
+ amba_bus = bus;
+
+ FUNCDBG("apbuart_register:\n");
+
+ if ((r = rtems_io_register_driver(0, &apbuart_driver, &m)) == RTEMS_SUCCESSFUL) {
+ DBG("APBUART driver successfully registered, major: %d\n", m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("APBUART rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("APBUART rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("APBUART rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); return -1;
+ default:
+ printk("APBUART rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+
+ rtems_status_code status;
+ int i;
+ amba_apb_device dev;
+ char fs_name[20];
+
+ FUNCDBG("apbuart_initialize\n");
+
+ /* Find all APB UART devices */
+ dev_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_APBUART);
+ if ( dev_cnt < 1 ){
+ /* Failed to find any CAN cores! */
+ printk("APBUART: Failed to find any APBUART cores\n\r");
+ return -1;
+ }
+
+ strcpy(fs_name,APBUART_DEVNAME);
+
+ DBG("Found %d APBUART(s)\n\r",dev_cnt);
+
+ /* Allocate memory for device structures */
+ apbuarts = malloc(sizeof(apbuart_priv) * dev_cnt);
+ if ( !apbuarts ){
+ printk("APBUART: Failed to allocate SW memory\n\r");
+ return -1;
+ }
+
+ memset(apbuarts,0,sizeof(sizeof(apbuart_priv) * dev_cnt));
+
+ /* Detect System Frequency from initialized timer */
+#ifndef SYS_FREQ_HZ
+#if defined(LEON3)
+ /* LEON3: find timer address via AMBA Plug&Play info */
+ {
+ amba_apb_device gptimer;
+ LEON3_Timer_Regs_Map *tregs;
+
+ if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&gptimer) == 1 ){
+ tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
+ sys_freq_hz = (tregs->scaler_reload+1)*1000*1000;
+ DBG("APBUART: detected %dHZ system frequency\n\r",sys_freq_hz);
+ }else{
+ sys_freq_hz = 40000000; /* Default to 40MHz */
+ printk("APBUART: Failed to detect system frequency\n\r");
+ }
+
+ }
+#elif defined(LEON2)
+ /* LEON2: use hardcoded address to get to timer */
+ {
+ LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
+ sys_freq_hz = (regs->Scaler_Reload+1)*1000*1000;
+ }
+#else
+ #error CPU not supported for OC_CAN driver
+#endif
+#else
+ /* Use hardcoded frequency */
+ sys_freq_hz = SYS_FREQ_HZ;
+#endif
+
+ for(i=0; i<dev_cnt; i++){
+ /* Get AMBA AHB device info from Plug&Play */
+ amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_APBUART,&dev,i);
+
+ printk("APBUART[%d]: at 0x%x irq %d (0x%x)\n\r",i,dev.start,dev.irq,(unsigned int)&apbuarts[i]);
+
+ apbuarts[i].regs = (ambapp_apb_uart *)dev.start;
+ apbuarts[i].irq = dev.irq;
+ apbuarts[i].minor = i;
+
+ /* Clear HW regs */
+ apbuarts[i].regs->status = 0;
+ apbuarts[i].regs->ctrl = 0;
+
+ /* Allocate default software buffers */
+ apbuarts[i].txfifo = apbuart_fifo_create(DEFAULT_TXBUF_SIZE);
+ apbuarts[i].rxfifo = apbuart_fifo_create(DEFAULT_RXBUF_SIZE);
+ if ( !apbuarts[i].txfifo || !apbuarts[i].rxfifo )
+ rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
+
+ APBUART_DEVNAME_NO(fs_name,i);
+
+ /* Bind name to device */
+ DBG("APBUART[%d]: binding to name %s\n\r",i,fs_name);
+ status = rtems_io_register_name(fs_name, major, i);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+
+ /* Setup interrupt handler for each channel */
+ APBUART_REG_INT(APBUART_PREFIX(_interrupt_handler), apbuarts[i].irq, &apbuarts[i]);
+
+ /* Device A Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'D', '0'+i),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &apbuarts[i].dev_sem) != RTEMS_SUCCESSFUL )
+ return RTEMS_INTERNAL_ERROR;
+
+ if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'T', '0'+i),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &apbuarts[i].tx_sem) != RTEMS_SUCCESSFUL )
+ return RTEMS_INTERNAL_ERROR;
+
+ if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'R', '0'+i),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &apbuarts[i].rx_sem) != RTEMS_SUCCESSFUL )
+ return RTEMS_INTERNAL_ERROR;
+
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ apbuart_priv *uart;
+
+ FUNCDBG("apbuart_open: major %d, minor %d\n", major, minor);
+
+ if ( (minor < 0) || (minor >= dev_cnt) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+
+ uart = &apbuarts[minor];
+
+ if (rtems_semaphore_obtain(uart->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
+ DBG("apbuart_open: resource in use\n");
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Clear HW regs */
+ uart->regs->status = 0;
+ uart->regs->ctrl = 0;
+
+ /* Set Defaults */
+
+ /* 38400 baudrate */
+ uart->scaler = 0; /* use uart->baud */
+ uart->baud = 38400;
+
+ /* Default to Blocking mode */
+ uart->txblk = 1;
+ uart->rxblk = 1;
+
+ /* Default to no flush mode */
+ uart->tx_flush = 0;
+
+ /* non-ascii mode */
+ uart->ascii_mode = 0;
+
+ /* not started */
+ uart->started = 0;
+
+ if ( !uart->txfifo || (uart->txfifo->size!=DEFAULT_TXBUF_SIZE) ){
+ apbuart_fifo_free(uart->txfifo);
+ uart->txfifo = apbuart_fifo_create(DEFAULT_TXBUF_SIZE);
+ }
+
+ if ( !uart->rxfifo || (uart->rxfifo->size!=DEFAULT_RXBUF_SIZE) ){
+ apbuart_fifo_free(uart->rxfifo);
+ uart->rxfifo = apbuart_fifo_create(DEFAULT_RXBUF_SIZE);
+ }
+
+ if ( !uart->rxfifo || !uart->txfifo ){
+ /* Failed to get memory */
+ return RTEMS_NO_MEMORY;
+ }
+
+ /* Now user must call ioctl(START,0) to begin */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ apbuart_priv *uart = &apbuarts[minor];
+
+ FUNCDBG("apbuart_close[%d]:\n",minor);
+
+ apbuart_hw_close(uart);
+
+ /* Software state will be set when open is called again */
+ rtems_semaphore_release(uart->rx_sem);
+ rtems_semaphore_release(uart->tx_sem);
+ uart->started = 0;
+
+ rtems_semaphore_release(uart->dev_sem);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args;
+ unsigned int count = 0, oldLevel;
+ unsigned char *buf;
+ apbuart_priv *uart = &apbuarts[minor];
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ FUNCDBG("apbuart_read\n");
+
+ buf = (unsigned char *)rw_args->buffer;
+ if ( (rw_args->count < 1) || !buf )
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
+ rtems_interrupt_disable(oldLevel);
+ do {
+ if ( (unsigned int)uart < 0x40000000 ) {
+ printk("UART %x is screwed\n",uart);
+ }
+ /* Read from SW fifo */
+ if ( apbuart_fifo_get(uart->rxfifo,&buf[count]) != 0 ){
+ /* non blocking or read at least 1 byte */
+ if ( (count > 0) || (!uart->rxblk) )
+ break; /* Return */
+
+ rtems_interrupt_enable(oldLevel);
+
+ /* Block thread until a char is received */
+ rtems_semaphore_obtain(uart->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ rtems_interrupt_disable(oldLevel);
+ continue;
+ }
+
+ /* Got char from SW FIFO */
+ count++;
+
+ } while (count < rw_args->count );
+
+ rtems_interrupt_enable(oldLevel);
+
+ rw_args->bytes_moved = count;
+
+ if (count == 0)
+ return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args;
+ unsigned int count, oldLevel, ctrl;
+ unsigned char *buf;
+ apbuart_priv *uart = &apbuarts[minor];
+ int direct=0;
+
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ FUNCDBG("apbuart_write\n");
+
+ buf = rw_args->buffer;
+
+ if ( rw_args->count < 1 || !buf )
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
+ count = 0;
+ rtems_interrupt_disable(oldLevel);
+ /* Do we need to start to send first char direct via HW
+ * to get IRQ going.
+ */
+
+ ctrl = READ_REG(&uart->regs->ctrl);
+ if ( (ctrl & APBUART_CTRL_TF) == 0 ){
+ /* TX interrupt is disabled ==>
+ * SW FIFO is empty and,
+ * HW FIFO empty
+ */
+ uart->regs->ctrl = ctrl | APBUART_CTRL_TF;
+ if ( uart->ascii_mode && (buf[0] == '\n') ){
+ uart->regs->data = '\r';
+ }else{
+ uart->regs->data = buf[0];
+ count++;
+ }
+ uart->regs->ctrl = ctrl | APBUART_CTRL_TE | APBUART_CTRL_TF;
+ direct = 1;
+ }
+
+ while( count < rw_args->count ) {
+ /* write to HW FIFO direct skipping SW FIFO */
+ if ( direct && ((READ_REG(&uart->regs->status) & APBUART_STATUS_TF) == 0) ){
+ uart->regs->data = buf[count];
+ }
+ /* write to SW FIFO */
+ else if ( apbuart_fifo_put(uart->txfifo,buf[count]) ){
+ direct = 0;
+ DBG("APBUART[%d]: write: SW FIFO Full\n\r",minor);
+
+ /* is full, block? */
+ if ( ((count < 1) && uart->txblk) || uart->tx_flush ){
+
+ rtems_interrupt_enable(oldLevel);
+
+ rtems_semaphore_obtain(uart->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ rtems_interrupt_disable(oldLevel);
+
+ /* Do we need to start to send first char direct via HW
+ * to get IRQ going.
+ */
+
+ ctrl = READ_REG(&uart->regs->ctrl);
+ if ( (ctrl & APBUART_CTRL_TF) == 0 ){
+ /* TX interrupt is disabled ==>
+ * SW FIFO is empty and,
+ * HW FIFO empty
+ */
+ uart->regs->ctrl = ctrl | APBUART_CTRL_TF;
+ if ( uart->ascii_mode && (buf[count] == '\n') ){
+ uart->regs->data = '\r';
+ }else{
+ uart->regs->data = buf[count];
+ count++;
+ }
+ uart->regs->ctrl = ctrl | APBUART_CTRL_TF | APBUART_CTRL_TE;
+ direct = 1;
+ }
+
+ continue;
+ }
+ /* don't block, return current status */
+ break;
+ }else{
+ direct = 0;
+ }
+
+ count++;
+
+ }
+
+ rtems_interrupt_enable(oldLevel);
+
+ rw_args->bytes_moved = count;
+
+ if (count == 0)
+ return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ apbuart_priv *uart = &apbuarts[minor];
+ int size;
+ unsigned int baudrate, blocking;
+ apbuart_stats *stats;
+
+ FUNCDBG("apbuart_control [%i,%i]\n",major, minor);
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+
+ /* Enable Receiver & transmitter */
+ case APBUART_START:
+ if ( uart->started )
+ return RTEMS_INVALID_NAME;
+ apbuart_hw_open(uart);
+ uart->started = 1;
+ break;
+
+ /* Close Receiver & transmitter */
+ case APBUART_STOP:
+ if ( !uart->started )
+ return RTEMS_INVALID_NAME;
+ apbuart_hw_close(uart);
+ uart->started = 0;
+ break;
+
+ /* Set RX FIFO Software buffer length
+ * It is only possible to change buffer size in
+ * non-running mode.
+ */
+ case APBUART_SET_RXFIFO_LEN:
+ if ( uart->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+
+ size = (int)ioarg->buffer;
+ if ( size < 1 )
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
+ /* Free old buffer */
+ apbuart_fifo_free(uart->rxfifo);
+
+ /* Allocate new buffer & init it */
+ uart->rxfifo = apbuart_fifo_create(size);
+ if ( !uart->rxfifo )
+ return RTEMS_NO_MEMORY;
+ break;
+
+ /* Set TX FIFO Software buffer length
+ * It is only possible to change buffer size
+ * while in non-running mode.
+ */
+ case APBUART_SET_TXFIFO_LEN:
+ if ( uart->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+
+ size = (int)ioarg->buffer;
+ if ( size < 1 )
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
+ /* Free old buffer */
+ apbuart_fifo_free(uart->txfifo);
+
+ /* Allocate new buffer & init it */
+ uart->txfifo = apbuart_fifo_create(size);
+ if ( !uart->txfifo )
+ return RTEMS_NO_MEMORY;
+ break;
+
+ case APBUART_SET_BAUDRATE:
+ /* Set baud rate of */
+ baudrate = (int)ioarg->buffer;
+ if ( (baudrate < 1) || (baudrate > 115200) ){
+ return RTEMS_INVALID_NAME;
+ }
+ uart->scaler = 0; /* use uart->baud */
+ uart->baud = baudrate;
+ break;
+
+ case APBUART_SET_SCALER:
+ /* use uart->scaler not uart->baud */
+ uart->scaler = data[0];
+ break;
+
+ case APBUART_SET_BLOCKING:
+ blocking = (unsigned int)ioarg->buffer;
+ uart->rxblk = ( blocking & APBUART_BLK_RX );
+ uart->txblk = ( blocking & APBUART_BLK_TX );
+ uart->tx_flush = ( blocking & APBUART_BLK_FLUSH );
+ break;
+
+ case APBUART_GET_STATS:
+ stats = (void *)ioarg->buffer;
+ if ( !stats )
+ return RTEMS_INVALID_NAME;
+
+ /* Copy Stats */
+ *stats = uart->stats;
+ break;
+
+ case APBUART_CLR_STATS:
+ /* Clear/reset Stats */
+ memset(&uart->stats,0,sizeof(uart->stats));
+ break;
+
+ case APBUART_SET_ASCII_MODE:
+ uart->ascii_mode = (int)ioarg->buffer;
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/******************* APBUART FIFO implementation ***********************/
+
+static apbuart_fifo *apbuart_fifo_create(int size){
+ apbuart_fifo *fifo;
+ fifo = (apbuart_fifo *) malloc( size + sizeof(apbuart_fifo));
+ if ( fifo ){
+ /* Init fifo */
+ fifo->size = size;
+ fifo->buf = (char *)(fifo+1);
+ fifo->tail = fifo->buf;
+ fifo->head = fifo->buf;
+ fifo->max = &fifo->buf[size-1];
+ fifo->full=0;
+ }
+ return fifo;
+}
+
+static void apbuart_fifo_free(apbuart_fifo *fifo){
+ if ( fifo )
+ free(fifo);
+}
+
+static inline int apbuart_fifo_isFull(apbuart_fifo *fifo){
+ return fifo->full;
+}
+
+static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo){
+ if ( (fifo->head == fifo->tail) && !fifo->full )
+ return -1;
+ return 0;
+}
+
+static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c){
+ if ( !fifo->full ){
+ *fifo->head = c;
+ fifo->head = (fifo->head >= fifo->max ) ? fifo->buf : fifo->head+1;
+ if ( fifo->head == fifo->tail )
+ fifo->full = -1;
+ return 0;
+ }
+ return -1;
+}
+
+static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c){
+ if ( apbuart_fifo_isEmpty(fifo) )
+ return -1;
+ if ( c )
+ *c = *fifo->tail;
+ fifo->tail = (fifo->tail >= fifo->max ) ? fifo->buf : fifo->tail+1;
+ fifo->full = 0;
+ return 0;
+}
+
+static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c){
+ if ( apbuart_fifo_isEmpty(fifo) )
+ return -1;
+ if ( c )
+ *c = fifo->tail;
+ return 0;
+}
+
+static void inline apbuart_fifo_skip(apbuart_fifo *fifo){
+ if ( !apbuart_fifo_isEmpty(fifo) ){
+ fifo->tail = (fifo->tail >= fifo->max ) ? fifo->buf : fifo->tail+1;
+ fifo->full = 0;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c
new file mode 100644
index 0000000000..ad2effa065
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_pci.c
@@ -0,0 +1,42 @@
+
+#undef DEBUG
+
+/* Set registered device name */
+#define APBUART_DEVNAME "/dev/apbupci0"
+#define APBUART_DEVNAME_NO(devstr,no) ((devstr)[12]='0'+(no))
+
+/* Any non-static function will begin with */
+#define APBUART_PREFIX(name) apbuartpci##name
+
+/* do nothing, assume that the interrupt handler is called
+ * setup externally calling apbuartpci_interrupt_handler.
+ */
+#define APBUART_REG_INT(handler,irq,arg) \
+ if ( apbuart_pci_int_reg ) \
+ apbuart_pci_int_reg(handler,irq,arg);
+
+void (*apbuart_pci_int_reg)(void *handler, int irq, void *arg) = 0;
+
+void apbuartpci_interrupt_handler(int irq, void *arg);
+
+/* AMBA Bus is clocked using the PCI clock (33.3MHz) */
+#define SYS_FREQ_HZ 33333333
+
+#include "apbuart.c"
+
+int apbuart_pci_register(amba_confarea_type *bus)
+{
+ /* Setup configuration */
+
+ /* Register the driver */
+ return APBUART_PREFIX(_register)(bus);
+}
+
+
+/* Call this from PCI interrupt handler
+ * irq = the irq number of the HW device local to that IRQMP controller
+ *
+ */
+void apbuartpci_interrupt_handler(int irq, void *arg){
+ apbuart_interrupt(arg);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c
new file mode 100644
index 0000000000..a5c365eb77
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_rasta.c
@@ -0,0 +1,42 @@
+
+#undef DEBUG
+
+/* Set registered device name */
+#define APBUART_DEVNAME "/dev/apburasta0"
+#define APBUART_DEVNAME_NO(devstr,no) ((devstr)[14]='0'+(no))
+
+/* Any non-static function will begin with */
+#define APBUART_PREFIX(name) apbuartrasta##name
+
+/* do nothing, assume that the interrupt handler is called
+ * setup externally calling apbuartrasta_interrupt_handler.
+ */
+#define APBUART_REG_INT(handler,irq,arg) \
+ if ( apbuart_rasta_int_reg ) \
+ apbuart_rasta_int_reg(handler,irq,arg);
+
+void (*apbuart_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
+
+void apbuartrasta_interrupt_handler(int irq, void *arg);
+
+/* AMBA Bus is clocked using the RASTA internal clock (30MHz) */
+#define SYS_FREQ_HZ 30000000
+
+#include "apbuart.c"
+
+int apbuart_rasta_register(amba_confarea_type *bus)
+{
+ /* Setup configuration */
+
+ /* Register the driver */
+ return APBUART_PREFIX(_register)(bus);
+}
+
+
+/* Call this from RASTA interrupt handler
+ * irq = the irq number of the HW device local to that IRQMP controller
+ *
+ */
+void apbuartrasta_interrupt_handler(int irq, void *arg){
+ apbuart_interrupt(arg);
+}