source: mainline/uspace/srv/hid/fb/fb.c@ a68a94e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a68a94e was 7c014d1, checked in by Martin Decky <martin@…>, 14 years ago

console and framebuffer server rewrite

  • Property mode set to 100644
File size: 24.3 KB
RevLine 
[afa6e74]1/*
[7c014d1]2 * Copyright (c) 2011 Martin Decky
[afa6e74]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[7c014d1]29#include <sys/types.h>
[2bc137c2]30#include <bool.h>
[7c014d1]31#include <loc.h>
32#include <errno.h>
[7ece1fbe]33#include <stdio.h>
[7c014d1]34#include <malloc.h>
35#include <inttypes.h>
36#include <as.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"
[afa6e74]44#include "fb.h"
[2ce520c]45
[7c014d1]46#define NAME "fb"
47#define NAMESPACE "hid"
[79ae36dd]48
[7c014d1]49#define TICK_INTERVAL 250000
[afa6e74]50
[7c014d1]51static LIST_INITIALIZE(fbdevs);
[171f9a1]52
[7c014d1]53fbdev_t *fbdev_register(fbdev_ops_t *ops, void *data)
54{
55 sysarg_t index = 0;
[ab1861a]56
[7c014d1]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 }
[76fca31]64
[7c014d1]65 fbdev_t *dev = (fbdev_t *) malloc(sizeof(fbdev_t));
66 if (dev == NULL)
67 return NULL;
[76fca31]68
[7c014d1]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);
[76fca31]77
[7c014d1]78 dev->ops = *ops;
79 dev->data = data;
[ab1861a]80
[7c014d1]81 char node[LOC_NAME_MAXLEN + 1];
82 snprintf(node, LOC_NAME_MAXLEN, "%s/%s%" PRIun, NAMESPACE, NAME,
83 index);
[ab1861a]84
[7c014d1]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 }
[ab1861a]90
[7c014d1]91 list_append(&dev->link, &fbdevs);
92 return dev;
[afa6e74]93}
94
[7c014d1]95static void fbsrv_yield(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[30885b9]96{
[7c014d1]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);
[afa6e74]107}
108
[7c014d1]109static void fbsrv_claim(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[ab1861a]110{
[7c014d1]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);
[ab1861a]121}
122
[7c014d1]123static void fbsrv_get_resolution(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[afa6e74]124{
[7c014d1]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);
[afa6e74]132}
133
[7c014d1]134static void fbsrv_pointer_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[ab1861a]135{
[7c014d1]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);
[ab1861a]142}
143
[7c014d1]144static fbvp_t *resolve_vp(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid)
[2d32081]145{
[7c014d1]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 }
[d410328]153 }
[ab1861a]154
[7c014d1]155 if (vp == NULL) {
156 async_answer_0(iid, ENOENT);
157 return NULL;
[2d32081]158 }
[7c014d1]159
160 return vp;
[2d32081]161}
[afa6e74]162
[7c014d1]163static frontbuf_t *resolve_frontbuf(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid)
[a2ae4f4]164{
[7c014d1]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;
[76fca31]171 }
[e92aabf]172 }
[ab1861a]173
[7c014d1]174 if (frontbuf == NULL) {
175 async_answer_0(iid, ENOENT);
176 return NULL;
[e92aabf]177 }
[ab1861a]178
[7c014d1]179 return frontbuf;
[67ec84b]180}
181
[7c014d1]182static imagemap_t *resolve_imagemap(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid)
[9805cde]183{
[7c014d1]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 }
[ab1861a]192
[7c014d1]193 if (imagemap == NULL) {
194 async_answer_0(iid, ENOENT);
195 return NULL;
[9805cde]196 }
[7c014d1]197
198 return imagemap;
[9805cde]199}
[afa6e74]200
[7c014d1]201static sequence_t *resolve_sequence(fbdev_t *dev, sysarg_t handle, ipc_callid_t iid)
[e92aabf]202{
[7c014d1]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;
[67c6c651]209 }
210 }
[ab1861a]211
[7c014d1]212 if (sequence == NULL) {
213 async_answer_0(iid, ENOENT);
214 return NULL;
[76fca31]215 }
[ab1861a]216
[7c014d1]217 return sequence;
[afa6e74]218}
219
[7c014d1]220static void fbsrv_vp_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[afa6e74]221{
[7c014d1]222 assert(dev->ops.font_metrics);
223 assert(dev->ops.vp_create);
[ab1861a]224
[7c014d1]225 fbvp_t *vp = (fbvp_t *) malloc(sizeof(fbvp_t));
226 if (vp == NULL) {
227 async_answer_0(iid, ENOMEM);
228 return;
[76fca31]229 }
[ab1861a]230
[7c014d1]231 link_initialize(&vp->link);
[76fca31]232
[7c014d1]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);
[afa6e74]237
[7c014d1]238 dev->ops.font_metrics(dev, vp->width, vp->height, &vp->cols, &vp->rows);
[76fca31]239
[7c014d1]240 vp->cursor_active = false;
241 vp->cursor_flash = false;
[afa6e74]242
[7c014d1]243 list_initialize(&vp->sequences);
[ab1861a]244
[7c014d1]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;
[68a4442]251 }
[ab1861a]252
[7c014d1]253 vp->top_row = 0;
[76fca31]254
[7c014d1]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 }
[76fca31]261
[7c014d1]262 list_append(&vp->link, &dev->vps);
263 async_answer_1(iid, EOK, (sysarg_t) vp);
[afa6e74]264}
265
[7c014d1]266static void fbsrv_vp_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[afa6e74]267{
[7c014d1]268 assert(dev->ops.vp_destroy);
[76fca31]269
[7c014d1]270 fbvp_t *vp = resolve_vp(dev, IPC_GET_ARG1(*icall), iid);
271 if (vp == NULL)
272 return;
[4527fb5]273
[7c014d1]274 if (dev->active_vp == vp) {
275 async_answer_0(iid, EPERM);
276 return;
277 }
[ab1861a]278
[7c014d1]279 dev->ops.vp_destroy(dev, vp);
[afa6e74]280
[7c014d1]281 list_remove(&vp->link);
282 free(vp->backbuf);
283 free(vp);
[2bc137c2]284
[7c014d1]285 async_answer_0(iid, EOK);
[afa6e74]286}
287
[7c014d1]288static void fbsrv_frontbuf_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[67c6c651]289{
[7c014d1]290 frontbuf_t *frontbuf = (frontbuf_t *) malloc(sizeof(frontbuf_t));
291 if (frontbuf == NULL) {
292 async_answer_0(iid, ENOMEM);
293 return;
[68a4442]294 }
[ab1861a]295
[7c014d1]296 link_initialize(&frontbuf->link);
[ab1861a]297
[7c014d1]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 frontbuf->data = as_get_mappable_page(frontbuf->size);
307 int rc = async_answer_1(callid, EOK, (sysarg_t) frontbuf->data);
308 if (rc != EOK) {
309 free(frontbuf);
310 async_answer_0(iid, ENOMEM);
311 return;
312 }
[ab1861a]313
[7c014d1]314 list_append(&frontbuf->link, &dev->frontbufs);
315 async_answer_1(iid, EOK, (sysarg_t) frontbuf);
316}
317
318static void fbsrv_frontbuf_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
319{
320 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid);
321 if (frontbuf == NULL)
322 return;
[ab1861a]323
[7c014d1]324 list_remove(&frontbuf->link);
325 as_area_destroy(frontbuf->data);
326 free(frontbuf);
[ab1861a]327
[7c014d1]328 async_answer_0(iid, EOK);
[68a4442]329}
330
[7c014d1]331static void fbsrv_imagemap_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[68a4442]332{
[7c014d1]333 imagemap_t *imagemap = (imagemap_t *) malloc(sizeof(imagemap_t));
334 if (imagemap == NULL) {
335 async_answer_0(iid, ENOMEM);
336 return;
[68a4442]337 }
[ab1861a]338
[7c014d1]339 link_initialize(&imagemap->link);
340 link_initialize(&imagemap->seq_link);
[ab1861a]341
[7c014d1]342 ipc_callid_t callid;
343 if (!async_share_out_receive(&callid, &imagemap->size,
344 &imagemap->flags)) {
345 free(imagemap);
346 async_answer_0(iid, EINVAL);
347 return;
348 }
[ab1861a]349
[7c014d1]350 imagemap->data = as_get_mappable_page(imagemap->size);
351 int rc = async_answer_1(callid, EOK, (sysarg_t) imagemap->data);
352 if (rc != EOK) {
353 free(imagemap);
354 async_answer_0(iid, ENOMEM);
355 return;
[68a4442]356 }
[7c014d1]357
358 list_append(&imagemap->link, &dev->imagemaps);
359 async_answer_1(iid, EOK, (sysarg_t) imagemap);
[67c6c651]360}
361
[7c014d1]362static void fbsrv_imagemap_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]363{
[7c014d1]364 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid);
365 if (imagemap == NULL)
366 return;
[76fca31]367
[7c014d1]368 list_remove(&imagemap->link);
369 list_remove(&imagemap->seq_link);
370 as_area_destroy(imagemap->data);
371 free(imagemap);
[ab1861a]372
[7c014d1]373 async_answer_0(iid, EOK);
[49d072e]374}
375
[7c014d1]376static void fbsrv_sequence_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[49d072e]377{
[7c014d1]378 sequence_t *sequence = (sequence_t *) malloc(sizeof(sequence_t));
379 if (sequence == NULL) {
380 async_answer_0(iid, ENOMEM);
381 return;
[49d072e]382 }
[7c014d1]383
384 link_initialize(&sequence->link);
385 list_initialize(&sequence->imagemaps);
386 sequence->count = 0;
387
388 list_append(&sequence->link, &dev->sequences);
389 async_answer_1(iid, EOK, (sysarg_t) sequence);
[49d072e]390}
391
[7c014d1]392static void fbsrv_sequence_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[49d072e]393{
[7c014d1]394 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid);
395 if (sequence == NULL)
396 return;
397
398 list_remove(&sequence->link);
399 free(sequence);
400
401 async_answer_0(iid, EOK);
[49d072e]402}
403
[7c014d1]404static void fbsrv_sequence_add_imagemap(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[88c3151]405{
[7c014d1]406 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid);
407 if (sequence == NULL)
408 return;
[ab1861a]409
[7c014d1]410 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG2(*icall), iid);
411 if (imagemap == NULL)
412 return;
[ab1861a]413
[7c014d1]414 if (list_member(&imagemap->seq_link, &sequence->imagemaps)) {
415 async_answer_0(iid, EEXISTS);
416 return;
417 }
[ab1861a]418
[7c014d1]419 list_append(&imagemap->seq_link, &sequence->imagemaps);
420 sequence->count++;
[88c3151]421
[7c014d1]422 async_answer_0(iid, EOK);
423}
424
425static void fbsrv_vp_focus(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
426{
427 fbvp_t *vp = resolve_vp(dev, IPC_GET_ARG1(*icall), iid);
428 if (vp == NULL)
429 return;
[76fca31]430
[7c014d1]431 if (dev->active_vp != vp)
432 dev->active_vp = vp;
[76fca31]433
[7c014d1]434 async_answer_0(iid, EOK);
[88c3151]435}
436
[7c014d1]437static void fbsrv_vp_clear(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[83b1d61]438{
[7c014d1]439 assert(dev->ops.vp_clear);
440
441 if ((dev->claimed) && (dev->active_vp)) {
442 screenbuffer_set_cursor_visibility(dev->active_vp->backbuf, false);
443 dev->ops.vp_clear(dev, dev->active_vp);
444 async_answer_0(iid, EOK);
445 } else
446 async_answer_0(iid, ENOENT);
[83b1d61]447}
448
[7c014d1]449static void fbsrv_vp_get_dimensions(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[a7d2d78]450{
[7c014d1]451 if (dev->active_vp)
452 async_answer_2(iid, EOK, dev->active_vp->cols, dev->active_vp->rows);
453 else
454 async_answer_0(iid, ENOENT);
[76fca31]455}
456
[7c014d1]457static void fbsrv_vp_get_caps(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[c6f08726]458{
[7c014d1]459 assert(dev->ops.vp_get_caps);
[c6f08726]460
[7c014d1]461 if (dev->active_vp)
462 async_answer_1(iid, EOK,
463 (sysarg_t) dev->ops.vp_get_caps(dev, dev->active_vp));
464 else
465 async_answer_0(iid, ENOENT);
[c6f08726]466}
[a7d2d78]467
[7c014d1]468static void fbsrv_vp_cursor_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]469{
[7c014d1]470 assert(dev->ops.vp_cursor_update);
[76fca31]471
[7c014d1]472 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid);
473 if (frontbuf == NULL)
474 return;
[76fca31]475
[7c014d1]476 if ((dev->claimed) && (dev->active_vp)) {
477 screenbuffer_t *screenbuf = (screenbuffer_t *) frontbuf->data;
478
479 sysarg_t prev_col;
480 sysarg_t prev_row;
481 sysarg_t col;
482 sysarg_t row;
483
484 screenbuffer_get_cursor(dev->active_vp->backbuf,
485 &prev_col, &prev_row);
486 screenbuffer_get_cursor(screenbuf, &col, &row);
487 screenbuffer_set_cursor(dev->active_vp->backbuf, col, row);
488
489 bool visible = screenbuffer_get_cursor_visibility(screenbuf);
490 screenbuffer_set_cursor_visibility(dev->active_vp->backbuf, visible);
491
492 if (visible)
493 dev->active_vp->cursor_active = true;
494
495 dev->ops.vp_cursor_update(dev, dev->active_vp, prev_col, prev_row,
496 col, row, visible);
497 async_answer_0(iid, EOK);
498 } else
499 async_answer_0(iid, ENOENT);
[a7d2d78]500}
501
[7c014d1]502static void fbsrv_vp_cursor_flash(fbdev_t *dev)
[a7d2d78]503{
[7c014d1]504 if ((dev->claimed) && (dev->ops.vp_cursor_flash)) {
505 list_foreach (dev->vps, link) {
506 fbvp_t *vp = list_get_instance(link, fbvp_t, link);
507
508 if (vp->cursor_active) {
509 sysarg_t col;
510 sysarg_t row;
511
512 screenbuffer_get_cursor(vp->backbuf, &col, &row);
513 vp->cursor_flash = !vp->cursor_flash;
514 dev->ops.vp_cursor_flash(dev, vp, col, row);
515 }
516 }
517 }
[a7d2d78]518}
519
[7c014d1]520static void fbsrv_sequences_update(fbdev_t *dev)
[90f5d64]521{
[7c014d1]522 if ((dev->claimed) && (dev->ops.vp_imgmap_damage)) {
523 list_foreach (dev->vps, vp_link) {
524 fbvp_t *vp = list_get_instance(vp_link, fbvp_t, link);
[76fca31]525
[7c014d1]526 list_foreach (vp->sequences, seq_vp_link) {
527 sequence_vp_t *seq_vp =
528 list_get_instance(seq_vp_link, sequence_vp_t, link);
529
530 seq_vp->current++;
531 if (seq_vp->current >= seq_vp->seq->count)
532 seq_vp->current = 0;
533
534 link_t *link =
535 list_nth(&seq_vp->seq->imagemaps, seq_vp->current);
536 if (link != NULL) {
537 imagemap_t *imagemap =
538 list_get_instance(link, imagemap_t, seq_link);
539
540 imgmap_t *imgmap = (imgmap_t *) imagemap->data;
541 sysarg_t width;
542 sysarg_t height;
543
544 imgmap_get_resolution(imgmap, &width, &height);
545 dev->ops.vp_imgmap_damage(dev, vp, imgmap,
546 0, 0, width, height);
547 }
548 }
[90f5d64]549 }
550 }
551}
[83b1d61]552
[7c014d1]553static void fbsrv_vp_set_style(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]554{
[7c014d1]555 if (dev->active_vp) {
556 dev->active_vp->attrs.type = CHAR_ATTR_STYLE;
557 dev->active_vp->attrs.val.style =
558 (console_style_t) IPC_GET_ARG1(*icall);
559 async_answer_0(iid, EOK);
560 } else
561 async_answer_0(iid, ENOENT);
[2ce520c]562}
563
[7c014d1]564static void fbsrv_vp_set_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[2ce520c]565{
[7c014d1]566 if (dev->active_vp) {
567 dev->active_vp->attrs.type = CHAR_ATTR_INDEX;
568 dev->active_vp->attrs.val.index.bgcolor =
569 (console_color_t) IPC_GET_ARG1(*icall);
570 dev->active_vp->attrs.val.index.fgcolor =
571 (console_color_t) IPC_GET_ARG2(*icall);
572 dev->active_vp->attrs.val.index.attr =
573 (console_color_attr_t) IPC_GET_ARG3(*icall);
574 async_answer_0(iid, EOK);
575 } else
576 async_answer_0(iid, ENOENT);
[429acb9]577}
578
[7c014d1]579static void fbsrv_vp_set_rgb_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[429acb9]580{
[7c014d1]581 if (dev->active_vp) {
582 dev->active_vp->attrs.type = CHAR_ATTR_RGB;
583 dev->active_vp->attrs.val.rgb.bgcolor = IPC_GET_ARG1(*icall);
584 dev->active_vp->attrs.val.rgb.fgcolor = IPC_GET_ARG2(*icall);
585 async_answer_0(iid, EOK);
[c6f08726]586 } else
[7c014d1]587 async_answer_0(iid, ENOENT);
[429acb9]588}
589
[7c014d1]590static void fbsrv_vp_putchar(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[1fd7700]591{
[7c014d1]592 assert(dev->ops.vp_char_update);
[1fd7700]593
[7c014d1]594 if ((dev->claimed) && (dev->active_vp)) {
595 charfield_t *field = screenbuffer_field_at(dev->active_vp->backbuf,
596 IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
[76fca31]597
[7c014d1]598 field->ch = IPC_GET_ARG3(*icall);
599
600 dev->ops.vp_char_update(dev, dev->active_vp, IPC_GET_ARG1(*icall),
601 IPC_GET_ARG2(*icall));
602 async_answer_0(iid, EOK);
603 } else
604 async_answer_0(iid, ENOENT);
[1fd7700]605}
606
[7c014d1]607static bool fbsrv_vp_update_scroll(fbdev_t *dev, fbvp_t *vp,
608 screenbuffer_t *frontbuf)
[2ce520c]609{
[7c014d1]610 assert(dev->ops.vp_char_update);
[76fca31]611
[7c014d1]612 sysarg_t top_row = screenbuffer_get_top_row(frontbuf);
[76fca31]613
[7c014d1]614 if (vp->top_row == top_row)
615 return false;
[76fca31]616
[7c014d1]617 vp->top_row = top_row;
618
619 for (sysarg_t y = 0; y < vp->rows; y++) {
620 for (sysarg_t x = 0; x < vp->cols; x++) {
621 charfield_t *front_field =
622 screenbuffer_field_at(frontbuf, x, y);
623 charfield_t *back_field =
624 screenbuffer_field_at(vp->backbuf, x, y);
625 bool update = false;
626
627 if (front_field->ch != back_field->ch) {
628 back_field->ch = front_field->ch;
629 update = true;
630 }
631
632 if (!attrs_same(front_field->attrs, back_field->attrs)) {
633 back_field->attrs = front_field->attrs;
634 update = true;
[2ce520c]635 }
[7c014d1]636
637 front_field->flags &= ~CHAR_FLAG_DIRTY;
638
639 if (update)
640 dev->ops.vp_char_update(dev, vp, x, y);
[2ce520c]641 }
642 }
[7c014d1]643
644 return true;
[2ce520c]645}
646
[7c014d1]647static void fbsrv_vp_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[1fd7700]648{
[7c014d1]649 assert(dev->ops.vp_char_update);
650
651 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid);
652 if (frontbuf == NULL)
653 return;
654
655 if ((dev->claimed) && (dev->active_vp)) {
656 fbvp_t *vp = dev->active_vp;
657 screenbuffer_t *screenbuf = (screenbuffer_t *) frontbuf->data;
658
659 if (fbsrv_vp_update_scroll(dev, vp, screenbuf)) {
660 async_answer_0(iid, EOK);
661 return;
[1fd7700]662 }
[7c014d1]663
664 for (sysarg_t y = 0; y < vp->rows; y++) {
665 for (sysarg_t x = 0; x < vp->cols; x++) {
666 charfield_t *front_field =
667 screenbuffer_field_at(screenbuf, x, y);
668 charfield_t *back_field =
669 screenbuffer_field_at(vp->backbuf, x, y);
670 bool update = false;
671
672 if ((front_field->flags & CHAR_FLAG_DIRTY) == CHAR_FLAG_DIRTY) {
673 if (front_field->ch != back_field->ch) {
674 back_field->ch = front_field->ch;
675 update = true;
676 }
677
678 if (!attrs_same(front_field->attrs, back_field->attrs)) {
679 back_field->attrs = front_field->attrs;
680 update = true;
681 }
682
683 front_field->flags &= ~CHAR_FLAG_DIRTY;
684 }
685
686 if (update)
687 dev->ops.vp_char_update(dev, vp, x, y);
688 }
[1fd7700]689 }
[7c014d1]690
691 async_answer_0(iid, EOK);
692 } else
693 async_answer_0(iid, ENOENT);
[1fd7700]694}
695
[7c014d1]696static void fbsrv_vp_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]697{
[7c014d1]698 assert(dev->ops.vp_char_update);
699
700 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid);
701 if (frontbuf == NULL)
702 return;
703
704 if ((dev->claimed) && (dev->active_vp)) {
705 fbvp_t *vp = dev->active_vp;
706 screenbuffer_t *screenbuf = (screenbuffer_t *) frontbuf->data;
[c6f08726]707
[7c014d1]708 if (fbsrv_vp_update_scroll(dev, vp, screenbuf)) {
709 async_answer_0(iid, EOK);
710 return;
[429acb9]711 }
[c6f08726]712
[7c014d1]713 sysarg_t col = IPC_GET_ARG2(*icall);
714 sysarg_t row = IPC_GET_ARG3(*icall);
[c6f08726]715
[7c014d1]716 sysarg_t cols = IPC_GET_ARG4(*icall);
717 sysarg_t rows = IPC_GET_ARG5(*icall);
[c6f08726]718
[7c014d1]719 for (sysarg_t y = 0; y < rows; y++) {
720 for (sysarg_t x = 0; x < cols; x++) {
721 charfield_t *front_field =
722 screenbuffer_field_at(screenbuf, col + x, row + y);
723 charfield_t *back_field =
724 screenbuffer_field_at(vp->backbuf, col + x, row + y);
725 bool update = false;
726
727 if (front_field->ch != back_field->ch) {
728 back_field->ch = front_field->ch;
729 update = true;
730 }
731
732 if (!attrs_same(front_field->attrs, back_field->attrs)) {
733 back_field->attrs = front_field->attrs;
734 update = true;
735 }
736
737 front_field->flags &= ~CHAR_FLAG_DIRTY;
738
739 if (update)
740 dev->ops.vp_char_update(dev, vp, col + x, row + y);
741 }
[429acb9]742 }
[c6f08726]743
[7c014d1]744 async_answer_0(iid, EOK);
745 } else
746 async_answer_0(iid, ENOENT);
[429acb9]747}
748
[7c014d1]749static void fbsrv_vp_imagemap_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[9805cde]750{
[7c014d1]751 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid);
752 if (imagemap == NULL)
753 return;
[9f1362d4]754
[7c014d1]755 if ((dev->claimed) && (dev->ops.vp_imgmap_damage)) {
756 if (dev->active_vp) {
757 dev->ops.vp_imgmap_damage(dev, dev->active_vp,
758 (imgmap_t *) imagemap->data,
759 IPC_GET_ARG2(*icall), IPC_GET_ARG3(*icall),
760 IPC_GET_ARG4(*icall), IPC_GET_ARG5(*icall));
761 async_answer_0(iid, EOK);
762 } else
763 async_answer_0(iid, ENOENT);
764 } else
765 async_answer_0(iid, ENOTSUP);
[4a62ec9]766}
767
[7c014d1]768static void fbsrv_vp_sequence_start(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[9805cde]769{
[7c014d1]770 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid);
771 if (sequence == NULL)
772 return;
773
774 if (dev->active_vp) {
775 /* Check if the sequence is not already started */
776 list_foreach(dev->active_vp->sequences, link) {
777 sequence_vp_t *seq_vp =
778 list_get_instance(link, sequence_vp_t, link);
779
780 if (seq_vp->seq == sequence) {
781 async_answer_0(iid, EEXISTS);
782 return;
783 }
784 }
785
786 sequence_vp_t *seq_vp =
787 (sequence_vp_t *) malloc(sizeof(sequence_vp_t));
788
789 if (seq_vp != NULL) {
790 link_initialize(&seq_vp->link);
791 seq_vp->seq = sequence;
792 seq_vp->current = 0;
793
794 list_append(&seq_vp->link, &dev->active_vp->sequences);
795 async_answer_0(iid, EOK);
796 } else
797 async_answer_0(iid, ENOMEM);
798 } else
799 async_answer_0(iid, ENOENT);
[9805cde]800}
801
[7c014d1]802static void fbsrv_vp_sequence_stop(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[9805cde]803{
[7c014d1]804 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid);
805 if (sequence == NULL)
806 return;
807
808 if (dev->active_vp) {
809 list_foreach(dev->active_vp->sequences, link) {
810 sequence_vp_t *seq_vp =
811 list_get_instance(link, sequence_vp_t, link);
812
813 if (seq_vp->seq == sequence) {
814 list_remove(&seq_vp->link);
815 free(seq_vp);
816
817 async_answer_0(iid, EOK);
818 return;
819 }
820 }
821
822 async_answer_0(iid, ENOENT);
823 } else
824 async_answer_0(iid, ENOENT);
[9805cde]825}
826
[7c014d1]827static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[a2ae4f4]828{
[7c014d1]829 fbdev_t *dev = NULL;
830 service_id_t dsid = (service_id_t) IPC_GET_ARG1(*icall);
831
832 list_foreach(fbdevs, link) {
833 fbdev_t *fbdev = list_get_instance(link, fbdev_t, link);
834 if (fbdev->dsid == dsid) {
835 dev = fbdev;
836 break;
837 }
838 }
[76fca31]839
[7c014d1]840 if (dev == NULL) {
841 async_answer_0(iid, ENOENT);
842 return;
843 }
844
845 if (atomic_get(&dev->refcnt) > 0) {
[ffa2c8ef]846 async_answer_0(iid, ELIMIT);
[a2ae4f4]847 return;
848 }
[76fca31]849
[7c014d1]850 /*
851 * Accept the connection
852 */
853
854 atomic_inc(&dev->refcnt);
855 dev->claimed = true;
[ffa2c8ef]856 async_answer_0(iid, EOK);
[76fca31]857
858 while (true) {
859 ipc_call_t call;
[7c014d1]860 ipc_callid_t callid =
861 async_get_call_timeout(&call, TICK_INTERVAL);
[76fca31]862
[49d072e]863 if (!callid) {
[7c014d1]864 fbsrv_vp_cursor_flash(dev);
865 fbsrv_sequences_update(dev);
[49d072e]866 continue;
867 }
[76fca31]868
[79ae36dd]869 if (!IPC_GET_IMETHOD(call)) {
[7c014d1]870 dev->claimed = false;
871 atomic_dec(&dev->refcnt);
872 async_answer_0(callid, EOK);
873 break;
[79ae36dd]874 }
[76fca31]875
[79ae36dd]876 switch (IPC_GET_IMETHOD(call)) {
[76fca31]877
[7c014d1]878 /* Screen methods */
879
880 case FB_GET_RESOLUTION:
881 fbsrv_get_resolution(dev, callid, &call);
882 break;
883 case FB_YIELD:
884 fbsrv_yield(dev, callid, &call);
885 break;
886 case FB_CLAIM:
887 fbsrv_claim(dev, callid, &call);
888 break;
889 case FB_POINTER_UPDATE:
890 fbsrv_pointer_update(dev, callid, &call);
[a2ae4f4]891 break;
[76fca31]892
[7c014d1]893 /* Object methods */
[76fca31]894
[7c014d1]895 case FB_VP_CREATE:
896 fbsrv_vp_create(dev, callid, &call);
897 break;
898 case FB_VP_DESTROY:
899 fbsrv_vp_destroy(dev, callid, &call);
900 break;
901 case FB_FRONTBUF_CREATE:
902 fbsrv_frontbuf_create(dev, callid, &call);
903 break;
904 case FB_FRONTBUF_DESTROY:
905 fbsrv_frontbuf_destroy(dev, callid, &call);
906 break;
907 case FB_IMAGEMAP_CREATE:
908 fbsrv_imagemap_create(dev, callid, &call);
909 break;
910 case FB_IMAGEMAP_DESTROY:
911 fbsrv_imagemap_destroy(dev, callid, &call);
912 break;
913 case FB_SEQUENCE_CREATE:
914 fbsrv_sequence_create(dev, callid, &call);
915 break;
916 case FB_SEQUENCE_DESTROY:
917 fbsrv_sequence_destroy(dev, callid, &call);
918 break;
919 case FB_SEQUENCE_ADD_IMAGEMAP:
920 fbsrv_sequence_add_imagemap(dev, callid, &call);
921 break;
[76fca31]922
[7c014d1]923 /* Viewport stateful methods */
924
925 case FB_VP_FOCUS:
926 fbsrv_vp_focus(dev, callid, &call);
927 break;
928 case FB_VP_CLEAR:
929 fbsrv_vp_clear(dev, callid, &call);
930 break;
931 case FB_VP_GET_DIMENSIONS:
932 fbsrv_vp_get_dimensions(dev, callid, &call);
933 break;
934 case FB_VP_GET_CAPS:
935 fbsrv_vp_get_caps(dev, callid, &call);
[88c3151]936 break;
[76fca31]937
[7c014d1]938 /* Style methods (viewport specific) */
939
940 case FB_VP_CURSOR_UPDATE:
941 fbsrv_vp_cursor_update(dev, callid, &call);
[88c3151]942 break;
[7c014d1]943 case FB_VP_SET_STYLE:
944 fbsrv_vp_set_style(dev, callid, &call);
[88c3151]945 break;
[7c014d1]946 case FB_VP_SET_COLOR:
947 fbsrv_vp_set_color(dev, callid, &call);
[88c3151]948 break;
[7c014d1]949 case FB_VP_SET_RGB_COLOR:
950 fbsrv_vp_set_rgb_color(dev, callid, &call);
[88c3151]951 break;
[7c014d1]952
953 /* Text output methods (viewport specific) */
954
955 case FB_VP_PUTCHAR:
956 fbsrv_vp_putchar(dev, callid, &call);
[88c3151]957 break;
[7c014d1]958 case FB_VP_UPDATE:
959 fbsrv_vp_update(dev, callid, &call);
960 break;
961 case FB_VP_DAMAGE:
962 fbsrv_vp_damage(dev, callid, &call);
963 break;
964
965 /* Image map methods (viewport specific) */
966
967 case FB_VP_IMAGEMAP_DAMAGE:
968 fbsrv_vp_imagemap_damage(dev, callid, &call);
969 break;
970
971 /* Sequence methods (viewport specific) */
972
973 case FB_VP_SEQUENCE_START:
974 fbsrv_vp_sequence_start(dev, callid, &call);
975 break;
976 case FB_VP_SEQUENCE_STOP:
977 fbsrv_vp_sequence_stop(dev, callid, &call);
978 break;
979
980 default:
981 async_answer_0(callid, EINVAL);
[a2ae4f4]982 }
983 }
[afa6e74]984}
985
[7c014d1]986int main(int argc, char *argv[])
[a2ae4f4]987{
[7c014d1]988 printf("%s: HelenOS framebuffer service\n", NAME);
[a2ae4f4]989
[7c014d1]990 /* Register server */
991 int rc = loc_server_register(NAME, client_connection);
992 if (rc != EOK) {
993 printf("%s: Unable to register driver (%d)\n", NAME, rc);
994 return 1;
995 }
[d9fae235]996
[7c014d1]997 ega_init();
998 kchar_init();
999 kfb_init();
1000 niagara_init();
1001 ski_init();
[d9fae235]1002
[7c014d1]1003 printf("%s: Accepting connections\n", NAME);
1004 task_retval(0);
1005 async_manager();
[d9fae235]1006
[7c014d1]1007 /* Never reached */
1008 return 0;
[a2ae4f4]1009}
Note: See TracBrowser for help on using the repository browser.