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

Last change on this file since 540 was 540, checked in by nicolas.van.phan@…, 3 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
Line 
1/*
2 * dev_txt.c - TXT (Text Terminal) generic device API implementation.
3 *
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
24#include <hal_kernel_types.h>
25#include <hal_special.h>
26#include <hal_remote.h>
27#include <hal_drivers.h>
28#include <thread.h>
29#include <chdev.h>
30#include <rpc.h>
31#include <printk.h>
32#include <dev_txt.h>
33
34/////////////////////////////////////////////////////////////////////////////////////////
35// Extern global variables
36/////////////////////////////////////////////////////////////////////////////////////////
37
38extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
39
40#if (DEBUG_SYS_READ & 1)
41extern uint32_t enter_txt_read;
42extern uint32_t exit_txt_read;
43#endif
44
45#if (DEBUG_SYS_WRITE & 1)
46extern uint32_t enter_txt_write;
47extern uint32_t exit_txt_write;
48#endif
49
50////////////////////////////////////////
51const char * dev_txt_type_str( dev_txt_cmd_t type )
52{
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  }
59}
60
61//////////////////////////////////
62void dev_txt_init( chdev_t * txt )
63{
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
67
68    xptr_t    pic_xp  = chdev_dir.pic;
69    uint32_t  channel = txt->channel;
70    uint32_t  impl    = txt->impl;
71    bool_t    is_rx   = txt->is_rx;
72
73    assert( (pic_xp != XPTR_NULL) || (channel == 0) ,
74            "PIC not initialised before TXT" );
75
76    // set chdev name
77    if( is_rx ) snprintf( txt->name , 16 , "txt%d_rx" , channel );
78    else        snprintf( txt->name , 16 , "txt%d_tx" , channel );
79
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   
85    // call driver init function
86    hal_drivers_txt_init(txt, impl);
87
88    // no server thread and no IRQ routing for TXT0
89    // except for LETI where there MUST be IRQ routing
90    // no server thread for IMPL_TXT_RS2 (multiplexed in software, not hardware)
91    if( channel != 0 && impl != IMPL_TXT_RS2 )
92    {
93        // select a core to execute the server thread
94        lid_t lid = cluster_select_local_core();
95
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        {
102        // bind IRQ to the selected core
103        dev_pic_bind_irq( lid , txt );
104
105        // enable IRQ
106        dev_pic_enable_irq( lid , XPTR( local_cxy , txt ) );
107        }
108
109        // create server thread
110        thread_t * new_thread;
111        error_t    error;
112
113        error = thread_kernel_create( &new_thread,
114                                      THREAD_DEV,
115                                      &chdev_sequencial_server,
116                                      txt,
117                                      lid );
118
119        assert( (error == 0) , "cannot create server thread" );
120
121        // set "server" field in chdev descriptor
122        txt->server = new_thread;
123
124        // set "chdev" field in thread descriptor
125        new_thread->chdev = txt;
126
127        // unblock server thread
128        thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL );
129    }
130}
131
132//////////////////////////////////////////////////////////////////////////////////
133// This static function is called by dev_txt_read(), dev_txt_write() functions.
134////////////////////////////////////i/////////////////////////////////////////////
135static error_t dev_txt_access( uint32_t   type,
136                               uint32_t   channel,
137                               char     * buffer,
138                               uint32_t   count )
139{
140    xptr_t     dev_xp;
141    thread_t * this = CURRENT_THREAD;
142
143    // check channel argument
144    assert( (channel < CONFIG_MAX_TXT_CHANNELS) , "illegal channel index" );
145
146    // get extended pointer on remote TXT chdev descriptor
147    if( type == TXT_WRITE )  dev_xp = chdev_dir.txt_tx[channel];
148    else                     dev_xp = chdev_dir.txt_rx[channel];
149
150    assert( (dev_xp != XPTR_NULL) , "undefined TXT chdev descriptor" );
151
152    // register command in calling thread descriptor
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;
157
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.
161    chdev_register_command( dev_xp );
162
163    // return I/O operation status from calling thread descriptor
164    return this->txt_cmd.error;
165}
166
167/////////////////////////////////////////
168error_t dev_txt_write( uint32_t   channel,
169                       char     * buffer,
170                       uint32_t   count )
171{
172
173#if (DEBUG_SYS_WRITE & 1)
174enter_txt_write = hal_time_stamp();
175#endif
176
177#if DEBUG_DEV_TXT_TX
178uint32_t cycle = (uint32_t)hal_get_cycles();
179if( DEBUG_DEV_TXT_TX < cycle )
180printk("\n[DBG] %s : thread %x enters / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
181#endif
182
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    {
215    return dev_txt_access( TXT_WRITE , channel , buffer , count );
216    }
217
218#if DEBUG_DEV_TXT_TX
219cycle = (uint32_t)hal_get_cycles();
220if( DEBUG_DEV_TXT_TX < cycle )
221printk("\n[DBG] %s : thread %x exit / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
222#endif
223
224#if (DEBUG_SYS_WRITE & 1)
225exit_txt_write = hal_time_stamp();
226#endif
227
228}
229
230/////////////////////////////////////////
231error_t dev_txt_read( uint32_t   channel,
232                      char     * buffer )
233{
234
235#if (DEBUG_SYS_READ & 1)
236enter_txt_read = hal_time_stamp();
237#endif
238
239#if DEBUG_DEV_TXT_RX
240uint32_t cycle = (uint32_t)hal_get_cycles();
241if( DEBUG_DEV_TXT_RX < cycle )
242printk("\n[DBG] %s : thread %x enters / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
243#endif
244
245    return dev_txt_access( TXT_READ , channel , buffer , 1 );
246
247#if DEBUG_DEV_TXT_RX
248cycle = (uint32_t)hal_get_cycles();
249if( DEBUG_DEV_TXT_RX < cycle )
250printk("\n[DBG] %s : thread %x exit / cycle %d\n", __FUNCTION__, CURRENT_THREAD, cycle );
251#endif
252
253#if (DEBUG_SYS_READ & 1)
254exit_txt_read = hal_time_stamp();
255#endif
256
257}
258
259//////////////////////////////////////////////
260error_t dev_txt_sync_write( char     * buffer,
261                            uint32_t   count )
262{
263    // get extended pointer on TXT[0] chdev
264    xptr_t  dev_xp = chdev_dir.txt_tx[0];
265
266    assert( (dev_xp != XPTR_NULL) ,
267    "undefined TXT0 chdev descriptor" );
268
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 );
272
273    // get driver command function
274    dev_aux_t * aux = (dev_aux_t *)hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->aux ) );
275
276    // build arguments structure
277    txt_sync_args_t  args;
278    args.dev_xp = dev_xp;
279    args.buffer = buffer;
280    args.count  = count;
281    args.channel = 0;
282
283    // call driver function
284    aux( &args );
285
286    return 0;
287}
288
Note: See TracBrowser for help on using the repository browser.