source: soft/giet_vm/giet_drivers/tty_driver.c @ 323

Last change on this file since 323 was 320, checked in by alain, 10 years ago

All drivers have been modified to use only the information
contained in the hard_config.h file

File size: 10.5 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : tty_driver.c
3// Date     : 23/05/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The tty_driver.c and tty_drivers.h files are part ot the GIET-VM kernel.
8// This driver supports the SocLib vci_multi_tty component.
9//
10// The total number of TTY terminals must be defined by the configuration
11// parameter NB_TTY_CHANNELS in the hard_config.h file.
12//
13// The "system" terminal is TTY[0].
14// The "user" TTYs are allocated to applications by the GIET in the boot phase,
15// as defined in the mapping_info data structure. The corresponding tty_id must
16// be stored in the context of the task by the boot code.
17//
18// The SEG_TTY_BASE address must be defined in the hard_config.h file.
19///////////////////////////////////////////////////////////////////////////////////
20// Implementation note:
21//
22// All physical accesses to device registers are done by the two
23// _tty_get_register(), _tty_set_register() low-level functions,
24// that are handling virtual / physical addressing.
25///////////////////////////////////////////////////////////////////////////////////
26
27#include <giet_config.h>
28#include <tty_driver.h>
29#include <xcu_driver.h>
30#include <ctx_handler.h>
31#include <utils.h>
32
33#if !defined(SEG_TTY_BASE)
34# error: You must define SEG_TTY_BASE in the hard_config.h file
35#endif
36
37#if !defined(NB_TTY_CHANNELS)
38# error: You must define NB_TTY_CHANNELS in the hard_config.h file
39#endif
40
41#if (NB_TTY_CHANNELS < 1)
42# error: NB_TTY_CHANNELS cannot be smaller than 1!
43#endif
44
45#define in_unckdata __attribute__((section (".unckdata")))
46#define in_kdata    __attribute__((section (".kdata")))
47
48//////////////////////////////////////////////////////////////////////////////
49//   TTY global variables
50//////////////////////////////////////////////////////////////////////////////
51
52in_unckdata volatile unsigned int _tty_rx_buf[NB_TTY_CHANNELS];
53
54in_unckdata volatile unsigned int _tty_rx_full[NB_TTY_CHANNELS] 
55                                     = { [0 ... NB_TTY_CHANNELS - 1] = 0 };
56
57in_kdata unsigned int _tty_lock[NB_TTY_CHANNELS] 
58                        = { [0 ... NB_TTY_CHANNELS - 1] = 0 };
59
60//////////////////////////////////////////////////////////////////////////////
61// This low level function returns the value of register (channel / index)
62//////////////////////////////////////////////////////////////////////////////
63unsigned int _tty_get_register( unsigned int channel,
64                                unsigned int index )
65{
66    unsigned int* vaddr = (unsigned int*)SEG_TTY_BASE + channel*TTY_SPAN + index;
67    return _io_extended_read( vaddr );
68}
69
70//////////////////////////////////////////////////////////////////////////////
71// This low level function set a new value in register (channel / index) 
72//////////////////////////////////////////////////////////////////////////////
73void _tty_set_register( unsigned int channel,
74                        unsigned int index,
75                        unsigned int value )
76{
77    unsigned int* vaddr = (unsigned int*)SEG_TTY_BASE + channel*TTY_SPAN + index;
78    _io_extended_write( vaddr, value );
79}
80
81/////////////////////////////////////////////////////////////////////////////////
82// This non-blocking function writes a character string from a fixed-length
83// buffer to a TTY terminal identified by the channel argument.
84// This function is intended to be used to handle a system call, and should
85// not be used by the kernel for log messages on TTY 0.
86// protecting exclusive access to the selected terminal.
87// If channel argument is 0xFFFFFFFF, the TTY index is found in the task context.
88// This is a non blocking call: it tests the TTY_STATUS register, and stops
89// the transfer as soon as the TTY_STATUS[WRITE] bit is set.
90/////////////////////////////////////////////////////////////////////////////////
91// Returns  the number of characters that have been written.
92/////////////////////////////////////////////////////////////////////////////////
93unsigned int _tty_write( const char*  buffer,   
94                         unsigned int length,    // number of characters
95                         unsigned int channel)   // channel index
96{
97    unsigned int  nwritten;
98
99    // compute and check tty channel
100    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
101    if( channel >= NB_TTY_CHANNELS ) return -1;
102
103    // write string to TTY channel
104    for (nwritten = 0; nwritten < length; nwritten++) 
105    {
106        // check tty's status
107        if ( _tty_get_register( channel, TTY_STATUS ) & 0x2 )  break;
108
109        // write one byte
110        if (buffer[nwritten] == '\n') {
111            _tty_set_register( channel, TTY_WRITE, (unsigned int)'\r' );
112        }
113        _tty_set_register( channel, TTY_WRITE, (unsigned int)buffer[nwritten] );
114    }
115   
116    return nwritten;
117}
118
119//////////////////////////////////////////////////////////////////////////////
120// This non-blocking function fetches one character from the
121// terminal identified by the channel argument. If the channel argument
122// is 0xFFFFFFFF, the channel index is obtained from the current task context.
123// It uses the TTY_GET_IRQ[tty_id] interrupt and the buffer must have been
124// filled by the TTY_ISR.
125// It test the _tty_rx_full[tty_id] variable, read the _tty_rx_buf[tty_id]
126// buffer, writes this character to the target buffer, and resets the
127// _tty_rx_full[tty_id] register.
128// The length argument is not used.
129//////////////////////////////////////////////////////////////////////////////
130// Returns  the number of characters that have been read (0/1).
131//////////////////////////////////////////////////////////////////////////////
132unsigned int _tty_read( char*        buffer, 
133                        unsigned int length,    // unused
134                        unsigned int channel)   // channel index
135{
136    // compute and check tty channel
137    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
138    if( channel >= NB_TTY_CHANNELS ) return -1;
139
140    // read one character from TTY channel
141    if (_tty_rx_full[channel] == 0) 
142    {
143        return 0;
144    }
145    else 
146    {
147        *buffer = _tty_rx_buf[channel];
148        _tty_rx_full[channel] = 0;
149        return 1;
150    }
151}
152
153//////////////////////////////////////////////////////////////////////////////
154// This function try to take the hardwired lock protecting
155// exclusive access to TTY terminal identified by the "channel" argument.
156// It enters a critical section before taking the lock, and save the SR value
157// at address defined by the "save_sr_ptr" argument.
158// It returns only when the lock has been successfully taken.
159//////////////////////////////////////////////////////////////////////////////
160void _tty_get_lock( unsigned int   channel,
161                    unsigned int * save_sr_ptr )
162{
163    if( channel >= NB_TTY_CHANNELS ) _exit();
164
165    _it_disable( save_sr_ptr );
166
167//    while ( _tty_get_register( channel, TTY_CONFIG ) ); // busy waiting
168
169    _get_lock( &_tty_lock[channel] );
170}
171
172//////////////////////////////////////////////////////////////////////////////
173// This function releases the hardwired lock protecting
174// exclusive access to TTY terminal identified by the channel argument.
175// It exit the critical section after lock release, and restore SR value
176// from address defined by the "save_sr_ptr" argument.
177//////////////////////////////////////////////////////////////////////////////
178void _tty_release_lock( unsigned int   channel,
179                        unsigned int * save_sr_ptr )
180{
181    if( channel >= NB_TTY_CHANNELS ) _exit();
182
183//    _tty_set_register( channel, TTY_CONFIG, 0 );
184
185    _release_lock( &_tty_lock[channel] );
186   
187    _it_restore( save_sr_ptr );
188}
189
190///////////////////////////////////////////////////////////////////////////////////
191// This ISR handles the IRQ signaling that the RX buffer is not empty.
192// IT can be an HWI or an SWI.
193// There is one communication buffer _tty_rx_buf[i] and one synchronisation
194// variable _tty_rx_full[i] per channel.
195// Does nothing if the TTY_RX buffer is empty, or if the kernel buffer is full
196// when the ISR is called.
197///////////////////////////////////////////////////////////////////////////////////
198void _tty_rx_isr( unsigned int irq_type,   // HWI / WTI
199                  unsigned int irq_id,     // index returned by XCU
200                  unsigned int channel )   // TTY channel
201{
202    unsigned int cluster_xy = _get_procid() / NB_PROCS_MAX;
203
204    // get TTY status
205    unsigned int status = _tty_get_register( channel, TTY_STATUS );
206
207    // check both TTY status and kernel buffer status:
208    // does nothing if kernel buffer full or tty_buffer empty
209    if ( ((status & 0x1) == 0) || 
210         (_tty_rx_full[channel] != 0) )  return;
211 
212    // reset WTI in XCU if WTI type
213    if ( irq_type == IRQ_TYPE_WTI ) 
214    {
215        unsigned int value;
216        _xcu_get_wti_value( cluster_xy, irq_id, &value );
217    }
218
219    // transfer character to kernel buffer and acknowledge TTY IRQ
220    _tty_rx_buf[channel]  = _tty_get_register( channel, TTY_READ ); 
221
222    // set kernel buffer status
223    asm volatile( "sync" );
224    _tty_rx_full[channel] = 1;
225
226#if GIET_DEBUG_IRQS  // we don't take the TTY lock to avoid deadlock
227unsigned int x              = cluster_xy >> Y_WIDTH;
228unsigned int y              = cluster_xy & ((1<<Y_WIDTH)-1);
229unsigned int lpid           = _get_procid() % NB_PROCS_MAX;
230_puts("\n[IRQS DEBUG] Processor[");
231_putd(x );
232_puts(",");
233_putd(y );
234_puts(",");
235_putd(lpid );
236_puts("] enters _tty_rx_isr() at cycle ");
237_putd(_get_proctime() );
238_puts("\n  read byte = ");
239_putx(_tty_rx_buf[channel] );
240_puts("\n");
241#endif
242
243}
244
245///////////////////////////////////////////////////////////////////////////////////
246// This ISR handles the IRQ signaling that the TX buffer is empty.
247// IT can be an HWI or an SWI.
248// There is one single multi_tty component controling all channels.
249// There is one communication buffer _tty_rx_buf[i] and one synchronisation
250// variable _tty_rx_full[i] per channel.
251// A character is lost if the buffer is full when the ISR is executed.
252///////////////////////////////////////////////////////////////////////////////////
253void _tty_tx_isr( unsigned int irq_type,   // HWI / WTI
254                  unsigned int irq_id,     // index returned by XCU
255                  unsigned int channel )   // TTY channel
256{
257    _puts("\n[GIET ERROR] the _tty_tx_isr() is not implemented\n");
258    _exit();
259}
260
261// Local Variables:
262// tab-width: 4
263// c-basic-offset: 4
264// c-file-offsets:((innamespace . 0)(inline-open . 0))
265// indent-tabs-mode: nil
266// End:
267// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
268
Note: See TracBrowser for help on using the repository browser.