From 84e4d10ca346e7c89314845420a650b6dab316b4 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 9 May 2017 16:00:56 +0200 Subject: leon, apbuart: remove old RAW UART driver This driver was initially intended for APBUART access on GRLIB PCI peripherals (AMBA-over-PCI). There are already many APBUART drivers for LEON. Instead of using this one the termios APBUART should work on AMBA-over-PCI systems with recent changes on LEON3, however that has not been tested yet. --- c/src/lib/libbsp/sparc/Makefile.am | 1 - c/src/lib/libbsp/sparc/leon2/Makefile.am | 1 - c/src/lib/libbsp/sparc/leon3/Makefile.am | 3 +- c/src/lib/libbsp/sparc/shared/include/apbuart.h | 33 - c/src/lib/libbsp/sparc/shared/uart/apbuart.c | 897 ------------------------ 5 files changed, 1 insertion(+), 934 deletions(-) delete mode 100644 c/src/lib/libbsp/sparc/shared/uart/apbuart.c diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am index a894f341cb..d17d691a55 100644 --- a/c/src/lib/libbsp/sparc/Makefile.am +++ b/c/src/lib/libbsp/sparc/Makefile.am @@ -83,7 +83,6 @@ EXTRA_DIST += shared/uart/cons.c EXTRA_DIST += shared/uart/apbuart_cons.c EXTRA_DIST += shared/include/cons.h EXTRA_DIST += shared/include/apbuart_cons.h -EXTRA_DIST += shared/uart/apbuart.c EXTRA_DIST += shared/include/apbuart.h # CAN (OC_CAN, GRCAN) diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am index 94e10cd7d8..349b44d06d 100644 --- a/c/src/lib/libbsp/sparc/leon2/Makefile.am +++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am @@ -154,7 +154,6 @@ libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c # UART (RAW) include_bsp_HEADERS += ../../sparc/shared/include/apbuart.h -libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c # I2CMST include_bsp_HEADERS += ../../sparc/shared/include/i2cmst.h diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am index 83e1dff7d2..52f6b569a9 100644 --- a/c/src/lib/libbsp/sparc/leon3/Makefile.am +++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am @@ -170,8 +170,7 @@ libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c # UART include_bsp_HEADERS += ../../sparc/shared/include/apbuart.h \ ../../sparc/shared/include/apbuart_termios.h -libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c \ - ../../sparc/shared/uart/apbuart_termios.c +libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart_termios.c # I2CMST include_bsp_HEADERS += ../../sparc/shared/include/i2cmst.h diff --git a/c/src/lib/libbsp/sparc/shared/include/apbuart.h b/c/src/lib/libbsp/sparc/shared/include/apbuart.h index 326e769592..a324805d7d 100644 --- a/c/src/lib/libbsp/sparc/shared/include/apbuart.h +++ b/c/src/lib/libbsp/sparc/shared/include/apbuart.h @@ -25,33 +25,6 @@ extern "C" { #endif -typedef struct { - unsigned int hw_dovr; - unsigned int hw_parity; - unsigned int hw_frame; - unsigned int sw_dovr; - unsigned int rx_cnt; - unsigned int tx_cnt; -} apbuart_stats; - -#define APBUART_START 0 -#define APBUART_STOP 1 -#define APBUART_SET_RXFIFO_LEN 2 -#define APBUART_SET_TXFIFO_LEN 3 -#define APBUART_SET_BAUDRATE 4 -#define APBUART_SET_SCALER 5 -#define APBUART_SET_BLOCKING 6 -#define APBUART_SET_ASCII_MODE 7 - - -#define APBUART_GET_STATS 16 -#define APBUART_CLR_STATS 17 - -#define APBUART_BLK_RX 0x1 -#define APBUART_BLK_TX 0x2 -#define APBUART_BLK_FLUSH 0x4 - - #define APBUART_CTRL_RE 0x1 #define APBUART_CTRL_TE 0x2 #define APBUART_CTRL_RI 0x4 @@ -80,12 +53,6 @@ typedef struct { #define APBUART_STATUS_TF 0x200 #define APBUART_STATUS_RF 0x400 -/* Register APBUART driver - * bus = pointer to AMBA bus description used to search for APBUART(s). - * (&ambapp_plb for LEON3), (LEON2: see amba_scan) - */ -int apbuart_register (struct ambapp_bus *bus); - #ifdef __cplusplus } #endif diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart.c deleted file mode 100644 index 171f114d86..0000000000 --- a/c/src/lib/libbsp/sparc/shared/uart/apbuart.c +++ /dev/null @@ -1,897 +0,0 @@ -/* - * 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.org/license/LICENSE. - * - * - * 2007-07-11, Daniel Hellstrom - * Added ioctl command APBUART_CLR_STATS - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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 -#else - #define APBUART_REGISTER_STATIC -#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) - #undef APBUART_DEFINE_INTHANDLER - #define APBUART_DEFINE_INTHANDLER -#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 { - struct apbuart_regs *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 struct ambapp_bus *amba_bus; - -static void apbuart_interrupt(apbuart_priv *uart); -#ifdef APBUART_DEFINE_INTHANDLER -static void apbuart_interrupt_handler(rtems_vector_number v); -#endif -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(struct apbuart_regs *regs, unsigned char ch) -{ - if ( (READ_REG(®s->status) & APBUART_STATUS_TE) == 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(struct apbuart_regs *regs) -{ - unsigned int status; - /* Clear errors if any */ - if ( (status=READ_REG(®s->status)) & APBUART_STATUS_ERR) { - regs->status = status & ~APBUART_STATUS_ERR; - } - - /* Is Data available? */ - if ( (READ_REG(®s->status) & APBUART_STATUS_DR) == 0 ) - return -1; /* No data avail */ - - /* Return Data */ - return (int)READ_REG(®s->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; -} - -#ifdef APBUART_DEFINE_INTHANDLER -/* 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; - } - } -} -#endif - -/* 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 = NULL; - 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); - } - } -} - -#ifdef APBUART_REGISTER_STATIC -static -#endif -int APBUART_PREFIX(_register)(struct ambapp_bus *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; - struct ambapp_apb_info dev; - char fs_name[20]; - - FUNCDBG("apbuart_initialize\n"); - - /* Find all APB UART devices */ - dev_cnt = ambapp_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 = calloc(dev_cnt, sizeof(*apbuarts)); - if ( !apbuarts ){ - printk("APBUART: Failed to allocate SW memory\n\r"); - return -1; - } - - /* Detect System Frequency from initialized timer */ -#ifndef SYS_FREQ_HZ -#if defined(LEON3) - /* LEON3: find timer address via AMBA Plug&Play info */ - { - struct ambapp_apb_info gptimer; - struct gptimer_regs *tregs; - - if ( ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, - GAISLER_GPTIMER, &gptimer) == 1 ){ - tregs = (struct gptimer_regs *)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; istatus = 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 %p 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; - 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 = (unsigned 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; - } -} -- cgit v1.2.3