Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2018, 2020 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include <rtems/console.h>
0033 #include <rtems/bspIo.h>
0034 #include <rtems/imfs.h>
0035 #include <rtems/thread.h>
0036 
0037 #include "consolesimple.h"
0038 
0039 #define CONSOLE_SIMPLE_TASK_BUFFER_SIZE 2048
0040 
0041 #define CONSOLE_SIMPLE_TASK_MAX_JUNK_SIZE 80
0042 
0043 typedef struct {
0044   IMFS_jnode_t Node;
0045   RTEMS_INTERRUPT_LOCK_MEMBER( buf_lock )
0046   rtems_mutex output_mutex;
0047   rtems_id task;
0048   size_t head;
0049   size_t tail;
0050   char buf[ CONSOLE_SIMPLE_TASK_BUFFER_SIZE ];
0051 } Console_simple_task_Control;
0052 
0053 static Console_simple_task_Control _Console_simple_task_Instance;
0054 
0055 static size_t _Console_simple_task_Capacity(
0056   const Console_simple_task_Control *cons
0057 )
0058 {
0059   return ( cons->tail - cons->head - 1 ) % CONSOLE_SIMPLE_TASK_BUFFER_SIZE;
0060 }
0061 
0062 static size_t _Console_simple_task_Available(
0063   const Console_simple_task_Control *cons
0064 )
0065 {
0066   return ( cons->head - cons->tail ) % CONSOLE_SIMPLE_TASK_BUFFER_SIZE;
0067 }
0068 
0069 static Console_simple_task_Control *_Console_simple_task_Iop_to_control(
0070   const rtems_libio_t *iop
0071 )
0072 {
0073   return (Console_simple_task_Control *) IMFS_iop_to_node( iop );
0074 }
0075 
0076 static ssize_t _Console_simple_task_Write(
0077   rtems_libio_t *iop,
0078   const void    *buffer,
0079   size_t         count
0080 )
0081 {
0082   Console_simple_task_Control *cons;
0083   const char                  *buf;
0084   size_t                       todo;
0085 
0086   cons = _Console_simple_task_Iop_to_control( iop );
0087   buf = buffer;
0088   todo = count;
0089 
0090   while ( todo > 0 ) {
0091     rtems_interrupt_lock_context lock_context;
0092     size_t                       junk;
0093     size_t                       head;
0094     size_t                       i;
0095 
0096     rtems_interrupt_lock_acquire( &cons->buf_lock, &lock_context );
0097 
0098     junk = _Console_simple_task_Capacity( cons );
0099 
0100     if ( junk > todo ) {
0101       junk = todo;
0102     }
0103 
0104     if ( junk > CONSOLE_SIMPLE_TASK_MAX_JUNK_SIZE ) {
0105       junk = CONSOLE_SIMPLE_TASK_MAX_JUNK_SIZE;
0106     }
0107 
0108     head = cons->head;
0109 
0110     for ( i = 0; i < junk; ++i ) {
0111       cons->buf[ head ] = *buf;
0112       head = ( head + 1 ) % CONSOLE_SIMPLE_TASK_BUFFER_SIZE;
0113       --todo;
0114       ++buf;
0115     }
0116 
0117     cons->head = head;
0118 
0119     rtems_interrupt_lock_release( &cons->buf_lock, &lock_context );
0120 
0121     if ( junk == 0 ) {
0122       break;
0123     }
0124   }
0125 
0126   rtems_event_system_send( cons->task, RTEMS_EVENT_SYSTEM_SERVER );
0127 
0128   return (ssize_t) ( count - todo );
0129 }
0130 
0131 static void _Console_simple_task_Put_chars( Console_simple_task_Control *cons )
0132 {
0133   rtems_interrupt_lock_context lock_context;
0134   size_t                       available;
0135   size_t                       tail;
0136   size_t                       i;
0137 
0138   rtems_mutex_lock( &cons->output_mutex );
0139 
0140   rtems_interrupt_lock_acquire( &cons->buf_lock, &lock_context );
0141 
0142   available = _Console_simple_task_Available( cons );
0143   tail = cons->tail;
0144 
0145   rtems_interrupt_lock_release( &cons->buf_lock, &lock_context );
0146 
0147   for ( i = 0; i < available; ++i) {
0148     rtems_putc( cons->buf[ tail ] );
0149     tail = ( tail + 1 ) % CONSOLE_SIMPLE_TASK_BUFFER_SIZE;
0150   }
0151 
0152   rtems_interrupt_lock_acquire( &cons->buf_lock, &lock_context );
0153 
0154   cons->tail = tail;
0155 
0156   rtems_interrupt_lock_release( &cons->buf_lock, &lock_context );
0157 
0158   rtems_mutex_unlock( &cons->output_mutex );
0159 }
0160 
0161 static int _Console_simple_task_Fsync( rtems_libio_t *iop )
0162 {
0163   Console_simple_task_Control *cons;
0164 
0165   cons = _Console_simple_task_Iop_to_control( iop );
0166   _Console_simple_task_Put_chars( cons );
0167 
0168   return 0;
0169 }
0170 
0171 static const rtems_filesystem_file_handlers_r _Console_simple_task_Handlers = {
0172   .open_h = rtems_filesystem_default_open,
0173   .close_h = rtems_filesystem_default_close,
0174   .read_h = _Console_simple_Read,
0175   .write_h = _Console_simple_task_Write,
0176   .ioctl_h = rtems_filesystem_default_ioctl,
0177   .lseek_h = rtems_filesystem_default_lseek,
0178   .fstat_h = IMFS_stat,
0179   .ftruncate_h = rtems_filesystem_default_ftruncate,
0180   .fsync_h = _Console_simple_task_Fsync,
0181   .fdatasync_h = _Console_simple_task_Fsync,
0182   .fcntl_h = rtems_filesystem_default_fcntl,
0183   .readv_h = rtems_filesystem_default_readv,
0184   .writev_h = rtems_filesystem_default_writev,
0185   .mmap_h = rtems_filesystem_default_mmap
0186 };
0187 
0188 static const IMFS_node_control
0189 _Console_simple_task_Node_control = IMFS_NODE_CONTROL_INITIALIZER(
0190   &_Console_simple_task_Handlers,
0191   IMFS_node_initialize_default,
0192   IMFS_do_nothing_destroy
0193 );
0194 
0195 static void _Console_simple_task_Task( rtems_task_argument arg )
0196 {
0197   Console_simple_task_Control *cons;
0198 
0199   cons = (Console_simple_task_Control *) arg;
0200 
0201   while ( true ) {
0202     rtems_event_set events;
0203 
0204     rtems_event_system_receive(
0205       RTEMS_EVENT_SYSTEM_SERVER,
0206       RTEMS_WAIT | RTEMS_EVENT_ALL,
0207       RTEMS_NO_TIMEOUT,
0208       &events
0209     );
0210 
0211     _Console_simple_task_Put_chars( cons );
0212   }
0213 }
0214 
0215 static const char _Console_simple_task_Name[] = "console";
0216 
0217 void _Console_simple_task_Initialize( void )
0218 {
0219   Console_simple_task_Control *cons;
0220   rtems_status_code status;
0221 
0222   cons = &_Console_simple_task_Instance;
0223 
0224   IMFS_node_preinitialize(
0225     &cons->Node,
0226     &_Console_simple_task_Node_control,
0227     _Console_simple_task_Name,
0228     sizeof( _Console_simple_task_Name ) - 1,
0229     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO
0230   );
0231 
0232   rtems_interrupt_lock_initialize( &cons->buf_lock, "Console" );
0233   rtems_mutex_init( &cons->output_mutex, "Console" );
0234 
0235   IMFS_add_node( "/dev", &cons->Node, NULL );
0236 
0237   status = rtems_task_create(
0238     rtems_build_name('C', 'O', 'N', 'S'),
0239     RTEMS_MAXIMUM_PRIORITY - 1,
0240     RTEMS_MINIMUM_STACK_SIZE,
0241     RTEMS_DEFAULT_ATTRIBUTES,
0242     RTEMS_DEFAULT_MODES,
0243     &cons->task
0244   );
0245   _Assert_Unused_variable_equals(status, RTEMS_SUCCESSFUL);
0246 
0247   status = rtems_task_start(
0248     cons->task,
0249     _Console_simple_task_Task,
0250     (rtems_task_argument) cons
0251   );
0252   _Assert_Unused_variable_equals(status, RTEMS_SUCCESSFUL);
0253 }