mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 07:05:45 +00:00
Edvin Catovic <edvin@gaisler.com> Konrad Eisele <konrad@gaisler.com> PR 827/bsps * ChangeLog, configure.ac, console/Makefile.am, console/console.c, console/debugputs.c, startup/Makefile.am, startup/linkcmds, tools/Makefile.am: Portion of large update of SPARC BSPs. Includes addition of sis, leon2 and leon3 BSPs, deletion of leon BSP, addition of SMC91111 NIC driver and much more.
441 lines
9.9 KiB
C
441 lines
9.9 KiB
C
/*
|
|
* This file contains the TTY driver for the serial ports on the erc32.
|
|
*
|
|
* This driver uses the termios pseudo driver.
|
|
*
|
|
* COPYRIGHT (c) 1989-1999.
|
|
* 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>
|
|
#include <rtems/bspIo.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 <ringbuf.h>
|
|
|
|
Ring_buffer_t TX_Buffer[ 2 ];
|
|
boolean 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 = (unsigned32) 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 = (unsigned32) 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()
|
|
{
|
|
rtems_unsigned32 port;
|
|
rtems_unsigned32 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 unsigned32 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
|
|
*
|
|
*/
|
|
|
|
int console_write_support (int minor, const char *buf, int 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;
|
|
|
|
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);
|
|
}
|
|
|
|
/* putchar/getchar for printk */
|
|
|
|
static void bsp_out_char (char c)
|
|
{
|
|
console_outbyte_polled(0, c);
|
|
}
|
|
|
|
BSP_output_char_function_type BSP_output_char = bsp_out_char;
|
|
|
|
static char bsp_in_char(void)
|
|
{
|
|
int tmp;
|
|
|
|
while ((tmp = console_inbyte_nonblocking(0)) < 0);
|
|
return (char) tmp;
|
|
}
|
|
|
|
BSP_polling_getchar_function_type BSP_poll_char = bsp_in_char;
|
|
|
|
|