os_kernel_lab/code/lab8/kern/fs/devs/dev_stdin.c

127 lines
2.8 KiB
C

#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);
}
}