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   char buf[32];
  62   int i = 0;
  63 
  64   while(i < n){
  65     int nn = sizeof(buf);
  66     if(nn > n - i)
  67       nn = n - i;
  68     if(either_copyin(buf, user_src, src+i, nn) == -1)
  69       break;
  70     uartwrite(buf, nn);
  71     i += nn;
  72   }
  73 
  74   return i;
  75 }
  76 
  77 //
  78 // user read()s from the console go here.
  79 // copy (up to) a whole input line to dst.
  80 // user_dist indicates whether dst is a user
  81 // or kernel address.
  82 //
  83 int
  84 consoleread(int user_dst, uint64 dst, int n)
  85 {
  86   uint target;
  87   int c;
  88   char cbuf;
  89 
  90   target = n;
  91   acquire(&cons.lock);
  92   while(n > 0){
  93     // wait until interrupt handler has put some
  94     // input into cons.buffer.
  95     while(cons.r == cons.w){
  96       if(killed(myproc())){
  97         release(&cons.lock);
  98         return -1;
  99       }
 100       sleep(&cons.r, &cons.lock);
 101     }
 102 
 103     c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
 104 
 105     if(c == C('D')){  // end-of-file
 106       if(n < target){
 107         // Save ^D for next time, to make sure
 108         // caller gets a 0-byte result.
 109         cons.r--;
 110       }
 111       break;
 112     }
 113 
 114     // copy the input byte to the user-space buffer.
 115     cbuf = c;
 116     if(either_copyout(user_dst, dst, &cbuf, 1) == -1)
 117       break;
 118 
 119     dst++;
 120     --n;
 121 
 122     if(c == '\n'){
 123       // a whole line has arrived, return to
 124       // the user-level read().
 125       break;
 126     }
 127   }
 128   release(&cons.lock);
 129 
 130   return target - n;
 131 }
 132 
 133 //
 134 // the console input interrupt handler.
 135 // uartintr() calls this for input character.
 136 // do erase/kill processing, append to cons.buf,
 137 // wake up consoleread() if a whole line has arrived.
 138 //
 139 void
 140 consoleintr(int c)
 141 {
 142   acquire(&cons.lock);
 143 
 144   switch(c){
 145   case C('P'):  // Print process list.
 146     procdump();
 147     break;
 148   case C('U'):  // Kill line.
 149     while(cons.e != cons.w &&
 150           cons.buf[(cons.e-1) % INPUT_BUF_SIZE] != '\n'){
 151       cons.e--;
 152       consputc(BACKSPACE);
 153     }
 154     break;
 155   case C('H'): // Backspace
 156   case '\x7f': // Delete key
 157     if(cons.e != cons.w){
 158       cons.e--;
 159       consputc(BACKSPACE);
 160     }
 161     break;
 162   default:
 163     if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){
 164       c = (c == '\r') ? '\n' : c;
 165 
 166       // echo back to the user.
 167       consputc(c);
 168 
 169       // store for consumption by consoleread().
 170       cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
 171 
 172       if(c == '\n' || c == C('D') || cons.e-cons.r == INPUT_BUF_SIZE){
 173         // wake up consoleread() if a whole line (or end-of-file)
 174         // has arrived.
 175         cons.w = cons.e;
 176         wakeup(&cons.r);
 177       }
 178     }
 179     break;
 180   }
 181   
 182   release(&cons.lock);
 183 }
 184 
 185 void
 186 consoleinit(void)
 187 {
 188   initlock(&cons.lock, "cons");
 189 
 190   uartinit();
 191 
 192   // connect read and write system calls
 193   // to consoleread and consolewrite.
 194   devsw[CONSOLE].read = consoleread;
 195   devsw[CONSOLE].write = consolewrite;
 196 }

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