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

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

Bug fix in both _tty_rx_isr() and _bdv_isr():
The ISR must do nothing it the status indicates that
there is no pending ISR.

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