source: mainline/uspace/srv/hid/fb/fb.c@ 9ba10f0

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

use symbolic values for address space constants

  • 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
[fbcdeb8]306 int rc = async_share_out_finalize(callid, &frontbuf->data);
[faba839]307 if ((rc != EOK) || (frontbuf->data == AS_MAP_FAILED)) {
[7c014d1]308 free(frontbuf);
309 async_answer_0(iid, ENOMEM);
310 return;
311 }
[ab1861a]312
[7c014d1]313 list_append(&frontbuf->link, &dev->frontbufs);
314 async_answer_1(iid, EOK, (sysarg_t) frontbuf);
315}
316
317static 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;
[ab1861a]322
[7c014d1]323 list_remove(&frontbuf->link);
324 as_area_destroy(frontbuf->data);
325 free(frontbuf);
[ab1861a]326
[7c014d1]327 async_answer_0(iid, EOK);
[68a4442]328}
329
[7c014d1]330static void fbsrv_imagemap_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[68a4442]331{
[7c014d1]332 imagemap_t *imagemap = (imagemap_t *) malloc(sizeof(imagemap_t));
333 if (imagemap == NULL) {
334 async_answer_0(iid, ENOMEM);
335 return;
[68a4442]336 }
[ab1861a]337
[7c014d1]338 link_initialize(&imagemap->link);
339 link_initialize(&imagemap->seq_link);
[ab1861a]340
[7c014d1]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 }
[ab1861a]348
[fbcdeb8]349 int rc = async_share_out_finalize(callid, &imagemap->data);
[faba839]350 if ((rc != EOK) || (imagemap->data == AS_MAP_FAILED)) {
[7c014d1]351 free(imagemap);
352 async_answer_0(iid, ENOMEM);
353 return;
[68a4442]354 }
[7c014d1]355
356 list_append(&imagemap->link, &dev->imagemaps);
357 async_answer_1(iid, EOK, (sysarg_t) imagemap);
[67c6c651]358}
359
[7c014d1]360static void fbsrv_imagemap_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]361{
[7c014d1]362 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid);
363 if (imagemap == NULL)
364 return;
[76fca31]365
[7c014d1]366 list_remove(&imagemap->link);
367 list_remove(&imagemap->seq_link);
368 as_area_destroy(imagemap->data);
369 free(imagemap);
[ab1861a]370
[7c014d1]371 async_answer_0(iid, EOK);
[49d072e]372}
373
[7c014d1]374static void fbsrv_sequence_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[49d072e]375{
[7c014d1]376 sequence_t *sequence = (sequence_t *) malloc(sizeof(sequence_t));
377 if (sequence == NULL) {
378 async_answer_0(iid, ENOMEM);
379 return;
[49d072e]380 }
[7c014d1]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);
[49d072e]388}
389
[7c014d1]390static void fbsrv_sequence_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[49d072e]391{
[7c014d1]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);
[49d072e]400}
401
[7c014d1]402static void fbsrv_sequence_add_imagemap(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[88c3151]403{
[7c014d1]404 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid);
405 if (sequence == NULL)
406 return;
[ab1861a]407
[7c014d1]408 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG2(*icall), iid);
409 if (imagemap == NULL)
410 return;
[ab1861a]411
[7c014d1]412 if (list_member(&imagemap->seq_link, &sequence->imagemaps)) {
413 async_answer_0(iid, EEXISTS);
414 return;
415 }
[ab1861a]416
[7c014d1]417 list_append(&imagemap->seq_link, &sequence->imagemaps);
418 sequence->count++;
[88c3151]419
[7c014d1]420 async_answer_0(iid, EOK);
421}
422
423static 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;
[76fca31]428
[7c014d1]429 if (dev->active_vp != vp)
430 dev->active_vp = vp;
[76fca31]431
[7c014d1]432 async_answer_0(iid, EOK);
[88c3151]433}
434
[7c014d1]435static void fbsrv_vp_clear(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[83b1d61]436{
[7c014d1]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);
[83b1d61]445}
446
[7c014d1]447static void fbsrv_vp_get_dimensions(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[a7d2d78]448{
[7c014d1]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);
[76fca31]453}
454
[7c014d1]455static void fbsrv_vp_get_caps(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[c6f08726]456{
[7c014d1]457 assert(dev->ops.vp_get_caps);
[c6f08726]458
[7c014d1]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);
[c6f08726]464}
[a7d2d78]465
[7c014d1]466static void fbsrv_vp_cursor_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]467{
[7c014d1]468 assert(dev->ops.vp_cursor_update);
[76fca31]469
[7c014d1]470 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid);
471 if (frontbuf == NULL)
472 return;
[76fca31]473
[7c014d1]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);
[a7d2d78]498}
499
[7c014d1]500static void fbsrv_vp_cursor_flash(fbdev_t *dev)
[a7d2d78]501{
[7c014d1]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 }
[a7d2d78]516}
517
[7c014d1]518static void fbsrv_sequences_update(fbdev_t *dev)
[90f5d64]519{
[7c014d1]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);
[76fca31]523
[7c014d1]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 }
[90f5d64]547 }
548 }
549}
[83b1d61]550
[7c014d1]551static void fbsrv_vp_set_style(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]552{
[7c014d1]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);
[2ce520c]560}
561
[7c014d1]562static void fbsrv_vp_set_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[2ce520c]563{
[7c014d1]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);
[429acb9]575}
576
[7c014d1]577static void fbsrv_vp_set_rgb_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[429acb9]578{
[7c014d1]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);
[c6f08726]584 } else
[7c014d1]585 async_answer_0(iid, ENOENT);
[429acb9]586}
587
[7c014d1]588static void fbsrv_vp_putchar(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[1fd7700]589{
[7c014d1]590 assert(dev->ops.vp_char_update);
[1fd7700]591
[7c014d1]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));
[76fca31]595
[7c014d1]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);
[1fd7700]603}
604
[7c014d1]605static bool fbsrv_vp_update_scroll(fbdev_t *dev, fbvp_t *vp,
606 screenbuffer_t *frontbuf)
[2ce520c]607{
[7c014d1]608 assert(dev->ops.vp_char_update);
[76fca31]609
[7c014d1]610 sysarg_t top_row = screenbuffer_get_top_row(frontbuf);
[76fca31]611
[7c014d1]612 if (vp->top_row == top_row)
613 return false;
[76fca31]614
[7c014d1]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;
[2ce520c]633 }
[7c014d1]634
635 front_field->flags &= ~CHAR_FLAG_DIRTY;
636
637 if (update)
638 dev->ops.vp_char_update(dev, vp, x, y);
[2ce520c]639 }
640 }
[7c014d1]641
642 return true;
[2ce520c]643}
644
[7c014d1]645static void fbsrv_vp_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[1fd7700]646{
[7c014d1]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;
[1fd7700]660 }
[7c014d1]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 }
[1fd7700]687 }
[7c014d1]688
689 async_answer_0(iid, EOK);
690 } else
691 async_answer_0(iid, ENOENT);
[1fd7700]692}
693
[7c014d1]694static void fbsrv_vp_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[76fca31]695{
[7c014d1]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;
[c6f08726]705
[7c014d1]706 if (fbsrv_vp_update_scroll(dev, vp, screenbuf)) {
707 async_answer_0(iid, EOK);
708 return;
[429acb9]709 }
[c6f08726]710
[7c014d1]711 sysarg_t col = IPC_GET_ARG2(*icall);
712 sysarg_t row = IPC_GET_ARG3(*icall);
[c6f08726]713
[7c014d1]714 sysarg_t cols = IPC_GET_ARG4(*icall);
715 sysarg_t rows = IPC_GET_ARG5(*icall);
[c6f08726]716
[7c014d1]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 }
[429acb9]740 }
[c6f08726]741
[7c014d1]742 async_answer_0(iid, EOK);
743 } else
744 async_answer_0(iid, ENOENT);
[429acb9]745}
746
[7c014d1]747static void fbsrv_vp_imagemap_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[9805cde]748{
[7c014d1]749 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid);
750 if (imagemap == NULL)
751 return;
[9f1362d4]752
[7c014d1]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);
[4a62ec9]764}
765
[7c014d1]766static void fbsrv_vp_sequence_start(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[9805cde]767{
[7c014d1]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);
[9805cde]798}
799
[7c014d1]800static void fbsrv_vp_sequence_stop(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
[9805cde]801{
[7c014d1]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);
[9805cde]823}
824
[7c014d1]825static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[a2ae4f4]826{
[7c014d1]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 }
[76fca31]837
[7c014d1]838 if (dev == NULL) {
839 async_answer_0(iid, ENOENT);
840 return;
841 }
842
843 if (atomic_get(&dev->refcnt) > 0) {
[ffa2c8ef]844 async_answer_0(iid, ELIMIT);
[a2ae4f4]845 return;
846 }
[76fca31]847
[7c014d1]848 /*
849 * Accept the connection
850 */
851
852 atomic_inc(&dev->refcnt);
853 dev->claimed = true;
[ffa2c8ef]854 async_answer_0(iid, EOK);
[76fca31]855
856 while (true) {
857 ipc_call_t call;
[7c014d1]858 ipc_callid_t callid =
859 async_get_call_timeout(&call, TICK_INTERVAL);
[76fca31]860
[49d072e]861 if (!callid) {
[7c014d1]862 fbsrv_vp_cursor_flash(dev);
863 fbsrv_sequences_update(dev);
[49d072e]864 continue;
865 }
[76fca31]866
[79ae36dd]867 if (!IPC_GET_IMETHOD(call)) {
[7c014d1]868 dev->claimed = false;
869 atomic_dec(&dev->refcnt);
870 async_answer_0(callid, EOK);
871 break;
[79ae36dd]872 }
[76fca31]873
[79ae36dd]874 switch (IPC_GET_IMETHOD(call)) {
[76fca31]875
[7c014d1]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);
[a2ae4f4]889 break;
[76fca31]890
[7c014d1]891 /* Object methods */
[76fca31]892
[7c014d1]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;
[76fca31]920
[7c014d1]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);
[88c3151]934 break;
[76fca31]935
[7c014d1]936 /* Style methods (viewport specific) */
937
938 case FB_VP_CURSOR_UPDATE:
939 fbsrv_vp_cursor_update(dev, callid, &call);
[88c3151]940 break;
[7c014d1]941 case FB_VP_SET_STYLE:
942 fbsrv_vp_set_style(dev, callid, &call);
[88c3151]943 break;
[7c014d1]944 case FB_VP_SET_COLOR:
945 fbsrv_vp_set_color(dev, callid, &call);
[88c3151]946 break;
[7c014d1]947 case FB_VP_SET_RGB_COLOR:
948 fbsrv_vp_set_rgb_color(dev, callid, &call);
[88c3151]949 break;
[7c014d1]950
951 /* Text output methods (viewport specific) */
952
953 case FB_VP_PUTCHAR:
954 fbsrv_vp_putchar(dev, callid, &call);
[88c3151]955 break;
[7c014d1]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);
[a2ae4f4]980 }
981 }
[afa6e74]982}
983
[7c014d1]984int main(int argc, char *argv[])
[a2ae4f4]985{
[7c014d1]986 printf("%s: HelenOS framebuffer service\n", NAME);
[a2ae4f4]987
[7c014d1]988 /* Register server */
[f302586]989 async_set_client_connection(client_connection);
990 int rc = loc_server_register(NAME);
[7c014d1]991 if (rc != EOK) {
[a47f522]992 printf("%s: Unable to register driver\n", NAME);
993 return rc;
[7c014d1]994 }
[d9fae235]995
[7c014d1]996 ega_init();
997 kchar_init();
998 kfb_init();
999 niagara_init();
1000 ski_init();
[d9fae235]1001
[7c014d1]1002 printf("%s: Accepting connections\n", NAME);
1003 task_retval(0);
1004 async_manager();
[d9fae235]1005
[7c014d1]1006 /* Never reached */
1007 return 0;
[a2ae4f4]1008}
Note: See TracBrowser for help on using the repository browser.