source: trunk/hal/tsar_mips32/drivers/soclib_tty.c @ 606

Last change on this file since 606 was 570, checked in by alain, 6 years ago

Introduction of the soclib_mty driver for the TSAR-LETI architecture.

File size: 19.9 KB
RevLine 
[75]1/*
2 * soclib_tty.c - soclib tty driver implementation.
3 *
[451]4 * Author  Alain Greiner (2016,2017,2018)
[75]5 *
6 * Copyright (c)  UPMC Sorbonne Universites
7 *
[570]8 * This file is part of ALMOS-MKH.
[75]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 *
[570]14 * ALMOS-MKH is distributed in the hope that it will be useful, but
[75]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
[570]20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
[75]21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[451]24
25#include <hal_kernel_types.h>
[75]26#include <dev_txt.h>
27#include <chdev.h>
28#include <soclib_tty.h>
29#include <thread.h>
[407]30#include <printk.h>
[75]31#include <hal_special.h>
32
[438]33#if (DEBUG_SYS_READ & 1)
[435]34extern uint32_t  enter_tty_cmd_read;
35extern uint32_t  exit_tty_cmd_read;
[407]36
[435]37extern uint32_t  enter_tty_isr_read;
38extern uint32_t  exit_tty_isr_read;
[407]39#endif
40
[438]41#if (DEBUG_SYS_WRITE & 1)
[435]42extern uint32_t  enter_tty_cmd_write;
43extern uint32_t  exit_tty_cmd_write;
44
45extern uint32_t  enter_tty_isr_write;
46extern uint32_t  exit_tty_isr_write;
47#endif
48
[436]49////////////////////////////////////////////////////////////////////////////////////
50// These global variables implement the TTY_RX  FIFOs (one per channel)
51////////////////////////////////////////////////////////////////////////////////////
[570]52// Implementation note:
53// We allocate - in each cluster - two arrays of FIFOs containing as many entries
54// as the total number of TXT channels, but all entries are not used in all
55// clusters: for a given cluster K, a given entry corresponding to a given channel
56// and a given direction is only used if the associated chdev is in cluster K.
57// With this policy, the driver can ignore the actual placement of chdevs.
58////////////////////////////////////////////////////////////////////////////////////
[436]59
60__attribute__((section(".kdata")))
61tty_fifo_t  tty_rx_fifo[CONFIG_MAX_TXT_CHANNELS];
62
63__attribute__((section(".kdata")))
64tty_fifo_t  tty_tx_fifo[CONFIG_MAX_TXT_CHANNELS];
65
[75]66///////////////////////////////////////
67void soclib_tty_init( chdev_t * chdev )
68{
[407]69    xptr_t reg_xp;
70
[436]71    // initialise function pointers in chdev
[77]72    chdev->cmd = &soclib_tty_cmd;
73    chdev->isr = &soclib_tty_isr;
[407]74    chdev->aux = &soclib_tty_aux;
[77]75
[407]76    // get TTY channel and extended pointer on TTY peripheral base address
77    xptr_t   tty_xp  = chdev->base;
78    uint32_t channel = chdev->channel;
[436]79    bool_t   is_rx   = chdev->is_rx;
[75]80
81    // get SOCLIB_TTY device cluster and local pointer
82    cxy_t      tty_cxy = GET_CXY( tty_xp );
[435]83    uint32_t * tty_ptr = GET_PTR( tty_xp );
[75]84
[435]85    // set TTY_RX_IRQ_ENABLE
[407]86    reg_xp = XPTR( tty_cxy , tty_ptr + (channel * TTY_SPAN) + TTY_RX_IRQ_ENABLE );
[570]87    hal_remote_s32( reg_xp , 1 );
[407]88
89    // reset TTY_TX_IRQ_ENABLE
90    reg_xp = XPTR( tty_cxy , tty_ptr + (channel * TTY_SPAN) + TTY_TX_IRQ_ENABLE );
[570]91    hal_remote_s32( reg_xp , 0 );
[75]92
[436]93    // reset relevant FIFO
94    if( is_rx )
95    {
96        tty_rx_fifo[channel].sts = 0;
97        tty_rx_fifo[channel].ptr = 0;
98        tty_rx_fifo[channel].ptw = 0;
99    }
100    else
101    {
102        tty_tx_fifo[channel].sts = 0;
103        tty_tx_fifo[channel].ptr = 0;
104        tty_tx_fifo[channel].ptw = 0;
105    }
106}  // end soclib_tty_init()
107
[75]108//////////////////////////////////////////////////////////////
109void __attribute__ ((noinline)) soclib_tty_cmd( xptr_t th_xp )
110{
[436]111    tty_fifo_t * fifo;     // TTY_RX or TTY_TX FIFO
112    char         byte;     // byte value
113    uint32_t     done;     // number of bytes moved
[407]114
[436]115    // get client thread cluster and local pointer
116    cxy_t      th_cxy = GET_CXY( th_xp );
117    thread_t * th_ptr = GET_PTR( th_xp );
118
119    // get command arguments
[570]120    uint32_t type     = hal_remote_l32 ( XPTR( th_cxy , &th_ptr->txt_cmd.type   ) );
121    xptr_t   buf_xp   = hal_remote_l64( XPTR( th_cxy , &th_ptr->txt_cmd.buf_xp ) );
122    uint32_t count    = hal_remote_l32 ( XPTR( th_cxy , &th_ptr->txt_cmd.count  ) );
[436]123    xptr_t   error_xp = XPTR( th_cxy , &th_ptr->txt_cmd.error );
124
[438]125#if (DEBUG_SYS_READ & 1)
[435]126if( type == TXT_READ) enter_tty_cmd_read = (uint32_t)hal_get_cycles();
[407]127#endif
128
[438]129#if (DEBUG_SYS_WRITE & 1)
[435]130if( type == TXT_WRITE) enter_tty_cmd_write = (uint32_t)hal_get_cycles();
[432]131#endif
[407]132
[440]133    // get TXT device cluster and pointers
[570]134    xptr_t     dev_xp = (xptr_t)hal_remote_l64( XPTR( th_cxy , &th_ptr->txt_cmd.dev_xp ) );
[440]135    cxy_t      dev_cxy = GET_CXY( dev_xp );
136    chdev_t  * dev_ptr = GET_PTR( dev_xp );
[436]137
[440]138    // get cluster and pointers for SOCLIB_TTY peripheral base segment
[570]139    xptr_t     tty_xp = (xptr_t)hal_remote_l64( XPTR( dev_cxy , &dev_ptr->base ) );
[436]140    cxy_t      tty_cxy = GET_CXY( tty_xp );
141    uint32_t * tty_ptr = GET_PTR( tty_xp );
142
143    // get TTY channel index and channel base address
[570]144    uint32_t   channel = hal_remote_l32( XPTR( dev_cxy , &dev_ptr->channel ) );
[436]145    uint32_t * base    = tty_ptr + TTY_SPAN * channel;
146
147    ///////////////////////
148    if( type == TXT_WRITE )         // write bytes to TTY_TX FIFO
[435]149    {
[436]150        fifo = &tty_tx_fifo[channel];
[75]151
[436]152        done = 0;
[75]153
[436]154        while( done < count )
155        {
156            if( fifo->sts < TTY_FIFO_DEPTH )   // put one byte to FIFO if TX_FIFO not full
157            {
158                // get one byte from command buffer
159                byte = hal_remote_lb( buf_xp + done );
[75]160
[451]161#if DEBUG_HAL_TXT_TX
162uint32_t tx_cycle = (uint32_t)hal_get_cycles();
163if( DEBUG_HAL_TXT_TX < tx_cycle )
164printk("\n[DBG] %s : thread %x put character <%c> to TXT%d_TX fifo / cycle %d\n",
165__FUNCTION__, CURRENT_THREAD, byte, channel, tx_cycle );
166#endif
[436]167                // write byte to FIFO
168                fifo->data[fifo->ptw] = byte;
[75]169
[436]170                // prevent race
171                hal_fence();
[75]172
[436]173                // update FIFO state
174                fifo->ptw = (fifo->ptw + 1) % TTY_FIFO_DEPTH;
175                hal_atomic_add( &fifo->sts , 1 );
[75]176
[436]177                // udate number of bytes moved
178                done++;
[75]179
[436]180                // enable TX_IRQ
[570]181                hal_remote_s32( XPTR( tty_cxy , base + TTY_TX_IRQ_ENABLE ) , 1 );
[436]182            }
183            else                                // block & deschedule if TX_FIFO full
184            {
185                // block on ISR
186                thread_block( XPTR( local_cxy , CURRENT_THREAD ) , THREAD_BLOCKED_ISR );
187
188                // deschedule
189                sched_yield( "TTY_TX_FIFO full" ); 
190            }
191        }
192
193        // set error status in command and return
[570]194        hal_remote_s32( error_xp , 0 );
[435]195    }
[436]196    ///////////////////////////
197    else if( type == TXT_READ )       // read bytes from TTY_RX FIFO   
[435]198    {
[436]199        fifo = &tty_rx_fifo[channel];
[75]200
[436]201        done = 0;
202
203        while( done < count )
204        {
205            if( fifo->sts > 0 )               // get byte from FIFO if not empty
206            {
207                // get one byte from FIFO
208                char byte = fifo->data[fifo->ptr];
209
[451]210#if DEBUG_HAL_TXT_RX
211uint32_t rx_cycle = (uint32_t)hal_get_cycles();
212if( DEBUG_HAL_TXT_RX < rx_cycle )
213printk("\n[DBG] %s : thread %x get character <%c> from TXT%d_RX fifo / cycle %d\n",
214__FUNCTION__, CURRENT_THREAD, byte, channel, rx_cycle );
215#endif
[436]216                // update FIFO state
217                fifo->ptr = (fifo->ptr + 1) % TTY_FIFO_DEPTH;
218                hal_atomic_add( &fifo->sts , -1 );
219
220                // set byte to command buffer
221                hal_remote_sb( buf_xp + done , byte );
222
223                // udate number of bytes
224                done++;
225            }
226            else                             //  deschedule if FIFO empty
227            {
228                // block on ISR
229                thread_block( XPTR( local_cxy , CURRENT_THREAD ) , THREAD_BLOCKED_ISR );
230   
231                // deschedule
[446]232                sched_yield( "TTY_RX_FIFO empty" );
[436]233            }
234        }  // end while
235
236        // set error status in command
[570]237        hal_remote_s32( error_xp , 0 );
[435]238    }
239    else
240    {
[492]241        assert( false , "illegal TXT command\n" );
[435]242    }
243
[438]244#if (DEBUG_SYS_READ & 1)
[435]245if( type == TXT_READ ) exit_tty_cmd_read = (uint32_t)hal_get_cycles();
[407]246#endif
247
[438]248#if (DEBUG_SYS_WRITE & 1)
[435]249if( type == TXT_WRITE ) exit_tty_cmd_write = (uint32_t)hal_get_cycles();
250#endif
251
[407]252}  // end soclib_tty_cmd()
253
[75]254/////////////////////////////////////////////////////////////////
255void __attribute__ ((noinline)) soclib_tty_isr( chdev_t * chdev )
256{
[446]257    thread_t   * server;            // pointer on TXT chdev server thread
258    lid_t        server_lid;        // local index of core running the server thread
259    uint32_t     channel;           // TXT chdev channel
260    bool_t       is_rx;             // TXT chdev direction
261    char         byte;              // byte value
262    xptr_t       owner_xp;          // extended pointer on TXT owner process
263    cxy_t        owner_cxy;         // TXT owner process cluster
264    process_t  * owner_ptr;         // local pointer on TXT owner process
265    pid_t        owner_pid;         // TXT owner process identifier
266    tty_fifo_t * fifo;              // pointer on TTY_TX or TTY_RX FIFO
267    cxy_t        tty_cxy;           // soclib_tty cluster
268    uint32_t   * tty_ptr;           // soclib_tty segment base address
269    uint32_t   * base;              // soclib_tty channel base address
270    xptr_t       status_xp;         // extended pointer on TTY_STATUS register
271    xptr_t       write_xp;          // extended pointer on TTY_WRITE register
272    xptr_t       read_xp;           // extended pointer on TTY_READ register
273    xptr_t       parent_xp;         // extended pointer on parent process
274    cxy_t        parent_cxy;        // parent process cluster
275    process_t  * parent_ptr;        // local pointer on parent process
276    thread_t   * parent_main_ptr;   // extended pointer on parent process main thread
277    xptr_t       parent_main_xp;    // local pointer on parent process main thread
[75]278
[457]279    // get TXT chdev channel, direction, server thread, and server core
[436]280    channel    = chdev->channel;
281    is_rx      = chdev->is_rx;
282    server     = chdev->server;
283    server_lid = server->core->lid;
284
[438]285#if (DEBUG_SYS_READ & 1)
[436]286if( is_rx ) enter_tty_isr_read = (uint32_t)hal_get_cycles();
[407]287#endif
288
[438]289#if (DEBUG_SYS_WRITE & 1)
[436]290if( is_rx == 0 ) enter_tty_isr_write = (uint32_t)hal_get_cycles();
[435]291#endif
292
[438]293#if DEBUG_HAL_TXT_RX
[446]294uint32_t rx_cycle = (uint32_t)hal_get_cycles();
[432]295#endif
296
[438]297#if DEBUG_HAL_TXT_TX
[446]298uint32_t tx_cycle = (uint32_t)hal_get_cycles();
[436]299#endif
[75]300
[424]301    // get SOCLIB_TTY peripheral cluster and local pointer
[436]302    tty_cxy = GET_CXY( chdev->base );
303    tty_ptr = GET_PTR( chdev->base );
[424]304
305    // get channel base address
[436]306    base    = tty_ptr + TTY_SPAN * channel;
[424]307
308    // get extended pointer on TTY registers
309    status_xp = XPTR( tty_cxy , base + TTY_STATUS );
310    write_xp  = XPTR( tty_cxy , base + TTY_WRITE );
311    read_xp   = XPTR( tty_cxy , base + TTY_READ );
312
[436]313    /////////////////////////// handle RX //////////////////////
314    if( is_rx )
[424]315    {
[436]316        fifo = &tty_rx_fifo[channel];
[424]317
[436]318        // try to move bytes until TTY_READ register empty
[570]319        while( hal_remote_l32( status_xp ) & TTY_STATUS_RX_FULL )   
[435]320        {
[436]321            // get one byte from TTY_READ register & acknowledge RX_IRQ
322            byte = (char)hal_remote_lb( read_xp );
[424]323
[446]324            // filter special character ^Z  => block TXT owner process
[436]325            if( byte == 0x1A ) 
326            {
[446]327
328#if DEBUG_HAL_TXT_RX
329if( DEBUG_HAL_TXT_RX < rx_cycle )
330printk("\n[DBG] %s : read ^Z character from TXT%d\n", __FUNCTION__, channel );
331#endif
[436]332                // get pointers on TXT owner process in owner cluster
333                owner_xp  = process_txt_get_owner( channel );
334               
335                // check process exist
[492]336                assert( (owner_xp != XPTR_NULL) ,
[436]337                "TXT owner process not found\n" );
[435]338
[446]339                // get relevant infos on TXT owner process
[436]340                owner_cxy = GET_CXY( owner_xp );
341                owner_ptr = GET_PTR( owner_xp );
[570]342                owner_pid = hal_remote_l32( XPTR( owner_cxy , &owner_ptr->pid ) );
[424]343
[446]344                // block TXT owner process only if it is not the INIT process
345                if( owner_pid != 1 )
[436]346                {
[446]347                    // get parent process descriptor pointers
[570]348                    parent_xp  = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
[446]349                    parent_cxy = GET_CXY( parent_xp );
350                    parent_ptr = GET_PTR( parent_xp );
351
352                    // get pointers on the parent process main thread
353                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
354                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
355
356                    // transfer TXT ownership
357                    process_txt_transfer_ownership( owner_xp );
358
359                    // block all threads in all clusters, but the main thread
[436]360                    process_sigaction( owner_pid , BLOCK_ALL_THREADS );
[424]361
[446]362                    // block the main thread
363                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
364                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
365
[436]366                    // atomically update owner process termination state
367                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
368                                          PROCESS_TERM_STOP );
[446]369
[570]370                    // unblock the parent process main thread
[446]371                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
372
[436]373                    return;
374                }
375            }
376
[446]377            // filter special character ^C  => kill TXT owner process
[436]378            if( byte == 0x03 )
379            {
[446]380
381#if DEBUG_HAL_TXT_RX
382if( DEBUG_HAL_TXT_RX < rx_cycle )
383printk("\n[DBG] %s : read ^C character from TXT%d\n", __FUNCTION__, channel );
384#endif
[440]385                // get pointer on TXT owner process in owner cluster
[436]386                owner_xp  = process_txt_get_owner( channel );
387
388                // check process exist
[492]389                assert( (owner_xp != XPTR_NULL) ,
[436]390                "TXT owner process not found\n" );
391
392                // get relevant infos on TXT owner process
393                owner_cxy = GET_CXY( owner_xp );
394                owner_ptr = GET_PTR( owner_xp );
[570]395                owner_pid = hal_remote_l32( XPTR( owner_cxy , &owner_ptr->pid ) );
[436]396
[446]397                // kill TXT owner process only if it is not the INIT process
[436]398                if( owner_pid != 1 )
399                {
[446]400                    // get parent process descriptor pointers
[570]401                    parent_xp  = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
[446]402                    parent_cxy = GET_CXY( parent_xp );
403                    parent_ptr = GET_PTR( parent_xp );
404
405                    // get pointers on the parent process main thread
406                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
407                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
408
[436]409                    // remove process from TXT list
410                    process_txt_detach( owner_xp );
411
[440]412                    // mark for delete all thread in all clusters, but the main
[436]413                    process_sigaction( owner_pid , DELETE_ALL_THREADS );
[435]414               
[446]415                    // block main thread
[436]416                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
417                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
[435]418
[436]419                    // atomically update owner process termination state
420                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
421                                          PROCESS_TERM_KILL );
[446]422
[570]423                    // unblock the parent process main thread
[446]424                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
425
[436]426                    return;
427                }
428            }
[424]429
[436]430            // write byte in TTY_RX FIFO if not full / discard byte if full
431            if ( fifo->sts < TTY_FIFO_DEPTH )
432            {
[446]433
434#if DEBUG_HAL_TXT_RX
435if( DEBUG_HAL_TXT_RX < rx_cycle )
[451]436printk("\n[DBG] %s : put character <%c> to TXT%d_RX fifo\n",
437__FUNCTION__, byte, channel );
[446]438#endif
[436]439                // store byte into FIFO
440                fifo->data[fifo->ptw] = (char)byte; 
441
442                // avoid race
443                hal_fence();
444
445                // update RX_FIFO state
446                fifo->ptw = (fifo->ptw + 1) % TTY_FIFO_DEPTH;
447                hal_atomic_add( &fifo->sts , 1 );
448
449                // unblock TXT_RX server thread
450                thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
451
[457]452                // send IPI to core running server thread if required
453                if( server_lid != CURRENT_THREAD->core->lid )
454                {
455                    dev_pic_send_ipi( local_cxy , server_lid );
456                }
[436]457            }
458            else
459            {
460                printk("\n[WARNING] %s : TTY_RX_FIFO[%d] full => discard character <%x>\n",
461                __FUNCTION__, channel, (uint32_t)byte );
462            }
463        }  // end while TTY_READ register full
464
465    }  // end RX
466
467    ///////////////////////  handle TX  /////////////////////////////
468    else
[424]469    {
[436]470        fifo = &tty_tx_fifo[channel];
471
472        // try to move bytes until TX_FIFO empty
473        while( fifo->sts > 0 )
[424]474        {
[446]475            // write one byte to TTY_WRITE register if empty / exit loop if full
[570]476            if( (hal_remote_l32( status_xp ) & TTY_STATUS_TX_FULL) == 0 ) 
[424]477            {
[436]478                // get one byte from TX_FIFO
479                byte = fifo->data[fifo->ptr];
[424]480
[446]481#if DEBUG_HAL_TXT_TX
482if( DEBUG_HAL_TXT_TX < tx_cycle )
[451]483printk("\n[DBG] %s : get character <%c> from TXT%d_TX fifo\n",
484__FUNCTION__, byte, channel );
[446]485#endif
[436]486                // update TX_FIFO state
487                fifo->ptr = (fifo->ptr + 1) % TTY_FIFO_DEPTH;
488                hal_atomic_add( &fifo->sts , -1 );
489
490                // write byte to TTY_WRITE register & acknowledge TX_IRQ
[424]491                hal_remote_sb( write_xp , byte );
492            }
493        }
494
[435]495        // disable TX_IRQ
[570]496        hal_remote_s32( XPTR( tty_cxy , base + TTY_TX_IRQ_ENABLE ) , 0 );
[424]497
[436]498        // unblock TXT_TX server thread
499        thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
[424]500
[457]501        // send IPI to core running server thread if required
502        if( server_lid != CURRENT_THREAD->core->lid )
503        {
504            dev_pic_send_ipi( local_cxy , server_lid );
505        }
[446]506
[436]507    }  // end TX
508
[435]509    hal_fence();
[424]510
[438]511#if (DEBUG_SYS_READ & 1)
[436]512if( is_rx ) exit_tty_isr_read = (uint32_t)hal_get_cycles();
[424]513#endif
514
[438]515#if (DEBUG_SYS_WRITE & 1)
[436]516if( is_rx == 0 ) exit_tty_isr_write = (uint32_t)hal_get_cycles();
[435]517#endif
518
[424]519}  // end soclib_tty_isr()
520
[436]521/////////////////////////////////////////////////////////////
522void __attribute__ ((noinline)) soclib_tty_aux( void * args )
523{
524    uint32_t   status;
525    bool_t     empty;
526    uint32_t   i;
527
[570]528    xptr_t       dev_xp = ((txt_sync_args_t *)args)->dev_xp;
529    const char * buffer = ((txt_sync_args_t *)args)->buffer;
530    uint32_t     count  = ((txt_sync_args_t *)args)->count;
[436]531   
[570]532    // get chdev cluster and local pointer
[436]533    cxy_t     dev_cxy = GET_CXY( dev_xp );
[570]534    chdev_t * dev_ptr = GET_PTR( dev_xp );
[436]535
536    // get extended pointer on TTY channel base address
[570]537    xptr_t tty_xp = (xptr_t)hal_remote_l64( XPTR( dev_cxy , &dev_ptr->base ) );
[436]538
539    // get TTY channel segment cluster and local pointer
540    cxy_t      tty_cxy = GET_CXY( tty_xp );
[570]541    uint32_t * tty_ptr = GET_PTR( tty_xp );
[436]542
543    // get extended pointers on TTY_WRITE & TTY_STATUS registers
544    xptr_t write_xp  = XPTR( tty_cxy , tty_ptr + TTY_WRITE );
545    xptr_t status_xp = XPTR( tty_cxy , tty_ptr + TTY_STATUS );
546
[570]547    // loop on characters
[436]548    for( i = 0 ; i < count ; i++ )
549    {
[570]550        // busy waiting policy on TTY_STATUS register
[436]551        do
552        {
553            // get TTY_STATUS
[570]554            status = hal_remote_l32( status_xp );
[436]555            empty  = ( (status & TTY_STATUS_TX_FULL) == 0 );
556
557            // transfer one byte if TX buffer empty
558            if ( empty )  hal_remote_sb( write_xp , buffer[i] );
559        }
560        while ( empty == false );
561    }
562}  // end soclib_tty_aux()
563
564
565
Note: See TracBrowser for help on using the repository browser.