Changes in uspace/srv/hid/console/console.c [ffa2c8ef:024fcc5] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/hid/console/console.c
rffa2c8ef r024fcc5 1 1 /* 2 * Copyright (c) 20 06 Josef Cejka2 * Copyright (c) 2011 Martin Decky 3 3 * All rights reserved. 4 4 * … … 33 33 */ 34 34 35 #include <libc.h> 36 #include <ipc/kbd.h> 35 #include <async.h> 36 #include <stdio.h> 37 #include <adt/prodcons.h> 38 #include <ipc/input.h> 39 #include <ipc/console.h> 40 #include <ipc/vfs.h> 41 #include <errno.h> 42 #include <str_error.h> 43 #include <loc.h> 44 #include <event.h> 37 45 #include <io/keycode.h> 38 #include <ipc/mouse.h> 39 #include <ipc/fb.h> 40 #include <ipc/services.h> 41 #include <ipc/ns.h> 42 #include <errno.h> 43 #include <ipc/console.h> 44 #include <unistd.h> 45 #include <async.h> 46 #include <adt/fifo.h> 47 #include <sys/mman.h> 48 #include <stdio.h> 49 #include <str.h> 50 #include <sysinfo.h> 51 #include <event.h> 52 #include <devmap.h> 53 #include <fcntl.h> 54 #include <vfs/vfs.h> 46 #include <screenbuffer.h> 47 #include <fb.h> 48 #include <imgmap.h> 49 #include <align.h> 50 #include <malloc.h> 51 #include <as.h> 55 52 #include <fibril_synch.h> 56 #include <io/style.h> 57 #include <io/screenbuffer.h> 58 53 #include "images.h" 59 54 #include "console.h" 60 #include "gcons.h"61 #include "keybuffer.h"62 63 55 64 56 #define NAME "console" 65 57 #define NAMESPACE "term" 66 58 67 /** Phone to the keyboard driver. */ 68 static int kbd_phone; 69 70 /** Phone to the mouse driver. */ 71 static int mouse_phone; 72 73 /** Information about framebuffer */ 74 struct { 75 int phone; /**< Framebuffer phone */ 76 sysarg_t cols; /**< Framebuffer columns */ 77 sysarg_t rows; /**< Framebuffer rows */ 78 sysarg_t color_cap; /**< Color capabilities (FB_CCAP_xxx) */ 79 } fb_info; 59 #define CONSOLE_TOP 66 60 #define CONSOLE_MARGIN 12 61 62 #define STATE_START 100 63 #define STATE_TOP 8 64 #define STATE_SPACE 4 65 #define STATE_WIDTH 48 66 #define STATE_HEIGHT 48 67 68 typedef enum { 69 CONS_DISCONNECTED = 0, 70 CONS_DISCONNECTED_SELECTED, 71 CONS_SELECTED, 72 CONS_IDLE, 73 CONS_DATA, 74 CONS_KERNEL, 75 CONS_LAST 76 } console_state_t; 80 77 81 78 typedef struct { 82 size_t index; /**< Console index */ 83 size_t refcount; /**< Connection reference count */ 84 devmap_handle_t devmap_handle; /**< Device handle */ 85 keybuffer_t keybuffer; /**< Buffer for incoming keys. */ 86 screenbuffer_t scr; /**< Screenbuffer for saving screen 87 contents and related settings. */ 79 atomic_t refcnt; /**< Connection reference count */ 80 prodcons_t input_pc; /**< Incoming keyboard events */ 81 82 fibril_mutex_t mtx; /**< Lock protecting mutable fields */ 83 84 size_t index; /**< Console index */ 85 console_state_t state; /**< Console state */ 86 service_id_t dsid; /**< Service handle */ 87 88 vp_handle_t state_vp; /**< State icon viewport */ 89 sysarg_t cols; /**< Number of columns */ 90 sysarg_t rows; /**< Number of rows */ 91 console_caps_t ccaps; /**< Console capabilities */ 92 93 screenbuffer_t *frontbuf; /**< Front buffer */ 94 frontbuf_handle_t fbid; /**< Front buffer handle */ 88 95 } console_t; 96 97 typedef enum { 98 GRAPHICS_NONE = 0, 99 GRAPHICS_BASIC = 1, 100 GRAPHICS_FULL = 2 101 } graphics_state_t; 102 103 /** Current console state */ 104 static graphics_state_t graphics_state = GRAPHICS_NONE; 105 106 /** State icons */ 107 static imagemap_handle_t state_icons[CONS_LAST]; 108 109 /** Session to the input server */ 110 static async_sess_t *input_sess; 111 112 /** Session to the framebuffer server */ 113 static async_sess_t *fb_sess; 114 115 /** Framebuffer resolution */ 116 static sysarg_t xres; 117 static sysarg_t yres; 89 118 90 119 /** Array of data for virtual consoles */ 91 120 static console_t consoles[CONSOLE_COUNT]; 92 121 122 /** Mutex for console switching */ 123 static FIBRIL_MUTEX_INITIALIZE(switch_mtx); 124 125 static console_t *prev_console = &consoles[0]; 93 126 static console_t *active_console = &consoles[0]; 94 static console_t *prev_console = &consoles[0];95 127 static console_t *kernel_console = &consoles[KERNEL_CONSOLE]; 96 128 97 /** Pointer to memory shared with framebufer used for 98 faster virtual console switching */ 99 static keyfield_t *interbuffer = NULL; 100 101 /** Information on row-span yet unsent to FB driver. */ 129 static imgmap_t *logo_img; 130 static imgmap_t *nameic_img; 131 132 static imgmap_t *anim_1_img; 133 static imgmap_t *anim_2_img; 134 static imgmap_t *anim_3_img; 135 static imgmap_t *anim_4_img; 136 137 static imagemap_handle_t anim_1; 138 static imagemap_handle_t anim_2; 139 static imagemap_handle_t anim_3; 140 static imagemap_handle_t anim_4; 141 142 static sequence_handle_t anim_seq; 143 144 static imgmap_t *cons_data_img; 145 static imgmap_t *cons_dis_img; 146 static imgmap_t *cons_dis_sel_img; 147 static imgmap_t *cons_idle_img; 148 static imgmap_t *cons_kernel_img; 149 static imgmap_t *cons_sel_img; 150 151 static vp_handle_t logo_vp; 152 static imagemap_handle_t logo_handle; 153 154 static vp_handle_t nameic_vp; 155 static imagemap_handle_t nameic_handle; 156 157 static vp_handle_t screen_vp; 158 static vp_handle_t console_vp; 159 102 160 struct { 103 sysarg_t col; /**< Leftmost column of the span. */ 104 sysarg_t row; /**< Row where the span lies. */ 105 sysarg_t cnt; /**< Width of the span. */ 106 } fb_pending; 107 108 static FIBRIL_MUTEX_INITIALIZE(input_mutex); 109 static FIBRIL_CONDVAR_INITIALIZE(input_cv); 110 111 static void curs_visibility(bool visible) 112 { 113 async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible); 114 } 115 116 static void curs_hide_sync(void) 117 { 118 async_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false); 119 } 120 121 static void curs_goto(sysarg_t x, sysarg_t y) 122 { 123 async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y); 124 } 125 126 static void screen_clear(void) 127 { 128 async_msg_0(fb_info.phone, FB_CLEAR); 129 } 130 131 static void screen_yield(void) 132 { 133 async_req_0_0(fb_info.phone, FB_SCREEN_YIELD); 134 } 135 136 static void screen_reclaim(void) 137 { 138 async_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM); 139 } 140 141 static void kbd_yield(void) 142 { 143 async_req_0_0(kbd_phone, KBD_YIELD); 144 } 145 146 static void kbd_reclaim(void) 147 { 148 async_req_0_0(kbd_phone, KBD_RECLAIM); 149 } 150 151 static void set_style(uint8_t style) 152 { 153 async_msg_1(fb_info.phone, FB_SET_STYLE, style); 154 } 155 156 static void set_color(uint8_t fgcolor, uint8_t bgcolor, uint8_t flags) 157 { 158 async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags); 159 } 160 161 static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor) 162 { 163 async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor); 164 } 165 166 static void set_attrs(attrs_t *attrs) 167 { 168 switch (attrs->t) { 169 case at_style: 170 set_style(attrs->a.s.style); 171 break; 172 case at_idx: 173 set_color(attrs->a.i.fg_color, attrs->a.i.bg_color, 174 attrs->a.i.flags); 175 break; 176 case at_rgb: 177 set_rgb_color(attrs->a.r.fg_color, attrs->a.r.bg_color); 178 break; 179 } 180 } 181 182 static int ccap_fb_to_con(sysarg_t ccap_fb, sysarg_t *ccap_con) 183 { 184 switch (ccap_fb) { 185 case FB_CCAP_NONE: 186 *ccap_con = CONSOLE_CCAP_NONE; 187 break; 188 case FB_CCAP_STYLE: 189 *ccap_con = CONSOLE_CCAP_STYLE; 190 break; 191 case FB_CCAP_INDEXED: 192 *ccap_con = CONSOLE_CCAP_INDEXED; 193 break; 194 case FB_CCAP_RGB: 195 *ccap_con = CONSOLE_CCAP_RGB; 196 break; 197 default: 198 return EINVAL; 199 } 200 201 return EOK; 202 } 203 204 /** Send an area of screenbuffer to the FB driver. */ 205 static void fb_update_area(console_t *cons, sysarg_t x0, sysarg_t y0, sysarg_t width, sysarg_t height) 206 { 207 if (interbuffer) { 208 sysarg_t x; 209 sysarg_t y; 210 211 for (y = 0; y < height; y++) { 212 for (x = 0; x < width; x++) { 213 interbuffer[y * width + x] = 214 *get_field_at(&cons->scr, x0 + x, y0 + y); 215 } 216 } 217 218 async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA, 219 x0, y0, width, height); 220 } 221 } 222 223 /** Flush pending cells to FB. */ 224 static void fb_pending_flush(void) 225 { 226 if (fb_pending.cnt > 0) { 227 fb_update_area(active_console, fb_pending.col, 228 fb_pending.row, fb_pending.cnt, 1); 229 fb_pending.cnt = 0; 230 } 231 } 232 233 /** Mark a character cell as changed. 161 sysarg_t x; 162 sysarg_t y; 163 164 sysarg_t btn_x; 165 sysarg_t btn_y; 166 167 bool pressed; 168 } mouse; 169 170 static void cons_redraw_state(console_t *cons) 171 { 172 if (graphics_state == GRAPHICS_FULL) { 173 fibril_mutex_lock(&cons->mtx); 174 175 fb_vp_imagemap_damage(fb_sess, cons->state_vp, 176 state_icons[cons->state], 0, 0, STATE_WIDTH, STATE_HEIGHT); 177 178 if ((cons->state != CONS_DISCONNECTED) && 179 (cons->state != CONS_KERNEL) && 180 (cons->state != CONS_DISCONNECTED_SELECTED)) { 181 char data[5]; 182 snprintf(data, 5, "%zu", cons->index + 1); 183 184 for (size_t i = 0; data[i] != 0; i++) 185 fb_vp_putchar(fb_sess, cons->state_vp, i + 2, 1, data[i]); 186 } 187 188 fibril_mutex_unlock(&cons->mtx); 189 } 190 } 191 192 static void cons_kernel_sequence_start(console_t *cons) 193 { 194 if (graphics_state == GRAPHICS_FULL) { 195 fibril_mutex_lock(&cons->mtx); 196 197 fb_vp_sequence_start(fb_sess, cons->state_vp, anim_seq); 198 fb_vp_imagemap_damage(fb_sess, cons->state_vp, 199 state_icons[cons->state], 0, 0, STATE_WIDTH, STATE_HEIGHT); 200 201 fibril_mutex_unlock(&cons->mtx); 202 } 203 } 204 205 static void cons_update_state(console_t *cons, console_state_t state) 206 { 207 bool update = false; 208 209 fibril_mutex_lock(&cons->mtx); 210 211 if (cons->state != state) { 212 cons->state = state; 213 update = true; 214 } 215 216 fibril_mutex_unlock(&cons->mtx); 217 218 if (update) 219 cons_redraw_state(cons); 220 } 221 222 static void cons_notify_data(console_t *cons) 223 { 224 fibril_mutex_lock(&switch_mtx); 225 226 if (cons != active_console) 227 cons_update_state(cons, CONS_DATA); 228 229 fibril_mutex_unlock(&switch_mtx); 230 } 231 232 static void cons_notify_connect(console_t *cons) 233 { 234 fibril_mutex_lock(&switch_mtx); 235 236 if (cons == active_console) 237 cons_update_state(cons, CONS_SELECTED); 238 else 239 cons_update_state(cons, CONS_IDLE); 240 241 fibril_mutex_unlock(&switch_mtx); 242 } 243 244 static void cons_notify_disconnect(console_t *cons) 245 { 246 fibril_mutex_lock(&switch_mtx); 247 248 if (cons == active_console) 249 cons_update_state(cons, CONS_DISCONNECTED_SELECTED); 250 else 251 cons_update_state(cons, CONS_DISCONNECTED); 252 253 fibril_mutex_unlock(&switch_mtx); 254 } 255 256 static void cons_update(console_t *cons) 257 { 258 fibril_mutex_lock(&switch_mtx); 259 fibril_mutex_lock(&cons->mtx); 260 261 if ((cons == active_console) && (active_console != kernel_console)) { 262 fb_vp_update(fb_sess, console_vp, cons->fbid); 263 fb_vp_cursor_update(fb_sess, console_vp, cons->fbid); 264 } 265 266 fibril_mutex_unlock(&cons->mtx); 267 fibril_mutex_unlock(&switch_mtx); 268 } 269 270 static void cons_update_cursor(console_t *cons) 271 { 272 fibril_mutex_lock(&switch_mtx); 273 fibril_mutex_lock(&cons->mtx); 274 275 if ((cons == active_console) && (active_console != kernel_console)) 276 fb_vp_cursor_update(fb_sess, console_vp, cons->fbid); 277 278 fibril_mutex_unlock(&cons->mtx); 279 fibril_mutex_unlock(&switch_mtx); 280 } 281 282 static void cons_clear(console_t *cons) 283 { 284 fibril_mutex_lock(&cons->mtx); 285 screenbuffer_clear(cons->frontbuf); 286 fibril_mutex_unlock(&cons->mtx); 287 288 cons_update(cons); 289 } 290 291 static void cons_damage_all(console_t *cons) 292 { 293 fibril_mutex_lock(&switch_mtx); 294 fibril_mutex_lock(&cons->mtx); 295 296 if ((cons == active_console) && (active_console != kernel_console)) { 297 fb_vp_damage(fb_sess, console_vp, cons->fbid, 0, 0, cons->cols, 298 cons->rows); 299 fb_vp_cursor_update(fb_sess, console_vp, cons->fbid); 300 } 301 302 fibril_mutex_unlock(&cons->mtx); 303 fibril_mutex_unlock(&switch_mtx); 304 } 305 306 static void cons_switch(console_t *cons) 307 { 308 fibril_mutex_lock(&switch_mtx); 309 310 if (cons == active_console) { 311 fibril_mutex_unlock(&switch_mtx); 312 return; 313 } 314 315 if (cons == kernel_console) { 316 fb_yield(fb_sess); 317 if (!console_kcon()) { 318 fb_claim(fb_sess); 319 fibril_mutex_unlock(&switch_mtx); 320 return; 321 } 322 } 323 324 if (active_console == kernel_console) 325 fb_claim(fb_sess); 326 327 prev_console = active_console; 328 active_console = cons; 329 330 if (prev_console->state == CONS_DISCONNECTED_SELECTED) 331 cons_update_state(prev_console, CONS_DISCONNECTED); 332 else 333 cons_update_state(prev_console, CONS_IDLE); 334 335 if ((cons->state == CONS_DISCONNECTED) || 336 (cons->state == CONS_DISCONNECTED_SELECTED)) 337 cons_update_state(cons, CONS_DISCONNECTED_SELECTED); 338 else 339 cons_update_state(cons, CONS_SELECTED); 340 341 fibril_mutex_unlock(&switch_mtx); 342 343 cons_damage_all(cons); 344 } 345 346 static console_t *cons_get_active_uspace(void) 347 { 348 fibril_mutex_lock(&switch_mtx); 349 350 console_t *active_uspace = active_console; 351 if (active_uspace == kernel_console) { 352 active_uspace = prev_console; 353 } 354 assert(active_uspace != kernel_console); 355 356 fibril_mutex_unlock(&switch_mtx); 357 358 return active_uspace; 359 } 360 361 static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi) 362 { 363 if (val > hi) 364 return hi; 365 366 if (val < lo) 367 return lo; 368 369 return val; 370 } 371 372 static void cons_mouse_move(sysarg_t dx, sysarg_t dy) 373 { 374 ssize_t sx = (ssize_t) dx; 375 ssize_t sy = (ssize_t) dy; 376 377 mouse.x = limit(mouse.x + sx, 0, xres); 378 mouse.y = limit(mouse.y + sy, 0, yres); 379 380 fb_pointer_update(fb_sess, mouse.x, mouse.y, true); 381 } 382 383 static console_t *cons_find_icon(sysarg_t x, sysarg_t y) 384 { 385 sysarg_t status_start = 386 STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN; 387 388 if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT)) 389 return NULL; 390 391 if (x < status_start) 392 return NULL; 393 394 if (x >= status_start + (STATE_WIDTH + STATE_SPACE) * CONSOLE_COUNT) 395 return NULL; 396 397 if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH) 398 return NULL; 399 400 sysarg_t btn = (x - status_start) / (STATE_WIDTH + STATE_SPACE); 401 402 if (btn < CONSOLE_COUNT) 403 return consoles + btn; 404 405 return NULL; 406 } 407 408 /** Handle mouse click 234 409 * 235 * This adds the cell to the pending rowspan if possible. Otherwise 236 * the old span is flushed first. 410 * @param state Button state (true - pressed, false - depressed) 237 411 * 238 412 */ 239 static void cell_mark_changed(sysarg_t col, sysarg_t row) 240 { 241 if (fb_pending.cnt != 0) { 242 if ((col != fb_pending.col + fb_pending.cnt) 243 || (row != fb_pending.row)) { 244 fb_pending_flush(); 245 } 246 } 247 248 if (fb_pending.cnt == 0) { 249 fb_pending.col = col; 250 fb_pending.row = row; 251 } 252 253 fb_pending.cnt++; 254 } 255 256 /** Print a character to the active VC with buffering. */ 257 static void fb_putchar(wchar_t c, sysarg_t col, sysarg_t row) 258 { 259 async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row); 413 static console_t *cons_mouse_button(bool state) 414 { 415 if (graphics_state != GRAPHICS_FULL) 416 return NULL; 417 418 if (state) { 419 console_t *cons = cons_find_icon(mouse.x, mouse.y); 420 if (cons != NULL) { 421 mouse.btn_x = mouse.x; 422 mouse.btn_y = mouse.y; 423 mouse.pressed = true; 424 } 425 426 return NULL; 427 } 428 429 if ((!state) && (!mouse.pressed)) 430 return NULL; 431 432 console_t *cons = cons_find_icon(mouse.x, mouse.y); 433 if (cons == cons_find_icon(mouse.btn_x, mouse.btn_y)) 434 return cons; 435 436 mouse.pressed = false; 437 return NULL; 438 } 439 440 static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg) 441 { 442 /* Ignore parameters, the connection is already opened */ 443 while (true) { 444 ipc_call_t call; 445 ipc_callid_t callid = async_get_call(&call); 446 447 if (!IPC_GET_IMETHOD(call)) { 448 /* TODO: Handle hangup */ 449 async_hangup(input_sess); 450 return; 451 } 452 453 kbd_event_type_t type; 454 keycode_t key; 455 keymod_t mods; 456 wchar_t c; 457 458 switch (IPC_GET_IMETHOD(call)) { 459 case INPUT_EVENT_KEY: 460 type = IPC_GET_ARG1(call); 461 key = IPC_GET_ARG2(call); 462 mods = IPC_GET_ARG3(call); 463 c = IPC_GET_ARG4(call); 464 465 if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) && 466 ((mods & KM_CTRL) == 0)) 467 cons_switch(&consoles[key - KC_F1]); 468 else { 469 /* Got key press/release event */ 470 kbd_event_t *event = 471 (kbd_event_t *) malloc(sizeof(kbd_event_t)); 472 if (event == NULL) { 473 async_answer_0(callid, ENOMEM); 474 break; 475 } 476 477 link_initialize(&event->link); 478 event->type = type; 479 event->key = key; 480 event->mods = mods; 481 event->c = c; 482 483 /* Kernel console does not read events 484 * from us, so we will redirect them 485 * to the (last) active userspace console 486 * if necessary. 487 */ 488 console_t *target_console = cons_get_active_uspace(); 489 490 prodcons_produce(&target_console->input_pc, 491 &event->link); 492 } 493 494 async_answer_0(callid, EOK); 495 break; 496 case INPUT_EVENT_MOVE: 497 cons_mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); 498 async_answer_0(callid, EOK); 499 break; 500 case INPUT_EVENT_BUTTON: 501 /* Got pointer button press/release event */ 502 if (IPC_GET_ARG1(call) == 1) { 503 console_t *cons = 504 cons_mouse_button((bool) IPC_GET_ARG2(call)); 505 if (cons != NULL) 506 cons_switch(cons); 507 } 508 async_answer_0(callid, EOK); 509 break; 510 default: 511 async_answer_0(callid, EINVAL); 512 } 513 } 260 514 } 261 515 262 516 /** Process a character from the client (TTY emulation). */ 263 static void write_char(console_t *cons, wchar_t ch) 264 { 265 bool flush_cursor = false; 517 static void cons_write_char(console_t *cons, wchar_t ch) 518 { 519 sysarg_t updated = 0; 520 521 fibril_mutex_lock(&cons->mtx); 266 522 267 523 switch (ch) { 268 524 case '\n': 269 fb_pending_flush(); 270 flush_cursor = true; 271 cons->scr.position_y++; 272 cons->scr.position_x = 0; 525 updated = screenbuffer_newline(cons->frontbuf); 273 526 break; 274 527 case '\r': 275 528 break; 276 529 case '\t': 277 cons->scr.position_x += 8; 278 cons->scr.position_x -= cons->scr.position_x % 8; 530 updated = screenbuffer_tabstop(cons->frontbuf, 8); 279 531 break; 280 532 case '\b': 281 if (cons->scr.position_x == 0) 282 break; 283 cons->scr.position_x--; 284 if (cons == active_console) 285 cell_mark_changed(cons->scr.position_x, cons->scr.position_y); 286 screenbuffer_putchar(&cons->scr, ' '); 533 updated = screenbuffer_backspace(cons->frontbuf); 287 534 break; 288 535 default: 289 if (cons == active_console) 290 cell_mark_changed(cons->scr.position_x, cons->scr.position_y); 291 292 screenbuffer_putchar(&cons->scr, ch); 293 cons->scr.position_x++; 294 } 295 296 if (cons->scr.position_x >= cons->scr.size_x) { 297 flush_cursor = true; 298 cons->scr.position_y++; 299 } 300 301 if (cons->scr.position_y >= cons->scr.size_y) { 302 fb_pending_flush(); 303 cons->scr.position_y = cons->scr.size_y - 1; 304 screenbuffer_clear_line(&cons->scr, cons->scr.top_line); 305 cons->scr.top_line = (cons->scr.top_line + 1) % cons->scr.size_y; 306 307 if (cons == active_console) 308 async_msg_1(fb_info.phone, FB_SCROLL, 1); 309 } 310 311 if (cons == active_console && flush_cursor) 312 curs_goto(cons->scr.position_x, cons->scr.position_y); 313 cons->scr.position_x = cons->scr.position_x % cons->scr.size_x; 314 } 315 316 /** Switch to new console */ 317 static void change_console(console_t *cons) 318 { 319 if (cons == active_console) 320 return; 321 322 fb_pending_flush(); 323 324 if (cons == kernel_console) { 325 async_serialize_start(); 326 curs_hide_sync(); 327 gcons_in_kernel(); 328 screen_yield(); 329 kbd_yield(); 330 async_serialize_end(); 331 332 if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) { 333 prev_console = active_console; 334 active_console = kernel_console; 335 } else 336 cons = active_console; 337 } 338 339 if (cons != kernel_console) { 340 async_serialize_start(); 341 342 if (active_console == kernel_console) { 343 screen_reclaim(); 344 kbd_reclaim(); 345 gcons_redraw_console(); 346 } 347 348 active_console = cons; 349 gcons_change_console(cons->index); 350 351 set_attrs(&cons->scr.attrs); 352 curs_visibility(false); 353 354 sysarg_t x; 355 sysarg_t y; 356 int rc = 0; 357 358 if (interbuffer) { 359 for (y = 0; y < cons->scr.size_y; y++) { 360 for (x = 0; x < cons->scr.size_x; x++) { 361 interbuffer[y * cons->scr.size_x + x] = 362 *get_field_at(&cons->scr, x, y); 363 } 364 } 365 366 /* This call can preempt, but we are already at the end */ 367 rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA, 368 0, 0, cons->scr.size_x, 369 cons->scr.size_y); 370 } 371 372 if ((!interbuffer) || (rc != 0)) { 373 set_attrs(&cons->scr.attrs); 374 screen_clear(); 375 376 for (y = 0; y < cons->scr.size_y; y++) 377 for (x = 0; x < cons->scr.size_x; x++) { 378 keyfield_t *field = get_field_at(&cons->scr, x, y); 379 380 if (!attrs_same(cons->scr.attrs, field->attrs)) 381 set_attrs(&field->attrs); 382 383 cons->scr.attrs = field->attrs; 384 if ((field->character == ' ') && 385 (attrs_same(field->attrs, cons->scr.attrs))) 386 continue; 387 388 fb_putchar(field->character, x, y); 389 } 390 } 391 392 curs_goto(cons->scr.position_x, cons->scr.position_y); 393 curs_visibility(cons->scr.is_cursor_visible); 394 395 async_serialize_end(); 396 } 397 } 398 399 /** Handler for keyboard */ 400 static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall) 401 { 402 /* Ignore parameters, the connection is already opened */ 403 while (true) { 404 ipc_call_t call; 405 ipc_callid_t callid = async_get_call(&call); 406 407 int retval; 408 console_event_t ev; 409 410 switch (IPC_GET_IMETHOD(call)) { 411 case IPC_M_PHONE_HUNGUP: 412 /* TODO: Handle hangup */ 413 return; 414 case KBD_EVENT: 415 /* Got event from keyboard driver. */ 416 retval = 0; 417 ev.type = IPC_GET_ARG1(call); 418 ev.key = IPC_GET_ARG2(call); 419 ev.mods = IPC_GET_ARG3(call); 420 ev.c = IPC_GET_ARG4(call); 421 422 if ((ev.key >= KC_F1) && (ev.key < KC_F1 + 423 CONSOLE_COUNT) && ((ev.mods & KM_CTRL) == 0)) { 424 if (ev.key == KC_F1 + KERNEL_CONSOLE) 425 change_console(kernel_console); 426 else 427 change_console(&consoles[ev.key - KC_F1]); 428 break; 429 } 430 431 fibril_mutex_lock(&input_mutex); 432 keybuffer_push(&active_console->keybuffer, &ev); 433 fibril_condvar_broadcast(&input_cv); 434 fibril_mutex_unlock(&input_mutex); 435 break; 436 default: 437 retval = ENOENT; 438 } 439 async_answer_0(callid, retval); 440 } 441 } 442 443 /** Handler for mouse events */ 444 static void mouse_events(ipc_callid_t iid, ipc_call_t *icall) 445 { 446 /* Ignore parameters, the connection is already opened */ 447 while (true) { 448 ipc_call_t call; 449 ipc_callid_t callid = async_get_call(&call); 450 451 int retval; 452 453 switch (IPC_GET_IMETHOD(call)) { 454 case IPC_M_PHONE_HUNGUP: 455 /* TODO: Handle hangup */ 456 return; 457 case MEVENT_BUTTON: 458 if (IPC_GET_ARG1(call) == 1) { 459 int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call)); 460 if (newcon != -1) 461 change_console(&consoles[newcon]); 462 } 463 retval = 0; 464 break; 465 case MEVENT_MOVE: 466 gcons_mouse_move((int) IPC_GET_ARG1(call), 467 (int) IPC_GET_ARG2(call)); 468 retval = 0; 469 break; 470 default: 471 retval = ENOENT; 472 } 473 474 async_answer_0(callid, retval); 475 } 476 } 477 478 static void cons_write(console_t *cons, ipc_callid_t rid, ipc_call_t *request) 536 updated = screenbuffer_putchar(cons->frontbuf, ch, true); 537 } 538 539 fibril_mutex_unlock(&cons->mtx); 540 541 if (updated > 1) 542 cons_update(cons); 543 } 544 545 static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row) 546 { 547 fibril_mutex_lock(&cons->mtx); 548 screenbuffer_set_cursor(cons->frontbuf, col, row); 549 fibril_mutex_unlock(&cons->mtx); 550 551 cons_update_cursor(cons); 552 } 553 554 static void cons_set_cursor_visibility(console_t *cons, bool visible) 555 { 556 fibril_mutex_lock(&cons->mtx); 557 screenbuffer_set_cursor_visibility(cons->frontbuf, visible); 558 fibril_mutex_unlock(&cons->mtx); 559 560 cons_update_cursor(cons); 561 } 562 563 static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall) 564 { 565 sysarg_t col; 566 sysarg_t row; 567 568 fibril_mutex_lock(&cons->mtx); 569 screenbuffer_get_cursor(cons->frontbuf, &col, &row); 570 fibril_mutex_unlock(&cons->mtx); 571 572 async_answer_2(iid, EOK, col, row); 573 } 574 575 static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall) 479 576 { 480 577 void *buf; … … 483 580 484 581 if (rc != EOK) { 485 async_answer_0( rid, rc);582 async_answer_0(iid, rc); 486 583 return; 487 584 } 488 585 489 async_serialize_start();490 491 586 size_t off = 0; 492 while (off < size) { 493 wchar_t ch = str_decode(buf, &off, size); 494 write_char(cons, ch); 495 } 496 497 async_serialize_end(); 498 499 gcons_notify_char(cons->index); 500 async_answer_1(rid, EOK, size); 501 587 while (off < size) 588 cons_write_char(cons, str_decode(buf, &off, size)); 589 590 async_answer_1(iid, EOK, size); 502 591 free(buf); 503 } 504 505 static void cons_read(console_t *cons, ipc_callid_t rid, ipc_call_t *request) 592 593 cons_notify_data(cons); 594 } 595 596 static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall) 506 597 { 507 598 ipc_callid_t callid; … … 509 600 if (!async_data_read_receive(&callid, &size)) { 510 601 async_answer_0(callid, EINVAL); 511 async_answer_0( rid, EINVAL);602 async_answer_0(iid, EINVAL); 512 603 return; 513 604 } … … 516 607 if (buf == NULL) { 517 608 async_answer_0(callid, ENOMEM); 518 async_answer_0( rid, ENOMEM);609 async_answer_0(iid, ENOMEM); 519 610 return; 520 611 } 521 612 522 613 size_t pos = 0; 523 console_event_t ev; 524 fibril_mutex_lock(&input_mutex); 525 526 recheck: 527 while ((keybuffer_pop(&cons->keybuffer, &ev)) && (pos < size)) { 528 if (ev.type == KEY_PRESS) { 529 buf[pos] = ev.c; 614 while (pos < size) { 615 link_t *link = prodcons_consume(&cons->input_pc); 616 kbd_event_t *event = list_get_instance(link, kbd_event_t, link); 617 618 if (event->type == KEY_PRESS) { 619 buf[pos] = event->c; 530 620 pos++; 531 621 } 532 } 533 534 if (pos == size) { 535 (void) async_data_read_finalize(callid, buf, size); 536 async_answer_1(rid, EOK, size); 537 free(buf); 538 } else { 539 fibril_condvar_wait(&input_cv, &input_mutex); 540 goto recheck; 541 } 542 543 fibril_mutex_unlock(&input_mutex); 544 } 545 546 static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request) 547 { 548 console_event_t ev; 549 550 fibril_mutex_lock(&input_mutex); 551 552 recheck: 553 if (keybuffer_pop(&cons->keybuffer, &ev)) { 554 async_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c); 555 } else { 556 fibril_condvar_wait(&input_cv, &input_mutex); 557 goto recheck; 558 } 559 560 fibril_mutex_unlock(&input_mutex); 561 } 562 563 /** Default thread for new connections */ 564 static void client_connection(ipc_callid_t iid, ipc_call_t *icall) 622 623 free(event); 624 } 625 626 (void) async_data_read_finalize(callid, buf, size); 627 async_answer_1(iid, EOK, size); 628 free(buf); 629 } 630 631 static void cons_set_style(console_t *cons, console_style_t style) 632 { 633 fibril_mutex_lock(&cons->mtx); 634 screenbuffer_set_style(cons->frontbuf, style); 635 fibril_mutex_unlock(&cons->mtx); 636 } 637 638 static void cons_set_color(console_t *cons, console_color_t bgcolor, 639 console_color_t fgcolor, console_color_attr_t attr) 640 { 641 fibril_mutex_lock(&cons->mtx); 642 screenbuffer_set_color(cons->frontbuf, bgcolor, fgcolor, attr); 643 fibril_mutex_unlock(&cons->mtx); 644 } 645 646 static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor, 647 pixel_t fgcolor) 648 { 649 fibril_mutex_lock(&cons->mtx); 650 screenbuffer_set_rgb_color(cons->frontbuf, bgcolor, fgcolor); 651 fibril_mutex_unlock(&cons->mtx); 652 } 653 654 static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall) 655 { 656 link_t *link = prodcons_consume(&cons->input_pc); 657 kbd_event_t *event = list_get_instance(link, kbd_event_t, link); 658 659 async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c); 660 free(event); 661 } 662 663 static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 565 664 { 566 665 console_t *cons = NULL; 567 666 568 size_t i; 569 for (i = 0; i < CONSOLE_COUNT; i++) { 667 for (size_t i = 0; i < CONSOLE_COUNT; i++) { 570 668 if (i == KERNEL_CONSOLE) 571 669 continue; 572 670 573 if (consoles[i].d evmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {671 if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) { 574 672 cons = &consoles[i]; 575 673 break; … … 582 680 } 583 681 584 ipc_callid_t callid; 585 ipc_call_t call; 586 sysarg_t arg1; 587 sysarg_t arg2; 588 sysarg_t arg3; 589 590 int rc; 591 592 async_serialize_start(); 593 if (cons->refcount == 0) 594 gcons_notify_connect(cons->index); 595 596 cons->refcount++; 682 if (atomic_postinc(&cons->refcnt) == 0) { 683 cons_set_cursor_visibility(cons, true); 684 cons_notify_connect(cons); 685 } 597 686 598 687 /* Accept the connection */ … … 600 689 601 690 while (true) { 602 async_serialize_end(); 603 callid = async_get_call(&call); 604 async_serialize_start(); 605 606 arg1 = 0; 607 arg2 = 0; 608 arg3 = 0; 691 ipc_call_t call; 692 ipc_callid_t callid = async_get_call(&call); 693 694 if (!IPC_GET_IMETHOD(call)) { 695 if (atomic_postdec(&cons->refcnt) == 1) 696 cons_notify_disconnect(cons); 697 698 return; 699 } 609 700 610 701 switch (IPC_GET_IMETHOD(call)) { 611 case IPC_M_PHONE_HUNGUP:612 cons->refcount--;613 if (cons->refcount == 0)614 gcons_notify_disconnect(cons->index);615 return;616 702 case VFS_OUT_READ: 617 async_serialize_end();618 703 cons_read(cons, callid, &call); 619 async_serialize_start(); 704 break; 705 case VFS_OUT_WRITE: 706 cons_write(cons, callid, &call); 707 break; 708 case VFS_OUT_SYNC: 709 cons_update(cons); 710 async_answer_0(callid, EOK); 711 break; 712 case CONSOLE_CLEAR: 713 cons_clear(cons); 714 async_answer_0(callid, EOK); 715 break; 716 case CONSOLE_GOTO: 717 cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call)); 718 async_answer_0(callid, EOK); 719 break; 720 case CONSOLE_GET_POS: 721 cons_get_cursor(cons, callid, &call); 722 break; 723 case CONSOLE_GET_SIZE: 724 async_answer_2(callid, EOK, cons->cols, cons->rows); 725 break; 726 case CONSOLE_GET_COLOR_CAP: 727 async_answer_1(callid, EOK, cons->ccaps); 728 break; 729 case CONSOLE_SET_STYLE: 730 cons_set_style(cons, IPC_GET_ARG1(call)); 731 async_answer_0(callid, EOK); 732 break; 733 case CONSOLE_SET_COLOR: 734 cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call), 735 IPC_GET_ARG3(call)); 736 async_answer_0(callid, EOK); 737 break; 738 case CONSOLE_SET_RGB_COLOR: 739 cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call)); 740 async_answer_0(callid, EOK); 741 break; 742 case CONSOLE_CURSOR_VISIBILITY: 743 cons_set_cursor_visibility(cons, IPC_GET_ARG1(call)); 744 async_answer_0(callid, EOK); 745 break; 746 case CONSOLE_GET_EVENT: 747 cons_get_event(cons, callid, &call); 748 break; 749 default: 750 async_answer_0(callid, EINVAL); 751 } 752 } 753 } 754 755 static async_sess_t *input_connect(const char *svc) 756 { 757 async_sess_t *sess; 758 service_id_t dsid; 759 760 int rc = loc_service_get_id(svc, &dsid, 0); 761 if (rc == EOK) { 762 sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0); 763 if (sess == NULL) { 764 printf("%s: Unable to connect to input service %s\n", NAME, 765 svc); 766 return NULL; 767 } 768 } else 769 return NULL; 770 771 async_exch_t *exch = async_exchange_begin(sess); 772 rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL); 773 async_exchange_end(exch); 774 775 if (rc != EOK) { 776 async_hangup(sess); 777 printf("%s: Unable to create callback connection to service %s (%s)\n", 778 NAME, svc, str_error(rc)); 779 return NULL; 780 } 781 782 return sess; 783 } 784 785 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call) 786 { 787 cons_switch(prev_console); 788 } 789 790 static async_sess_t *fb_connect(const char *svc) 791 { 792 async_sess_t *sess; 793 service_id_t dsid; 794 795 int rc = loc_service_get_id(svc, &dsid, 0); 796 if (rc == EOK) { 797 sess = loc_service_connect(EXCHANGE_SERIALIZE, dsid, 0); 798 if (sess == NULL) { 799 printf("%s: Unable to connect to framebuffer service %s\n", 800 NAME, svc); 801 return NULL; 802 } 803 } else 804 return NULL; 805 806 return sess; 807 } 808 809 static bool console_srv_init(char *input_svc, char *fb_svc) 810 { 811 /* Avoid double initialization */ 812 if (graphics_state != GRAPHICS_NONE) 813 return false; 814 815 /* Connect to input service */ 816 input_sess = input_connect(input_svc); 817 if (input_sess == NULL) 818 return false; 819 820 /* Connect to framebuffer service */ 821 fb_sess = fb_connect(fb_svc); 822 if (fb_sess == NULL) 823 return false; 824 825 /* Register server */ 826 int rc = loc_server_register(NAME, client_connection); 827 if (rc < 0) { 828 printf("%s: Unable to register server (%s)\n", NAME, 829 str_error(rc)); 830 return false; 831 } 832 833 fb_get_resolution(fb_sess, &xres, &yres); 834 835 /* Initialize the screen */ 836 screen_vp = fb_vp_create(fb_sess, 0, 0, xres, yres); 837 838 if ((xres >= 800) && (yres >= 600)) { 839 logo_vp = fb_vp_create(fb_sess, xres - 66, 2, 64, 60); 840 logo_img = imgmap_decode_tga((void *) helenos_tga, 841 helenos_tga_size, IMGMAP_FLAG_SHARED); 842 logo_handle = fb_imagemap_create(fb_sess, logo_img); 843 844 nameic_vp = fb_vp_create(fb_sess, 5, 17, 100, 26); 845 nameic_img = imgmap_decode_tga((void *) nameic_tga, 846 nameic_tga_size, IMGMAP_FLAG_SHARED); 847 nameic_handle = fb_imagemap_create(fb_sess, nameic_img); 848 849 cons_data_img = imgmap_decode_tga((void *) cons_data_tga, 850 cons_data_tga_size, IMGMAP_FLAG_SHARED); 851 cons_dis_img = imgmap_decode_tga((void *) cons_dis_tga, 852 cons_dis_tga_size, IMGMAP_FLAG_SHARED); 853 cons_dis_sel_img = imgmap_decode_tga((void *) cons_dis_sel_tga, 854 cons_dis_sel_tga_size, IMGMAP_FLAG_SHARED); 855 cons_idle_img = imgmap_decode_tga((void *) cons_idle_tga, 856 cons_idle_tga_size, IMGMAP_FLAG_SHARED); 857 cons_kernel_img = imgmap_decode_tga((void *) cons_kernel_tga, 858 cons_kernel_tga_size, IMGMAP_FLAG_SHARED); 859 cons_sel_img = imgmap_decode_tga((void *) cons_sel_tga, 860 cons_sel_tga_size, IMGMAP_FLAG_SHARED); 861 862 state_icons[CONS_DISCONNECTED] = 863 fb_imagemap_create(fb_sess, cons_dis_img); 864 state_icons[CONS_DISCONNECTED_SELECTED] = 865 fb_imagemap_create(fb_sess, cons_dis_sel_img); 866 state_icons[CONS_SELECTED] = 867 fb_imagemap_create(fb_sess, cons_sel_img); 868 state_icons[CONS_IDLE] = 869 fb_imagemap_create(fb_sess, cons_idle_img); 870 state_icons[CONS_DATA] = 871 fb_imagemap_create(fb_sess, cons_data_img); 872 state_icons[CONS_KERNEL] = 873 fb_imagemap_create(fb_sess, cons_kernel_img); 874 875 anim_1_img = imgmap_decode_tga((void *) anim_1_tga, 876 anim_1_tga_size, IMGMAP_FLAG_SHARED); 877 anim_2_img = imgmap_decode_tga((void *) anim_2_tga, 878 anim_2_tga_size, IMGMAP_FLAG_SHARED); 879 anim_3_img = imgmap_decode_tga((void *) anim_3_tga, 880 anim_3_tga_size, IMGMAP_FLAG_SHARED); 881 anim_4_img = imgmap_decode_tga((void *) anim_4_tga, 882 anim_4_tga_size, IMGMAP_FLAG_SHARED); 883 884 anim_1 = fb_imagemap_create(fb_sess, anim_1_img); 885 anim_2 = fb_imagemap_create(fb_sess, anim_2_img); 886 anim_3 = fb_imagemap_create(fb_sess, anim_3_img); 887 anim_4 = fb_imagemap_create(fb_sess, anim_4_img); 888 889 anim_seq = fb_sequence_create(fb_sess); 890 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_1); 891 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_2); 892 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_3); 893 fb_sequence_add_imagemap(fb_sess, anim_seq, anim_4); 894 895 console_vp = fb_vp_create(fb_sess, CONSOLE_MARGIN, CONSOLE_TOP, 896 xres - 2 * CONSOLE_MARGIN, yres - (CONSOLE_TOP + CONSOLE_MARGIN)); 897 898 fb_vp_clear(fb_sess, screen_vp); 899 fb_vp_imagemap_damage(fb_sess, logo_vp, logo_handle, 900 0, 0, 64, 60); 901 fb_vp_imagemap_damage(fb_sess, nameic_vp, nameic_handle, 902 0, 0, 100, 26); 903 904 graphics_state = GRAPHICS_FULL; 905 } else { 906 console_vp = screen_vp; 907 graphics_state = GRAPHICS_BASIC; 908 } 909 910 fb_vp_set_style(fb_sess, console_vp, STYLE_NORMAL); 911 fb_vp_clear(fb_sess, console_vp); 912 913 sysarg_t cols; 914 sysarg_t rows; 915 fb_vp_get_dimensions(fb_sess, console_vp, &cols, &rows); 916 917 console_caps_t ccaps; 918 fb_vp_get_caps(fb_sess, console_vp, &ccaps); 919 920 mouse.x = xres / 2; 921 mouse.y = yres / 2; 922 mouse.pressed = false; 923 924 /* Inititalize consoles */ 925 for (size_t i = 0; i < CONSOLE_COUNT; i++) { 926 consoles[i].index = i; 927 atomic_set(&consoles[i].refcnt, 0); 928 fibril_mutex_initialize(&consoles[i].mtx); 929 prodcons_initialize(&consoles[i].input_pc); 930 931 if (graphics_state == GRAPHICS_FULL) { 932 /* Create state buttons */ 933 consoles[i].state_vp = 934 fb_vp_create(fb_sess, STATE_START + (xres - 800) / 2 + 935 CONSOLE_MARGIN + i * (STATE_WIDTH + STATE_SPACE), 936 STATE_TOP, STATE_WIDTH, STATE_HEIGHT); 937 } 938 939 if (i == KERNEL_CONSOLE) { 940 consoles[i].state = CONS_KERNEL; 941 cons_redraw_state(&consoles[i]); 942 cons_kernel_sequence_start(&consoles[i]); 620 943 continue; 621 case VFS_OUT_WRITE: 622 async_serialize_end(); 623 cons_write(cons, callid, &call); 624 async_serialize_start(); 625 continue; 626 case VFS_OUT_SYNC: 627 fb_pending_flush(); 628 if (cons == active_console) { 629 async_req_0_0(fb_info.phone, FB_FLUSH); 630 curs_goto(cons->scr.position_x, cons->scr.position_y); 631 } 632 break; 633 case CONSOLE_CLEAR: 634 /* Send message to fb */ 635 if (cons == active_console) 636 async_msg_0(fb_info.phone, FB_CLEAR); 637 638 screenbuffer_clear(&cons->scr); 639 640 break; 641 case CONSOLE_GOTO: 642 screenbuffer_goto(&cons->scr, 643 IPC_GET_ARG1(call), IPC_GET_ARG2(call)); 644 if (cons == active_console) 645 curs_goto(IPC_GET_ARG1(call), 646 IPC_GET_ARG2(call)); 647 break; 648 case CONSOLE_GET_POS: 649 arg1 = cons->scr.position_x; 650 arg2 = cons->scr.position_y; 651 break; 652 case CONSOLE_GET_SIZE: 653 arg1 = fb_info.cols; 654 arg2 = fb_info.rows; 655 break; 656 case CONSOLE_GET_COLOR_CAP: 657 rc = ccap_fb_to_con(fb_info.color_cap, &arg1); 658 if (rc != EOK) { 659 async_answer_0(callid, rc); 660 continue; 661 } 662 break; 663 case CONSOLE_SET_STYLE: 664 fb_pending_flush(); 665 arg1 = IPC_GET_ARG1(call); 666 screenbuffer_set_style(&cons->scr, arg1); 667 if (cons == active_console) 668 set_style(arg1); 669 break; 670 case CONSOLE_SET_COLOR: 671 fb_pending_flush(); 672 arg1 = IPC_GET_ARG1(call); 673 arg2 = IPC_GET_ARG2(call); 674 arg3 = IPC_GET_ARG3(call); 675 screenbuffer_set_color(&cons->scr, arg1, arg2, arg3); 676 if (cons == active_console) 677 set_color(arg1, arg2, arg3); 678 break; 679 case CONSOLE_SET_RGB_COLOR: 680 fb_pending_flush(); 681 arg1 = IPC_GET_ARG1(call); 682 arg2 = IPC_GET_ARG2(call); 683 screenbuffer_set_rgb_color(&cons->scr, arg1, arg2); 684 if (cons == active_console) 685 set_rgb_color(arg1, arg2); 686 break; 687 case CONSOLE_CURSOR_VISIBILITY: 688 fb_pending_flush(); 689 arg1 = IPC_GET_ARG1(call); 690 cons->scr.is_cursor_visible = arg1; 691 if (cons == active_console) 692 curs_visibility(arg1); 693 break; 694 case CONSOLE_GET_EVENT: 695 async_serialize_end(); 696 cons_get_event(cons, callid, &call); 697 async_serialize_start(); 698 continue; 699 case CONSOLE_KCON_ENABLE: 700 change_console(kernel_console); 701 break; 702 } 703 async_answer_3(callid, EOK, arg1, arg2, arg3); 704 } 705 } 706 707 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call) 708 { 709 change_console(prev_console); 710 } 711 712 static bool console_init(char *input) 713 { 714 /* Connect to input device */ 715 int input_fd = open(input, O_RDONLY); 716 if (input_fd < 0) { 717 printf(NAME ": Failed opening %s\n", input); 718 return false; 719 } 720 721 kbd_phone = fd_phone(input_fd); 722 if (kbd_phone < 0) { 723 printf(NAME ": Failed to connect to input device\n"); 724 return false; 725 } 726 727 /* NB: The callback connection is slotted for removal */ 728 if (async_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, keyboard_events) 729 != 0) { 730 printf(NAME ": Failed to create callback from input device\n"); 731 return false; 732 } 733 734 /* Connect to mouse device */ 735 mouse_phone = -1; 736 int mouse_fd = open("/dev/hid_in/mouse", O_RDONLY); 737 738 if (mouse_fd < 0) { 739 printf(NAME ": Notice - failed opening %s\n", "/dev/hid_in/mouse"); 740 goto skip_mouse; 741 } 742 743 mouse_phone = fd_phone(mouse_fd); 744 if (mouse_phone < 0) { 745 printf(NAME ": Failed to connect to mouse device\n"); 746 goto skip_mouse; 747 } 748 749 if (async_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, mouse_events) 750 != 0) { 751 printf(NAME ": Failed to create callback from mouse device\n"); 752 mouse_phone = -1; 753 goto skip_mouse; 754 } 755 756 skip_mouse: 757 758 /* Connect to framebuffer driver */ 759 fb_info.phone = service_connect_blocking(SERVICE_VIDEO, 0, 0); 760 if (fb_info.phone < 0) { 761 printf(NAME ": Failed to connect to video service\n"); 762 return -1; 763 } 764 765 /* Register driver */ 766 int rc = devmap_driver_register(NAME, client_connection); 767 if (rc < 0) { 768 printf(NAME ": Unable to register driver (%d)\n", rc); 769 return false; 770 } 771 772 /* Initialize gcons */ 773 gcons_init(fb_info.phone); 774 775 /* Synchronize, the gcons could put something in queue */ 776 async_req_0_0(fb_info.phone, FB_FLUSH); 777 async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows); 778 async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap); 779 780 /* Set up shared memory buffer. */ 781 size_t ib_size = sizeof(keyfield_t) * fb_info.cols * fb_info.rows; 782 interbuffer = as_get_mappable_page(ib_size); 783 784 if (as_area_create(interbuffer, ib_size, AS_AREA_READ | 785 AS_AREA_WRITE | AS_AREA_CACHEABLE) != interbuffer) 786 interbuffer = NULL; 787 788 if (interbuffer) { 789 if (async_share_out_start(fb_info.phone, interbuffer, 790 AS_AREA_READ) != EOK) { 791 as_area_destroy(interbuffer); 792 interbuffer = NULL; 793 } 794 } 795 796 fb_pending.cnt = 0; 797 798 /* Inititalize consoles */ 799 size_t i; 800 for (i = 0; i < CONSOLE_COUNT; i++) { 801 if (i != KERNEL_CONSOLE) { 802 if (screenbuffer_init(&consoles[i].scr, 803 fb_info.cols, fb_info.rows) == NULL) { 804 printf(NAME ": Unable to allocate screen buffer %zu\n", i); 805 return false; 806 } 807 screenbuffer_clear(&consoles[i].scr); 808 keybuffer_init(&consoles[i].keybuffer); 809 consoles[i].index = i; 810 consoles[i].refcount = 0; 811 812 char vc[DEVMAP_NAME_MAXLEN + 1]; 813 snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i); 814 815 if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) { 816 printf(NAME ": Unable to register device %s\n", vc); 817 return false; 818 } 819 } 820 } 821 822 /* Disable kernel output to the console */ 823 __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE); 824 825 /* Initialize the screen */ 826 async_serialize_start(); 827 gcons_redraw_console(); 828 set_style(STYLE_NORMAL); 829 screen_clear(); 830 curs_goto(0, 0); 831 curs_visibility(active_console->scr.is_cursor_visible); 832 async_serialize_end(); 944 } 945 946 if (i == 0) 947 consoles[i].state = CONS_DISCONNECTED_SELECTED; 948 else 949 consoles[i].state = CONS_DISCONNECTED; 950 951 consoles[i].cols = cols; 952 consoles[i].rows = rows; 953 consoles[i].ccaps = ccaps; 954 consoles[i].frontbuf = 955 screenbuffer_create(cols, rows, SCREENBUFFER_FLAG_SHARED); 956 957 if (consoles[i].frontbuf == NULL) { 958 printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i); 959 return false; 960 } 961 962 consoles[i].fbid = fb_frontbuf_create(fb_sess, consoles[i].frontbuf); 963 if (consoles[i].fbid == 0) { 964 printf("%s: Unable to create frontbuffer %zu\n", NAME, i); 965 return false; 966 } 967 968 cons_redraw_state(&consoles[i]); 969 970 char vc[LOC_NAME_MAXLEN + 1]; 971 snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i); 972 973 if (loc_service_register(vc, &consoles[i].dsid) != EOK) { 974 printf("%s: Unable to register device %s\n", NAME, vc); 975 return false; 976 } 977 } 833 978 834 979 /* Receive kernel notifications */ 835 980 async_set_interrupt_received(interrupt_received); 836 if (event_subscribe(EVENT_KCONSOLE, 0) != EOK) 837 printf(NAME ": Error registering kconsole notifications\n"); 981 rc = event_subscribe(EVENT_KCONSOLE, 0); 982 if (rc != EOK) 983 printf("%s: Failed to register kconsole notifications (%s)\n", 984 NAME, str_error(rc)); 838 985 839 986 return true; … … 842 989 static void usage(void) 843 990 { 844 printf("Usage: console <input >\n");991 printf("Usage: console <input_dev> <framebuffer_dev>\n"); 845 992 } 846 993 847 994 int main(int argc, char *argv[]) 848 995 { 849 if (argc < 2) {996 if (argc < 3) { 850 997 usage(); 851 998 return -1; 852 999 } 853 1000 854 printf( NAME ": HelenOS Console service\n");855 856 if (!console_ init(argv[1]))1001 printf("%s: HelenOS Console service\n", NAME); 1002 1003 if (!console_srv_init(argv[1], argv[2])) 857 1004 return -1; 858 1005 859 printf(NAME ": Accepting connections\n"); 1006 printf("%s: Accepting connections\n", NAME); 1007 task_retval(0); 860 1008 async_manager(); 861 1009
Note:
See TracChangeset
for help on using the changeset viewer.