#include <defs.h>
|
|
#include <stdio.h>
|
|
#include <wait.h>
|
|
#include <sync.h>
|
|
#include <proc.h>
|
|
#include <sched.h>
|
|
#include <dev.h>
|
|
#include <vfs.h>
|
|
#include <iobuf.h>
|
|
#include <inode.h>
|
|
#include <unistd.h>
|
|
#include <error.h>
|
|
#include <assert.h>
|
|
|
|
#define STDIN_BUFSIZE 4096
|
|
|
|
static char stdin_buffer[STDIN_BUFSIZE];
|
|
static off_t p_rpos, p_wpos;
|
|
static wait_queue_t __wait_queue, *wait_queue = &__wait_queue;
|
|
|
|
void
|
|
dev_stdin_write(char c) {
|
|
bool intr_flag;
|
|
if (c != '\0') {
|
|
local_intr_save(intr_flag);
|
|
{
|
|
stdin_buffer[p_wpos % STDIN_BUFSIZE] = c;
|
|
if (p_wpos - p_rpos < STDIN_BUFSIZE) {
|
|
p_wpos ++;
|
|
}
|
|
if (!wait_queue_empty(wait_queue)) {
|
|
wakeup_queue(wait_queue, WT_KBD, 1);
|
|
}
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
}
|
|
}
|
|
|
|
static int
|
|
dev_stdin_read(char *buf, size_t len) {
|
|
int ret = 0;
|
|
bool intr_flag;
|
|
local_intr_save(intr_flag);
|
|
{
|
|
for (; ret < len; ret ++, p_rpos ++) {
|
|
try_again:
|
|
if (p_rpos < p_wpos) {
|
|
*buf ++ = stdin_buffer[p_rpos % STDIN_BUFSIZE];
|
|
}
|
|
else {
|
|
wait_t __wait, *wait = &__wait;
|
|
wait_current_set(wait_queue, wait, WT_KBD);
|
|
local_intr_restore(intr_flag);
|
|
|
|
schedule();
|
|
|
|
local_intr_save(intr_flag);
|
|
wait_current_del(wait_queue, wait);
|
|
if (wait->wakeup_flags == WT_KBD) {
|
|
goto try_again;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
local_intr_restore(intr_flag);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
stdin_open(struct device *dev, uint32_t open_flags) {
|
|
if (open_flags != O_RDONLY) {
|
|
return -E_INVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
stdin_close(struct device *dev) {
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
stdin_io(struct device *dev, struct iobuf *iob, bool write) {
|
|
if (!write) {
|
|
int ret;
|
|
if ((ret = dev_stdin_read(iob->io_base, iob->io_resid)) > 0) {
|
|
iob->io_resid -= ret;
|
|
}
|
|
return ret;
|
|
}
|
|
return -E_INVAL;
|
|
}
|
|
|
|
static int
|
|
stdin_ioctl(struct device *dev, int op, void *data) {
|
|
return -E_INVAL;
|
|
}
|
|
|
|
static void
|
|
stdin_device_init(struct device *dev) {
|
|
dev->d_blocks = 0;
|
|
dev->d_blocksize = 1;
|
|
dev->d_open = stdin_open;
|
|
dev->d_close = stdin_close;
|
|
dev->d_io = stdin_io;
|
|
dev->d_ioctl = stdin_ioctl;
|
|
|
|
p_rpos = p_wpos = 0;
|
|
wait_queue_init(wait_queue);
|
|
}
|
|
|
|
void
|
|
dev_init_stdin(void) {
|
|
struct inode *node;
|
|
if ((node = dev_create_inode()) == NULL) {
|
|
panic("stdin: dev_create_node.\n");
|
|
}
|
|
stdin_device_init(vop_info(node, device));
|
|
|
|
int ret;
|
|
if ((ret = vfs_add_dev("stdin", node, 0)) != 0) {
|
|
panic("stdin: vfs_add_dev: %e.\n", ret);
|
|
}
|
|
}
|
|
|