source: mainline/uspace/lib/c/generic/devman.c@ 18ad56a8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 18ad56a8 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 17.4 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
71/** Start an async exchange on the devman session (blocking).
72 *
73 * @param iface Device manager interface to choose
74 *
75 * @return New exchange.
76 *
77 */
78async_exch_t *devman_exchange_begin_blocking(iface_t iface)
79{
80 switch (iface) {
81 case INTERFACE_DDF_DRIVER:
82 fibril_mutex_lock(&devman_driver_block_mutex);
83
84 while (devman_driver_block_sess == NULL) {
85 clone_session(&devman_driver_mutex, devman_driver_sess,
86 &devman_driver_block_sess);
87
88 if (devman_driver_block_sess == NULL)
89 devman_driver_block_sess =
90 service_connect_blocking(SERVICE_DEVMAN,
91 INTERFACE_DDF_DRIVER, 0);
92 }
93
94 fibril_mutex_unlock(&devman_driver_block_mutex);
95
96 clone_session(&devman_driver_mutex, devman_driver_block_sess,
97 &devman_driver_sess);
98
99 return async_exchange_begin(devman_driver_block_sess);
100 case INTERFACE_DDF_CLIENT:
101 fibril_mutex_lock(&devman_client_block_mutex);
102
103 while (devman_client_block_sess == NULL) {
104 clone_session(&devman_client_mutex, devman_client_sess,
105 &devman_client_block_sess);
106
107 if (devman_client_block_sess == NULL)
108 devman_client_block_sess =
109 service_connect_blocking(SERVICE_DEVMAN,
110 INTERFACE_DDF_CLIENT, 0);
111 }
112
113 fibril_mutex_unlock(&devman_client_block_mutex);
114
115 clone_session(&devman_client_mutex, devman_client_block_sess,
116 &devman_client_sess);
117
118 return async_exchange_begin(devman_client_block_sess);
119 default:
120 return NULL;
121 }
122}
123
124/** Start an async exchange on the devman session.
125 *
126 * @param iface Device manager interface to choose
127 *
128 * @return New exchange.
129 *
130 */
131async_exch_t *devman_exchange_begin(iface_t iface)
132{
133 switch (iface) {
134 case INTERFACE_DDF_DRIVER:
135 fibril_mutex_lock(&devman_driver_mutex);
136
137 if (devman_driver_sess == NULL)
138 devman_driver_sess =
139 service_connect(SERVICE_DEVMAN,
140 INTERFACE_DDF_DRIVER, 0);
141
142 fibril_mutex_unlock(&devman_driver_mutex);
143
144 if (devman_driver_sess == NULL)
145 return NULL;
146
147 return async_exchange_begin(devman_driver_sess);
148 case INTERFACE_DDF_CLIENT:
149 fibril_mutex_lock(&devman_client_mutex);
150
151 if (devman_client_sess == NULL)
152 devman_client_sess =
153 service_connect(SERVICE_DEVMAN,
154 INTERFACE_DDF_CLIENT, 0);
155
156 fibril_mutex_unlock(&devman_client_mutex);
157
158 if (devman_client_sess == NULL)
159 return NULL;
160
161 return async_exchange_begin(devman_client_sess);
162 default:
163 return NULL;
164 }
165}
166
167/** Finish an async exchange on the devman session.
168 *
169 * @param exch Exchange to be finished.
170 *
171 */
172void devman_exchange_end(async_exch_t *exch)
173{
174 async_exchange_end(exch);
175}
176
177/** Register running driver with device manager. */
178errno_t devman_driver_register(const char *name)
179{
180 async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
181
182 ipc_call_t answer;
183 aid_t req = async_send_2(exch, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
184 errno_t retval = async_data_write_start(exch, name, str_size(name));
185
186 devman_exchange_end(exch);
187
188 if (retval != EOK) {
189 async_forget(req);
190 return retval;
191 }
192
193 exch = devman_exchange_begin(INTERFACE_DDF_DRIVER);
194 async_connect_to_me(exch, 0, 0, 0);
195 devman_exchange_end(exch);
196
197 async_wait_for(req, &retval);
198 return retval;
199}
200
201/** Add function to a device.
202 *
203 * Request devman to add a new function to the specified device owned by
204 * this driver task.
205 *
206 * @param name Name of the new function
207 * @param ftype Function type, fun_inner or fun_exposed
208 * @param match_ids Match IDs (should be empty for fun_exposed)
209 * @param devh Devman handle of the device
210 * @param funh Place to store handle of the new function
211 *
212 * @return EOK on success or an error code.
213 *
214 */
215errno_t devman_add_function(const char *name, fun_type_t ftype,
216 match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
217{
218 unsigned long match_count = list_count(&match_ids->ids);
219 async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
220
221 ipc_call_t answer;
222 aid_t req = async_send_3(exch, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
223 devh, match_count, &answer);
224 errno_t retval = async_data_write_start(exch, name, str_size(name));
225 if (retval != EOK) {
226 devman_exchange_end(exch);
227 async_forget(req);
228 return retval;
229 }
230
231 list_foreach(match_ids->ids, link, match_id_t, match_id) {
232 ipc_call_t answer2;
233 aid_t req2 = async_send_1(exch, DEVMAN_ADD_MATCH_ID,
234 match_id->score, &answer2);
235 retval = async_data_write_start(exch, match_id->id,
236 str_size(match_id->id));
237 if (retval != EOK) {
238 devman_exchange_end(exch);
239 async_forget(req2);
240 async_forget(req);
241 return retval;
242 }
243
244 async_wait_for(req2, &retval);
245 if (retval != EOK) {
246 devman_exchange_end(exch);
247 async_forget(req);
248 return retval;
249 }
250 }
251
252 devman_exchange_end(exch);
253
254 async_wait_for(req, &retval);
255 if (retval == EOK) {
256 if (funh != NULL)
257 *funh = (int) IPC_GET_ARG1(answer);
258 } else {
259 if (funh != NULL)
260 *funh = -1;
261 }
262
263 return retval;
264}
265
266errno_t devman_add_device_to_category(devman_handle_t devman_handle,
267 const char *cat_name)
268{
269 async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
270
271 ipc_call_t answer;
272 aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CATEGORY,
273 devman_handle, &answer);
274 errno_t retval = async_data_write_start(exch, cat_name,
275 str_size(cat_name));
276
277 devman_exchange_end(exch);
278
279 if (retval != EOK) {
280 async_forget(req);
281 return retval;
282 }
283
284 async_wait_for(req, &retval);
285 return retval;
286}
287
288async_sess_t *devman_device_connect(devman_handle_t handle, unsigned int flags)
289{
290 async_sess_t *sess;
291
292 if (flags & IPC_FLAG_BLOCKING)
293 sess = service_connect_blocking(SERVICE_DEVMAN,
294 INTERFACE_DEVMAN_DEVICE, handle);
295 else
296 sess = service_connect(SERVICE_DEVMAN,
297 INTERFACE_DEVMAN_DEVICE, handle);
298
299 return sess;
300}
301
302/** Remove function from device.
303 *
304 * Request devman to remove function owned by this driver task.
305 * @param funh Devman handle of the function
306 *
307 * @return EOK on success or an error code.
308 */
309errno_t devman_remove_function(devman_handle_t funh)
310{
311 async_exch_t *exch;
312 errno_t retval;
313
314 exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
315 retval = async_req_1_0(exch, DEVMAN_REMOVE_FUNCTION, (sysarg_t) funh);
316 devman_exchange_end(exch);
317
318 return retval;
319}
320
321errno_t devman_drv_fun_online(devman_handle_t funh)
322{
323 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_DRIVER);
324 if (exch == NULL)
325 return ENOMEM;
326
327 errno_t retval = async_req_1_0(exch, DEVMAN_DRV_FUN_ONLINE, funh);
328
329 devman_exchange_end(exch);
330 return retval;
331}
332
333errno_t devman_drv_fun_offline(devman_handle_t funh)
334{
335 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_DRIVER);
336 if (exch == NULL)
337 return ENOMEM;
338
339 errno_t retval = async_req_1_0(exch, DEVMAN_DRV_FUN_OFFLINE, funh);
340
341 devman_exchange_end(exch);
342 return retval;
343}
344
345async_sess_t *devman_parent_device_connect(devman_handle_t handle,
346 unsigned int flags)
347{
348 async_sess_t *sess;
349
350 if (flags & IPC_FLAG_BLOCKING)
351 sess = service_connect_blocking(SERVICE_DEVMAN,
352 INTERFACE_DEVMAN_PARENT, handle);
353 else
354 sess = service_connect_blocking(SERVICE_DEVMAN,
355 INTERFACE_DEVMAN_PARENT, handle);
356
357 return sess;
358}
359
360errno_t devman_fun_get_handle(const char *pathname, devman_handle_t *handle,
361 unsigned int flags)
362{
363 async_exch_t *exch;
364
365 if (flags & IPC_FLAG_BLOCKING)
366 exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
367 else {
368 exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
369 if (exch == NULL)
370 return ENOMEM;
371 }
372
373 ipc_call_t answer;
374 aid_t req = async_send_2(exch, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
375 &answer);
376 errno_t retval = async_data_write_start(exch, pathname,
377 str_size(pathname));
378
379 devman_exchange_end(exch);
380
381 if (retval != EOK) {
382 async_forget(req);
383 return retval;
384 }
385
386 async_wait_for(req, &retval);
387
388 if (retval != EOK) {
389 if (handle != NULL)
390 *handle = (devman_handle_t) -1;
391
392 return retval;
393 }
394
395 if (handle != NULL)
396 *handle = (devman_handle_t) IPC_GET_ARG1(answer);
397
398 return retval;
399}
400
401static errno_t devman_get_str_internal(sysarg_t method, sysarg_t arg1,
402 sysarg_t arg2, sysarg_t *r1, char *buf, size_t buf_size)
403{
404 async_exch_t *exch;
405 ipc_call_t dreply;
406 size_t act_size;
407 errno_t dretval;
408
409 exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
410
411 ipc_call_t answer;
412 aid_t req = async_send_2(exch, method, arg1, arg2, &answer);
413 aid_t dreq = async_data_read(exch, buf, buf_size - 1, &dreply);
414 async_wait_for(dreq, &dretval);
415
416 devman_exchange_end(exch);
417
418 if (dretval != EOK) {
419 async_forget(req);
420 return dretval;
421 }
422
423 errno_t retval;
424 async_wait_for(req, &retval);
425
426 if (retval != EOK) {
427 return retval;
428 }
429
430 if (r1 != NULL)
431 *r1 = IPC_GET_ARG1(answer);
432 act_size = IPC_GET_ARG2(dreply);
433 assert(act_size <= buf_size - 1);
434 buf[act_size] = '\0';
435
436 return EOK;
437}
438
439errno_t devman_fun_get_path(devman_handle_t handle, char *buf, size_t buf_size)
440{
441 return devman_get_str_internal(DEVMAN_FUN_GET_PATH, handle, 0, NULL,
442 buf, buf_size);
443}
444
445errno_t devman_fun_get_match_id(devman_handle_t handle, size_t index, char *buf,
446 size_t buf_size, unsigned int *rscore)
447{
448 errno_t rc;
449 sysarg_t score = 0;
450
451 rc = devman_get_str_internal(DEVMAN_FUN_GET_MATCH_ID, handle, index,
452 &score, buf, buf_size);
453 if (rc != EOK)
454 return rc;
455
456 *rscore = score;
457 return rc;
458}
459
460errno_t devman_fun_get_name(devman_handle_t handle, char *buf, size_t buf_size)
461{
462 return devman_get_str_internal(DEVMAN_FUN_GET_NAME, handle, 0, NULL,
463 buf, buf_size);
464}
465
466errno_t devman_fun_get_driver_name(devman_handle_t handle, char *buf, size_t buf_size)
467{
468 return devman_get_str_internal(DEVMAN_FUN_GET_DRIVER_NAME, handle, 0,
469 NULL, buf, buf_size);
470}
471
472errno_t devman_fun_online(devman_handle_t funh)
473{
474 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
475 if (exch == NULL)
476 return ENOMEM;
477
478 errno_t retval = async_req_1_0(exch, DEVMAN_FUN_ONLINE, funh);
479
480 devman_exchange_end(exch);
481 return retval;
482}
483
484errno_t devman_fun_offline(devman_handle_t funh)
485{
486 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
487 if (exch == NULL)
488 return ENOMEM;
489
490 errno_t retval = async_req_1_0(exch, DEVMAN_FUN_OFFLINE, funh);
491
492 devman_exchange_end(exch);
493 return retval;
494}
495
496static errno_t devman_get_handles_once(sysarg_t method, sysarg_t arg1,
497 devman_handle_t *handle_buf, size_t buf_size, size_t *act_size)
498{
499 async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
500
501 ipc_call_t answer;
502 aid_t req = async_send_1(exch, method, arg1, &answer);
503 errno_t rc = async_data_read_start(exch, handle_buf, buf_size);
504
505 devman_exchange_end(exch);
506
507 if (rc != EOK) {
508 async_forget(req);
509 return rc;
510 }
511
512 errno_t retval;
513 async_wait_for(req, &retval);
514
515 if (retval != EOK) {
516 return retval;
517 }
518
519 *act_size = IPC_GET_ARG1(answer);
520 return EOK;
521}
522
523/** Get list of handles.
524 *
525 * Returns an allocated array of handles.
526 *
527 * @param method IPC method
528 * @param arg1 IPC argument 1
529 * @param data Place to store pointer to array of handles
530 * @param count Place to store number of handles
531 * @return EOK on success or an error code
532 */
533static errno_t devman_get_handles_internal(sysarg_t method, sysarg_t arg1,
534 devman_handle_t **data, size_t *count)
535{
536 devman_handle_t *handles;
537 size_t act_size;
538 size_t alloc_size;
539 errno_t rc;
540
541 *data = NULL;
542 act_size = 0; /* silence warning */
543
544 rc = devman_get_handles_once(method, arg1, NULL, 0,
545 &act_size);
546 if (rc != EOK)
547 return rc;
548
549 alloc_size = act_size;
550 handles = malloc(alloc_size);
551 if (handles == NULL)
552 return ENOMEM;
553
554 while (true) {
555 rc = devman_get_handles_once(method, arg1, handles, alloc_size,
556 &act_size);
557 if (rc != EOK)
558 return rc;
559
560 if (act_size <= alloc_size)
561 break;
562
563 alloc_size *= 2;
564 free(handles);
565
566 handles = malloc(alloc_size);
567 if (handles == NULL)
568 return ENOMEM;
569 }
570
571 *count = act_size / sizeof(devman_handle_t);
572 *data = handles;
573 return EOK;
574}
575
576errno_t devman_fun_get_child(devman_handle_t funh, devman_handle_t *devh)
577{
578 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
579 if (exch == NULL)
580 return ENOMEM;
581
582 errno_t retval = async_req_1_1(exch, DEVMAN_FUN_GET_CHILD,
583 funh, devh);
584
585 devman_exchange_end(exch);
586 return retval;
587}
588
589errno_t devman_dev_get_functions(devman_handle_t devh, devman_handle_t **funcs,
590 size_t *count)
591{
592 return devman_get_handles_internal(DEVMAN_DEV_GET_FUNCTIONS,
593 devh, funcs, count);
594}
595
596errno_t devman_dev_get_parent(devman_handle_t devh, devman_handle_t *funh)
597{
598 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
599 if (exch == NULL)
600 return ENOMEM;
601
602 errno_t retval = async_req_1_1(exch, DEVMAN_DEV_GET_PARENT,
603 devh, funh);
604
605 devman_exchange_end(exch);
606 return retval;
607}
608
609errno_t devman_fun_sid_to_handle(service_id_t sid, devman_handle_t *handle)
610{
611 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
612 if (exch == NULL)
613 return ENOMEM;
614
615 errno_t retval = async_req_1_1(exch, DEVMAN_FUN_SID_TO_HANDLE,
616 sid, handle);
617
618 devman_exchange_end(exch);
619 return retval;
620}
621
622errno_t devman_get_drivers(devman_handle_t **drvs,
623 size_t *count)
624{
625 return devman_get_handles_internal(DEVMAN_GET_DRIVERS, 0, drvs, count);
626}
627
628errno_t devman_driver_get_devices(devman_handle_t drvh, devman_handle_t **devs,
629 size_t *count)
630{
631 return devman_get_handles_internal(DEVMAN_DRIVER_GET_DEVICES,
632 drvh, devs, count);
633}
634
635errno_t devman_driver_get_handle(const char *drvname, devman_handle_t *handle)
636{
637 async_exch_t *exch;
638
639 exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
640 if (exch == NULL)
641 return ENOMEM;
642
643 ipc_call_t answer;
644 aid_t req = async_send_0(exch, DEVMAN_DRIVER_GET_HANDLE, &answer);
645 errno_t retval = async_data_write_start(exch, drvname,
646 str_size(drvname));
647
648 devman_exchange_end(exch);
649
650 if (retval != EOK) {
651 async_forget(req);
652 return retval;
653 }
654
655 async_wait_for(req, &retval);
656
657 if (retval != EOK) {
658 if (handle != NULL)
659 *handle = (devman_handle_t) -1;
660
661 return retval;
662 }
663
664 if (handle != NULL)
665 *handle = (devman_handle_t) IPC_GET_ARG1(answer);
666
667 return retval;
668}
669
670errno_t devman_driver_get_match_id(devman_handle_t handle, size_t index, char *buf,
671 size_t buf_size, unsigned int *rscore)
672{
673 errno_t rc;
674 sysarg_t score = 0;
675
676 rc = devman_get_str_internal(DEVMAN_DRIVER_GET_MATCH_ID, handle, index,
677 &score, buf, buf_size);
678 if (rc != EOK)
679 return rc;
680
681 *rscore = score;
682 return rc;
683}
684
685errno_t devman_driver_get_name(devman_handle_t handle, char *buf, size_t buf_size)
686{
687 return devman_get_str_internal(DEVMAN_DRIVER_GET_NAME, handle, 0, NULL,
688 buf, buf_size);
689}
690
691errno_t devman_driver_get_state(devman_handle_t drvh, driver_state_t *rstate)
692{
693 sysarg_t state;
694 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
695 if (exch == NULL)
696 return ENOMEM;
697
698 errno_t rc = async_req_1_1(exch, DEVMAN_DRIVER_GET_STATE, drvh,
699 &state);
700
701 devman_exchange_end(exch);
702 if (rc != EOK)
703 return rc;
704
705 *rstate = state;
706 return rc;
707}
708
709errno_t devman_driver_load(devman_handle_t drvh)
710{
711 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
712 if (exch == NULL)
713 return ENOMEM;
714
715 errno_t rc = async_req_1_0(exch, DEVMAN_DRIVER_LOAD, drvh);
716
717 devman_exchange_end(exch);
718 return rc;
719}
720
721errno_t devman_driver_unload(devman_handle_t drvh)
722{
723 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
724 if (exch == NULL)
725 return ENOMEM;
726
727 errno_t rc = async_req_1_0(exch, DEVMAN_DRIVER_UNLOAD, drvh);
728
729 devman_exchange_end(exch);
730 return rc;
731}
732
733/** @}
734 */
Note: See TracBrowser for help on using the repository browser.