source: mainline/uspace/lib/graph/graph.c@ b623b68

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b623b68 was feeac0d, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Simplify use of list_foreach.

  • Property mode set to 100644
File size: 14.9 KB
Line 
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, visualizer_t, vcur) {
168 if (vcur->reg_svc_handle == handle) {
169 vs = vcur;
170 break;
171 }
172 }
173 fibril_mutex_unlock(&visualizer_list_mtx);
174
175 return vs;
176}
177
178renderer_t *graph_get_renderer(sysarg_t handle)
179{
180 renderer_t *rnd = NULL;
181
182 fibril_mutex_lock(&renderer_list_mtx);
183 list_foreach(renderer_list, link, renderer_t, rcur) {
184 if (rcur->reg_svc_handle == handle) {
185 rnd = rcur;
186 break;
187 }
188 }
189 fibril_mutex_unlock(&renderer_list_mtx);
190
191 return rnd;
192}
193
194int graph_unregister_visualizer(visualizer_t *vs)
195{
196 int rc = EOK;
197
198 fibril_mutex_lock(&visualizer_list_mtx);
199 rc = loc_service_unregister(vs->reg_svc_handle);
200 list_remove(&vs->link);
201 fibril_mutex_unlock(&visualizer_list_mtx);
202
203 return rc;
204}
205
206int graph_unregister_renderer(renderer_t *rnd)
207{
208 int rc = EOK;
209
210 fibril_mutex_lock(&renderer_list_mtx);
211 rc = loc_service_unregister(rnd->reg_svc_handle);
212 list_remove(&rnd->link);
213 fibril_mutex_unlock(&renderer_list_mtx);
214
215 return rc;
216}
217
218void graph_destroy_visualizer(visualizer_t *vs)
219{
220 assert(atomic_get(&vs->ref_cnt) == 0);
221 assert(vs->notif_sess == NULL);
222 assert(!fibril_mutex_is_locked(&vs->mode_mtx));
223 assert(list_empty(&vs->modes));
224 assert(vs->mode_set == false);
225 assert(vs->cells.data == NULL);
226 assert(vs->dev_ctx == NULL);
227
228 free(vs);
229}
230
231void graph_destroy_renderer(renderer_t *rnd)
232{
233 // TODO
234 assert(atomic_get(&rnd->ref_cnt) == 0);
235
236 free(rnd);
237}
238
239int graph_notify_mode_change(async_sess_t *sess, sysarg_t handle, sysarg_t mode_idx)
240{
241 async_exch_t *exch = async_exchange_begin(sess);
242 int ret = async_req_2_0(exch, VISUALIZER_MODE_CHANGE, handle, mode_idx);
243 async_exchange_end(exch);
244
245 return ret;
246}
247
248int graph_notify_disconnect(async_sess_t *sess, sysarg_t handle)
249{
250 async_exch_t *exch = async_exchange_begin(sess);
251 int ret = async_req_1_0(exch, VISUALIZER_DISCONNECT, handle);
252 async_exchange_end(exch);
253
254 async_hangup(sess);
255
256 return ret;
257}
258
259static void vs_claim(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
260{
261 vs->client_side_handle = IPC_GET_ARG1(*icall);
262 int rc = vs->ops.claim(vs);
263 async_answer_0(iid, rc);
264}
265
266static void vs_yield(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
267{
268 /* Deallocate resources for the current mode. */
269 if (vs->mode_set) {
270 if (vs->cells.data != NULL) {
271 as_area_destroy((void *) vs->cells.data);
272 vs->cells.data = NULL;
273 }
274 }
275
276 /* Driver might also deallocate resources for the current mode. */
277 int rc = vs->ops.yield(vs);
278
279 /* Now that the driver was given a chance to deallocate resources,
280 * current mode can be unset. */
281 if (vs->mode_set) {
282 vs->mode_set = false;
283 }
284
285 async_answer_0(iid, rc);
286}
287
288static void vs_enumerate_modes(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
289{
290 fibril_mutex_lock(&vs->mode_mtx);
291 link_t *link = list_nth(&vs->modes, IPC_GET_ARG1(*icall));
292
293 if (link != NULL) {
294 vslmode_list_element_t *mode_elem =
295 list_get_instance(link, vslmode_list_element_t, link);
296 vslmode_t mode = mode_elem->mode;
297 fibril_mutex_unlock(&vs->mode_mtx);
298
299 ipc_callid_t callid;
300 size_t len;
301
302 if (!async_data_read_receive(&callid, &len)) {
303 async_answer_0(iid, EINVAL);
304 return;
305 }
306 int rc = async_data_read_finalize(callid, &mode, len);
307 if (rc != EOK) {
308 async_answer_0(iid, ENOMEM);
309 return;
310 }
311
312 async_answer_0(iid, EOK);
313 } else {
314 async_answer_0(iid, ENOENT);
315 }
316}
317
318static void vs_get_default_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
319{
320 fibril_mutex_lock(&vs->mode_mtx);
321 vslmode_list_element_t *mode_elem = NULL;
322 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
323 if (cur->mode.index == vs->def_mode_idx) {
324 mode_elem = cur;
325 break;
326 }
327 }
328
329 vslmode_t mode;
330 if (mode_elem != NULL) {
331 mode = mode_elem->mode;
332 fibril_mutex_unlock(&vs->mode_mtx);
333
334 ipc_callid_t callid;
335 size_t len;
336
337 if (!async_data_read_receive(&callid, &len)) {
338 async_answer_0(iid, EINVAL);
339 return;
340 }
341 int rc = async_data_read_finalize(callid, &mode, len);
342 if (rc != EOK) {
343 async_answer_0(iid, ENOMEM);
344 return;
345 }
346 async_answer_0(iid, EOK);
347 } else {
348 fibril_mutex_unlock(&vs->mode_mtx);
349 async_answer_0(iid, ENOENT);
350 }
351}
352
353static void vs_get_current_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
354{
355 if (vs->mode_set) {
356 ipc_callid_t callid;
357 size_t len;
358
359 if (!async_data_read_receive(&callid, &len)) {
360 async_answer_0(iid, EINVAL);
361 return;
362 }
363 int rc = async_data_read_finalize(callid, &vs->cur_mode, len);
364 if (rc != EOK) {
365 async_answer_0(iid, ENOMEM);
366 return;
367 }
368
369 async_answer_0(iid, EOK);
370 } else {
371 async_answer_0(iid, ENOENT);
372 }
373}
374
375static void vs_get_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
376{
377 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
378
379 fibril_mutex_lock(&vs->mode_mtx);
380 vslmode_list_element_t *mode_elem = NULL;
381 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
382 if (cur->mode.index == mode_idx) {
383 mode_elem = cur;
384 break;
385 }
386 }
387
388 vslmode_t mode;
389 if (mode_elem != NULL) {
390 mode = mode_elem->mode;
391 fibril_mutex_unlock(&vs->mode_mtx);
392
393 ipc_callid_t callid;
394 size_t len;
395
396 if (!async_data_read_receive(&callid, &len)) {
397 async_answer_0(iid, EINVAL);
398 return;
399 }
400 int rc = async_data_read_finalize(callid, &mode, len);
401 if (rc != EOK) {
402 async_answer_0(iid, ENOMEM);
403 return;
404 }
405 async_answer_0(iid, EOK);
406 } else {
407 fibril_mutex_unlock(&vs->mode_mtx);
408 async_answer_0(iid, ENOENT);
409 }
410}
411
412static void vs_set_mode(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
413{
414 int rc = EOK;
415
416 /* Retrieve mode index and version. */
417 sysarg_t mode_idx = IPC_GET_ARG1(*icall);
418 sysarg_t mode_version = IPC_GET_ARG2(*icall);
419
420 /* Find mode in the list. */
421 fibril_mutex_lock(&vs->mode_mtx);
422 vslmode_list_element_t *mode_elem = NULL;
423 list_foreach(vs->modes, link, vslmode_list_element_t, cur) {
424 if (cur->mode.index == mode_idx) {
425 mode_elem = cur;
426 break;
427 }
428 }
429
430 /* Extract mode description from the list node. */
431 vslmode_t new_mode;
432 if (mode_elem != NULL) {
433 new_mode = mode_elem->mode;
434 fibril_mutex_unlock(&vs->mode_mtx);
435 } else {
436 fibril_mutex_unlock(&vs->mode_mtx);
437 async_answer_0(iid, ENOENT);
438 return;
439 }
440
441 /* Check whether the mode is still up-to-date. */
442 if (new_mode.version != mode_version) {
443 async_answer_0(iid, EINVAL);
444 return;
445 }
446
447 ipc_callid_t callid;
448 size_t size;
449 unsigned int flags;
450
451 /* Retrieve the shared cell storage for the new mode. */
452 if (!async_share_out_receive(&callid, &size, &flags)) {
453 async_answer_0(iid, EINVAL);
454 return;
455 }
456 void *new_cell_storage;
457 rc = async_share_out_finalize(callid, &new_cell_storage);
458 if ((rc != EOK) || (new_cell_storage == AS_MAP_FAILED)) {
459 async_answer_0(iid, ENOMEM);
460 return;
461 }
462
463 /* Change device internal state. */
464 rc = vs->ops.change_mode(vs, new_mode);
465
466 /* Device driver could not establish new mode. Rollback. */
467 if (rc != EOK) {
468 as_area_destroy(new_cell_storage);
469 async_answer_0(iid, ENOMEM);
470 return;
471 }
472
473 /* Because resources for the new mode were successfully claimed,
474 * it is finally possible to free resources allocated for the old mode. */
475 if (vs->mode_set) {
476 if (vs->cells.data != NULL) {
477 as_area_destroy((void *) vs->cells.data);
478 vs->cells.data = NULL;
479 }
480 }
481
482 /* Insert new mode into the visualizer. */
483 vs->cells.width = new_mode.screen_width;
484 vs->cells.height = new_mode.screen_height;
485 vs->cells.data = (pixel_t *) new_cell_storage;
486 vs->cur_mode = new_mode;
487 vs->mode_set = true;
488
489 async_answer_0(iid, EOK);
490}
491
492static void vs_update_damaged_region(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
493{
494#ifdef __32_BITS__
495 sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 16);
496 sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0x0000ffff);
497#else
498 sysarg_t x_offset = (IPC_GET_ARG5(*icall) >> 32);
499 sysarg_t y_offset = (IPC_GET_ARG5(*icall) & 0xffffffff);
500#endif
501
502 int rc = vs->ops.handle_damage(vs,
503 IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall),
504 IPC_GET_ARG3(*icall), IPC_GET_ARG4(*icall),
505 x_offset, y_offset);
506 async_answer_0(iid, rc);
507}
508
509static void vs_suspend(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
510{
511 int rc = vs->ops.suspend(vs);
512 async_answer_0(iid, rc);
513}
514
515static void vs_wakeup(visualizer_t *vs, ipc_callid_t iid, ipc_call_t *icall)
516{
517 int rc = vs->ops.wakeup(vs);
518 async_answer_0(iid, rc);
519}
520
521void graph_visualizer_connection(visualizer_t *vs,
522 ipc_callid_t iid, ipc_call_t *icall, void *arg)
523{
524 ipc_call_t call;
525 ipc_callid_t callid;
526
527 /* Claim the visualizer. */
528 if (!cas(&vs->ref_cnt, 0, 1)) {
529 async_answer_0(iid, ELIMIT);
530 return;
531 }
532
533 /* Accept the connection. */
534 async_answer_0(iid, EOK);
535
536 /* Establish callback session. */
537 callid = async_get_call(&call);
538 vs->notif_sess = async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
539 if (vs->notif_sess != NULL) {
540 async_answer_0(callid, EOK);
541 } else {
542 async_answer_0(callid, ELIMIT);
543 }
544
545 /* Enter command loop. */
546 while (true) {
547 callid = async_get_call(&call);
548
549 if (!IPC_GET_IMETHOD(call)) {
550 async_answer_0(callid, EINVAL);
551 break;
552 }
553
554 switch (IPC_GET_IMETHOD(call)) {
555 case VISUALIZER_CLAIM:
556 vs_claim(vs, callid, &call);
557 break;
558 case VISUALIZER_YIELD:
559 vs_yield(vs, callid, &call);
560 goto terminate;
561 case VISUALIZER_ENUMERATE_MODES:
562 vs_enumerate_modes(vs, callid, &call);
563 break;
564 case VISUALIZER_GET_DEFAULT_MODE:
565 vs_get_default_mode(vs, callid, &call);
566 break;
567 case VISUALIZER_GET_CURRENT_MODE:
568 vs_get_current_mode(vs, callid, &call);
569 break;
570 case VISUALIZER_GET_MODE:
571 vs_get_mode(vs, callid, &call);
572 break;
573 case VISUALIZER_SET_MODE:
574 vs_set_mode(vs, callid, &call);
575 break;
576 case VISUALIZER_UPDATE_DAMAGED_REGION:
577 vs_update_damaged_region(vs, callid, &call);
578 break;
579 case VISUALIZER_SUSPEND:
580 vs_suspend(vs, callid, &call);
581 break;
582 case VISUALIZER_WAKE_UP:
583 vs_wakeup(vs, callid, &call);
584 break;
585 default:
586 async_answer_0(callid, EINVAL);
587 goto terminate;
588 }
589 }
590
591terminate:
592 async_hangup(vs->notif_sess);
593 vs->notif_sess = NULL;
594 atomic_set(&vs->ref_cnt, 0);
595}
596
597void graph_renderer_connection(renderer_t *rnd,
598 ipc_callid_t iid, ipc_call_t *icall, void *arg)
599{
600 // TODO
601
602 ipc_call_t call;
603 ipc_callid_t callid;
604
605 /* Accept the connection. */
606 atomic_inc(&rnd->ref_cnt);
607 async_answer_0(iid, EOK);
608
609 /* Enter command loop. */
610 while (true) {
611 callid = async_get_call(&call);
612
613 if (!IPC_GET_IMETHOD(call)) {
614 async_answer_0(callid, EINVAL);
615 break;
616 }
617
618 switch (IPC_GET_IMETHOD(call)) {
619 default:
620 async_answer_0(callid, EINVAL);
621 goto terminate;
622 }
623 }
624
625terminate:
626 atomic_dec(&rnd->ref_cnt);
627}
628
629void graph_client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
630{
631 /* Find the visualizer or renderer with the given service ID. */
632 visualizer_t *vs = graph_get_visualizer(IPC_GET_ARG1(*icall));
633 renderer_t *rnd = graph_get_renderer(IPC_GET_ARG1(*icall));
634
635 if (vs != NULL) {
636 graph_visualizer_connection(vs, iid, icall, arg);
637 } else if (rnd != NULL) {
638 graph_renderer_connection(rnd, iid, icall, arg);
639 } else {
640 async_answer_0(iid, ENOENT);
641 }
642}
643
644/** @}
645 */
Note: See TracBrowser for help on using the repository browser.