source: mainline/uspace/lib/c/generic/devmap.c@ 9934f7d

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

Add extra argument to async connection handlers that can be used for passing
information from async_connect_to_me() to the handler.

  • Property mode set to 100644
File size: 12.7 KB
RevLine 
[1090b8c]1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2009 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
[19f857a]30#include <str.h>
[1090b8c]31#include <ipc/services.h>
[79ae36dd]32#include <ns.h>
[1090b8c]33#include <ipc/devmap.h>
34#include <devmap.h>
[79ae36dd]35#include <fibril_synch.h>
[1090b8c]36#include <async.h>
37#include <errno.h>
[1313ee9]38#include <malloc.h>
39#include <bool.h>
[1090b8c]40
[79ae36dd]41static FIBRIL_MUTEX_INITIALIZE(devmap_driver_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(devmap_client_block_mutex);
[1090b8c]43
[79ae36dd]44static FIBRIL_MUTEX_INITIALIZE(devmap_driver_mutex);
45static FIBRIL_MUTEX_INITIALIZE(devmap_client_mutex);
46
47static async_sess_t *devmap_driver_block_sess = NULL;
48static async_sess_t *devmap_client_block_sess = NULL;
49
50static async_sess_t *devmap_driver_sess = NULL;
51static async_sess_t *devmap_client_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 devmap session (blocking).
65 *
66 * @param iface Device mapper interface to choose
67 *
68 * @return New exchange.
69 *
70 */
71async_exch_t *devmap_exchange_begin_blocking(devmap_interface_t iface)
[1090b8c]72{
[cb41a5e]73 switch (iface) {
74 case DEVMAP_DRIVER:
[79ae36dd]75 fibril_mutex_lock(&devmap_driver_block_mutex);
[cb41a5e]76
[79ae36dd]77 while (devmap_driver_block_sess == NULL) {
78 clone_session(&devmap_driver_mutex, devmap_driver_sess,
79 &devmap_driver_block_sess);
80
81 if (devmap_driver_block_sess == NULL)
82 devmap_driver_block_sess =
83 service_connect_blocking(EXCHANGE_SERIALIZE,
84 SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
85 }
86
87 fibril_mutex_unlock(&devmap_driver_block_mutex);
[cb41a5e]88
[79ae36dd]89 clone_session(&devmap_driver_mutex, devmap_driver_block_sess,
90 &devmap_driver_sess);
91
92 return async_exchange_begin(devmap_driver_block_sess);
[cb41a5e]93 case DEVMAP_CLIENT:
[79ae36dd]94 fibril_mutex_lock(&devmap_client_block_mutex);
[cb41a5e]95
[79ae36dd]96 while (devmap_client_block_sess == NULL) {
97 clone_session(&devmap_client_mutex, devmap_client_sess,
98 &devmap_client_block_sess);
99
100 if (devmap_client_block_sess == NULL)
101 devmap_client_block_sess =
102 service_connect_blocking(EXCHANGE_SERIALIZE,
103 SERVICE_DEVMAP, DEVMAP_CLIENT, 0);
104 }
105
106 fibril_mutex_unlock(&devmap_client_block_mutex);
107
108 clone_session(&devmap_client_mutex, devmap_client_block_sess,
109 &devmap_client_sess);
[cb41a5e]110
[79ae36dd]111 return async_exchange_begin(devmap_client_block_sess);
[cb41a5e]112 default:
[79ae36dd]113 return NULL;
[1090b8c]114 }
[cb41a5e]115}
[1090b8c]116
[79ae36dd]117/** Start an async exchange on the devmap session.
118 *
119 * @param iface Device mapper interface to choose
120 *
121 * @return New exchange.
122 *
123 */
124async_exch_t *devmap_exchange_begin(devmap_interface_t iface)
[cb41a5e]125{
126 switch (iface) {
127 case DEVMAP_DRIVER:
[79ae36dd]128 fibril_mutex_lock(&devmap_driver_mutex);
129
130 if (devmap_driver_sess == NULL)
131 devmap_driver_sess =
132 service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAP,
133 DEVMAP_DRIVER, 0);
134
135 fibril_mutex_unlock(&devmap_driver_mutex);
136
137 if (devmap_driver_sess == NULL)
138 return NULL;
139
140 return async_exchange_begin(devmap_driver_sess);
[cb41a5e]141 case DEVMAP_CLIENT:
[79ae36dd]142 fibril_mutex_lock(&devmap_client_mutex);
143
144 if (devmap_client_sess == NULL)
145 devmap_client_sess =
146 service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAP,
147 DEVMAP_CLIENT, 0);
148
149 fibril_mutex_unlock(&devmap_client_mutex);
150
151 if (devmap_client_sess == NULL)
152 return NULL;
153
154 return async_exchange_begin(devmap_client_sess);
[cb41a5e]155 default:
[79ae36dd]156 return NULL;
[cb41a5e]157 }
[1090b8c]158}
159
[79ae36dd]160/** Finish an async exchange on the devmap session.
161 *
162 * @param exch Exchange to be finished.
163 *
164 */
165void devmap_exchange_end(async_exch_t *exch)
166{
167 async_exchange_end(exch);
168}
169
[1090b8c]170/** Register new driver with devmap. */
171int devmap_driver_register(const char *name, async_client_conn_t conn)
172{
[79ae36dd]173 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
[e77994dd]174
[cb41a5e]175 ipc_call_t answer;
[79ae36dd]176 aid_t req = async_send_2(exch, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
177 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
178
179 devmap_exchange_end(exch);
[cb41a5e]180
[1090b8c]181 if (retval != EOK) {
182 async_wait_for(req, NULL);
[79ae36dd]183 return retval;
[1090b8c]184 }
[cb41a5e]185
[1090b8c]186 async_set_client_connection(conn);
[cb41a5e]187
[79ae36dd]188 exch = devmap_exchange_begin(DEVMAP_DRIVER);
[9934f7d]189 async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
[79ae36dd]190 devmap_exchange_end(exch);
[e77994dd]191
[79ae36dd]192 async_wait_for(req, &retval);
[cb41a5e]193 return retval;
[1090b8c]194}
195
[cb41a5e]196/** Register new device.
197 *
[47a7174f]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 devmap handle of the device.
[79ae36dd]201 *
[47a7174f]202 * When the interface is zero (default), the first argument is directly
203 * the handle (to ensure backward compatibility).
204 *
[79ae36dd]205 * @param fqdn Fully qualified device name.
206 * @param[out] handle Handle to the created instance of device.
207 * @param interface Interface when forwarding.
[cb41a5e]208 *
209 */
[47a7174f]210int devmap_device_register_with_iface(const char *fqdn,
211 devmap_handle_t *handle, sysarg_t interface)
[1090b8c]212{
[79ae36dd]213 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
[e77994dd]214
[1090b8c]215 ipc_call_t answer;
[79ae36dd]216 aid_t req = async_send_2(exch, DEVMAP_DEVICE_REGISTER, interface, 0,
[cb41a5e]217 &answer);
[79ae36dd]218 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
219
220 devmap_exchange_end(exch);
[cb41a5e]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;
[79ae36dd]232
[cb41a5e]233 return retval;
234 }
235
236 if (handle != NULL)
[991f645]237 *handle = (devmap_handle_t) IPC_GET_ARG1(answer);
[cb41a5e]238
239 return retval;
240}
[1090b8c]241
[47a7174f]242/** Register new device.
243 *
[79ae36dd]244 * @param fqdn Fully qualified device name.
245 * @param handle Output: Handle to the created instance of device.
[47a7174f]246 *
247 */
248int devmap_device_register(const char *fqdn, devmap_handle_t *handle)
249{
250 return devmap_device_register_with_iface(fqdn, handle, 0);
251}
252
[79ae36dd]253int devmap_device_get_handle(const char *fqdn, devmap_handle_t *handle,
254 unsigned int flags)
[cb41a5e]255{
[79ae36dd]256 async_exch_t *exch;
257
258 if (flags & IPC_FLAG_BLOCKING)
259 exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
260 else {
261 exch = devmap_exchange_begin(DEVMAP_CLIENT);
262 if (exch == NULL)
263 return errno;
264 }
[e77994dd]265
[cb41a5e]266 ipc_call_t answer;
[79ae36dd]267 aid_t req = async_send_2(exch, DEVMAP_DEVICE_GET_HANDLE, flags, 0,
[1090b8c]268 &answer);
[79ae36dd]269 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
270
271 devmap_exchange_end(exch);
[cb41a5e]272
[1313ee9]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)
[991f645]282 *handle = (devmap_handle_t) -1;
[79ae36dd]283
[1313ee9]284 return retval;
285 }
286
287 if (handle != NULL)
[991f645]288 *handle = (devmap_handle_t) IPC_GET_ARG1(answer);
[1313ee9]289
290 return retval;
291}
292
[79ae36dd]293int devmap_namespace_get_handle(const char *name, devmap_handle_t *handle,
294 unsigned int flags)
[1313ee9]295{
[79ae36dd]296 async_exch_t *exch;
297
298 if (flags & IPC_FLAG_BLOCKING)
299 exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
300 else {
301 exch = devmap_exchange_begin(DEVMAP_CLIENT);
302 if (exch == NULL)
303 return errno;
304 }
[1313ee9]305
306 ipc_call_t answer;
[79ae36dd]307 aid_t req = async_send_2(exch, DEVMAP_NAMESPACE_GET_HANDLE, flags, 0,
[1313ee9]308 &answer);
[79ae36dd]309 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
310
311 devmap_exchange_end(exch);
[1313ee9]312
[1090b8c]313 if (retval != EOK) {
314 async_wait_for(req, NULL);
315 return retval;
316 }
[cb41a5e]317
[1090b8c]318 async_wait_for(req, &retval);
[cb41a5e]319
[1090b8c]320 if (retval != EOK) {
321 if (handle != NULL)
[991f645]322 *handle = (devmap_handle_t) -1;
[79ae36dd]323
[1090b8c]324 return retval;
325 }
[cb41a5e]326
[1090b8c]327 if (handle != NULL)
[991f645]328 *handle = (devmap_handle_t) IPC_GET_ARG1(answer);
[cb41a5e]329
[1090b8c]330 return retval;
331}
332
[991f645]333devmap_handle_type_t devmap_handle_probe(devmap_handle_t handle)
[1313ee9]334{
[79ae36dd]335 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
[1313ee9]336
[96b02eb9]337 sysarg_t type;
[79ae36dd]338 int retval = async_req_1_1(exch, DEVMAP_HANDLE_PROBE, handle, &type);
339
340 devmap_exchange_end(exch);
341
[1313ee9]342 if (retval != EOK)
343 return DEV_HANDLE_NONE;
344
345 return (devmap_handle_type_t) type;
346}
347
[79ae36dd]348async_sess_t *devmap_device_connect(exch_mgmt_t mgmt, devmap_handle_t handle,
349 unsigned int flags)
[1090b8c]350{
[79ae36dd]351 async_sess_t *sess;
[cb41a5e]352
[79ae36dd]353 if (flags & IPC_FLAG_BLOCKING)
354 sess = service_connect_blocking(mgmt, SERVICE_DEVMAP,
[1090b8c]355 DEVMAP_CONNECT_TO_DEVICE, handle);
[79ae36dd]356 else
357 sess = service_connect(mgmt, SERVICE_DEVMAP,
[1090b8c]358 DEVMAP_CONNECT_TO_DEVICE, handle);
[cb41a5e]359
[79ae36dd]360 return sess;
[1090b8c]361}
362
[7fcb74c]363int devmap_null_create(void)
364{
[79ae36dd]365 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
[7fcb74c]366
[96b02eb9]367 sysarg_t null_id;
[79ae36dd]368 int retval = async_req_0_1(exch, DEVMAP_NULL_CREATE, &null_id);
369
370 devmap_exchange_end(exch);
371
[7fcb74c]372 if (retval != EOK)
373 return -1;
374
375 return (int) null_id;
376}
377
378void devmap_null_destroy(int null_id)
379{
[79ae36dd]380 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
381 async_req_1_0(exch, DEVMAP_NULL_DESTROY, (sysarg_t) null_id);
382 devmap_exchange_end(exch);
[7fcb74c]383}
384
[79ae36dd]385static size_t devmap_count_namespaces_internal(async_exch_t *exch)
[1090b8c]386{
[96b02eb9]387 sysarg_t count;
[79ae36dd]388 int retval = async_req_0_1(exch, DEVMAP_GET_NAMESPACE_COUNT, &count);
[1313ee9]389 if (retval != EOK)
[cb41a5e]390 return 0;
391
[1313ee9]392 return count;
393}
394
[79ae36dd]395static size_t devmap_count_devices_internal(async_exch_t *exch,
396 devmap_handle_t ns_handle)
[1313ee9]397{
[96b02eb9]398 sysarg_t count;
[79ae36dd]399 int retval = async_req_1_1(exch, DEVMAP_GET_DEVICE_COUNT, ns_handle,
400 &count);
[cb41a5e]401 if (retval != EOK)
402 return 0;
403
404 return count;
405}
[1090b8c]406
[1313ee9]407size_t devmap_count_namespaces(void)
[cb41a5e]408{
[79ae36dd]409 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
410 size_t size = devmap_count_namespaces_internal(exch);
411 devmap_exchange_end(exch);
[cb41a5e]412
[79ae36dd]413 return size;
[1313ee9]414}
415
[991f645]416size_t devmap_count_devices(devmap_handle_t ns_handle)
[1313ee9]417{
[79ae36dd]418 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
419 size_t size = devmap_count_devices_internal(exch, ns_handle);
420 devmap_exchange_end(exch);
[cb41a5e]421
[79ae36dd]422 return size;
[1313ee9]423}
424
425size_t devmap_get_namespaces(dev_desc_t **data)
426{
427 /* Loop until namespaces read succesful */
428 while (true) {
[79ae36dd]429 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
430 size_t count = devmap_count_namespaces_internal(exch);
431 devmap_exchange_end(exch);
432
[1313ee9]433 if (count == 0)
434 return 0;
435
436 dev_desc_t *devs = (dev_desc_t *) calloc(count, sizeof(dev_desc_t));
437 if (devs == NULL)
438 return 0;
439
[79ae36dd]440 exch = devmap_exchange_begin(DEVMAP_CLIENT);
[1313ee9]441
442 ipc_call_t answer;
[79ae36dd]443 aid_t req = async_send_0(exch, DEVMAP_GET_NAMESPACES, &answer);
444 int rc = async_data_read_start(exch, devs, count * sizeof(dev_desc_t));
445
446 devmap_exchange_end(exch);
[1313ee9]447
448 if (rc == EOVERFLOW) {
449 /*
450 * Number of namespaces has changed since
451 * the last call of DEVMAP_DEVICE_GET_NAMESPACE_COUNT
452 */
453 free(devs);
454 continue;
455 }
456
457 if (rc != EOK) {
458 async_wait_for(req, NULL);
459 free(devs);
460 return 0;
461 }
462
[96b02eb9]463 sysarg_t retval;
[1313ee9]464 async_wait_for(req, &retval);
465
466 if (retval != EOK)
467 return 0;
468
469 *data = devs;
470 return count;
471 }
472}
473
[991f645]474size_t devmap_get_devices(devmap_handle_t ns_handle, dev_desc_t **data)
[1313ee9]475{
[79ae36dd]476 /* Loop until devices read succesful */
[1313ee9]477 while (true) {
[79ae36dd]478 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
479 size_t count = devmap_count_devices_internal(exch, ns_handle);
480 devmap_exchange_end(exch);
481
[1313ee9]482 if (count == 0)
483 return 0;
484
485 dev_desc_t *devs = (dev_desc_t *) calloc(count, sizeof(dev_desc_t));
486 if (devs == NULL)
487 return 0;
488
[79ae36dd]489 exch = devmap_exchange_begin(DEVMAP_CLIENT);
[1313ee9]490
491 ipc_call_t answer;
[79ae36dd]492 aid_t req = async_send_1(exch, DEVMAP_GET_DEVICES, ns_handle, &answer);
493 int rc = async_data_read_start(exch, devs, count * sizeof(dev_desc_t));
494
495 devmap_exchange_end(exch);
[1313ee9]496
497 if (rc == EOVERFLOW) {
498 /*
499 * Number of devices has changed since
500 * the last call of DEVMAP_DEVICE_GET_DEVICE_COUNT
501 */
502 free(devs);
503 continue;
504 }
505
506 if (rc != EOK) {
507 async_wait_for(req, NULL);
508 free(devs);
509 return 0;
510 }
511
[96b02eb9]512 sysarg_t retval;
[1313ee9]513 async_wait_for(req, &retval);
514
515 if (retval != EOK)
516 return 0;
517
518 *data = devs;
519 return count;
520 }
[1090b8c]521}
Note: See TracBrowser for help on using the repository browser.