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

Last change on this file since 436 was 426, checked in by alain, 10 years ago

Introducing fixed format (X_WIDTH / Y_WIDTH / P_WIDTH ) for processor index.

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