diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2010-05-07 12:13:23 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2010-05-07 12:13:23 +0000 |
commit | e455a1252f03253d991b0e2aa24cd0348ab60fac (patch) | |
tree | 9f402710e7ef5773e1c165e2858a56486309da16 /c/src/lib/libbsp/sparc/erc32/console/erc32_console.c | |
parent | 2010-05-07 Arnout Vandecappelle <arnout@mind.be> (diff) | |
download | rtems-e455a1252f03253d991b0e2aa24cd0348ab60fac.tar.bz2 |
2010-04-27 Tiemen Schut <T.Schut@sron.nl>
PR 1506/bsps
* console/console.c: Removed.
* console/erc32_console.c: New file. Use shared console driver.
Make sure interrupt support works. PPPD confirmed on sis.
* Makefile.am: Reflect changes above.
Diffstat (limited to 'c/src/lib/libbsp/sparc/erc32/console/erc32_console.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/erc32/console/erc32_console.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/erc32/console/erc32_console.c b/c/src/lib/libbsp/sparc/erc32/console/erc32_console.c new file mode 100644 index 0000000000..e91c4c0f0a --- /dev/null +++ b/c/src/lib/libbsp/sparc/erc32/console/erc32_console.c @@ -0,0 +1,262 @@ +/** + * @file + * + * @brief Driver for serial ports on the ERC32. + */ + +/* + * Copyright (c) 2010 Tiemen Schut <T.Schut@sron.nl> + * + * 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. + * + * $Id$ + */ + +#include <unistd.h> +#include <termios.h> +#include <stdlib.h> + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/console.h> +#include <rtems/termiostypes.h> + +#include <libchip/serial.h> +#include <libchip/sersupp.h> + +#include <bsp.h> + +#define CONSOLE_BUF_SIZE (16) + +#define CONSOLE_UART_A_TRAP ERC32_TRAP_TYPE(ERC32_INTERRUPT_UART_A_RX_TX) +#define CONSOLE_UART_B_TRAP ERC32_TRAP_TYPE(ERC32_INTERRUPT_UART_B_RX_TX) + +static uint8_t erc32_console_get_register(uint32_t addr, uint8_t i) +{ + volatile uint32_t *reg = (volatile uint32_t *)addr; + return (uint8_t) reg [i]; +} + +static void erc32_console_set_register(uint32_t addr, uint8_t i, uint8_t val) +{ + volatile uint32_t *reg = (volatile uint32_t *)addr; + reg [i] = val; +} + +static int erc32_console_first_open(int major, int minor, void *arg); +static ssize_t erc32_console_write_support_int(int minor, const char *buf, size_t len); +static void erc32_console_initialize(int minor); + +rtems_device_minor_number Console_Port_Minor = 0; + +console_fns erc32_fns = { + libchip_serial_default_probe, /* deviceProbe */ + erc32_console_first_open, /* deviceFirstOpen */ + NULL, /* deviceLastClose */ + NULL, /* deviceRead */ + erc32_console_write_support_int, /* deviceWrite */ + erc32_console_initialize, /* deviceInitialize */ + NULL, /* deviceWritePolled */ + NULL, /* deviceSetAttributes */ + true /* deviceOutputUsesInterrupts */ +}; + +console_tbl Console_Port_Tbl [] = { + { + .sDeviceName = "/dev/console", + .deviceType = SERIAL_CUSTOM, + .pDeviceFns = &erc32_fns, + .deviceProbe = NULL, + .pDeviceFlow = NULL, + .ulMargin = 16, + .ulHysteresis = 8, + .pDeviceParams = (void *) 1, + .ulCtrlPort1 = 0, + .ulCtrlPort2 = 0, + .ulDataPort = 0, + .getRegister = erc32_console_get_register, + .setRegister = erc32_console_set_register, + .getData = NULL, + .setData = NULL, + .ulClock = 16, + .ulIntVector = ERC32_INTERRUPT_UART_A_RX_TX + }, + { + .sDeviceName = "/dev/console_b", + .deviceType = SERIAL_CUSTOM, + .pDeviceFns = &erc32_fns, + .deviceProbe = NULL, + .pDeviceFlow = NULL, + .ulMargin = 16, + .ulHysteresis = 8, + .pDeviceParams = (void *) 1, + .ulCtrlPort1 = 0, + .ulCtrlPort2 = 0, + .ulDataPort = 0, + .getRegister = erc32_console_get_register, + .setRegister = erc32_console_set_register, + .getData = NULL, + .setData = NULL, + .ulClock = 16, + .ulIntVector = ERC32_INTERRUPT_UART_B_RX_TX + }, +}; + +/* always exactly two uarts for erc32 */ +#define ERC32_UART_COUNT (2) + +unsigned long Console_Port_Count = ERC32_UART_COUNT; + +console_data Console_Port_Data [ERC32_UART_COUNT]; + +static int erc32_console_first_open(int major, int minor, void *arg) +{ + /* Check minor number */ + if (minor < 0 || minor > 1) { + return -1; + } + + rtems_libio_open_close_args_t *oca = arg; + struct rtems_termios_tty *tty = oca->iop->data1; + console_tbl *ct = &Console_Port_Tbl [minor]; + console_data *cd = &Console_Port_Data [minor]; + + cd->termios_data = tty; + rtems_termios_set_initial_baud(tty, (int32_t)ct->pDeviceParams); + + return 0; +} + +static ssize_t erc32_console_write_support_int(int minor, const char *buf, size_t len) +{ + console_data *cd = &Console_Port_Data[minor]; + int k = 0; + + if (minor == 0) { /* uart a */ + for (k = 0; k < len && (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA); k ++) { + ERC32_MEC.UART_Channel_A = (unsigned char)buf[k]; + } + ERC32_Force_interrupt(ERC32_INTERRUPT_UART_A_RX_TX); + } else { /* uart b */ + for (k = 0; k < len && (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB); k ++) { + ERC32_MEC.UART_Channel_B = (unsigned char)buf[k]; + } + ERC32_Force_interrupt(ERC32_INTERRUPT_UART_B_RX_TX); + } + + if (len > 0) { + cd->pDeviceContext = (void *)k; + cd->bActive = true; + } + + return 0; +} + +static void erc32_console_isr_a( + rtems_vector_number vector +) +{ + console_data *cd = &Console_Port_Data[0]; + + /* check for error */ + if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_ERRA) { + ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA; + ERC32_MEC.Control = ERC32_MEC.Control; + } + + do { + int chars_to_dequeue = (int)cd->pDeviceContext; + int rv = 0; + int i = 0; + char buf[CONSOLE_BUF_SIZE]; + + /* enqueue received chars */ + while (i < CONSOLE_BUF_SIZE) { + if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRA) { + buf[i] = ERC32_MEC.UART_Channel_A; + ++i; + } else { + break; + } + } + rtems_termios_enqueue_raw_characters(cd->termios_data, buf, i); + + /* dequeue transmitted chars */ + cd->pDeviceContext = 0; + rv = rtems_termios_dequeue_characters(cd->termios_data, chars_to_dequeue); + if (rv == 0 && !(ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRA)) { + cd->bActive = false; + ERC32_Clear_interrupt (ERC32_INTERRUPT_UART_A_RX_TX); + } + } while (ERC32_Is_interrupt_pending (ERC32_INTERRUPT_UART_A_RX_TX)); +} + +static void erc32_console_isr_b( + rtems_vector_number vector +) +{ + console_data *cd = &Console_Port_Data[1]; + + /* check for error */ + if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_ERRB) { + ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB; + ERC32_MEC.Control = ERC32_MEC.Control; + } + + do { + int chars_to_dequeue = (int)cd->pDeviceContext; + int rv = 0; + int i = 0; + char buf[CONSOLE_BUF_SIZE]; + + /* enqueue received chars */ + while (i < CONSOLE_BUF_SIZE) { + if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRB) { + buf[i] = ERC32_MEC.UART_Channel_B; + ++i; + } else { + break; + } + } + rtems_termios_enqueue_raw_characters(cd->termios_data, buf, i); + + /* dequeue transmitted chars */ + cd->pDeviceContext = 0; + rv = rtems_termios_dequeue_characters(cd->termios_data, chars_to_dequeue); + if (rv == 0 && !(ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRB)) { + cd->bActive = false; + ERC32_Clear_interrupt (ERC32_INTERRUPT_UART_B_RX_TX); + } + } while (ERC32_Is_interrupt_pending (ERC32_INTERRUPT_UART_B_RX_TX)); +} + + +/* + * Console Device Driver Entry Points + * + */ + +static void erc32_console_initialize( + int minor +) +{ + console_data *cd = &Console_Port_Data [minor]; + + cd->bActive = false; + cd->pDeviceContext = 0; + + /* + * Initialize the Termios infrastructure. If Termios has already + * been initialized by another device driver, then this call will + * have no effect. + */ + rtems_termios_initialize(); + + /* + * Initialize Hardware + */ + set_vector(erc32_console_isr_a, CONSOLE_UART_A_TRAP, 1); + set_vector(erc32_console_isr_b, CONSOLE_UART_B_TRAP, 1); +} |