source: trunk/hal/tsar_mips32/drivers/soclib_mtty.c @ 539

Last change on this file since 539 was 539, checked in by nicolas.van.phan@…, 3 years ago

TTY MUX 4 : Multiplex TTY character sending

Now, when a thread wants to write to a tty,
when the dev_txt_write() or dev_txt_sync_write() are called,
they all call soclib_mtty_aux() with a channel number.
The soclib_mtty_aux() function will write the string char by char,
with each char preceded by the channel number, so that the receiving end
knows to which tty a character is addressed to.

N.B. dev_txt_write() makes *synchronous* writes for the moment
because unlike the vci_tty_tsar, the vci_multi_tty doesn't raise
interrupt except when a new char is received, so we can't use the
interrupt mechanism for writes.

N.B. Now, the TTY DEV threads all write to the same register (WRITE),
but when a thread sends a 2-byte (tty dest. nb. + char), the two must be
send consecutively, without another thread sending a byte in between.
Consequently, a lock has been added to guarantee this atomicity.

File size: 21.8 KB
Line 
1/*
2 * soclib_mtty.c - soclib tty driver implementation.
3 *
4 * Author  Alain Greiner (2016,2017,2018)
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
24
25#include <hal_kernel_types.h>
26#include <dev_txt.h>
27#include <chdev.h>
28#include <soclib_mtty.h>
29#include <remote_spinlock.h>
30#include <thread.h>
31#include <printk.h>
32#include <hal_special.h>
33
34#if (DEBUG_SYS_READ & 1)
35extern uint32_t  enter_tty_cmd_read;
36extern uint32_t  exit_tty_cmd_read;
37
38extern uint32_t  enter_tty_isr_read;
39extern uint32_t  exit_tty_isr_read;
40#endif
41
42#if (DEBUG_SYS_WRITE & 1)
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
50extern   chdev_directory_t    chdev_dir;  // allocated in the kernel_init.c file.
51extern   spinlock_t           txt0_lock;  // Initialized in kernel_init.c
52////////////////////////////////////////////////////////////////////////////////////
53// These global variables implement the MTTY_RX  FIFOs (one per channel)
54////////////////////////////////////////////////////////////////////////////////////
55
56__attribute__((section(".kdata")))
57mtty_fifo_t  mtty_rx_fifo[CONFIG_MAX_TXT_CHANNELS];
58
59__attribute__((section(".kdata")))
60mtty_fifo_t  mtty_tx_fifo[CONFIG_MAX_TXT_CHANNELS];
61
62///////////////////////////////////////
63void soclib_mtty_init( chdev_t * chdev )
64{
65    xptr_t reg_xp;
66
67    // initialise function pointers in chdev
68    chdev->cmd = &soclib_mtty_cmd;
69    chdev->isr = &soclib_mtty_isr;
70    chdev->aux = &soclib_mtty_aux;
71
72    // get TTY channel and extended pointer on TTY peripheral base address
73    xptr_t   tty_xp  = chdev->base;
74    uint32_t channel = chdev->channel;
75    bool_t   is_rx   = chdev->is_rx;
76
77    // get SOCLIB_TTY device cluster and local pointer
78    cxy_t      tty_cxy = GET_CXY( tty_xp );
79    uint32_t * tty_ptr = GET_PTR( tty_xp );
80
81    // enable interruptions for RX but not for TX
82    reg_xp = XPTR( tty_cxy , tty_ptr + MTTY_CONFIG );
83    hal_remote_sw( reg_xp , MTTY_CONFIG_RX_ENABLE );
84
85    // reset relevant FIFO
86    if( is_rx )
87    {
88        mtty_rx_fifo[channel].sts = 0;
89        mtty_rx_fifo[channel].ptr = 0;
90        mtty_rx_fifo[channel].ptw = 0;
91    }
92    else
93    {
94        mtty_tx_fifo[channel].sts = 0;
95        mtty_tx_fifo[channel].ptr = 0;
96        mtty_tx_fifo[channel].ptw = 0;
97    }
98}  // end soclib_mtty_init()
99
100//////////////////////////////////////////////////////////////
101void __attribute__ ((noinline)) soclib_mtty_cmd( xptr_t th_xp )
102{
103    mtty_fifo_t * fifo;     // MTTY_RX or MTTY_TX FIFO
104    char         byte;     // byte value
105    uint32_t     done;     // number of bytes moved
106
107    // get client thread cluster and local pointer
108    cxy_t      th_cxy = GET_CXY( th_xp );
109    thread_t * th_ptr = GET_PTR( th_xp );
110
111    // get command arguments
112    uint32_t type     = hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.type   ) );
113    xptr_t   buf_xp   = hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.buf_xp ) );
114    uint32_t count    = hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.count  ) );
115    xptr_t   error_xp = XPTR( th_cxy , &th_ptr->txt_cmd.error );
116
117#if (DEBUG_SYS_READ & 1)
118if( type == TXT_READ) enter_tty_cmd_read = (uint32_t)hal_get_cycles();
119#endif
120
121#if (DEBUG_SYS_WRITE & 1)
122if( type == TXT_WRITE) enter_tty_cmd_write = (uint32_t)hal_get_cycles();
123#endif
124
125    // get TXT device cluster and pointers
126    xptr_t     dev_xp = (xptr_t)hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.dev_xp ) );
127    cxy_t      dev_cxy = GET_CXY( dev_xp );
128    chdev_t  * dev_ptr = GET_PTR( dev_xp );
129
130    // get cluster and pointers for SOCLIB_TTY peripheral base segment
131    xptr_t     tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
132    cxy_t      tty_cxy = GET_CXY( tty_xp );
133    uint32_t * tty_ptr = GET_PTR( tty_xp );
134
135    // get TTY channel index and channel base address
136    uint32_t   channel = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->channel ) );
137    uint32_t * base    = tty_ptr;
138
139    ///////////////////////
140    if( type == TXT_WRITE )         // write bytes to MTTY_TX FIFO
141    {
142        fifo = &mtty_tx_fifo[channel];
143
144        done = 0;
145
146        while( done < count )
147        {
148            if( fifo->sts < MTTY_FIFO_DEPTH )   // put one byte to FIFO if TX_FIFO not full
149            {
150                // get one byte from command buffer
151                byte = hal_remote_lb( buf_xp + done );
152
153#if DEBUG_HAL_TXT_TX
154uint32_t tx_cycle = (uint32_t)hal_get_cycles();
155if( DEBUG_HAL_TXT_TX < tx_cycle )
156printk("\n[DBG] %s : thread %x put character <%c> to TXT%d_TX fifo / cycle %d\n",
157__FUNCTION__, CURRENT_THREAD, byte, channel, tx_cycle );
158#endif
159                // write byte to FIFO
160                fifo->data[fifo->ptw] = byte;
161
162                // prevent race
163                hal_fence();
164
165                // update FIFO state
166                fifo->ptw = (fifo->ptw + 1) % MTTY_FIFO_DEPTH;
167                hal_atomic_add( &fifo->sts , 1 );
168
169                // udate number of bytes moved
170                done++;
171
172                // enable TX_IRQ
173                //      vci_multi_tty devices never raise TX IRQs
174                //      so the following instructions are useless
175                //      and moreover they kernel panic
176                // xptr_t config_xp = XPTR( tty_cxy , base + MTTY_CONFIG );
177                // uint32_t old = hal_remote_lw( config_xp );
178                // uint32_t new = old | MTTY_CONFIG_TX_ENABLE;
179                // hal_remote_atomic_cas( config_xp , old , new );
180                // hal_remote_sw( XPTR( tty_cxy , base + MTTY_CONFIG ) , MTTY_CONFIG_TX_ENABLE );
181            }
182            else                                // block & deschedule if TX_FIFO full
183            {
184                // block on ISR
185                thread_block( XPTR( local_cxy , CURRENT_THREAD ) , THREAD_BLOCKED_ISR );
186
187                // deschedule
188                sched_yield( "MTTY_TX_FIFO full" ); 
189            }
190        }
191
192        // set error status in command and return
193        hal_remote_sw( error_xp , 0 );
194    }
195    ///////////////////////////
196    else if( type == TXT_READ )       // read bytes from MTTY_RX FIFO   
197    {
198        fifo = &mtty_rx_fifo[channel];
199
200        done = 0;
201
202        while( done < count )
203        {
204            if( fifo->sts > 0 )               // get byte from FIFO if not empty
205            {
206                // get one byte from FIFO
207                char byte = fifo->data[fifo->ptr];
208
209#if DEBUG_HAL_TXT_RX
210uint32_t rx_cycle = (uint32_t)hal_get_cycles();
211if( DEBUG_HAL_TXT_RX < rx_cycle )
212printk("\n[DBG] %s : thread %x get character <%c> from TXT%d_RX fifo / cycle %d\n",
213__FUNCTION__, CURRENT_THREAD, byte, channel, rx_cycle );
214#endif
215                // update FIFO state
216                fifo->ptr = (fifo->ptr + 1) % MTTY_FIFO_DEPTH;
217                hal_atomic_add( &fifo->sts , -1 );
218
219                // set byte to command buffer
220                hal_remote_sb( buf_xp + done , byte );
221
222                // udate number of bytes
223                done++;
224            }
225            else                             //  deschedule if FIFO empty
226            {
227                // block on ISR
228                thread_block( XPTR( local_cxy , CURRENT_THREAD ) , THREAD_BLOCKED_ISR );
229   
230                // deschedule
231                sched_yield( "MTTY_RX_FIFO empty" );
232            }
233        }  // end while
234
235        // set error status in command
236        hal_remote_sw( error_xp , 0 );
237    }
238    else
239    {
240        assert( false , __FUNCTION__ , "illegal TXT command\n" );
241    }
242
243#if (DEBUG_SYS_READ & 1)
244if( type == TXT_READ ) exit_tty_cmd_read = (uint32_t)hal_get_cycles();
245#endif
246
247#if (DEBUG_SYS_WRITE & 1)
248if( type == TXT_WRITE ) exit_tty_cmd_write = (uint32_t)hal_get_cycles();
249#endif
250
251}  // end soclib_mtty_cmd()
252
253/////////////////////////////////////////////////////////////////
254void __attribute__ ((noinline)) soclib_mtty_isr( chdev_t * chdev )
255{
256    thread_t   * server;            // pointer on TXT chdev server thread
257    lid_t        server_lid;        // local index of core running the server thread
258    uint32_t     channel;           // TXT chdev channel
259    bool_t       is_rx;             // TXT chdev direction
260    char         byte;              // byte value
261    xptr_t       owner_xp;          // extended pointer on TXT owner process
262    cxy_t        owner_cxy;         // TXT owner process cluster
263    process_t  * owner_ptr;         // local pointer on TXT owner process
264    pid_t        owner_pid;         // TXT owner process identifier
265    mtty_fifo_t * fifo;              // pointer on MTTY_TX or MTTY_RX FIFO
266    cxy_t        tty_cxy;           // soclib_mtty cluster
267    uint32_t   * tty_ptr;           // soclib_mtty segment base address
268    uint32_t   * base;              // soclib_mtty channel base address
269    xptr_t       status_xp;         // extended pointer on MTTY_STATUS register
270    xptr_t       write_xp;          // extended pointer on MTTY_WRITE register
271    xptr_t       read_xp;           // extended pointer on MTTY_READ register
272    xptr_t       parent_xp;         // extended pointer on parent process
273    cxy_t        parent_cxy;        // parent process cluster
274    process_t  * parent_ptr;        // local pointer on parent process
275    xptr_t       children_lock_xp;  // extended pointer on children processes lock
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
278
279    // get TXT chdev channel, direction and server thread
280    channel    = chdev->channel;
281    is_rx      = chdev->is_rx;
282    server     = chdev->server;
283    server_lid = server->core->lid;
284
285#if (DEBUG_SYS_READ & 1)
286if( is_rx ) enter_tty_isr_read = (uint32_t)hal_get_cycles();
287#endif
288
289#if (DEBUG_SYS_WRITE & 1)
290if( is_rx == 0 ) enter_tty_isr_write = (uint32_t)hal_get_cycles();
291#endif
292
293#if DEBUG_HAL_TXT_RX
294uint32_t rx_cycle = (uint32_t)hal_get_cycles();
295#endif
296
297#if DEBUG_HAL_TXT_TX
298uint32_t tx_cycle = (uint32_t)hal_get_cycles();
299#endif
300
301    // get SOCLIB_TTY peripheral cluster and local pointer
302    tty_cxy = GET_CXY( chdev->base );
303    tty_ptr = GET_PTR( chdev->base );
304
305    // get channel base address
306    base    = tty_ptr;
307
308    // get extended pointer on TTY registers
309    status_xp = XPTR( tty_cxy , base + MTTY_STATUS );
310    write_xp  = XPTR( tty_cxy , base + MTTY_WRITE );
311    read_xp   = XPTR( tty_cxy , base + MTTY_READ );
312
313    /////////////////////////// handle RX //////////////////////
314    if( is_rx )
315    {
316        fifo = &mtty_rx_fifo[channel];
317
318        // try to move bytes until MTTY_READ register empty
319        while( hal_remote_lw( status_xp ) & MTTY_STATUS_RX_FULL )   
320        {
321            // get one byte from MTTY_READ register & acknowledge RX_IRQ
322            byte = (char)hal_remote_lb( read_xp );
323
324            // filter special character ^Z  => block TXT owner process
325            if( byte == 0x1A ) 
326            {
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
332                // get pointers on TXT owner process in owner cluster
333                owner_xp  = process_txt_get_owner( channel );
334               
335                // check process exist
336                assert( (owner_xp != XPTR_NULL) , __FUNCTION__, 
337                "TXT owner process not found\n" );
338
339                // get relevant infos on TXT owner process
340                owner_cxy = GET_CXY( owner_xp );
341                owner_ptr = GET_PTR( owner_xp );
342                owner_pid = hal_remote_lw( XPTR( owner_cxy , &owner_ptr->pid ) );
343
344                // block TXT owner process only if it is not the INIT process
345                if( owner_pid != 1 )
346                {
347                    // get parent process descriptor pointers
348                    parent_xp  = hal_remote_lwd( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
349                    parent_cxy = GET_CXY( parent_xp );
350                    parent_ptr = GET_PTR( parent_xp );
351
352                    // get extended pointer on lock protecting children list in parent process
353                    children_lock_xp = XPTR( parent_cxy , &parent_ptr->children_lock ); 
354
355                    // get pointers on the parent process main thread
356                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
357                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
358
359                    // transfer TXT ownership
360                    process_txt_transfer_ownership( owner_xp );
361
362                    // block all threads in all clusters, but the main thread
363                    process_sigaction( owner_pid , BLOCK_ALL_THREADS );
364
365                    // block the main thread
366                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
367                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
368
369                    // atomically update owner process termination state
370                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
371                                          PROCESS_TERM_STOP );
372
373                    // take the children lock and unblock the parent process main thread
374                    remote_spinlock_lock( children_lock_xp );
375                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
376                    remote_spinlock_unlock( children_lock_xp );
377
378                    return;
379                }
380            }
381
382            // filter special character ^C  => kill TXT owner process
383            if( byte == 0x03 )
384            {
385
386#if DEBUG_HAL_TXT_RX
387if( DEBUG_HAL_TXT_RX < rx_cycle )
388printk("\n[DBG] %s : read ^C character from TXT%d\n", __FUNCTION__, channel );
389#endif
390                // get pointer on TXT owner process in owner cluster
391                owner_xp  = process_txt_get_owner( channel );
392
393                // check process exist
394                assert( (owner_xp != XPTR_NULL) , __FUNCTION__,
395                "TXT owner process not found\n" );
396
397                // get relevant infos on TXT owner process
398                owner_cxy = GET_CXY( owner_xp );
399                owner_ptr = GET_PTR( owner_xp );
400                owner_pid = hal_remote_lw( XPTR( owner_cxy , &owner_ptr->pid ) );
401
402                // kill TXT owner process only if it is not the INIT process
403                if( owner_pid != 1 )
404                {
405                    // get parent process descriptor pointers
406                    parent_xp  = hal_remote_lwd( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
407                    parent_cxy = GET_CXY( parent_xp );
408                    parent_ptr = GET_PTR( parent_xp );
409
410                    // get extended pointer on lock protecting children list in parent process
411                    children_lock_xp = XPTR( parent_cxy , &parent_ptr->children_lock ); 
412
413                    // get pointers on the parent process main thread
414                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
415                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
416
417                    // remove process from TXT list
418                    process_txt_detach( owner_xp );
419
420                    // mark for delete all thread in all clusters, but the main
421                    process_sigaction( owner_pid , DELETE_ALL_THREADS );
422               
423                    // block main thread
424                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
425                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
426
427                    // atomically update owner process termination state
428                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
429                                          PROCESS_TERM_KILL );
430
431                    // take the children lock and unblock the parent process main thread
432                    remote_spinlock_lock( children_lock_xp );
433                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
434                    remote_spinlock_unlock( children_lock_xp );
435
436                    return;
437                }
438            }
439
440            // write byte in MTTY_RX FIFO if not full / discard byte if full
441            if ( fifo->sts < MTTY_FIFO_DEPTH )
442            {
443
444#if DEBUG_HAL_TXT_RX
445if( DEBUG_HAL_TXT_RX < rx_cycle )
446printk("\n[DBG] %s : put character <%c> to TXT%d_RX fifo\n",
447__FUNCTION__, byte, channel );
448#endif
449                // store byte into FIFO
450                fifo->data[fifo->ptw] = (char)byte; 
451
452                // avoid race
453                hal_fence();
454
455                // update RX_FIFO state
456                fifo->ptw = (fifo->ptw + 1) % MTTY_FIFO_DEPTH;
457                hal_atomic_add( &fifo->sts , 1 );
458
459                // unblock TXT_RX server thread
460                thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
461
462                // send IPI to core running server thread
463                dev_pic_send_ipi( local_cxy , server_lid );
464            }
465            else
466            {
467                printk("\n[WARNING] %s : MTTY_RX_FIFO[%d] full => discard character <%x>\n",
468                __FUNCTION__, channel, (uint32_t)byte );
469            }
470        }  // end while MTTY_READ register full
471
472    }  // end RX
473
474    ///////////////////////  handle TX  /////////////////////////////
475    else
476    {
477        fifo = &mtty_tx_fifo[channel];
478
479        // try to move bytes until TX_FIFO empty
480        while( fifo->sts > 0 )
481        {
482            // write one byte to MTTY_WRITE register if empty / exit loop if full
483            if( (hal_remote_lw( status_xp ) & MTTY_STATUS_TX_FULL) == 0 ) 
484            {
485                // get one byte from TX_FIFO
486                byte = fifo->data[fifo->ptr];
487
488#if DEBUG_HAL_TXT_TX
489if( DEBUG_HAL_TXT_TX < tx_cycle )
490printk("\n[DBG] %s : get character <%c> from TXT%d_TX fifo\n",
491__FUNCTION__, byte, channel );
492#endif
493                // update TX_FIFO state
494                fifo->ptr = (fifo->ptr + 1) % MTTY_FIFO_DEPTH;
495                hal_atomic_add( &fifo->sts , -1 );
496
497                // write byte to MTTY_WRITE register & acknowledge TX_IRQ
498                hal_remote_sb( write_xp , byte );
499            }
500        }
501
502        // disable TX_IRQ
503        //      vci_multi_tty devices never raise TX IRQs
504        //      so the following instructions are useless
505        //      and moreover they kernel panic
506        // xptr_t config_xp = XPTR( tty_cxy , base + MTTY_CONFIG );
507        // uint32_t old = hal_remote_lw( config_xp );
508        // uint32_t new = old & ~(MTTY_CONFIG_TX_ENABLE);
509        // hal_remote_atomic_cas( config_xp , old , new );
510        // hal_remote_sw( XPTR( tty_cxy , base + MTTY_CONFIG ) , 0 );
511
512        // unblock TXT_TX server thread
513        thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
514
515        // send IPI to core running server thread
516        dev_pic_send_ipi( local_cxy , server_lid );
517
518    }  // end TX
519
520    hal_fence();
521
522#if (DEBUG_SYS_READ & 1)
523if( is_rx ) exit_tty_isr_read = (uint32_t)hal_get_cycles();
524#endif
525
526#if (DEBUG_SYS_WRITE & 1)
527if( is_rx == 0 ) exit_tty_isr_write = (uint32_t)hal_get_cycles();
528#endif
529
530}  // end soclib_mtty_isr()
531
532/////////////////////////////////////////////////////////////
533void __attribute__ ((noinline)) soclib_mtty_aux( void * args )
534{
535    uint32_t   status;
536    bool_t     empty;
537    uint32_t   i;
538
539    xptr_t     dev_xp = ((txt_sync_args_t *)args)->dev_xp;
540    char     * buffer = ((txt_sync_args_t *)args)->buffer;
541    uint32_t   count  = ((txt_sync_args_t *)args)->count;
542    uint32_t   channel = ((txt_sync_args_t *)args)->channel;
543   
544    // get TXT0 chdev cluster and local pointer
545    cxy_t     dev_cxy = GET_CXY( dev_xp );
546    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
547
548    // get extended pointer on TTY channel base address
549    xptr_t tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
550
551    // get TTY channel segment cluster and local pointer
552    cxy_t      tty_cxy = GET_CXY( tty_xp );
553    uint32_t * tty_ptr = (uint32_t *)GET_PTR( tty_xp );
554
555    // get extended pointers on MTTY_WRITE & MTTY_STATUS registers
556    xptr_t write_xp  = XPTR( tty_cxy , tty_ptr + MTTY_WRITE );
557    xptr_t status_xp = XPTR( tty_cxy , tty_ptr + MTTY_STATUS );
558
559    reg_t  save_sr;
560
561    // loop on characters (busy waiting policy)
562    for( i = 0 ; i < count ; i++ )
563    {
564        // This is the MTTY multiplexing
565        // Before each character, we send the destination TTY number for this char.
566        // The two bytes (dest number + char) must be sent consecutively,
567        // so to guarantee this atomicity, we use a lock to prevent other
568        // concurrent server DEV threads to write a byte in between our two bytes
569
570        // Get the lock
571        spinlock_lock_busy( &txt0_lock, &save_sr );
572
573        // Send the destination TTY number
574        do
575        {
576            // get MTTY_STATUS
577            status = hal_remote_lw( status_xp );
578            empty  = ( (status & MTTY_STATUS_TX_FULL) == 0 );
579
580            // transfer one byte if TX buffer empty
581            if ( empty )  hal_remote_sb( write_xp , channel + '0' );
582           
583        }
584        while ( empty == false );
585
586        // Send the character
587        do
588        {
589            // get MTTY_STATUS
590            status = hal_remote_lw( status_xp );
591            empty  = ( (status & MTTY_STATUS_TX_FULL) == 0 );
592
593            // transfer one byte if TX buffer empty
594            if ( empty )  hal_remote_sb( write_xp , buffer[i] );
595        }
596        while ( empty == false );
597
598        // Release the lock
599        spinlock_unlock_busy( &txt0_lock, save_sr );
600    }
601}  // end soclib_mtty_aux()
602
603
604
Note: See TracBrowser for help on using the repository browser.