diff options
Diffstat (limited to '')
-rw-r--r-- | kernel/old/sio.c | 694 |
1 files changed, 0 insertions, 694 deletions
diff --git a/kernel/old/sio.c b/kernel/old/sio.c deleted file mode 100644 index a5c7b75..0000000 --- a/kernel/old/sio.c +++ /dev/null @@ -1,694 +0,0 @@ -/** -** @file sio.c -** -** @author Warren R. Carithers -** -** @brief SIO module -** -** For maximum compatibility from semester to semester, this code uses -** several "stand-in" type names and macros which should be defined -** in the accompanying "compat.h" header file if they're not part of -** the baseline system: -** -** standard-sized integer types: intN_t, uintN_t -** other types: PCBTYPE, QTYPE -** scheduler functions: SCHED, DISPATCH -** queue functions: QCREATE, QLENGTH, QDEQUE -** other functions: SLENGTH -** sio read queue: QNAME -** -** Our SIO scheme is very simple: -** -** Input: We maintain a buffer of incoming characters that haven't -** yet been read by processes. When a character comes in, if -** there is no process waiting for it, it goes in the buffer; -** otherwise, the first waiting process is awakeneda and it -** gets the character. -** -** When a process invokes readch(), if there is a character in -** the input buffer, the process gets it; otherwise, it is -** blocked until input appears -** -** Communication with system calls is via two routines. -** sio_readc() returns the first available character (if -** there is one), resetting the input variables if this was -** the last character in the buffer. If there are no -** characters in the buffer, sio_read() returns a -1 -** (presumably so the requesting process can be blocked). -** -** sio_read() copies the contents of the input buffer into -** a user-supplied buffer. It returns the number of characters -** copied. If there are no characters available, return a -1. -** -** Output: We maintain a buffer of outgoing characters that haven't -** yet been sent to the device, and an indication of whether -** or not we are in the middle of a transmit sequence. When -** an interrupt comes in, if there is another character to -** send we copy it to the transmitter buffer; otherwise, we -** end the transmit sequence. -** -** Communication with user processes is via three functions. -** sio_writec() writes a single character; sio_write() -** writes a sized buffer full of characters; sio_puts() -** prints a NUL-terminated string. If we are in the middle -** of a transmit sequence, all characters will be added -** to the output buffer (from where they will be sent -** automatically); otherwise, we send the first character -** directly, add the rest of the characters (if there are -** any) to the output buffer, and set the "sending" flag -** to indicate that we're expecting a transmitter interrupt. -*/ - -#define KERNEL_SRC - -// this should do all includes required for this OS -#include <compat.h> - -// all other framework includes are next -#include <x86/uart.h> -#include <x86/arch.h> -#include <x86/pic.h> - -#include <sio.h> -#include <lib.h> - -/* -** PRIVATE DEFINITIONS -*/ - -#define BUF_SIZE 2048 - -/* -** PRIVATE GLOBALS -*/ - - // input character buffer -static char inbuffer[ BUF_SIZE ]; -static char *inlast; -static char *innext; -static uint32_t incount; - - // output character buffer -static char outbuffer[ BUF_SIZE ]; -static char *outlast; -static char *outnext; -static uint32_t outcount; - - // output control flag -static int sending; - - // interrupt register status -static uint8_t ier; - -/* -** PUBLIC GLOBAL VARIABLES -*/ - -// queue for read-blocked processes -#ifdef QNAME -QTYPE QNAME; -#endif - -/* -** PRIVATE FUNCTIONS -*/ - -/** -** sio_isr(vector,ecode) -** -** Interrupt handler for the SIO module. Handles all pending -** events (as described by the SIO controller). -** -** @param vector The interrupt vector number for this interrupt -** @param ecode The error code associated with this interrupt -*/ -static void sio_isr( int vector, int ecode ) { - int ch; - -#if TRACING_SIO_ISR - cio_puts( "SIO: int:" ); -#endif - // - // Must process all pending events; loop until the IRR - // says there's nothing else to do. - // - - for(;;) { - - // get the "pending event" indicator - int iir = inb( UA4_IIR ) & UA4_IIR_INT_PRI_MASK; - - // process this event - switch( iir ) { - - case UA4_IIR_LINE_STATUS: - // shouldn't happen, but just in case.... - cio_printf( "** SIO int, LSR = %02x\n", inb(UA4_LSR) ); - break; - - case UA4_IIR_RX: -#if TRACING_SIO_ISR - cio_puts( " RX" ); -#endif - // get the character - ch = inb( UA4_RXD ); - if( ch == '\r' ) { // map CR to LF - ch = '\n'; - } -#if TRACING_SIO_ISR - cio_printf( " ch %02x", ch ); -#endif - -#ifdef QNAME - // - // If there is a waiting process, this must be - // the first input character; give it to that - // process and awaken the process. - // - - if( !QEMPTY(QNAME) ) { - PCBTYPE *pcb; - - QDEQUE( QNAME, pcb ); - // make sure we got a non-NULL result - assert( pcb ); - - // return char via arg #2 and count in EAX - char *buf = (char *) ARG(pcb,2); - *buf = ch & 0xff; - RET(pcb) = 1; - SCHED( pcb ); - - } else { -#endif /* QNAME */ - - // - // Nobody waiting - add to the input buffer - // if there is room, otherwise just ignore it. - // - - if( incount < BUF_SIZE ) { - *inlast++ = ch; - ++incount; - } - -#ifdef QNAME - } -#endif /* QNAME */ - break; - - case UA5_IIR_RX_FIFO: - // shouldn't happen, but just in case.... - ch = inb( UA4_RXD ); - cio_printf( "** SIO FIFO timeout, RXD = %02x\n", ch ); - break; - - case UA4_IIR_TX: -#if TRACING_SIO_ISR - cio_puts( " TX" ); -#endif - // if there is another character, send it - if( sending && outcount > 0 ) { -#if TRACING_SIO_ISR - cio_printf( " ch %02x", *outnext ); -#endif - outb( UA4_TXD, *outnext ); - ++outnext; - // wrap around if necessary - if( outnext >= (outbuffer + BUF_SIZE) ) { - outnext = outbuffer; - } - --outcount; -#if TRACING_SIO_ISR - cio_printf( " (outcount %d)", outcount ); -#endif - } else { -#if TRACING_SIO_ISR - cio_puts( " EOS" ); -#endif - // no more data - reset the output vars - outcount = 0; - outlast = outnext = outbuffer; - sending = 0; - // disable TX interrupts - sio_disable( SIO_TX ); - } - break; - - case UA4_IIR_NO_INT: -#if TRACING_SIO_ISR - cio_puts( " EOI\n" ); -#endif - // nothing to do - tell the PIC we're done - outb( PIC1_CMD, PIC_EOI ); - return; - - case UA4_IIR_MODEM_STATUS: - // shouldn't happen, but just in case.... - cio_printf( "** SIO int, MSR = %02x\n", inb(UA4_MSR) ); - break; - - default: - // uh-oh.... - sprint( b256, "sio isr: IIR %02x\n", ((uint32_t) iir) & 0xff ); - PANIC( 0, b256 ); - } - - } - - // should never reach this point! - assert( false ); -} - -/* -** PUBLIC FUNCTIONS -*/ - -/** -** sio_init() -** -** Initialize the UART chip. -*/ -void sio_init( void ) { - -#if TRACING_INIT - cio_puts( " Sio" ); -#endif - - /* - ** Initialize SIO variables. - */ - - memclr( (void *) inbuffer, sizeof(inbuffer) ); - inlast = innext = inbuffer; - incount = 0; - - memclr( (void *) outbuffer, sizeof(outbuffer) ); - outlast = outnext = outbuffer; - outcount = 0; - sending = 0; - - // queue of read-blocked processes - QCREATE( QNAME ); - - /* - ** Next, initialize the UART. - ** - ** Initialize the FIFOs - ** - ** this is a bizarre little sequence of operations - */ - - outb( UA5_FCR, 0x20 ); - outb( UA5_FCR, UA5_FCR_FIFO_RESET ); // 0x00 - outb( UA5_FCR, UA5_FCR_FIFO_EN ); // 0x01 - outb( UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR ); // 0x03 - outb( UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR | UA5_FCR_TXSR ); // 0x07 - - /* - ** disable interrupts - ** - ** note that we leave them disabled; sio_enable() must be - ** called to switch them back on - */ - - outb( UA4_IER, 0 ); - ier = 0; - - /* - ** select the divisor latch registers and set the data rate - */ - - outb( UA4_LCR, UA4_LCR_DLAB ); - outb( UA4_DLL, BAUD_LOW_BYTE( DL_BAUD_9600 ) ); - outb( UA4_DLM, BAUD_HIGH_BYTE( DL_BAUD_9600 ) ); - - /* - ** deselect the latch registers, by setting the data - ** characteristics in the LCR - */ - - outb( UA4_LCR, UA4_LCR_WLS_8 | UA4_LCR_1_STOP_BIT | UA4_LCR_NO_PARITY ); - - /* - ** Set the ISEN bit to enable the interrupt request signal, - ** and the DTR and RTS bits to enable two-way communication. - */ - - outb( UA4_MCR, UA4_MCR_ISEN | UA4_MCR_DTR | UA4_MCR_RTS ); - - /* - ** Install our ISR - */ - - install_isr( VEC_COM1, sio_isr ); -} - -/** -** sio_enable() -** -** Enable SIO interrupts -** -** usage: uint8_t old = sio_enable( uint8_t which ) -** -** @param which Bit mask indicating which interrupt(s) to enable -** -** @return the prior IER setting -*/ -uint8_t sio_enable( uint8_t which ) { - uint8_t old; - - // remember the current status - - old = ier; - - // figure out what to enable - - if( which & SIO_TX ) { - ier |= UA4_IER_TX_IE; - } - - if( which & SIO_RX ) { - ier |= UA4_IER_RX_IE; - } - - // if there was a change, make it - - if( old != ier ) { - outb( UA4_IER, ier ); - } - - // return the prior settings - - return( old ); -} - -/** -** sio_disable() -** -** Disable SIO interrupts -** -** usage: uint8_t old = sio_disable( uint8_t which ) -** -** @param which Bit mask indicating which interrupt(s) to disable -** -** @return the prior IER setting -*/ -uint8_t sio_disable( uint8_t which ) { - uint8_t old; - - // remember the current status - - old = ier; - - // figure out what to disable - - if( which & SIO_TX ) { - ier &= ~UA4_IER_TX_IE; - } - - if( which & SIO_RX ) { - ier &= ~UA4_IER_RX_IE; - } - - // if there was a change, make it - - if( old != ier ) { - outb( UA4_IER, ier ); - } - - // return the prior settings - - return( old ); -} - -/** -** sio_inq_length() -** -** Get the input queue length -** -** usage: int num = sio_inq_length() -** -** @return the count of characters still in the input queue -*/ -int sio_inq_length( void ) { - return( incount ); -} - -/** -** sio_readc() -** -** Get the next input character -** -** usage: int ch = sio_readc() -** -** @return the next character, or -1 if no character is available -*/ -int sio_readc( void ) { - int ch; - - // assume there is no character available - ch = -1; - - // - // If there is a character, return it - // - - if( incount > 0 ) { - - // take it out of the input buffer - ch = ((int)(*innext++)) & 0xff; - --incount; - - // reset the buffer variables if this was the last one - if( incount < 1 ) { - inlast = innext = inbuffer; - } - - } - - return( ch ); - -} - -/** -** sio_read(buf,length) -** -** Read the entire input buffer into a user buffer of a specified size -** -** usage: int num = sio_read( char *buffer, int length ) -** -** @param buf The destination buffer -** @param length Length of the buffer -** -** @return the number of bytes copied, or 0 if no characters were available -*/ - -int sio_read( char *buf, int length ) { - char *ptr = buf; - int copied = 0; - - // if there are no characters, just return 0 - - if( incount < 1 ) { - return( 0 ); - } - - // - // We have characters. Copy as many of them into the user - // buffer as will fit. - // - - while( incount > 0 && copied < length ) { - *ptr++ = *innext++ & 0xff; - if( innext > (inbuffer + BUF_SIZE) ) { - innext = inbuffer; - } - --incount; - ++copied; - } - - // reset the input buffer if necessary - - if( incount < 1 ) { - inlast = innext = inbuffer; - } - - // return the copy count - - return( copied ); -} - - -/** -** sio_writec( ch ) -** -** Write a character to the serial output -** -** usage: sio_writec( int ch ) -** -** @param ch Character to be written (in the low-order 8 bits) -*/ -void sio_writec( int ch ){ - - - // - // Must do LF -> CRLF mapping - // - - if( ch == '\n' ) { - sio_writec( '\r' ); - } - - // - // If we're currently transmitting, just add this to the buffer - // - - if( sending ) { - *outlast++ = ch; - ++outcount; - return; - } - - // - // Not sending - must prime the pump - // - - sending = 1; - outb( UA4_TXD, ch ); - - // Also must enable transmitter interrupts - - sio_enable( SIO_TX ); - -} - -/** -** sio_write( buffer, length ) -** -** Write a buffer of characters to the serial output -** -** usage: int num = sio_write( const char *buffer, int length ) -** -** @param buffer Buffer containing characters to write -** @param length Number of characters to write -** -** @return the number of characters copied into the SIO output buffer -*/ -int sio_write( const char *buffer, int length ) { - int first = *buffer; - const char *ptr = buffer; - int copied = 0; - - // - // If we are currently sending, we want to append all - // the characters to the output buffer; else, we want - // to append all but the first character, and then use - // sio_writec() to send the first one out. - // - - if( !sending ) { - ptr += 1; - copied++; - } - - while( copied < length && outcount < BUF_SIZE ) { - *outlast++ = *ptr++; - // wrap around if necessary - if( outlast >= (outbuffer + BUF_SIZE) ) { - outlast = outbuffer; - } - ++outcount; - ++copied; - } - - // - // We use sio_writec() to send out the first character, - // as it will correctly set all the other necessary - // variables for us. - // - - if( !sending ) { - sio_writec( first ); - } - - // Return the transfer count - - - return( copied ); - -} - -/** -** sio_puts( buf ) -** -** Write a NUL-terminated buffer of characters to the serial output -** -** usage: int num = sio_puts( const char *buffer ) -** -** @param buffer The buffer containing a NUL-terminated string -** -** @return the count of bytes transferred -*/ -int sio_puts( const char *buffer ) { - int n; // must be outside the loop so we can return it - - n = SLENGTH( buffer ); - sio_write( buffer, n ); - - return( n ); -} - -/** -** sio_dump( full ) -** -** dump the contents of the SIO buffers to the console -** -** usage: sio_dump(true) or sio_dump(false) -** -** @param full Boolean indicating whether or not a "full" dump -** is being requested (which includes the contents -** of the queues) -*/ - -void sio_dump( bool_t full ) { - int n; - char *ptr; - - // dump basic info into the status region - - cio_printf_at( 48, 0, - "SIO: IER %02x (%c%c%c) in %d ot %d", - ((uint32_t)ier) & 0xff, sending ? '*' : '.', - (ier & UA4_IER_TX_IE) ? 'T' : 't', - (ier & UA4_IER_RX_IE) ? 'R' : 'r', - incount, outcount ); - - // if we're not doing a full dump, stop now - - if( !full ) { - return; - } - - // also want the queue contents, but we'll - // dump them into the scrolling region - - if( incount ) { - cio_puts( "SIO input queue: \"" ); - ptr = innext; - for( n = 0; n < incount; ++n ) { - put_char_or_code( *ptr++ ); - } - cio_puts( "\"\n" ); - } - - if( outcount ) { - cio_puts( "SIO output queue: \"" ); - cio_puts( " ot: \"" ); - ptr = outnext; - for( n = 0; n < outcount; ++n ) { - put_char_or_code( *ptr++ ); - } - cio_puts( "\"\n" ); - } -} |