33,46 → 33,119 |
*/ |
|
#include <console/chardev.h> |
#include <putchar.h> |
#include <synch/waitq.h> |
#include <synch/spinlock.h> |
#include <print.h> |
#include <func.h> |
#include <arch.h> |
|
/** Initialize character device. |
/** Initialize input character device. |
* |
* @param chardev Character device. |
* @param op Implementation of character device operations. |
* @param indev Input character device. |
* @param op Implementation of input character device operations. |
* |
*/ |
void chardev_initialize(char *name, chardev_t *chardev, |
chardev_operations_t *op) |
void indev_initialize(char *name, indev_t *indev, |
indev_operations_t *op) |
{ |
chardev->name = name; |
|
waitq_initialize(&chardev->wq); |
spinlock_initialize(&chardev->lock, "chardev"); |
chardev->counter = 0; |
chardev->index = 0; |
chardev->op = op; |
indev->name = name; |
waitq_initialize(&indev->wq); |
spinlock_initialize(&indev->lock, "indev"); |
indev->counter = 0; |
indev->index = 0; |
indev->op = op; |
} |
|
/** Push character read from input character device. |
* |
* @param chardev Character device. |
* @param indev Input character device. |
* @param ch Character being pushed. |
* |
*/ |
void chardev_push_character(chardev_t *chardev, uint8_t ch) |
void indev_push_character(indev_t *indev, wchar_t ch) |
{ |
spinlock_lock(&chardev->lock); |
chardev->counter++; |
if (chardev->counter == CHARDEV_BUFLEN - 1) { |
/* buffer full => disable device interrupt */ |
chardev->op->suspend(chardev); |
ASSERT(indev); |
|
spinlock_lock(&indev->lock); |
if (indev->counter == INDEV_BUFLEN - 1) { |
/* Buffer full */ |
spinlock_unlock(&indev->lock); |
return; |
} |
|
chardev->buffer[chardev->index++] = ch; |
chardev->index = chardev->index % CHARDEV_BUFLEN; /* index modulo size of buffer */ |
waitq_wakeup(&chardev->wq, WAKEUP_FIRST); |
spinlock_unlock(&chardev->lock); |
indev->counter++; |
indev->buffer[indev->index++] = ch; |
|
/* Index modulo size of buffer */ |
indev->index = indev->index % INDEV_BUFLEN; |
waitq_wakeup(&indev->wq, WAKEUP_FIRST); |
spinlock_unlock(&indev->lock); |
} |
|
/** Pop character from input character device. |
* |
* @param indev Input character device. |
* |
* @return Character read. |
* |
*/ |
wchar_t indev_pop_character(indev_t *indev) |
{ |
if (atomic_get(&haltstate)) { |
/* If we are here, we are hopefully on the processor that |
* issued the 'halt' command, so proceed to read the character |
* directly from input |
*/ |
if (check_poll(indev)) |
return indev->op->poll(indev); |
|
/* No other way of interacting with user */ |
interrupts_disable(); |
|
if (CPU) |
printf("cpu%u: ", CPU->id); |
else |
printf("cpu: "); |
|
printf("halted (no polling input)\n"); |
cpu_halt(); |
} |
|
waitq_sleep(&indev->wq); |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&indev->lock); |
wchar_t ch = indev->buffer[(indev->index - indev->counter) % INDEV_BUFLEN]; |
indev->counter--; |
spinlock_unlock(&indev->lock); |
interrupts_restore(ipl); |
|
return ch; |
} |
|
/** Initialize output character device. |
* |
* @param outdev Output character device. |
* @param op Implementation of output character device operations. |
* |
*/ |
void outdev_initialize(char *name, outdev_t *outdev, |
outdev_operations_t *op) |
{ |
outdev->name = name; |
spinlock_initialize(&outdev->lock, "outdev"); |
outdev->op = op; |
} |
|
bool check_poll(indev_t *indev) |
{ |
if (indev == NULL) |
return false; |
|
if (indev->op == NULL) |
return false; |
|
return (indev->op->poll != NULL); |
} |
|
/** @} |
*/ |