Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4668 → Rev 4667

/branches/dd/uspace/srv/console/console.c
51,7 → 51,6
#include <sysinfo.h>
#include <event.h>
#include <devmap.h>
#include <fibril_sync.h>
 
#include "console.h"
#include "gcons.h"
69,7 → 68,6
int phone; /**< Framebuffer phone */
ipcarg_t cols; /**< Framebuffer columns */
ipcarg_t rows; /**< Framebuffer rows */
int color_cap; /**< Color capabilities (FB_CCAP_xxx) */
} fb_info;
 
typedef struct {
99,9 → 97,64
size_t cnt; /**< Width of the span. */
} fb_pending;
 
static FIBRIL_MUTEX_INITIALIZE(input_mutex);
static FIBRIL_CONDVAR_INITIALIZE(input_cv);
/** Pending input structure. */
typedef struct {
link_t link;
console_t *cons; /**< Console waiting for input */
ipc_callid_t rid; /**< Call ID waiting for input */
ipc_callid_t callid; /**< Call ID waiting for IPC_DATA_READ */
size_t pos; /**< Position of the last stored data */
size_t size; /**< Size of ther buffer */
char *data; /**< Already stored data */
} pending_input_t;
 
LIST_INITIALIZE(pending_input);
 
/** Process pending input requests */
static void process_pending_input(void)
{
async_serialize_start();
link_t *cur;
loop:
for (cur = pending_input.next; cur != &pending_input; cur = cur->next) {
pending_input_t *pr = list_get_instance(cur, pending_input_t, link);
console_event_t ev;
if (keybuffer_pop(&pr->cons->keybuffer, &ev)) {
if (pr->data != NULL) {
if (ev.type == KEY_PRESS) {
pr->data[pr->pos] = ev.c;
pr->pos++;
}
} else {
ipc_answer_4(pr->rid, EOK, ev.type, ev.key, ev.mods, ev.c);
list_remove(cur);
free(pr);
goto loop;
}
}
if ((pr->data != NULL) && (pr->pos == pr->size)) {
(void) ipc_data_read_finalize(pr->callid, pr->data, pr->size);
ipc_answer_1(pr->rid, EOK, pr->size);
free(pr->data);
list_remove(cur);
free(pr);
goto loop;
}
}
async_serialize_end();
}
 
static void curs_visibility(bool visible)
{
async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
173,19 → 226,6
}
}
 
int ccap_fb_to_con(int ccap_fb, int *ccap_con)
{
switch (ccap_fb) {
case FB_CCAP_NONE: *ccap_con = CONSOLE_CCAP_NONE; break;
case FB_CCAP_STYLE: *ccap_con = CONSOLE_CCAP_STYLE; break;
case FB_CCAP_INDEXED: *ccap_con = CONSOLE_CCAP_INDEXED; break;
case FB_CCAP_RGB: *ccap_con = CONSOLE_CCAP_RGB; break;
default: return EINVAL;
}
 
return EOK;
}
 
/** Send an area of screenbuffer to the FB driver. */
static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height)
{
247,12 → 287,9
/** Process a character from the client (TTY emulation). */
static void write_char(console_t *cons, wchar_t ch)
{
bool flush_cursor = false;
 
switch (ch) {
case '\n':
fb_pending_flush();
flush_cursor = true;
cons->scr.position_y++;
cons->scr.position_x = 0;
break;
278,10 → 315,8
cons->scr.position_x++;
}
if (cons->scr.position_x >= cons->scr.size_x) {
flush_cursor = true;
if (cons->scr.position_x >= cons->scr.size_x)
cons->scr.position_y++;
}
if (cons->scr.position_y >= cons->scr.size_y) {
fb_pending_flush();
292,9 → 327,7
if (cons == active_console)
async_msg_1(fb_info.phone, FB_SCROLL, 1);
}
 
if (cons == active_console && flush_cursor)
curs_goto(cons->scr.position_x, cons->scr.position_y);
cons->scr.position_x = cons->scr.position_x % cons->scr.size_x;
}
 
413,10 → 446,7
break;
}
fibril_mutex_lock(&input_mutex);
keybuffer_push(&active_console->keybuffer, &ev);
fibril_condvar_broadcast(&input_cv);
fibril_mutex_unlock(&input_mutex);
break;
default:
retval = ENOENT;
452,6 → 482,9
write_char(cons, ch);
}
if (cons == active_console)
curs_goto(cons->scr.position_x, cons->scr.position_y);
async_serialize_end();
gcons_notify_char(cons->index);
477,10 → 510,10
return;
}
async_serialize_start();
size_t pos = 0;
console_event_t ev;
fibril_mutex_lock(&input_mutex);
recheck:
while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) {
if (ev.type == KEY_PRESS) {
buf[pos] = ev.c;
493,25 → 526,50
ipc_answer_1(rid, EOK, size);
free(buf);
} else {
fibril_condvar_wait(&input_cv, &input_mutex);
goto recheck;
pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
if (!pr) {
ipc_answer_0(callid, ENOMEM);
ipc_answer_0(rid, ENOMEM);
free(buf);
async_serialize_end();
return;
}
pr->cons = cons;
pr->rid = rid;
pr->callid = callid;
pr->pos = pos;
pr->size = size;
pr->data = buf;
list_append(&pr->link, &pending_input);
}
fibril_mutex_unlock(&input_mutex);
async_serialize_end();
}
 
static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
{
async_serialize_start();
console_event_t ev;
 
fibril_mutex_lock(&input_mutex);
recheck:
if (keybuffer_pop(&cons->keybuffer, &ev)) {
ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
} else {
fibril_condvar_wait(&input_cv, &input_mutex);
goto recheck;
pending_input_t *pr = (pending_input_t *) malloc(sizeof(pending_input_t));
if (!pr) {
ipc_answer_0(rid, ENOMEM);
async_serialize_end();
return;
}
pr->cons = cons;
pr->rid = rid;
pr->callid = 0;
pr->data = NULL;
list_append(&pr->link, &pending_input);
}
fibril_mutex_unlock(&input_mutex);
async_serialize_end();
}
 
/** Default thread for new connections */
540,9 → 598,6
ipcarg_t arg1;
ipcarg_t arg2;
ipcarg_t arg3;
 
int cons_ccap;
int rc;
async_serialize_start();
if (cons->refcount == 0)
568,17 → 623,17
if (cons->refcount == 0)
gcons_notify_disconnect(cons->index);
return;
case VFS_OUT_READ:
case VFS_READ:
async_serialize_end();
cons_read(cons, callid, &call);
async_serialize_start();
continue;
case VFS_OUT_WRITE:
case VFS_WRITE:
async_serialize_end();
cons_write(cons, callid, &call);
async_serialize_start();
continue;
case VFS_OUT_SYNC:
case VFS_SYNC:
fb_pending_flush();
if (cons == active_console) {
async_req_0_0(fb_info.phone, FB_FLUSH);
605,14 → 660,6
arg1 = fb_info.cols;
arg2 = fb_info.rows;
break;
case CONSOLE_GET_COLOR_CAP:
rc = ccap_fb_to_con(fb_info.color_cap, &cons_ccap);
if (rc != EOK) {
ipc_answer_0(callid, rc);
continue;
}
arg1 = cons_ccap;
break;
case CONSOLE_SET_STYLE:
fb_pending_flush();
arg1 = IPC_GET_ARG1(call);
664,12 → 711,13
 
static bool console_init(void)
{
ipcarg_t color_cap;
 
async_serialize_start();
/* Connect to keyboard driver */
kbd_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_KEYBOARD, 0, 0);
if (kbd_phone < 0) {
printf(NAME ": Failed to connect to keyboard service\n");
async_serialize_end();
return false;
}
676,15 → 724,18
ipcarg_t phonehash;
if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
printf(NAME ": Failed to create callback from keyboard service\n");
async_serialize_end();
return false;
}
async_set_pending(process_pending_input);
async_new_connection(phonehash, 0, NULL, keyboard_events);
 
/* Connect to framebuffer driver */
fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
if (fb_info.phone < 0) {
printf(NAME ": Failed to connect to video service\n");
async_serialize_end();
return -1;
}
692,6 → 743,7
int rc = devmap_driver_register(NAME, client_connection);
if (rc < 0) {
printf(NAME ": Unable to register driver (%d)\n", rc);
async_serialize_end();
return false;
}
701,8 → 753,6
/* Synchronize, the gcons could put something in queue */
async_req_0_0(fb_info.phone, FB_FLUSH);
async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &color_cap);
fb_info.color_cap = color_cap;
/* Set up shared memory buffer. */
size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
729,6 → 779,7
if (screenbuffer_init(&consoles[i].scr,
fb_info.cols, fb_info.rows) == NULL) {
printf(NAME ": Unable to allocate screen buffer %u\n", i);
async_serialize_end();
return false;
}
screenbuffer_clear(&consoles[i].scr);
742,6 → 793,7
if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
devmap_hangup_phone(DEVMAP_DRIVER);
printf(NAME ": Unable to register device %s\n", vc);
async_serialize_end();
return false;
}
}
751,13 → 803,11
__SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
/* Initialize the screen */
async_serialize_start();
gcons_redraw_console();
set_rgb_color(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
screen_clear();
curs_goto(0, 0);
curs_visibility(active_console->scr.is_cursor_visible);
async_serialize_end();
/* Receive kernel notifications */
if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
765,6 → 815,7
async_set_interrupt_received(interrupt_received);
async_serialize_end();
return true;
}