source: mainline/uspace/lib/graph/graph.c@ 257feec

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

cherrypick GUI implementation (originally by Petr Koupy), with several major changes

  • for character-oriented devices a new output server and output protocol was created based on the original fb server
  • DDF visualizer drivers are pixel-oriented only
  • console and compositor can coexist in the same build
  • terminal widget is self-sufficient, no strange console nesting is needed
  • Property mode set to 100644
File size: 15.2 KB
RevLine 
[6d5e378]1/*
2 * Copyright (c) 2011 Petr Koupy
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/** @addtogroup graph
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <assert.h>
37#include <errno.h>
38#include <inttypes.h>
39#include <stdio.h>
40#include <malloc.h>
41#include <as.h>
42#include "graph.h"
43
44#define NAMESPACE "graphemu"
45#define VISUALIZER_NAME "vsl"
46#define RENDERER_NAME "rnd"
47
48static sysarg_t namespace_idx = 0;
49static sysarg_t visualizer_idx = 0;
50static sysarg_t renderer_idx = 0;
51
52static LIST_INITIALIZE(visualizer_list);
53static LIST_INITIALIZE(renderer_list);
54
55static FIBRIL_MUTEX_INITIALIZE(visualizer_list_mtx);
56static FIBRIL_MUTEX_INITIALIZE(renderer_list_mtx);
57
58visualizer_t *graph_alloc_visualizer(void)
59{
60 visualizer_t *vs = (visualizer_t *) malloc(sizeof(visualizer_t));
61 if (vs == NULL) {
62 return NULL;
63 }
64
65 return vs;
66}
67
68renderer_t *graph_alloc_renderer(void)
69{
70 // TODO
71 renderer_t *rnd = (renderer_t *) malloc(sizeof(renderer_t));
72 if (rnd == NULL) {
73 return NULL;
74 }
75
76 return rnd;
77}
78
79void graph_init_visualizer(visualizer_t *vs)
80{
81 link_initialize(&vs->link);
82 atomic_set(&vs->ref_cnt, 0);
83 vs->notif_sess = NULL;
84 fibril_mutex_initialize(&vs->mode_mtx);
85 list_initialize(&vs->modes);
86 vs->mode_set = false;
87 vs->cells.data = NULL;
88 vs->dev_ctx = NULL;
89}
90
91void graph_init_renderer(renderer_t *rnd)
92{
93 // TODO
94 link_initialize(&rnd->link);
95 atomic_set(&rnd->ref_cnt, 0);
96}
97
98int graph_register_visualizer(visualizer_t *vs)
99{
100 int rc = EOK;
101
102 char node[LOC_NAME_MAXLEN + 1];
103 snprintf(node, LOC_NAME_MAXLEN, "%s%zu/%s%zu", NAMESPACE,
104 namespace_idx, VISUALIZER_NAME, visualizer_idx++);
105
106 category_id_t cat;
107 rc = loc_category_get_id("visualizer", &cat, 0);
108 if (rc != EOK) {
109 return rc;
110 }
111
112 rc = loc_service_register(node, &vs->reg_svc_handle);
113 if (rc != EOK) {
114 return rc;
115 }
116
117 rc = loc_service_add_to_cat(vs->reg_svc_handle, cat);
118 if (rc != EOK) {
119 loc_service_unregister(vs->reg_svc_handle);
120 return rc;
121 }
122
123 fibril_mutex_lock(&visualizer_list_mtx);
124 list_append(&vs->link, &visualizer_list);
125 fibril_mutex_unlock(&visualizer_list_mtx);
126
127 return rc;
128}
129
130int graph_register_renderer(renderer_t *rnd)
131{
132 int rc = EOK;
133
134 char node[LOC_NAME_MAXLEN + 1];
135 snprintf(node, LOC_NAME_MAXLEN, "%s%zu/%s%zu", NAMESPACE,
136 namespace_idx, RENDERER_NAME, renderer_idx++);
137
138 category_id_t cat;
139 rc = loc_category_get_id("renderer", &cat, 0);
140 if (rc != EOK) {
141 return rc;
142 }
143
144 rc = loc_service_register(node, &rnd->reg_svc_handle);
145 if (rc != EOK) {
146 return rc;
147 }
148
149 rc = loc_service_add_to_cat(rnd->reg_svc_handle, cat);
150 if (rc != EOK) {
151 loc_service_unregister(rnd->reg_svc_handle);
152 return rc;
153 }
154
155 fibril_mutex_lock(&renderer_list_mtx);
156 list_append(&rnd->link, &renderer_list);
157 fibril_mutex_unlock(&renderer_list_mtx);
158
159 return rc;
160}
161
162visualizer_t *graph_get_visualizer(sysarg_t handle)
163{
164 visualizer_t *vs = NULL;
165
166 fibril_mutex_lock(&visualizer_list_mtx);
167 list_foreach(visualizer_list, link) {
168 visualizer_t *cur = list_get_instance(link, visualizer_t, link);
169 if (cur->reg_svc_handle == handle) {
170 vs = cur;
171 break;
172 }
173 }
174 fibril_mutex_unlock(&visualizer_list_mtx);
175
176 return vs;
177}
178
179renderer_t *graph_get_renderer(sysarg_t handle)
180{
181 renderer_t *rnd = NULL;
182
183 fibril_mutex_lock(&renderer_list_mtx);
184 list_foreach(renderer_list, link) {
185 renderer_t *cur = list_get_instance(link, renderer_t, link);
186 if (cur->reg_svc_handle == handle) {
187 rnd = cur;
188 break;
189 }
190 }
191 fibril_mutex_unlock(&renderer_list_mtx);
192
193 return rnd;
194}
195
196int graph_unregister_visualizer(visualizer_t *vs)
197{
198 int rc = EOK;
199
200 fibril_mutex_lock(&visualizer_list_mtx);
201 rc = loc_service_unregister(vs->reg_svc_handle);
202 list_remove(&vs->link);
203 fibril_mutex_unlock(&visualizer_list_mtx);
204
205 return rc;
206}
207
208int graph_unregister_renderer(renderer_t *rnd)
209{
210 int rc = EOK;
211
212 fibril_mutex_lock(&renderer_list_mtx);
213 rc = loc_service_unregister(rnd->reg_svc_handle);
214 list_remove(&rnd->link);
215 fibril_mutex_unlock(&renderer_list_mtx);
216
217 return rc;
218}
219
220void graph_destroy_visualizer(visualizer_t *vs)
221{
222 assert(atomic_get(&vs->ref_cnt) == 0);
223 assert(vs->notif_sess == NULL);
224 assert(!fibril_mutex_is_locked(&vs->mode_mtx));
225 assert(list_empty(&vs->modes));
226 assert(vs->mode_set == false);
227 assert(vs->cells.data == NULL);
228 assert(vs->dev_ctx == NULL);
229
230 free(vs);
231}
232
233void graph_destroy_renderer(renderer_t *rnd)
234{
235 // TODO
236 assert(atomic_get(&rnd->ref_cnt) == 0);
237
238 free(rnd);
239}
240
241int graph_notify_mode_change(async_sess_t *sess, sysarg_t handle, sysarg_t mode_idx)
242{
243 async_exch_t *exch = async_exchange_begin(sess);
244 int ret = async_req_2_0(exch, VISUALIZER_MODE_CHANGE, handle, mode_idx);
245 async_exchange_end(exch);
246
247 return ret;
248}
249
250int graph_notify_disconnect(async_sess_t *sess, sysarg_t handle)
251{
252 async_exch_t *exch = async_exchange_begin(sess);
253 int ret = async_req_1_0(exch, VISUALIZER_DISCONNECT, handle);
254 async_exchange_end(exch);
255
256 async_hangup(sess);
257
258 return ret;
259}
260
261static void vs_claim(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
262{
263 vs->client_side_handle = IPC_GET_ARG1(*icall);
264 int rc = vs->ops.claim(vs);
265 async_answer_0(iid, rc);
266}
267
268static void vs_yield(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
269{
270 /* Deallocate resources for the current mode. */
271 if (vs->mode_set) {
272 if (vs->cells.data != NULL) {
273 as_area_destroy((void *) vs->cells.data);
274 vs->cells.data = NULL;
275 }
276 }
277
278 /* Driver might also deallocate resources for the current mode. */
279 int rc = vs->ops.yield(vs);
280
281 /* Now that the driver was given a chance to deallocate resources,
282 * current mode can be unset. */
283 if (vs->mode_set) {
284 vs->mode_set = false;
285 }
286
287 async_answer_0(iid, rc);
288}
289
290static void vs_enumerate_modes(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
291{
292 fibril_mutex_lock(&vs->mode_mtx);
293 link_t *link = list_nth(&vs->modes, IPC_GET_ARG1(*icall));
294
295 if (link != NULL) {
296 vslmode_list_element_t *mode_elem =
297 list_get_instance(link, vslmode_list_element_t, link);
298 vslmode_t mode = mode_elem->mode;
299 fibril_mutex_unlock(&vs->mode_mtx);
300
301 ipc_callid_t callid;
302 size_t len;
303
304 if (!async_data_read_receive(&callid, &len)) {
305 async_answer_0(iid, EINVAL);
306 return;
307 }
308 int rc = async_data_read_finalize(callid, &mode, len);
309 if (rc != EOK) {
310 async_answer_0(iid, ENOMEM);
311 return;
312 }
313
314 async_answer_0(iid, EOK);
315 } else {
316 async_answer_0(iid, ENOENT);
317 }
318}
319
320static void vs_get_default_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
321{
322 fibril_mutex_lock(&vs->mode_mtx);
323 vslmode_list_element_t *mode_elem = NULL;
324 list_foreach(vs->modes, link) {
325 vslmode_list_element_t *cur = list_get_instance(link, vslmode_list_element_t, link);
326 if (cur->mode.index == vs->def_mode_idx) {
327 mode_elem = cur;
328 break;
329 }
330 }
331
332 vslmode_t mode;
333 if (mode_elem != NULL) {
334 mode = mode_elem->mode;
335 fibril_mutex_unlock(&vs->mode_mtx);
336
337 ipc_callid_t callid;
338 size_t len;
339
340 if (!async_data_read_receive(&callid, &len)) {
341 async_answer_0(iid, EINVAL);
342 return;
343 }
344 int rc = async_data_read_finalize(callid, &mode, len);
345 if (rc != EOK) {
346 async_answer_0(iid, ENOMEM);
347 return;
348 }
349 async_answer_0(iid, EOK);
350 } else {
351 fibril_mutex_unlock(&vs->mode_mtx);
352 async_answer_0(iid, ENOENT);
353 }
354}
355
356static void vs_get_current_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
357{
358 if (vs->mode_set) {
359 ipc_callid_t callid;
360 size_t len;
361
362 if (!async_data_read_receive(&callid, &len)) {
363 async_answer_0(iid, EINVAL);
364 return;
365 }
366 int rc = async_data_read_finalize(callid, &vs->cur_mode, len);
367 if (rc != EOK) {
368 async_answer_0(iid, ENOMEM);
369 return;
370 }
371
372 async_answer_0(iid, EOK);
373 } else {
374 async_answer_0(iid, ENOENT);
375 }
376}
377
378static void vs_get_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
379{
380 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
381
382 fibril_mutex_lock(&vs->mode_mtx);
383 vslmode_list_element_t *mode_elem = NULL;
384 list_foreach(vs->modes, link) {
385 vslmode_list_element_t *cur = list_get_instance(link, vslmode_list_element_t, link);
386 if (cur->mode.index == mode_idx) {
387 mode_elem = cur;
388 break;
389 }
390 }
391
392 vslmode_t mode;
393 if (mode_elem != NULL) {
394 mode = mode_elem->mode;
395 fibril_mutex_unlock(&vs->mode_mtx);
396
397 ipc_callid_t callid;
398 size_t len;
399
400 if (!async_data_read_receive(&callid, &len)) {
401 async_answer_0(iid, EINVAL);
402 return;
403 }
404 int rc = async_data_read_finalize(callid, &mode, len);
405 if (rc != EOK) {
406 async_answer_0(iid, ENOMEM);
407 return;
408 }
409 async_answer_0(iid, EOK);
410 } else {
411 fibril_mutex_unlock(&vs->mode_mtx);
412 async_answer_0(iid, ENOENT);
413 }
414}
415
416static void vs_set_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
417{
418 int rc = EOK;
419
420 /* Retrieve mode index and version. */
421 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
422 sysarg_t mode_version = IPC_GET_ARG2(*icall);
423
424 /* Find mode in the list. */
425 fibril_mutex_lock(&vs->mode_mtx);
426 vslmode_list_element_t *mode_elem = NULL;
427 list_foreach(vs->modes, link) {
428 vslmode_list_element_t *cur = list_get_instance(link, vslmode_list_element_t, link);
429 if (cur->mode.index == mode_idx) {
430 mode_elem = cur;
431 break;
432 }
433 }
434
435 /* Extract mode description from the list node. */
436 vslmode_t new_mode;
437 if (mode_elem != NULL) {
438 new_mode = mode_elem->mode;
439 fibril_mutex_unlock(&vs->mode_mtx);
440 } else {
441 fibril_mutex_unlock(&vs->mode_mtx);
442 async_answer_0(iid, ENOENT);
443 return;
444 }
445
446 /* Check whether the mode is still up-to-date. */
447 if (new_mode.version != mode_version) {
448 async_answer_0(iid, EINVAL);
449 return;
450 }
451
452 ipc_callid_t callid;
453 size_t size;
454 unsigned int flags;
455
456 /* Retrieve the shared cell storage for the new mode. */
457 if (!async_share_out_receive(&callid, &size, &flags)) {
458 async_answer_0(iid, EINVAL);
459 return;
460 }
461 void *new_cell_storage;
462 rc = async_share_out_finalize(callid, &new_cell_storage);
463 if ((rc != EOK) || (new_cell_storage == AS_MAP_FAILED)) {
464 async_answer_0(iid, ENOMEM);
465 return;
466 }
467
468 /* Change device internal state. */
469 rc = vs->ops.change_mode(vs, new_mode);
470
471 /* Device driver could not establish new mode. Rollback. */
472 if (rc != EOK) {
473 as_area_destroy(new_cell_storage);
474 async_answer_0(iid, ENOMEM);
475 return;
476 }
477
478 /* Because resources for the new mode were successfully claimed,
479 * it is finally possible to free resources allocated for the old mode. */
480 if (vs->mode_set) {
481 if (vs->cells.data != NULL) {
482 as_area_destroy((void *) vs->cells.data);
483 vs->cells.data = NULL;
484 }
485 }
486
487 /* Insert new mode into the visualizer. */
488 vs->cells.width = new_mode.screen_width;
489 vs->cells.height = new_mode.screen_height;
490 vs->cells.data = (pixel_t *) new_cell_storage;
491 vs->cur_mode = new_mode;
492 vs->mode_set = true;
493
494 async_answer_0(iid, EOK);
495}
496
497static void vs_update_damaged_region(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
498{
499#ifdef __32_BITS__
500 sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 16);
501 sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0x0000ffff);
502#else
503 sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 32);
504 sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0xffffffff);
505#endif
506
507 int rc = vs->ops.handle_damage(vs,
508 IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall),
509 IPC_GET_ARG3(*icall), IPC_GET_ARG4(*icall),
510 x_offset, y_offset);
511 async_answer_0(iid, rc);
512}
513
514static void vs_suspend(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
515{
516 int rc = vs->ops.suspend(vs);
517 async_answer_0(iid, rc);
518}
519
520static void vs_wakeup(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
521{
522 int rc = vs->ops.wakeup(vs);
523 async_answer_0(iid, rc);
524}
525
526void graph_visualizer_connection(visualizer_t *vs,
527 ipc_callid_t iid, ipc_call_t *icall, void *arg)
528{
529 ipc_call_t call;
530 ipc_callid_t callid;
531
532 /* Claim the visualizer. */
533 if (!cas(&vs->ref_cnt, 0, 1)) {
534 async_answer_0(iid, ELIMIT);
535 return;
536 }
537
538 /* Accept the connection. */
539 async_answer_0(iid, EOK);
540
541 /* Establish callback session. */
542 callid = async_get_call(&call);
543 vs->notif_sess = async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
544 if (vs->notif_sess != NULL) {
545 async_answer_0(callid, EOK);
546 } else {
547 async_answer_0(callid, ELIMIT);
548 }
549
550 /* Enter command loop. */
551 while (true) {
552 callid = async_get_call(&call);
553
554 if (!IPC_GET_IMETHOD(call)) {
555 async_answer_0(callid, EINVAL);
556 break;
557 }
558
559 switch (IPC_GET_IMETHOD(call)) {
560 case VISUALIZER_CLAIM:
561 vs_claim(vs, callid, &call);
562 break;
563 case VISUALIZER_YIELD:
564 vs_yield(vs, callid, &call);
565 goto terminate;
566 case VISUALIZER_ENUMERATE_MODES:
567 vs_enumerate_modes(vs, callid, &call);
568 break;
569 case VISUALIZER_GET_DEFAULT_MODE:
570 vs_get_default_mode(vs, callid, &call);
571 break;
572 case VISUALIZER_GET_CURRENT_MODE:
573 vs_get_current_mode(vs, callid, &call);
574 break;
575 case VISUALIZER_GET_MODE:
576 vs_get_mode(vs, callid, &call);
577 break;
578 case VISUALIZER_SET_MODE:
579 vs_set_mode(vs, callid, &call);
580 break;
581 case VISUALIZER_UPDATE_DAMAGED_REGION:
582 vs_update_damaged_region(vs, callid, &call);
583 break;
584 case VISUALIZER_SUSPEND:
585 vs_suspend(vs, callid, &call);
586 break;
587 case VISUALIZER_WAKE_UP:
588 vs_wakeup(vs, callid, &call);
589 break;
590 default:
591 async_answer_0(callid, EINVAL);
592 goto terminate;
593 }
594 }
595
596terminate:
597 async_hangup(vs->notif_sess);
598 vs->notif_sess = NULL;
599 atomic_set(&vs->ref_cnt, 0);
600}
601
602void graph_renderer_connection(renderer_t *rnd,
603 ipc_callid_t iid, ipc_call_t *icall, void *arg)
604{
605 // TODO
606
607 ipc_call_t call;
608 ipc_callid_t callid;
609
610 /* Accept the connection. */
611 atomic_inc(&rnd->ref_cnt);
612 async_answer_0(iid, EOK);
613
614 /* Enter command loop. */
615 while (true) {
616 callid = async_get_call(&call);
617
618 if (!IPC_GET_IMETHOD(call)) {
619 async_answer_0(callid, EINVAL);
620 break;
621 }
622
623 switch (IPC_GET_IMETHOD(call)) {
624 default:
625 async_answer_0(callid, EINVAL);
626 goto terminate;
627 }
628 }
629
630terminate:
631 atomic_dec(&rnd->ref_cnt);
632}
633
634void graph_client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
635{
636 /* Find the visualizer or renderer with the given service ID. */
637 visualizer_t *vs = graph_get_visualizer(IPC_GET_ARG1(*icall));
638 renderer_t *rnd = graph_get_renderer(IPC_GET_ARG1(*icall));
639
640 if (vs != NULL) {
641 graph_visualizer_connection(vs, iid, icall, arg);
642 } else if (rnd != NULL) {
643 graph_renderer_connection(rnd, iid, icall, arg);
644 } else {
645 async_answer_0(iid, ENOENT);
646 }
647}
648
649/** @}
650 */
Note: See TracBrowser for help on using the repository browser.