view src/console.cbc @ 41:087d7b61c86b

cbc cmake version
author kono
date Sat, 02 Mar 2019 19:01:03 +0900
parents src/console.c@a7144583914c
children 3931ac87d850
line wrap: on
line source

// Console input and output.
// Input is from the keyboard or serial port.
// Output is written to the screen and serial port.

#include "types.h"
#include "defs.h"
#include "param.h"
#include "spinlock.h"
#include "fs.h"
#include "file.h"
#include "memlayout.h"
#include "mmu.h"
#include "proc.h"

__code cbc_consoleread1 ();
__code cbc_consoleread2 ();

static void consputc (int);

static int panicked = 0;

static struct {
    struct spinlock lock;
    int locking;
} cons;

static void printint (int xx, int base, int sign)
{
    static char digits[] = "0123456789abcdef";
    char buf[16];
    int i;
    uint x;

    if (sign && (sign = xx < 0)) {
        x = -xx;
    } else {
        x = xx;
    }

    i = 0;

    do {
        buf[i++] = digits[x % base];
    } while ((x /= base) != 0);

    if (sign) {
        buf[i++] = '-';
    }

    while (--i >= 0) {
        consputc(buf[i]);
    }
}
//PAGEBREAK: 50

// Print to the console. only understands %d, %x, %p, %s.
void cprintf (char *fmt, ...)
{
    int i, c, locking;
    uint *argp;
    char *s;

    locking = cons.locking;

    if (locking) {
        acquire(&cons.lock);
    }

    if (fmt == 0) {
        panic("null fmt");
    }

    argp = (uint*) (void*) (&fmt + 1);

    for (i = 0; (c = fmt[i] & 0xff) != 0; i++) {
        if (c != '%') {
            consputc(c);
            continue;
        }

        c = fmt[++i] & 0xff;

        if (c == 0) {
            break;
        }

        switch (c) {
        case 'd':
            printint(*argp++, 10, 1);
            break;

        case 'x':
        case 'p':
            printint(*argp++, 16, 0);
            break;

        case 's':
            if ((s = (char*) *argp++) == 0) {
                s = "(null)";
            }

            for (; *s; s++) {
                consputc(*s);
            }
            break;

        case '%':
            consputc('%');
            break;

        default:
            // Print unknown % sequence to draw attention.
            consputc('%');
            consputc(c);
            break;
        }
    }

    if (locking) {
        release(&cons.lock);
    }
}

__code cbc_panic (char *s)
{
    cli();

    cons.locking = 0;

    cprintf("cpu%d: panic: ", cpu->id);

    show_callstk(s);
    panicked = 1; // freeze other CPU

    while (1)
        ;
}

void panic (char *s)
{
    cli();

    cons.locking = 0;

    cprintf("cpu%d: panic: ", cpu->id);

    show_callstk(s);
    panicked = 1; // freeze other CPU

    while (1)
        ;
}

//PAGEBREAK: 50
#define BACKSPACE 0x100
#define CRTPORT 0x3d4

void consputc (int c)
{
    if (panicked) {
        cli();
        while (1)
            ;
    }

    if (c == BACKSPACE) {
        uartputc('\b');
        uartputc(' ');
        uartputc('\b');
    } else {
        uartputc(c);
    }

    // cgaputc(c);
}

#define INPUT_BUF 512
struct {
    struct spinlock lock;
    char buf[INPUT_BUF];
    uint r;  // Read index
    uint w;  // Write index
    uint e;  // Edit index
} input;

#define C(x)  ((x)-'@')  // Control-x
void consoleintr (int (*getc) (void))
{
    int c;

    acquire(&input.lock);

    while ((c = getc()) >= 0) {
        switch (c) {
        case C('P'):  // Process listing.
            procdump();
            break;

        case C('U'):  // Kill line.
            while ((input.e != input.w) && (input.buf[(input.e - 1) % INPUT_BUF] != '\n')) {
                input.e--;
                consputc(BACKSPACE);
            }

            break;

        case C('H'):
        case '\x7f':  // Backspace
            if (input.e != input.w) {
                input.e--;
                consputc(BACKSPACE);
            }

            break;

        default:
            if ((c != 0) && (input.e - input.r < INPUT_BUF)) {
                c = (c == '\r') ? '\n' : c;

                input.buf[input.e++ % INPUT_BUF] = c;
                consputc(c);

                if (c == '\n' || c == C('D') || input.e == input.r + INPUT_BUF) {
                    input.w = input.e;
                    wakeup(&input.r);
                }
            }

            break;
        }
    }

    release(&input.lock);
}

__code cbc_consoleread2 ()
{
    struct inode *ip = proc->cbc_arg.cbc_console_arg.ip;
    __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next;
    if (input.r == input.w) {
        if (proc->killed) {
            release(&input.lock);
            ilock(ip);
            goto next(-1);
        }
       goto cbc_sleep(&input.r, &input.lock, cbc_consoleread2);
    }
    goto cbc_consoleread1();
}

__code cbc_consoleread1 ()
{
    int cont = 1;
    int n = proc->cbc_arg.cbc_console_arg.n;
    int target = proc->cbc_arg.cbc_console_arg.target;
    char* dst = proc->cbc_arg.cbc_console_arg.dst;
    struct inode *ip = proc->cbc_arg.cbc_console_arg.ip;
    __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next;
    
    int c = input.buf[input.r++ % INPUT_BUF];

    if (c == C('D')) {  // EOF
        if (n < target) {
            // Save ^D for next time, to make sure
            // caller gets a 0-byte result.
            input.r--;  
        }
        cont = 0;
    }

    *dst++ = c;
    --n;

    if (c == '\n') {
        cont = 0;
    }

    if (cont == 1) {
        if (n > 0) {
            proc->cbc_arg.cbc_console_arg.n = n;
            proc->cbc_arg.cbc_console_arg.target = target;
            proc->cbc_arg.cbc_console_arg.dst = dst;
            proc->cbc_arg.cbc_console_arg.ip = ip;
            proc->cbc_arg.cbc_console_arg.next = next;
            goto cbc_sleep(&input.r, &input.lock, cbc_consoleread2);
        }
    }
    
    release(&input.lock);
    ilock(ip);

    goto next(target - n);
}

__code cbc_consoleread (struct inode *ip, char *dst, int n, __code(*next)(int ret))
{
    uint target;

    iunlock(ip);

    target = n;
    acquire(&input.lock);

    if (n > 0) {
        proc->cbc_arg.cbc_console_arg.n = n;
        proc->cbc_arg.cbc_console_arg.target = target;
    	proc->cbc_arg.cbc_console_arg.dst = dst;
	    proc->cbc_arg.cbc_console_arg.ip = ip;
	    proc->cbc_arg.cbc_console_arg.next = next;
        goto cbc_consoleread2();    
    }
	goto cbc_consoleread1();
}

int consoleread (struct inode *ip, char *dst, int n)
{
    uint target;
    int c;

    iunlock(ip);

    target = n;
    acquire(&input.lock);

    while (n > 0) {
        while (input.r == input.w) {
            if (proc->killed) {
                release(&input.lock);
                ilock(ip);
                return -1;
            }

            sleep(&input.r, &input.lock);
        }

        c = input.buf[input.r++ % INPUT_BUF];

        if (c == C('D')) {  // EOF
            if (n < target) {
                // Save ^D for next time, to make sure
                // caller gets a 0-byte result.
                input.r--;
            }

            break;
        }

        *dst++ = c;
        --n;

        if (c == '\n') {
            break;
        }
    }

    release(&input.lock);
    ilock(ip);

    return target - n;
}

int consolewrite (struct inode *ip, char *buf, int n)
{
    int i;

    iunlock(ip);

    acquire(&cons.lock);

    for (i = 0; i < n; i++) {
        consputc(buf[i] & 0xff);
    }

    release(&cons.lock);

    ilock(ip);

    return n;
}

void consoleinit (void)
{
    initlock(&cons.lock, "console");
    initlock(&input.lock, "input");

    devsw[CONSOLE].write = consolewrite;
    devsw[CONSOLE].read = consoleread;
    //cbc_devsw[CONSOLE].write = cbc_consolewrite;
    cbc_devsw[CONSOLE].read = cbc_consoleread;

    cons.locking = 1;
}