|  | /* Copyright (c) 2012 The Regents of the University of California | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * Console (Keyboard/serial/whatever) related functions. */ | 
|  |  | 
|  | #include <console.h> | 
|  | #include <ros/ring_buffer.h> | 
|  | #include <monitor.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | struct kb_buffer cons_buf; | 
|  |  | 
|  | void kb_buf_init(struct kb_buffer *kb) | 
|  | { | 
|  | kb->prod_idx = 0; | 
|  | kb->cons_idx = 0; | 
|  | spinlock_init(&kb->buf_lock); | 
|  | sem_init(&kb->buf_sem, 0); | 
|  | /* no need to memset the buffer - we only read something that is written */ | 
|  | } | 
|  |  | 
|  | /* Producers don't block - their input is dropped.  Should be rare for now; if | 
|  | * it happens, it's probably a bug. */ | 
|  | void kb_add_to_buf(struct kb_buffer *kb, char c) | 
|  | { | 
|  | /* make sure we're a power of 2 */ | 
|  | static_assert(KB_BUF_SIZE == __RD32(KB_BUF_SIZE)); | 
|  | bool was_empty = FALSE; | 
|  | spin_lock(&kb->buf_lock); | 
|  | if (!__ring_full(KB_BUF_SIZE, kb->prod_idx, kb->cons_idx)) { | 
|  | if (__ring_empty(kb->prod_idx, kb->cons_idx)) | 
|  | was_empty = TRUE; | 
|  | kb->buf[kb->prod_idx % KB_BUF_SIZE] = c;	// compiler should shift | 
|  | kb->prod_idx++; | 
|  | } else { | 
|  | /* else drop the char */ | 
|  | printk("[kernel] KB buffer overflowed %c\n", c); | 
|  | } | 
|  | spin_unlock(&kb->buf_lock); | 
|  | /* up the sem when it goes from empty->non_empty.   rule for syncing with | 
|  | * blockers: if there are any items in the buffer, either the sem is upped, | 
|  | * or there is an active consumer.  consumers immediately down (to become an | 
|  | * active consumer). */ | 
|  | if (was_empty) | 
|  | sem_up(&kb->buf_sem); | 
|  | /* also note that multiple readers on the console/serial are going to fight | 
|  | * for input and it is going to get interleaved - broader issue */ | 
|  | } | 
|  |  | 
|  | /* Will read cnt chars from the KB buf into dst.  Will block until complete. */ | 
|  | void kb_get_from_buf(struct kb_buffer *kb, char *dst, size_t cnt) | 
|  | { | 
|  | unsigned int dst_idx = 0; /* aka, amt copied so far */ | 
|  | bool need_an_up = FALSE; | 
|  |  | 
|  | /* so long as we still need items, we'll sleep til there is activity, then | 
|  | * grab everything we can til the kb buf is empty (or we're done).  If we | 
|  | * didn't empty the buf, we'll need to up the sem later. */ | 
|  | while (dst_idx < cnt) { | 
|  | /* this will return immediately if some data is already there, o/w we | 
|  | * block til there is some activity */ | 
|  | sem_down(&kb->buf_sem); | 
|  | spin_lock(&kb->buf_lock); | 
|  | /* under the current scheme, we should only have one active consumer at | 
|  | * a time, so if we woke up, the ring must not be empty. */ | 
|  | assert(!__ring_empty(kb->prod_idx, kb->cons_idx)); | 
|  | while (!__ring_empty(kb->prod_idx, kb->cons_idx)) { | 
|  | if (dst_idx == cnt) { | 
|  | /* we're done, and it's not empty yet */ | 
|  | need_an_up = TRUE; | 
|  | break; | 
|  | } | 
|  | dst[dst_idx] = kb->buf[kb->cons_idx % KB_BUF_SIZE]; | 
|  | kb->cons_idx++; | 
|  | dst_idx++; | 
|  | } | 
|  | spin_unlock(&kb->buf_lock); | 
|  | } | 
|  | /* Remember: if the buf is non empty, there is either an active consumer or | 
|  | * the sem is upped. */ | 
|  | if (need_an_up) | 
|  | sem_up(&kb->buf_sem); | 
|  | } | 
|  |  | 
|  | /* Kernel messages associated with the console.  Arch-specific interrupt | 
|  | * handlers need to call these.  For add char, a0 = &cons_buf and a1 = the char | 
|  | * you read.  Call __run_mon on your 'magic' input.  */ | 
|  | void __cons_add_char(uint32_t srcid, long a0, long a1, long a2) | 
|  | { | 
|  | kb_add_to_buf((struct kb_buffer*)a0, (char)a1); | 
|  | } | 
|  |  | 
|  | void __run_mon(uint32_t srcid, long a0, long a1, long a2) | 
|  | { | 
|  | monitor(0); | 
|  | } |