xv6-cs450/console.c

322 lines
5.3 KiB
C
Raw Normal View History

#include "types.h"
2006-06-12 17:22:12 +02:00
#include "defs.h"
2007-08-28 01:26:33 +02:00
#include "param.h"
#include "traps.h"
#include "spinlock.h"
#include "dev.h"
2006-09-07 18:52:13 +02:00
#include "mmu.h"
2007-08-08 12:29:42 +02:00
#include "proc.h"
2007-08-28 01:26:33 +02:00
#include "x86.h"
#include "kbd.h"
2007-08-24 22:28:08 +02:00
#define CRTPORT 0x3d4
#define LPTPORT 0x378
static ushort *crt = (ushort*)0xb8000; // CGA memory
static struct spinlock console_lock;
2006-07-17 03:25:22 +02:00
int panicked = 0;
int use_console_lock = 0;
2006-06-12 17:22:12 +02:00
2006-09-06 19:50:20 +02:00
// Copy console output to parallel port, which you can tell
// .bochsrc to copy to the stdout:
// parport1: enabled=1, file="/dev/stdout"
2006-06-22 17:51:57 +02:00
static void
lpt_putc(int c)
{
int i;
2006-06-22 17:51:57 +02:00
2007-08-24 22:28:08 +02:00
for(i = 0; !(inb(LPTPORT+1) & 0x80) && i < 12800; i++)
;
2007-08-24 22:28:08 +02:00
outb(LPTPORT+0, c);
outb(LPTPORT+2, 0x08|0x04|0x01);
outb(LPTPORT+2, 0x08);
2006-06-22 17:51:57 +02:00
}
static void
cons_putc(int c)
2006-06-12 17:22:12 +02:00
{
int ind;
2006-07-17 03:25:22 +02:00
if(panicked){
cli();
2006-07-17 03:25:22 +02:00
for(;;)
;
}
2006-06-22 17:51:57 +02:00
lpt_putc(c);
2006-06-12 17:22:12 +02:00
// cursor position, 16 bits, col + 80*row
2007-08-24 22:28:08 +02:00
outb(CRTPORT, 14);
ind = inb(CRTPORT + 1) << 8;
outb(CRTPORT, 15);
ind |= inb(CRTPORT + 1);
2006-06-12 17:22:12 +02:00
c &= 0xff;
if(c == '\n'){
ind -= (ind % 80);
ind += 80;
} else {
c |= 0x0700; // black on white
crt[ind] = c;
ind++;
2006-06-12 17:22:12 +02:00
}
if((ind / 80) >= 24){
// scroll up
memmove(crt, crt + 80, sizeof(crt[0]) * (23 * 80));
2006-06-12 17:22:12 +02:00
ind -= 80;
memset(crt + ind, 0, sizeof(crt[0]) * ((24 * 80) - ind));
}
2007-08-24 22:28:08 +02:00
outb(CRTPORT, 14);
outb(CRTPORT + 1, ind >> 8);
outb(CRTPORT, 15);
outb(CRTPORT + 1, ind);
}
2006-06-12 17:22:12 +02:00
void
printint(int xx, int base, int sgn)
{
2007-08-24 22:28:08 +02:00
static char digits[] = "0123456789ABCDEF";
2006-06-12 17:22:12 +02:00
char buf[16];
int i = 0, neg = 0;
uint x;
2006-09-06 19:27:19 +02:00
2006-06-12 17:22:12 +02:00
if(sgn && xx < 0){
neg = 1;
x = 0 - xx;
} else {
x = xx;
}
do {
buf[i++] = digits[x % base];
} while((x /= base) != 0);
if(neg)
buf[i++] = '-';
while(--i >= 0)
cons_putc(buf[i]);
2006-06-12 17:22:12 +02:00
}
2006-09-06 19:50:20 +02:00
// Print to the console. only understands %d, %x, %p, %s.
2006-06-12 17:22:12 +02:00
void
cprintf(char *fmt, ...)
{
int i, c, state, locking;
uint *argp;
char *s;
2006-06-12 17:22:12 +02:00
locking = use_console_lock;
if(locking)
acquire(&console_lock);
argp = (uint*)(void*)&fmt + 1;
state = 0;
2006-06-12 17:22:12 +02:00
for(i = 0; fmt[i]; i++){
c = fmt[i] & 0xff;
switch(state){
case 0:
if(c == '%')
2006-06-12 17:22:12 +02:00
state = '%';
else
cons_putc(c);
break;
case '%':
switch(c){
case 'd':
printint(*argp++, 10, 1);
break;
case 'x':
case 'p':
printint(*argp++, 16, 0);
break;
case 's':
s = (char*)*argp++;
if(s == 0)
s = "(null)";
for(; *s; s++)
cons_putc(*s);
break;
case '%':
cons_putc('%');
break;
default:
// Print unknown % sequence to draw attention.
cons_putc('%');
cons_putc(c);
break;
2006-06-12 17:22:12 +02:00
}
state = 0;
break;
2006-06-12 17:22:12 +02:00
}
}
if(locking)
release(&console_lock);
2006-06-12 17:22:12 +02:00
}
void
panic(char *s)
{
2006-09-07 18:52:13 +02:00
int i;
uint pcs[10];
__asm __volatile("cli");
use_console_lock = 0;
2006-08-15 17:53:46 +02:00
cprintf("panic (%d): ", cpu());
2006-06-12 17:22:12 +02:00
cprintf(s, 0);
cprintf("\n", 0);
2006-09-07 18:52:13 +02:00
getcallerpcs(&s, pcs);
for(i=0; i<10; i++)
cprintf(" %p", pcs[i]);
2006-07-17 03:25:22 +02:00
panicked = 1; // freeze other CPU
for(;;)
2006-06-12 17:22:12 +02:00
;
}
int
2006-09-06 19:27:19 +02:00
console_write(int minor, char *buf, int n)
{
int i;
acquire(&console_lock);
for(i = 0; i < n; i++)
cons_putc(buf[i] & 0xff);
release(&console_lock);
return n;
}
#define KBD_BUF 64
struct {
uchar buf[KBD_BUF];
int r;
int w;
struct spinlock lock;
} kbd;
void
2007-08-08 11:32:39 +02:00
kbd_intr(void)
{
static uint shift;
static uchar *charcode[4] = {
normalmap,
shiftmap,
ctlmap,
ctlmap
};
uint st, data, c;
2007-08-14 21:41:01 +02:00
acquire(&kbd.lock);
st = inb(KBSTATP);
2006-09-07 18:52:13 +02:00
if((st & KBS_DIB) == 0)
goto out;
data = inb(KBDATAP);
2006-09-06 19:27:19 +02:00
if(data == 0xE0) {
shift |= E0ESC;
2006-09-07 18:52:13 +02:00
goto out;
2006-09-06 19:27:19 +02:00
} else if(data & 0x80) {
// Key released
data = (shift & E0ESC ? data : data & 0x7F);
shift &= ~(shiftcode[data] | E0ESC);
2006-09-07 18:52:13 +02:00
goto out;
2006-09-06 19:27:19 +02:00
} else if(shift & E0ESC) {
// Last character was an E0 escape; or with 0x80
data |= 0x80;
shift &= ~E0ESC;
}
2006-09-06 19:27:19 +02:00
shift |= shiftcode[data];
shift ^= togglecode[data];
2006-09-06 19:27:19 +02:00
c = charcode[shift & (CTL | SHIFT)][data];
2006-09-06 19:27:19 +02:00
if(shift & CAPSLOCK) {
if('a' <= c && c <= 'z')
c += 'A' - 'a';
2006-09-06 19:27:19 +02:00
else if('A' <= c && c <= 'Z')
c += 'a' - 'A';
}
2006-09-07 17:45:38 +02:00
switch(c){
case 0:
// Ignore unknown keystrokes.
break;
case C('T'):
cprintf("#"); // Let user know we're still alive.
break;
case C('P'):
procdump();
break;
default:
2007-08-14 21:41:01 +02:00
if(((kbd.w + 1) % KBD_BUF) != kbd.r){
kbd.buf[kbd.w++] = c;
if(kbd.w >= KBD_BUF)
kbd.w = 0;
wakeup(&kbd.r);
2006-09-07 17:45:38 +02:00
}
break;
}
2006-09-07 18:52:13 +02:00
out:
2007-08-14 21:41:01 +02:00
release(&kbd.lock);
}
//PAGEBREAK: 25
int
console_read(int minor, char *dst, int n)
{
uint target;
int c;
target = n;
acquire(&kbd.lock);
while(n > 0){
while(kbd.r == kbd.w){
2007-08-10 18:37:27 +02:00
if(cp->killed){
release(&kbd.lock);
2007-08-08 12:29:42 +02:00
return -1;
}
sleep(&kbd.r, &kbd.lock);
2007-08-08 12:29:42 +02:00
}
c = kbd.buf[kbd.r++];
if(c == C('D')){ // EOF
if(n < target){
// Save ^D for next time, to make sure
// caller gets a 0-byte result.
kbd.r--;
}
break;
}
*dst++ = c;
cons_putc(c);
--n;
if(kbd.r >= KBD_BUF)
kbd.r = 0;
}
release(&kbd.lock);
return target - n;
}
void
2007-08-08 11:32:39 +02:00
console_init(void)
{
initlock(&console_lock, "console");
initlock(&kbd.lock, "kbd");
2006-09-07 15:08:23 +02:00
devsw[CONSOLE].write = console_write;
devsw[CONSOLE].read = console_read;
use_console_lock = 1;
2006-09-07 17:29:54 +02:00
irq_enable(IRQ_KBD);
2006-09-06 19:27:19 +02:00
ioapic_enable(IRQ_KBD, 0);
}