source: mainline/uspace/lib/device/src/devman.c@ accdf882

Last change on this file since accdf882 was 832cbe7, checked in by Jiri Svoboda <jiri@…>, 5 months ago

Add proper IDE PCI to ISA fallback mechanism.

To determine if legacy IDE I/O ports are free, isa-ide asks isa,
who asks pciintel. pciintel waits for bus enumeration to complete,
then waits for all functions except the one who is asking
(which is ISA bus) to stabilize. During attach pci-ide will claim
the legacy IDE ports. Thus, if at this point legacy IDE ports
are unclaimed, pciintel tells ISA they are free, which tells isa-ide,
which continues to attach. If they are not free, isa-ide will not
attach.

This works for all use cases, including system without PCI bus,
system with PCI bus, but no (or disabled) PCI IDE, system with PCI
IDE with unrecognized VID/PID (which we will handle in legacy ISA mode).

  • Property mode set to 100644
File size: 17.7 KB
Line 
1/*
2 * Copyright (c) 2025 Jiri Svoboda
3 * Copyright (c) 2007 Josef Cejka
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 libdevice
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, NULL);
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, NULL);
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, NULL);
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, NULL);
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, INTERFACE_ANY, 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, NULL);
295 else
296 sess = service_connect(SERVICE_DEVMAN,
297 INTERFACE_DEVMAN_DEVICE, handle, NULL);
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
345errno_t devman_drv_fun_wait_stable(devman_handle_t funh)
346{
347 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_DRIVER);
348 if (exch == NULL)
349 return ENOMEM;
350
351 errno_t retval = async_req_1_0(exch, DEVMAN_DRV_FUN_WAIT_STABLE, funh);
352
353 devman_exchange_end(exch);
354 return retval;
355}
356
357async_sess_t *devman_parent_device_connect(devman_handle_t handle,
358 unsigned int flags)
359{
360 async_sess_t *sess;
361
362 if (flags & IPC_FLAG_BLOCKING)
363 sess = service_connect_blocking(SERVICE_DEVMAN,
364 INTERFACE_DEVMAN_PARENT, handle, NULL);
365 else
366 sess = service_connect(SERVICE_DEVMAN,
367 INTERFACE_DEVMAN_PARENT, handle, NULL);
368
369 return sess;
370}
371
372errno_t devman_fun_get_handle(const char *pathname, devman_handle_t *handle,
373 unsigned int flags)
374{
375 async_exch_t *exch;
376
377 if (flags & IPC_FLAG_BLOCKING)
378 exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
379 else {
380 exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
381 if (exch == NULL)
382 return ENOMEM;
383 }
384
385 ipc_call_t answer;
386 aid_t req = async_send_2(exch, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
387 &answer);
388 errno_t retval = async_data_write_start(exch, pathname,
389 str_size(pathname));
390
391 devman_exchange_end(exch);
392
393 if (retval != EOK) {
394 async_forget(req);
395 return retval;
396 }
397
398 async_wait_for(req, &retval);
399
400 if (retval != EOK) {
401 if (handle != NULL)
402 *handle = (devman_handle_t) -1;
403
404 return retval;
405 }
406
407 if (handle != NULL)
408 *handle = (devman_handle_t) ipc_get_arg1(&answer);
409
410 return retval;
411}
412
413static errno_t devman_get_str_internal(sysarg_t method, sysarg_t arg1,
414 sysarg_t arg2, sysarg_t *r1, char *buf, size_t buf_size)
415{
416 async_exch_t *exch;
417 ipc_call_t dreply;
418 size_t act_size;
419 errno_t dretval;
420
421 exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
422
423 ipc_call_t answer;
424 aid_t req = async_send_2(exch, method, arg1, arg2, &answer);
425 aid_t dreq = async_data_read(exch, buf, buf_size - 1, &dreply);
426 async_wait_for(dreq, &dretval);
427
428 devman_exchange_end(exch);
429
430 if (dretval != EOK) {
431 async_forget(req);
432 return dretval;
433 }
434
435 errno_t retval;
436 async_wait_for(req, &retval);
437
438 if (retval != EOK) {
439 return retval;
440 }
441
442 if (r1 != NULL)
443 *r1 = ipc_get_arg1(&answer);
444 act_size = ipc_get_arg2(&dreply);
445 assert(act_size <= buf_size - 1);
446 buf[act_size] = '\0';
447
448 return EOK;
449}
450
451errno_t devman_fun_get_path(devman_handle_t handle, char *buf, size_t buf_size)
452{
453 return devman_get_str_internal(DEVMAN_FUN_GET_PATH, handle, 0, NULL,
454 buf, buf_size);
455}
456
457errno_t devman_fun_get_match_id(devman_handle_t handle, size_t index, char *buf,
458 size_t buf_size, unsigned int *rscore)
459{
460 errno_t rc;
461 sysarg_t score = 0;
462
463 rc = devman_get_str_internal(DEVMAN_FUN_GET_MATCH_ID, handle, index,
464 &score, buf, buf_size);
465 if (rc != EOK)
466 return rc;
467
468 *rscore = score;
469 return rc;
470}
471
472errno_t devman_fun_get_name(devman_handle_t handle, char *buf, size_t buf_size)
473{
474 return devman_get_str_internal(DEVMAN_FUN_GET_NAME, handle, 0, NULL,
475 buf, buf_size);
476}
477
478errno_t devman_fun_get_driver_name(devman_handle_t handle, char *buf, size_t buf_size)
479{
480 return devman_get_str_internal(DEVMAN_FUN_GET_DRIVER_NAME, handle, 0,
481 NULL, buf, buf_size);
482}
483
484errno_t devman_fun_online(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_ONLINE, funh);
491
492 devman_exchange_end(exch);
493 return retval;
494}
495
496errno_t devman_fun_offline(devman_handle_t funh)
497{
498 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
499 if (exch == NULL)
500 return ENOMEM;
501
502 errno_t retval = async_req_1_0(exch, DEVMAN_FUN_OFFLINE, funh);
503
504 devman_exchange_end(exch);
505 return retval;
506}
507
508static errno_t devman_get_handles_once(sysarg_t method, sysarg_t arg1,
509 devman_handle_t *handle_buf, size_t buf_size, size_t *act_size)
510{
511 async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
512
513 ipc_call_t answer;
514 aid_t req = async_send_1(exch, method, arg1, &answer);
515 errno_t rc = async_data_read_start(exch, handle_buf, buf_size);
516
517 devman_exchange_end(exch);
518
519 if (rc != EOK) {
520 async_forget(req);
521 return rc;
522 }
523
524 errno_t retval;
525 async_wait_for(req, &retval);
526
527 if (retval != EOK) {
528 return retval;
529 }
530
531 *act_size = ipc_get_arg1(&answer);
532 return EOK;
533}
534
535/** Get list of handles.
536 *
537 * Returns an allocated array of handles.
538 *
539 * @param method IPC method
540 * @param arg1 IPC argument 1
541 * @param data Place to store pointer to array of handles
542 * @param count Place to store number of handles
543 * @return EOK on success or an error code
544 */
545static errno_t devman_get_handles_internal(sysarg_t method, sysarg_t arg1,
546 devman_handle_t **data, size_t *count)
547{
548 devman_handle_t *handles;
549 size_t act_size;
550 size_t alloc_size;
551 errno_t rc;
552
553 *data = NULL;
554 act_size = 0; /* silence warning */
555
556 rc = devman_get_handles_once(method, arg1, NULL, 0,
557 &act_size);
558 if (rc != EOK)
559 return rc;
560
561 alloc_size = act_size;
562 handles = malloc(alloc_size);
563 if (handles == NULL)
564 return ENOMEM;
565
566 while (true) {
567 rc = devman_get_handles_once(method, arg1, handles, alloc_size,
568 &act_size);
569 if (rc != EOK)
570 return rc;
571
572 if (act_size <= alloc_size)
573 break;
574
575 alloc_size *= 2;
576 free(handles);
577
578 handles = malloc(alloc_size);
579 if (handles == NULL)
580 return ENOMEM;
581 }
582
583 *count = act_size / sizeof(devman_handle_t);
584 *data = handles;
585 return EOK;
586}
587
588errno_t devman_fun_get_child(devman_handle_t funh, devman_handle_t *devh)
589{
590 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
591 if (exch == NULL)
592 return ENOMEM;
593
594 errno_t retval = async_req_1_1(exch, DEVMAN_FUN_GET_CHILD,
595 funh, devh);
596
597 devman_exchange_end(exch);
598 return retval;
599}
600
601errno_t devman_dev_get_functions(devman_handle_t devh, devman_handle_t **funcs,
602 size_t *count)
603{
604 return devman_get_handles_internal(DEVMAN_DEV_GET_FUNCTIONS,
605 devh, funcs, count);
606}
607
608errno_t devman_dev_get_parent(devman_handle_t devh, devman_handle_t *funh)
609{
610 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
611 if (exch == NULL)
612 return ENOMEM;
613
614 errno_t retval = async_req_1_1(exch, DEVMAN_DEV_GET_PARENT,
615 devh, funh);
616
617 devman_exchange_end(exch);
618 return retval;
619}
620
621errno_t devman_fun_sid_to_handle(service_id_t sid, devman_handle_t *handle)
622{
623 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
624 if (exch == NULL)
625 return ENOMEM;
626
627 errno_t retval = async_req_1_1(exch, DEVMAN_FUN_SID_TO_HANDLE,
628 sid, handle);
629
630 devman_exchange_end(exch);
631 return retval;
632}
633
634errno_t devman_get_drivers(devman_handle_t **drvs,
635 size_t *count)
636{
637 return devman_get_handles_internal(DEVMAN_GET_DRIVERS, 0, drvs, count);
638}
639
640errno_t devman_driver_get_devices(devman_handle_t drvh, devman_handle_t **devs,
641 size_t *count)
642{
643 return devman_get_handles_internal(DEVMAN_DRIVER_GET_DEVICES,
644 drvh, devs, count);
645}
646
647errno_t devman_driver_get_handle(const char *drvname, devman_handle_t *handle)
648{
649 async_exch_t *exch;
650
651 exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
652 if (exch == NULL)
653 return ENOMEM;
654
655 ipc_call_t answer;
656 aid_t req = async_send_0(exch, DEVMAN_DRIVER_GET_HANDLE, &answer);
657 errno_t retval = async_data_write_start(exch, drvname,
658 str_size(drvname));
659
660 devman_exchange_end(exch);
661
662 if (retval != EOK) {
663 async_forget(req);
664 return retval;
665 }
666
667 async_wait_for(req, &retval);
668
669 if (retval != EOK) {
670 if (handle != NULL)
671 *handle = (devman_handle_t) -1;
672
673 return retval;
674 }
675
676 if (handle != NULL)
677 *handle = (devman_handle_t) ipc_get_arg1(&answer);
678
679 return retval;
680}
681
682errno_t devman_driver_get_match_id(devman_handle_t handle, size_t index, char *buf,
683 size_t buf_size, unsigned int *rscore)
684{
685 errno_t rc;
686 sysarg_t score = 0;
687
688 rc = devman_get_str_internal(DEVMAN_DRIVER_GET_MATCH_ID, handle, index,
689 &score, buf, buf_size);
690 if (rc != EOK)
691 return rc;
692
693 *rscore = score;
694 return rc;
695}
696
697errno_t devman_driver_get_name(devman_handle_t handle, char *buf, size_t buf_size)
698{
699 return devman_get_str_internal(DEVMAN_DRIVER_GET_NAME, handle, 0, NULL,
700 buf, buf_size);
701}
702
703errno_t devman_driver_get_state(devman_handle_t drvh, driver_state_t *rstate)
704{
705 sysarg_t state;
706 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
707 if (exch == NULL)
708 return ENOMEM;
709
710 errno_t rc = async_req_1_1(exch, DEVMAN_DRIVER_GET_STATE, drvh,
711 &state);
712
713 devman_exchange_end(exch);
714 if (rc != EOK)
715 return rc;
716
717 *rstate = state;
718 return rc;
719}
720
721errno_t devman_driver_load(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_LOAD, drvh);
728
729 devman_exchange_end(exch);
730 return rc;
731}
732
733errno_t devman_driver_unload(devman_handle_t drvh)
734{
735 async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
736 if (exch == NULL)
737 return ENOMEM;
738
739 errno_t rc = async_req_1_0(exch, DEVMAN_DRIVER_UNLOAD, drvh);
740
741 devman_exchange_end(exch);
742 return rc;
743}
744
745/** @}
746 */
Note: See TracBrowser for help on using the repository browser.