阅读材料
- Xv6代码:console.c
- 教材第5章
console驱动
consputc函数
该函数在发送字符前增加了判断:如果是BACKSPACE,则用空格覆盖,否则直接调用uartputc_sync函数
void consputc(int c)
{
if (c == BACKSPACE)
{
// if the user typed backspace, overwrite with a space.
uartputc_sync('\b');
uartputc_sync(' ');
uartputc_sync('\b');
}
else
{
uartputc_sync(c);
}
}
consolewrite函数
该函数用于输出字符,一次一个字符,拷贝自用户/内核空间
- user_src == 1:用户地址空间
- user_src == 0:内核地址空间
int consolewrite(int user_src, uint64 src, int n)
{
int i;
for (i = 0; i < n; i++)
{
char c;
if (either_copyin(&c, user_src, src + i, 1) == -1)
break;
uartputc(c);
}
return i;
}
consoleread函数
该函数实际上是从缓冲区往外读
- 先判断缓冲区是否为空,如果为空,则主动调用sleep函数
- 如果读到EOF标志,且未达到目标读取字节数,则保存该字符并终止循环
- 如果读取到换行符\n,则认为已读取完整行,终止循环。
int consoleread(int user_dst, uint64 dst, int n)
{
uint target;
int c;
char cbuf;
target = n;
acquire(&cons.lock);
while (n > 0)
{
// wait until interrupt handler has put some
// input into cons.buffer.
while (cons.r == cons.w)
{
if (killed(myproc()))
{
release(&cons.lock);
return -1;
}
sleep(&cons.r, &cons.lock);
}
c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
if (c == C('D'))
{ // end-of-file
if (n < target)
{
// Save ^D for next time, to make sure
// caller gets a 0-byte result.
cons.r--;
}
break;
}
// copy the input byte to the user-space buffer.
cbuf = c;
if (either_copyout(user_dst, dst, &cbuf, 1) == -1)
break;
dst++;
--n;
if (c == '\n')
{
// a whole line has arrived, return to
// the user-level read().
break;
}
}
release(&cons.lock);
return target - n;
}
consoleintr函数
当uartintr函数发现RHR寄存器中有字符时,会调用该函数。
该函数具体功能:
- Ctrl+P:打印进程列表
- Ctrl+U:只要缓冲区非空或者不到上一个换行符,就不断调用consputc函数进行回退
- Ctrl+H:只要缓冲区非空,回退一个字符
- 默认情况:将字符显示到控制台,并存入缓冲区;如果缓冲区已满或者读到换行符\EOF,则唤醒等待的进程
void consoleintr(int c)
{
acquire(&cons.lock);
switch (c)
{
case C('P'): // Print process list.
procdump();
break;
case C('U'): // Kill line.
while (cons.e != cons.w &&
cons.buf[(cons.e - 1) % INPUT_BUF_SIZE] != '\n')
{
cons.e--;
consputc(BACKSPACE);
}
break;
case C('H'): // Backspace
case '\x7f': // Delete key
if (cons.e != cons.w)
{
cons.e--;
consputc(BACKSPACE);
}
break;
default:
if (c != 0 && cons.e - cons.r < INPUT_BUF_SIZE)
{
c = (c == '\r') ? '\n' : c;
// echo back to the user.
consputc(c);
// store for consumption by consoleread().
cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
if (c == '\n' || c == C('D') || cons.e - cons.r == INPUT_BUF_SIZE)
{
// wake up consoleread() if a whole line (or end-of-file)
// has arrived.
cons.w = cons.e;
wakeup(&cons.r);
}
}
break;
}
release(&cons.lock);
}
consoleinit函数
- 初始化锁
- 调用uartinit函数,初始化UART
- 注册consoleread和consolewrite函数(这个后续在文件系统里面讲解)
void consoleinit(void)
{
initlock(&cons.lock, "cons");
uartinit();
// connect read and write system calls
// to consoleread and consolewrite.
devsw[CONSOLE].read = consoleread;
devsw[CONSOLE].write = consolewrite;
}