Move keyboard code into kbd.c; add backspace handling.
This commit is contained in:
parent
c1bfbfa2f7
commit
f0d11fea82
4 changed files with 210 additions and 175 deletions
1
Makefile
1
Makefile
|
@ -23,6 +23,7 @@ OBJS = \
|
||||||
fs.o\
|
fs.o\
|
||||||
exec.o\
|
exec.o\
|
||||||
8253pit.o\
|
8253pit.o\
|
||||||
|
kbd.o\
|
||||||
|
|
||||||
# Cross-compiling (e.g., on Mac OS X)
|
# Cross-compiling (e.g., on Mac OS X)
|
||||||
#TOOLPREFIX = i386-jos-elf-
|
#TOOLPREFIX = i386-jos-elf-
|
||||||
|
|
328
console.c
328
console.c
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#define CRTPORT 0x3d4
|
#define CRTPORT 0x3d4
|
||||||
#define LPTPORT 0x378
|
#define LPTPORT 0x378
|
||||||
|
#define BACKSPACE 0x100
|
||||||
|
|
||||||
static ushort *crt = (ushort*)0xb8000; // CGA memory
|
static ushort *crt = (ushort*)0xb8000; // CGA memory
|
||||||
|
|
||||||
static struct spinlock console_lock;
|
static struct spinlock console_lock;
|
||||||
|
@ -27,16 +29,48 @@ lpt_putc(int c)
|
||||||
|
|
||||||
for(i = 0; !(inb(LPTPORT+1) & 0x80) && i < 12800; i++)
|
for(i = 0; !(inb(LPTPORT+1) & 0x80) && i < 12800; i++)
|
||||||
;
|
;
|
||||||
|
if(c == BACKSPACE)
|
||||||
|
c = '\b';
|
||||||
outb(LPTPORT+0, c);
|
outb(LPTPORT+0, c);
|
||||||
outb(LPTPORT+2, 0x08|0x04|0x01);
|
outb(LPTPORT+2, 0x08|0x04|0x01);
|
||||||
outb(LPTPORT+2, 0x08);
|
outb(LPTPORT+2, 0x08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cga_putc(int c)
|
||||||
|
{
|
||||||
|
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
|
static void
|
||||||
cons_putc(int c)
|
cons_putc(int c)
|
||||||
{
|
{
|
||||||
int ind;
|
|
||||||
|
|
||||||
if(panicked){
|
if(panicked){
|
||||||
cli();
|
cli();
|
||||||
for(;;)
|
for(;;)
|
||||||
|
@ -44,34 +78,7 @@ cons_putc(int c)
|
||||||
}
|
}
|
||||||
|
|
||||||
lpt_putc(c);
|
lpt_putc(c);
|
||||||
|
cga_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -99,7 +106,7 @@ printint(int xx, int base, int sgn)
|
||||||
cons_putc(buf[i]);
|
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
|
void
|
||||||
cprintf(char *fmt, ...)
|
cprintf(char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -157,6 +164,122 @@ cprintf(char *fmt, ...)
|
||||||
release(&console_lock);
|
release(&console_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
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 INPUT_BUF 128
|
||||||
|
struct {
|
||||||
|
struct spinlock lock;
|
||||||
|
char buf[INPUT_BUF];
|
||||||
|
int r; // Read index
|
||||||
|
int w; // Write index
|
||||||
|
int e; // Edit index
|
||||||
|
} input;
|
||||||
|
|
||||||
|
void
|
||||||
|
console_intr(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--;
|
||||||
|
cons_putc(BACKSPACE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case C('H'): // Backspace
|
||||||
|
if(input.e > input.w){
|
||||||
|
input.e--;
|
||||||
|
cons_putc(BACKSPACE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release(&input.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
console_read(int minor, char *dst, int n)
|
||||||
|
{
|
||||||
|
uint target;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
target = n;
|
||||||
|
acquire(&input.lock);
|
||||||
|
while(n > 0){
|
||||||
|
while(input.r == input.w){
|
||||||
|
if(cp->killed){
|
||||||
|
release(&input.lock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sleep(&input.r, &input.lock);
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
input.r--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dst++ = c;
|
||||||
|
cons_putc(c);
|
||||||
|
--n;
|
||||||
|
if(c == '\n')
|
||||||
|
break;
|
||||||
|
if(input.r >= INPUT_BUF)
|
||||||
|
input.r = 0;
|
||||||
|
}
|
||||||
|
release(&input.lock);
|
||||||
|
|
||||||
|
return target - n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
console_init(void)
|
||||||
|
{
|
||||||
|
initlock(&console_lock, "console");
|
||||||
|
initlock(&input.lock, "console input");
|
||||||
|
|
||||||
|
devsw[CONSOLE].write = console_write;
|
||||||
|
devsw[CONSOLE].read = console_read;
|
||||||
|
use_console_lock = 1;
|
||||||
|
|
||||||
|
irq_enable(IRQ_KBD);
|
||||||
|
ioapic_enable(IRQ_KBD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
panic(char *s)
|
panic(char *s)
|
||||||
{
|
{
|
||||||
|
@ -176,146 +299,3 @@ panic(char *s)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
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
|
|
||||||
kbd_intr(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';
|
|
||||||
}
|
|
||||||
|
|
||||||
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:
|
|
||||||
if(((kbd.w + 1) % KBD_BUF) != kbd.r){
|
|
||||||
kbd.buf[kbd.w++] = c;
|
|
||||||
if(kbd.w >= KBD_BUF)
|
|
||||||
kbd.w = 0;
|
|
||||||
wakeup(&kbd.r);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
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){
|
|
||||||
if(cp->killed){
|
|
||||||
release(&kbd.lock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sleep(&kbd.r, &kbd.lock);
|
|
||||||
}
|
|
||||||
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
|
|
||||||
console_init(void)
|
|
||||||
{
|
|
||||||
initlock(&console_lock, "console");
|
|
||||||
initlock(&kbd.lock, "kbd");
|
|
||||||
|
|
||||||
devsw[CONSOLE].write = console_write;
|
|
||||||
devsw[CONSOLE].read = console_read;
|
|
||||||
use_console_lock = 1;
|
|
||||||
|
|
||||||
irq_enable(IRQ_KBD);
|
|
||||||
ioapic_enable(IRQ_KBD, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
5
defs.h
5
defs.h
|
@ -19,7 +19,7 @@ void bwrite(struct buf*);
|
||||||
// console.c
|
// console.c
|
||||||
void console_init(void);
|
void console_init(void);
|
||||||
void cprintf(char*, ...);
|
void cprintf(char*, ...);
|
||||||
void kbd_intr(void);
|
void console_intr(int(*)(void));
|
||||||
void panic(char*) __attribute__((noreturn));
|
void panic(char*) __attribute__((noreturn));
|
||||||
|
|
||||||
// exec.c
|
// exec.c
|
||||||
|
@ -67,6 +67,9 @@ char* kalloc(int);
|
||||||
void kfree(char*, int);
|
void kfree(char*, int);
|
||||||
void kinit(void);
|
void kinit(void);
|
||||||
|
|
||||||
|
// kbd.c
|
||||||
|
void kbd_intr(void);
|
||||||
|
|
||||||
// lapic.c
|
// lapic.c
|
||||||
int cpu(void);
|
int cpu(void);
|
||||||
extern volatile uint* lapic;
|
extern volatile uint* lapic;
|
||||||
|
|
51
kbd.c
Normal file
51
kbd.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue