kthread_usleep()
[akaros.git] / kern / src / console.c
1 /* Copyright (c) 2012 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Console (Keyboard/serial/whatever) related functions. */
6
7 #include <console.h>
8 #include <ros/ring_buffer.h>
9 #include <monitor.h>
10 #include <stdio.h>
11
12 struct kb_buffer cons_buf;
13
14 void kb_buf_init(struct kb_buffer *kb)
15 {
16         kb->prod_idx = 0;
17         kb->cons_idx = 0;
18         spinlock_init(&kb->buf_lock);
19         sem_init(&kb->buf_sem, 0);
20         /* no need to memset the buffer - we only read something that is written */
21 }
22
23 /* Producers don't block - their input is dropped.  Should be rare for now; if
24  * it happens, it's probably a bug. */
25 void kb_add_to_buf(struct kb_buffer *kb, char c)
26 {
27         /* make sure we're a power of 2 */
28         static_assert(KB_BUF_SIZE == __RD32(KB_BUF_SIZE));
29         bool was_empty = FALSE;
30         spin_lock(&kb->buf_lock);
31         if (!__ring_full(KB_BUF_SIZE, kb->prod_idx, kb->cons_idx)) {
32                 if (__ring_empty(kb->prod_idx, kb->cons_idx))
33                         was_empty = TRUE;
34                 kb->buf[kb->prod_idx % KB_BUF_SIZE] = c;        // compiler should shift
35                 kb->prod_idx++;
36         } else {
37                 /* else drop the char */
38                 printk("[kernel] KB buffer overflowed %c\n", c);
39         }
40         spin_unlock(&kb->buf_lock);
41         /* up the sem when it goes from empty->non_empty.   rule for syncing with
42          * blockers: if there are any items in the buffer, either the sem is upped,
43          * or there is an active consumer.  consumers immediately down (to become an
44          * active consumer). */
45         if (was_empty)
46                 sem_up(&kb->buf_sem);
47         /* also note that multiple readers on the console/serial are going to fight
48          * for input and it is going to get interleaved - broader issue */
49 }
50
51 /* Will read cnt chars from the KB buf into dst.  Will block until complete. */
52 void kb_get_from_buf(struct kb_buffer *kb, char *dst, size_t cnt)
53 {
54         unsigned int dst_idx = 0; /* aka, amt copied so far */
55         bool need_an_up = FALSE;
56
57         /* so long as we still need items, we'll sleep til there is activity, then
58          * grab everything we can til the kb buf is empty (or we're done).  If we
59          * didn't empty the buf, we'll need to up the sem later. */
60         while (dst_idx < cnt) {
61                 /* this will return immediately if some data is already there, o/w we
62                  * block til there is some activity */
63                 sem_down(&kb->buf_sem);
64                 spin_lock(&kb->buf_lock);
65                 /* under the current scheme, we should only have one active consumer at
66                  * a time, so if we woke up, the ring must not be empty. */
67                 assert(!__ring_empty(kb->prod_idx, kb->cons_idx));
68                 while (!__ring_empty(kb->prod_idx, kb->cons_idx)) {
69                         if (dst_idx == cnt) {
70                                 /* we're done, and it's not empty yet */
71                                 need_an_up = TRUE;
72                                 break;
73                         }
74                         dst[dst_idx] = kb->buf[kb->cons_idx % KB_BUF_SIZE];
75                         kb->cons_idx++;
76                         dst_idx++;
77                 }
78                 spin_unlock(&kb->buf_lock);
79         }
80         /* Remember: if the buf is non empty, there is either an active consumer or
81          * the sem is upped. */
82         if (need_an_up)
83                 sem_up(&kb->buf_sem);
84 }
85
86 /* Kernel messages associated with the console.  Arch-specific interrupt
87  * handlers need to call these.  For add char, a0 = &cons_buf and a1 = the char
88  * you read.  Call __run_mon on your 'magic' input.  */
89 void __cons_add_char(uint32_t srcid, long a0, long a1, long a2)
90 {
91         kb_add_to_buf((struct kb_buffer*)a0, (char)a1);
92 }
93
94 void __run_mon(uint32_t srcid, long a0, long a1, long a2)
95 {
96         monitor(0);
97 }