source: mainline/uspace/lib/c/generic/loc.c@ 889cdb1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 889cdb1 was 889cdb1, checked in by Jakub Jermar <jakub@…>, 7 years ago

Always answer the IPC_M_PHONE_HUNGUP message

  • Property mode set to 100644
File size: 19.9 KB
RevLine 
[15f3c3f]1/*
2 * Copyright (c) 2007 Josef Cejka
[cc574511]3 * Copyright (c) 2011 Jiri Svoboda
[15f3c3f]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <str.h>
31#include <ipc/services.h>
32#include <ns.h>
33#include <ipc/loc.h>
34#include <loc.h>
35#include <fibril_synch.h>
36#include <async.h>
37#include <errno.h>
[38d150e]38#include <stdlib.h>
[3e6a98c5]39#include <stdbool.h>
[15f3c3f]40
41static FIBRIL_MUTEX_INITIALIZE(loc_supp_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex);
43
44static FIBRIL_MUTEX_INITIALIZE(loc_supplier_mutex);
45static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex);
46
[12f9f0d0]47static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
48static bool loc_callback_created = false;
[a6240a31]49static loc_cat_change_cb_t cat_change_cb = NULL;
[e89a06a]50static void *cat_change_arg = NULL;
[12f9f0d0]51
[15f3c3f]52static async_sess_t *loc_supp_block_sess = NULL;
53static async_sess_t *loc_cons_block_sess = NULL;
54
55static async_sess_t *loc_supplier_sess = NULL;
56static async_sess_t *loc_consumer_sess = NULL;
57
[984a9ba]58static void loc_cb_conn(ipc_call_t *icall, void *arg)
[12f9f0d0]59{
60 while (true) {
61 ipc_call_t call;
[984a9ba]62 async_get_call(&call);
[a35b458]63
[12f9f0d0]64 if (!IPC_GET_IMETHOD(call)) {
[889cdb1]65 async_answer_0(&call, EOK);
[12f9f0d0]66 return;
67 }
[a35b458]68
[12f9f0d0]69 switch (IPC_GET_IMETHOD(call)) {
70 case LOC_EVENT_CAT_CHANGE:
71 fibril_mutex_lock(&loc_callback_mutex);
[a6240a31]72 loc_cat_change_cb_t cb_fun = cat_change_cb;
[e89a06a]73 void *cb_arg = cat_change_arg;
[12f9f0d0]74 fibril_mutex_unlock(&loc_callback_mutex);
[a35b458]75
[984a9ba]76 async_answer_0(&call, EOK);
[a35b458]77
[a6240a31]78 if (cb_fun != NULL)
[e89a06a]79 (*cb_fun)(cb_arg);
[a35b458]80
[12f9f0d0]81 break;
82 default:
[984a9ba]83 async_answer_0(&call, ENOTSUP);
[12f9f0d0]84 }
85 }
86}
87
[15f3c3f]88static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
89 async_sess_t **dst)
90{
91 fibril_mutex_lock(mtx);
[a35b458]92
[15f3c3f]93 if ((*dst == NULL) && (src != NULL))
94 *dst = src;
[a35b458]95
[15f3c3f]96 fibril_mutex_unlock(mtx);
97}
98
[a6240a31]99/** Create callback
100 *
101 * Must be called with loc_callback_mutex locked.
102 *
103 * @return EOK on success.
104 *
105 */
[b7fd2a0]106static errno_t loc_callback_create(void)
[12f9f0d0]107{
108 if (!loc_callback_created) {
[a6240a31]109 async_exch_t *exch =
[f9b2cb4c]110 loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]111
[12f9f0d0]112 ipc_call_t answer;
113 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
[a35b458]114
[f9b2cb4c]115 port_id_t port;
[b7fd2a0]116 errno_t rc = async_create_callback_port(exch, INTERFACE_LOC_CB, 0, 0,
[f9b2cb4c]117 loc_cb_conn, NULL, &port);
[a35b458]118
[12f9f0d0]119 loc_exchange_end(exch);
[a35b458]120
[12f9f0d0]121 if (rc != EOK)
[a6240a31]122 return rc;
[a35b458]123
[b7fd2a0]124 errno_t retval;
[cd66f3c]125 async_wait_for(req, &retval);
126 if (retval != EOK)
127 return retval;
[a35b458]128
[12f9f0d0]129 loc_callback_created = true;
130 }
[a35b458]131
[a6240a31]132 return EOK;
[12f9f0d0]133}
134
[15f3c3f]135/** Start an async exchange on the loc session (blocking).
136 *
137 * @param iface Location service interface to choose
138 *
139 * @return New exchange.
140 *
141 */
[f9b2cb4c]142async_exch_t *loc_exchange_begin_blocking(iface_t iface)
[15f3c3f]143{
144 switch (iface) {
[f9b2cb4c]145 case INTERFACE_LOC_SUPPLIER:
[15f3c3f]146 fibril_mutex_lock(&loc_supp_block_mutex);
[a35b458]147
[15f3c3f]148 while (loc_supp_block_sess == NULL) {
149 clone_session(&loc_supplier_mutex, loc_supplier_sess,
150 &loc_supp_block_sess);
[a35b458]151
[15f3c3f]152 if (loc_supp_block_sess == NULL)
153 loc_supp_block_sess =
[f9b2cb4c]154 service_connect_blocking(SERVICE_LOC,
155 INTERFACE_LOC_SUPPLIER, 0);
[15f3c3f]156 }
[a35b458]157
[15f3c3f]158 fibril_mutex_unlock(&loc_supp_block_mutex);
[a35b458]159
[15f3c3f]160 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
161 &loc_supplier_sess);
[a35b458]162
[15f3c3f]163 return async_exchange_begin(loc_supp_block_sess);
[f9b2cb4c]164 case INTERFACE_LOC_CONSUMER:
[15f3c3f]165 fibril_mutex_lock(&loc_cons_block_mutex);
[a35b458]166
[15f3c3f]167 while (loc_cons_block_sess == NULL) {
168 clone_session(&loc_consumer_mutex, loc_consumer_sess,
169 &loc_cons_block_sess);
[a35b458]170
[15f3c3f]171 if (loc_cons_block_sess == NULL)
172 loc_cons_block_sess =
[f9b2cb4c]173 service_connect_blocking(SERVICE_LOC,
174 INTERFACE_LOC_CONSUMER, 0);
[15f3c3f]175 }
[a35b458]176
[15f3c3f]177 fibril_mutex_unlock(&loc_cons_block_mutex);
[a35b458]178
[15f3c3f]179 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
180 &loc_consumer_sess);
[a35b458]181
[15f3c3f]182 return async_exchange_begin(loc_cons_block_sess);
183 default:
184 return NULL;
185 }
186}
187
188/** Start an async exchange on the loc session.
189 *
190 * @param iface Location service interface to choose
191 *
192 * @return New exchange.
193 *
194 */
[f9b2cb4c]195async_exch_t *loc_exchange_begin(iface_t iface)
[15f3c3f]196{
197 switch (iface) {
[f9b2cb4c]198 case INTERFACE_LOC_SUPPLIER:
[15f3c3f]199 fibril_mutex_lock(&loc_supplier_mutex);
[a35b458]200
[15f3c3f]201 if (loc_supplier_sess == NULL)
202 loc_supplier_sess =
[f9b2cb4c]203 service_connect(SERVICE_LOC,
204 INTERFACE_LOC_SUPPLIER, 0);
[a35b458]205
[15f3c3f]206 fibril_mutex_unlock(&loc_supplier_mutex);
[a35b458]207
[15f3c3f]208 if (loc_supplier_sess == NULL)
209 return NULL;
[a35b458]210
[15f3c3f]211 return async_exchange_begin(loc_supplier_sess);
[f9b2cb4c]212 case INTERFACE_LOC_CONSUMER:
[15f3c3f]213 fibril_mutex_lock(&loc_consumer_mutex);
[a35b458]214
[15f3c3f]215 if (loc_consumer_sess == NULL)
216 loc_consumer_sess =
[f9b2cb4c]217 service_connect(SERVICE_LOC,
218 INTERFACE_LOC_CONSUMER, 0);
[a35b458]219
[15f3c3f]220 fibril_mutex_unlock(&loc_consumer_mutex);
[a35b458]221
[15f3c3f]222 if (loc_consumer_sess == NULL)
223 return NULL;
[a35b458]224
[15f3c3f]225 return async_exchange_begin(loc_consumer_sess);
226 default:
227 return NULL;
228 }
229}
230
231/** Finish an async exchange on the loc session.
232 *
233 * @param exch Exchange to be finished.
234 *
235 */
236void loc_exchange_end(async_exch_t *exch)
237{
238 async_exchange_end(exch);
239}
240
241/** Register new driver with loc. */
[b7fd2a0]242errno_t loc_server_register(const char *name)
[15f3c3f]243{
[f9b2cb4c]244 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[a35b458]245
[15f3c3f]246 ipc_call_t answer;
247 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
[b7fd2a0]248 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]249
[15f3c3f]250 if (retval != EOK) {
[50b581d]251 async_forget(req);
[0239846]252 loc_exchange_end(exch);
[15f3c3f]253 return retval;
254 }
[a35b458]255
[9b1baac]256 async_connect_to_me(exch, INTERFACE_ANY, 0, 0);
[0239846]257
258 /*
259 * First wait for the answer and then end the exchange. The opposite
260 * order is generally wrong because it may lead to a deadlock under
261 * certain circumstances.
262 */
263 async_wait_for(req, &retval);
[15f3c3f]264 loc_exchange_end(exch);
[a35b458]265
[15f3c3f]266 return retval;
267}
268
[d0dd7b5]269/** Register new service.
[15f3c3f]270 *
[f9b2cb4c]271 * @param fqsn Fully qualified service name
272 * @param[out] sid Service ID of new service
[15f3c3f]273 *
274 */
[b7fd2a0]275errno_t loc_service_register(const char *fqsn, service_id_t *sid)
[15f3c3f]276{
[f9b2cb4c]277 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[a35b458]278
[15f3c3f]279 ipc_call_t answer;
[f9b2cb4c]280 aid_t req = async_send_0(exch, LOC_SERVICE_REGISTER, &answer);
[b7fd2a0]281 errno_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
[a35b458]282
[15f3c3f]283 if (retval != EOK) {
[50b581d]284 async_forget(req);
[0239846]285 loc_exchange_end(exch);
[15f3c3f]286 return retval;
287 }
[a35b458]288
[0239846]289 /*
290 * First wait for the answer and then end the exchange. The opposite
291 * order is generally wrong because it may lead to a deadlock under
292 * certain circumstances.
293 */
[15f3c3f]294 async_wait_for(req, &retval);
[0239846]295 loc_exchange_end(exch);
[a35b458]296
[15f3c3f]297 if (retval != EOK) {
[d0dd7b5]298 if (sid != NULL)
299 *sid = -1;
[a35b458]300
[15f3c3f]301 return retval;
302 }
[a35b458]303
[d0dd7b5]304 if (sid != NULL)
305 *sid = (service_id_t) IPC_GET_ARG1(answer);
[a35b458]306
[15f3c3f]307 return retval;
308}
309
[d0dd7b5]310/** Unregister service.
311 *
312 * @param sid Service ID
313 */
[b7fd2a0]314errno_t loc_service_unregister(service_id_t sid)
[d0dd7b5]315{
316 async_exch_t *exch;
[b7fd2a0]317 errno_t retval;
[a35b458]318
[f9b2cb4c]319 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[d0dd7b5]320 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
321 loc_exchange_end(exch);
[a35b458]322
[b7fd2a0]323 return (errno_t)retval;
[15f3c3f]324}
325
[b7fd2a0]326errno_t loc_service_get_id(const char *fqdn, service_id_t *handle,
[15f3c3f]327 unsigned int flags)
328{
329 async_exch_t *exch;
[a35b458]330
[15f3c3f]331 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]332 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]333 else {
[f9b2cb4c]334 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]335 if (exch == NULL)
336 return errno;
337 }
[a35b458]338
[15f3c3f]339 ipc_call_t answer;
340 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
341 &answer);
[b7fd2a0]342 errno_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
[a35b458]343
[15f3c3f]344 loc_exchange_end(exch);
[a35b458]345
[15f3c3f]346 if (retval != EOK) {
[50b581d]347 async_forget(req);
[15f3c3f]348 return retval;
349 }
[a35b458]350
[15f3c3f]351 async_wait_for(req, &retval);
[a35b458]352
[15f3c3f]353 if (retval != EOK) {
354 if (handle != NULL)
355 *handle = (service_id_t) -1;
[a35b458]356
[15f3c3f]357 return retval;
358 }
[a35b458]359
[15f3c3f]360 if (handle != NULL)
361 *handle = (service_id_t) IPC_GET_ARG1(answer);
[a35b458]362
[15f3c3f]363 return retval;
364}
365
[763e0cd]366/** Get object name.
[cce8a83]367 *
[763e0cd]368 * Provided ID of an object, return its name.
[cce8a83]369 *
[763e0cd]370 * @param method IPC method
371 * @param id Object ID
[cce8a83]372 * @param name Place to store pointer to new string. Caller should
373 * free it using free().
[cde999a]374 * @return EOK on success or an error code
[cce8a83]375 */
[b7fd2a0]376static errno_t loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
[cce8a83]377{
378 async_exch_t *exch;
379 char name_buf[LOC_NAME_MAXLEN + 1];
[45058baa]380 ipc_call_t dreply;
381 size_t act_size;
[b7fd2a0]382 errno_t dretval;
[a35b458]383
[cce8a83]384 *name = NULL;
[f9b2cb4c]385 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]386
[cce8a83]387 ipc_call_t answer;
[763e0cd]388 aid_t req = async_send_1(exch, method, id, &answer);
[45058baa]389 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
390 &dreply);
391 async_wait_for(dreq, &dretval);
[a35b458]392
[cce8a83]393 loc_exchange_end(exch);
[a35b458]394
[45058baa]395 if (dretval != EOK) {
[50b581d]396 async_forget(req);
[45058baa]397 return dretval;
[cce8a83]398 }
[a35b458]399
[b7fd2a0]400 errno_t retval;
[cce8a83]401 async_wait_for(req, &retval);
[a35b458]402
[cce8a83]403 if (retval != EOK)
404 return retval;
[a35b458]405
[45058baa]406 act_size = IPC_GET_ARG2(dreply);
407 assert(act_size <= LOC_NAME_MAXLEN);
408 name_buf[act_size] = '\0';
409
[cce8a83]410 *name = str_dup(name_buf);
411 if (*name == NULL)
412 return ENOMEM;
[a35b458]413
[cce8a83]414 return EOK;
415}
416
[763e0cd]417/** Get category name.
418 *
419 * Provided ID of a service, return its name.
420 *
421 * @param cat_id Category ID
422 * @param name Place to store pointer to new string. Caller should
423 * free it using free().
[cde999a]424 * @return EOK on success or an error code
[763e0cd]425 */
[b7fd2a0]426errno_t loc_category_get_name(category_id_t cat_id, char **name)
[763e0cd]427{
428 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
429}
430
431/** Get service name.
432 *
433 * Provided ID of a service, return its name.
434 *
435 * @param svc_id Service ID
436 * @param name Place to store pointer to new string. Caller should
437 * free it using free().
[cde999a]438 * @return EOK on success or an error code
[763e0cd]439 */
[b7fd2a0]440errno_t loc_service_get_name(service_id_t svc_id, char **name)
[763e0cd]441{
442 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
443}
[cce8a83]444
[a3fcfba]445/** Get service server name.
446 *
447 * Provided ID of a service, return the name of its server.
448 *
449 * @param svc_id Service ID
450 * @param name Place to store pointer to new string. Caller should
451 * free it using free().
[cde999a]452 * @return EOK on success or an error code
[a3fcfba]453 */
[b7fd2a0]454errno_t loc_service_get_server_name(service_id_t svc_id, char **name)
[a3fcfba]455{
456 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
457}
458
[b7fd2a0]459errno_t loc_namespace_get_id(const char *name, service_id_t *handle,
[15f3c3f]460 unsigned int flags)
461{
462 async_exch_t *exch;
[a35b458]463
[15f3c3f]464 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]465 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]466 else {
[f9b2cb4c]467 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]468 if (exch == NULL)
469 return errno;
470 }
[a35b458]471
[15f3c3f]472 ipc_call_t answer;
473 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
474 &answer);
[b7fd2a0]475 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]476
[15f3c3f]477 loc_exchange_end(exch);
[a35b458]478
[15f3c3f]479 if (retval != EOK) {
[50b581d]480 async_forget(req);
[15f3c3f]481 return retval;
482 }
[a35b458]483
[15f3c3f]484 async_wait_for(req, &retval);
[a35b458]485
[15f3c3f]486 if (retval != EOK) {
487 if (handle != NULL)
488 *handle = (service_id_t) -1;
[a35b458]489
[15f3c3f]490 return retval;
491 }
[a35b458]492
[15f3c3f]493 if (handle != NULL)
494 *handle = (service_id_t) IPC_GET_ARG1(answer);
[a35b458]495
[15f3c3f]496 return retval;
497}
498
[cc574511]499/** Get category ID.
500 *
501 * Provided name of a category, return its ID.
502 *
503 * @param name Category name
504 * @param cat_id Place to store ID
505 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
[cde999a]506 * @return EOK on success or an error code
[cc574511]507 */
[b7fd2a0]508errno_t loc_category_get_id(const char *name, category_id_t *cat_id,
[cc574511]509 unsigned int flags)
510{
511 async_exch_t *exch;
[a35b458]512
[cc574511]513 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]514 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[cc574511]515 else {
[f9b2cb4c]516 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[cc574511]517 if (exch == NULL)
518 return errno;
519 }
[a35b458]520
[cc574511]521 ipc_call_t answer;
522 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
523 &answer);
[b7fd2a0]524 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]525
[cc574511]526 loc_exchange_end(exch);
[a35b458]527
[cc574511]528 if (retval != EOK) {
[50b581d]529 async_forget(req);
[cc574511]530 return retval;
531 }
[a35b458]532
[cc574511]533 async_wait_for(req, &retval);
[a35b458]534
[cc574511]535 if (retval != EOK) {
536 if (cat_id != NULL)
537 *cat_id = (category_id_t) -1;
[a35b458]538
[cc574511]539 return retval;
540 }
[a35b458]541
[cc574511]542 if (cat_id != NULL)
543 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
[a35b458]544
[cc574511]545 return retval;
546}
547
[15f3c3f]548loc_object_type_t loc_id_probe(service_id_t handle)
549{
[f9b2cb4c]550 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]551
[15f3c3f]552 sysarg_t type;
[b7fd2a0]553 errno_t retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
[a35b458]554
[15f3c3f]555 loc_exchange_end(exch);
[a35b458]556
[15f3c3f]557 if (retval != EOK)
558 return LOC_OBJECT_NONE;
[a35b458]559
[15f3c3f]560 return (loc_object_type_t) type;
561}
562
[f9b2cb4c]563async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
[15f3c3f]564 unsigned int flags)
565{
566 async_sess_t *sess;
[a35b458]567
[15f3c3f]568 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]569 sess = service_connect_blocking(SERVICE_LOC, iface, handle);
[15f3c3f]570 else
[f9b2cb4c]571 sess = service_connect(SERVICE_LOC, iface, handle);
[a35b458]572
[15f3c3f]573 return sess;
574}
575
[d5c1051]576/**
577 * @return ID of a new NULL device, or -1 if failed.
578 */
[15f3c3f]579int loc_null_create(void)
580{
[f9b2cb4c]581 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]582
[15f3c3f]583 sysarg_t null_id;
[b7fd2a0]584 errno_t retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
[a35b458]585
[15f3c3f]586 loc_exchange_end(exch);
[a35b458]587
[15f3c3f]588 if (retval != EOK)
589 return -1;
[a35b458]590
[15f3c3f]591 return (int) null_id;
592}
593
594void loc_null_destroy(int null_id)
595{
[f9b2cb4c]596 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]597 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
598 loc_exchange_end(exch);
599}
600
601static size_t loc_count_namespaces_internal(async_exch_t *exch)
602{
603 sysarg_t count;
[b7fd2a0]604 errno_t retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
[15f3c3f]605 if (retval != EOK)
606 return 0;
[a35b458]607
[15f3c3f]608 return count;
609}
610
[cc574511]611/** Add service to category.
612 *
613 * @param svc_id Service ID
614 * @param cat_id Category ID
[cde999a]615 * @return EOK on success or an error code
[cc574511]616 */
[b7fd2a0]617errno_t loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
[cc574511]618{
619 async_exch_t *exch;
[b7fd2a0]620 errno_t retval;
[a35b458]621
[f9b2cb4c]622 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[cc574511]623 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
624 loc_exchange_end(exch);
[a35b458]625
[cc574511]626 return retval;
627}
628
[15f3c3f]629static size_t loc_count_services_internal(async_exch_t *exch,
630 service_id_t ns_handle)
631{
632 sysarg_t count;
[b7fd2a0]633 errno_t retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
[15f3c3f]634 &count);
635 if (retval != EOK)
636 return 0;
[a35b458]637
[15f3c3f]638 return count;
639}
640
641size_t loc_count_namespaces(void)
642{
[f9b2cb4c]643 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]644 size_t size = loc_count_namespaces_internal(exch);
645 loc_exchange_end(exch);
[a35b458]646
[15f3c3f]647 return size;
648}
649
650size_t loc_count_services(service_id_t ns_handle)
651{
[f9b2cb4c]652 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]653 size_t size = loc_count_services_internal(exch, ns_handle);
654 loc_exchange_end(exch);
[a35b458]655
[15f3c3f]656 return size;
657}
658
659size_t loc_get_namespaces(loc_sdesc_t **data)
660{
[cc574511]661 /* Loop until read is succesful */
[15f3c3f]662 while (true) {
[f9b2cb4c]663 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]664 size_t count = loc_count_namespaces_internal(exch);
665 loc_exchange_end(exch);
[a35b458]666
[15f3c3f]667 if (count == 0)
668 return 0;
[a35b458]669
[15f3c3f]670 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
671 if (devs == NULL)
672 return 0;
[a35b458]673
[f9b2cb4c]674 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[a35b458]675
[15f3c3f]676 ipc_call_t answer;
677 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
[b7fd2a0]678 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]679
[15f3c3f]680 loc_exchange_end(exch);
[a35b458]681
[15f3c3f]682 if (rc == EOVERFLOW) {
683 /*
684 * Number of namespaces has changed since
685 * the last call of LOC_GET_NAMESPACE_COUNT
686 */
687 free(devs);
688 continue;
689 }
[a35b458]690
[15f3c3f]691 if (rc != EOK) {
[50b581d]692 async_forget(req);
[15f3c3f]693 free(devs);
694 return 0;
695 }
[a35b458]696
[b7fd2a0]697 errno_t retval;
[15f3c3f]698 async_wait_for(req, &retval);
[a35b458]699
[15f3c3f]700 if (retval != EOK)
701 return 0;
[a35b458]702
[15f3c3f]703 *data = devs;
704 return count;
705 }
706}
707
708size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
709{
[cc574511]710 /* Loop until read is succesful */
[15f3c3f]711 while (true) {
[f9b2cb4c]712 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]713 size_t count = loc_count_services_internal(exch, ns_handle);
714 loc_exchange_end(exch);
[a35b458]715
[15f3c3f]716 if (count == 0)
717 return 0;
[a35b458]718
[15f3c3f]719 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
720 if (devs == NULL)
721 return 0;
[a35b458]722
[f9b2cb4c]723 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[a35b458]724
[15f3c3f]725 ipc_call_t answer;
726 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
[b7fd2a0]727 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]728
[15f3c3f]729 loc_exchange_end(exch);
[a35b458]730
[15f3c3f]731 if (rc == EOVERFLOW) {
732 /*
733 * Number of services has changed since
734 * the last call of LOC_GET_SERVICE_COUNT
735 */
736 free(devs);
737 continue;
738 }
[a35b458]739
[15f3c3f]740 if (rc != EOK) {
[50b581d]741 async_forget(req);
[15f3c3f]742 free(devs);
743 return 0;
744 }
[a35b458]745
[b7fd2a0]746 errno_t retval;
[15f3c3f]747 async_wait_for(req, &retval);
[a35b458]748
[15f3c3f]749 if (retval != EOK)
750 return 0;
[a35b458]751
[15f3c3f]752 *data = devs;
753 return count;
754 }
755}
[cc574511]756
[b7fd2a0]757static errno_t loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
[278ac72]758 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
[cc574511]759{
[f9b2cb4c]760 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[cc574511]761
762 ipc_call_t answer;
[278ac72]763 aid_t req = async_send_1(exch, method, arg1, &answer);
[b7fd2a0]764 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
[a35b458]765
[cc574511]766 loc_exchange_end(exch);
[a35b458]767
[cc574511]768 if (rc != EOK) {
[50b581d]769 async_forget(req);
[cc574511]770 return rc;
771 }
[a35b458]772
[b7fd2a0]773 errno_t retval;
[cc574511]774 async_wait_for(req, &retval);
[a35b458]775
[cc574511]776 if (retval != EOK) {
777 return retval;
778 }
[a35b458]779
[cc574511]780 *act_size = IPC_GET_ARG1(answer);
781 return EOK;
782}
783
[278ac72]784/** Get list of IDs.
[cc574511]785 *
786 * Returns an allocated array of service IDs.
787 *
[278ac72]788 * @param method IPC method
789 * @param arg1 IPC argument 1
[cc574511]790 * @param data Place to store pointer to array of IDs
791 * @param count Place to store number of IDs
[cde999a]792 * @return EOK on success or an error code
[cc574511]793 */
[b7fd2a0]794static errno_t loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
[278ac72]795 sysarg_t **data, size_t *count)
[cc574511]796{
797 *data = NULL;
[88057e3]798 *count = 0;
[a35b458]799
[88057e3]800 size_t act_size = 0;
[b7fd2a0]801 errno_t rc = loc_category_get_ids_once(method, arg1, NULL, 0,
[278ac72]802 &act_size);
[cc574511]803 if (rc != EOK)
804 return rc;
[a35b458]805
[88057e3]806 size_t alloc_size = act_size;
807 service_id_t *ids = malloc(alloc_size);
[cc574511]808 if (ids == NULL)
809 return ENOMEM;
[a35b458]810
[cc574511]811 while (true) {
[278ac72]812 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
[cc574511]813 &act_size);
814 if (rc != EOK)
815 return rc;
[a35b458]816
[c1f27f1d]817 if (act_size <= alloc_size)
[cc574511]818 break;
[a35b458]819
[88057e3]820 alloc_size = act_size;
821 ids = realloc(ids, alloc_size);
[cc574511]822 if (ids == NULL)
823 return ENOMEM;
824 }
[a35b458]825
[cc574511]826 *count = act_size / sizeof(category_id_t);
827 *data = ids;
828 return EOK;
829}
[278ac72]830
831/** Get list of services in category.
832 *
833 * Returns an allocated array of service IDs.
834 *
835 * @param cat_id Category ID
836 * @param data Place to store pointer to array of IDs
837 * @param count Place to store number of IDs
[cde999a]838 * @return EOK on success or an error code
[278ac72]839 */
[b7fd2a0]840errno_t loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
[278ac72]841 size_t *count)
842{
843 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
844 data, count);
845}
846
847/** Get list of categories.
848 *
849 * Returns an allocated array of category IDs.
850 *
851 * @param data Place to store pointer to array of IDs
852 * @param count Place to store number of IDs
[cde999a]853 * @return EOK on success or an error code
[278ac72]854 */
[b7fd2a0]855errno_t loc_get_categories(category_id_t **data, size_t *count)
[278ac72]856{
857 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
858 data, count);
859}
[12f9f0d0]860
[e89a06a]861errno_t loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun, void *cb_arg)
[12f9f0d0]862{
[a6240a31]863 fibril_mutex_lock(&loc_callback_mutex);
[e89a06a]864 if (cat_change_cb != NULL) {
865 fibril_mutex_unlock(&loc_callback_mutex);
866 return EEXIST;
867 }
868
[a6240a31]869 if (loc_callback_create() != EOK) {
870 fibril_mutex_unlock(&loc_callback_mutex);
[12f9f0d0]871 return EIO;
[a6240a31]872 }
[a35b458]873
[12f9f0d0]874 cat_change_cb = cb_fun;
[e89a06a]875 cat_change_arg = cb_arg;
[a6240a31]876 fibril_mutex_unlock(&loc_callback_mutex);
[a35b458]877
[12f9f0d0]878 return EOK;
879}
Note: See TracBrowser for help on using the repository browser.