/////////////////////////////////////////////////////////////////////////////////// // File : tty_driver.c // Date : 23/05/2013 // Author : alain greiner // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// // The tty_driver.c and tty_drivers.h files are part ot the GIET-VM kernel. // This driver supports the SocLib vci_multi_tty component. // // It can exist only one multi_tty controler in the architecture. // // The total number of TTY terminals must be defined by the configuration // parameter NB_TTY_CHANNELS in the hard_config.h file. // // The register offsets must be defined in the hwr_mapping.h file. // // The "system" terminal is TTY[0]. // The "user" TTYs are allocated to applications by the GIET in the boot phase, // as defined in the mapping_info data structure. The corresponding tty_id must // be stored in the context of the task by the boot code. /////////////////////////////////////////////////////////////////////////////////// // The virtual base address of the segment associated to a channel is: // // seg_tty_base + TTY_SPAN * channel_id // // The seg_tty_base virtual base addresses must be defined in giet_vsegs.ld file. /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #if !defined(NB_TTY_CHANNELS) # error: You must define NB_TTY_CHANNELS in the hard_config.h file #endif #if (NB_TTY_CHANNELS < 1) # error: NB_TTY_CHANNELS cannot be smaller than 1! #endif #define in_unckdata __attribute__((section (".unckdata"))) ///////////////// TTY global variables in_unckdata volatile unsigned char _tty_get_buf[NB_TTY_CHANNELS]; in_unckdata volatile unsigned char _tty_get_full[NB_TTY_CHANNELS] = { [0 ... NB_TTY_CHANNELS - 1] = 0 }; ///////////////////////////////////////////////////////////////////////////////// // This non-blocking function writes a character string from a fixed-length // buffer to the TTY_WRITE register of a TTY terminal identified by the // channel argument. If the channel argument is 0xFFFFFFFF, the channel // index is obtained from the current taxk context. // It doesn't use any interrupt. // This is a non blocking call: it tests the TTY_STATUS register, and stops // the transfer as soon as the TTY_STATUS[WRITE] bit is set. ///////////////////////////////////////////////////////////////////////////////// // Returns the number of characters that have been written. ///////////////////////////////////////////////////////////////////////////////// unsigned int _tty_write( const char* buffer, unsigned int length, // number of characters unsigned int channel) // channel index { unsigned int nwritten; unsigned int tty_id; unsigned int* tty_address = (unsigned int *) &seg_tty_base; // compute tty channel if( channel == 0xFFFFFFFF ) { tty_id = _get_context_slot(CTX_TTY_ID); } else { tty_id = (unsigned int)channel; } // write string to TTY channel for (nwritten = 0; nwritten < length; nwritten++) { // check tty's status if ((tty_address[tty_id * TTY_SPAN + TTY_STATUS] & 0x2) == 0x2) break; _tty_write_data( tty_id, buffer[nwritten] ); } return nwritten; } ////////////////////////////////////////////////////////////////////////////// // This non-blocking function fetches one character from the // terminal identified by the channel argument. If the channel argument // is 0xFFFFFFFF, the channel index is obtained from the current task context. // It uses the TTY_GET_IRQ[tty_id] interrupt and the buffer must have been // filled by the TTY_ISR. // It test the _tty_get_full[tty_id] register, read the _tty_get_buf[tty_id] // buffer, writes this character to the target buffer, and resets the // _tty_get_full[tty_id] register. // The length argument is not used. ////////////////////////////////////////////////////////////////////////////// // Returns the number of characters that have been read (0/1). ////////////////////////////////////////////////////////////////////////////// unsigned int _tty_read( char* buffer, unsigned int length, // unused unsigned int channel) // channel index { unsigned int tty_id; // compute tty channel if( channel == 0xFFFFFFFF ) { tty_id = _get_context_slot(CTX_TTY_ID); } else { tty_id = (unsigned int)channel; } // read one character from TTY channel if (_tty_get_full[tty_id] == 0) { return 0; } else { *buffer = _tty_get_buf[tty_id]; _tty_get_full[tty_id] = 0; return 1; } } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // This function try to take the hardwired lock protecting exclusive access // to TTY terminal identified by the channel argument. // It returns only when the lock has been successfully taken. ////////////////////////////////////////////////////////////////////////////// void _tty_get_lock( unsigned int channel ) { unsigned int* tty_address = (unsigned int *) &seg_tty_base; if( channel >= NB_TTY_CHANNELS ) { _puts("[GIET ERROR] in _tty_get_lock() : illegal TTY index\n"); _exit(); } while ( tty_address[channel * TTY_SPAN + TTY_CONFIG] ); } ////////////////////////////////////////////////////////////////////////////// // This function releases the hardwired lock protecting exclusive access // to TTY terminal identified by the channel argument. ////////////////////////////////////////////////////////////////////////////// void _tty_release_lock( unsigned int channel ) { unsigned int* tty_address = (unsigned int *) &seg_tty_base; if( channel >= NB_TTY_CHANNELS ) { _puts("[GIET ERROR] in _tty_release_lock() : illegal TTY index\n"); _exit(); } tty_address[channel * TTY_SPAN + TTY_CONFIG] = 0; } ////////////////////////////////////////////////////////////////////////////// // This function returns the content of the TTY_READ register in the // TTY terminal identified by the channel argument. ////////////////////////////////////////////////////////////////////////////// unsigned int _tty_read_data( unsigned int channel ) { unsigned int* tty_address = (unsigned int *) &seg_tty_base; if( channel >= NB_TTY_CHANNELS ) { _puts("[GIET ERROR] in _tty_read_data() : illegal TTY index\n"); _exit(); } return tty_address[channel * TTY_SPAN + TTY_READ]; } ////////////////////////////////////////////////////////////////////////////// // This function returns the content of the TTY_STATUS register in the // TTY terminal identified by the channel argument. ////////////////////////////////////////////////////////////////////////////// unsigned int _tty_get_status( unsigned int channel ) { unsigned int* tty_address = (unsigned int *) &seg_tty_base; if( channel >= NB_TTY_CHANNELS ) { _puts("[GIET ERROR] in _tty_get_status() : illegal TTY index\n"); _exit(); } return tty_address[channel * TTY_SPAN + TTY_STATUS]; } ////////////////////////////////////////////////////////////////////////////// // This function writes one character in the TTY_WRITE register in the // TTY terminal identified by the channel argument. ////////////////////////////////////////////////////////////////////////////// void _tty_write_data( unsigned int channel, char byte ) { unsigned int* tty_address = (unsigned int *) &seg_tty_base; if( channel >= NB_TTY_CHANNELS ) { _puts("[GIET ERROR] in _tty_write_data() : illegal TTY index\n"); _exit(); } tty_address[channel * TTY_SPAN + TTY_WRITE] = (unsigned int) byte; } // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4