summaryrefslogtreecommitdiff
path: root/kernel/sio.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-03 12:31:21 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-03 12:31:21 -0400
commita524eb3846aac4d1b38f08cba49ff3503107042f (patch)
treedbe81fccf975f646a681e4fdcebd227cdfb98774 /kernel/sio.c
parentnew libs (diff)
downloadcomus-a524eb3846aac4d1b38f08cba49ff3503107042f.tar.gz
comus-a524eb3846aac4d1b38f08cba49ff3503107042f.tar.bz2
comus-a524eb3846aac4d1b38f08cba49ff3503107042f.zip
move old kernel code (for now) into kernel/old, trying to get long mode
Diffstat (limited to 'kernel/sio.c')
-rw-r--r--kernel/sio.c690
1 files changed, 0 insertions, 690 deletions
diff --git a/kernel/sio.c b/kernel/sio.c
deleted file mode 100644
index 8bcc8a1..0000000
--- a/kernel/sio.c
+++ /dev/null
@@ -1,690 +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
-extern 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");
- }
-}