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 | |
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')
-rw-r--r-- | c/src/lib/libbsp/sparc/erc32/ChangeLog | 8 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/erc32/Makefile.am | 2 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/erc32/console/console.c | 419 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/erc32/console/erc32_console.c | 262 |
4 files changed, 271 insertions, 420 deletions
diff --git a/c/src/lib/libbsp/sparc/erc32/ChangeLog b/c/src/lib/libbsp/sparc/erc32/ChangeLog index a10964d075..d1fdca01a4 100644 --- a/c/src/lib/libbsp/sparc/erc32/ChangeLog +++ b/c/src/lib/libbsp/sparc/erc32/ChangeLog @@ -1,3 +1,11 @@ +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. + 2009-12-10 Ralf Corsépius <ralf.corsepius@rtems.org> * console/console.c: diff --git a/c/src/lib/libbsp/sparc/erc32/Makefile.am b/c/src/lib/libbsp/sparc/erc32/Makefile.am index 84e477304b..f6620266be 100644 --- a/c/src/lib/libbsp/sparc/erc32/Makefile.am +++ b/c/src/lib/libbsp/sparc/erc32/Makefile.am @@ -43,7 +43,7 @@ libbsp_a_SOURCES += ../../shared/bspclean.c ../../shared/bsplibc.c \ # gnatsupp libbsp_a_SOURCES += gnatsupp/gnatsupp.c ../../sparc/shared/gnatcommon.c # console -libbsp_a_SOURCES += console/console.c +libbsp_a_SOURCES += console/erc32_console.c ../../shared/console.c # debugio libbsp_a_SOURCES += console/debugputs.c # clock diff --git a/c/src/lib/libbsp/sparc/erc32/console/console.c b/c/src/lib/libbsp/sparc/erc32/console/console.c deleted file mode 100644 index 13d48e100c..0000000000 --- a/c/src/lib/libbsp/sparc/erc32/console/console.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * This file contains the TTY driver for the serial ports on the erc32. - * - * This driver uses the termios pseudo driver. - * - * COPYRIGHT (c) 1989-2009. - * On-Line Applications Research Corporation (OAR). - * - * 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 <bsp.h> -#include <rtems/libio.h> -#include <stdlib.h> -#include <assert.h> - -/* - * Should we use a polled or interrupt drived console? - * - * NOTE: This is defined in the custom/erc32.cfg file. - * - * WARNING: In sis 1.6, it did not appear that the UART interrupts - * worked in a desirable fashion. Immediately upon writing - * a character into the TX buffer, an interrupt was generated. - * This did not allow enough time for the program to put more - * characters in the buffer. So every character resulted in - * "priming" the transmitter. This effectively results in - * in a polled console with a useless interrupt per character - * on output. It is reasonable to assume that input does not - * share this problem although it was not investigated. - * - */ - -/* - * console_outbyte_polled - * - * This routine transmits a character using polling. - */ - -void console_outbyte_polled( - int port, - char ch -); - -/* body is in debugputs.c */ - -/* - * console_inbyte_nonblocking - * - * This routine polls for a character. - */ - -int console_inbyte_nonblocking( int port ); - -/* body is in debugputs.c */ - -/* - * Interrupt driven console IO - */ - -#if (CONSOLE_USE_INTERRUPTS) - -/* - * Buffers between task and ISRs - */ - -#include <rtems/ringbuf.h> - -Ring_buffer_t TX_Buffer[ 2 ]; -bool Is_TX_active[ 2 ]; - -void *console_termios_data[ 2 ]; - -/* - * console_isr_a - * - * This routine is the console interrupt handler for Channel A. - * - * Input parameters: - * vector - vector number - * - * Output parameters: NONE - * - * Return values: NONE - */ - -rtems_isr console_isr_a( - rtems_vector_number vector -) -{ - char ch; - int UStat; - - if ( (UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRA ) { - if (UStat & ERC32_MEC_UART_STATUS_ERRA) { - ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA; - ERC32_MEC.Control = ERC32_MEC.Control; - } - ch = ERC32_MEC.UART_Channel_A; - - rtems_termios_enqueue_raw_characters( console_termios_data[ 0 ], &ch, 1 ); - } - - if ( ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA ) { - if ( !Ring_buffer_Is_empty( &TX_Buffer[ 0 ] ) ) { - Ring_buffer_Remove_character( &TX_Buffer[ 0 ], ch ); - ERC32_MEC.UART_Channel_A = (uint32_t) ch; - } else - Is_TX_active[ 0 ] = false; - } - - ERC32_Clear_interrupt( ERC32_INTERRUPT_UART_A_RX_TX ); -} - -/* - * console_isr_b - * - * This routine is the console interrupt handler for Channel B. - * - * Input parameters: - * vector - vector number - * - * Output parameters: NONE - * - * Return values: NONE - */ - -rtems_isr console_isr_b( - rtems_vector_number vector -) -{ - char ch; - int UStat; - - if ( (UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRB ) { - if (UStat & ERC32_MEC_UART_STATUS_ERRB) { - ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB; - ERC32_MEC.Control = ERC32_MEC.Control; - } - ch = ERC32_MEC.UART_Channel_B; - rtems_termios_enqueue_raw_characters( console_termios_data[ 1 ], &ch, 1 ); - - } - - if ( ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB ) { - if ( !Ring_buffer_Is_empty( &TX_Buffer[ 1 ] ) ) { - Ring_buffer_Remove_character( &TX_Buffer[ 1 ], ch ); - ERC32_MEC.UART_Channel_B = (uint32_t) ch; - } else - Is_TX_active[ 1 ] = false; - } - - ERC32_Clear_interrupt( ERC32_INTERRUPT_UART_B_RX_TX ); -} - -/* - * console_exit - * - * This routine allows the console to exit by masking its associated interrupt - * vectors. - * - * Input parameters: NONE - * - * Output parameters: NONE - * - * Return values: NONE - */ - -void console_exit(void) -{ - uint32_t port; - uint32_t ch; - - /* - * Although the interrupts for the UART are unmasked, the PIL is set to - * disable all external interrupts. So we might as well do this first. - */ - - ERC32_Mask_interrupt( ERC32_INTERRUPT_UART_A_RX_TX ); - ERC32_Mask_interrupt( ERC32_INTERRUPT_UART_B_RX_TX ); - - for ( port=0 ; port <= 1 ; port++ ) { - while ( !Ring_buffer_Is_empty( &TX_Buffer[ port ] ) ) { - Ring_buffer_Remove_character( &TX_Buffer[ port ], ch ); - console_outbyte_polled( port, ch ); - } - } - - /* - * Now wait for all the data to actually get out ... the send register - * should be empty. - */ - - while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA) != - ERC32_MEC_UART_STATUS_THEA ); - - while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB) != - ERC32_MEC_UART_STATUS_THEB ); - -} - -#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 ) - -/* - * console_initialize_interrupts - * - * This routine initializes the console's receive and transmit - * ring buffers and loads the appropriate vectors to handle the interrupts. - * - * Input parameters: NONE - * - * Output parameters: NONE - * - * Return values: NONE - */ - -#ifdef RDB_BREAK_IN - extern uint32_t trap_table[]; -#endif - -void console_initialize_interrupts( void ) -{ - Ring_buffer_Initialize( &TX_Buffer[ 0 ] ); - Ring_buffer_Initialize( &TX_Buffer[ 1 ] ); - - Is_TX_active[ 0 ] = false; - Is_TX_active[ 1 ] = false; - - atexit( console_exit ); - - set_vector( console_isr_a, CONSOLE_UART_A_TRAP, 1 ); -#ifdef RDB_BREAK_IN - if (trap_table[0x150/4] == 0x91d02000) -#endif - set_vector( console_isr_b, CONSOLE_UART_B_TRAP, 1 ); -} - -/* - * console_outbyte_interrupt - * - * This routine transmits a character out. - * - * Input parameters: - * port - port to transmit character to - * ch - character to be transmitted - * - * Output parameters: NONE - * - * Return values: NONE - */ - -void console_outbyte_interrupt( - int port, - char ch -) -{ - /* - * If this is the first character then we need to prime the pump - */ - - if ( Is_TX_active[ port ] == false ) { - Is_TX_active[ port ] = true; - console_outbyte_polled( port, ch ); - return; - } - - while ( Ring_buffer_Is_full( &TX_Buffer[ port ] ) ); - - Ring_buffer_Add_character( &TX_Buffer[ port ], ch ); -} - -#endif /* CONSOLE_USE_INTERRUPTS */ - -/* - * Console Termios Support Entry Points - * - */ - -ssize_t console_write_support (int minor, const char *buf, size_t len) -{ - int nwrite = 0; - - while (nwrite < len) { -#if (CONSOLE_USE_INTERRUPTS) - console_outbyte_interrupt( minor, *buf++ ); -#else - console_outbyte_polled( minor, *buf++ ); -#endif - nwrite++; - } - return nwrite; -} - -/* - * Console Device Driver Entry Points - * - */ - -rtems_device_driver console_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) -{ - rtems_status_code status; - - /* - * Ensure Termios is initialized - */ - rtems_termios_initialize(); - - /* - * Register Device Names - */ - status = rtems_io_register_name( "/dev/console", major, 0 ); - if (status != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred(status); - - status = rtems_io_register_name( "/dev/console_b", major, 1 ); - if (status != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred(status); - - /* - * Initialize Hardware - */ - #if (CONSOLE_USE_INTERRUPTS) - console_initialize_interrupts(); - #endif - - return RTEMS_SUCCESSFUL; -} - -rtems_device_driver console_open( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - rtems_status_code sc; -#if (CONSOLE_USE_INTERRUPTS) - rtems_libio_open_close_args_t *args = arg; - static const rtems_termios_callbacks intrCallbacks = { - NULL, /* firstOpen */ - NULL, /* lastClose */ - NULL, /* pollRead */ - console_write_support, /* write */ - NULL, /* setAttributes */ - NULL, /* stopRemoteTx */ - NULL, /* startRemoteTx */ - 0 /* outputUsesInterrupts */ - }; -#else - static const rtems_termios_callbacks pollCallbacks = { - NULL, /* firstOpen */ - NULL, /* lastClose */ - console_inbyte_nonblocking, /* pollRead */ - console_write_support, /* write */ - NULL, /* setAttributes */ - NULL, /* stopRemoteTx */ - NULL, /* startRemoteTx */ - 0 /* outputUsesInterrupts */ - }; -#endif - - assert( minor <= 1 ); - if ( minor > 2 ) - return RTEMS_INVALID_NUMBER; - -#if (CONSOLE_USE_INTERRUPTS) - sc = rtems_termios_open (major, minor, arg, &intrCallbacks); - - console_termios_data[ minor ] = args->iop->data1; -#else - sc = rtems_termios_open (major, minor, arg, &pollCallbacks); -#endif - - return RTEMS_SUCCESSFUL; -} - -rtems_device_driver console_close( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_close (arg); -} - -rtems_device_driver console_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_read (arg); -} - -rtems_device_driver console_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_write (arg); -} - -rtems_device_driver console_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_ioctl (arg); -} 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); +} |