source: mainline/uspace/lib/c/generic/devman.c@ 95faa4d

Last change on this file since 95faa4d was 95faa4d, checked in by Jiří Zárevúcky <jiri.zarevucky@…>, 7 years ago

Convert a bit of devman.

  • Property mode set to 100644
File size: 16.8 KB
Line 
1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2013 Jiri Svoboda
4 * Copyright (c) 2010 Lenka Trochtova
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libc
32 * @{
33 */
34/** @file
35 */
36
37#include <adt/list.h>
38#include <str.h>
39#include <ipc/services.h>
40#include <ns.h>
41#include <ipc/devman.h>
42#include <devman.h>
43#include <fibril_synch.h>
44#include <async.h>
45#include <errno.h>
46#include <stdlib.h>
47
48static FIBRIL_MUTEX_INITIALIZE(devman_driver_block_mutex);
49static FIBRIL_MUTEX_INITIALIZE(devman_client_block_mutex);
50
51static FIBRIL_MUTEX_INITIALIZE(devman_driver_mutex);
52static FIBRIL_MUTEX_INITIALIZE(devman_client_mutex);
53
54static async_sess_t *devman_driver_block_sess = NULL;
55static async_sess_t *devman_client_block_sess = NULL;
56
57static async_sess_t *devman_driver_sess = NULL;
58static async_sess_t *devman_client_sess = NULL;
59
60static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
61 async_sess_t **dst)
62{
63 fibril_mutex_lock(mtx);
64
65 if ((*dst == NULL) && (src != NULL))
66 *dst = src;
67
68 fibril_mutex_unlock(mtx);
69}
70
71static async_sess_t *devman_session_blocking(iface_t iface)
72{
73 switch (iface) {
74 case INTERFACE_DDF_DRIVER:
75 fibril_mutex_lock(&devman_driver_block_mutex);
76
77 while (devman_driver_block_sess == NULL) {
78 clone_session(&devman_driver_mutex, devman_driver_sess,
79 &devman_driver_block_sess);
80
81 if (devman_driver_block_sess == NULL)
82 devman_driver_block_sess =
83 service_connect_blocking(SERVICE_DEVMAN,
84 INTERFACE_DDF_DRIVER, 0);
85 }
86
87 fibril_mutex_unlock(&devman_driver_block_mutex);
88
89 clone_session(&devman_driver_mutex, devman_driver_block_sess,
90 &devman_driver_sess);
91
92 return devman_driver_block_sess;
93 case INTERFACE_DDF_CLIENT:
94 fibril_mutex_lock(&devman_client_block_mutex);
95
96 while (devman_client_block_sess == NULL) {
97 clone_session(&devman_client_mutex, devman_client_sess,
98 &devman_client_block_sess);
99
100 if (devman_client_block_sess == NULL)
101 devman_client_block_sess =
102 service_connect_blocking(SERVICE_DEVMAN,
103 INTERFACE_DDF_CLIENT, 0);
104 }
105
106 fibril_mutex_unlock(&devman_client_block_mutex);
107
108 clone_session(&devman_client_mutex, devman_client_block_sess,
109 &devman_client_sess);
110
111 return devman_client_block_sess;
112 default:
113 return NULL;
114 }
115}
116
117/** Start an async exchange on the devman session (blocking).
118 *
119 * @param iface Device manager interface to choose
120 *
121 * @return New exchange.
122 *
123 */
124async_exch_t *devman_exchange_begin_blocking(iface_t iface)
125{
126 async_sess_t *sess = devman_session_blocking(iface);
127 if (!sess)
128 return NULL;
129 return async_exchange_begin(sess);
130}
131
132static async_sess_t *devman_session(iface_t iface)
133{
134 switch (iface) {
135 case INTERFACE_DDF_DRIVER:
136 fibril_mutex_lock(&devman_driver_mutex);
137
138 if (devman_driver_sess == NULL)
139 devman_driver_sess =
140 service_connect(SERVICE_DEVMAN,
141 INTERFACE_DDF_DRIVER, 0);
142
143 fibril_mutex_unlock(&devman_driver_mutex);
144
145 if (devman_driver_sess == NULL)
146 return NULL;
147
148 return devman_driver_sess;
149 case INTERFACE_DDF_CLIENT:
150 fibril_mutex_lock(&devman_client_mutex);
151
152 if (devman_client_sess == NULL)
153 devman_client_sess =
154 service_connect(SERVICE_DEVMAN,
155 INTERFACE_DDF_CLIENT, 0);
156
157 fibril_mutex_unlock(&devman_client_mutex);
158
159 if (devman_client_sess == NULL)
160 return NULL;
161
162 return devman_client_sess;
163 default:
164 return NULL;
165 }
166}
167
168/** Start an async exchange on the devman session.
169 *
170 * @param iface Device manager interface to choose
171 *
172 * @return New exchange.
173 *
174 */
175async_exch_t *devman_exchange_begin(iface_t iface)
176{
177 async_sess_t *sess = devman_session(iface);
178 if (!sess)
179 return NULL;
180 return async_exchange_begin(sess);
181}
182
183/** Finish an async exchange on the devman session.
184 *
185 * @param exch Exchange to be finished.
186 *
187 */
188void devman_exchange_end(async_exch_t *exch)
189{
190 async_exchange_end(exch);
191}
192
193/** Register running driver with device manager. */
194errno_t devman_driver_register(const char *name)
195{
196 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_DRIVER);
197
198 async_call_t call;
199 async_call_data_t write, connect;
200
201 async_call_begin(&call, sess, DEVMAN_DRIVER_REGISTER, 0, 0, 0, 0);
202 async_call_write(&call, &write, name, str_size(name), NULL);
203 async_call_connect_to_me(&call, &connect, 0, 0, 0);
204
205 return async_call_finish(&call);
206}
207
208/** Add function to a device.
209 *
210 * Request devman to add a new function to the specified device owned by
211 * this driver task.
212 *
213 * @param name Name of the new function
214 * @param ftype Function type, fun_inner or fun_exposed
215 * @param match_ids Match IDs (should be empty for fun_exposed)
216 * @param devh Devman handle of the device
217 * @param funh Place to store handle of the new function
218 *
219 * @return EOK on success or an error code.
220 *
221 */
222errno_t devman_add_function(const char *name, fun_type_t ftype,
223 match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
224{
225 unsigned long match_count = list_count(&match_ids->ids);
226
227 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_DRIVER);
228
229 async_call_t call;
230 async_call_data_t write1, method_n, write_n;
231
232 async_call_begin(&call, sess, DEVMAN_ADD_FUNCTION,
233 (sysarg_t) ftype, devh, match_count, 0);
234
235 async_call_write(&call, &write1, name, str_size(name), NULL);
236
237 list_foreach(match_ids->ids, link, match_id_t, match_id) {
238 async_call_method(&call, &method_n, DEVMAN_ADD_MATCH_ID,
239 match_id->score, 0, 0, 0);
240
241 async_call_write(&call, &write_n,
242 match_id->id, str_size(match_id->id), NULL);
243
244 /* Wait so that we can recycle `method_n` and `write_n`. */
245 (void) async_call_wait(&call);
246 }
247
248 errno_t rc = async_call_finish(&call);
249
250 if (funh) {
251 if (rc == EOK) {
252 *funh = (devman_handle_t)
253 IPC_GET_ARG1(call.initial.answer);
254 } else {
255 *funh = -1;
256 }
257 }
258
259 return rc;
260}
261
262errno_t devman_add_device_to_category(devman_handle_t devman_handle,
263 const char *cat_name)
264{
265 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_DRIVER);
266
267 async_call_t call;
268 async_call_data_t write;
269
270 async_call_begin(&call, sess, DEVMAN_ADD_DEVICE_TO_CATEGORY, devman_handle, 0, 0, 0);
271 async_call_write(&call, &write, cat_name, str_size(cat_name), NULL);
272 return async_call_finish(&call);
273}
274
275async_sess_t *devman_device_connect(devman_handle_t handle, unsigned int flags)
276{
277 async_sess_t *sess;
278
279 if (flags & IPC_FLAG_BLOCKING)
280 sess = service_connect_blocking(SERVICE_DEVMAN,
281 INTERFACE_DEVMAN_DEVICE, handle);
282 else
283 sess = service_connect(SERVICE_DEVMAN,
284 INTERFACE_DEVMAN_DEVICE, handle);
285
286 return sess;
287}
288
289/** Remove function from device.
290 *
291 * Request devman to remove function owned by this driver task.
292 * @param funh Devman handle of the function
293 *
294 * @return EOK on success or an error code.
295 */
296errno_t devman_remove_function(devman_handle_t funh)
297{
298 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_DRIVER);
299
300 async_call_t call;
301 async_call_begin(&call, sess, DEVMAN_REMOVE_FUNCTION, funh, 0, 0, 0);
302 return async_call_finish(&call);
303}
304
305errno_t devman_drv_fun_online(devman_handle_t funh)
306{
307 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_DRIVER);
308
309 async_call_t call;
310 async_call_begin(&call, sess, DEVMAN_DRV_FUN_ONLINE, funh, 0, 0, 0);
311 return async_call_finish(&call);
312}
313
314errno_t devman_drv_fun_offline(devman_handle_t funh)
315{
316 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_DRIVER);
317
318 async_call_t call;
319 async_call_begin(&call, sess, DEVMAN_DRV_FUN_OFFLINE, funh, 0, 0, 0);
320 return async_call_finish(&call);
321}
322
323async_sess_t *devman_parent_device_connect(devman_handle_t handle,
324 unsigned int flags)
325{
326 async_sess_t *sess;
327
328 if (flags & IPC_FLAG_BLOCKING)
329 sess = service_connect_blocking(SERVICE_DEVMAN,
330 INTERFACE_DEVMAN_PARENT, handle);
331 else
332 sess = service_connect_blocking(SERVICE_DEVMAN,
333 INTERFACE_DEVMAN_PARENT, handle);
334
335 return sess;
336}
337
338errno_t devman_fun_get_handle(const char *pathname, devman_handle_t *handle,
339 unsigned int flags)
340{
341 async_sess_t *sess;
342 async_call_t call;
343 async_call_data_t write;
344
345 if (flags & IPC_FLAG_BLOCKING)
346 sess = devman_session_blocking(INTERFACE_DDF_CLIENT);
347 else
348 sess = devman_session(INTERFACE_DDF_CLIENT);
349
350 async_call_begin(&call, sess, DEVMAN_DEVICE_GET_HANDLE, flags, 0, 0, 0);
351 async_call_write(&call, &write, pathname, str_size(pathname), NULL);
352 errno_t rc = async_call_finish(&call);
353
354 if (rc != EOK) {
355 if (handle != NULL)
356 *handle = (devman_handle_t) -1;
357
358 return rc;
359 }
360
361 if (handle != NULL)
362 *handle = (devman_handle_t) IPC_GET_ARG1(call.initial.answer);
363
364 return EOK;
365}
366
367static errno_t devman_get_str_internal(sysarg_t method, sysarg_t arg1,
368 sysarg_t arg2, sysarg_t *r1, char *buf, size_t buf_size)
369{
370 async_call_t call;
371 async_call_data_t read;
372 size_t act_size;
373
374 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_CLIENT);
375
376 async_call_begin(&call, sess, method, arg1, arg2, 0, 0);
377 async_call_read(&call, &read, buf, buf_size - 1, &act_size);
378 errno_t rc = async_call_finish(&call);
379 if (rc != EOK)
380 return rc;
381
382 if (r1 != NULL)
383 *r1 = IPC_GET_ARG1(call.initial.answer);
384
385 assert(act_size <= buf_size - 1);
386 buf[act_size] = '\0';
387 return EOK;
388}
389
390errno_t devman_fun_get_path(devman_handle_t handle, char *buf, size_t buf_size)
391{
392 return devman_get_str_internal(DEVMAN_FUN_GET_PATH, handle, 0, NULL,
393 buf, buf_size);
394}
395
396errno_t devman_fun_get_match_id(devman_handle_t handle, size_t index, char *buf,
397 size_t buf_size, unsigned int *rscore)
398{
399 errno_t rc;
400 sysarg_t score = 0;
401
402 rc = devman_get_str_internal(DEVMAN_FUN_GET_MATCH_ID, handle, index,
403 &score, buf, buf_size);
404 if (rc != EOK)
405 return rc;
406
407 *rscore = score;
408 return rc;
409}
410
411errno_t devman_fun_get_name(devman_handle_t handle, char *buf, size_t buf_size)
412{
413 return devman_get_str_internal(DEVMAN_FUN_GET_NAME, handle, 0, NULL,
414 buf, buf_size);
415}
416
417errno_t devman_fun_get_driver_name(devman_handle_t handle, char *buf, size_t buf_size)
418{
419 return devman_get_str_internal(DEVMAN_FUN_GET_DRIVER_NAME, handle, 0,
420 NULL, buf, buf_size);
421}
422
423errno_t devman_fun_online(devman_handle_t funh)
424{
425 async_sess_t *sess = devman_session(INTERFACE_DDF_CLIENT);
426
427 async_call_t call;
428 async_call_begin(&call, sess, DEVMAN_FUN_ONLINE, funh, 0, 0, 0);
429 return async_call_finish(&call);
430}
431
432errno_t devman_fun_offline(devman_handle_t funh)
433{
434 async_sess_t *sess = devman_session(INTERFACE_DDF_CLIENT);
435
436 async_call_t call;
437 async_call_begin(&call, sess, DEVMAN_FUN_OFFLINE, funh, 0, 0, 0);
438 return async_call_finish(&call);
439}
440
441static errno_t devman_get_handles_once(sysarg_t method, sysarg_t arg1,
442 devman_handle_t *handle_buf, size_t buf_size, size_t *act_size)
443{
444 async_sess_t *sess = devman_session_blocking(INTERFACE_DDF_CLIENT);
445
446 async_call_t call;
447 async_call_data_t read;
448
449 async_call_begin(&call, sess, method, arg1, 0, 0, 0);
450 async_call_read(&call, &read, handle_buf, buf_size, NULL);
451 errno_t rc = async_call_finish(&call);
452 if (rc != EOK)
453 return rc;
454
455 *act_size = IPC_GET_ARG1(call.initial.answer);
456 return EOK;
457}
458
459/** Get list of handles.
460 *
461 * Returns an allocated array of handles.
462 *
463 * @param method IPC method
464 * @param arg1 IPC argument 1
465 * @param data Place to store pointer to array of handles
466 * @param count Place to store number of handles
467 * @return EOK on success or an error code
468 */
469static errno_t devman_get_handles_internal(sysarg_t method, sysarg_t arg1,
470 devman_handle_t **data, size_t *count)
471{
472 devman_handle_t *handles;
473 size_t act_size;
474 size_t alloc_size;
475 errno_t rc;
476
477 *data = NULL;
478 act_size = 0; /* silence warning */
479
480 rc = devman_get_handles_once(method, arg1, NULL, 0,
481 &act_size);
482 if (rc != EOK)
483 return rc;
484
485 alloc_size = act_size;
486 handles = malloc(alloc_size);
487 if (handles == NULL)
488 return ENOMEM;
489
490 while (true) {
491 rc = devman_get_handles_once(method, arg1, handles, alloc_size,
492 &act_size);
493 if (rc != EOK)
494 return rc;
495
496 if (act_size <= alloc_size)
497 break;
498
499 alloc_size *= 2;
500 free(handles);
501
502 handles = malloc(alloc_size);
503 if (handles == NULL)
504 return ENOMEM;
505 }
506
507 *count = act_size / sizeof(devman_handle_t);
508 *data = handles;
509 return EOK;
510}
511
512errno_t devman_fun_get_child(devman_handle_t funh, devman_handle_t *devh)
513{
514 async_sess_t *sess = devman_session(INTERFACE_DDF_CLIENT);
515
516 async_call_t call;
517 async_call_begin(&call, sess, DEVMAN_FUN_GET_CHILD, funh, 0, 0, 0);
518 errno_t rc = async_call_finish(&call);
519 if (rc != EOK)
520 return rc;
521
522 *devh = (devman_handle_t) IPC_GET_ARG1(call.initial.answer);
523 return EOK;
524}
525
526errno_t devman_dev_get_functions(devman_handle_t devh, devman_handle_t **funcs,
527 size_t *count)
528{
529 return devman_get_handles_internal(DEVMAN_DEV_GET_FUNCTIONS,
530 devh, funcs, count);
531}
532
533errno_t devman_dev_get_parent(devman_handle_t devh, devman_handle_t *funh)
534{
535 async_sess_t *sess = devman_session(INTERFACE_DDF_CLIENT);
536
537 async_call_t call;
538 async_call_begin(&call, sess, DEVMAN_DEV_GET_PARENT, devh, 0, 0, 0);
539 errno_t rc = async_call_finish(&call);
540 if (rc != EOK)
541 return rc;
542
543 *funh = (devman_handle_t) IPC_GET_ARG1(call.initial.answer);
544 return EOK;
545}
546
547errno_t devman_fun_sid_to_handle(service_id_t sid, devman_handle_t *handle)
548{
549 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
550 if (exch == NULL)
551 return ENOMEM;
552
553 errno_t retval = async_req_1_1(exch, DEVMAN_FUN_SID_TO_HANDLE,
554 sid, handle);
555
556 devman_exchange_end(exch);
557 return retval;
558}
559
560errno_t devman_get_drivers(devman_handle_t **drvs,
561 size_t *count)
562{
563 return devman_get_handles_internal(DEVMAN_GET_DRIVERS, 0, drvs, count);
564}
565
566errno_t devman_driver_get_devices(devman_handle_t drvh, devman_handle_t **devs,
567 size_t *count)
568{
569 return devman_get_handles_internal(DEVMAN_DRIVER_GET_DEVICES,
570 drvh, devs, count);
571}
572
573errno_t devman_driver_get_handle(const char *drvname, devman_handle_t *handle)
574{
575 async_exch_t *exch;
576
577 exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
578 if (exch == NULL)
579 return ENOMEM;
580
581 ipc_call_t answer;
582 aid_t req = async_send_0(exch, DEVMAN_DRIVER_GET_HANDLE, &answer);
583 errno_t retval = async_data_write_start(exch, drvname,
584 str_size(drvname));
585
586 devman_exchange_end(exch);
587
588 if (retval != EOK) {
589 async_forget(req);
590 return retval;
591 }
592
593 async_wait_for(req, &retval);
594
595 if (retval != EOK) {
596 if (handle != NULL)
597 *handle = (devman_handle_t) -1;
598
599 return retval;
600 }
601
602 if (handle != NULL)
603 *handle = (devman_handle_t) IPC_GET_ARG1(answer);
604
605 return retval;
606}
607
608errno_t devman_driver_get_match_id(devman_handle_t handle, size_t index, char *buf,
609 size_t buf_size, unsigned int *rscore)
610{
611 errno_t rc;
612 sysarg_t score = 0;
613
614 rc = devman_get_str_internal(DEVMAN_DRIVER_GET_MATCH_ID, handle, index,
615 &score, buf, buf_size);
616 if (rc != EOK)
617 return rc;
618
619 *rscore = score;
620 return rc;
621}
622
623errno_t devman_driver_get_name(devman_handle_t handle, char *buf, size_t buf_size)
624{
625 return devman_get_str_internal(DEVMAN_DRIVER_GET_NAME, handle, 0, NULL,
626 buf, buf_size);
627}
628
629errno_t devman_driver_get_state(devman_handle_t drvh, driver_state_t *rstate)
630{
631 sysarg_t state;
632 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
633 if (exch == NULL)
634 return ENOMEM;
635
636 errno_t rc = async_req_1_1(exch, DEVMAN_DRIVER_GET_STATE, drvh,
637 &state);
638
639 devman_exchange_end(exch);
640 if (rc != EOK)
641 return rc;
642
643 *rstate = state;
644 return rc;
645}
646
647errno_t devman_driver_load(devman_handle_t drvh)
648{
649 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
650 if (exch == NULL)
651 return ENOMEM;
652
653 errno_t rc = async_req_1_0(exch, DEVMAN_DRIVER_LOAD, drvh);
654
655 devman_exchange_end(exch);
656 return rc;
657}
658
659errno_t devman_driver_unload(devman_handle_t drvh)
660{
661 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
662 if (exch == NULL)
663 return ENOMEM;
664
665 errno_t rc = async_req_1_0(exch, DEVMAN_DRIVER_UNLOAD, drvh);
666
667 devman_exchange_end(exch);
668 return rc;
669}
670
671/** @}
672 */
Note: See TracBrowser for help on using the repository browser.