Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:08

0001 /**
0002  * @file
0003  * @ingroup RTEMSBSPsSPARCLEON2
0004  * @brief TTY driver driver for the serial ports on the LEON console
0005  *
0006  *  This file contains the TTY driver for the serial ports on the LEON.
0007  */
0008 
0009 /*
0010  *  COPYRIGHT (c) 1989-2014.
0011  *  On-Line Applications Research Corporation (OAR).
0012  *
0013  *  The license and distribution terms for this file may be
0014  *  found in the file LICENSE in this distribution or at
0015  *  http://www.rtems.org/license/LICENSE.
0016  */
0017 
0018 #include <stdlib.h>
0019 #include <assert.h>
0020 
0021 #include <rtems/console.h>
0022 #include <rtems/libio.h>
0023 #include <bsp.h>
0024 
0025 /*
0026  *  Interrupt driven console IO
0027  */
0028 
0029 #if (CONSOLE_USE_INTERRUPTS)
0030 
0031 /*
0032  *  Buffers between task and ISRs
0033  */
0034 
0035 #include <rtems/ringbuf.h>
0036 
0037 Ring_buffer_t  TX_Buffer[ 2 ];
0038 bool           Is_TX_active[ 2 ];
0039 
0040 void *console_termios_data[ 2 ];
0041 
0042 /*
0043  *  console_isr_a
0044  *
0045  *  This routine is the console interrupt handler for Channel 1.
0046  *
0047  *  Input parameters:
0048  *    vector - vector number
0049  *
0050  *  Output parameters: NONE
0051  *
0052  *  Return values:     NONE
0053  */
0054 
0055 rtems_isr console_isr_a(
0056   rtems_vector_number vector
0057 )
0058 {
0059   char ch;
0060   int UStat;
0061 
0062   if ( (UStat = LEON_REG.UART_Status_1) & LEON_REG_UART_STATUS_DR ) {
0063     if (UStat & LEON_REG_UART_STATUS_ERR) {
0064       LEON_REG.UART_Status_1 = LEON_REG_UART_STATUS_CLR;
0065     }
0066     ch = LEON_REG.UART_Channel_1;
0067 
0068     rtems_termios_enqueue_raw_characters( console_termios_data[ 0 ], &ch, 1 );
0069   }
0070 
0071   if ( LEON_REG.UART_Status_1 & LEON_REG_UART_STATUS_THE ) {
0072     if ( !Ring_buffer_Is_empty( &TX_Buffer[ 0 ] ) ) {
0073       Ring_buffer_Remove_character( &TX_Buffer[ 0 ], ch );
0074       LEON_REG.UART_Channel_1 = (uint32_t) ch;
0075     } else
0076      Is_TX_active[ 0 ] = false;
0077   }
0078 
0079   LEON_Clear_interrupt( LEON_INTERRUPT_UART_1_RX_TX );
0080 }
0081 
0082 /*
0083  *  console_isr_b
0084  *
0085  *  This routine is the console interrupt handler for Channel 2.
0086  *
0087  *  Input parameters:
0088  *    vector - vector number
0089  *
0090  *  Output parameters: NONE
0091  *
0092  *  Return values:     NONE
0093  */
0094 
0095 rtems_isr console_isr_b(
0096   rtems_vector_number vector
0097 )
0098 {
0099   char ch;
0100   int UStat;
0101 
0102   if ( (UStat = LEON_REG.UART_Status_2) & LEON_REG_UART_STATUS_DR ) {
0103     if (UStat & LEON_REG_UART_STATUS_ERR) {
0104       LEON_REG.UART_Status_2 = LEON_REG_UART_STATUS_CLR;
0105     }
0106     ch = LEON_REG.UART_Channel_2;
0107     rtems_termios_enqueue_raw_characters( console_termios_data[ 1 ], &ch, 1 );
0108 
0109   }
0110 
0111   if ( LEON_REG.UART_Status_2 & LEON_REG_UART_STATUS_THE ) {
0112     if ( !Ring_buffer_Is_empty( &TX_Buffer[ 1 ] ) ) {
0113       Ring_buffer_Remove_character( &TX_Buffer[ 1 ], ch );
0114       LEON_REG.UART_Channel_2 = (uint32_t) ch;
0115     } else
0116      Is_TX_active[ 1 ] = false;
0117   }
0118 
0119   LEON_Clear_interrupt( LEON_INTERRUPT_UART_2_RX_TX );
0120 }
0121 
0122 /*
0123  *  console_exit
0124  *
0125  *  This routine allows the console to exit by masking its associated interrupt
0126  *  vectors.
0127  *
0128  *  Input parameters:  NONE
0129  *
0130  *  Output parameters: NONE
0131  *
0132  *  Return values:     NONE
0133  */
0134 
0135 void console_exit()
0136 {
0137   uint32_t port;
0138   uint32_t ch;
0139 
0140   /*
0141    *  Although the interrupts for the UART are unmasked, the PIL is set to
0142    *  disable all external interrupts.  So we might as well do this first.
0143    */
0144 
0145   LEON_Mask_interrupt( LEON_INTERRUPT_UART_1_RX_TX );
0146   LEON_Mask_interrupt( LEON_INTERRUPT_UART_2_RX_TX );
0147 
0148   for ( port=0 ; port <= 1 ; port++ ) {
0149     while ( !Ring_buffer_Is_empty( &TX_Buffer[ port ] ) ) {
0150       Ring_buffer_Remove_character( &TX_Buffer[ port ], ch );
0151       console_outbyte_polled( port, ch );
0152     }
0153   }
0154 
0155   /*
0156    *  Now wait for all the data to actually get out ... the send register
0157    *  should be empty.
0158    */
0159 
0160   while ( (LEON_REG.UART_Status_1 & LEON_REG_UART_STATUS_THE) !=
0161           LEON_REG_UART_STATUS_THE );
0162 
0163   while ( (LEON_REG.UART_Status_2 & LEON_REG_UART_STATUS_THE) !=
0164           LEON_REG_UART_STATUS_THE );
0165 
0166   LEON_REG.UART_Control_1 = 0;
0167   LEON_REG.UART_Control_2 = 0;
0168   LEON_REG.UART_Status_1 = 0;
0169   LEON_REG.UART_Status_2 = 0;
0170 
0171 
0172 }
0173 
0174 #define CONSOLE_UART_1_TRAP  LEON_TRAP_TYPE( LEON_INTERRUPT_UART_1_RX_TX )
0175 #define CONSOLE_UART_2_TRAP  LEON_TRAP_TYPE( LEON_INTERRUPT_UART_2_RX_TX )
0176 
0177 /*
0178  *  console_initialize_interrupts
0179  *
0180  *  This routine initializes the console's receive and transmit
0181  *  ring buffers and loads the appropriate vectors to handle the interrupts.
0182  *
0183  *  Input parameters:  NONE
0184  *
0185  *  Output parameters: NONE
0186  *
0187  *  Return values:     NONE
0188  */
0189 
0190 #ifdef RDB_BREAK_IN
0191   extern uint32_t trap_table[];
0192 #endif
0193 
0194 void console_initialize_interrupts( void )
0195 {
0196   Ring_buffer_Initialize( &TX_Buffer[ 0 ] );
0197   Ring_buffer_Initialize( &TX_Buffer[ 1 ] );
0198 
0199   Is_TX_active[ 0 ] = false;
0200   Is_TX_active[ 1 ] = false;
0201 
0202   atexit( console_exit );
0203 
0204   LEON_REG.UART_Control_1 |= LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI;
0205   LEON_REG.UART_Control_2 |= LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI;
0206 
0207   set_vector( console_isr_a, CONSOLE_UART_1_TRAP, 1 );
0208 #ifdef RDB_BREAK_IN
0209   if (trap_table[0x150/4] == 0x91d02000)
0210 #endif
0211   set_vector( console_isr_b, CONSOLE_UART_2_TRAP, 1 );
0212 }
0213 
0214 /*
0215  *  console_outbyte_interrupt
0216  *
0217  *  This routine transmits a character out.
0218  *
0219  *  Input parameters:
0220  *    port - port to transmit character to
0221  *    ch  - character to be transmitted
0222  *
0223  *  Output parameters:  NONE
0224  *
0225  *  Return values:      NONE
0226  */
0227 
0228 void console_outbyte_interrupt(
0229   int   port,
0230   char  ch
0231 )
0232 {
0233   /*
0234    *  If this is the first character then we need to prime the pump
0235    */
0236 
0237   if ( Is_TX_active[ port ] == false ) {
0238     Is_TX_active[ port ] = true;
0239     console_outbyte_polled( port, ch );
0240     return;
0241   }
0242 
0243   while ( Ring_buffer_Is_full( &TX_Buffer[ port ] ) );
0244 
0245   Ring_buffer_Add_character( &TX_Buffer[ port ], ch );
0246 }
0247 
0248 #endif /* CONSOLE_USE_INTERRUPTS */
0249 
0250 /*
0251  *  Console Termios Support Entry Points
0252  *
0253  */
0254 
0255 static ssize_t console_write_support (int minor, const char *buf, size_t len)
0256 {
0257   int nwrite = 0;
0258 
0259   while (nwrite < len) {
0260 #if (CONSOLE_USE_INTERRUPTS)
0261     console_outbyte_interrupt( minor, *buf++ );
0262 #else
0263     console_outbyte_polled( minor, *buf++ );
0264 #endif
0265     nwrite++;
0266   }
0267   return nwrite;
0268 }
0269 
0270 /*
0271  *  Console Device Driver Entry Points
0272  *
0273  */
0274 
0275 rtems_device_driver console_initialize(
0276   rtems_device_major_number  major,
0277   rtems_device_minor_number  minor,
0278   void                      *arg
0279 )
0280 {
0281   rtems_status_code status;
0282 
0283   rtems_termios_initialize();
0284 
0285   /*
0286    *  Register Device Names
0287    */
0288 
0289   status = rtems_io_register_name( "/dev/console", major, 0 );
0290   if (status != RTEMS_SUCCESSFUL)
0291     rtems_fatal_error_occurred(status);
0292 
0293   status = rtems_io_register_name( "/dev/console_b", major, 1 );
0294   if (status != RTEMS_SUCCESSFUL)
0295     rtems_fatal_error_occurred(status);
0296 
0297   /*
0298    *  Initialize Hardware
0299    */
0300 
0301   LEON_REG.UART_Control_1 |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
0302   LEON_REG.UART_Control_2 |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE |
0303       LEON_REG_UART_CTRL_RI;  /* rx irq default enable for remote debugger */
0304   LEON_REG.UART_Status_1 = 0;
0305   LEON_REG.UART_Status_2 = 0;
0306 #if (CONSOLE_USE_INTERRUPTS)
0307   console_initialize_interrupts();
0308 #endif
0309 
0310   return RTEMS_SUCCESSFUL;
0311 }
0312 
0313 rtems_device_driver console_open(
0314   rtems_device_major_number major,
0315   rtems_device_minor_number minor,
0316   void                    * arg
0317 )
0318 {
0319   rtems_status_code sc;
0320 #if (CONSOLE_USE_INTERRUPTS)
0321   rtems_libio_open_close_args_t *args = arg;
0322   static const rtems_termios_callbacks intrCallbacks = {
0323     NULL,                        /* firstOpen */
0324     NULL,                        /* lastClose */
0325     NULL,                        /* pollRead */
0326     console_write_support,       /* write */
0327     NULL,                        /* setAttributes */
0328     NULL,                        /* stopRemoteTx */
0329     NULL,                        /* startRemoteTx */
0330     TERMIOS_POLLED               /* outputUsesInterrupts */
0331   };
0332 #else
0333   static const rtems_termios_callbacks pollCallbacks = {
0334     NULL,                        /* firstOpen */
0335     NULL,                        /* lastClose */
0336     console_inbyte_nonblocking,  /* pollRead */
0337     console_write_support,       /* write */
0338     NULL,                        /* setAttributes */
0339     NULL,                        /* stopRemoteTx */
0340     NULL,                        /* startRemoteTx */
0341     TERMIOS_POLLED               /* outputUsesInterrupts */
0342   };
0343 #endif
0344 
0345   assert( minor <= 1 );
0346   if ( minor > 2 )
0347     return RTEMS_INVALID_NUMBER;
0348 
0349 #if (CONSOLE_USE_INTERRUPTS)
0350   sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
0351 
0352   console_termios_data[ minor ] = args->iop->data1;
0353 #else
0354   sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
0355 #endif
0356   (void) sc; /* avoid set but not used warning */
0357 
0358   return RTEMS_SUCCESSFUL;
0359 }
0360 
0361 rtems_device_driver console_close(
0362   rtems_device_major_number major,
0363   rtems_device_minor_number minor,
0364   void                    * arg
0365 )
0366 {
0367   return rtems_termios_close (arg);
0368 }
0369 
0370 rtems_device_driver console_read(
0371   rtems_device_major_number major,
0372   rtems_device_minor_number minor,
0373   void                    * arg
0374 )
0375 {
0376   return rtems_termios_read (arg);
0377 }
0378 
0379 rtems_device_driver console_write(
0380   rtems_device_major_number major,
0381   rtems_device_minor_number minor,
0382   void                    * arg
0383 )
0384 {
0385   return rtems_termios_write (arg);
0386 }
0387 
0388 rtems_device_driver console_control(
0389   rtems_device_major_number major,
0390   rtems_device_minor_number minor,
0391   void                    * arg
0392 )
0393 {
0394   return rtems_termios_ioctl (arg);
0395 }