37,9 → 37,23 |
#include <arch/drivers/niagara.h> |
#include <console/chardev.h> |
#include <console/console.h> |
#include <ddi/ddi.h> |
#include <ddi/device.h> |
#include <arch/asm.h> |
#include <arch/drivers/kbd.h> |
#include <arch/sun4v/hypercall.h> |
#include <sysinfo/sysinfo.h> |
#include <ipc/irq.h> |
|
/** |
* The driver is polling based, but in order to notify the userspace |
* of a key being pressed, we need to supply the interface with some |
* interrupt number. The interrupt number can be arbitrary as it it |
* will never be used for identifying HW interrupts, but only in |
* notifying the userspace. |
*/ |
#define FICTIONAL_INR 1 |
|
/* functions referenced from definitions of I/O operations structures */ |
static void niagara_putchar(chardev_t *, const char); |
static void niagara_noop(chardev_t *); |
53,12 → 67,61 |
.read = niagara_read |
}; |
|
/* |
* The driver uses hypercalls to print characters to the console. Since the |
* hypercall cannot be performed from the userspace, we do this: |
* The kernel "little brother" driver (which will be present no matter what the |
* DDI architecture is - as we need the kernel part for the kconsole) |
* defines a shared buffer. Kernel walks through the buffer (in the same thread |
* which is used for polling the keyboard) and prints any pending characters |
* to the console (using hypercalls). The userspace fb server maps this shared |
* buffer to its address space and output operation it does is performed using |
* the mapped buffer. The shared buffer definition follows. |
*/ |
#define OUTPUT_BUFFER_SIZE ((PAGE_SIZE) - 2 * 8) |
static volatile struct { |
uint64_t read_ptr; |
uint64_t write_ptr; |
char data[OUTPUT_BUFFER_SIZE]; |
} |
__attribute__ ((packed)) |
__attribute__ ((aligned(PAGE_SIZE))) |
output_buffer; |
|
/** Niagara character device */ |
chardev_t niagara_io; |
|
/** |
* Niagara IRQ structure. So far used only for notifying the userspace of the |
* key being pressed, not for kernel being informed about keyboard interrupts. |
*/ |
static irq_t niagara_irq; |
|
/** defined in drivers/kbd.c */ |
extern kbd_type_t kbd_type; |
|
/** |
* The character read will be stored here until the (notified) uspace |
* driver picks it up. |
*/ |
static char read_char; |
|
/** |
* The driver works in polled mode, so no interrupt should be handled by it. |
*/ |
static irq_ownership_t niagara_claim(void) |
{ |
return IRQ_DECLINE; |
} |
|
/** |
* The driver works in polled mode, so no interrupt should be handled by it. |
*/ |
static void niagara_irq_handler(irq_t *irq, void *arg, ...) |
{ |
panic("Not yet implemented, SGCN works in polled mode.\n"); |
} |
|
/** Writes a single character to the standard output. */ |
static inline void do_putchar(const char c) { |
/* repeat until the buffer is non-full */ |
79,6 → 142,11 |
*/ |
void niagara_grab(void) |
{ |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&niagara_irq.lock); |
niagara_irq.notif_cfg.notify = false; |
spinlock_unlock(&niagara_irq.lock); |
interrupts_restore(ipl); |
} |
|
/** |
86,6 → 154,12 |
*/ |
void niagara_release(void) |
{ |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&niagara_irq.lock); |
if (niagara_irq.notif_cfg.answerbox) |
niagara_irq.notif_cfg.notify = true; |
spinlock_unlock(&niagara_irq.lock); |
interrupts_restore(ipl); |
} |
|
/** |
96,14 → 170,29 |
} |
|
/** |
* Called when actively reading the character. Not implemented yet. |
* Called when actively reading the character. |
*/ |
static char niagara_read(chardev_t *d) |
{ |
return (char) 0; |
uint64_t c; |
|
if (__hypercall_fast_ret1(0, 0, 0, 0, 0, CONS_GETCHAR, &c) == EOK) { |
return (char) c; |
} |
|
return '\0'; |
} |
|
/** |
* Returns the character last read. This function is called from the |
* pseudocode - the character returned by this function is passed to |
* the userspace keyboard driver. |
*/ |
char niagara_getc(void) { |
return read_char; |
} |
|
/** |
* Function regularly called by the keyboard polling thread. Asks the |
* hypervisor whether there is any unread character. If so, it picks it up |
* and sends it to the upper layers of HelenOS. |
110,12 → 199,37 |
*/ |
void niagara_poll(void) |
{ |
uint64_t c = 50; |
while (output_buffer.read_ptr != output_buffer.write_ptr) { |
do_putchar(output_buffer.data[output_buffer.read_ptr]); |
output_buffer.read_ptr = |
((output_buffer.read_ptr) + 1) % OUTPUT_BUFFER_SIZE; |
} |
|
uint64_t c; |
|
if (__hypercall_fast_ret1(0, 0, 0, 0, 0, CONS_GETCHAR, &c) == EOK) { |
chardev_push_character(&niagara_io, c); |
if (c == '\r') |
chardev_push_character(&niagara_io, '\n'); |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&niagara_irq.lock); |
|
if (niagara_irq.notif_cfg.notify && |
niagara_irq.notif_cfg.answerbox) { |
/* |
* remember the character, uspace will pick it |
* up using pseudocode |
*/ |
read_char = (char) c; |
ipc_irq_send_notif(&niagara_irq); |
spinlock_unlock(&niagara_irq.lock); |
interrupts_restore(ipl); |
return; |
} else { |
spinlock_unlock(&niagara_irq.lock); |
interrupts_restore(ipl); |
|
chardev_push_character(&niagara_io, c); |
if (c == '\r') |
chardev_push_character(&niagara_io, '\n'); |
} |
} |
|
} |
128,6 → 242,39 |
{ |
kbd_type = KBD_SUN4V; |
|
devno_t devno = device_assign_devno(); |
irq_initialize(&niagara_irq); |
niagara_irq.devno = devno; |
niagara_irq.inr = FICTIONAL_INR; |
niagara_irq.claim = niagara_claim; |
niagara_irq.handler = niagara_irq_handler; |
irq_register(&niagara_irq); |
|
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.type", NULL, KBD_SUN4V); |
sysinfo_set_item_val("kbd.devno", NULL, devno); |
sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR); |
sysinfo_set_item_val("fb.kind", NULL, 5); |
|
/* |
* Set sysinfos and pareas so that the userspace counterpart of the |
* niagara fb driver can communicate with kernel using a shared buffer. |
*/ |
output_buffer.read_ptr = 0; |
output_buffer.write_ptr = 0; |
sysinfo_set_item_val("niagara.outbuf.address", NULL, |
KA2PA(&output_buffer)); |
sysinfo_set_item_val("niagara.outbuf.size", NULL, |
PAGE_SIZE); |
sysinfo_set_item_val("niagara.outbuf.datasize", NULL, |
OUTPUT_BUFFER_SIZE); |
static parea_t outbuf_parea; |
outbuf_parea.pbase = (uintptr_t) (KA2PA(&output_buffer)); |
outbuf_parea.vbase = (uintptr_t) (&output_buffer); |
outbuf_parea.frames = 1; |
outbuf_parea.cacheable = false; |
ddi_parea_register(&outbuf_parea); |
|
chardev_initialize("niagara_io", &niagara_io, &niagara_ops); |
stdin = &niagara_io; |
stdout = &niagara_io; |