Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:59

0001 /*
0002  *  console.c
0003  *
0004  *  This file contains the Intec SS555 termios serial I/O package.
0005  *
0006  *  The SCI channels are assigned as follows
0007  *
0008  *   Channel     Device      Minor
0009  *    SCI1      /dev/tty0      0
0010  *    SCI2      /dev/tty1      1
0011  *
0012  *  All ports support termios. The use of termios is recommended for real-time
0013  *  applications. Termios provides buffering and input processing. When not
0014  *  using termios, processing is limited to the substitution of LF for CR on
0015  *  input, and the output of a CR following the output of a LF character.
0016  *  Note that the terminal should not send CR/LF pairs when the return key
0017  *  is pressed, and that output lines are terminated with LF/CR, not CR/LF
0018  *  (although that would be easy to change).
0019  *
0020  *  I/O may be interrupt-driven (recommended for real-time applications) or
0021  *  polled.
0022  *
0023  *  LIMITATIONS:
0024  *
0025  *  It is not possible to use different I/O modes on the different ports. The
0026  *  exception is with printk. The printk port can use a different mode from
0027  *  the other ports. If this is done, it is important not to open the printk
0028  *  port from an RTEMS application.
0029  *
0030  *  Currently, the I/O modes are determined at build time. It would be much
0031  *  better to have the mode selected at boot time based on parameters in
0032  *  NVRAM.
0033  *
0034  *  Interrupt-driven I/O requires termios.
0035  *
0036  *  TESTS:
0037  *
0038  *  TO RUN THE TESTS, USE POLLED I/O WITHOUT TERMIOS SUPPORT. Some tests
0039  *  play with the interrupt masks and turn off I/O. Those tests will hang
0040  *  when interrupt-driven I/O is used. Other tests, such as cdtest, do I/O
0041  *  from the static constructors before the console is open. This test
0042  *  will not work with interrupt-driven I/O. Because of the buffering
0043  *  performed in termios, test output may not be in sequence.The tests
0044  *  should all be fixed to work with interrupt-driven I/O and to
0045  *  produce output in the expected sequence. Obviously, the termios test
0046  *  requires termios support in the driver.
0047  *
0048  *  Set CONSOLE_MINOR to the appropriate device minor number in the
0049  *  config file. This allows the RTEMS application console to be different
0050  *  from the GDB port.
0051  *
0052  *  This driver handles both available serial ports: it distinguishes
0053  *  the sub-devices using minor device numbers. It is not possible to have
0054  *  other protocols running on the other ports when this driver is used as
0055  *  currently written.
0056  *
0057  *
0058  *  SS555 port sponsored by Defence Research and Development Canada - Suffield
0059  *  Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
0060  *
0061  *  Derived from c/src/lib/libbsp/powerpc/mbx8xx/console/console.c:
0062  *
0063  *  Based on code (alloc860.c in eth_comm port) by
0064  *  Jay Monkman (jmonkman@frasca.com),
0065  *  Copyright (C) 1998 by Frasca International, Inc.
0066  *
0067  *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
0068  *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>.
0069  *  Copyright (c) 2000, National Research Council of Canada
0070  *
0071  */
0072 #include <stdarg.h>
0073 #include <stdio.h>
0074 #include <termios.h>
0075 
0076 #include <rtems/console.h>
0077 #include <rtems/bspIo.h>
0078 #include <rtems/libio.h>
0079 #include <bsp.h>                /* Must be before libio.h */
0080 
0081 static void _BSP_output_char( char c );
0082 static rtems_status_code do_poll_read( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
0083 static rtems_status_code do_poll_write( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
0084 
0085 static void _BSP_null_char( char c ) {return;}
0086 
0087 BSP_output_char_function_type     BSP_output_char = _BSP_null_char;
0088 BSP_polling_getchar_function_type BSP_poll_char = NULL;
0089 
0090 /*
0091  *  do_poll_read
0092  *
0093  *  Input characters through polled I/O. Returns as soon as a character has
0094  *  been received. Otherwise, if we wait for the number of requested
0095  *  characters, we could be here forever!
0096  *
0097  *  CR is converted to LF on input. The terminal should not send a CR/LF pair
0098  *  when the return or enter key is pressed.
0099  *
0100  *  Input parameters:
0101  *    major - ignored. Should be the major number for this driver.
0102  *    minor - selected channel.
0103  *    arg->buffer - where to put the received characters.
0104  *    arg->count  - number of characters to receive before returning--Ignored.
0105  *
0106  *  Output parameters:
0107  *    arg->bytes_moved - the number of characters read. Always 1.
0108  *
0109  *  Return value: RTEMS_SUCCESSFUL
0110  *
0111  *  CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
0112  */
0113 static rtems_status_code do_poll_read(
0114   rtems_device_major_number major,
0115   rtems_device_minor_number minor,
0116   void                    * arg
0117 )
0118 {
0119   rtems_libio_rw_args_t *rw_args = arg;
0120   int c;
0121 
0122   while( (c = m5xx_uart_pollRead(minor)) == -1 );
0123   rw_args->buffer[0] = (uint8_t)c;
0124   if( rw_args->buffer[0] == '\r' )
0125       rw_args->buffer[0] = '\n';
0126   rw_args->bytes_moved = 1;
0127 
0128   return RTEMS_SUCCESSFUL;
0129 }
0130 
0131 /*
0132  *  do_poll_write
0133  *
0134  *  Output characters through polled I/O. Returns only once every character has
0135  *  been sent.
0136  *
0137  *  CR is transmitted AFTER a LF on output.
0138  *
0139  *  Input parameters:
0140  *    major - ignored. Should be the major number for this driver.
0141  *    minor - selected channel
0142  *    arg->buffer - where to get the characters to transmit.
0143  *    arg->count  - the number of characters to transmit before returning.
0144  *
0145  *  Output parameters:
0146  *    arg->bytes_moved - the number of characters read
0147  *
0148  *  Return value: RTEMS_SUCCESSFUL
0149  *
0150  *  CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
0151  */
0152 static rtems_status_code do_poll_write(
0153   rtems_device_major_number major,
0154   rtems_device_minor_number minor,
0155   void                    * arg
0156 )
0157 {
0158   rtems_libio_rw_args_t *rw_args = arg;
0159   uint32_t i;
0160   char cr ='\r';
0161 
0162   for( i = 0; i < rw_args->count; i++ ) {
0163     m5xx_uart_pollWrite(minor, &(rw_args->buffer[i]), 1);
0164     if ( rw_args->buffer[i] == '\n' )
0165       m5xx_uart_pollWrite(minor, &cr, 1);
0166   }
0167   rw_args->bytes_moved = i;
0168 
0169   return RTEMS_SUCCESSFUL;
0170 }
0171 
0172 /*
0173  *  Print functions prototyped in bspIo.h
0174  */
0175 
0176 static void _BSP_output_char( char c )
0177 {
0178   char cr = '\r';
0179 
0180   /*
0181    *  Can't rely on console_initialize having been called before this
0182    *  function is used, so it may fail.
0183    */
0184 
0185   m5xx_uart_pollWrite( PRINTK_MINOR, &c, 1 );
0186   if( c == '\n' )
0187     m5xx_uart_pollWrite( PRINTK_MINOR, &cr, 1 );
0188 }
0189 
0190 /*
0191  ***************
0192  * BOILERPLATE *
0193  ***************
0194  *
0195  *  All these functions are prototyped in rtems/c/src/lib/include/console.h.
0196  */
0197 
0198 /*
0199  * Initialize and register the device
0200  */
0201 rtems_device_driver console_initialize(
0202   rtems_device_major_number major,
0203   rtems_device_minor_number minor,
0204   void *arg
0205 )
0206 {
0207   rtems_status_code status;
0208 
0209   /*
0210    * Set up TERMIOS if needed
0211    */
0212   #if UARTS_USE_TERMIOS == 1
0213     rtems_termios_initialize ();
0214   #endif /* UARTS_USE_TERMIOS */
0215 
0216   /*
0217    * Do device-specific initialization
0218    */
0219   BSP_output_char = _BSP_output_char;
0220 
0221   m5xx_uart_initialize(SCI1_MINOR);
0222   status = rtems_io_register_name ("/dev/tty0", major, SCI1_MINOR);
0223   if (status != RTEMS_SUCCESSFUL)
0224     rtems_fatal_error_occurred (status);
0225 
0226   m5xx_uart_initialize(SCI2_MINOR);
0227   status = rtems_io_register_name ("/dev/tty1", major, SCI2_MINOR);
0228   if (status != RTEMS_SUCCESSFUL)
0229     rtems_fatal_error_occurred (status);
0230 
0231   /* Now register the RTEMS console */
0232   status = rtems_io_register_name ("/dev/console", major, CONSOLE_MINOR);
0233   if (status != RTEMS_SUCCESSFUL)
0234     rtems_fatal_error_occurred (status);
0235 
0236   return RTEMS_SUCCESSFUL;
0237 }
0238 
0239 /*
0240  * Open the device
0241  */
0242 rtems_device_driver console_open(
0243   rtems_device_major_number major,
0244   rtems_device_minor_number minor,
0245   void *arg
0246 )
0247 {
0248   rtems_status_code sc;
0249 
0250   if ( minor > NUM_PORTS - 1 )
0251     return RTEMS_INVALID_NUMBER;
0252 
0253   #if (UARTS_USE_TERMIOS == 1)
0254   {
0255     #if (UARTS_IO_MODE == 1)    /* RTEMS interrupt-driven I/O with termios */
0256 
0257       static const rtems_termios_callbacks callbacks = {
0258         m5xx_uart_firstOpen,            /* firstOpen */
0259         m5xx_uart_lastClose,            /* lastClose */
0260         NULL,                           /* pollRead */
0261         m5xx_uart_write,                /* write */
0262         m5xx_uart_setAttributes,        /* setAttributes */
0263         NULL,                           /* stopRemoteTx */
0264         NULL,                           /* startRemoteTx */
0265         TERMIOS_IRQ_DRIVEN              /* outputUsesInterrupts */
0266       };
0267       sc = rtems_termios_open( major, minor, arg, &callbacks );
0268 
0269     #else /* UARTS_IO_MODE != 1 */  /* RTEMS polled I/O with termios */
0270 
0271       static const rtems_termios_callbacks callbacks = {
0272         m5xx_uart_firstOpen,            /* firstOpen */
0273         m5xx_uart_lastClose,            /* lastClose */
0274         m5xx_uart_pollRead,             /* pollRead */
0275         m5xx_uart_pollWrite,            /* write */
0276         m5xx_uart_setAttributes,        /* setAttributes */
0277         NULL,                           /* stopRemoteTx */
0278         NULL,                           /* startRemoteTx */
0279         TERMIOS_POLLED                  /* outputUsesInterrupts */
0280       };
0281       sc = rtems_termios_open( major, minor, arg, &callbacks );
0282 
0283     #endif
0284 
0285     return sc;
0286   }
0287 
0288   #else     /* no termios -- default to polled I/O */
0289   {
0290     sc = RTEMS_SUCCESSFUL;
0291   }
0292   #endif
0293 
0294   return sc;
0295 }
0296 
0297 /*
0298  * Close the device
0299  */
0300 rtems_device_driver console_close(
0301   rtems_device_major_number major,
0302   rtems_device_minor_number minor,
0303   void *arg
0304 )
0305 {
0306   if ( minor > NUM_PORTS-1 )
0307     return RTEMS_INVALID_NUMBER;
0308 
0309   #if UARTS_USE_TERMIOS == 1
0310     return rtems_termios_close( arg );
0311   #else
0312     return RTEMS_SUCCESSFUL;
0313   #endif
0314 }
0315 
0316 /*
0317  * Read from the device
0318  */
0319 rtems_device_driver console_read(
0320   rtems_device_major_number major,
0321   rtems_device_minor_number minor,
0322   void *arg
0323 )
0324 {
0325   if ( minor > NUM_PORTS-1 )
0326     return RTEMS_INVALID_NUMBER;
0327 
0328   #if UARTS_USE_TERMIOS == 1
0329     return rtems_termios_read( arg );
0330   #else
0331     return do_poll_read( major, minor, arg );
0332   #endif
0333 }
0334 
0335 /*
0336  * Write to the device
0337  */
0338 rtems_device_driver console_write(
0339   rtems_device_major_number major,
0340   rtems_device_minor_number minor,
0341   void *arg
0342 )
0343 {
0344   if ( minor > NUM_PORTS-1 )
0345     return RTEMS_INVALID_NUMBER;
0346 
0347   #if UARTS_USE_TERMIOS == 1
0348     return rtems_termios_write( arg );
0349   #else
0350     return do_poll_write( major, minor, arg );
0351   #endif
0352 }
0353 
0354 /*
0355  * Handle ioctl request.
0356  */
0357 rtems_device_driver console_control(
0358   rtems_device_major_number major,
0359   rtems_device_minor_number minor,
0360   void *arg
0361 )
0362 {
0363   if ( minor > NUM_PORTS-1 )
0364     return RTEMS_INVALID_NUMBER;
0365 
0366   #if UARTS_USE_TERMIOS == 1
0367     return rtems_termios_ioctl( arg );
0368   #else
0369     return RTEMS_SUCCESSFUL;
0370   #endif
0371 }