00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035
00036 #include <stdio.h>
00037
00038 #include <fb.h>
00039 #include <ipc/ipc.h>
00040 #include <keys.h>
00041 #include <ipc/fb.h>
00042 #include <ipc/services.h>
00043 #include <errno.h>
00044 #include <key_buffer.h>
00045 #include <console.h>
00046 #include <unistd.h>
00047 #include <async.h>
00048 #include <libadt/fifo.h>
00049 #include <screenbuffer.h>
00050 #include <sys/mman.h>
00051
00052 #include "gcons.h"
00053
00054 #define MAX_KEYREQUESTS_BUFFERED 32
00055
00056 #define NAME "CONSOLE"
00057
00060 int active_console = 0;
00061
00064 struct {
00065 int phone;
00066 ipcarg_t rows;
00067 ipcarg_t cols;
00068 } fb_info;
00069
00070
00071 typedef struct {
00072 keybuffer_t keybuffer;
00073 FIFO_CREATE_STATIC(keyrequests, ipc_callid_t , MAX_KEYREQUESTS_BUFFERED);
00074 int keyrequest_counter;
00075 int client_phone;
00076 int used;
00077 screenbuffer_t screenbuffer;
00078 } connection_t;
00079
00080 static connection_t connections[CONSOLE_COUNT];
00081 static keyfield_t *interbuffer = NULL;
00083 static int kernel_pixmap = -1;
00089 static int find_free_connection(void)
00090 {
00091 int i = 0;
00092
00093 for (i=0; i < CONSOLE_COUNT; i++) {
00094 if (!connections[i].used)
00095 return i;
00096 }
00097 return -1;
00098 }
00099
00100 static void clrscr(void)
00101 {
00102 async_msg(fb_info.phone, FB_CLEAR, 0);
00103 }
00104
00105 static void curs_visibility(int v)
00106 {
00107 async_msg(fb_info.phone, FB_CURSOR_VISIBILITY, v);
00108 }
00109
00110 static void curs_goto(int row, int col)
00111 {
00112 async_msg_2(fb_info.phone, FB_CURSOR_GOTO, row, col);
00113
00114 }
00115
00116 static void set_style(style_t *style)
00117 {
00118 async_msg_2(fb_info.phone, FB_SET_STYLE, style->fg_color, style->bg_color);
00119 }
00120
00121 static void set_style_col(int fgcolor, int bgcolor)
00122 {
00123 async_msg_2(fb_info.phone, FB_SET_STYLE, fgcolor, bgcolor);
00124 }
00125
00126 static void prtchr(char c, int row, int col)
00127 {
00128 async_msg_3(fb_info.phone, FB_PUTCHAR, c, row, col);
00129
00130 }
00131
00135 static void write_char(int console, char key)
00136 {
00137 screenbuffer_t *scr = &(connections[console].screenbuffer);
00138
00139 switch (key) {
00140 case '\n':
00141 scr->position_y += 1;
00142 scr->position_x = 0;
00143 break;
00144 case '\r':
00145 break;
00146 case '\t':
00147 scr->position_x += 8;
00148 scr->position_x -= scr->position_x % 8;
00149 break;
00150 case '\b':
00151 if (scr->position_x == 0)
00152 break;
00153
00154 scr->position_x--;
00155
00156 if (console == active_console)
00157 prtchr(' ', scr->position_y, scr->position_x);
00158
00159 screenbuffer_putchar(scr, ' ');
00160
00161 break;
00162 default:
00163 if (console == active_console)
00164 prtchr(key, scr->position_y, scr->position_x);
00165
00166 screenbuffer_putchar(scr, key);
00167 scr->position_x++;
00168 }
00169
00170 scr->position_y += (scr->position_x >= scr->size_x);
00171
00172 if (scr->position_y >= scr->size_y) {
00173 scr->position_y = scr->size_y - 1;
00174 screenbuffer_clear_line(scr, scr->top_line);
00175 scr->top_line = (scr->top_line+1) % scr->size_y;
00176 if (console == active_console)
00177 async_msg(fb_info.phone, FB_SCROLL, 1);
00178 }
00179
00180 scr->position_x = scr->position_x % scr->size_x;
00181
00182 if (console == active_console)
00183 curs_goto(scr->position_y, scr->position_x);
00184
00185 }
00186
00192 static int switch_screens(int oldpixmap)
00193 {
00194 int newpmap;
00195
00196
00197 newpmap = async_req(fb_info.phone, FB_VP2PIXMAP, 0, NULL);
00198 if (newpmap < 0)
00199 return -1;
00200
00201 if (oldpixmap != -1) {
00202
00203 async_msg_2(fb_info.phone, FB_VP_DRAW_PIXMAP, 0, oldpixmap);
00204
00205 async_msg(fb_info.phone, FB_DROP_PIXMAP, oldpixmap);
00206 }
00207
00208 return newpmap;
00209 }
00210
00212 static void change_console(int newcons)
00213 {
00214 connection_t *conn;
00215 static int console_pixmap = -1;
00216 int i, j, rc;
00217 keyfield_t *field;
00218 style_t *style;
00219
00220 if (newcons == active_console)
00221 return;
00222
00223 if (newcons == KERNEL_CONSOLE) {
00224 if (active_console == KERNEL_CONSOLE)
00225 return;
00226 active_console = KERNEL_CONSOLE;
00227 curs_visibility(0);
00228
00229 async_serialize_start();
00230 if (kernel_pixmap == -1) {
00231
00232 set_style_col(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
00233 clrscr();
00234 } else {
00235 gcons_in_kernel();
00236 console_pixmap = switch_screens(kernel_pixmap);
00237 kernel_pixmap = -1;
00238 }
00239 async_serialize_end();
00240
00241 __SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE);
00242 return;
00243 }
00244
00245 async_serialize_start();
00246
00247 if (console_pixmap != -1) {
00248 kernel_pixmap = switch_screens(console_pixmap);
00249 console_pixmap = -1;
00250 }
00251 active_console = newcons;
00252 gcons_change_console(newcons);
00253 conn = &connections[active_console];
00254
00255 set_style(&conn->screenbuffer.style);
00256 curs_visibility(0);
00257 if (interbuffer) {
00258 for (i = 0; i < conn->screenbuffer.size_x; i++)
00259 for (j = 0; j < conn->screenbuffer.size_y; j++)
00260 interbuffer[i + j*conn->screenbuffer.size_x] = *get_field_at(&(conn->screenbuffer),i, j);
00261
00262 rc = async_req_2(fb_info.phone, FB_DRAW_TEXT_DATA, 0, 0, NULL, NULL);
00263 };
00264
00265 if ((!interbuffer) || (rc != 0)) {
00266 set_style(&conn->screenbuffer.style);
00267 clrscr();
00268 style = &conn->screenbuffer.style;
00269
00270 for (j = 0; j < conn->screenbuffer.size_y; j++)
00271 for (i = 0; i < conn->screenbuffer.size_x; i++) {
00272 field = get_field_at(&(conn->screenbuffer),i, j);
00273 if (!style_same(*style, field->style))
00274 set_style(&field->style);
00275 style = &field->style;
00276 if ((field->character == ' ') && (style_same(field->style, conn->screenbuffer.style)))
00277 continue;
00278
00279 prtchr(field->character, j, i);
00280 }
00281 }
00282
00283 curs_goto(conn->screenbuffer.position_y, conn->screenbuffer.position_x);
00284 curs_visibility(conn->screenbuffer.is_cursor_visible);
00285
00286 async_serialize_end();
00287 }
00288
00290 static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
00291 {
00292 ipc_callid_t callid;
00293 ipc_call_t call;
00294 int retval;
00295 int c;
00296 connection_t *conn;
00297 int newcon;
00298
00299
00300 while (1) {
00301 callid = async_get_call(&call);
00302 switch (IPC_GET_METHOD(call)) {
00303 case IPC_M_PHONE_HUNGUP:
00304
00305 return;
00306 case KBD_MS_LEFT:
00307 newcon = gcons_mouse_btn(IPC_GET_ARG1(call));
00308 if (newcon != -1)
00309 change_console(newcon);
00310 retval = 0;
00311 break;
00312 case KBD_MS_MOVE:
00313 gcons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
00314 retval = 0;
00315 break;
00316 case KBD_PUSHCHAR:
00317
00318
00319 retval = 0;
00320 c = IPC_GET_ARG1(call);
00321
00322
00323 conn = &connections[active_console];
00324
00325 if ((c >= 0x101) && (c < 0x101 + CONSOLE_COUNT)) {
00326 if (c == 0x112)
00327 change_console(KERNEL_CONSOLE);
00328 else
00329 change_console(c - 0x101);
00330 break;
00331 }
00332
00333
00334 if (conn->keyrequest_counter > 0) {
00335 conn->keyrequest_counter--;
00336 ipc_answer_fast(fifo_pop(conn->keyrequests), 0, c, 0);
00337 break;
00338 }
00339
00340 keybuffer_push(&conn->keybuffer, c);
00341 retval = 0;
00342
00343 break;
00344 default:
00345 retval = ENOENT;
00346 }
00347 ipc_answer_fast(callid, retval, 0, 0);
00348 }
00349 }
00350
00352 static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
00353 {
00354 ipc_callid_t callid;
00355 ipc_call_t call;
00356 int consnum;
00357 ipcarg_t arg1, arg2;
00358 connection_t *conn;
00359
00360 if ((consnum = find_free_connection()) == -1) {
00361 ipc_answer_fast(iid,ELIMIT,0,0);
00362 return;
00363 }
00364 conn = &connections[consnum];
00365 conn->used = 1;
00366
00367 async_serialize_start();
00368 gcons_notify_connect(consnum);
00369 conn->client_phone = IPC_GET_ARG3(call);
00370 screenbuffer_clear(&conn->screenbuffer);
00371
00372
00373 ipc_answer_fast(iid,0,0,0);
00374
00375 while (1) {
00376 async_serialize_end();
00377 callid = async_get_call(&call);
00378 async_serialize_start();
00379
00380 arg1 = arg2 = 0;
00381 switch (IPC_GET_METHOD(call)) {
00382 case IPC_M_PHONE_HUNGUP:
00383 gcons_notify_disconnect(consnum);
00384
00385
00386 while (conn->keyrequest_counter > 0) {
00387 conn->keyrequest_counter--;
00388 ipc_answer_fast(fifo_pop(conn->keyrequests), ENOENT, 0, 0);
00389 break;
00390 }
00391 conn->used = 0;
00392 return;
00393 case CONSOLE_PUTCHAR:
00394 write_char(consnum, IPC_GET_ARG1(call));
00395 gcons_notify_char(consnum);
00396 break;
00397 case CONSOLE_CLEAR:
00398
00399 if (consnum == active_console) {
00400 async_msg(fb_info.phone, FB_CLEAR, 0);
00401 }
00402
00403 screenbuffer_clear(&conn->screenbuffer);
00404
00405 break;
00406 case CONSOLE_GOTO:
00407
00408 screenbuffer_goto(&conn->screenbuffer, IPC_GET_ARG2(call), IPC_GET_ARG1(call));
00409 if (consnum == active_console)
00410 curs_goto(IPC_GET_ARG1(call),IPC_GET_ARG2(call));
00411
00412 break;
00413
00414 case CONSOLE_GETSIZE:
00415 arg1 = fb_info.rows;
00416 arg2 = fb_info.cols;
00417 break;
00418 case CONSOLE_FLUSH:
00419 if (consnum == active_console)
00420 async_req_2(fb_info.phone, FB_FLUSH, 0, 0, NULL, NULL);
00421 break;
00422 case CONSOLE_SET_STYLE:
00423
00424 arg1 = IPC_GET_ARG1(call);
00425 arg2 = IPC_GET_ARG2(call);
00426 screenbuffer_set_style(&conn->screenbuffer,arg1, arg2);
00427 if (consnum == active_console)
00428 set_style_col(arg1, arg2);
00429
00430 break;
00431 case CONSOLE_CURSOR_VISIBILITY:
00432 arg1 = IPC_GET_ARG1(call);
00433 conn->screenbuffer.is_cursor_visible = arg1;
00434 if (consnum == active_console)
00435 curs_visibility(arg1);
00436 break;
00437 case CONSOLE_GETCHAR:
00438 if (keybuffer_empty(&conn->keybuffer)) {
00439
00440 if (conn->keyrequest_counter < MAX_KEYREQUESTS_BUFFERED) {
00441 fifo_push(conn->keyrequests, callid);
00442 conn->keyrequest_counter++;
00443 } else {
00444
00445 ipc_answer_fast(callid, ELIMIT, 0, 0);
00446 }
00447 continue;
00448 };
00449 keybuffer_pop(&conn->keybuffer, (int *)&arg1);
00450
00451 break;
00452 }
00453 ipc_answer_fast(callid, 0, arg1, arg2);
00454 }
00455 }
00456
00457 int main(int argc, char *argv[])
00458 {
00459 ipcarg_t phonehash;
00460 int kbd_phone;
00461 int i;
00462
00463 async_set_client_connection(client_connection);
00464
00465
00466
00467 while ((kbd_phone = ipc_connect_me_to(PHONE_NS, SERVICE_KEYBOARD, 0)) < 0) {
00468 usleep(10000);
00469 };
00470
00471 if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, &phonehash) != 0) {
00472 return -1;
00473 };
00474 async_new_connection(phonehash, 0, NULL, keyboard_events);
00475
00476
00477
00478 while ((fb_info.phone = ipc_connect_me_to(PHONE_NS, SERVICE_VIDEO, 0)) < 0) {
00479 usleep(10000);
00480 }
00481
00482
00483 kernel_pixmap = switch_screens(-1);
00484
00485
00486 gcons_init(fb_info.phone);
00487
00488 async_req(fb_info.phone, FB_FLUSH, 0, NULL);
00489
00490 async_msg_2(fb_info.phone, FB_VIEWPORT_DB, (sysarg_t)-1, 1);
00491
00492 async_req_2(fb_info.phone, FB_GET_CSIZE, 0, 0, &(fb_info.rows), &(fb_info.cols));
00493 set_style_col(DEFAULT_FOREGROUND, DEFAULT_BACKGROUND);
00494 clrscr();
00495
00496
00497 for (i = 0; i < CONSOLE_COUNT; i++) {
00498 connections[i].used = 0;
00499 keybuffer_init(&(connections[i].keybuffer));
00500
00501 connections[i].keyrequests.head = connections[i].keyrequests.tail = 0;
00502 connections[i].keyrequests.items = MAX_KEYREQUESTS_BUFFERED;
00503 connections[i].keyrequest_counter = 0;
00504
00505 if (screenbuffer_init(&(connections[i].screenbuffer), fb_info.cols, fb_info.rows ) == NULL) {
00506
00507 return -1;
00508 }
00509 }
00510 connections[KERNEL_CONSOLE].used = 1;
00511
00512 if ((interbuffer = mmap(NULL, sizeof(keyfield_t) * fb_info.cols * fb_info.rows , PROTO_READ|PROTO_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0 ,0 )) != NULL) {
00513 if (async_req_3(fb_info.phone, IPC_M_AS_AREA_SEND, (ipcarg_t)interbuffer, 0, AS_AREA_READ, NULL, NULL, NULL) != 0) {
00514 munmap(interbuffer, sizeof(keyfield_t) * fb_info.cols * fb_info.rows);
00515 interbuffer = NULL;
00516 }
00517 }
00518
00519 curs_goto(0,0);
00520 curs_visibility(connections[active_console].screenbuffer.is_cursor_visible);
00521
00522
00523 if (ipc_connect_to_me(PHONE_NS, SERVICE_CONSOLE, 0, &phonehash) != 0) {
00524 return -1;
00525 };
00526
00527 async_manager();
00528
00529 return 0;
00530 }
00531