summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsc <rsc>2007-08-28 03:28:13 +0000
committerrsc <rsc>2007-08-28 03:28:13 +0000
commitf0d11fea8251ef959cf1197b62e523922855df3a (patch)
treec1ac5b50ec8cffb2e46636a6b5569f758dcaf8ae
parentc1bfbfa2f7b995ee38ef138ca3250274213dc010 (diff)
downloadxv6-labs-f0d11fea8251ef959cf1197b62e523922855df3a.tar.gz
xv6-labs-f0d11fea8251ef959cf1197b62e523922855df3a.tar.bz2
xv6-labs-f0d11fea8251ef959cf1197b62e523922855df3a.zip
Move keyboard code into kbd.c; add backspace handling.
-rw-r--r--Makefile1
-rw-r--r--console.c236
-rw-r--r--defs.h5
-rw-r--r--kbd.c51
4 files changed, 164 insertions, 129 deletions
diff --git a/Makefile b/Makefile
index cde81e5..7e05cfc 100644
--- a/Makefile
+++ b/Makefile
@@ -23,6 +23,7 @@ OBJS = \
fs.o\
exec.o\
8253pit.o\
+ kbd.o\
# Cross-compiling (e.g., on Mac OS X)
#TOOLPREFIX = i386-jos-elf-
diff --git a/console.c b/console.c
index 3e45e3e..b7fd56e 100644
--- a/console.c
+++ b/console.c
@@ -11,6 +11,8 @@
#define CRTPORT 0x3d4
#define LPTPORT 0x378
+#define BACKSPACE 0x100
+
static ushort *crt = (ushort*)0xb8000; // CGA memory
static struct spinlock console_lock;
@@ -27,16 +29,48 @@ lpt_putc(int c)
for(i = 0; !(inb(LPTPORT+1) & 0x80) && i < 12800; i++)
;
+ if(c == BACKSPACE)
+ c = '\b';
outb(LPTPORT+0, c);
outb(LPTPORT+2, 0x08|0x04|0x01);
outb(LPTPORT+2, 0x08);
}
static void
-cons_putc(int c)
+cga_putc(int c)
{
- int ind;
+ int pos;
+
+ // Cursor position: col + 80*row.
+ outb(CRTPORT, 14);
+ pos = inb(CRTPORT+1) << 8;
+ outb(CRTPORT, 15);
+ pos |= inb(CRTPORT+1);
+
+ if(c == '\n')
+ pos += 80 - pos%80;
+ else if(c == BACKSPACE){
+ if(pos > 0)
+ crt[--pos] = ' ' | 0x0700;
+ }else
+ crt[pos++] = (c&0xff) | 0x0700; // black on white
+
+ if((pos/80) >= 24){ // Scroll up.
+ memmove(crt, crt+80, sizeof(crt[0])*23*80);
+ pos -= 80;
+ memset(crt+pos, 0, sizeof(crt[0])*(24*80 - pos));
+ }
+
+ outb(CRTPORT, 14);
+ outb(CRTPORT+1, pos>>8);
+ outb(CRTPORT, 15);
+ outb(CRTPORT+1, pos);
+ crt[pos] = ' ' | 0x0700;
+}
+static void
+cons_putc(int c)
+{
if(panicked){
cli();
for(;;)
@@ -44,34 +78,7 @@ cons_putc(int c)
}
lpt_putc(c);
-
- // cursor position, 16 bits, col + 80*row
- outb(CRTPORT, 14);
- ind = inb(CRTPORT + 1) << 8;
- outb(CRTPORT, 15);
- ind |= inb(CRTPORT + 1);
-
- c &= 0xff;
- if(c == '\n'){
- ind -= (ind % 80);
- ind += 80;
- } else {
- c |= 0x0700; // black on white
- crt[ind] = c;
- ind++;
- }
-
- if((ind / 80) >= 24){
- // scroll up
- memmove(crt, crt + 80, sizeof(crt[0]) * (23 * 80));
- ind -= 80;
- memset(crt + ind, 0, sizeof(crt[0]) * ((24 * 80) - ind));
- }
-
- outb(CRTPORT, 14);
- outb(CRTPORT + 1, ind >> 8);
- outb(CRTPORT, 15);
- outb(CRTPORT + 1, ind);
+ cga_putc(c);
}
void
@@ -99,7 +106,7 @@ printint(int xx, int base, int sgn)
cons_putc(buf[i]);
}
-// Print to the console. only understands %d, %x, %p, %s.
+// Print to the input. only understands %d, %x, %p, %s.
void
cprintf(char *fmt, ...)
{
@@ -157,25 +164,6 @@ cprintf(char *fmt, ...)
release(&console_lock);
}
-void
-panic(char *s)
-{
- int i;
- uint pcs[10];
-
- __asm __volatile("cli");
- use_console_lock = 0;
- cprintf("panic (%d): ", cpu());
- cprintf(s, 0);
- cprintf("\n", 0);
- getcallerpcs(&s, pcs);
- for(i=0; i<10; i++)
- cprintf(" %p", pcs[i]);
- panicked = 1; // freeze other CPU
- for(;;)
- ;
-}
-
int
console_write(int minor, char *buf, int n)
{
@@ -189,86 +177,57 @@ console_write(int minor, char *buf, int n)
return n;
}
-#define KBD_BUF 64
+#define INPUT_BUF 128
struct {
- uchar buf[KBD_BUF];
- int r;
- int w;
struct spinlock lock;
-} kbd;
+ char buf[INPUT_BUF];
+ int r; // Read index
+ int w; // Write index
+ int e; // Edit index
+} input;
void
-kbd_intr(void)
+console_intr(int (*getc)(void))
{
- static uint shift;
- static uchar *charcode[4] = {
- normalmap,
- shiftmap,
- ctlmap,
- ctlmap
- };
- uint st, data, c;
-
- acquire(&kbd.lock);
-
- st = inb(KBSTATP);
- if((st & KBS_DIB) == 0)
- goto out;
- data = inb(KBDATAP);
-
- if(data == 0xE0) {
- shift |= E0ESC;
- goto out;
- } else if(data & 0x80) {
- // Key released
- data = (shift & E0ESC ? data : data & 0x7F);
- shift &= ~(shiftcode[data] | E0ESC);
- goto out;
- } else if(shift & E0ESC) {
- // Last character was an E0 escape; or with 0x80
- data |= 0x80;
- shift &= ~E0ESC;
- }
-
- shift |= shiftcode[data];
- shift ^= togglecode[data];
-
- c = charcode[shift & (CTL | SHIFT)][data];
- if(shift & CAPSLOCK) {
- if('a' <= c && c <= 'z')
- c += 'A' - 'a';
- else if('A' <= c && c <= 'Z')
- c += 'a' - 'A';
- }
+ int c;
- switch(c){
- case 0:
- // Ignore unknown keystrokes.
- break;
+ 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--;
+ cons_putc(BACKSPACE);
+ }
+ break;
- case C('T'):
- cprintf("#"); // Let user know we're still alive.
- break;
+ case C('H'): // Backspace
+ if(input.e > input.w){
+ input.e--;
+ cons_putc(BACKSPACE);
+ }
+ break;
- case C('P'):
- procdump();
- break;
-
- default:
- if(((kbd.w + 1) % KBD_BUF) != kbd.r){
- kbd.buf[kbd.w++] = c;
- if(kbd.w >= KBD_BUF)
- kbd.w = 0;
- wakeup(&kbd.r);
+ default:
+ if(c != 0 && input.e < input.r+INPUT_BUF){
+ input.buf[input.e++] = c;
+ cons_putc(c);
+ if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
+ input.w = input.e;
+ wakeup(&input.r);
+ }
+ }
+ break;
}
- break;
}
-
-out:
- release(&kbd.lock);
+ release(&input.lock);
}
-//PAGEBREAK: 25
int
console_read(int minor, char *dst, int n)
{
@@ -276,31 +235,33 @@ console_read(int minor, char *dst, int n)
int c;
target = n;
- acquire(&kbd.lock);
+ acquire(&input.lock);
while(n > 0){
- while(kbd.r == kbd.w){
+ while(input.r == input.w){
if(cp->killed){
- release(&kbd.lock);
+ release(&input.lock);
return -1;
}
- sleep(&kbd.r, &kbd.lock);
+ sleep(&input.r, &input.lock);
}
- c = kbd.buf[kbd.r++];
+ c = input.buf[input.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--;
+ input.r--;
}
break;
}
*dst++ = c;
cons_putc(c);
--n;
- if(kbd.r >= KBD_BUF)
- kbd.r = 0;
+ if(c == '\n')
+ break;
+ if(input.r >= INPUT_BUF)
+ input.r = 0;
}
- release(&kbd.lock);
+ release(&input.lock);
return target - n;
}
@@ -309,7 +270,7 @@ void
console_init(void)
{
initlock(&console_lock, "console");
- initlock(&kbd.lock, "kbd");
+ initlock(&input.lock, "console input");
devsw[CONSOLE].write = console_write;
devsw[CONSOLE].read = console_read;
@@ -319,3 +280,22 @@ console_init(void)
ioapic_enable(IRQ_KBD, 0);
}
+void
+panic(char *s)
+{
+ int i;
+ uint pcs[10];
+
+ __asm __volatile("cli");
+ use_console_lock = 0;
+ cprintf("panic (%d): ", cpu());
+ cprintf(s, 0);
+ cprintf("\n", 0);
+ getcallerpcs(&s, pcs);
+ for(i=0; i<10; i++)
+ cprintf(" %p", pcs[i]);
+ panicked = 1; // freeze other CPU
+ for(;;)
+ ;
+}
+
diff --git a/defs.h b/defs.h
index 7ed89ef..40f34b1 100644
--- a/defs.h
+++ b/defs.h
@@ -19,7 +19,7 @@ void bwrite(struct buf*);
// console.c
void console_init(void);
void cprintf(char*, ...);
-void kbd_intr(void);
+void console_intr(int(*)(void));
void panic(char*) __attribute__((noreturn));
// exec.c
@@ -67,6 +67,9 @@ char* kalloc(int);
void kfree(char*, int);
void kinit(void);
+// kbd.c
+void kbd_intr(void);
+
// lapic.c
int cpu(void);
extern volatile uint* lapic;
diff --git a/kbd.c b/kbd.c
new file mode 100644
index 0000000..a4dd381
--- /dev/null
+++ b/kbd.c
@@ -0,0 +1,51 @@
+#include "types.h"
+#include "x86.h"
+#include "defs.h"
+#include "kbd.h"
+
+int
+kbd_getc(void)
+{
+ static uint shift;
+ static uchar *charcode[4] = {
+ normalmap, shiftmap, ctlmap, ctlmap
+ };
+ uint st, data, c;
+
+ st = inb(KBSTATP);
+ if((st & KBS_DIB) == 0)
+ return -1;
+ data = inb(KBDATAP);
+
+ if(data == 0xE0) {
+ shift |= E0ESC;
+ return 0;
+ } else if(data & 0x80) {
+ // Key released
+ data = (shift & E0ESC ? data : data & 0x7F);
+ shift &= ~(shiftcode[data] | E0ESC);
+ return 0;
+ } else if(shift & E0ESC) {
+ // Last character was an E0 escape; or with 0x80
+ data |= 0x80;
+ shift &= ~E0ESC;
+ }
+
+ shift |= shiftcode[data];
+ shift ^= togglecode[data];
+ c = charcode[shift & (CTL | SHIFT)][data];
+ if(shift & CAPSLOCK) {
+ if('a' <= c && c <= 'z')
+ c += 'A' - 'a';
+ else if('A' <= c && c <= 'Z')
+ c += 'a' - 'A';
+ }
+ return c;
+}
+
+void
+kbd_intr(void)
+{
+ console_intr(kbd_getc);
+}
+