source: mainline/uspace/lib/c/generic/loc.c@ cc574511

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

Basic category support in location service. Devman adds device services
to categories. Switch over input server device discovery from using
/dev/class to loc categories.

  • Property mode set to 100644
File size: 15.3 KB
Line 
1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2011 Jiri Svoboda
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>
38#include <malloc.h>
39#include <bool.h>
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
47static async_sess_t *loc_supp_block_sess = NULL;
48static async_sess_t *loc_cons_block_sess = NULL;
49
50static async_sess_t *loc_supplier_sess = NULL;
51static async_sess_t *loc_consumer_sess = NULL;
52
53static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
54 async_sess_t **dst)
55{
56 fibril_mutex_lock(mtx);
57
58 if ((*dst == NULL) && (src != NULL))
59 *dst = src;
60
61 fibril_mutex_unlock(mtx);
62}
63
64/** Start an async exchange on the loc session (blocking).
65 *
66 * @param iface Location service interface to choose
67 *
68 * @return New exchange.
69 *
70 */
71async_exch_t *loc_exchange_begin_blocking(loc_interface_t iface)
72{
73 switch (iface) {
74 case LOC_PORT_SUPPLIER:
75 fibril_mutex_lock(&loc_supp_block_mutex);
76
77 while (loc_supp_block_sess == NULL) {
78 clone_session(&loc_supplier_mutex, loc_supplier_sess,
79 &loc_supp_block_sess);
80
81 if (loc_supp_block_sess == NULL)
82 loc_supp_block_sess =
83 service_connect_blocking(EXCHANGE_SERIALIZE,
84 SERVICE_LOC, LOC_PORT_SUPPLIER, 0);
85 }
86
87 fibril_mutex_unlock(&loc_supp_block_mutex);
88
89 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
90 &loc_supplier_sess);
91
92 return async_exchange_begin(loc_supp_block_sess);
93 case LOC_PORT_CONSUMER:
94 fibril_mutex_lock(&loc_cons_block_mutex);
95
96 while (loc_cons_block_sess == NULL) {
97 clone_session(&loc_consumer_mutex, loc_consumer_sess,
98 &loc_cons_block_sess);
99
100 if (loc_cons_block_sess == NULL)
101 loc_cons_block_sess =
102 service_connect_blocking(EXCHANGE_SERIALIZE,
103 SERVICE_LOC, LOC_PORT_CONSUMER, 0);
104 }
105
106 fibril_mutex_unlock(&loc_cons_block_mutex);
107
108 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
109 &loc_consumer_sess);
110
111 return async_exchange_begin(loc_cons_block_sess);
112 default:
113 return NULL;
114 }
115}
116
117/** Start an async exchange on the loc session.
118 *
119 * @param iface Location service interface to choose
120 *
121 * @return New exchange.
122 *
123 */
124async_exch_t *loc_exchange_begin(loc_interface_t iface)
125{
126 switch (iface) {
127 case LOC_PORT_SUPPLIER:
128 fibril_mutex_lock(&loc_supplier_mutex);
129
130 if (loc_supplier_sess == NULL)
131 loc_supplier_sess =
132 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
133 LOC_PORT_SUPPLIER, 0);
134
135 fibril_mutex_unlock(&loc_supplier_mutex);
136
137 if (loc_supplier_sess == NULL)
138 return NULL;
139
140 return async_exchange_begin(loc_supplier_sess);
141 case LOC_PORT_CONSUMER:
142 fibril_mutex_lock(&loc_consumer_mutex);
143
144 if (loc_consumer_sess == NULL)
145 loc_consumer_sess =
146 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
147 LOC_PORT_CONSUMER, 0);
148
149 fibril_mutex_unlock(&loc_consumer_mutex);
150
151 if (loc_consumer_sess == NULL)
152 return NULL;
153
154 return async_exchange_begin(loc_consumer_sess);
155 default:
156 return NULL;
157 }
158}
159
160/** Finish an async exchange on the loc session.
161 *
162 * @param exch Exchange to be finished.
163 *
164 */
165void loc_exchange_end(async_exch_t *exch)
166{
167 async_exchange_end(exch);
168}
169
170/** Register new driver with loc. */
171int loc_server_register(const char *name, async_client_conn_t conn)
172{
173 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
174
175 ipc_call_t answer;
176 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
177 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
178
179 loc_exchange_end(exch);
180
181 if (retval != EOK) {
182 async_wait_for(req, NULL);
183 return retval;
184 }
185
186 async_set_client_connection(conn);
187
188 exch = loc_exchange_begin(LOC_PORT_SUPPLIER);
189 async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
190 loc_exchange_end(exch);
191
192 async_wait_for(req, &retval);
193 return retval;
194}
195
196/** Register new device.
197 *
198 * The @p interface is used when forwarding connection to the driver.
199 * If not 0, the first argument is the interface and the second argument
200 * is the service ID.
201 *
202 * When the interface is zero (default), the first argument is directly
203 * the handle (to ensure backward compatibility).
204 *
205 * @param fqdn Fully qualified device name.
206 * @param[out] handle Handle to the created instance of device.
207 * @param interface Interface when forwarding.
208 *
209 */
210int loc_service_register_with_iface(const char *fqdn,
211 service_id_t *handle, sysarg_t interface)
212{
213 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
214
215 ipc_call_t answer;
216 aid_t req = async_send_2(exch, LOC_SERVICE_REGISTER, interface, 0,
217 &answer);
218 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
219
220 loc_exchange_end(exch);
221
222 if (retval != EOK) {
223 async_wait_for(req, NULL);
224 return retval;
225 }
226
227 async_wait_for(req, &retval);
228
229 if (retval != EOK) {
230 if (handle != NULL)
231 *handle = -1;
232
233 return retval;
234 }
235
236 if (handle != NULL)
237 *handle = (service_id_t) IPC_GET_ARG1(answer);
238
239 return retval;
240}
241
242/** Register new device.
243 *
244 * @param fqdn Fully qualified device name.
245 * @param handle Output: Handle to the created instance of device.
246 *
247 */
248int loc_service_register(const char *fqdn, service_id_t *handle)
249{
250 return loc_service_register_with_iface(fqdn, handle, 0);
251}
252
253int loc_service_get_id(const char *fqdn, service_id_t *handle,
254 unsigned int flags)
255{
256 async_exch_t *exch;
257
258 if (flags & IPC_FLAG_BLOCKING)
259 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
260 else {
261 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
262 if (exch == NULL)
263 return errno;
264 }
265
266 ipc_call_t answer;
267 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
268 &answer);
269 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
270
271 loc_exchange_end(exch);
272
273 if (retval != EOK) {
274 async_wait_for(req, NULL);
275 return retval;
276 }
277
278 async_wait_for(req, &retval);
279
280 if (retval != EOK) {
281 if (handle != NULL)
282 *handle = (service_id_t) -1;
283
284 return retval;
285 }
286
287 if (handle != NULL)
288 *handle = (service_id_t) IPC_GET_ARG1(answer);
289
290 return retval;
291}
292
293int loc_namespace_get_id(const char *name, service_id_t *handle,
294 unsigned int flags)
295{
296 async_exch_t *exch;
297
298 if (flags & IPC_FLAG_BLOCKING)
299 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
300 else {
301 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
302 if (exch == NULL)
303 return errno;
304 }
305
306 ipc_call_t answer;
307 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
308 &answer);
309 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
310
311 loc_exchange_end(exch);
312
313 if (retval != EOK) {
314 async_wait_for(req, NULL);
315 return retval;
316 }
317
318 async_wait_for(req, &retval);
319
320 if (retval != EOK) {
321 if (handle != NULL)
322 *handle = (service_id_t) -1;
323
324 return retval;
325 }
326
327 if (handle != NULL)
328 *handle = (service_id_t) IPC_GET_ARG1(answer);
329
330 return retval;
331}
332
333/** Get category ID.
334 *
335 * Provided name of a category, return its ID.
336 *
337 * @param name Category name
338 * @param cat_id Place to store ID
339 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
340 * @return EOK on success or negative error code
341 */
342int loc_category_get_id(const char *name, category_id_t *cat_id,
343 unsigned int flags)
344{
345 async_exch_t *exch;
346
347 if (flags & IPC_FLAG_BLOCKING)
348 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
349 else {
350 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
351 if (exch == NULL)
352 return errno;
353 }
354
355 ipc_call_t answer;
356 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
357 &answer);
358 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
359
360 loc_exchange_end(exch);
361
362 if (retval != EOK) {
363 async_wait_for(req, NULL);
364 return retval;
365 }
366
367 async_wait_for(req, &retval);
368
369 if (retval != EOK) {
370 if (cat_id != NULL)
371 *cat_id = (category_id_t) -1;
372
373 return retval;
374 }
375
376 if (cat_id != NULL)
377 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
378
379 return retval;
380}
381
382
383loc_object_type_t loc_id_probe(service_id_t handle)
384{
385 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
386
387 sysarg_t type;
388 int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
389
390 loc_exchange_end(exch);
391
392 if (retval != EOK)
393 return LOC_OBJECT_NONE;
394
395 return (loc_object_type_t) type;
396}
397
398async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
399 unsigned int flags)
400{
401 async_sess_t *sess;
402
403 if (flags & IPC_FLAG_BLOCKING)
404 sess = service_connect_blocking(mgmt, SERVICE_LOC,
405 LOC_CONNECT_TO_SERVICE, handle);
406 else
407 sess = service_connect(mgmt, SERVICE_LOC,
408 LOC_CONNECT_TO_SERVICE, handle);
409
410 return sess;
411}
412
413int loc_null_create(void)
414{
415 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
416
417 sysarg_t null_id;
418 int retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
419
420 loc_exchange_end(exch);
421
422 if (retval != EOK)
423 return -1;
424
425 return (int) null_id;
426}
427
428void loc_null_destroy(int null_id)
429{
430 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
431 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
432 loc_exchange_end(exch);
433}
434
435static size_t loc_count_namespaces_internal(async_exch_t *exch)
436{
437 sysarg_t count;
438 int retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
439 if (retval != EOK)
440 return 0;
441
442 return count;
443}
444
445/** Add service to category.
446 *
447 * @param svc_id Service ID
448 * @param cat_id Category ID
449 * @return EOK on success or negative error code
450 */
451int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
452{
453 async_exch_t *exch;
454 sysarg_t retval;
455
456 exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
457 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
458 loc_exchange_end(exch);
459
460 return retval;
461}
462
463static size_t loc_count_services_internal(async_exch_t *exch,
464 service_id_t ns_handle)
465{
466 sysarg_t count;
467 int retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
468 &count);
469 if (retval != EOK)
470 return 0;
471
472 return count;
473}
474
475size_t loc_count_namespaces(void)
476{
477 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
478 size_t size = loc_count_namespaces_internal(exch);
479 loc_exchange_end(exch);
480
481 return size;
482}
483
484size_t loc_count_services(service_id_t ns_handle)
485{
486 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
487 size_t size = loc_count_services_internal(exch, ns_handle);
488 loc_exchange_end(exch);
489
490 return size;
491}
492
493size_t loc_get_namespaces(loc_sdesc_t **data)
494{
495 /* Loop until read is succesful */
496 while (true) {
497 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
498 size_t count = loc_count_namespaces_internal(exch);
499 loc_exchange_end(exch);
500
501 if (count == 0)
502 return 0;
503
504 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
505 if (devs == NULL)
506 return 0;
507
508 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
509
510 ipc_call_t answer;
511 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
512 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
513
514 loc_exchange_end(exch);
515
516 if (rc == EOVERFLOW) {
517 /*
518 * Number of namespaces has changed since
519 * the last call of LOC_GET_NAMESPACE_COUNT
520 */
521 free(devs);
522 continue;
523 }
524
525 if (rc != EOK) {
526 async_wait_for(req, NULL);
527 free(devs);
528 return 0;
529 }
530
531 sysarg_t retval;
532 async_wait_for(req, &retval);
533
534 if (retval != EOK)
535 return 0;
536
537 *data = devs;
538 return count;
539 }
540}
541
542size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
543{
544 /* Loop until read is succesful */
545 while (true) {
546 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
547 size_t count = loc_count_services_internal(exch, ns_handle);
548 loc_exchange_end(exch);
549
550 if (count == 0)
551 return 0;
552
553 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
554 if (devs == NULL)
555 return 0;
556
557 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
558
559 ipc_call_t answer;
560 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
561 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
562
563 loc_exchange_end(exch);
564
565 if (rc == EOVERFLOW) {
566 /*
567 * Number of services has changed since
568 * the last call of LOC_GET_SERVICE_COUNT
569 */
570 free(devs);
571 continue;
572 }
573
574 if (rc != EOK) {
575 async_wait_for(req, NULL);
576 free(devs);
577 return 0;
578 }
579
580 sysarg_t retval;
581 async_wait_for(req, &retval);
582
583 if (retval != EOK)
584 return 0;
585
586 *data = devs;
587 return count;
588 }
589}
590
591static int loc_category_get_svcs_internal(category_id_t cat_id,
592 service_id_t *id_buf, size_t buf_size, size_t *act_size)
593{
594 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
595
596 ipc_call_t answer;
597 aid_t req = async_send_1(exch, LOC_CATEGORY_GET_SVCS, cat_id,
598 &answer);
599 int rc = async_data_read_start(exch, id_buf, buf_size);
600
601 loc_exchange_end(exch);
602
603 if (rc != EOK) {
604 async_wait_for(req, NULL);
605 return rc;
606 }
607
608 sysarg_t retval;
609 async_wait_for(req, &retval);
610
611 if (retval != EOK) {
612 return retval;
613 }
614
615 *act_size = IPC_GET_ARG1(answer);
616 return EOK;
617}
618
619/** Get list of services in category.
620 *
621 * Returns an allocated array of service IDs.
622 *
623 * @param cat_id Category ID
624 * @param data Place to store pointer to array of IDs
625 * @param count Place to store number of IDs
626 * @return EOK on success or negative error code
627 */
628int loc_category_get_svcs(category_id_t cat_id, category_id_t **data,
629 size_t *count)
630{
631 service_id_t *ids;
632 size_t act_size;
633 size_t alloc_size;
634 int rc;
635
636 *data = NULL;
637 act_size = 0; /* silence warning */
638
639 rc = loc_category_get_svcs_internal(cat_id, NULL, 0, &act_size);
640 if (rc != EOK)
641 return rc;
642
643 alloc_size = act_size;
644 ids = malloc(alloc_size);
645 if (ids == NULL)
646 return ENOMEM;
647
648 while (true) {
649 rc = loc_category_get_svcs_internal(cat_id, ids, alloc_size,
650 &act_size);
651 if (rc != EOK)
652 return rc;
653
654 if (act_size <= alloc_size)
655 break;
656
657 alloc_size *= 2;
658 free(ids);
659
660 ids = malloc(alloc_size);
661 if (ids == NULL)
662 return ENOMEM;
663 }
664
665 *count = act_size / sizeof(category_id_t);
666 *data = ids;
667 return EOK;
668}
Note: See TracBrowser for help on using the repository browser.