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

Last change on this file since 432 was 432, checked in by alain, 4 years ago

bloup

File size: 15.6 KB
Line 
1/*
2 * soclib_tty.c - soclib tty driver implementation.
3 *
4 * Author  Alain Greiner (2016)
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#include <dev_txt.h>
25#include <chdev.h>
26#include <soclib_tty.h>
27#include <remote_spinlock.h>
28#include <thread.h>
29#include <printk.h>
30#include <hal_special.h>
31
32#if CONFIG_READ_DEBUG
33extern uint32_t  enter_tty_cmd;
34extern uint32_t  exit_tty_cmd;
35
36extern uint32_t  enter_tty_isr;
37extern uint32_t  exit_tty_isr;
38#endif
39
40///////////////////////////////////////
41void soclib_tty_init( chdev_t * chdev )
42{
43    xptr_t reg_xp;
44
45    chdev->cmd = &soclib_tty_cmd;
46    chdev->isr = &soclib_tty_isr;
47    chdev->aux = &soclib_tty_aux;
48
49    // get TTY channel and extended pointer on TTY peripheral base address
50    xptr_t   tty_xp  = chdev->base;
51    uint32_t channel = chdev->channel;
52
53    // get SOCLIB_TTY device cluster and local pointer
54    cxy_t      tty_cxy = GET_CXY( tty_xp );
55    uint32_t * tty_ptr = (uint32_t *)GET_PTR( tty_xp );
56
57    // reset TTY_RX_IRQ_ENABLE
58    reg_xp = XPTR( tty_cxy , tty_ptr + (channel * TTY_SPAN) + TTY_RX_IRQ_ENABLE );
59    hal_remote_sw( reg_xp , 0 );
60
61    // reset TTY_TX_IRQ_ENABLE
62    reg_xp = XPTR( tty_cxy , tty_ptr + (channel * TTY_SPAN) + TTY_TX_IRQ_ENABLE );
63    hal_remote_sw( reg_xp , 0 );
64}
65
66//////////////////////////////////////////////////////////////
67void __attribute__ ((noinline)) soclib_tty_cmd( xptr_t th_xp )
68{
69
70#if CONFIG_READ_DEBUG
71enter_tty_cmd = hal_time_stamp();
72#endif
73
74#if CONFIG_DEBUG_HAL_TXT
75uint32_t cycle = (uint32_t)hal_get_cycles();
76if (CONFIG_DEBUG_HAL_TXT < cycle )
77printk("\n[DBG] %s : thread %x enter / cycle %d\n",
78__FUNCTION__ , CURRENT_THREAD , cycle );
79#endif
80
81    // get client thread cluster and local pointer
82    cxy_t      th_cxy = GET_CXY( th_xp );
83    thread_t * th_ptr = (thread_t *)GET_PTR( th_xp );
84
85    // get command type and extended pointer on TXT device
86    uint32_t type   =         hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.type ) );
87    xptr_t   dev_xp = (xptr_t)hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.dev_xp ) );
88
89    assert( (type == TXT_READ) || (type == TXT_WRITE) , __FUNCTION__, "illegal command type");
90
91    // get TXT device cluster and local pointer
92    cxy_t     dev_cxy = GET_CXY( dev_xp );
93    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
94
95    // get extended pointer on SOCLIB_TTY base segment
96    xptr_t tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
97
98    // get SOCLIB_TTY base segment cluster and local pointer
99    cxy_t      tty_cxy = GET_CXY( tty_xp );
100    uint32_t * tty_ptr = (uint32_t *)GET_PTR( tty_xp );
101
102    // get TTY channel index and channel base address
103    uint32_t   channel = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->channel ) );
104    uint32_t * base    = tty_ptr + TTY_SPAN * channel;
105
106    // compute extended pointer on relevant TTY register
107    xptr_t reg_xp; 
108    if( type == TXT_READ )  reg_xp = XPTR( tty_cxy , base + TTY_RX_IRQ_ENABLE );
109    else                    reg_xp = XPTR( tty_cxy , base + TTY_TX_IRQ_ENABLE );
110
111    // enable relevant IRQ : data transfer will be done by the TTY_RX ISR)
112    hal_remote_sw( reg_xp , 1 );
113
114#if CONFIG_DEBUG_HAL_TXT
115cycle = (uint32_t)hal_get_cycles();
116if (CONFIG_DEBUG_HAL_TXT < cycle )
117printk("\n[DBG] %s : thread %x deschedule / cycle %d\n", 
118__FUNCTION__ , CURRENT_THREAD , cycle );
119#endif
120
121    // Block and deschedule server thread
122    thread_block( CURRENT_THREAD , THREAD_BLOCKED_DEV_ISR );
123    sched_yield("blocked on ISR");
124
125#if CONFIG_DEBUG_HAL_TXT
126cycle = (uint32_t)hal_get_cycles();
127if (CONFIG_DEBUG_HAL_TXT < cycle )
128printk("\n[DBG] %s : thread %x resume / cycle %d\n", 
129__FUNCTION__ , CURRENT_THREAD , cycle );
130#endif
131
132#if CONFIG_READ_DEBUG
133exit_tty_cmd = hal_time_stamp();
134#endif
135
136}  // end soclib_tty_cmd()
137
138/////////////////////////////////////////////////////////////
139void __attribute__ ((noinline)) soclib_tty_aux( void * args )
140{
141    uint32_t   status;
142    bool_t     empty;
143    uint32_t   i;
144
145    xptr_t     dev_xp = ((txt_aux_t *)args)->dev_xp;
146    char     * buffer = ((txt_aux_t *)args)->buffer;
147    uint32_t   count  = ((txt_aux_t *)args)->count;
148   
149    // get TXT0 chdev cluster and local pointer
150    cxy_t     dev_cxy = GET_CXY( dev_xp );
151    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
152
153    // get extended pointer on TTY channel base address
154    xptr_t tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
155
156    // get TTY channel segment cluster and local pointer
157    cxy_t      tty_cxy = GET_CXY( tty_xp );
158    uint32_t * tty_ptr = (uint32_t *)GET_PTR( tty_xp );
159
160    // get extended pointers on TTY_WRITE & TTY_STATUS registers
161    xptr_t write_xp  = XPTR( tty_cxy , tty_ptr + TTY_WRITE );
162    xptr_t status_xp = XPTR( tty_cxy , tty_ptr + TTY_STATUS );
163
164    // loop on characters (busy waiting strategy)
165    for( i = 0 ; i < count ; i++ )
166    {
167        do
168        {
169            // get TTY_STATUS
170            status = hal_remote_lw( status_xp );
171            empty  = ( (status & TTY_STATUS_TX_FULL) == 0 );
172
173            // transfer one byte if TX buffer empty
174            if ( empty )  hal_remote_sb( write_xp , buffer[i] );
175        }
176        while ( empty == false );
177    }
178}  // end soclib_tty_aux()
179
180
181/////////////////////////////////////////////////////////////////
182void __attribute__ ((noinline)) soclib_tty_isr( chdev_t * chdev )
183{
184    uint32_t   type;         // command type
185    uint32_t   count;        // number of bytes in buffer
186    xptr_t     buf_xp;       // extended pointer on buffer
187    xptr_t     status_xp;    // extended pointer on TTY_STATUS register
188    xptr_t     write_xp;     // extended pointer on TTY_WRITE register
189    xptr_t     read_xp;      // extended pointer on TTY_READ register
190    uint32_t   status;       // TTY terminal status
191    char       byte;         // read byte
192    uint32_t   i;
193
194#if (CONFIG_READ_DEBUG & 0x1) || (CONFIG_WRITE_DEBUG & 0x1)
195enter_tty_isr = hal_time_stamp();
196#endif
197
198#if CONFIG_DEBUG_HAL_TXT
199uint32_t cycle = (uint32_t)hal_get_cycles();
200if (CONFIG_DEBUG_HAL_TXT < cycle)
201printk("\n[DBG] %s : enter / cycle %d\n", __FUNCTION__ , cycle );
202#endif
203
204    // get extended pointer on client thread
205    xptr_t root      = XPTR( local_cxy , &chdev->wait_root );
206    xptr_t client_xp = XLIST_FIRST_ELEMENT( root , thread_t , wait_list );
207
208    // get client thread cluster and local pointer
209    cxy_t      client_cxy = GET_CXY( client_xp );
210    thread_t * client_ptr = (thread_t *)GET_PTR( client_xp );
211
212    // get command arguments
213    type    = hal_remote_lw ( XPTR( client_cxy , &client_ptr->txt_cmd.type   ) );
214    count   = hal_remote_lw ( XPTR( client_cxy , &client_ptr->txt_cmd.count  ) );
215    buf_xp  = hal_remote_lwd( XPTR( client_cxy , &client_ptr->txt_cmd.buf_xp ) );
216
217    // get SOCLIB_TTY peripheral cluster and local pointer
218    cxy_t      tty_cxy = GET_CXY( chdev->base );
219    uint32_t * tty_ptr = (uint32_t *)GET_PTR( chdev->base );
220
221    // get channel base address
222    uint32_t * base = tty_ptr + TTY_SPAN * chdev->channel;
223
224    // get extended pointer on TTY registers
225    status_xp = XPTR( tty_cxy , base + TTY_STATUS );
226    write_xp  = XPTR( tty_cxy , base + TTY_WRITE );
227    read_xp   = XPTR( tty_cxy , base + TTY_READ );
228
229    if( type == TXT_READ )              // read one single character
230    {
231        // get TTY_STATUS
232        status = hal_remote_lw( status_xp );
233
234        if( status & TTY_STATUS_RX_FULL )   // TTY_RX full => move one byte
235        {
236            // get a byte from TTY_READ, and acknowledge RX_IRQ
237            byte = (char)hal_remote_lb( read_xp );
238
239            // write it to command buffer
240            hal_remote_sb( buf_xp , byte );
241        }
242        else                               // buffer empty => exit ISR for retry
243        {
244            return;
245        }
246
247        // disable RX_IRQ
248        xptr_t reg_xp = XPTR( tty_cxy , base + TTY_RX_IRQ_ENABLE );
249        hal_remote_sw( reg_xp , 0 );
250    }
251    else   // type == TXT_WRITE           // write all characters in string
252    {
253        // loop on characters
254        for( i = 0 ; i < count ; i++ )
255        {
256            // get TTY_STATUS
257            status = hal_remote_lw( status_xp );
258
259            if( (status & TTY_STATUS_TX_FULL) == 0 ) // TTY_TX empty => move one byte
260            {
261                // get one byte from command buffer
262                byte = (char)hal_remote_lb( buf_xp + i );
263
264                // write byte to TTY_WRITE, and acknowledge TX_IRQ
265                hal_remote_sb( write_xp , byte );
266            }
267            else         // TTY_TX full => update command arguments and exit ISR for retry
268            {
269                hal_remote_sw ( XPTR( client_cxy , &client_ptr->txt_cmd.count ), count-i );
270                hal_remote_swd( XPTR( client_cxy , &client_ptr->txt_cmd.buf_xp ), buf_xp+i );
271                return;
272            }
273        }
274
275        // disable TX_IRQ
276        xptr_t reg_xp = XPTR( tty_cxy , base + TTY_TX_IRQ_ENABLE );
277        hal_remote_sw( reg_xp , 0 );
278    }
279
280    // The I/O operation completed when we reach this point
281
282    // set I/O operation status in command
283    hal_remote_sw( XPTR( client_cxy , &client_ptr->txt_cmd.error ) , 0 );
284
285    // unblock server thread
286    thread_unblock( XPTR( local_cxy , chdev->server ) , THREAD_BLOCKED_DEV_ISR );
287
288    // unblock client thread
289    // thread_unblock( client_xp , THREAD_BLOCKED_IO );
290
291    hal_fence();
292
293#if CONFIG_DEBUG_HAL_TXT
294cycle = (uint32_t)hal_get_cycles();
295if (CONFIG_DEBUG_HAL_TXT < cycle)
296{
297    if( type == TXT_READ) 
298        printk("\n[DBG] %s : exit after RX / cycle %d\n", __FUNCTION__ , cycle );
299    else
300        printk("\n[DBG] %s : exit after TX / cycle %d\n", __FUNCTION__ , cycle );
301}     
302#endif
303
304#if (CONFIG_READ_DEBUG & 0x1) || (CONFIG_WRITE_DEBUG & 0x1)
305exit_tty_isr = hal_time_stamp();
306#endif
307
308}  // end soclib_tty_isr()
309
310/*
311/////////////////////////////////////////////////////////////////
312void __attribute__ ((noinline)) soclib_tty_isr( chdev_t * chdev )
313{
314    xptr_t     root_xp;      // extended pointer on command list root
315    xptr_t     client_xp;    // extended pointer on client thread
316    cxy_t      client_cxy;   // client thread cluster
317    thread_t * client_ptr;   // client_thread local pointer
318    uint32_t   type;         // command type
319    uint32_t   count;        // number of bytes in buffer
320    xptr_t     buf_xp;       // extended pointer on buffer
321    xptr_t     status_xp;    // extended pointer on TTY_STATUS register
322    xptr_t     write_xp;     // extended pointer on TTY_WRITE register
323    xptr_t     read_xp;      // extended pointer on TTY_READ register
324    uint32_t   status;       // TTY terminal status
325    char       byte;         // read byte
326    uint32_t   i;
327
328#if (CONFIG_READ_DEBUG & 0x1) || (CONFIG_WRITE_DEBUG & 0x1)
329enter_tty_isr = hal_time_stamp();
330#endif
331
332txt_dmsg("\n[DBG] %s : core[%x,%d] enter / cycle %d\n",
333__FUNCTION__ , local_cxy, CURRENT_THREAD->core->lid , hal_time_stamp() );
334
335    // get SOCLIB_TTY peripheral cluster and local pointer
336    cxy_t      tty_cxy = GET_CXY( chdev->base );
337    uint32_t * tty_ptr = (uint32_t *)GET_PTR( chdev->base );
338
339    // get channel base address
340    uint32_t * base = tty_ptr + TTY_SPAN * chdev->channel;
341
342    // get extended pointer on TTY registers
343    status_xp = XPTR( tty_cxy , base + TTY_STATUS );
344    write_xp  = XPTR( tty_cxy , base + TTY_WRITE );
345    read_xp   = XPTR( tty_cxy , base + TTY_READ );
346
347    // get TTY_STATUS
348    status = hal_remote_lw( status_xp );
349
350    // get extended pointer on the command list root
351    root_xp = XPTR( local_cxy , &chdev->wait_root );
352
353    // get extended pointer on client thread
354    if(xlist_is_empty(root_xp)) client_xp = XLIST_FIRST_ELEMENT(root, thread_t, wait_list);
355    else                        client_xp = XPTR_NULL;
356
357    if( client_xp )
358    {
359        // get client thread cluster and local pointer
360        client_cxy = GET_CXY( client_xp );
361        client_ptr = (thread_t *)GET_PTR( client_xp );
362
363        // get command arguments
364        type    = hal_remote_lw ( XPTR( client_cxy , &client_ptr->txt_cmd.type   ) );
365        count   = hal_remote_lw ( XPTR( client_cxy , &client_ptr->txt_cmd.count  ) );
366        buf_xp  = hal_remote_lwd( XPTR( client_cxy , &client_ptr->txt_cmd.buf_xp ) );
367    }
368
369    ///////////// handle RX if TTY_RX full
370    if( status & TTY_STATUS_RX_FULL )   
371    {
372        // get a byte from TTY_READ, and acknowledge RX_IRQ
373        byte = (char)hal_remote_lb( read_xp );
374
375        // FIXME The RX_IRQ must be always enabled !!! 
376        // xptr_t reg_xp = XPTR( tty_cxy , base + TTY_RX_IRQ_ENABLE );
377        // hal_remote_sw( reg_xp , 0 );
378
379        // analyse received character
380        switch( byte )
381        {
382            case CONTROL_C:          // SIGINT to process
383            case CONTROL_D:
384            {
385                // TODO SIGINT
386                return
387            }
388            break;
389            default:                 
390            {
391                if( (type == TXT_READ) && (client_xp != XPTR_NULL) ) 
392                {
393                    // write byte to command buffer
394                    hal_remote_sb( buf_xp , byte );
395
396                    // set status in command
397                    hal_remote_sw( XPTR( client_cxy , &client_ptr->txt_cmd.error ) , 0 );
398
399                    hal_fence();
400
401                    // unblock server thread
402                    thread_unblock( XPTR(local_cxy,chdev->server), THREAD_BLOCKED_DEV_ISR );
403                }
404                else                    // discard byte
405                {
406                    // TODO WARNING
407                    return
408                }
409            }
410        }
411    } // end RX handling
412
413    //////////////// handle TX if WRITE command pending
414    if( (type == TXT_WRITE) && (client_xp != XPTR_NULL) )
415    {
416        // loop on characters
417        for( i = 0 ; i < count ; i++ )
418        {
419            // get TTY_STATUS
420            status = hal_remote_lw( status_xp );
421
422            if( (status & TTY_STATUS_TX_FULL) == 0 ) // TTY_TX empty => move one byte
423            {
424                // get one byte from command buffer
425                byte = (char)hal_remote_lb( buf_xp + i );
426
427                // write byte to TTY_WRITE, and acknowledge TX_IRQ
428                hal_remote_sb( write_xp , byte );
429            }
430            else         // TTY_TX full => update command arguments and exit ISR for retry
431            {
432                hal_remote_sw ( XPTR( client_cxy , &client_ptr->txt_cmd.count ), count-i );
433                hal_remote_swd( XPTR( client_cxy , &client_ptr->txt_cmd.buf_xp ), buf_xp+i );
434                return;
435            }
436        }
437
438        // disable TX_IRQ
439        xptr_t reg_xp = XPTR( tty_cxy , base + TTY_TX_IRQ_ENABLE );
440        hal_remote_sw( reg_xp , 0 );
441
442        // set I/O operation status in command
443        hal_remote_sw( XPTR( client_cxy , &client_ptr->txt_cmd.error ) , 0 );
444
445        hal_fence();
446
447        // unblock server thread
448        thread_unblock( XPTR( local_cxy , chdev->server ) , THREAD_BLOCKED_DEV_ISR );
449
450    }  // end TX handling
451
452txt_dmsg("\n[DBG] %s : core[%x,%d] exit / cycle %d\n",
453__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , hal_time_stamp() );
454
455#if (CONFIG_READ_DEBUG & 0x1) || (CONFIG_WRITE_DEBUG & 0x1)
456exit_tty_isr = hal_time_stamp();
457#endif
458
459}  // end soclib_tty_isr()
460
461*/
Note: See TracBrowser for help on using the repository browser.