source: trunk/kernel/devices/dev_txt.c @ 547

Last change on this file since 547 was 540, checked in by nicolas.van.phan@…, 6 years ago

TTY MUX 5/5 : Multiplex TTY character receiving

The multiplexing for receving chars is done by redirecting
the IRQs (when a char is received) to the right chdev (so the right
server DEV thread). When the user types an uppercase letter,
it is treated as a special char used to change the active tty
by redirecting the IRQs to the chdev corresponding to the appropriate
channel.

Add some documentation and example in the code.

Add mfences calls in spinlock_unlock_busy fix a bug on letty physical
hardware.

File size: 8.8 KB
RevLine 
[1]1/*
2 * dev_txt.c - TXT (Text Terminal) generic device API implementation.
[49]3 *
[1]4 * Author  Alain Greiner    (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MK
9 *
10 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH.is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[457]24#include <hal_kernel_types.h>
[1]25#include <hal_special.h>
26#include <hal_remote.h>
[77]27#include <hal_drivers.h>
[1]28#include <thread.h>
[407]29#include <chdev.h>
[1]30#include <rpc.h>
31#include <printk.h>
32#include <dev_txt.h>
33
34/////////////////////////////////////////////////////////////////////////////////////////
35// Extern global variables
36/////////////////////////////////////////////////////////////////////////////////////////
37
[3]38extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
[1]39
[438]40#if (DEBUG_SYS_READ & 1)
[407]41extern uint32_t enter_txt_read;
42extern uint32_t exit_txt_read;
43#endif
44
[438]45#if (DEBUG_SYS_WRITE & 1)
[435]46extern uint32_t enter_txt_write;
47extern uint32_t exit_txt_write;
48#endif
49
50////////////////////////////////////////
[527]51const char * dev_txt_type_str( dev_txt_cmd_t type )
[435]52{
[527]53  switch (type) {
54    case (TXT_SYNC_WRITE): return "TXT_SYNC_WRITE";
55    case (TXT_READ):       return "TXT_READ";
56    case (TXT_WRITE):      return "TXT_WRITE";
57    default:               return "undefined";
58  }
[435]59}
60
[188]61//////////////////////////////////
62void dev_txt_init( chdev_t * txt )
[1]63{
[188]64    // For all TXT channels other than the TXT0 (kernel terminal),
65    // the PIC chdev must be initialized before the TXT chdev, because
66    // the TXT chdev initialization requires the routing of an external IRQ
[1]67
[188]68    xptr_t    pic_xp  = chdev_dir.pic;
69    uint32_t  channel = txt->channel;
70    uint32_t  impl    = txt->impl;
[407]71    bool_t    is_rx   = txt->is_rx;
[1]72
[492]73    assert( (pic_xp != XPTR_NULL) || (channel == 0) ,
[188]74            "PIC not initialised before TXT" );
75
[23]76    // set chdev name
[407]77    if( is_rx ) snprintf( txt->name , 16 , "txt%d_rx" , channel );
78    else        snprintf( txt->name , 16 , "txt%d_tx" , channel );
[23]79
[422]80    // set TXT chdev extension
81    txt->ext.txt.owner_xp = XPTR_NULL;
82    xlist_root_init( XPTR( local_cxy, &txt->ext.txt.root ) );
83    remote_spinlock_init( XPTR( local_cxy , &txt->ext.txt.lock ) );
84   
[245]85    // call driver init function
86    hal_drivers_txt_init(txt, impl);
[1]87
[422]88    // no server thread and no IRQ routing for TXT0
[540]89    // except for LETI where there MUST be IRQ routing
[422]90    // no server thread for IMPL_TXT_RS2 (multiplexed in software, not hardware)
[255]91    if( channel != 0 && impl != IMPL_TXT_RS2 )
[188]92    {
[407]93        // select a core to execute the server thread
[188]94        lid_t lid = cluster_select_local_core();
[3]95
[540]96        // The unique IRQ from cluster 00's MTTY must be bound to a RX chdev
97        // so that all IRQs are considered as RX IRQs and treated as such
98        // Indeed, IRQs are raised by the MTTY only on user keystroke, so IRQs must
99        // always be considered as RX IRQs.
100        if ( ( impl != IMPL_TXT_MTY ) || ( channel == 1 && is_rx == 1 ) ) 
101        {
[407]102        // bind IRQ to the selected core
[188]103        dev_pic_bind_irq( lid , txt );
[3]104
[407]105        // enable IRQ
[238]106        dev_pic_enable_irq( lid , XPTR( local_cxy , txt ) );
[540]107        }
[3]108
[188]109        // create server thread
110        thread_t * new_thread;
111        error_t    error;
[3]112
[188]113        error = thread_kernel_create( &new_thread,
114                                      THREAD_DEV,
115                                      &chdev_sequencial_server,
116                                      txt,
117                                      lid );
[3]118
[492]119        assert( (error == 0) , "cannot create server thread" );
[1]120
[188]121        // set "server" field in chdev descriptor
122        txt->server = new_thread;
[1]123
[408]124        // set "chdev" field in thread descriptor
125        new_thread->chdev = txt;
126
127        // unblock server thread
[188]128        thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL );
129    }
[49]130}
[1]131
132//////////////////////////////////////////////////////////////////////////////////
[3]133// This static function is called by dev_txt_read(), dev_txt_write() functions.
[1]134////////////////////////////////////i/////////////////////////////////////////////
135static error_t dev_txt_access( uint32_t   type,
136                               uint32_t   channel,
137                               char     * buffer,
138                               uint32_t   count )
139{
[407]140    xptr_t     dev_xp;
[1]141    thread_t * this = CURRENT_THREAD;
142
143    // check channel argument
[492]144    assert( (channel < CONFIG_MAX_TXT_CHANNELS) , "illegal channel index" );
[1]145
[3]146    // get extended pointer on remote TXT chdev descriptor
[407]147    if( type == TXT_WRITE )  dev_xp = chdev_dir.txt_tx[channel];
148    else                     dev_xp = chdev_dir.txt_rx[channel];
[1]149
[492]150    assert( (dev_xp != XPTR_NULL) , "undefined TXT chdev descriptor" );
[1]151
152    // register command in calling thread descriptor
[279]153    this->txt_cmd.dev_xp  = dev_xp;
154    this->txt_cmd.type    = type;
155    this->txt_cmd.buf_xp  = XPTR( local_cxy , buffer );
156    this->txt_cmd.count   = count;
[1]157
[3]158    // register client thread in waiting queue, activate server thread
159    // block client thread on THREAD_BLOCKED_IO and deschedule.
160    // it is re-activated by the ISR signaling IO operation completion.
[407]161    chdev_register_command( dev_xp );
[1]162
163    // return I/O operation status from calling thread descriptor
[279]164    return this->txt_cmd.error;
[49]165}
[1]166
167/////////////////////////////////////////
168error_t dev_txt_write( uint32_t   channel,
169                       char     * buffer,
170                       uint32_t   count )
171{
[436]172
[438]173#if (DEBUG_SYS_WRITE & 1)
[436]174enter_txt_write = hal_time_stamp();
175#endif
176
[438]177#if DEBUG_DEV_TXT_TX
[436]178uint32_t cycle = (uint32_t)hal_get_cycles();
[438]179if( DEBUG_DEV_TXT_TX < cycle )
[436]180printk("\n[DBG] %s : thread %x enters / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
181#endif
182
[539]183    // get extended pointer on TXT[0] chdev
184    xptr_t dev_xp = chdev_dir.txt_tx[0];
185
186    assert( (dev_xp != XPTR_NULL) , __FUNCTION__ ,
187    "undefined TXT0 chdev descriptor" );
188
189    // get TXTO chdev cluster and local pointer
190    cxy_t    dev_cxy  = GET_CXY( dev_xp );
191    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
192
193    // If we use MTTYs (vci_multi_tty), we perform only sync writes
194    if( dev_ptr->impl == IMPL_TXT_MTY )
195    {
196        // get driver command function
197        dev_aux_t * aux = (dev_aux_t *)hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->aux ) );
198
199        // build arguments structure
200        txt_sync_args_t  args;
201        args.dev_xp = dev_xp;
202        args.buffer = buffer;
203        args.count  = count;
204        args.channel = channel;
205
206        // call driver function
207        aux( &args );
208
209        return 0;
210    }
211
212    // Otherwise, we use vci_tty_tsar so we can use async writes
213    else
214    {
[435]215    return dev_txt_access( TXT_WRITE , channel , buffer , count );
[539]216    }
[436]217
[438]218#if DEBUG_DEV_TXT_TX
[436]219cycle = (uint32_t)hal_get_cycles();
[438]220if( DEBUG_DEV_TXT_TX < cycle )
[436]221printk("\n[DBG] %s : thread %x exit / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
222#endif
223
[438]224#if (DEBUG_SYS_WRITE & 1)
[436]225exit_txt_write = hal_time_stamp();
226#endif
227
[1]228}
[49]229
[1]230/////////////////////////////////////////
231error_t dev_txt_read( uint32_t   channel,
232                      char     * buffer )
233{
[436]234
[438]235#if (DEBUG_SYS_READ & 1)
[436]236enter_txt_read = hal_time_stamp();
237#endif
238
[438]239#if DEBUG_DEV_TXT_RX
[436]240uint32_t cycle = (uint32_t)hal_get_cycles();
[438]241if( DEBUG_DEV_TXT_RX < cycle )
[436]242printk("\n[DBG] %s : thread %x enters / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
243#endif
244
[435]245    return dev_txt_access( TXT_READ , channel , buffer , 1 );
[436]246
[438]247#if DEBUG_DEV_TXT_RX
[436]248cycle = (uint32_t)hal_get_cycles();
[438]249if( DEBUG_DEV_TXT_RX < cycle )
[436]250printk("\n[DBG] %s : thread %x exit / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
251#endif
252
[438]253#if (DEBUG_SYS_READ & 1)
[436]254exit_txt_read = hal_time_stamp();
255#endif
256
[1]257}
258
[407]259//////////////////////////////////////////////
260error_t dev_txt_sync_write( char     * buffer,
[3]261                            uint32_t   count )
[1]262{
[49]263    // get extended pointer on TXT[0] chdev
[407]264    xptr_t  dev_xp = chdev_dir.txt_tx[0];
[1]265
[492]266    assert( (dev_xp != XPTR_NULL) ,
[407]267    "undefined TXT0 chdev descriptor" );
[23]268
[407]269    // get TXTO chdev cluster and local pointer
270    cxy_t    dev_cxy  = GET_CXY( dev_xp );
271    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
[1]272
[49]273    // get driver command function
[407]274    dev_aux_t * aux = (dev_aux_t *)hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->aux ) );
[1]275
[407]276    // build arguments structure
[435]277    txt_sync_args_t  args;
[407]278    args.dev_xp = dev_xp;
279    args.buffer = buffer;
280    args.count  = count;
[539]281    args.channel = 0;
[407]282
[279]283    // call driver function
[407]284    aux( &args );
[1]285
[407]286    return 0;
[49]287}
[1]288
Note: See TracBrowser for help on using the repository browser.