Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4166 → Rev 4167

/trunk/uspace/lib/libc/include/ipc/fb.h
39,7 → 39,6
 
typedef enum {
FB_PUTCHAR = IPC_FIRST_USER_METHOD,
FB_WRITE,
FB_CLEAR,
FB_GET_CSIZE,
FB_CURSOR_VISIBILITY,
/trunk/uspace/srv/console/console.c
62,8 → 62,7
int active_console = 0;
int prev_console = 0;
 
/** Information about framebuffer
*/
/** Information about framebuffer */
struct {
int phone; /**< Framebuffer phone */
ipcarg_t rows; /**< Framebuffer rows */
89,18 → 88,14
* with framebufer used for
* faster virtual console
* switching */
/** Size of fb_buf. */
#define FB_BUF_SIZE 256
 
/** Buffer for sending characters to FB driver. */
static char fb_buf[FB_BUF_SIZE];
/** Information on row-span yet unsent to FB driver. */
struct {
int row; /**< Row where the span lies. */
int col; /**< Leftmost column of the span. */
int n; /**< Width of the span. */
} fb_pending;
 
/* Properties of fb_buf data. */
static int fb_buf_row; /**< Row where fb_buf data belong. */
static int fb_buf_col; /**< Column where fb_buf data start. */
static int fb_console; /**< VC to which fb_buf data belong. */
int fb_bi = 0; /**< Number of valid chars in fb_buf. */
 
/** Size of cwrite_buf. */
#define CWRITE_BUF_SIZE 256
 
107,7 → 102,9
/** Buffer for receiving data via the CONSOLE_WRITE call from the client. */
static char cwrite_buf[CWRITE_BUF_SIZE];
 
static void fb_putchar(char c, int row, int col);
 
 
/** Find unused virtual console.
*
*/
175,72 → 172,90
}
}
 
/** Write a character vector to FB driver via IPC. */
static ssize_t fb_write(const char *buf, size_t nbyte, int row, int col)
/** Send an area of screenbuffer to the FB driver. */
static void fb_update_area(connection_t *conn, int x, int y, int w, int h)
{
ipcarg_t rc;
ipc_call_t answer;
aid_t req;
int i, j;
int rc;
attrs_t *attrs;
keyfield_t *field;
 
async_serialize_start();
req = async_send_2(fb_info.phone, FB_WRITE, row, col, &answer);
rc = ipc_data_write_start(fb_info.phone, (void *) buf, nbyte);
if (interbuffer) {
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
interbuffer[i + j * w] =
*get_field_at(&conn->screenbuffer,
x + i, y + j);
}
}
 
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
return (ssize_t) rc;
rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
x, y, w, h);
} else {
rc = ENOTSUP;
}
 
async_wait_for(req, &rc);
async_serialize_end();
if (rc != 0) {
attrs = &conn->screenbuffer.attrs;
 
if (rc == EOK)
return (ssize_t) IPC_GET_ARG1(answer);
else
return -1;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
field = get_field_at(&conn->screenbuffer,
x + i, y + j);
if (!attrs_same(*attrs, field->attrs))
set_attrs(&field->attrs);
attrs = &field->attrs;
 
fb_putchar(field->character, y + j, x + i);
}
}
}
}
 
/** Flush buffered characters to FB. */
static void fb_buf_flush(void)
/** Flush pending cells to FB. */
static void fb_pending_flush(void)
{
screenbuffer_t *scr;
int i;
 
scr = &(connections[fb_console].screenbuffer);
scr = &(connections[active_console].screenbuffer);
 
if (fb_bi > 0) {
if (fb_write(fb_buf, fb_bi, fb_buf_row, fb_buf_col) < 0) {
/* Try falling back to char-by-char. */
for (i = 0; i < fb_bi; i++) {
async_msg_3(fb_info.phone, FB_PUTCHAR, fb_buf[i],
fb_buf_row, fb_buf_col + i);
}
}
fb_bi = 0;
if (fb_pending.n > 0) {
fb_update_area(&connections[active_console], fb_pending.col,
fb_pending.row, fb_pending.n, 1);
fb_pending.n = 0;
}
}
 
/** Print a character to the active VC with buffering. */
static void prtchr(char c, int row, int col)
/** Mark a character cell as changed.
*
* This adds the cell to the pending rowspan if possible. Otherwise
* the old span is flushed first.
*/
static void cell_mark_changed(int row, int col)
{
if (fb_bi >= FB_BUF_SIZE)
fb_buf_flush();
if (fb_pending.n != 0) {
if (row != fb_pending.row ||
col != fb_pending.col + fb_pending.n) {
fb_pending_flush();
}
}
 
if (fb_bi == 0) {
fb_buf_row = row;
fb_buf_col = col;
fb_console = active_console;
if (fb_pending.n == 0) {
fb_pending.row = row;
fb_pending.col = col;
}
 
fb_buf[fb_bi++] = c;
++fb_pending.n;
}
 
/** Check key and process special keys.
*
*
*/
 
/** Print a character to the active VC with buffering. */
static void fb_putchar(char c, int row, int col)
{
async_msg_3(fb_info.phone, FB_PUTCHAR, c, row, col);
}
 
/** Process a character from the client (TTY emulation). */
static void write_char(int console, char key)
{
bool flush_cursor = false;
248,31 → 263,28
 
switch (key) {
case '\n':
fb_buf_flush();
fb_pending_flush();
flush_cursor = true;
scr->position_y++;
scr->position_x = 0;
break;
case '\r':
fb_buf_flush();
break;
case '\t':
fb_buf_flush();
scr->position_x += 8;
scr->position_x -= scr->position_x % 8;
break;
case '\b':
fb_buf_flush();
if (scr->position_x == 0)
break;
scr->position_x--;
if (console == active_console)
prtchr(' ', scr->position_y, scr->position_x);
cell_mark_changed(scr->position_y, scr->position_x);
screenbuffer_putchar(scr, ' ');
break;
default:
if (console == active_console)
prtchr(key, scr->position_y, scr->position_x);
cell_mark_changed(scr->position_y, scr->position_x);
 
screenbuffer_putchar(scr, key);
scr->position_x++;
279,12 → 291,12
}
 
if (scr->position_x >= scr->size_x) {
fb_buf_flush();
flush_cursor = true;
scr->position_y++;
}
if (scr->position_y >= scr->size_y) {
fb_pending_flush();
scr->position_y = scr->size_y - 1;
screenbuffer_clear_line(scr, scr->top_line);
scr->top_line = (scr->top_line + 1) % scr->size_y;
309,7 → 321,7
if (newcons == active_console)
return;
 
fb_buf_flush();
fb_pending_flush();
 
if (newcons == KERNEL_CONSOLE) {
async_serialize_start();
337,16 → 349,19
set_attrs(&conn->screenbuffer.attrs);
curs_visibility(false);
if (interbuffer) {
for (i = 0; i < conn->screenbuffer.size_x; i++)
for (j = 0; j < conn->screenbuffer.size_y; j++) {
for (j = 0; j < conn->screenbuffer.size_y; j++) {
for (i = 0; i < conn->screenbuffer.size_x; i++) {
unsigned int size_x;
size_x = conn->screenbuffer.size_x;
interbuffer[i + j * size_x] =
interbuffer[j * size_x + i] =
*get_field_at(&conn->screenbuffer, i, j);
}
}
/* This call can preempt, but we are already at the end */
rc = async_req_0_0(fb_info.phone, FB_DRAW_TEXT_DATA);
rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
0, 0, conn->screenbuffer.size_x,
conn->screenbuffer.size_y);
}
if ((!interbuffer) || (rc != 0)) {
365,7 → 380,7
conn->screenbuffer.attrs)))
continue;
 
prtchr(field->character, j, i);
fb_putchar(field->character, j, i);
}
}
478,6 → 493,7
int consnum;
ipcarg_t arg1, arg2, arg3, arg4;
connection_t *conn;
screenbuffer_t *scr;
if ((consnum = find_free_connection()) == -1) {
ipc_answer_0(iid, ELIMIT);
534,7 → 550,6
break;
case CONSOLE_GOTO:
fb_buf_flush();
screenbuffer_goto(&conn->screenbuffer,
IPC_GET_ARG2(call), IPC_GET_ARG1(call));
if (consnum == active_console)
546,12 → 561,16
arg2 = fb_info.cols;
break;
case CONSOLE_FLUSH:
fb_buf_flush();
if (consnum == active_console)
fb_pending_flush();
if (consnum == active_console) {
async_req_0_0(fb_info.phone, FB_FLUSH);
 
scr = &(connections[consnum].screenbuffer);
curs_goto(scr->position_y, scr->position_x);
}
break;
case CONSOLE_SET_STYLE:
fb_buf_flush();
fb_pending_flush();
arg1 = IPC_GET_ARG1(call);
screenbuffer_set_style(&conn->screenbuffer, arg1);
if (consnum == active_console)
558,7 → 577,7
set_style(arg1);
break;
case CONSOLE_SET_COLOR:
fb_buf_flush();
fb_pending_flush();
arg1 = IPC_GET_ARG1(call);
arg2 = IPC_GET_ARG2(call);
arg3 = IPC_GET_ARG3(call);
568,7 → 587,7
set_color(arg1, arg2, arg3);
break;
case CONSOLE_SET_RGB_COLOR:
fb_buf_flush();
fb_pending_flush();
arg1 = IPC_GET_ARG1(call);
arg2 = IPC_GET_ARG2(call);
screenbuffer_set_rgb_color(&conn->screenbuffer, arg1,
577,7 → 596,7
set_rgb_color(arg1, arg2);
break;
case CONSOLE_CURSOR_VISIBILITY:
fb_buf_flush();
fb_pending_flush();
arg1 = IPC_GET_ARG1(call);
conn->screenbuffer.is_cursor_visible = arg1;
if (consnum == active_console)
683,6 → 702,8
ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows;
interbuffer = as_get_mappable_page(ib_size);
 
fb_pending.n = 0;
 
if (as_area_create(interbuffer, ib_size, AS_AREA_READ |
AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer) {
interbuffer = NULL;
/trunk/uspace/srv/fb/serial_console.c
223,21 → 223,40
}
}
 
static void draw_text_data(keyfield_t *data)
/** Draw text data to viewport.
*
* @param vport Viewport id
* @param data Text data.
* @param x Leftmost column of the area.
* @param y Topmost row of the area.
* @param w Number of rows.
* @param h Number of columns.
*/
static void draw_text_data(keyfield_t *data, unsigned int x,
unsigned int y, unsigned int w, unsigned int h)
{
int i, j;
unsigned int i, j;
keyfield_t *field;
attrs_t *a0, *a1;
 
serial_goto(0, 0);
serial_goto(y, x);
a0 = &data[0].attrs;
serial_set_attrs(a0);
 
for (i = 0; i < scr_height; i++) {
for (j = 0; j < scr_width; j++) {
a1 = &data[i * scr_width + j].attrs;
for (j = 0; j < h; j++) {
if (j > 0 && w != scr_width)
serial_goto(y, x);
 
for (i = 0; i < w; i++) {
unsigned int col = x + i;
unsigned int row = y + j;
 
field = &data[j * w + i];
 
a1 = &field->attrs;
if (!attrs_same(*a0, *a1))
serial_set_attrs(a1);
(*putc_function)(data[i * scr_width + j].character);
(*putc_function)(field->character);
a0 = a1;
}
}
246,51 → 265,6
int lastcol = 0;
int lastrow = 0;
 
#define FB_WRITE_BUF_SIZE 256
static char fb_write_buf[FB_WRITE_BUF_SIZE];
 
static void fb_write(ipc_callid_t rid, ipc_call_t *request)
{
int row, col;
ipc_callid_t callid;
size_t len;
size_t i;
 
row = IPC_GET_ARG1(*request);
col = IPC_GET_ARG2(*request);
 
if ((col >= scr_width) || (row >= scr_height)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
if (!ipc_data_write_receive(&callid, &len)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
if (len > FB_WRITE_BUF_SIZE)
len = FB_WRITE_BUF_SIZE;
if (len >= scr_width - col)
len = scr_width - col;
 
(void) ipc_data_write_finalize(callid, fb_write_buf, len);
 
if ((lastcol != col) || (lastrow != row))
serial_goto(row, col);
 
for (i = 0; i < len; i++) {
(*putc_function)(fb_write_buf[i]);
}
 
lastcol = col + len;
lastrow = row;
 
ipc_answer_1(rid, EOK, len);
}
 
/**
* Main function of the thread serving client connections.
*/
303,8 → 277,7
size_t intersize = 0;
 
char c;
int newcol;
int newrow;
int col, row, w, h;
int fgcolor;
int bgcolor;
int flags;
345,35 → 318,40
retval = EINVAL;
break;
case FB_DRAW_TEXT_DATA:
col = IPC_GET_ARG1(call);
row = IPC_GET_ARG2(call);
w = IPC_GET_ARG3(call);
h = IPC_GET_ARG4(call);
if (!interbuf) {
retval = EINVAL;
break;
}
draw_text_data(interbuf);
if (col + w > scr_width || row + h > scr_height) {
retval = EINVAL;
break;
}
draw_text_data(interbuf, col, row, w, h);
lastrow = row + h - 1;
lastcol = col + w;
retval = 0;
break;
case FB_PUTCHAR:
c = IPC_GET_ARG1(call);
newrow = IPC_GET_ARG2(call);
newcol = IPC_GET_ARG3(call);
if ((lastcol != newcol) || (lastrow != newrow))
serial_goto(newrow, newcol);
lastcol = newcol + 1;
lastrow = newrow;
row = IPC_GET_ARG2(call);
col = IPC_GET_ARG3(call);
if ((lastcol != col) || (lastrow != row))
serial_goto(row, col);
lastcol = col + 1;
lastrow = row;
(*putc_function)(c);
retval = 0;
break;
case FB_WRITE:
fb_write(callid, &call);
/* Message already answered */
continue;
case FB_CURSOR_GOTO:
newrow = IPC_GET_ARG1(call);
newcol = IPC_GET_ARG2(call);
serial_goto(newrow, newcol);
lastrow = newrow;
lastcol = newcol;
row = IPC_GET_ARG1(call);
col = IPC_GET_ARG2(call);
serial_goto(row, col);
lastrow = row;
lastcol = col;
retval = 0;
break;
case FB_GET_CSIZE:
/trunk/uspace/srv/fb/msim.c
45,7 → 45,7
#include "msim.h"
 
#define WIDTH 80
#define HEIGHT 25
#define HEIGHT 24
 
static char *virt_addr;
 
/trunk/uspace/srv/fb/ski.c
47,7 → 47,7
#define SKI_PUTCHAR 31
 
#define WIDTH 80
#define HEIGHT 25
#define HEIGHT 24
 
/** Display character on ski debug console
*
/trunk/uspace/srv/fb/fb.c
866,35 → 866,40
cursor_show(vport);
}
 
 
/** Draw text data to viewport
/** Draw text data to viewport.
*
* @param vport Viewport id
* @param data Text data fitting exactly into viewport
*
* @param data Text data.
* @param x Leftmost column of the area.
* @param y Topmost row of the area.
* @param w Number of rows.
* @param h Number of columns.
*/
static void draw_text_data(viewport_t *vport, keyfield_t *data)
static void draw_text_data(viewport_t *vport, keyfield_t *data, unsigned int x,
unsigned int y, unsigned int w, unsigned int h)
{
unsigned int i;
unsigned int i, j;
bb_cell_t *bbp;
attrs_t *a;
attr_rgb_t rgb;
for (i = 0; i < vport->cols * vport->rows; i++) {
unsigned int col = i % vport->cols;
unsigned int row = i / vport->cols;
bbp = &vport->backbuf[BB_POS(vport, col, row)];
uint8_t glyph = bbp->glyph;
 
a = &data[i].attrs;
rgb_from_attr(&rgb, a);
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
unsigned int col = x + i;
unsigned int row = y + j;
 
bbp->glyph = data[i].character;
bbp->fg_color = rgb.fg_color;
bbp->bg_color = rgb.bg_color;
bbp = &vport->backbuf[BB_POS(vport, col, row)];
uint8_t glyph = bbp->glyph;
 
draw_vp_glyph(vport, false, col, row);
a = &data[j * w + i].attrs;
rgb_from_attr(&rgb, a);
 
bbp->glyph = data[j * w + i].character;
bbp->fg_color = rgb.fg_color;
bbp->bg_color = rgb.bg_color;
 
draw_vp_glyph(vport, false, col, row);
}
}
cursor_show(vport);
}
998,6 → 1003,8
viewport_t *vport = &viewports[vp];
unsigned int x;
unsigned int y;
unsigned int w;
unsigned int h;
switch (IPC_GET_METHOD(*call)) {
case IPC_M_SHARE_OUT:
1058,15 → 1065,23
IPC_GET_ARG2(*call), vport->width - x, vport->height - y, putpixel, (void *) vport);
break;
case FB_DRAW_TEXT_DATA:
x = IPC_GET_ARG1(*call);
y = IPC_GET_ARG2(*call);
w = IPC_GET_ARG3(*call);
h = IPC_GET_ARG4(*call);
if (!interbuffer) {
retval = EINVAL;
break;
}
if (intersize < vport->cols * vport->rows * sizeof(*interbuffer)) {
if (x + w > vport->cols || y + h > vport->rows) {
retval = EINVAL;
break;
}
draw_text_data(vport, interbuffer);
if (intersize < w * h * sizeof(*interbuffer)) {
retval = EINVAL;
break;
}
draw_text_data(vport, interbuffer, x, y, w, h);
break;
default:
handled = false;
1472,46 → 1487,6
return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);
}
 
#define FB_WRITE_BUF_SIZE 256
static char fb_write_buf[FB_WRITE_BUF_SIZE];
 
static void fb_write(viewport_t *vport, ipc_callid_t rid, ipc_call_t *request)
{
int row, col;
ipc_callid_t callid;
size_t len;
size_t i;
 
row = IPC_GET_ARG1(*request);
col = IPC_GET_ARG2(*request);
 
if ((col >= vport->cols) || (row >= vport->rows)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
if (!ipc_data_write_receive(&callid, &len)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
if (len > FB_WRITE_BUF_SIZE)
len = FB_WRITE_BUF_SIZE;
if (len >= vport->cols - col)
len = vport->cols - col;
 
(void) ipc_data_write_finalize(callid, fb_write_buf, len);
 
for (i = 0; i < len; i++) {
draw_char(vport, fb_write_buf[i], col++, row);
}
 
ipc_answer_1(rid, EOK, len);
}
 
 
/** Function for handling connections to FB
*
*/
1586,11 → 1561,6
/* Message already answered */
continue;
case FB_WRITE:
fb_write(vport, callid, &call);
/* Message already answered */
continue;
case FB_CLEAR:
vport_clear(vport);
cursor_show(vport);
/trunk/uspace/srv/fb/ega.c
78,7 → 78,7
 
static unsigned int scr_width;
static unsigned int scr_height;
static char *scr_addr;
static uint8_t *scr_addr;
 
static unsigned int style;
 
151,13 → 151,30
cursor_goto(row, col + 1);
}
 
static void draw_text_data(keyfield_t *data)
/** Draw text data to viewport.
*
* @param vport Viewport id
* @param data Text data.
* @param x Leftmost column of the area.
* @param y Topmost row of the area.
* @param w Number of rows.
* @param h Number of columns.
*/
static void draw_text_data(keyfield_t *data, unsigned int x,
unsigned int y, unsigned int w, unsigned int h)
{
int i;
unsigned int i, j;
keyfield_t *field;
uint8_t *dp;
 
for (i = 0; i < scr_width * scr_height; i++) {
scr_addr[i * 2] = data[i].character;
scr_addr[i * 2 + 1] = attr_to_ega_style(&data[i].attrs);
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
field = &data[j * w + i];
dp = &scr_addr[2 * ((y + j) * scr_width + (x + i))];
 
dp[0] = field->character;
dp[1] = attr_to_ega_style(&field->attrs);
}
}
}
 
231,45 → 248,6
}
}
 
#define FB_WRITE_BUF_SIZE 256
static char fb_write_buf[FB_WRITE_BUF_SIZE];
 
static void fb_write(ipc_callid_t rid, ipc_call_t *request)
{
int row, col;
ipc_callid_t callid;
size_t len;
size_t i;
 
row = IPC_GET_ARG1(*request);
col = IPC_GET_ARG2(*request);
 
if ((col >= scr_width) || (row >= scr_height)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
if (!ipc_data_write_receive(&callid, &len)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
if (len > FB_WRITE_BUF_SIZE)
len = FB_WRITE_BUF_SIZE;
if (len >= scr_width - col)
len = scr_width - col;
 
(void) ipc_data_write_finalize(callid, fb_write_buf, len);
 
for (i = 0; i < len; i++) {
printchar(fb_write_buf[i], row, col++);
}
 
ipc_answer_1(rid, EOK, len);
}
 
static void ega_client_connection(ipc_callid_t iid, ipc_call_t *icall)
{
int retval;
276,7 → 254,7
ipc_callid_t callid;
ipc_call_t call;
char c;
unsigned int row, col;
unsigned int row, col, w, h;
int bg_color, fg_color, attr;
uint32_t bg_rgb, fg_rgb;
keyfield_t *interbuf = NULL;
309,11 → 287,19
retval = EINVAL;
break;
case FB_DRAW_TEXT_DATA:
col = IPC_GET_ARG1(call);
row = IPC_GET_ARG2(call);
w = IPC_GET_ARG3(call);
h = IPC_GET_ARG4(call);
if (!interbuf) {
retval = EINVAL;
break;
}
draw_text_data(interbuf);
if (col + w > scr_width || row + h > scr_height) {
retval = EINVAL;
break;
}
draw_text_data(interbuf, col, row, w, h);
retval = 0;
break;
case FB_GET_CSIZE:
334,11 → 320,6
printchar(c, row, col);
retval = 0;
break;
case FB_WRITE:
fb_write(callid, &call);
 
/* Message already answered */
continue;
case FB_CURSOR_GOTO:
row = IPC_GET_ARG1(call);
col = IPC_GET_ARG2(call);