Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup Console
0007  *
0008  * @brief Extension of the generic libchip console driver shell
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 1989-2011, 2016.
0013  *  On-Line Applications Research Corporation (OAR).
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #include <bsp.h>
0038 #include <bsp/fatal.h>
0039 #include <rtems/libio.h>
0040 #include <rtems/console.h>
0041 #include <stdlib.h>
0042 #include <string.h>
0043 #include <assert.h>
0044 #include <termios.h>
0045 
0046 #include <rtems/termiostypes.h>
0047 #include <libchip/serial.h>
0048 #include "legacy-console.h"
0049 
0050 unsigned long               Console_Port_Count  = 0;
0051 console_tbl               **Console_Port_Tbl    = NULL;
0052 console_data               *Console_Port_Data   = NULL;
0053 rtems_device_minor_number   Console_Port_Minor  = 0;
0054 static bool                 console_initialized = false;
0055 
0056 /*
0057  *  console_find_console_entry
0058  *
0059  *  This method is used to search the console entries for a
0060  *  specific device entry.
0061  */
0062 console_tbl* console_find_console_entry(
0063   const char                *match,
0064   size_t                     length,
0065   rtems_device_minor_number *match_minor
0066 )
0067 {
0068   rtems_device_minor_number  minor;
0069 
0070   /*
0071    * The the match name is NULL get the minor number entry.
0072    */
0073   if (match == NULL) {
0074     if (*match_minor < Console_Port_Count)
0075       return Console_Port_Tbl[*match_minor];
0076     return NULL;
0077   }
0078 
0079   for (minor=0; minor < Console_Port_Count ; minor++) {
0080     console_tbl  *cptr = Console_Port_Tbl[minor];
0081 
0082     /*
0083      * Console table entries include /dev/ prefix, device names passed
0084      * in on command line do not.
0085      */
0086     if ( !strncmp( cptr->sDeviceName, match, length ) ) {
0087       *match_minor = minor;
0088       return cptr;
0089     }
0090   }
0091 
0092   return NULL;
0093 }
0094 
0095 /*
0096  *  console_initialize_data
0097  *
0098  *  This method is used to initialize the table of pointers to the
0099  *  serial port configuration structure entries.
0100  */
0101 void console_initialize_data(void)
0102 {
0103   int i;
0104 
0105   if ( Console_Port_Tbl )
0106     return;
0107 
0108   /*
0109    * Allocate memory for the table of device pointers.
0110    */
0111   Console_Port_Count = Console_Configuration_Count;
0112   Console_Port_Tbl   = malloc( Console_Port_Count * sizeof( console_tbl * ) );
0113   if (Console_Port_Tbl == NULL)
0114     bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_0 );
0115 
0116   /*
0117    * Allocate memory for the table of device specific data pointers.
0118    */
0119   Console_Port_Data  = calloc( Console_Port_Count, sizeof( console_data ) );
0120   if ( Console_Port_Data == NULL ) {
0121     bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_3 );
0122   }
0123 
0124   /*
0125    * Fill in the Console Table
0126    */
0127   for (i=0 ; i < Console_Port_Count ; i++) {
0128     Console_Port_Tbl[i] = &Console_Configuration_Ports[i];
0129   }
0130 }
0131 
0132 /*
0133  *  console_register_devices
0134  *
0135  *  This method is used to add dynamically discovered devices to the
0136  *  set of serial ports supported.
0137  */
0138 void console_register_devices(
0139   console_tbl *new_ports,
0140   size_t       number_of_ports
0141 )
0142 {
0143   int  old_number_of_ports;
0144   int  i;
0145 
0146   /*
0147    * Initialize the console data elements
0148    */
0149   console_initialize_data();
0150 
0151   /*
0152    *  console_initialize() has been invoked so it is now too late to
0153    *  register devices.
0154    */
0155   if ( console_initialized ) {
0156     bsp_fatal( BSP_FATAL_CONSOLE_MULTI_INIT );
0157   }
0158 
0159   /*
0160    *  Allocate memory for the console port extension
0161    */
0162   old_number_of_ports = Console_Port_Count;
0163   Console_Port_Count += number_of_ports;
0164   Console_Port_Tbl = realloc(
0165     Console_Port_Tbl,
0166     Console_Port_Count * sizeof(console_tbl *)
0167   );
0168   if ( Console_Port_Tbl == NULL ) {
0169     bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_1 );
0170   }
0171 
0172   /*
0173    * Since we can only add devices before console_initialize(),
0174    * the data area will contain no information and must be zero
0175    * before it is used. So extend the area and zero it out.
0176    */
0177   Console_Port_Data = realloc(
0178     Console_Port_Data,
0179     Console_Port_Count * sizeof(console_data)
0180   );
0181   if ( Console_Port_Data == NULL ) {
0182     bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_2 );
0183   }
0184   memset(Console_Port_Data, '\0', Console_Port_Count * sizeof(console_data));
0185 
0186   /*
0187    *  Now add the new devices at the end.
0188    */
0189   for (i=0 ; i < number_of_ports ; i++) {
0190     Console_Port_Tbl[old_number_of_ports + i]  = &new_ports[i];
0191   }
0192 }
0193 
0194 /*
0195  *  console_open
0196  *
0197  *  open a port as a termios console.
0198  */
0199 rtems_device_driver console_open(
0200   rtems_device_major_number major,
0201   rtems_device_minor_number minor,
0202   void                    * arg
0203 )
0204 {
0205   rtems_status_code              status;
0206   rtems_libio_open_close_args_t *args = arg;
0207   rtems_libio_ioctl_args_t       IoctlArgs;
0208   struct termios                 Termios;
0209   rtems_termios_callbacks        Callbacks;
0210   console_tbl                   *cptr;
0211   struct rtems_termios_tty      *current_tty;
0212 
0213   /*
0214    * Verify the port number is valid.
0215    */
0216   if ( minor > Console_Port_Count ) {
0217     return RTEMS_INVALID_NUMBER;
0218   }
0219 
0220   /*
0221    * Open the port as a termios console driver.
0222    */
0223 
0224   cptr = Console_Port_Tbl[minor];
0225   Callbacks.firstOpen            = cptr->pDeviceFns->deviceFirstOpen;
0226   Callbacks.lastClose            = cptr->pDeviceFns->deviceLastClose;
0227   Callbacks.pollRead             = cptr->pDeviceFns->deviceRead;
0228   Callbacks.write                = cptr->pDeviceFns->deviceWrite;
0229   Callbacks.setAttributes        = cptr->pDeviceFns->deviceSetAttributes;
0230   if (cptr->pDeviceFlow != NULL) {
0231     Callbacks.stopRemoteTx  = cptr->pDeviceFlow->deviceStopRemoteTx;
0232     Callbacks.startRemoteTx = cptr->pDeviceFlow->deviceStartRemoteTx;
0233   } else {
0234     Callbacks.stopRemoteTx  = NULL;
0235     Callbacks.startRemoteTx = NULL;
0236   }
0237   if (cptr->pDeviceFns->deviceOutputUsesInterrupts) {
0238     Callbacks.outputUsesInterrupts = TERMIOS_IRQ_DRIVEN;
0239   } else {
0240     Callbacks.outputUsesInterrupts = TERMIOS_POLLED;
0241   }
0242 
0243   /* XXX what about
0244    *        Console_Port_Tbl[minor].ulMargin,
0245    *        Console_Port_Tbl[minor].ulHysteresis);
0246    */
0247 
0248   status = rtems_termios_open( major, minor, arg, &Callbacks );
0249   Console_Port_Data[minor].termios_data = args->iop->data1;
0250 
0251   /* Get tty pointur from the Console_Port_Data */
0252   current_tty = Console_Port_Data[minor].termios_data;
0253 
0254   if ( (current_tty->refcount == 1) ) {
0255 
0256     /*
0257      *  If this BSP has a preferred default rate, then use that.
0258      */
0259     #if defined(BSP_DEFAULT_BAUD_RATE)
0260       rtems_termios_set_initial_baud( current_tty, BSP_DEFAULT_BAUD_RATE );
0261     #endif
0262 
0263     /*
0264      * If it's the first open, modified, if need, the port parameters
0265      */
0266     if ( minor != Console_Port_Minor ) {
0267       /*
0268        * If this is not the console we do not want ECHO and so forth
0269        */
0270       IoctlArgs.iop     = args->iop;
0271       IoctlArgs.command = TIOCGETA;
0272       IoctlArgs.buffer  = &Termios;
0273       rtems_termios_ioctl( &IoctlArgs );
0274 
0275       Termios.c_lflag   = ICANON;
0276       IoctlArgs.command = TIOCSETA;
0277       rtems_termios_ioctl( &IoctlArgs );
0278     }
0279   }
0280 
0281   if (rtems_libio_iop_is_readable(args->iop) &&
0282       cptr->pDeviceFlow &&
0283       cptr->pDeviceFlow->deviceStartRemoteTx) {
0284     cptr->pDeviceFlow->deviceStartRemoteTx(minor);
0285   }
0286 
0287   return status;
0288 }
0289 
0290 /*
0291  *  console_close
0292  *
0293  *  This routine closes a port that has been opened as console.
0294  */
0295 rtems_device_driver console_close(
0296   rtems_device_major_number major,
0297   rtems_device_minor_number minor,
0298   void                    * arg
0299 )
0300 {
0301   rtems_libio_open_close_args_t *args = arg;
0302   struct rtems_termios_tty      *current_tty;
0303   console_tbl                   *cptr;
0304 
0305   cptr  = Console_Port_Tbl[minor];
0306 
0307   /* Get tty pointer from the Console_Port_Data */
0308   current_tty = Console_Port_Data[minor].termios_data;
0309 
0310   /* Get the tty refcount to determine if we need to do deviceStopRemoteTx.
0311    * Stop only if it's the last one opened.
0312    */
0313   if ( (current_tty->refcount == 1) ) {
0314     if (rtems_libio_iop_is_readable(args->iop) &&
0315           cptr->pDeviceFlow &&
0316           cptr->pDeviceFlow->deviceStopRemoteTx) {
0317       cptr->pDeviceFlow->deviceStopRemoteTx(minor);
0318     }
0319   }
0320 
0321   return rtems_termios_close (arg);
0322 }
0323 
0324 /*
0325  *  console_initialize
0326  *
0327  *  Routine called to initialize the console device driver.
0328  */
0329 rtems_device_driver console_initialize(
0330   rtems_device_major_number  major,
0331   rtems_device_minor_number  minor_arg,
0332   void                      *arg
0333 )
0334 {
0335   rtems_status_code          status;
0336   rtems_device_minor_number  minor;
0337   console_tbl               *port;
0338 
0339   /*
0340    * If we have no devices which were registered earlier then we
0341    * must still initialize pointers for Console_Port_Tbl and
0342    * Console_Port_Data.
0343    */
0344   console_initialize_data();
0345 
0346   /*
0347    *  console_initialize has been invoked so it is now too late to
0348    *  register devices.
0349    */
0350   console_initialized = true;
0351 
0352   /*
0353    *  Initialize the termio interface, our table of pointers to device
0354    *  information structures, and determine if the user has explicitly
0355    *  specified which device is to be used for the console.
0356    */
0357   rtems_termios_initialize();
0358   bsp_console_select();
0359 
0360   /*
0361    *  Iterate over all of the console devices we know about
0362    *  and initialize them.
0363    */
0364   for (minor=0 ; minor < Console_Port_Count ; minor++) {
0365     /*
0366      *  First perform the configuration dependent probe, then the
0367      *  device dependent probe
0368      */
0369     port = Console_Port_Tbl[minor];
0370 
0371     if ( (!port->deviceProbe || port->deviceProbe(minor)) &&
0372          port->pDeviceFns->deviceProbe(minor)) {
0373 
0374       if (port->sDeviceName != NULL) {
0375         status = rtems_io_register_name( port->sDeviceName, major, minor );
0376         if (status != RTEMS_SUCCESSFUL) {
0377           bsp_fatal( BSP_FATAL_CONSOLE_REGISTER_DEV_0 );
0378         }
0379       }
0380 
0381       if (minor == Console_Port_Minor) {
0382         status = rtems_io_register_name( CONSOLE_DEVICE_NAME, major, minor );
0383         if (status != RTEMS_SUCCESSFUL) {
0384           bsp_fatal( BSP_FATAL_CONSOLE_REGISTER_DEV_1 );
0385         }
0386       }
0387 
0388       /*
0389        * Initialize the hardware device.
0390        */
0391       port->pDeviceFns->deviceInitialize(minor);
0392 
0393     }
0394   }
0395 
0396   return RTEMS_SUCCESSFUL;
0397 }
0398 
0399 /*
0400  *  console_read
0401  *
0402  *  This routine uses the termios driver to read a character.
0403  */
0404 rtems_device_driver console_read(
0405   rtems_device_major_number major,
0406   rtems_device_minor_number minor,
0407   void                    * arg
0408 )
0409 {
0410   return rtems_termios_read (arg);
0411 }
0412 
0413 /*
0414  *  console_write
0415  *
0416  *  this routine uses the termios driver to write a character.
0417  */
0418 rtems_device_driver console_write(
0419   rtems_device_major_number major,
0420   rtems_device_minor_number minor,
0421   void                    * arg
0422 )
0423 {
0424   return rtems_termios_write (arg);
0425 }