summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/boot.s4
-rw-r--r--kernel/serial.c58
-rw-r--r--kernel/sys.c10
-rw-r--r--kernel/tty.c86
4 files changed, 103 insertions, 55 deletions
diff --git a/kernel/boot.s b/kernel/boot.s
index d609611..ac7e0e3 100644
--- a/kernel/boot.s
+++ b/kernel/boot.s
@@ -8,10 +8,10 @@ extern hd_init
extern kmain
extern paging_init
extern printk
-extern serial_init
extern syscall_init
extern timer_init
extern traps_init
+extern tty_init
%define NRTASKS 64
@@ -42,7 +42,7 @@ kboot:
call printk
add esp, 4
; initialize secondary subsystems
- call serial_init
+ call tty_init
call hd_init
; last minute setup, then transfer to kmain
call timer_init
diff --git a/kernel/serial.c b/kernel/serial.c
index f5610f5..39c5ee0 100644
--- a/kernel/serial.c
+++ b/kernel/serial.c
@@ -3,6 +3,8 @@
#include <errno.h>
#include <kernel/con.h>
#include <kernel/sched.h>
+#include <kernel/serial.h>
+#include <kernel/tty.h>
#include <sys/types.h>
#include <unistd.h>
@@ -25,11 +27,11 @@
extern void rs_isr(void);
-static char present;
+struct tty_struct tty_rs = {
+ .init = &serial_init
+};
-static char rxbuf[256];
-static unsigned rxread, rxwrite;
-static struct task_struct *waiting_task;
+static char present;
int rsputs(char *s) {
if(!present)
@@ -80,53 +82,19 @@ void serial_init(void) {
rsputs("[kernel] Serial monitor initialized!\n\r");
printk("[rs] Serial port COM0 initialized!\n");
- rxread = 0;
- rxwrite = 1;
- waiting_task = NULL;
present = 1;
}
-ssize_t rsread(void *buf, size_t len) {
- ssize_t n = len;
- char *b = buf;
-
- if(!present)
- return -ENXIO;
-
- if(len == 0)
- return 0;
-
- while(n--) {
- /* check if the buffer's empty and if so, go to sleep */
- cli();
- if(rxread == rxwrite)
- interruptible_sleep_on(&waiting_task);
-
- /* check again to see if anything was read, or we were interrupted */
- if(rxread == rxwrite) {
- sti();
- return -EINTR;
- }
-
- sti();
-
- *b++ = rxbuf[rxread];
- rxread = rxread + 1 % sizeof(rxbuf);
- }
-
- return len;
-}
-
void rs_handler(void) {
+ struct tty_queue *q = &tty_rs.rqueue;
+
if((inb(RSLINES) & 1) == 0)
return;
- if(rxwrite == (rxread - 1 % sizeof(rxbuf)))
+ if(q->pwrite == (q->pread - 1 % sizeof(q->buf)))
return;
- rxbuf[rxwrite] = inb(RSDATA);
- rxwrite = rxwrite + 1 % sizeof(rxbuf);
- if(waiting_task != NULL) {
- waiting_task->state = TSTATE_RUNNING;
- waiting_task = NULL;
- }
+ q->buf[q->pwrite] = inb(RSDATA);
+ q->pwrite = q->pwrite + 1 % sizeof(q->buf);
+
+ wake_up(&q->waiting);
}
diff --git a/kernel/sys.c b/kernel/sys.c
index cfe9483..6127f58 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2,6 +2,7 @@
#include <kernel/con.h>
#include <kernel/sched.h>
#include <kernel/serial.h>
+#include <kernel/tty.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
@@ -80,14 +81,7 @@ int sys_ctty(int ctty) {
}
ssize_t sys_read(void *buf, size_t len) {
- switch(ctask->ctty) {
- case 1:
- return rsread(buf, len);
- break;
- default:
- return -EBADF;
- break;
- }
+ return tty_read(ctask->ctty, buf, len);
}
int sys_dummy(void) {
diff --git a/kernel/tty.c b/kernel/tty.c
new file mode 100644
index 0000000..1946110
--- /dev/null
+++ b/kernel/tty.c
@@ -0,0 +1,86 @@
+#include <asm/interrupt.h>
+#include <errno.h>
+#include <kernel/sched.h>
+#include <kernel/serial.h>
+#include <kernel/tty.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define NRTTY \
+ (sizeof(ttys) / sizeof(struct tty_struct*))
+
+static struct tty_struct *ttys[] = {
+ NULL,
+ &tty_rs
+};
+
+/* check if the buffer's empty and if so, go to sleep */
+static int sleep_while_empty(struct tty_queue *q) {
+ if(q->pread != q->pwrite)
+ return 0;
+
+ cli();
+ while(1) {
+ if(q->pread == q->pwrite)
+ interruptible_sleep_on(&q->waiting);
+
+ /* check again to see if anything was read, or we were interrupted */
+ if(q->pread == q->pwrite) {
+ sti();
+ return -1;
+ }
+
+ sti();
+ return 0;
+ }
+}
+
+ssize_t tty_read(unsigned tty, void *buf, size_t len) {
+ size_t i;
+ char *b = buf;
+ struct tty_queue *q = &ttys[tty]->rqueue;
+
+ if(tty > NRTTY || ttys[tty] == NULL)
+ return -1;
+
+ if(len == 0)
+ return 0;
+
+ if(len > SSIZE_MAX)
+ len = SSIZE_MAX;
+
+ for(i = 0; i < len; i++) {
+ /* check if the buffer's empty and if so, go to sleep */
+ if(sleep_while_empty(q) < 0) {
+ if(i == 0)
+ return -EINTR;
+
+ return i;
+ }
+
+ *b++ = q->buf[q->pread];
+ q->pread = q->pread + 1 % TTY_BUF_SIZE;
+ }
+
+ return len;
+}
+
+void tty_init(void) {
+ int i;
+
+ for(i = 0; i < NRTTY; i++) {
+ if(!ttys[i])
+ continue;
+
+ memset(&ttys[i]->rqueue, 0, sizeof(struct tty_queue));
+ memset(&ttys[i]->wqueue, 0, sizeof(struct tty_queue));
+
+ ttys[i]->rqueue.pwrite = 1;
+ ttys[i]->wqueue.pwrite = 1;
+
+ if(ttys[i]->init)
+ ttys[i]->init();
+ }
+}