summaryrefslogtreecommitdiff
path: root/kernel/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/tty.c')
-rw-r--r--kernel/tty.c64
1 files changed, 56 insertions, 8 deletions
diff --git a/kernel/tty.c b/kernel/tty.c
index 1946110..75c3701 100644
--- a/kernel/tty.c
+++ b/kernel/tty.c
@@ -16,11 +16,8 @@ static struct tty_struct *ttys[] = {
&tty_rs
};
-/* check if the buffer's empty and if so, go to sleep */
+/* check if a 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)
@@ -37,6 +34,24 @@ static int sleep_while_empty(struct tty_queue *q) {
}
}
+/* check if a buffer's full and if so, go to sleep */
+static int sleep_while_full(struct tty_queue *q) {
+ cli();
+ while(1) {
+ if(q->pwrite == (q->pread - 1 % sizeof(q->buf)))
+ interruptible_sleep_on(&q->waiting);
+
+ /* check again to see if anything was removed, or we were interrupted */
+ if(q->pwrite == (q->pread - 1 % sizeof(q->buf))) {
+ sti();
+ return -1;
+ }
+
+ sti();
+ return 0;
+ }
+}
+
ssize_t tty_read(unsigned tty, void *buf, size_t len) {
size_t i;
char *b = buf;
@@ -61,9 +76,45 @@ ssize_t tty_read(unsigned tty, void *buf, size_t len) {
}
*b++ = q->buf[q->pread];
- q->pread = q->pread + 1 % TTY_BUF_SIZE;
+ q->pread = (q->pread + 1) % TTY_BUF_SIZE;
+ }
+
+ return len;
+}
+
+ssize_t tty_write(unsigned tty, void *buf, size_t len) {
+ size_t i;
+ char *b = buf;
+ struct tty_queue *q = &ttys[tty]->wqueue;
+
+ 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 full and if so, go to sleep */
+ if(sleep_while_full(q) < 0) {
+ if(i == 0)
+ return -EINTR;
+
+ return i;
+ }
+
+ q->buf[q->pwrite] = *b++;
+ q->pwrite = (q->pwrite + 1) % TTY_BUF_SIZE;
}
+ /* tell the driver that new data is available */
+ cli();
+ if(ttys[tty]->write)
+ ttys[tty]->write();
+ sti();
+
return len;
}
@@ -77,9 +128,6 @@ void tty_init(void) {
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();
}