diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c | 867 |
1 files changed, 0 insertions, 867 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c deleted file mode 100644 index e406bc01b7..0000000000 --- a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c +++ /dev/null @@ -1,867 +0,0 @@ -/* This file contains the driver for the GRLIB APBUART serial port. The driver - * is implemented by using the cons.c console layer. Interrupt/Polling/Task - * driven mode can be configured using driver resources: - * - * - mode (0=Polling, 1=Interrupt, 2=Task-Driven-Interrupt Mode) - * - syscon (0=Force not Ssystem Console, 1=Suggest System Console) - * - * The BSP define APBUART_INFO_AVAIL in order to add the info routine - * used for debugging. - * - * COPYRIGHT (c) 2010. - * Cobham Gaisler AB. - * - * 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. - */ - -/******************* Driver manager interface ***********************/ -#include <bsp.h> -#include <stdlib.h> -#include <assert.h> -#include <rtems/bspIo.h> -#include <string.h> -#include <stdio.h> - -#include <drvmgr/drvmgr.h> -#include <drvmgr/ambapp_bus.h> -#include <bsp/apbuart.h> -#include <ambapp.h> -#include <grlib.h> -#include <bsp/cons.h> -#include <rtems/termiostypes.h> -#include <bsp/apbuart_cons.h> - -/*#define DEBUG 1 */ - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* LEON3 Low level transmit/receive functions provided by debug-uart code */ -extern void apbuart_outbyte_polled( - struct apbuart_regs *regs, - unsigned char ch, - int do_cr_on_newline, - int wait_sent); -extern int apbuart_inbyte_nonblocking(struct apbuart_regs *regs); -#ifdef LEON3 -extern struct apbuart_regs *leon3_debug_uart; /* The debug UART */ -#endif - -/* Probed hardware capabilities */ -enum { - CAP_FIFO = 0x01, /* FIFO available */ - CAP_DI = 0x02, /* RX delayed interrupt available */ -}; -struct apbuart_priv { - struct console_dev condev; - struct drvmgr_dev *dev; - struct apbuart_regs *regs; - struct rtems_termios_tty *tty; - char devName[32]; - volatile int sending; - int mode; - int cap; -}; - -/* Getters for different interfaces. It happens to be just casting which we do - * in one place to avoid getting cast away. */ -static struct console_dev *base_get_condev(rtems_termios_device_context *base) -{ - return (struct console_dev *) base; -} - -static struct apbuart_priv *condev_get_priv(struct console_dev *condev) -{ - return (struct apbuart_priv *) condev; -} - -static struct apbuart_priv *base_get_priv(rtems_termios_device_context *base) -{ - return condev_get_priv(base_get_condev(base)); -} - -/* TERMIOS Layer Callback functions */ -static bool first_open( - rtems_termios_tty *tty, - rtems_termios_device_context *base, - struct termios *term, - rtems_libio_open_close_args_t *args -); -static void last_close( - rtems_termios_tty *tty, - rtems_termios_device_context *base, - rtems_libio_open_close_args_t *args -); -static void write_interrupt( - rtems_termios_device_context *base, - const char *buf, - size_t len -); -static bool set_attributes( - rtems_termios_device_context *base, - const struct termios *t -); -static void get_attributes( - rtems_termios_device_context *base, - struct termios *t -); -static int read_polled(rtems_termios_device_context *base); -static int read_task(rtems_termios_device_context *base); -static void write_polled( - rtems_termios_device_context *base, - const char *buf, - size_t len -); - -static void apbuart_cons_isr(void *arg); -int apbuart_get_baud(struct apbuart_priv *uart); - -int apbuart_init1(struct drvmgr_dev *dev); -#ifdef APBUART_INFO_AVAIL -static int apbuart_info( - struct drvmgr_dev *dev, - void (*print_line)(void *p, char *str), - void *p, int, char *argv[]); -#define APBUART_INFO_FUNC apbuart_info -#else -#define APBUART_INFO_FUNC NULL -#endif - -struct drvmgr_drv_ops apbuart_ops = -{ - .init = {apbuart_init1, NULL, NULL, NULL}, - .remove = NULL, - .info = APBUART_INFO_FUNC -}; - -static struct amba_dev_id apbuart_ids[] = -{ - {VENDOR_GAISLER, GAISLER_APBUART}, - {0, 0} /* Mark end of table */ -}; - -static struct amba_drv_info apbuart_drv_info = -{ - { - DRVMGR_OBJ_DRV, /* Driver */ - NULL, /* Next driver */ - NULL, /* Device list */ - DRIVER_AMBAPP_GAISLER_APBUART_ID, /* Driver ID */ - "APBUART_DRV", /* Driver Name */ - DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ - &apbuart_ops, - NULL, /* Funcs */ - 0, /* No devices yet */ - sizeof(struct apbuart_priv), /*DrvMgr alloc private*/ - }, - &apbuart_ids[0] -}; - -void apbuart_cons_register_drv (void) -{ - DBG("Registering APBUART Console driver\n"); - drvmgr_drv_register(&apbuart_drv_info.general); -} - -static const rtems_termios_device_handler handler_interrupt = { - .first_open = first_open, - .last_close = last_close, - .write = write_interrupt, - .set_attributes = set_attributes, - .mode = TERMIOS_IRQ_DRIVEN -}; - -static const rtems_termios_device_handler handler_task = { - .first_open = first_open, - .last_close = last_close, - .poll_read = read_task, - .write = write_interrupt, - .set_attributes = set_attributes, - .mode = TERMIOS_TASK_DRIVEN -}; - -static const rtems_termios_device_handler handler_polled = { - .first_open = first_open, - .last_close = last_close, - .poll_read = read_polled, - .write = write_polled, - .set_attributes = set_attributes, - .mode = TERMIOS_POLLED -}; - -/* - * APBUART hardware instantiation is flexible. Probe features here and driver - * can select appropriate routines for the hardware. probecap() return value - * is a CAP_ bitmask. - */ -static int probecap(struct apbuart_regs *regs) -{ - int cap = 0; - - /* Probe FIFO */ - if (regs->ctrl & APBUART_CTRL_FA) { - cap |= CAP_FIFO; - - /* Probe RX delayed interrupt */ - regs->ctrl |= APBUART_CTRL_DI; - if (regs->ctrl & APBUART_CTRL_DI) { - regs->ctrl &= ~APBUART_CTRL_DI; - cap |= CAP_DI; - } - } - - return cap; -} - -int apbuart_init1(struct drvmgr_dev *dev) -{ - struct apbuart_priv *priv; - struct amba_dev_info *ambadev; - struct ambapp_core *pnpinfo; - union drvmgr_key_value *value; - char prefix[32]; - unsigned int db; - static int first_uart = 1; - - /* The default operation in AMP is to use APBUART[0] for CPU[0], - * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used - * since we don't know how many CPU-cores there are. Note this only - * affects the on-chip amba bus (the root bus). The user can override - * the default resource sharing by defining driver resources for the - * APBUART devices on each AMP OS instance. - */ -#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3) - if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index && - drvmgr_keys_get(dev, NULL) != 0) { - /* User hasn't configured on-chip APBUART, leave it untouched */ - return DRVMGR_EBUSY; - } -#endif - - DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); - /* Private data was allocated and zeroed by driver manager */ - priv = dev->priv; - if (!priv) - return DRVMGR_NOMEM; - priv->dev = dev; - - /* Get device information from AMBA PnP information */ - ambadev = (struct amba_dev_info *)priv->dev->businfo; - if (ambadev == NULL) - return -1; - pnpinfo = &ambadev->info; - priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start; - - /* Clear HW regs, leave baudrate register as it is */ - priv->regs->status = 0; - - /* leave Transmitter/receiver if this is the RTEMS debug UART (assume - * it has been setup by boot loader). - */ - db = 0; -#ifdef LEON3 - if (priv->regs == leon3_debug_uart) { - db = priv->regs->ctrl & (LEON_REG_UART_CTRL_RE | - LEON_REG_UART_CTRL_TE | - LEON_REG_UART_CTRL_PE | - LEON_REG_UART_CTRL_PS); - } -#endif - /* Let UART debug tunnelling be untouched if Flow-control is set. - * - * With old APBUARTs debug is enabled by setting LB and FL, since LB or - * DB are not reset we can not trust them. However since FL is reset we - * guess that we are debugging if FL is already set, the debugger set - * either LB or DB depending on UART capabilities. - */ - if (priv->regs->ctrl & LEON_REG_UART_CTRL_FL) { - db |= priv->regs->ctrl & (LEON_REG_UART_CTRL_DB | - LEON_REG_UART_CTRL_LB | LEON_REG_UART_CTRL_FL); - } - - priv->regs->ctrl = db; - - priv->cap = probecap(priv->regs); - - /* The system console and Debug console may depend on this device, so - * initialize it straight away. - * - * We default to have System Console on first APBUART, user may override - * this behaviour by setting the syscon option to 0. - */ - if (drvmgr_on_rootbus(dev) && first_uart) { - priv->condev.flags = CONSOLE_FLAG_SYSCON; - first_uart = 0; - } else { - priv->condev.flags = 0; - } - - value = drvmgr_dev_key_get(priv->dev, "syscon", DRVMGR_KT_INT); - if (value) { - if (value->i) - priv->condev.flags |= CONSOLE_FLAG_SYSCON; - else - priv->condev.flags &= ~CONSOLE_FLAG_SYSCON; - } - - /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */ - value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT); - if (value) - priv->mode = value->i; - else - priv->mode = TERMIOS_POLLED; - /* TERMIOS device handlers */ - if (priv->mode == TERMIOS_IRQ_DRIVEN) { - priv->condev.handler = &handler_interrupt; - } else if (priv->mode == TERMIOS_TASK_DRIVEN) { - priv->condev.handler = &handler_task; - } else { - priv->condev.handler = &handler_polled; - } - - priv->condev.fsname = NULL; - /* Get Filesystem name prefix */ - prefix[0] = '\0'; - if (drvmgr_get_dev_prefix(dev, prefix)) { - /* Got special prefix, this means we have a bus prefix - * And we should use our "bus minor" - */ - sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus); - priv->condev.fsname = priv->devName; - } else { - sprintf(priv->devName, "/dev/apbuart%d", dev->minor_drv); - } - - /* Register it as a console device, the console driver will register - * a termios device as well - */ - console_dev_register(&priv->condev); - - return DRVMGR_OK; -} - -#ifdef APBUART_INFO_AVAIL -static int apbuart_info( - struct drvmgr_dev *dev, - void (*print_line)(void *p, char *str), - void *p, int argc, char *argv[]) -{ - struct apbuart_priv *priv = dev->priv; - char *str1; - char buf[64]; - - if (dev->priv == NULL) - return -DRVMGR_EINVAL; - - if (priv->mode == TERMIOS_POLLED) - str1 = "TERMIOS_POLLED"; - else if (priv->mode == TERMIOS_IRQ_DRIVEN) - str1 = "TERMIOS_IRQ_DRIVEN"; - else if (priv->mode == TERMIOS_TASK_DRIVEN) - str1 = "TERMIOS_TASK_DRIVEN"; - else - str1 = "BAD MODE"; - - sprintf(buf, "UART Mode: %s", str1); - print_line(p, buf); - if (priv->condev.fsname) { - sprintf(buf, "FS Name: %s", priv->condev.fsname); - print_line(p, buf); - } - sprintf(buf, "STATUS REG: 0x%x", priv->regs->status); - print_line(p, buf); - sprintf(buf, "CTRL REG: 0x%x", priv->regs->ctrl); - print_line(p, buf); - sprintf(buf, "SCALER REG: 0x%x baud rate %d", - priv->regs->scaler, apbuart_get_baud(priv)); - print_line(p, buf); - - return DRVMGR_OK; -} -#endif - -#ifndef LEON3 -/* This routine transmits a character, it will busy-wait until on character - * fits in the APBUART Transmit FIFO - */ -void apbuart_outbyte_polled( - struct apbuart_regs *regs, - unsigned char ch, - int do_cr_on_newline, - int wait_sent) -{ -send: - while ((regs->status & LEON_REG_UART_STATUS_THE) == 0) { - /* Lower bus utilization while waiting for UART */ - asm volatile ("nop"::); asm volatile ("nop"::); - asm volatile ("nop"::); asm volatile ("nop"::); - asm volatile ("nop"::); asm volatile ("nop"::); - asm volatile ("nop"::); asm volatile ("nop"::); - } - regs->data = (unsigned int) ch; - - if ((ch == '\n') && do_cr_on_newline) { - ch = '\r'; - goto send; - } - - /* Wait until the character has been sent? */ - if (wait_sent) { - while ((regs->status & LEON_REG_UART_STATUS_THE) == 0) - ; - } -} - -/* This routine polls for one character, return EOF if no character is available */ -int apbuart_inbyte_nonblocking(struct apbuart_regs *regs) -{ - if (regs->status & LEON_REG_UART_STATUS_ERR) { - regs->status = ~LEON_REG_UART_STATUS_ERR; - } - - if ((regs->status & LEON_REG_UART_STATUS_DR) == 0) - return EOF; - - return (int)regs->data; -} -#endif - -static bool first_open( - rtems_termios_tty *tty, - rtems_termios_device_context *base, - struct termios *term, - rtems_libio_open_close_args_t *args -) -{ - struct apbuart_priv *uart = base_get_priv(base); - - uart->tty = tty; - - /* Inherit UART hardware parameters from bootloader on system console */ - if (uart->condev.flags & CONSOLE_FLAG_SYSCON_GRANT) { - get_attributes(base, term); - term->c_oflag |= ONLCR; - set_attributes(base, term); - } - - /* Enable TX/RX */ - uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE; - - if (uart->mode != TERMIOS_POLLED) { - int ret; - uint32_t ctrl; - - /* Register interrupt and enable it */ - ret = drvmgr_interrupt_register( - uart->dev, 0, uart->devName, apbuart_cons_isr, tty - ); - if (ret) { - return false; - } - - uart->sending = 0; - - /* Turn on RX interrupts */ - ctrl = uart->regs->ctrl; - ctrl |= APBUART_CTRL_RI; - if (uart->cap & CAP_DI) { - /* Use RX FIFO interrupt only if delayed interrupt available. */ - ctrl |= (APBUART_CTRL_DI | APBUART_CTRL_RF); - } - uart->regs->ctrl = ctrl; - } - - return true; -} - -static void last_close( - rtems_termios_tty *tty, - rtems_termios_device_context *base, - rtems_libio_open_close_args_t *args -) -{ - struct apbuart_priv *uart = base_get_priv(base); - rtems_interrupt_lock_context lock_context; - - if (uart->mode != TERMIOS_POLLED) { - /* Turn off RX interrupts */ - rtems_termios_device_lock_acquire(base, &lock_context); - uart->regs->ctrl &= - ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF); - rtems_termios_device_lock_release(base, &lock_context); - - /**** Flush device ****/ - while (uart->sending) { - /* Wait until all data has been sent */ - } - while ( - (uart->regs->ctrl & APBUART_CTRL_TE) && - !(uart->regs->status & APBUART_STATUS_TS) - ) { - /* Wait until all data has left shift register */ - } - - /* Disable and unregister interrupt handler */ - drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty); - } - -#ifdef LEON3 - /* Disable TX/RX if not used for DEBUG */ - if (uart->regs != leon3_debug_uart) - uart->regs->ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE); -#endif -} - -static int read_polled(rtems_termios_device_context *base) -{ - struct apbuart_priv *uart = base_get_priv(base); - - return apbuart_inbyte_nonblocking(uart->regs); -} - -/* This function is called from TERMIOS rxdaemon task without device lock. */ -static int read_task(rtems_termios_device_context *base) -{ - rtems_interrupt_lock_context lock_context; - struct apbuart_priv *uart = base_get_priv(base); - struct apbuart_regs *regs = uart->regs; - int cnt; - char buf[33]; - struct rtems_termios_tty *tty; - uint32_t ctrl_add; - - ctrl_add = APBUART_CTRL_RI; - if (uart->cap & CAP_DI) { - ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF); - } - tty = uart->tty; - do { - cnt = 0; - while ( - (regs->status & APBUART_STATUS_DR) && - (cnt < sizeof(buf)) - ) { - buf[cnt] = regs->data; - cnt++; - } - if (0 < cnt) { - /* Tell termios layer about new characters */ - rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt); - } - - /* - * Turn on RX interrupts. A new character in FIFO now may not - * cause interrupt so we must check data ready again - * afterwards. - */ - rtems_termios_device_lock_acquire(base, &lock_context); - regs->ctrl |= ctrl_add; - rtems_termios_device_lock_release(base, &lock_context); - } while (regs->status & APBUART_STATUS_DR); - - return EOF; -} - - -struct apbuart_baud { - unsigned int num; - unsigned int baud; -}; -static struct apbuart_baud apbuart_baud_table[] = { - {B50, 50}, - {B75, 75}, - {B110, 110}, - {B134, 134}, - {B150, 150}, - {B200, 200}, - {B300, 300}, - {B600, 600}, - {B1200, 1200}, - {B1800, 1800}, - {B2400, 2400}, - {B4800, 4800}, - {B9600, 9600}, - {B19200, 19200}, - {B38400, 38400}, - {B57600, 57600}, - {B115200, 115200}, - {B230400, 230400}, - {B460800, 460800}, -}; -#define BAUD_NUM (sizeof(apbuart_baud_table)/sizeof(struct apbuart_baud)) - -static int apbuart_baud_num2baud(unsigned int num) -{ - int i; - - for(i=0; i<BAUD_NUM; i++) - if (apbuart_baud_table[i].num == num) - return apbuart_baud_table[i].baud; - return -1; -} - -static struct apbuart_baud *apbuart_baud_find_closest(unsigned int baud) -{ - int i, diff; - - for(i=0; i<BAUD_NUM-1; i++) { - diff = apbuart_baud_table[i+1].baud - - apbuart_baud_table[i].baud; - if (baud < (apbuart_baud_table[i].baud + diff/2)) - return &apbuart_baud_table[i]; - } - return &apbuart_baud_table[BAUD_NUM-1]; -} - -int apbuart_get_baud(struct apbuart_priv *uart) -{ - unsigned int core_clk_hz; - unsigned int scaler; - - /* Get current scaler setting */ - scaler = uart->regs->scaler; - - /* Get APBUART core frequency */ - drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz); - - /* Calculate baud rate from generator "scaler" number */ - return core_clk_hz / ((scaler + 1) * 8); -} - -static struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart) -{ - return apbuart_baud_find_closest(apbuart_get_baud(uart)); -} - -static bool set_attributes( - rtems_termios_device_context *base, - const struct termios *t -) -{ - unsigned int core_clk_hz; - unsigned int scaler; - unsigned int ctrl; - int baud; - struct apbuart_priv *uart = base_get_priv(base); - rtems_interrupt_lock_context lock_context; - - switch(t->c_cflag & CSIZE) { - default: - case CS5: - case CS6: - case CS7: - /* Hardware doesn't support other than CS8 */ - return false; - case CS8: - break; - } - - rtems_termios_device_lock_acquire(base, &lock_context); - - /* Read out current value */ - ctrl = uart->regs->ctrl; - - switch(t->c_cflag & (PARENB|PARODD)){ - case (PARENB|PARODD): - /* Odd parity */ - ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS; - break; - - case PARENB: - /* Even parity */ - ctrl &= ~LEON_REG_UART_CTRL_PS; - ctrl |= LEON_REG_UART_CTRL_PE; - break; - - default: - case 0: - case PARODD: - /* No Parity */ - ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE); - } - - if (!(t->c_cflag & CLOCAL)) - ctrl |= LEON_REG_UART_CTRL_FL; - else - ctrl &= ~LEON_REG_UART_CTRL_FL; - - /* Update new settings */ - uart->regs->ctrl = ctrl; - - rtems_termios_device_lock_release(base, &lock_context); - - /* Baud rate */ - baud = apbuart_baud_num2baud(t->c_ospeed); - if (baud > 0){ - /* Get APBUART core frequency */ - drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz); - - /* Calculate Baud rate generator "scaler" number */ - scaler = (((core_clk_hz*10)/(baud*8))-5)/10; - - /* Set new baud rate by setting scaler */ - uart->regs->scaler = scaler; - } - - return true; -} - -static void get_attributes( - rtems_termios_device_context *base, - struct termios *t -) -{ - struct apbuart_priv *uart = base_get_priv(base); - unsigned int ctrl; - struct apbuart_baud *baud; - - t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL); - - /* Hardware support only CS8 */ - t->c_cflag |= CS8; - - /* Read out current parity */ - ctrl = uart->regs->ctrl; - if (ctrl & LEON_REG_UART_CTRL_PE) { - if (ctrl & LEON_REG_UART_CTRL_PS) - t->c_cflag |= PARENB|PARODD; /* Odd parity */ - else - t->c_cflag |= PARENB; /* Even parity */ - } - - if ((ctrl & LEON_REG_UART_CTRL_FL) == 0) - t->c_cflag |= CLOCAL; - - baud = apbuart_get_baud_closest(uart); - t->c_cflag |= baud->num; -} - -static void write_polled( - rtems_termios_device_context *base, - const char *buf, - size_t len -) -{ - struct apbuart_priv *uart = base_get_priv(base); - int nwrite = 0; - - while (nwrite < len) { - apbuart_outbyte_polled(uart->regs, *buf++, 0, 0); - nwrite++; - } -} - -static void write_interrupt( - rtems_termios_device_context *base, - const char *buf, - size_t len -) -{ - struct apbuart_priv *uart = base_get_priv(base); - struct apbuart_regs *regs = uart->regs; - int sending; - unsigned int ctrl; - - ctrl = regs->ctrl; - - if (len > 0) { - /* - * sending is used to remember how much we have outstanding so - * we can tell termios later. - */ - /* Enable TX interrupt (interrupt is edge-triggered) */ - regs->ctrl = ctrl | APBUART_CTRL_TI; - - if (ctrl & APBUART_CTRL_FA) { - /* APBUART with FIFO.. Fill as many as FIFO allows */ - sending = 0; - while ( - ((regs->status & APBUART_STATUS_TF) == 0) && - (sending < len) - ) { - regs->data = *buf; - buf++; - sending++; - } - } else { - /* start UART TX, this will result in an interrupt when done */ - regs->data = *buf; - - sending = 1; - } - } else { - /* No more to send, disable TX interrupts */ - regs->ctrl = ctrl & ~APBUART_CTRL_TI; - - /* Tell close that we sent everything */ - sending = 0; - } - - uart->sending = sending; -} - -/* Handle UART interrupts */ -static void apbuart_cons_isr(void *arg) -{ - rtems_termios_tty *tty = arg; - rtems_termios_device_context *base; - struct console_dev *condev = rtems_termios_get_device_context(tty); - struct apbuart_priv *uart = condev_get_priv(condev); - struct apbuart_regs *regs = uart->regs; - unsigned int status; - char buf[33]; - int cnt; - - if (uart->mode == TERMIOS_TASK_DRIVEN) { - if ((status = regs->status) & APBUART_STATUS_DR) { - rtems_interrupt_lock_context lock_context; - - /* Turn off RX interrupts */ - base = rtems_termios_get_device_context(tty); - rtems_termios_device_lock_acquire(base, &lock_context); - regs->ctrl &= - ~(APBUART_CTRL_DI | APBUART_CTRL_RI | - APBUART_CTRL_RF); - rtems_termios_device_lock_release(base, &lock_context); - /* Activate termios RX daemon task */ - rtems_termios_rxirq_occured(tty); - } - } else { - /* - * Get all new characters from APBUART RX (FIFO) and store them - * on the stack. Then tell termios about the new characters. - * Maximum APBUART RX FIFO size is 32 characters. - */ - cnt = 0; - while ( - ((status=regs->status) & APBUART_STATUS_DR) && - (cnt < sizeof(buf)) - ) { - buf[cnt] = regs->data; - cnt++; - } - if (0 < cnt) { - /* Tell termios layer about new characters */ - rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt); - } - } - - if (uart->sending && (status & APBUART_STATUS_TE)) { - /* Tell close that we sent everything */ - cnt = uart->sending; - - /* - * Tell termios how much we have sent. dequeue() may call - * write_interrupt() to refill the transmitter. - * write_interrupt() will eventually be called with 0 len to - * disable TX interrupts. - */ - rtems_termios_dequeue_characters(tty, cnt); - } -} - |