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\
 | 
			
		||||
	exec.o\
 | 
			
		||||
	8253pit.o\
 | 
			
		||||
	kbd.o\
 | 
			
		||||
 | 
			
		||||
# Cross-compiling (e.g., on Mac OS X)
 | 
			
		||||
#TOOLPREFIX = i386-jos-elf-
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										328
									
								
								console.c
									
										
									
									
									
								
							
							
						
						
									
										328
									
								
								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
 | 
			
		||||
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
 | 
			
		||||
cons_putc(int c)
 | 
			
		||||
{
 | 
			
		||||
  int ind;
 | 
			
		||||
 | 
			
		||||
  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,6 +164,122 @@ cprintf(char *fmt, ...)
 | 
			
		|||
    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
 | 
			
		||||
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
 | 
			
		||||
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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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…
	
	Add table
		
		Reference in a new issue