Changeset 00aece0 in mainline for uspace/srv/hid/fb/fb.c
- Timestamp:
- 2012-02-18T16:47:38Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 4449c6c
- Parents:
- bd5f3b7 (diff), f943dd3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/hid/fb/fb.c
rbd5f3b7 r00aece0 1 1 /* 2 * Copyright (c) 2008 Martin Decky 3 * Copyright (c) 2006 Jakub Vana 4 * Copyright (c) 2006 Ondrej Palkovsky 2 * Copyright (c) 2011 Martin Decky 5 3 * All rights reserved. 6 4 * … … 29 27 */ 30 28 31 /** 32 * @defgroup fb Graphical framebuffer 33 * @brief HelenOS graphical framebuffer. 34 * @ingroup fbs 35 * @{ 36 */ 37 38 /** @file 39 */ 40 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <str.h> 44 #include <ddi.h> 45 #include <sysinfo.h> 46 #include <align.h> 29 #include <sys/types.h> 30 #include <bool.h> 31 #include <loc.h> 32 #include <errno.h> 33 #include <stdio.h> 34 #include <malloc.h> 35 #include <inttypes.h> 47 36 #include <as.h> 48 #include <ipc/fb.h> 49 #include <ipc/ns.h> 50 #include <ipc/services.h> 51 #include <errno.h> 52 #include <abi/fb/visuals.h> 53 #include <io/color.h> 54 #include <io/style.h> 55 #include <async.h> 56 #include <fibril.h> 57 #include <bool.h> 58 #include <stdio.h> 59 #include <byteorder.h> 60 #include <io/screenbuffer.h> 61 #include <imgmap.h> 62 #include "font-8x16.h" 37 #include <fb.h> 38 #include <screenbuffer.h> 39 #include "port/ega.h" 40 #include "port/kchar.h" 41 #include "port/kfb.h" 42 #include "port/niagara.h" 43 #include "port/ski.h" 63 44 #include "fb.h" 64 #include "main.h" 65 #include "pointer.xbm" 66 #include "pointer_mask.xbm" 67 68 // FIXME: remove this header 69 #include <abi/ipc/methods.h> 70 71 #define DEFAULT_BGCOLOR 0xf0f0f0 72 #define DEFAULT_FGCOLOR 0x000000 73 74 #define GLYPH_UNAVAIL '?' 75 76 #define MAX_ANIM_LEN 8 77 #define MAX_ANIMATIONS 4 78 #define MAX_IMGMAPS 256 /**< Maximum number of saved image maps */ 79 #define MAX_VIEWPORTS 128 /**< Viewport is a rectangular area on the screen */ 80 81 /** Function to render a pixel from a RGB value. */ 82 typedef void (*rgb_conv_t)(void *, uint32_t); 83 84 /** Function to render a bit mask. */ 85 typedef void (*mask_conv_t)(void *, bool); 86 87 /** Function to draw a glyph. */ 88 typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor, 89 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color); 90 91 struct { 92 uint8_t *fb_addr; 93 94 unsigned int xres; 95 unsigned int yres; 96 97 unsigned int scanline; 98 unsigned int glyphscanline; 99 100 unsigned int pixelbytes; 101 unsigned int glyphbytes; 102 103 /** Pre-rendered mask for rendering glyphs. Specific for the visual. */ 104 uint8_t *glyphs; 105 106 rgb_conv_t rgb_conv; 107 mask_conv_t mask_conv; 108 } screen; 109 110 /** Backbuffer character cell. */ 111 typedef struct { 112 uint32_t glyph; 113 uint32_t fg_color; 114 uint32_t bg_color; 115 } bb_cell_t; 116 117 typedef struct { 118 bool initialized; 119 unsigned int x; 120 unsigned int y; 121 unsigned int width; 122 unsigned int height; 123 124 /* Text support in window */ 125 unsigned int cols; 126 unsigned int rows; 45 46 #define NAME "fb" 47 #define NAMESPACE "hid" 48 49 #define TICK_INTERVAL 250000 50 51 static LIST_INITIALIZE(fbdevs); 52 53 fbdev_t *fbdev_register(fbdev_ops_t *ops, void *data) 54 { 55 sysarg_t index = 0; 56 57 if (!list_empty(&fbdevs)) { 58 list_foreach(fbdevs, link) { 59 fbdev_t *dev = list_get_instance(link, fbdev_t, link); 60 if (index <= dev->index) 61 index = dev->index + 1; 62 } 63 } 64 65 fbdev_t *dev = (fbdev_t *) malloc(sizeof(fbdev_t)); 66 if (dev == NULL) 67 return NULL; 68 69 link_initialize(&dev->link); 70 atomic_set(&dev->refcnt, 0); 71 dev->claimed = false; 72 dev->index = index; 73 list_initialize(&dev->vps); 74 list_initialize(&dev->frontbufs); 75 list_initialize(&dev->imagemaps); 76 list_initialize(&dev->sequences); 77 78 dev->ops = *ops; 79 dev->data = data; 80 81 char node[LOC_NAME_MAXLEN + 1]; 82 snprintf(node, LOC_NAME_MAXLEN, "%s/%s%" PRIun, NAMESPACE, NAME, 83 index); 84 85 if (loc_service_register(node, &dev->dsid) != EOK) { 86 printf("%s: Unable to register device %s\n", NAME, node); 87 free(dev); 88 return NULL; 89 } 90 91 list_append(&dev->link, &fbdevs); 92 return dev; 93 } 94 95 static void fbsrv_yield(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 96 { 97 assert(dev->ops.yield); 98 99 if (dev->claimed) { 100 int rc = dev->ops.yield(dev); 101 if (rc == EOK) 102 dev->claimed = false; 103 104 async_answer_0(iid, rc); 105 } else 106 async_answer_0(iid, ENOENT); 107 } 108 109 static void fbsrv_claim(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 110 { 111 assert(dev->ops.claim); 112 113 if (!dev->claimed) { 114 int rc = dev->ops.claim(dev); 115 if (rc == EOK) 116 dev->claimed = true; 117 118 async_answer_0(iid, rc); 119 } else 120 async_answer_0(iid, ENOENT); 121 } 122 123 static void fbsrv_get_resolution(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 124 { 125 assert(dev->ops.get_resolution); 126 127 sysarg_t width; 128 sysarg_t height; 129 int rc = dev->ops.get_resolution(dev, &width, &height); 130 131 async_answer_2(iid, rc, width, height); 132 } 133 134 static void fbsrv_pointer_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 135 { 136 if ((dev->claimed) && (dev->ops.pointer_update)) { 137 dev->ops.pointer_update(dev, IPC_GET_ARG1(*icall), 138 IPC_GET_ARG2(*icall), IPC_GET_ARG3(*icall)); 139 async_answer_0(iid, EOK); 140 } else 141 async_answer_0(iid, ENOTSUP); 142 } 143 144 static fbvp_t *resolve_vp(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid) 145 { 146 fbvp_t *vp = NULL; 147 list_foreach(dev->vps, link) { 148 fbvp_t *cur = list_get_instance(link, fbvp_t, link); 149 if (cur == (fbvp_t *) handle) { 150 vp = cur; 151 break; 152 } 153 } 154 155 if (vp == NULL) { 156 async_answer_0(iid, ENOENT); 157 return NULL; 158 } 159 160 return vp; 161 } 162 163 static frontbuf_t *resolve_frontbuf(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid) 164 { 165 frontbuf_t *frontbuf = NULL; 166 list_foreach(dev->frontbufs, link) { 167 frontbuf_t *cur = list_get_instance(link, frontbuf_t, link); 168 if (cur == (frontbuf_t *) handle) { 169 frontbuf = cur; 170 break; 171 } 172 } 173 174 if (frontbuf == NULL) { 175 async_answer_0(iid, ENOENT); 176 return NULL; 177 } 178 179 return frontbuf; 180 } 181 182 static imagemap_t *resolve_imagemap(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid) 183 { 184 imagemap_t *imagemap = NULL; 185 list_foreach(dev->imagemaps, link) { 186 imagemap_t *cur = list_get_instance(link, imagemap_t, link); 187 if (cur == (imagemap_t *) handle) { 188 imagemap = cur; 189 break; 190 } 191 } 192 193 if (imagemap == NULL) { 194 async_answer_0(iid, ENOENT); 195 return NULL; 196 } 197 198 return imagemap; 199 } 200 201 static sequence_t *resolve_sequence(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid) 202 { 203 sequence_t *sequence = NULL; 204 list_foreach(dev->sequences, link) { 205 sequence_t *cur = list_get_instance(link, sequence_t, link); 206 if (cur == (sequence_t *) handle) { 207 sequence = cur; 208 break; 209 } 210 } 211 212 if (sequence == NULL) { 213 async_answer_0(iid, ENOENT); 214 return NULL; 215 } 216 217 return sequence; 218 } 219 220 static void fbsrv_vp_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 221 { 222 assert(dev->ops.font_metrics); 223 assert(dev->ops.vp_create); 224 225 fbvp_t *vp = (fbvp_t *) malloc(sizeof(fbvp_t)); 226 if (vp == NULL) { 227 async_answer_0(iid, ENOMEM); 228 return; 229 } 230 231 link_initialize(&vp->link); 232 233 vp->x = IPC_GET_ARG1(*icall); 234 vp->y = IPC_GET_ARG2(*icall); 235 vp->width = IPC_GET_ARG3(*icall); 236 vp->height = IPC_GET_ARG4(*icall); 237 238 dev->ops.font_metrics(dev, vp->width, vp->height, &vp->cols, &vp->rows); 239 240 vp->cursor_active = false; 241 vp->cursor_flash = false; 242 243 list_initialize(&vp->sequences); 244 245 vp->backbuf = screenbuffer_create(vp->cols, vp->rows, 246 SCREENBUFFER_FLAG_NONE); 247 if (vp->backbuf == NULL) { 248 free(vp); 249 async_answer_0(iid, ENOMEM); 250 return; 251 } 252 253 vp->top_row = 0; 254 255 int rc = dev->ops.vp_create(dev, vp); 256 if (rc != EOK) { 257 free(vp); 258 async_answer_0(iid, ENOMEM); 259 return; 260 } 261 262 list_append(&vp->link, &dev->vps); 263 async_answer_1(iid, EOK, (sysarg_t) vp); 264 } 265 266 static void fbsrv_vp_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 267 { 268 assert(dev->ops.vp_destroy); 269 270 fbvp_t *vp = resolve_vp(dev, IPC_GET_ARG1(*icall), iid); 271 if (vp == NULL) 272 return; 273 274 if (dev->active_vp == vp) { 275 async_answer_0(iid, EPERM); 276 return; 277 } 278 279 dev->ops.vp_destroy(dev, vp); 280 281 list_remove(&vp->link); 282 free(vp->backbuf); 283 free(vp); 284 285 async_answer_0(iid, EOK); 286 } 287 288 static void fbsrv_frontbuf_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 289 { 290 frontbuf_t *frontbuf = (frontbuf_t *) malloc(sizeof(frontbuf_t)); 291 if (frontbuf == NULL) { 292 async_answer_0(iid, ENOMEM); 293 return; 294 } 295 296 link_initialize(&frontbuf->link); 297 298 ipc_callid_t callid; 299 if (!async_share_out_receive(&callid, &frontbuf->size, 300 &frontbuf->flags)) { 301 free(frontbuf); 302 async_answer_0(iid, EINVAL); 303 return; 304 } 305 306 int rc = async_share_out_finalize(callid, &frontbuf->data); 307 if ((rc != EOK) || (frontbuf->data == (void *) -1)) { 308 free(frontbuf); 309 async_answer_0(iid, ENOMEM); 310 return; 311 } 312 313 list_append(&frontbuf->link, &dev->frontbufs); 314 async_answer_1(iid, EOK, (sysarg_t) frontbuf); 315 } 316 317 static void fbsrv_frontbuf_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 318 { 319 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid); 320 if (frontbuf == NULL) 321 return; 322 323 list_remove(&frontbuf->link); 324 as_area_destroy(frontbuf->data); 325 free(frontbuf); 326 327 async_answer_0(iid, EOK); 328 } 329 330 static void fbsrv_imagemap_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 331 { 332 imagemap_t *imagemap = (imagemap_t *) malloc(sizeof(imagemap_t)); 333 if (imagemap == NULL) { 334 async_answer_0(iid, ENOMEM); 335 return; 336 } 337 338 link_initialize(&imagemap->link); 339 link_initialize(&imagemap->seq_link); 340 341 ipc_callid_t callid; 342 if (!async_share_out_receive(&callid, &imagemap->size, 343 &imagemap->flags)) { 344 free(imagemap); 345 async_answer_0(iid, EINVAL); 346 return; 347 } 348 349 int rc = async_share_out_finalize(callid, &imagemap->data); 350 if ((rc != EOK) || (imagemap->data == (void *) -1)) { 351 free(imagemap); 352 async_answer_0(iid, ENOMEM); 353 return; 354 } 355 356 list_append(&imagemap->link, &dev->imagemaps); 357 async_answer_1(iid, EOK, (sysarg_t) imagemap); 358 } 359 360 static void fbsrv_imagemap_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 361 { 362 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid); 363 if (imagemap == NULL) 364 return; 365 366 list_remove(&imagemap->link); 367 list_remove(&imagemap->seq_link); 368 as_area_destroy(imagemap->data); 369 free(imagemap); 370 371 async_answer_0(iid, EOK); 372 } 373 374 static void fbsrv_sequence_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 375 { 376 sequence_t *sequence = (sequence_t *) malloc(sizeof(sequence_t)); 377 if (sequence == NULL) { 378 async_answer_0(iid, ENOMEM); 379 return; 380 } 381 382 link_initialize(&sequence->link); 383 list_initialize(&sequence->imagemaps); 384 sequence->count = 0; 385 386 list_append(&sequence->link, &dev->sequences); 387 async_answer_1(iid, EOK, (sysarg_t) sequence); 388 } 389 390 static void fbsrv_sequence_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 391 { 392 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid); 393 if (sequence == NULL) 394 return; 395 396 list_remove(&sequence->link); 397 free(sequence); 398 399 async_answer_0(iid, EOK); 400 } 401 402 static void fbsrv_sequence_add_imagemap(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 403 { 404 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid); 405 if (sequence == NULL) 406 return; 407 408 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG2(*icall), iid); 409 if (imagemap == NULL) 410 return; 411 412 if (list_member(&imagemap->seq_link, &sequence->imagemaps)) { 413 async_answer_0(iid, EEXISTS); 414 return; 415 } 416 417 list_append(&imagemap->seq_link, &sequence->imagemaps); 418 sequence->count++; 419 420 async_answer_0(iid, EOK); 421 } 422 423 static void fbsrv_vp_focus(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 424 { 425 fbvp_t *vp = resolve_vp(dev, IPC_GET_ARG1(*icall), iid); 426 if (vp == NULL) 427 return; 428 429 if (dev->active_vp != vp) 430 dev->active_vp = vp; 431 432 async_answer_0(iid, EOK); 433 } 434 435 static void fbsrv_vp_clear(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 436 { 437 assert(dev->ops.vp_clear); 438 439 if ((dev->claimed) && (dev->active_vp)) { 440 screenbuffer_set_cursor_visibility(dev->active_vp->backbuf, false); 441 dev->ops.vp_clear(dev, dev->active_vp); 442 async_answer_0(iid, EOK); 443 } else 444 async_answer_0(iid, ENOENT); 445 } 446 447 static void fbsrv_vp_get_dimensions(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 448 { 449 if (dev->active_vp) 450 async_answer_2(iid, EOK, dev->active_vp->cols, dev->active_vp->rows); 451 else 452 async_answer_0(iid, ENOENT); 453 } 454 455 static void fbsrv_vp_get_caps(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 456 { 457 assert(dev->ops.vp_get_caps); 458 459 if (dev->active_vp) 460 async_answer_1(iid, EOK, 461 (sysarg_t) dev->ops.vp_get_caps(dev, dev->active_vp)); 462 else 463 async_answer_0(iid, ENOENT); 464 } 465 466 static void fbsrv_vp_cursor_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 467 { 468 assert(dev->ops.vp_cursor_update); 469 470 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid); 471 if (frontbuf == NULL) 472 return; 473 474 if ((dev->claimed) && (dev->active_vp)) { 475 screenbuffer_t *screenbuf = (screenbuffer_t *) frontbuf->data; 476 477 sysarg_t prev_col; 478 sysarg_t prev_row; 479 sysarg_t col; 480 sysarg_t row; 481 482 screenbuffer_get_cursor(dev->active_vp->backbuf, 483 &prev_col, &prev_row); 484 screenbuffer_get_cursor(screenbuf, &col, &row); 485 screenbuffer_set_cursor(dev->active_vp->backbuf, col, row); 486 487 bool visible = screenbuffer_get_cursor_visibility(screenbuf); 488 screenbuffer_set_cursor_visibility(dev->active_vp->backbuf, visible); 489 490 if (visible) 491 dev->active_vp->cursor_active = true; 492 493 dev->ops.vp_cursor_update(dev, dev->active_vp, prev_col, prev_row, 494 col, row, visible); 495 async_answer_0(iid, EOK); 496 } else 497 async_answer_0(iid, ENOENT); 498 } 499 500 static void fbsrv_vp_cursor_flash(fbdev_t *dev) 501 { 502 if ((dev->claimed) && (dev->ops.vp_cursor_flash)) { 503 list_foreach (dev->vps, link) { 504 fbvp_t *vp = list_get_instance(link, fbvp_t, link); 505 506 if (vp->cursor_active) { 507 sysarg_t col; 508 sysarg_t row; 509 510 screenbuffer_get_cursor(vp->backbuf, &col, &row); 511 vp->cursor_flash = !vp->cursor_flash; 512 dev->ops.vp_cursor_flash(dev, vp, col, row); 513 } 514 } 515 } 516 } 517 518 static void fbsrv_sequences_update(fbdev_t *dev) 519 { 520 if ((dev->claimed) && (dev->ops.vp_imgmap_damage)) { 521 list_foreach (dev->vps, vp_link) { 522 fbvp_t *vp = list_get_instance(vp_link, fbvp_t, link); 523 524 list_foreach (vp->sequences, seq_vp_link) { 525 sequence_vp_t *seq_vp = 526 list_get_instance(seq_vp_link, sequence_vp_t, link); 527 528 seq_vp->current++; 529 if (seq_vp->current >= seq_vp->seq->count) 530 seq_vp->current = 0; 531 532 link_t *link = 533 list_nth(&seq_vp->seq->imagemaps, seq_vp->current); 534 if (link != NULL) { 535 imagemap_t *imagemap = 536 list_get_instance(link, imagemap_t, seq_link); 537 538 imgmap_t *imgmap = (imgmap_t *) imagemap->data; 539 sysarg_t width; 540 sysarg_t height; 541 542 imgmap_get_resolution(imgmap, &width, &height); 543 dev->ops.vp_imgmap_damage(dev, vp, imgmap, 544 0, 0, width, height); 545 } 546 } 547 } 548 } 549 } 550 551 static void fbsrv_vp_set_style(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 552 { 553 if (dev->active_vp) { 554 dev->active_vp->attrs.type = CHAR_ATTR_STYLE; 555 dev->active_vp->attrs.val.style = 556 (console_style_t) IPC_GET_ARG1(*icall); 557 async_answer_0(iid, EOK); 558 } else 559 async_answer_0(iid, ENOENT); 560 } 561 562 static void fbsrv_vp_set_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 563 { 564 if (dev->active_vp) { 565 dev->active_vp->attrs.type = CHAR_ATTR_INDEX; 566 dev->active_vp->attrs.val.index.bgcolor = 567 (console_color_t) IPC_GET_ARG1(*icall); 568 dev->active_vp->attrs.val.index.fgcolor = 569 (console_color_t) IPC_GET_ARG2(*icall); 570 dev->active_vp->attrs.val.index.attr = 571 (console_color_attr_t) IPC_GET_ARG3(*icall); 572 async_answer_0(iid, EOK); 573 } else 574 async_answer_0(iid, ENOENT); 575 } 576 577 static void fbsrv_vp_set_rgb_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 578 { 579 if (dev->active_vp) { 580 dev->active_vp->attrs.type = CHAR_ATTR_RGB; 581 dev->active_vp->attrs.val.rgb.bgcolor = IPC_GET_ARG1(*icall); 582 dev->active_vp->attrs.val.rgb.fgcolor = IPC_GET_ARG2(*icall); 583 async_answer_0(iid, EOK); 584 } else 585 async_answer_0(iid, ENOENT); 586 } 587 588 static void fbsrv_vp_putchar(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 589 { 590 assert(dev->ops.vp_char_update); 591 592 if ((dev->claimed) && (dev->active_vp)) { 593 charfield_t *field = screenbuffer_field_at(dev->active_vp->backbuf, 594 IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall)); 595 596 field->ch = IPC_GET_ARG3(*icall); 597 598 dev->ops.vp_char_update(dev, dev->active_vp, IPC_GET_ARG1(*icall), 599 IPC_GET_ARG2(*icall)); 600 async_answer_0(iid, EOK); 601 } else 602 async_answer_0(iid, ENOENT); 603 } 604 605 static bool fbsrv_vp_update_scroll(fbdev_t *dev, fbvp_t *vp, 606 screenbuffer_t *frontbuf) 607 { 608 assert(dev->ops.vp_char_update); 609 610 sysarg_t top_row = screenbuffer_get_top_row(frontbuf); 611 612 if (vp->top_row == top_row) 613 return false; 614 615 vp->top_row = top_row; 616 617 for (sysarg_t y = 0; y < vp->rows; y++) { 618 for (sysarg_t x = 0; x < vp->cols; x++) { 619 charfield_t *front_field = 620 screenbuffer_field_at(frontbuf, x, y); 621 charfield_t *back_field = 622 screenbuffer_field_at(vp->backbuf, x, y); 623 bool update = false; 624 625 if (front_field->ch != back_field->ch) { 626 back_field->ch = front_field->ch; 627 update = true; 628 } 629 630 if (!attrs_same(front_field->attrs, back_field->attrs)) { 631 back_field->attrs = front_field->attrs; 632 update = true; 633 } 634 635 front_field->flags &= ~CHAR_FLAG_DIRTY; 636 637 if (update) 638 dev->ops.vp_char_update(dev, vp, x, y); 639 } 640 } 641 642 return true; 643 } 644 645 static void fbsrv_vp_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 646 { 647 assert(dev->ops.vp_char_update); 648 649 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid); 650 if (frontbuf == NULL) 651 return; 652 653 if ((dev->claimed) && (dev->active_vp)) { 654 fbvp_t *vp = dev->active_vp; 655 screenbuffer_t *screenbuf = (screenbuffer_t *) frontbuf->data; 656 657 if (fbsrv_vp_update_scroll(dev, vp, screenbuf)) { 658 async_answer_0(iid, EOK); 659 return; 660 } 661 662 for (sysarg_t y = 0; y < vp->rows; y++) { 663 for (sysarg_t x = 0; x < vp->cols; x++) { 664 charfield_t *front_field = 665 screenbuffer_field_at(screenbuf, x, y); 666 charfield_t *back_field = 667 screenbuffer_field_at(vp->backbuf, x, y); 668 bool update = false; 669 670 if ((front_field->flags & CHAR_FLAG_DIRTY) == CHAR_FLAG_DIRTY) { 671 if (front_field->ch != back_field->ch) { 672 back_field->ch = front_field->ch; 673 update = true; 674 } 675 676 if (!attrs_same(front_field->attrs, back_field->attrs)) { 677 back_field->attrs = front_field->attrs; 678 update = true; 679 } 680 681 front_field->flags &= ~CHAR_FLAG_DIRTY; 682 } 683 684 if (update) 685 dev->ops.vp_char_update(dev, vp, x, y); 686 } 687 } 688 689 async_answer_0(iid, EOK); 690 } else 691 async_answer_0(iid, ENOENT); 692 } 693 694 static void fbsrv_vp_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 695 { 696 assert(dev->ops.vp_char_update); 697 698 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid); 699 if (frontbuf == NULL) 700 return; 701 702 if ((dev->claimed) && (dev->active_vp)) { 703 fbvp_t *vp = dev->active_vp; 704 screenbuffer_t *screenbuf = (screenbuffer_t *) frontbuf->data; 705 706 if (fbsrv_vp_update_scroll(dev, vp, screenbuf)) { 707 async_answer_0(iid, EOK); 708 return; 709 } 710 711 sysarg_t col = IPC_GET_ARG2(*icall); 712 sysarg_t row = IPC_GET_ARG3(*icall); 713 714 sysarg_t cols = IPC_GET_ARG4(*icall); 715 sysarg_t rows = IPC_GET_ARG5(*icall); 716 717 for (sysarg_t y = 0; y < rows; y++) { 718 for (sysarg_t x = 0; x < cols; x++) { 719 charfield_t *front_field = 720 screenbuffer_field_at(screenbuf, col + x, row + y); 721 charfield_t *back_field = 722 screenbuffer_field_at(vp->backbuf, col + x, row + y); 723 bool update = false; 724 725 if (front_field->ch != back_field->ch) { 726 back_field->ch = front_field->ch; 727 update = true; 728 } 729 730 if (!attrs_same(front_field->attrs, back_field->attrs)) { 731 back_field->attrs = front_field->attrs; 732 update = true; 733 } 734 735 front_field->flags &= ~CHAR_FLAG_DIRTY; 736 737 if (update) 738 dev->ops.vp_char_update(dev, vp, col + x, row + y); 739 } 740 } 741 742 async_answer_0(iid, EOK); 743 } else 744 async_answer_0(iid, ENOENT); 745 } 746 747 static void fbsrv_vp_imagemap_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 748 { 749 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid); 750 if (imagemap == NULL) 751 return; 752 753 if ((dev->claimed) && (dev->ops.vp_imgmap_damage)) { 754 if (dev->active_vp) { 755 dev->ops.vp_imgmap_damage(dev, dev->active_vp, 756 (imgmap_t *) imagemap->data, 757 IPC_GET_ARG2(*icall), IPC_GET_ARG3(*icall), 758 IPC_GET_ARG4(*icall), IPC_GET_ARG5(*icall)); 759 async_answer_0(iid, EOK); 760 } else 761 async_answer_0(iid, ENOENT); 762 } else 763 async_answer_0(iid, ENOTSUP); 764 } 765 766 static void fbsrv_vp_sequence_start(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 767 { 768 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid); 769 if (sequence == NULL) 770 return; 771 772 if (dev->active_vp) { 773 /* Check if the sequence is not already started */ 774 list_foreach(dev->active_vp->sequences, link) { 775 sequence_vp_t *seq_vp = 776 list_get_instance(link, sequence_vp_t, link); 777 778 if (seq_vp->seq == sequence) { 779 async_answer_0(iid, EEXISTS); 780 return; 781 } 782 } 783 784 sequence_vp_t *seq_vp = 785 (sequence_vp_t *) malloc(sizeof(sequence_vp_t)); 786 787 if (seq_vp != NULL) { 788 link_initialize(&seq_vp->link); 789 seq_vp->seq = sequence; 790 seq_vp->current = 0; 791 792 list_append(&seq_vp->link, &dev->active_vp->sequences); 793 async_answer_0(iid, EOK); 794 } else 795 async_answer_0(iid, ENOMEM); 796 } else 797 async_answer_0(iid, ENOENT); 798 } 799 800 static void fbsrv_vp_sequence_stop(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall) 801 { 802 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid); 803 if (sequence == NULL) 804 return; 805 806 if (dev->active_vp) { 807 list_foreach(dev->active_vp->sequences, link) { 808 sequence_vp_t *seq_vp = 809 list_get_instance(link, sequence_vp_t, link); 810 811 if (seq_vp->seq == sequence) { 812 list_remove(&seq_vp->link); 813 free(seq_vp); 814 815 async_answer_0(iid, EOK); 816 return; 817 } 818 } 819 820 async_answer_0(iid, ENOENT); 821 } else 822 async_answer_0(iid, ENOENT); 823 } 824 825 static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 826 { 827 fbdev_t *dev = NULL; 828 service_id_t dsid = (service_id_t) IPC_GET_ARG1(*icall); 829 830 list_foreach(fbdevs, link) { 831 fbdev_t *fbdev = list_get_instance(link, fbdev_t, link); 832 if (fbdev->dsid == dsid) { 833 dev = fbdev; 834 break; 835 } 836 } 837 838 if (dev == NULL) { 839 async_answer_0(iid, ENOENT); 840 return; 841 } 842 843 if (atomic_get(&dev->refcnt) > 0) { 844 async_answer_0(iid, ELIMIT); 845 return; 846 } 127 847 128 848 /* 129 * Style and glyphs for text printing849 * Accept the connection 130 850 */ 131 851 132 /** Current attributes. */ 133 attr_rgb_t attr; 134 135 uint8_t *bgpixel; 136 137 /** 138 * Glyph drawing function for this viewport. Different viewports 139 * might use different drawing functions depending on whether their 140 * scanlines are aligned on a word boundary. 141 */ 142 dg_t dglyph; 143 144 /* Auto-cursor position */ 145 bool cursor_active; 146 unsigned int cur_col; 147 unsigned int cur_row; 148 bool cursor_shown; 149 150 /* Back buffer */ 151 bb_cell_t *backbuf; 152 unsigned int bbsize; 153 } viewport_t; 154 155 typedef struct { 156 bool initialized; 157 bool enabled; 158 unsigned int vp; 159 160 unsigned int pos; 161 unsigned int animlen; 162 unsigned int imgmaps[MAX_ANIM_LEN]; 163 } animation_t; 164 165 static animation_t animations[MAX_ANIMATIONS]; 166 static bool anims_enabled; 167 168 static imgmap_t *imgmaps[MAX_IMGMAPS]; 169 static viewport_t viewports[128]; 170 171 static bool client_connected = false; /**< Allow only 1 connection */ 172 173 static uint32_t color_table[16] = { 174 [COLOR_BLACK] = 0x000000, 175 [COLOR_BLUE] = 0x0000f0, 176 [COLOR_GREEN] = 0x00f000, 177 [COLOR_CYAN] = 0x00f0f0, 178 [COLOR_RED] = 0xf00000, 179 [COLOR_MAGENTA] = 0xf000f0, 180 [COLOR_YELLOW] = 0xf0f000, 181 [COLOR_WHITE] = 0xf0f0f0, 182 183 [8 + COLOR_BLACK] = 0x000000, 184 [8 + COLOR_BLUE] = 0x0000ff, 185 [8 + COLOR_GREEN] = 0x00ff00, 186 [8 + COLOR_CYAN] = 0x00ffff, 187 [8 + COLOR_RED] = 0xff0000, 188 [8 + COLOR_MAGENTA] = 0xff00ff, 189 [8 + COLOR_YELLOW] = 0xffff00, 190 [8 + COLOR_WHITE] = 0xffffff, 191 }; 192 193 static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a); 194 static int rgb_from_style(attr_rgb_t *rgb, int style); 195 static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color, 196 sysarg_t bg_color, sysarg_t flags); 197 198 static int fb_set_color(viewport_t *vport, sysarg_t fg_color, 199 sysarg_t bg_color, sysarg_t attr); 200 201 static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor, 202 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color); 203 static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor, 204 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color); 205 206 static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col, 207 unsigned int row); 208 209 #define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1)) 210 #define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1)) 211 #define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1)) 212 213 #define COL2X(col) ((col) * FONT_WIDTH) 214 #define ROW2Y(row) ((row) * FONT_SCANLINES) 215 216 #define X2COL(x) ((x) / FONT_WIDTH) 217 #define Y2ROW(y) ((y) / FONT_SCANLINES) 218 219 #define FB_POS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes) 220 #define BB_POS(vport, col, row) ((row) * vport->cols + (col)) 221 #define GLYPH_POS(glyph, y, cursor) (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline) 222 223 /* 224 * RGB conversion and mask functions. 225 * 226 * These functions write an RGB value to some memory in some predefined format. 227 * The naming convention corresponds to the format created by these functions. 228 * The functions use the so called network order (i.e. big endian) with respect 229 * to their names. 230 */ 231 232 static void rgb_0888(void *dst, uint32_t rgb) 233 { 234 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) | 235 (RED(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (BLUE(rgb, 8))); 236 } 237 238 static void bgr_0888(void *dst, uint32_t rgb) 239 { 240 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) | 241 (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (RED(rgb, 8))); 242 } 243 244 static void mask_0888(void *dst, bool mask) 245 { 246 bgr_0888(dst, mask ? 0xffffff : 0); 247 } 248 249 static void rgb_8880(void *dst, uint32_t rgb) 250 { 251 *((uint32_t *) dst) = host2uint32_t_be((RED(rgb, 8) << 24) | 252 (GREEN(rgb, 8) << 16) | (BLUE(rgb, 8) << 8) | 0); 253 } 254 255 static void bgr_8880(void *dst, uint32_t rgb) 256 { 257 *((uint32_t *) dst) = host2uint32_t_be((BLUE(rgb, 8) << 24) | 258 (GREEN(rgb, 8) << 16) | (RED(rgb, 8) << 8) | 0); 259 } 260 261 static void mask_8880(void *dst, bool mask) 262 { 263 bgr_8880(dst, mask ? 0xffffff : 0); 264 } 265 266 static void rgb_888(void *dst, uint32_t rgb) 267 { 268 ((uint8_t *) dst)[0] = RED(rgb, 8); 269 ((uint8_t *) dst)[1] = GREEN(rgb, 8); 270 ((uint8_t *) dst)[2] = BLUE(rgb, 8); 271 } 272 273 static void bgr_888(void *dst, uint32_t rgb) 274 { 275 ((uint8_t *) dst)[0] = BLUE(rgb, 8); 276 ((uint8_t *) dst)[1] = GREEN(rgb, 8); 277 ((uint8_t *) dst)[2] = RED(rgb, 8); 278 } 279 280 static void mask_888(void *dst, bool mask) 281 { 282 bgr_888(dst, mask ? 0xffffff : 0); 283 } 284 285 static void rgb_555_be(void *dst, uint32_t rgb) 286 { 287 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 10 | 288 GREEN(rgb, 5) << 5 | BLUE(rgb, 5)); 289 } 290 291 static void rgb_555_le(void *dst, uint32_t rgb) 292 { 293 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 10 | 294 GREEN(rgb, 5) << 5 | BLUE(rgb, 5)); 295 } 296 297 static void rgb_565_be(void *dst, uint32_t rgb) 298 { 299 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 11 | 300 GREEN(rgb, 6) << 5 | BLUE(rgb, 5)); 301 } 302 303 static void rgb_565_le(void *dst, uint32_t rgb) 304 { 305 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 11 | 306 GREEN(rgb, 6) << 5 | BLUE(rgb, 5)); 307 } 308 309 static void mask_555(void *dst, bool mask) 310 { 311 rgb_555_be(dst, mask ? 0xffffff : 0); 312 } 313 314 static void mask_565(void *dst, bool mask) 315 { 316 rgb_565_be(dst, mask ? 0xffffff : 0); 317 } 318 319 static void bgr_323(void *dst, uint32_t rgb) 320 { 321 *((uint8_t *) dst) 322 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3)); 323 } 324 325 static void mask_323(void *dst, bool mask) 326 { 327 bgr_323(dst, mask ? 0x0 : ~0x0); 328 } 329 330 /** Draw a filled rectangle. 331 * 332 * @note Need real implementation that does not access VRAM twice. 333 * 334 */ 335 static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1, 336 unsigned int y1, uint32_t color) 337 { 338 unsigned int x; 339 unsigned int y; 340 unsigned int copy_bytes; 341 342 uint8_t *sp; 343 uint8_t *dp; 344 uint8_t cbuf[4]; 345 346 if ((y0 >= y1) || (x0 >= x1)) 347 return; 348 349 screen.rgb_conv(cbuf, color); 350 351 sp = &screen.fb_addr[FB_POS(x0, y0)]; 352 dp = sp; 353 354 /* Draw the first line. */ 355 for (x = x0; x < x1; x++) { 356 memcpy(dp, cbuf, screen.pixelbytes); 357 dp += screen.pixelbytes; 358 } 359 360 dp = sp + screen.scanline; 361 copy_bytes = (x1 - x0) * screen.pixelbytes; 362 363 /* Draw the remaining lines by copying. */ 364 for (y = y0 + 1; y < y1; y++) { 365 memcpy(dp, sp, copy_bytes); 366 dp += screen.scanline; 367 } 368 } 369 370 /** Redraw viewport. 371 * 372 * @param vport Viewport to redraw 373 * 374 */ 375 static void vport_redraw(viewport_t *vport) 376 { 377 unsigned int col; 378 unsigned int row; 379 380 for (row = 0; row < vport->rows; row++) { 381 for (col = 0; col < vport->cols; col++) { 382 draw_vp_glyph(vport, false, col, row); 383 } 384 } 385 386 if (COL2X(vport->cols) < vport->width) { 387 draw_filled_rect( 388 vport->x + COL2X(vport->cols), vport->y, 389 vport->x + vport->width, vport->y + vport->height, 390 vport->attr.bg_color); 391 } 392 393 if (ROW2Y(vport->rows) < vport->height) { 394 draw_filled_rect( 395 vport->x, vport->y + ROW2Y(vport->rows), 396 vport->x + vport->width, vport->y + vport->height, 397 vport->attr.bg_color); 398 } 399 } 400 401 static void backbuf_clear(bb_cell_t *backbuf, size_t len, uint32_t fg_color, 402 uint32_t bg_color) 403 { 404 size_t i; 405 406 for (i = 0; i < len; i++) { 407 backbuf[i].glyph = 0; 408 backbuf[i].fg_color = fg_color; 409 backbuf[i].bg_color = bg_color; 410 } 411 } 412 413 /** Clear viewport. 414 * 415 * @param vport Viewport to clear 416 * 417 */ 418 static void vport_clear(viewport_t *vport) 419 { 420 backbuf_clear(vport->backbuf, vport->cols * vport->rows, 421 vport->attr.fg_color, vport->attr.bg_color); 422 vport_redraw(vport); 423 } 424 425 /** Scroll viewport by the specified number of lines. 426 * 427 * @param vport Viewport to scroll 428 * @param lines Number of lines to scroll 429 * 430 */ 431 static void vport_scroll(viewport_t *vport, int lines) 432 { 433 unsigned int col; 434 unsigned int row; 435 unsigned int x; 436 unsigned int y; 437 uint32_t glyph; 438 uint32_t fg_color; 439 uint32_t bg_color; 440 bb_cell_t *bbp; 441 bb_cell_t *xbp; 442 443 /* 444 * Redraw. 445 */ 446 447 y = vport->y; 448 for (row = 0; row < vport->rows; row++) { 449 x = vport->x; 450 for (col = 0; col < vport->cols; col++) { 451 if (((int) row + lines >= 0) && 452 ((int) row + lines < (int) vport->rows)) { 453 xbp = &vport->backbuf[BB_POS(vport, col, row + lines)]; 454 bbp = &vport->backbuf[BB_POS(vport, col, row)]; 455 456 glyph = xbp->glyph; 457 fg_color = xbp->fg_color; 458 bg_color = xbp->bg_color; 459 460 if ((bbp->glyph == glyph) 461 && (bbp->fg_color == xbp->fg_color) 462 && (bbp->bg_color == xbp->bg_color)) { 463 x += FONT_WIDTH; 464 continue; 465 } 466 } else { 467 glyph = 0; 468 fg_color = vport->attr.fg_color; 469 bg_color = vport->attr.bg_color; 470 } 471 472 (*vport->dglyph)(x, y, false, screen.glyphs, glyph, 473 fg_color, bg_color); 474 x += FONT_WIDTH; 475 } 476 y += FONT_SCANLINES; 477 } 478 479 /* 480 * Scroll backbuffer. 481 */ 482 483 if (lines > 0) { 484 memmove(vport->backbuf, vport->backbuf + vport->cols * lines, 485 vport->cols * (vport->rows - lines) * sizeof(bb_cell_t)); 486 backbuf_clear(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)], 487 vport->cols * lines, vport->attr.fg_color, vport->attr.bg_color); 488 } else { 489 memmove(vport->backbuf - vport->cols * lines, vport->backbuf, 490 vport->cols * (vport->rows + lines) * sizeof(bb_cell_t)); 491 backbuf_clear(vport->backbuf, - vport->cols * lines, 492 vport->attr.fg_color, vport->attr.bg_color); 493 } 494 } 495 496 /** Render glyphs 497 * 498 * Convert glyphs from device independent font 499 * description to current visual representation. 500 * 501 */ 502 static void render_glyphs(void) 503 { 504 unsigned int glyph; 505 506 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) { 507 unsigned int y; 508 509 for (y = 0; y < FONT_SCANLINES; y++) { 510 unsigned int x; 511 512 for (x = 0; x < FONT_WIDTH; x++) { 513 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes], 514 (fb_font[glyph][y] & (1 << (7 - x))) ? true : false); 515 516 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes], 517 (fb_font[glyph][y] & (1 << (7 - x))) ? false : true); 518 } 519 } 520 } 521 } 522 523 /** Create new viewport 524 * 525 * @param x Origin of the viewport (x). 526 * @param y Origin of the viewport (y). 527 * @param width Width of the viewport. 528 * @param height Height of the viewport. 529 * 530 * @return New viewport number. 531 * 532 */ 533 static int vport_create(unsigned int x, unsigned int y, 534 unsigned int width, unsigned int height) 535 { 536 unsigned int i; 537 538 for (i = 0; i < MAX_VIEWPORTS; i++) { 539 if (!viewports[i].initialized) 852 atomic_inc(&dev->refcnt); 853 dev->claimed = true; 854 async_answer_0(iid, EOK); 855 856 while (true) { 857 ipc_call_t call; 858 ipc_callid_t callid = 859 async_get_call_timeout(&call, TICK_INTERVAL); 860 861 if (!callid) { 862 fbsrv_vp_cursor_flash(dev); 863 fbsrv_sequences_update(dev); 864 continue; 865 } 866 867 if (!IPC_GET_IMETHOD(call)) { 868 dev->claimed = false; 869 atomic_dec(&dev->refcnt); 870 async_answer_0(callid, EOK); 540 871 break; 541 }542 543 if (i == MAX_VIEWPORTS)544 return ELIMIT;545 546 unsigned int cols = width / FONT_WIDTH;547 unsigned int rows = height / FONT_SCANLINES;548 unsigned int bbsize = cols * rows * sizeof(bb_cell_t);549 unsigned int word_size = sizeof(unsigned long);550 551 bb_cell_t *backbuf = (bb_cell_t *) malloc(bbsize);552 if (!backbuf)553 return ENOMEM;554 555 uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);556 if (!bgpixel) {557 free(backbuf);558 return ENOMEM;559 }560 561 backbuf_clear(backbuf, cols * rows, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR);562 memset(bgpixel, 0, screen.pixelbytes);563 564 viewports[i].x = x;565 viewports[i].y = y;566 viewports[i].width = width;567 viewports[i].height = height;568 569 viewports[i].cols = cols;570 viewports[i].rows = rows;571 572 viewports[i].attr.bg_color = DEFAULT_BGCOLOR;573 viewports[i].attr.fg_color = DEFAULT_FGCOLOR;574 575 viewports[i].bgpixel = bgpixel;576 577 /*578 * Conditions necessary to select aligned version:579 * - word size is divisible by pixelbytes580 * - cell scanline size is divisible by word size581 * - cell scanlines are word-aligned582 *583 */584 if (((word_size % screen.pixelbytes) == 0)585 && ((FONT_WIDTH * screen.pixelbytes) % word_size == 0)586 && ((x * screen.pixelbytes) % word_size == 0)587 && (screen.scanline % word_size == 0)) {588 viewports[i].dglyph = draw_glyph_aligned;589 } else {590 viewports[i].dglyph = draw_glyph_fallback;591 }592 593 viewports[i].cur_col = 0;594 viewports[i].cur_row = 0;595 viewports[i].cursor_active = false;596 viewports[i].cursor_shown = false;597 598 viewports[i].bbsize = bbsize;599 viewports[i].backbuf = backbuf;600 601 viewports[i].initialized = true;602 603 screen.rgb_conv(viewports[i].bgpixel, viewports[i].attr.bg_color);604 605 return i;606 }607 608 609 /** Initialize framebuffer as a chardev output device610 *611 * @param addr Address of the framebuffer612 * @param xres Screen width in pixels613 * @param yres Screen height in pixels614 * @param visual Bits per pixel (8, 16, 24, 32)615 * @param scan Bytes per one scanline616 *617 */618 static bool screen_init(void *addr, unsigned int xres, unsigned int yres,619 unsigned int scan, unsigned int visual)620 {621 switch (visual) {622 case VISUAL_INDIRECT_8:623 screen.rgb_conv = bgr_323;624 screen.mask_conv = mask_323;625 screen.pixelbytes = 1;626 break;627 case VISUAL_RGB_5_5_5_LE:628 screen.rgb_conv = rgb_555_le;629 screen.mask_conv = mask_555;630 screen.pixelbytes = 2;631 break;632 case VISUAL_RGB_5_5_5_BE:633 screen.rgb_conv = rgb_555_be;634 screen.mask_conv = mask_555;635 screen.pixelbytes = 2;636 break;637 case VISUAL_RGB_5_6_5_LE:638 screen.rgb_conv = rgb_565_le;639 screen.mask_conv = mask_565;640 screen.pixelbytes = 2;641 break;642 case VISUAL_RGB_5_6_5_BE:643 screen.rgb_conv = rgb_565_be;644 screen.mask_conv = mask_565;645 screen.pixelbytes = 2;646 break;647 case VISUAL_RGB_8_8_8:648 screen.rgb_conv = rgb_888;649 screen.mask_conv = mask_888;650 screen.pixelbytes = 3;651 break;652 case VISUAL_BGR_8_8_8:653 screen.rgb_conv = bgr_888;654 screen.mask_conv = mask_888;655 screen.pixelbytes = 3;656 break;657 case VISUAL_RGB_8_8_8_0:658 screen.rgb_conv = rgb_8880;659 screen.mask_conv = mask_8880;660 screen.pixelbytes = 4;661 break;662 case VISUAL_RGB_0_8_8_8:663 screen.rgb_conv = rgb_0888;664 screen.mask_conv = mask_0888;665 screen.pixelbytes = 4;666 break;667 case VISUAL_BGR_0_8_8_8:668 screen.rgb_conv = bgr_0888;669 screen.mask_conv = mask_0888;670 screen.pixelbytes = 4;671 break;672 case VISUAL_BGR_8_8_8_0:673 screen.rgb_conv = bgr_8880;674 screen.mask_conv = mask_8880;675 screen.pixelbytes = 4;676 break;677 default:678 return false;679 }680 681 screen.fb_addr = (unsigned char *) addr;682 screen.xres = xres;683 screen.yres = yres;684 screen.scanline = scan;685 686 screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;687 screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;688 689 size_t glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;690 uint8_t *glyphs = (uint8_t *) malloc(glyphsize);691 if (!glyphs)692 return false;693 694 memset(glyphs, 0, glyphsize);695 screen.glyphs = glyphs;696 697 render_glyphs();698 699 /* Create first viewport */700 vport_create(0, 0, xres, yres);701 702 return true;703 }704 705 706 /** Draw a glyph, takes advantage of alignment.707 *708 * This version can only be used if the following conditions are met:709 *710 * - word size is divisible by pixelbytes711 * - cell scanline size is divisible by word size712 * - cell scanlines are word-aligned713 *714 * It makes use of the pre-rendered mask to process (possibly) several715 * pixels at once (word size / pixelbytes pixels at a time are processed)716 * making it very fast. Most notably this version is not applicable at 24 bits717 * per pixel.718 *719 * @param x x coordinate of top-left corner on screen.720 * @param y y coordinate of top-left corner on screen.721 * @param cursor Draw glyph with cursor722 * @param glyphs Pointer to font bitmap.723 * @param glyph Code of the glyph to draw.724 * @param fg_color Foreground color.725 * @param bg_color Backgroudn color.726 *727 */728 static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,729 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)730 {731 unsigned int i;732 unsigned int yd;733 unsigned long fg_buf;734 unsigned long bg_buf;735 unsigned long mask;736 737 /*738 * Prepare a pair of words, one filled with foreground-color739 * pattern and the other filled with background-color pattern.740 */741 for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {742 screen.rgb_conv(&((uint8_t *) &fg_buf)[i * screen.pixelbytes],743 fg_color);744 screen.rgb_conv(&((uint8_t *) &bg_buf)[i * screen.pixelbytes],745 bg_color);746 }747 748 /* Pointer to the current position in the mask. */749 unsigned long *maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];750 751 /* Pointer to the current position on the screen. */752 unsigned long *dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];753 754 /* Width of the character cell in words. */755 unsigned int ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);756 757 /* Offset to add when moving to another screen scanline. */758 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;759 760 for (yd = 0; yd < FONT_SCANLINES; yd++) {761 /*762 * Now process the cell scanline, combining foreground763 * and background color patters using the pre-rendered mask.764 */765 for (i = 0; i < ww; i++) {766 mask = *maskp++;767 *dp++ = (fg_buf & mask) | (bg_buf & ~mask);768 }769 770 /* Move to the beginning of the next scanline of the cell. */771 dp = (unsigned long *) ((uint8_t *) dp + d_add);772 }773 }774 775 /** Draw a glyph, fallback version.776 *777 * This version does not make use of the pre-rendered mask, it uses778 * the font bitmap directly. It works always, but it is slower.779 *780 * @param x x coordinate of top-left corner on screen.781 * @param y y coordinate of top-left corner on screen.782 * @param cursor Draw glyph with cursor783 * @param glyphs Pointer to font bitmap.784 * @param glyph Code of the glyph to draw.785 * @param fg_color Foreground color.786 * @param bg_color Backgroudn color.787 *788 */789 void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,790 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)791 {792 unsigned int i;793 unsigned int j;794 unsigned int yd;795 uint8_t fg_buf[4];796 uint8_t bg_buf[4];797 uint8_t *sp;798 uint8_t b;799 800 /* Pre-render 1x the foreground and background color pixels. */801 if (cursor) {802 screen.rgb_conv(fg_buf, bg_color);803 screen.rgb_conv(bg_buf, fg_color);804 } else {805 screen.rgb_conv(fg_buf, fg_color);806 screen.rgb_conv(bg_buf, bg_color);807 }808 809 /* Pointer to the current position on the screen. */810 uint8_t *dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];811 812 /* Offset to add when moving to another screen scanline. */813 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;814 815 for (yd = 0; yd < FONT_SCANLINES; yd++) {816 /* Byte containing bits of the glyph scanline. */817 b = fb_font[glyph][yd];818 819 for (i = 0; i < FONT_WIDTH; i++) {820 /* Choose color based on the current bit. */821 sp = (b & 0x80) ? fg_buf : bg_buf;822 823 /* Copy the pixel. */824 for (j = 0; j < screen.pixelbytes; j++) {825 *dp++ = *sp++;826 }827 828 /* Move to the next bit. */829 b = b << 1;830 }831 832 /* Move to the beginning of the next scanline of the cell. */833 dp += d_add;834 }835 }836 837 /** Draw glyph at specified position in viewport.838 *839 * @param vport Viewport identification840 * @param cursor Draw glyph with cursor841 * @param col Screen position relative to viewport842 * @param row Screen position relative to viewport843 *844 */845 static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,846 unsigned int row)847 {848 unsigned int x = vport->x + COL2X(col);849 unsigned int y = vport->y + ROW2Y(row);850 851 uint32_t glyph = vport->backbuf[BB_POS(vport, col, row)].glyph;852 uint32_t fg_color = vport->backbuf[BB_POS(vport, col, row)].fg_color;853 uint32_t bg_color = vport->backbuf[BB_POS(vport, col, row)].bg_color;854 855 (*vport->dglyph)(x, y, cursor, screen.glyphs, glyph,856 fg_color, bg_color);857 }858 859 /** Hide cursor if it is shown860 *861 */862 static void cursor_hide(viewport_t *vport)863 {864 if ((vport->cursor_active) && (vport->cursor_shown)) {865 draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);866 vport->cursor_shown = false;867 }868 }869 870 /** Show cursor if cursor showing is enabled871 *872 */873 static void cursor_show(viewport_t *vport)874 {875 /* Do not check for cursor_shown */876 if (vport->cursor_active) {877 draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);878 vport->cursor_shown = true;879 }880 }881 882 /** Invert cursor, if it is enabled883 *884 */885 static void cursor_blink(viewport_t *vport)886 {887 if (vport->cursor_shown)888 cursor_hide(vport);889 else890 cursor_show(vport);891 }892 893 /** Draw character at given position relative to viewport894 *895 * @param vport Viewport identification896 * @param c Character to draw897 * @param col Screen position relative to viewport898 * @param row Screen position relative to viewport899 *900 */901 static void draw_char(viewport_t *vport, wchar_t c, unsigned int col, unsigned int row)902 {903 bb_cell_t *bbp;904 905 /* Do not hide cursor if we are going to overwrite it */906 if ((vport->cursor_active) && (vport->cursor_shown) &&907 ((vport->cur_col != col) || (vport->cur_row != row)))908 cursor_hide(vport);909 910 bbp = &vport->backbuf[BB_POS(vport, col, row)];911 bbp->glyph = fb_font_glyph(c);912 bbp->fg_color = vport->attr.fg_color;913 bbp->bg_color = vport->attr.bg_color;914 915 draw_vp_glyph(vport, false, col, row);916 917 vport->cur_col = col;918 vport->cur_row = row;919 920 vport->cur_col++;921 if (vport->cur_col >= vport->cols) {922 vport->cur_col = 0;923 vport->cur_row++;924 if (vport->cur_row >= vport->rows)925 vport->cur_row--;926 }927 928 cursor_show(vport);929 }930 931 /** Draw text data to viewport.932 *933 * @param vport Viewport id934 * @param data Text data.935 * @param x Leftmost column of the area.936 * @param y Topmost row of the area.937 * @param w Number of rows.938 * @param h Number of columns.939 *940 */941 static void draw_text_data(viewport_t *vport, keyfield_t *data, unsigned int x,942 unsigned int y, unsigned int w, unsigned int h)943 {944 unsigned int i;945 unsigned int j;946 bb_cell_t *bbp;947 attrs_t *a;948 949 for (j = 0; j < h; j++) {950 for (i = 0; i < w; i++) {951 unsigned int col = x + i;952 unsigned int row = y + j;953 954 bbp = &vport->backbuf[BB_POS(vport, col, row)];955 956 a = &data[j * w + i].attrs;957 958 attr_rgb_t rgb;959 rgb.fg_color = 0;960 rgb.bg_color = 0;961 rgb_from_attr(&rgb, a);962 963 bbp->glyph = fb_font_glyph(data[j * w + i].character);964 bbp->fg_color = rgb.fg_color;965 bbp->bg_color = rgb.bg_color;966 967 draw_vp_glyph(vport, false, col, row);968 }969 }970 cursor_show(vport);971 }972 973 static void putpixel(viewport_t *vport, unsigned int x, unsigned int y,974 uint32_t color)975 {976 unsigned int dx = vport->x + x;977 unsigned int dy = vport->y + y;978 979 screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);980 }981 982 /** Draw image map983 *984 * @param[in] img Image map.985 * @param[in] sx Coordinate of upper left corner.986 * @param[in] sy Coordinate of upper left corner.987 * @param[in] maxwidth Maximum allowed width for picture.988 * @param[in] maxheight Maximum allowed height for picture.989 * @param[in] vport Viewport.990 *991 * @return EOK on success.992 *993 */994 static int imgmap_draw(imgmap_t *img, unsigned int sx, unsigned int sy,995 unsigned int maxwidth, unsigned int maxheight, void *vport)996 {997 if (img->visual != VISUAL_BGR_8_8_8)998 return EINVAL;999 1000 uint8_t *data = (uint8_t *) img->data;1001 1002 for (sysarg_t y = 0; y < img->height; y++) {1003 for (sysarg_t x = 0; x < img->width; x++) {1004 if ((x > maxwidth) || (y > maxheight)) {1005 data += 3;1006 continue;1007 }1008 1009 uint32_t color = (data[2] << 16) + (data[1] << 8) + data[0];1010 1011 putpixel(vport, sx + x, sy + y, color);1012 data += 3;1013 }1014 }1015 1016 return EOK;1017 }1018 1019 /** Return first free image map1020 *1021 */1022 static int find_free_imgmap(void)1023 {1024 unsigned int i;1025 1026 for (i = 0; i < MAX_IMGMAPS; i++)1027 if (!imgmaps[i])1028 return i;1029 1030 return -1;1031 }1032 1033 /** Create a new image map and return appropriate ID1034 *1035 */1036 static int shm2imgmap(imgmap_t *shm, size_t size)1037 {1038 int im = find_free_imgmap();1039 if (im == -1)1040 return ELIMIT;1041 1042 imgmap_t *imap = malloc(size);1043 if (!imap)1044 return ENOMEM;1045 1046 memcpy(imap, shm, size);1047 imgmaps[im] = imap;1048 return im;1049 }1050 1051 /** Handle shared memory communication calls1052 *1053 * Protocol for drawing image maps:1054 * - FB_PREPARE_SHM(client shm identification)1055 * - IPC_M_AS_AREA_SEND1056 * - FB_DRAW_IMGMAP(startx, starty)1057 * - FB_DROP_SHM1058 *1059 * Protocol for text drawing1060 * - IPC_M_AS_AREA_SEND1061 * - FB_DRAW_TEXT_DATA1062 *1063 * @param callid Callid of the current call1064 * @param call Current call data1065 * @param vp Active viewport1066 *1067 * @return false if the call was not handled byt this function, true otherwise1068 *1069 * Note: this function is not thread-safe, you would have1070 * to redefine static variables with fibril_local.1071 *1072 */1073 static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)1074 {1075 static keyfield_t *interbuffer = NULL;1076 static size_t intersize = 0;1077 1078 static imgmap_t *shm = NULL;1079 static sysarg_t shm_id = 0;1080 static size_t shm_size;1081 1082 bool handled = true;1083 int retval = EOK;1084 viewport_t *vport = &viewports[vp];1085 unsigned int x;1086 unsigned int y;1087 unsigned int w;1088 unsigned int h;1089 1090 switch (IPC_GET_IMETHOD(*call)) {1091 case IPC_M_SHARE_OUT:1092 /* We accept one area for data interchange */1093 if (IPC_GET_ARG1(*call) == shm_id) {1094 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));1095 shm_size = IPC_GET_ARG2(*call);1096 if (async_answer_1(callid, EOK, (sysarg_t) dest)) {1097 shm_id = 0;1098 return false;1099 }1100 1101 shm = dest;1102 return true;1103 } else {1104 intersize = IPC_GET_ARG2(*call);1105 receive_comm_area(callid, call, (void *) &interbuffer);1106 }1107 return true;1108 case FB_PREPARE_SHM:1109 if (shm_id)1110 retval = EBUSY;1111 else1112 shm_id = IPC_GET_ARG1(*call);1113 break;1114 case FB_DROP_SHM:1115 if (shm) {1116 as_area_destroy(shm);1117 shm = NULL;1118 }1119 shm_id = 0;1120 break;1121 case FB_SHM2IMGMAP:1122 if (!shm) {1123 retval = EINVAL;1124 break;1125 }1126 retval = shm2imgmap(shm, shm_size);1127 break;1128 case FB_DRAW_IMGMAP:1129 if (!shm) {1130 retval = EINVAL;1131 break;1132 }1133 1134 x = IPC_GET_ARG1(*call);1135 y = IPC_GET_ARG2(*call);1136 1137 if ((x > vport->width) || (y > vport->height)) {1138 retval = EINVAL;1139 break;1140 }1141 1142 imgmap_draw(shm, IPC_GET_ARG1(*call), IPC_GET_ARG2(*call),1143 vport->width - x, vport->height - y, vport);1144 break;1145 case FB_DRAW_TEXT_DATA:1146 x = IPC_GET_ARG1(*call);1147 y = IPC_GET_ARG2(*call);1148 w = IPC_GET_ARG3(*call);1149 h = IPC_GET_ARG4(*call);1150 if (!interbuffer) {1151 retval = EINVAL;1152 break;1153 }1154 if (x + w > vport->cols || y + h > vport->rows) {1155 retval = EINVAL;1156 break;1157 }1158 if (intersize < w * h * sizeof(*interbuffer)) {1159 retval = EINVAL;1160 break;1161 }1162 draw_text_data(vport, interbuffer, x, y, w, h);1163 break;1164 default:1165 handled = false;1166 }1167 1168 if (handled)1169 async_answer_0(callid, retval);1170 1171 return handled;1172 }1173 1174 static void copy_vp_to_imgmap(viewport_t *vport, imgmap_t *imap)1175 {1176 unsigned int width = vport->width;1177 unsigned int height = vport->height;1178 1179 if (width + vport->x > screen.xres)1180 width = screen.xres - vport->x;1181 1182 if (height + vport->y > screen.yres)1183 height = screen.yres - vport->y;1184 1185 unsigned int realwidth = imap->width <= width ? imap->width : width;1186 unsigned int realheight = imap->height <= height ? imap->height : height;1187 1188 unsigned int srcrowsize = vport->width * screen.pixelbytes;1189 unsigned int realrowsize = realwidth * screen.pixelbytes;1190 1191 unsigned int y;1192 for (y = 0; y < realheight; y++) {1193 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;1194 memcpy(imap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);1195 }1196 }1197 1198 /** Save viewport to image map1199 *1200 */1201 static int save_vp_to_imgmap(viewport_t *vport)1202 {1203 int im = find_free_imgmap();1204 if (im == -1)1205 return ELIMIT;1206 1207 size_t size = screen.pixelbytes * vport->width * vport->height;1208 imgmap_t *imap = malloc(sizeof(imgmap_t) + size);1209 if (!imap)1210 return ENOMEM;1211 1212 imap->size = sizeof(imgmap_t) + size;1213 imap->width = vport->width;1214 imap->height = vport->height;1215 imap->visual = (visual_t) -1;1216 1217 copy_vp_to_imgmap(vport, imap);1218 imgmaps[im] = imap;1219 return im;1220 }1221 1222 /** Draw image map to screen1223 *1224 * @param vp Viewport to draw to1225 * @param im Image map identifier1226 *1227 */1228 static int draw_imgmap(int vp, int im)1229 {1230 imgmap_t *imap = imgmaps[im];1231 if (!imap)1232 return EINVAL;1233 1234 viewport_t *vport = &viewports[vp];1235 1236 unsigned int width = vport->width;1237 unsigned int height = vport->height;1238 1239 if (width + vport->x > screen.xres)1240 width = screen.xres - vport->x;1241 1242 if (height + vport->y > screen.yres)1243 height = screen.yres - vport->y;1244 1245 unsigned int realwidth = imap->width <= width ? imap->width : width;1246 unsigned int realheight = imap->height <= height ? imap->height : height;1247 1248 if (imap->visual == (visual_t) -1) {1249 unsigned int srcrowsize = vport->width * screen.pixelbytes;1250 unsigned int realrowsize = realwidth * screen.pixelbytes;1251 1252 unsigned int y;1253 for (y = 0; y < realheight; y++) {1254 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;1255 memcpy(screen.fb_addr + tmp, imap->data + y * srcrowsize, realrowsize);1256 }1257 } else1258 imgmap_draw(imap, 0, 0, realwidth, realheight, vport);1259 1260 return EOK;1261 }1262 1263 /** Tick animation one step forward1264 *1265 */1266 static void anims_tick(void)1267 {1268 unsigned int i;1269 static int counts = 0;1270 1271 /* Limit redrawing */1272 counts = (counts + 1) % 8;1273 if (counts)1274 return;1275 1276 for (i = 0; i < MAX_ANIMATIONS; i++) {1277 if ((!animations[i].animlen) || (!animations[i].initialized) ||1278 (!animations[i].enabled))1279 continue;1280 1281 draw_imgmap(animations[i].vp, animations[i].imgmaps[animations[i].pos]);1282 animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;1283 }1284 }1285 1286 1287 static unsigned int pointer_x;1288 static unsigned int pointer_y;1289 static bool pointer_shown, pointer_enabled;1290 static int pointer_vport = -1;1291 static int pointer_imgmap = -1;1292 1293 1294 static void mouse_show(void)1295 {1296 int i, j;1297 int visibility;1298 int color;1299 int bytepos;1300 1301 if ((pointer_shown) || (!pointer_enabled))1302 return;1303 1304 /* Save image under the pointer. */1305 if (pointer_vport == -1) {1306 pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);1307 if (pointer_vport < 0)1308 return;1309 } else {1310 viewports[pointer_vport].x = pointer_x;1311 viewports[pointer_vport].y = pointer_y;1312 }1313 1314 if (pointer_imgmap == -1)1315 pointer_imgmap = save_vp_to_imgmap(&viewports[pointer_vport]);1316 else1317 copy_vp_to_imgmap(&viewports[pointer_vport], imgmaps[pointer_imgmap]);1318 1319 /* Draw mouse pointer. */1320 for (i = 0; i < pointer_height; i++)1321 for (j = 0; j < pointer_width; j++) {1322 bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;1323 visibility = pointer_mask_bits[bytepos] &1324 (1 << (j % 8));1325 if (visibility) {1326 color = pointer_bits[bytepos] &1327 (1 << (j % 8)) ? 0 : 0xffffff;1328 if (pointer_x + j < screen.xres && pointer_y +1329 i < screen.yres)1330 putpixel(&viewports[0], pointer_x + j,1331 pointer_y + i, color);1332 }1333 }1334 pointer_shown = 1;1335 }1336 1337 1338 static void mouse_hide(void)1339 {1340 /* Restore image under the pointer. */1341 if (pointer_shown) {1342 draw_imgmap(pointer_vport, pointer_imgmap);1343 pointer_shown = 0;1344 }1345 }1346 1347 1348 static void mouse_move(unsigned int x, unsigned int y)1349 {1350 mouse_hide();1351 pointer_x = x % screen.xres;1352 pointer_y = y % screen.yres;1353 mouse_show();1354 }1355 1356 1357 static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)1358 {1359 bool handled = true;1360 int retval = EOK;1361 int i, nvp;1362 int newval;1363 1364 switch (IPC_GET_IMETHOD(*call)) {1365 case FB_ANIM_CREATE:1366 nvp = IPC_GET_ARG1(*call);1367 if (nvp == -1)1368 nvp = vp;1369 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||1370 !viewports[nvp].initialized) {1371 retval = EINVAL;1372 break;1373 }1374 for (i = 0; i < MAX_ANIMATIONS; i++) {1375 if (!animations[i].initialized)1376 break;1377 }1378 if (i == MAX_ANIMATIONS) {1379 retval = ELIMIT;1380 break;1381 }1382 animations[i].initialized = 1;1383 animations[i].animlen = 0;1384 animations[i].pos = 0;1385 animations[i].enabled = 0;1386 animations[i].vp = nvp;1387 retval = i;1388 break;1389 case FB_ANIM_DROP:1390 i = IPC_GET_ARG1(*call);1391 if (i >= MAX_ANIMATIONS || i < 0) {1392 retval = EINVAL;1393 break;1394 }1395 animations[i].initialized = 0;1396 break;1397 case FB_ANIM_ADDIMGMAP:1398 i = IPC_GET_ARG1(*call);1399 if (i >= MAX_ANIMATIONS || i < 0 ||1400 !animations[i].initialized) {1401 retval = EINVAL;1402 break;1403 }1404 if (animations[i].animlen == MAX_ANIM_LEN) {1405 retval = ELIMIT;1406 break;1407 }1408 newval = IPC_GET_ARG2(*call);1409 if (newval < 0 || newval > MAX_IMGMAPS ||1410 !imgmaps[newval]) {1411 retval = EINVAL;1412 break;1413 }1414 animations[i].imgmaps[animations[i].animlen++] = newval;1415 break;1416 case FB_ANIM_CHGVP:1417 i = IPC_GET_ARG1(*call);1418 if (i >= MAX_ANIMATIONS || i < 0) {1419 retval = EINVAL;1420 break;1421 }1422 nvp = IPC_GET_ARG2(*call);1423 if (nvp == -1)1424 nvp = vp;1425 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||1426 !viewports[nvp].initialized) {1427 retval = EINVAL;1428 break;1429 }1430 animations[i].vp = nvp;1431 break;1432 case FB_ANIM_START:1433 case FB_ANIM_STOP:1434 i = IPC_GET_ARG1(*call);1435 if (i >= MAX_ANIMATIONS || i < 0) {1436 retval = EINVAL;1437 break;1438 }1439 newval = (IPC_GET_IMETHOD(*call) == FB_ANIM_START);1440 if (newval ^ animations[i].enabled) {1441 animations[i].enabled = newval;1442 anims_enabled += newval ? 1 : -1;1443 }1444 break;1445 default:1446 handled = 0;1447 }1448 if (handled)1449 async_answer_0(callid, retval);1450 return handled;1451 }1452 1453 /** Handler for messages concerning image map handling1454 *1455 */1456 static int imgmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)1457 {1458 bool handled = true;1459 int retval = EOK;1460 int i, nvp;1461 1462 switch (IPC_GET_IMETHOD(*call)) {1463 case FB_VP_DRAW_IMGMAP:1464 nvp = IPC_GET_ARG1(*call);1465 if (nvp == -1)1466 nvp = vp;1467 1468 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||1469 !viewports[nvp].initialized) {1470 retval = EINVAL;1471 break;1472 }1473 1474 i = IPC_GET_ARG2(*call);1475 retval = draw_imgmap(nvp, i);1476 break;1477 case FB_VP2IMGMAP:1478 nvp = IPC_GET_ARG1(*call);1479 if (nvp == -1)1480 nvp = vp;1481 1482 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||1483 !viewports[nvp].initialized) {1484 retval = EINVAL;1485 break;1486 }1487 1488 retval = save_vp_to_imgmap(&viewports[nvp]);1489 break;1490 case FB_DROP_IMGMAP:1491 i = IPC_GET_ARG1(*call);1492 if (i >= MAX_IMGMAPS) {1493 retval = EINVAL;1494 break;1495 }1496 1497 if (imgmaps[i]) {1498 free(imgmaps[i]);1499 imgmaps[i] = NULL;1500 }1501 1502 break;1503 default:1504 handled = 0;1505 }1506 1507 if (handled)1508 async_answer_0(callid, retval);1509 return handled;1510 1511 }1512 1513 static int rgb_from_style(attr_rgb_t *rgb, int style)1514 {1515 switch (style) {1516 case STYLE_NORMAL:1517 rgb->fg_color = color_table[COLOR_BLACK];1518 rgb->bg_color = color_table[COLOR_WHITE];1519 break;1520 case STYLE_EMPHASIS:1521 rgb->fg_color = color_table[COLOR_RED];1522 rgb->bg_color = color_table[COLOR_WHITE];1523 break;1524 case STYLE_INVERTED:1525 rgb->fg_color = color_table[COLOR_WHITE];1526 rgb->bg_color = color_table[COLOR_BLACK];1527 break;1528 case STYLE_SELECTED:1529 rgb->fg_color = color_table[COLOR_WHITE];1530 rgb->bg_color = color_table[COLOR_RED];1531 break;1532 default:1533 return EINVAL;1534 }1535 1536 return EOK;1537 }1538 1539 static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color,1540 sysarg_t bg_color, sysarg_t flags)1541 {1542 fg_color = (fg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);1543 bg_color = (bg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);1544 1545 rgb->fg_color = color_table[fg_color];1546 rgb->bg_color = color_table[bg_color];1547 1548 return EOK;1549 }1550 1551 static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a)1552 {1553 int rc;1554 1555 switch (a->t) {1556 case at_style:1557 rc = rgb_from_style(rgb, a->a.s.style);1558 break;1559 case at_idx:1560 rc = rgb_from_idx(rgb, a->a.i.fg_color,1561 a->a.i.bg_color, a->a.i.flags);1562 break;1563 case at_rgb:1564 *rgb = a->a.r;1565 rc = EOK;1566 break;1567 }1568 1569 return rc;1570 }1571 1572 static int fb_set_style(viewport_t *vport, sysarg_t style)1573 {1574 return rgb_from_style(&vport->attr, (int) style);1575 }1576 1577 static int fb_set_color(viewport_t *vport, sysarg_t fg_color,1578 sysarg_t bg_color, sysarg_t flags)1579 {1580 return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);1581 }1582 1583 /** Function for handling connections to FB1584 *1585 */1586 static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall,1587 void *arg)1588 {1589 unsigned int vp = 0;1590 viewport_t *vport = &viewports[vp];1591 1592 if (client_connected) {1593 async_answer_0(iid, ELIMIT);1594 return;1595 }1596 1597 /* Accept connection */1598 client_connected = true;1599 async_answer_0(iid, EOK);1600 1601 while (true) {1602 ipc_callid_t callid;1603 ipc_call_t call;1604 int retval;1605 unsigned int i;1606 int scroll;1607 wchar_t ch;1608 unsigned int col, row;1609 1610 if ((vport->cursor_active) || (anims_enabled))1611 callid = async_get_call_timeout(&call, 250000);1612 else1613 callid = async_get_call(&call);1614 1615 mouse_hide();1616 if (!callid) {1617 cursor_blink(vport);1618 anims_tick();1619 mouse_show();1620 continue;1621 }1622 1623 if (shm_handle(callid, &call, vp))1624 continue;1625 1626 if (imgmap_handle(callid, &call, vp))1627 continue;1628 1629 if (anim_handle(callid, &call, vp))1630 continue;1631 1632 if (!IPC_GET_IMETHOD(call)) {1633 client_connected = false;1634 1635 /* Cleanup other viewports */1636 for (i = 1; i < MAX_VIEWPORTS; i++)1637 vport->initialized = false;1638 1639 /* Exit thread */1640 return;1641 872 } 1642 873 1643 874 switch (IPC_GET_IMETHOD(call)) { 1644 case FB_PUTCHAR: 1645 ch = IPC_GET_ARG1(call); 1646 col = IPC_GET_ARG2(call); 1647 row = IPC_GET_ARG3(call); 1648 1649 if ((col >= vport->cols) || (row >= vport->rows)) { 1650 retval = EINVAL; 1651 break; 1652 } 1653 async_answer_0(callid, EOK); 1654 1655 draw_char(vport, ch, col, row); 1656 1657 /* Message already answered */ 1658 continue; 1659 case FB_CLEAR: 1660 vport_clear(vport); 1661 cursor_show(vport); 1662 retval = EOK; 1663 break; 1664 case FB_CURSOR_GOTO: 1665 col = IPC_GET_ARG1(call); 1666 row = IPC_GET_ARG2(call); 1667 1668 if ((col >= vport->cols) || (row >= vport->rows)) { 1669 retval = EINVAL; 1670 break; 1671 } 1672 retval = EOK; 1673 1674 cursor_hide(vport); 1675 vport->cur_col = col; 1676 vport->cur_row = row; 1677 cursor_show(vport); 1678 break; 1679 case FB_CURSOR_VISIBILITY: 1680 cursor_hide(vport); 1681 vport->cursor_active = IPC_GET_ARG1(call); 1682 cursor_show(vport); 1683 retval = EOK; 1684 break; 1685 case FB_GET_CSIZE: 1686 async_answer_2(callid, EOK, vport->cols, vport->rows); 1687 continue; 1688 case FB_GET_COLOR_CAP: 1689 async_answer_1(callid, EOK, FB_CCAP_RGB); 1690 continue; 1691 case FB_SCROLL: 1692 scroll = IPC_GET_ARG1(call); 1693 if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) { 1694 retval = EINVAL; 1695 break; 1696 } 1697 cursor_hide(vport); 1698 vport_scroll(vport, scroll); 1699 cursor_show(vport); 1700 retval = EOK; 1701 break; 1702 case FB_VIEWPORT_SWITCH: 1703 i = IPC_GET_ARG1(call); 1704 if (i >= MAX_VIEWPORTS) { 1705 retval = EINVAL; 1706 break; 1707 } 1708 if (!viewports[i].initialized) { 1709 retval = EADDRNOTAVAIL; 1710 break; 1711 } 1712 cursor_hide(vport); 1713 vp = i; 1714 vport = &viewports[vp]; 1715 cursor_show(vport); 1716 retval = EOK; 1717 break; 1718 case FB_VIEWPORT_CREATE: 1719 retval = vport_create(IPC_GET_ARG1(call) >> 16, 1720 IPC_GET_ARG1(call) & 0xffff, 1721 IPC_GET_ARG2(call) >> 16, 1722 IPC_GET_ARG2(call) & 0xffff); 1723 break; 1724 case FB_VIEWPORT_DELETE: 1725 i = IPC_GET_ARG1(call); 1726 if (i >= MAX_VIEWPORTS) { 1727 retval = EINVAL; 1728 break; 1729 } 1730 if (!viewports[i].initialized) { 1731 retval = EADDRNOTAVAIL; 1732 break; 1733 } 1734 viewports[i].initialized = false; 1735 if (viewports[i].bgpixel) 1736 free(viewports[i].bgpixel); 1737 if (viewports[i].backbuf) 1738 free(viewports[i].backbuf); 1739 retval = EOK; 1740 break; 1741 case FB_SET_STYLE: 1742 retval = fb_set_style(vport, IPC_GET_ARG1(call)); 1743 break; 1744 case FB_SET_COLOR: 1745 retval = fb_set_color(vport, IPC_GET_ARG1(call), 1746 IPC_GET_ARG2(call), IPC_GET_ARG3(call)); 1747 break; 1748 case FB_SET_RGB_COLOR: 1749 vport->attr.fg_color = IPC_GET_ARG1(call); 1750 vport->attr.bg_color = IPC_GET_ARG2(call); 1751 retval = EOK; 1752 break; 1753 case FB_GET_RESOLUTION: 1754 async_answer_2(callid, EOK, screen.xres, screen.yres); 1755 continue; 1756 case FB_POINTER_MOVE: 1757 pointer_enabled = true; 1758 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); 1759 retval = EOK; 1760 break; 1761 case FB_SCREEN_YIELD: 1762 case FB_SCREEN_RECLAIM: 1763 retval = EOK; 1764 break; 1765 default: 1766 retval = ENOENT; 1767 } 1768 async_answer_0(callid, retval); 1769 } 1770 } 1771 1772 /** Initialization of framebuffer 1773 * 1774 */ 1775 int fb_init(void) 1776 { 1777 async_set_client_connection(fb_client_connection); 1778 1779 sysarg_t fb_ph_addr; 1780 if (sysinfo_get_value("fb.address.physical", &fb_ph_addr) != EOK) 1781 return -1; 1782 1783 sysarg_t fb_offset; 1784 if (sysinfo_get_value("fb.offset", &fb_offset) != EOK) 1785 fb_offset = 0; 1786 1787 sysarg_t fb_width; 1788 if (sysinfo_get_value("fb.width", &fb_width) != EOK) 1789 return -1; 1790 1791 sysarg_t fb_height; 1792 if (sysinfo_get_value("fb.height", &fb_height) != EOK) 1793 return -1; 1794 1795 sysarg_t fb_scanline; 1796 if (sysinfo_get_value("fb.scanline", &fb_scanline) != EOK) 1797 return -1; 1798 1799 sysarg_t fb_visual; 1800 if (sysinfo_get_value("fb.visual", &fb_visual) != EOK) 1801 return -1; 1802 1803 sysarg_t fbsize = fb_scanline * fb_height; 1804 void *fb_addr = as_get_mappable_page(fbsize); 1805 1806 if (physmem_map((void *) fb_ph_addr + fb_offset, fb_addr, 1807 ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE) != 0) 1808 return -1; 1809 1810 if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual)) 1811 return 0; 1812 1813 return -1; 1814 } 1815 1816 /** 1817 * @} 1818 */ 875 876 /* Screen methods */ 877 878 case FB_GET_RESOLUTION: 879 fbsrv_get_resolution(dev, callid, &call); 880 break; 881 case FB_YIELD: 882 fbsrv_yield(dev, callid, &call); 883 break; 884 case FB_CLAIM: 885 fbsrv_claim(dev, callid, &call); 886 break; 887 case FB_POINTER_UPDATE: 888 fbsrv_pointer_update(dev, callid, &call); 889 break; 890 891 /* Object methods */ 892 893 case FB_VP_CREATE: 894 fbsrv_vp_create(dev, callid, &call); 895 break; 896 case FB_VP_DESTROY: 897 fbsrv_vp_destroy(dev, callid, &call); 898 break; 899 case FB_FRONTBUF_CREATE: 900 fbsrv_frontbuf_create(dev, callid, &call); 901 break; 902 case FB_FRONTBUF_DESTROY: 903 fbsrv_frontbuf_destroy(dev, callid, &call); 904 break; 905 case FB_IMAGEMAP_CREATE: 906 fbsrv_imagemap_create(dev, callid, &call); 907 break; 908 case FB_IMAGEMAP_DESTROY: 909 fbsrv_imagemap_destroy(dev, callid, &call); 910 break; 911 case FB_SEQUENCE_CREATE: 912 fbsrv_sequence_create(dev, callid, &call); 913 break; 914 case FB_SEQUENCE_DESTROY: 915 fbsrv_sequence_destroy(dev, callid, &call); 916 break; 917 case FB_SEQUENCE_ADD_IMAGEMAP: 918 fbsrv_sequence_add_imagemap(dev, callid, &call); 919 break; 920 921 /* Viewport stateful methods */ 922 923 case FB_VP_FOCUS: 924 fbsrv_vp_focus(dev, callid, &call); 925 break; 926 case FB_VP_CLEAR: 927 fbsrv_vp_clear(dev, callid, &call); 928 break; 929 case FB_VP_GET_DIMENSIONS: 930 fbsrv_vp_get_dimensions(dev, callid, &call); 931 break; 932 case FB_VP_GET_CAPS: 933 fbsrv_vp_get_caps(dev, callid, &call); 934 break; 935 936 /* Style methods (viewport specific) */ 937 938 case FB_VP_CURSOR_UPDATE: 939 fbsrv_vp_cursor_update(dev, callid, &call); 940 break; 941 case FB_VP_SET_STYLE: 942 fbsrv_vp_set_style(dev, callid, &call); 943 break; 944 case FB_VP_SET_COLOR: 945 fbsrv_vp_set_color(dev, callid, &call); 946 break; 947 case FB_VP_SET_RGB_COLOR: 948 fbsrv_vp_set_rgb_color(dev, callid, &call); 949 break; 950 951 /* Text output methods (viewport specific) */ 952 953 case FB_VP_PUTCHAR: 954 fbsrv_vp_putchar(dev, callid, &call); 955 break; 956 case FB_VP_UPDATE: 957 fbsrv_vp_update(dev, callid, &call); 958 break; 959 case FB_VP_DAMAGE: 960 fbsrv_vp_damage(dev, callid, &call); 961 break; 962 963 /* Image map methods (viewport specific) */ 964 965 case FB_VP_IMAGEMAP_DAMAGE: 966 fbsrv_vp_imagemap_damage(dev, callid, &call); 967 break; 968 969 /* Sequence methods (viewport specific) */ 970 971 case FB_VP_SEQUENCE_START: 972 fbsrv_vp_sequence_start(dev, callid, &call); 973 break; 974 case FB_VP_SEQUENCE_STOP: 975 fbsrv_vp_sequence_stop(dev, callid, &call); 976 break; 977 978 default: 979 async_answer_0(callid, EINVAL); 980 } 981 } 982 } 983 984 int main(int argc, char *argv[]) 985 { 986 printf("%s: HelenOS framebuffer service\n", NAME); 987 988 /* Register server */ 989 async_set_client_connection(client_connection); 990 int rc = loc_server_register(NAME); 991 if (rc != EOK) { 992 printf("%s: Unable to register driver (%d)\n", NAME, rc); 993 return 1; 994 } 995 996 ega_init(); 997 kchar_init(); 998 kfb_init(); 999 niagara_init(); 1000 ski_init(); 1001 1002 printf("%s: Accepting connections\n", NAME); 1003 task_retval(0); 1004 async_manager(); 1005 1006 /* Never reached */ 1007 return 0; 1008 }
Note:
See TracChangeset
for help on using the changeset viewer.