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
Line 
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
30#include <str.h>
31#include <ipc/services.h>
32#include <ns.h>
33#include <ipc/devmap.h>
34#include <devmap.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(devmap_driver_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(devmap_client_block_mutex);
43
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)
72{
73 switch (iface) {
74 case DEVMAP_DRIVER:
75 fibril_mutex_lock(&devmap_driver_block_mutex);
76
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);
88
89 clone_session(&devmap_driver_mutex, devmap_driver_block_sess,
90 &devmap_driver_sess);
91
92 return async_exchange_begin(devmap_driver_block_sess);
93 case DEVMAP_CLIENT:
94 fibril_mutex_lock(&devmap_client_block_mutex);
95
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);
110
111 return async_exchange_begin(devmap_client_block_sess);
112 default:
113 return NULL;
114 }
115}
116
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)
125{
126 switch (iface) {
127 case DEVMAP_DRIVER:
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);
141 case DEVMAP_CLIENT:
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);
155 default:
156 return NULL;
157 }
158}
159
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
170/** Register new driver with devmap. */
171int devmap_driver_register(const char *name, async_client_conn_t conn)
172{
173 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
174
175 ipc_call_t answer;
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);
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 = devmap_exchange_begin(DEVMAP_DRIVER);
189 async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
190 devmap_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 devmap handle of the device.
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 devmap_device_register_with_iface(const char *fqdn,
211 devmap_handle_t *handle, sysarg_t interface)
212{
213 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
214
215 ipc_call_t answer;
216 aid_t req = async_send_2(exch, DEVMAP_DEVICE_REGISTER, interface, 0,
217 &answer);
218 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
219
220 devmap_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 = (devmap_handle_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 devmap_device_register(const char *fqdn, devmap_handle_t *handle)
249{
250 return devmap_device_register_with_iface(fqdn, handle, 0);
251}
252
253int devmap_device_get_handle(const char *fqdn, devmap_handle_t *handle,
254 unsigned int flags)
255{
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 }
265
266 ipc_call_t answer;
267 aid_t req = async_send_2(exch, DEVMAP_DEVICE_GET_HANDLE, flags, 0,
268 &answer);
269 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
270
271 devmap_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 = (devmap_handle_t) -1;
283
284 return retval;
285 }
286
287 if (handle != NULL)
288 *handle = (devmap_handle_t) IPC_GET_ARG1(answer);
289
290 return retval;
291}
292
293int devmap_namespace_get_handle(const char *name, devmap_handle_t *handle,
294 unsigned int flags)
295{
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 }
305
306 ipc_call_t answer;
307 aid_t req = async_send_2(exch, DEVMAP_NAMESPACE_GET_HANDLE, flags, 0,
308 &answer);
309 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
310
311 devmap_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 = (devmap_handle_t) -1;
323
324 return retval;
325 }
326
327 if (handle != NULL)
328 *handle = (devmap_handle_t) IPC_GET_ARG1(answer);
329
330 return retval;
331}
332
333devmap_handle_type_t devmap_handle_probe(devmap_handle_t handle)
334{
335 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
336
337 sysarg_t type;
338 int retval = async_req_1_1(exch, DEVMAP_HANDLE_PROBE, handle, &type);
339
340 devmap_exchange_end(exch);
341
342 if (retval != EOK)
343 return DEV_HANDLE_NONE;
344
345 return (devmap_handle_type_t) type;
346}
347
348async_sess_t *devmap_device_connect(exch_mgmt_t mgmt, devmap_handle_t handle,
349 unsigned int flags)
350{
351 async_sess_t *sess;
352
353 if (flags & IPC_FLAG_BLOCKING)
354 sess = service_connect_blocking(mgmt, SERVICE_DEVMAP,
355 DEVMAP_CONNECT_TO_DEVICE, handle);
356 else
357 sess = service_connect(mgmt, SERVICE_DEVMAP,
358 DEVMAP_CONNECT_TO_DEVICE, handle);
359
360 return sess;
361}
362
363int devmap_null_create(void)
364{
365 async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
366
367 sysarg_t null_id;
368 int retval = async_req_0_1(exch, DEVMAP_NULL_CREATE, &null_id);
369
370 devmap_exchange_end(exch);
371
372 if (retval != EOK)
373 return -1;
374
375 return (int) null_id;
376}
377
378void devmap_null_destroy(int null_id)
379{
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);
383}
384
385static size_t devmap_count_namespaces_internal(async_exch_t *exch)
386{
387 sysarg_t count;
388 int retval = async_req_0_1(exch, DEVMAP_GET_NAMESPACE_COUNT, &count);
389 if (retval != EOK)
390 return 0;
391
392 return count;
393}
394
395static size_t devmap_count_devices_internal(async_exch_t *exch,
396 devmap_handle_t ns_handle)
397{
398 sysarg_t count;
399 int retval = async_req_1_1(exch, DEVMAP_GET_DEVICE_COUNT, ns_handle,
400 &count);
401 if (retval != EOK)
402 return 0;
403
404 return count;
405}
406
407size_t devmap_count_namespaces(void)
408{
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);
412
413 return size;
414}
415
416size_t devmap_count_devices(devmap_handle_t ns_handle)
417{
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);
421
422 return size;
423}
424
425size_t devmap_get_namespaces(dev_desc_t **data)
426{
427 /* Loop until namespaces read succesful */
428 while (true) {
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
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
440 exch = devmap_exchange_begin(DEVMAP_CLIENT);
441
442 ipc_call_t answer;
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);
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
463 sysarg_t retval;
464 async_wait_for(req, &retval);
465
466 if (retval != EOK)
467 return 0;
468
469 *data = devs;
470 return count;
471 }
472}
473
474size_t devmap_get_devices(devmap_handle_t ns_handle, dev_desc_t **data)
475{
476 /* Loop until devices read succesful */
477 while (true) {
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
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
489 exch = devmap_exchange_begin(DEVMAP_CLIENT);
490
491 ipc_call_t answer;
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);
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
512 sysarg_t retval;
513 async_wait_for(req, &retval);
514
515 if (retval != EOK)
516 return 0;
517
518 *data = devs;
519 return count;
520 }
521}
Note: See TracBrowser for help on using the repository browser.