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

Last change on this file since 482 was 457, checked in by alain, 6 years ago

This version modifies the exec syscall and fixes a large number of small bugs.
The version number has been updated (0.1)

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