source: mainline/uspace/lib/graph/graph.c@ 8565a42

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8565a42 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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