root/kernel/console.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. consputc
  2. consolewrite
  3. consoleread
  4. consoleintr
  5. consoleinit

   1 //
   2 // Console input and output, to the uart.
   3 // Reads are line at a time.
   4 // Implements special input characters:
   5 //   newline -- end of line
   6 //   control-h -- backspace
   7 //   control-u -- kill line
   8 //   control-d -- end of file
   9 //   control-p -- print process list
  10 //
  11 
  12 #include <stdarg.h>
  13 
  14 #include "types.h"
  15 #include "param.h"
  16 #include "spinlock.h"
  17 #include "sleeplock.h"
  18 #include "fs.h"
  19 #include "file.h"
  20 #include "memlayout.h"
  21 #include "riscv.h"
  22 #include "defs.h"
  23 #include "proc.h"
  24 
  25 #define BACKSPACE 0x100
  26 #define C(x)  ((x)-'@')  // Control-x
  27 
  28 //
  29 // send one character to the uart.
  30 // called by printf(), and to echo input characters,
  31 // but not from write().
  32 //
  33 void
  34 consputc(int c)
  35 {
  36   if(c == BACKSPACE){
  37     // if the user typed backspace, overwrite with a space.
  38     uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');
  39   } else {
  40     uartputc_sync(c);
  41   }
  42 }
  43 
  44 struct {
  45   struct spinlock lock;
  46   
  47   // input
  48 #define INPUT_BUF_SIZE 128
  49   char buf[INPUT_BUF_SIZE];
  50   uint r;  // Read index
  51   uint w;  // Write index
  52   uint e;  // Edit index
  53 } cons;
  54 
  55 //
  56 // user write()s to the console go here.
  57 //
  58 int
  59 consolewrite(int user_src, uint64 src, int n)
  60 {
  61   int i;
  62 
  63   for(i = 0; i < n; i++){
  64     char c;
  65     if(either_copyin(&c, user_src, src+i, 1) == -1)
  66       break;
  67     uartputc(c);
  68   }
  69 
  70   return i;
  71 }
  72 
  73 //
  74 // user read()s from the console go here.
  75 // copy (up to) a whole input line to dst.
  76 // user_dist indicates whether dst is a user
  77 // or kernel address.
  78 //
  79 int
  80 consoleread(int user_dst, uint64 dst, int n)
  81 {
  82   uint target;
  83   int c;
  84   char cbuf;
  85 
  86   target = n;
  87   acquire(&cons.lock);
  88   while(n > 0){
  89     // wait until interrupt handler has put some
  90     // input into cons.buffer.
  91     while(cons.r == cons.w){
  92       if(killed(myproc())){
  93         release(&cons.lock);
  94         return -1;
  95       }
  96       sleep(&cons.r, &cons.lock);
  97     }
  98 
  99     c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
 100 
 101     if(c == C('D')){  // end-of-file
 102       if(n < target){
 103         // Save ^D for next time, to make sure
 104         // caller gets a 0-byte result.
 105         cons.r--;
 106       }
 107       break;
 108     }
 109 
 110     // copy the input byte to the user-space buffer.
 111     cbuf = c;
 112     if(either_copyout(user_dst, dst, &cbuf, 1) == -1)
 113       break;
 114 
 115     dst++;
 116     --n;
 117 
 118     if(c == '\n'){
 119       // a whole line has arrived, return to
 120       // the user-level read().
 121       break;
 122     }
 123   }
 124   release(&cons.lock);
 125 
 126   return target - n;
 127 }
 128 
 129 //
 130 // the console input interrupt handler.
 131 // uartintr() calls this for input character.
 132 // do erase/kill processing, append to cons.buf,
 133 // wake up consoleread() if a whole line has arrived.
 134 //
 135 void
 136 consoleintr(int c)
 137 {
 138   acquire(&cons.lock);
 139 
 140   switch(c){
 141   case C('P'):  // Print process list.
 142     procdump();
 143     break;
 144   case C('U'):  // Kill line.
 145     while(cons.e != cons.w &&
 146           cons.buf[(cons.e-1) % INPUT_BUF_SIZE] != '\n'){
 147       cons.e--;
 148       consputc(BACKSPACE);
 149     }
 150     break;
 151   case C('H'): // Backspace
 152   case '\x7f': // Delete key
 153     if(cons.e != cons.w){
 154       cons.e--;
 155       consputc(BACKSPACE);
 156     }
 157     break;
 158   default:
 159     if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){
 160       c = (c == '\r') ? '\n' : c;
 161 
 162       // echo back to the user.
 163       consputc(c);
 164 
 165       // store for consumption by consoleread().
 166       cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
 167 
 168       if(c == '\n' || c == C('D') || cons.e-cons.r == INPUT_BUF_SIZE){
 169         // wake up consoleread() if a whole line (or end-of-file)
 170         // has arrived.
 171         cons.w = cons.e;
 172         wakeup(&cons.r);
 173       }
 174     }
 175     break;
 176   }
 177   
 178   release(&cons.lock);
 179 }
 180 
 181 void
 182 consoleinit(void)
 183 {
 184   initlock(&cons.lock, "cons");
 185 
 186   uartinit();
 187 
 188   // connect read and write system calls
 189   // to consoleread and consolewrite.
 190   devsw[CONSOLE].read = consoleread;
 191   devsw[CONSOLE].write = consolewrite;
 192 }

/* [<][>][^][v][top][bottom][index][help] */