source: mainline/uspace/srv/hid/fb/fb.c@ 99c2e9f3

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

Remove the two-phase way of creating virtual memory areas (first asking for a mappable address and then mapping it) which was prone to race conditions when two or more calls to as_get_mappable_page() and as_area_create() were interleaved. This for example caused the e1k driver to randomly fail.

The memory area related syscalls and IPC calls have all been altered to accept a special value (void *) -1, representing a demand to atomically search for a mappable address space "hole" and map to it.

Individual changes:

  • IPC_M_SHARE_OUT: the destination address space area is supplied by the kernel, the callee only specifies the lower bound

(the address is returned to the callee via a pointer in an IPC reply argument)

  • IPC_M_SHARE_IN: the destination address space ares is supplied by the kernel, the callee only specifies the lower bound

(the address is returned to the caller as usual via an IPC argument)

  • SYS_AS_GET_UNMAPPED_AREA was removed
  • dummy implementations of SYS_PHYSMEM_UNMAP and SYS_IOSPACE_DISABLE were added for the sake of symmetry (they do nothing yet)
  • SYS_PHYSMEM_MAP and SYS_DMAMEM_MAP were altered to accept (void *) -1 as address space area base and a lower bound
  • kernel as_area_create() and as_area_share() were altered to accept (void *) -1 as address space area base and a lower bound
  • uspace libraries and programs were altered to reflect the new API
  • Property mode set to 100644
File size: 24.2 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
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
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>
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"
44#include "fb.h"
45
46#define NAME "fb"
47#define NAMESPACE "hid"
48
49#define TICK_INTERVAL 250000
50
51static LIST_INITIALIZE(fbdevs);
52
53fbdev_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
95static 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
109static 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
123static 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
134static 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
144static 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
163static 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
182static 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
201static 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
220static 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
266static 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
288static 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
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;
322
323 list_remove(&frontbuf->link);
324 as_area_destroy(frontbuf->data);
325 free(frontbuf);
326
327 async_answer_0(iid, EOK);
328}
329
330static 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
360static 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
374static 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
390static 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
402static 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
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;
428
429 if (dev->active_vp != vp)
430 dev->active_vp = vp;
431
432 async_answer_0(iid, EOK);
433}
434
435static 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
447static 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
455static 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
466static 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
500static 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
518static 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
551static 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
562static 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
577static 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
588static 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
605static 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
645static 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
694static 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
747static 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
766static 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
800static 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
825static 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 }
847
848 /*
849 * Accept the connection
850 */
851
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);
871 break;
872 }
873
874 switch (IPC_GET_IMETHOD(call)) {
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
984int main(int argc, char *argv[])
985{
986 printf("%s: HelenOS framebuffer service\n", NAME);
987
988 /* Register server */
989 int rc = loc_server_register(NAME, client_connection);
990 if (rc != EOK) {
991 printf("%s: Unable to register driver (%d)\n", NAME, rc);
992 return 1;
993 }
994
995 ega_init();
996 kchar_init();
997 kfb_init();
998 niagara_init();
999 ski_init();
1000
1001 printf("%s: Accepting connections\n", NAME);
1002 task_retval(0);
1003 async_manager();
1004
1005 /* Never reached */
1006 return 0;
1007}
Note: See TracBrowser for help on using the repository browser.