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

Last change on this file since 543 was 540, checked in by nicolas.van.phan@…, 8 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.