source: mainline/uspace/srv/hid/fb/fb.c@ 4ee7364

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4ee7364 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
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 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 }
313
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;
323
324 list_remove(&frontbuf->link);
325 as_area_destroy(frontbuf->data);
326 free(frontbuf);
327
328 async_answer_0(iid, EOK);
329}
330
331static void fbsrv_imagemap_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
332{
333 imagemap_t *imagemap = (imagemap_t *) malloc(sizeof(imagemap_t));
334 if (imagemap == NULL) {
335 async_answer_0(iid, ENOMEM);
336 return;
337 }
338
339 link_initialize(&imagemap->link);
340 link_initialize(&imagemap->seq_link);
341
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 }
349
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;
356 }
357
358 list_append(&imagemap->link, &dev->imagemaps);
359 async_answer_1(iid, EOK, (sysarg_t) imagemap);
360}
361
362static void fbsrv_imagemap_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
363{
364 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid);
365 if (imagemap == NULL)
366 return;
367
368 list_remove(&imagemap->link);
369 list_remove(&imagemap->seq_link);
370 as_area_destroy(imagemap->data);
371 free(imagemap);
372
373 async_answer_0(iid, EOK);
374}
375
376static void fbsrv_sequence_create(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
377{
378 sequence_t *sequence = (sequence_t *) malloc(sizeof(sequence_t));
379 if (sequence == NULL) {
380 async_answer_0(iid, ENOMEM);
381 return;
382 }
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);
390}
391
392static void fbsrv_sequence_destroy(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
393{
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);
402}
403
404static void fbsrv_sequence_add_imagemap(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
405{
406 sequence_t *sequence = resolve_sequence(dev, IPC_GET_ARG1(*icall), iid);
407 if (sequence == NULL)
408 return;
409
410 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG2(*icall), iid);
411 if (imagemap == NULL)
412 return;
413
414 if (list_member(&imagemap->seq_link, &sequence->imagemaps)) {
415 async_answer_0(iid, EEXISTS);
416 return;
417 }
418
419 list_append(&imagemap->seq_link, &sequence->imagemaps);
420 sequence->count++;
421
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;
430
431 if (dev->active_vp != vp)
432 dev->active_vp = vp;
433
434 async_answer_0(iid, EOK);
435}
436
437static void fbsrv_vp_clear(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
438{
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);
447}
448
449static void fbsrv_vp_get_dimensions(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
450{
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);
455}
456
457static void fbsrv_vp_get_caps(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
458{
459 assert(dev->ops.vp_get_caps);
460
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);
466}
467
468static void fbsrv_vp_cursor_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
469{
470 assert(dev->ops.vp_cursor_update);
471
472 frontbuf_t *frontbuf = resolve_frontbuf(dev, IPC_GET_ARG1(*icall), iid);
473 if (frontbuf == NULL)
474 return;
475
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);
500}
501
502static void fbsrv_vp_cursor_flash(fbdev_t *dev)
503{
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 }
518}
519
520static void fbsrv_sequences_update(fbdev_t *dev)
521{
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);
525
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 }
549 }
550 }
551}
552
553static void fbsrv_vp_set_style(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
554{
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);
562}
563
564static void fbsrv_vp_set_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
565{
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);
577}
578
579static void fbsrv_vp_set_rgb_color(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
580{
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);
586 } else
587 async_answer_0(iid, ENOENT);
588}
589
590static void fbsrv_vp_putchar(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
591{
592 assert(dev->ops.vp_char_update);
593
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));
597
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);
605}
606
607static bool fbsrv_vp_update_scroll(fbdev_t *dev, fbvp_t *vp,
608 screenbuffer_t *frontbuf)
609{
610 assert(dev->ops.vp_char_update);
611
612 sysarg_t top_row = screenbuffer_get_top_row(frontbuf);
613
614 if (vp->top_row == top_row)
615 return false;
616
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;
635 }
636
637 front_field->flags &= ~CHAR_FLAG_DIRTY;
638
639 if (update)
640 dev->ops.vp_char_update(dev, vp, x, y);
641 }
642 }
643
644 return true;
645}
646
647static void fbsrv_vp_update(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
648{
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;
662 }
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 }
689 }
690
691 async_answer_0(iid, EOK);
692 } else
693 async_answer_0(iid, ENOENT);
694}
695
696static void fbsrv_vp_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
697{
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;
707
708 if (fbsrv_vp_update_scroll(dev, vp, screenbuf)) {
709 async_answer_0(iid, EOK);
710 return;
711 }
712
713 sysarg_t col = IPC_GET_ARG2(*icall);
714 sysarg_t row = IPC_GET_ARG3(*icall);
715
716 sysarg_t cols = IPC_GET_ARG4(*icall);
717 sysarg_t rows = IPC_GET_ARG5(*icall);
718
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 }
742 }
743
744 async_answer_0(iid, EOK);
745 } else
746 async_answer_0(iid, ENOENT);
747}
748
749static void fbsrv_vp_imagemap_damage(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
750{
751 imagemap_t *imagemap = resolve_imagemap(dev, IPC_GET_ARG1(*icall), iid);
752 if (imagemap == NULL)
753 return;
754
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);
766}
767
768static void fbsrv_vp_sequence_start(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
769{
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);
800}
801
802static void fbsrv_vp_sequence_stop(fbdev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
803{
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);
825}
826
827static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
828{
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 }
839
840 if (dev == NULL) {
841 async_answer_0(iid, ENOENT);
842 return;
843 }
844
845 if (atomic_get(&dev->refcnt) > 0) {
846 async_answer_0(iid, ELIMIT);
847 return;
848 }
849
850 /*
851 * Accept the connection
852 */
853
854 atomic_inc(&dev->refcnt);
855 dev->claimed = true;
856 async_answer_0(iid, EOK);
857
858 while (true) {
859 ipc_call_t call;
860 ipc_callid_t callid =
861 async_get_call_timeout(&call, TICK_INTERVAL);
862
863 if (!callid) {
864 fbsrv_vp_cursor_flash(dev);
865 fbsrv_sequences_update(dev);
866 continue;
867 }
868
869 if (!IPC_GET_IMETHOD(call)) {
870 dev->claimed = false;
871 atomic_dec(&dev->refcnt);
872 async_answer_0(callid, EOK);
873 break;
874 }
875
876 switch (IPC_GET_IMETHOD(call)) {
877
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);
891 break;
892
893 /* Object methods */
894
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;
922
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);
936 break;
937
938 /* Style methods (viewport specific) */
939
940 case FB_VP_CURSOR_UPDATE:
941 fbsrv_vp_cursor_update(dev, callid, &call);
942 break;
943 case FB_VP_SET_STYLE:
944 fbsrv_vp_set_style(dev, callid, &call);
945 break;
946 case FB_VP_SET_COLOR:
947 fbsrv_vp_set_color(dev, callid, &call);
948 break;
949 case FB_VP_SET_RGB_COLOR:
950 fbsrv_vp_set_rgb_color(dev, callid, &call);
951 break;
952
953 /* Text output methods (viewport specific) */
954
955 case FB_VP_PUTCHAR:
956 fbsrv_vp_putchar(dev, callid, &call);
957 break;
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);
982 }
983 }
984}
985
986int main(int argc, char *argv[])
987{
988 printf("%s: HelenOS framebuffer service\n", NAME);
989
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 }
996
997 ega_init();
998 kchar_init();
999 kfb_init();
1000 niagara_init();
1001 ski_init();
1002
1003 printf("%s: Accepting connections\n", NAME);
1004 task_retval(0);
1005 async_manager();
1006
1007 /* Never reached */
1008 return 0;
1009}
Note: See TracBrowser for help on using the repository browser.