source: mainline/uspace/srv/devman/driver.c@ 76f566d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 76f566d 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: 19.4 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup devman
30 * @{
31 */
32
33#include <dirent.h>
34#include <errno.h>
35#include <io/log.h>
36#include <vfs/vfs.h>
37#include <loc.h>
38#include <str_error.h>
39#include <stdio.h>
40#include <task.h>
41
42#include "dev.h"
43#include "devman.h"
44#include "driver.h"
45#include "match.h"
46
47/**
48 * Initialize the list of device driver's.
49 *
50 * @param drv_list the list of device driver's.
51 *
52 */
53void init_driver_list(driver_list_t *drv_list)
54{
55 assert(drv_list != NULL);
56
57 list_initialize(&drv_list->drivers);
58 fibril_mutex_initialize(&drv_list->drivers_mutex);
59 drv_list->next_handle = 1;
60}
61
62/** Allocate and initialize a new driver structure.
63 *
64 * @return Driver structure.
65 */
66driver_t *create_driver(void)
67{
68 driver_t *res = malloc(sizeof(driver_t));
69 if (res != NULL)
70 init_driver(res);
71 return res;
72}
73
74/** Add a driver to the list of drivers.
75 *
76 * @param drivers_list List of drivers.
77 * @param drv Driver structure.
78 */
79void add_driver(driver_list_t *drivers_list, driver_t *drv)
80{
81 fibril_mutex_lock(&drivers_list->drivers_mutex);
82 list_append(&drv->drivers, &drivers_list->drivers);
83 drv->handle = drivers_list->next_handle++;
84 fibril_mutex_unlock(&drivers_list->drivers_mutex);
85
86 log_msg(LOG_DEFAULT, LVL_DEBUG, "Driver `%s' was added to the list of available "
87 "drivers.", drv->name);
88}
89
90/**
91 * Get information about a driver.
92 *
93 * Each driver has its own directory in the base directory.
94 * The name of the driver's directory is the same as the name of the driver.
95 * The driver's directory contains driver's binary (named as the driver without
96 * extension) and the configuration file with match ids for device-to-driver
97 * matching (named as the driver with a special extension).
98 *
99 * This function searches for the driver's directory and containing
100 * configuration files. If all the files needed are found, they are parsed and
101 * the information about the driver is stored in the driver's structure.
102 *
103 * @param base_path The base directory, in which we look for driver's
104 * subdirectory.
105 * @param name The name of the driver.
106 * @param drv The driver structure to fill information in.
107 *
108 * @return True on success, false otherwise.
109 */
110bool get_driver_info(const char *base_path, const char *name, driver_t *drv)
111{
112 log_msg(LOG_DEFAULT, LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
113 base_path, name);
114
115 assert(base_path != NULL && name != NULL && drv != NULL);
116
117 bool suc = false;
118 char *match_path = NULL;
119 size_t name_size = 0;
120
121 /* Read the list of match ids from the driver's configuration file. */
122 match_path = get_abs_path(base_path, name, MATCH_EXT);
123 if (match_path == NULL)
124 goto cleanup;
125
126 if (!read_match_ids(match_path, &drv->match_ids))
127 goto cleanup;
128
129 /* Allocate and fill driver's name. */
130 name_size = str_size(name) + 1;
131 drv->name = malloc(name_size);
132 if (drv->name == NULL)
133 goto cleanup;
134 str_cpy(drv->name, name_size, name);
135
136 /* Initialize path with driver's binary. */
137 drv->binary_path = get_abs_path(base_path, name, "");
138 if (drv->binary_path == NULL)
139 goto cleanup;
140
141 /* Check whether the driver's binary exists. */
142 vfs_stat_t s;
143 if (vfs_stat_path(drv->binary_path, &s) != EOK) {
144 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver not found at path `%s'.",
145 drv->binary_path);
146 goto cleanup;
147 }
148
149 suc = true;
150
151cleanup:
152 if (!suc) {
153 free(drv->binary_path);
154 free(drv->name);
155 /* Set the driver structure to the default state. */
156 init_driver(drv);
157 }
158
159 free(match_path);
160
161 return suc;
162}
163
164/** Lookup drivers in the directory.
165 *
166 * @param drivers_list The list of available drivers.
167 * @param dir_path The path to the directory where we search for drivers.
168 * @return Number of drivers which were found.
169 */
170int lookup_available_drivers(driver_list_t *drivers_list, const char *dir_path)
171{
172 log_msg(LOG_DEFAULT, LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
173
174 int drv_cnt = 0;
175 DIR *dir = NULL;
176 struct dirent *diren;
177
178 dir = opendir(dir_path);
179
180 if (dir != NULL) {
181 driver_t *drv = create_driver();
182 while ((diren = readdir(dir))) {
183 if (get_driver_info(dir_path, diren->d_name, drv)) {
184 add_driver(drivers_list, drv);
185 drv_cnt++;
186 drv = create_driver();
187 }
188 }
189 delete_driver(drv);
190 closedir(dir);
191 }
192
193 return drv_cnt;
194}
195
196/** Lookup the best matching driver for the specified device in the list of
197 * drivers.
198 *
199 * A match between a device and a driver is found if one of the driver's match
200 * ids match one of the device's match ids. The score of the match is the
201 * product of the driver's and device's score associated with the matching id.
202 * The best matching driver for a device is the driver with the highest score
203 * of the match between the device and the driver.
204 *
205 * @param drivers_list The list of drivers, where we look for the driver
206 * suitable for handling the device.
207 * @param node The device node structure of the device.
208 * @return The best matching driver or NULL if no matching driver
209 * is found.
210 */
211driver_t *find_best_match_driver(driver_list_t *drivers_list, dev_node_t *node)
212{
213 driver_t *best_drv = NULL;
214 int best_score = 0, score = 0;
215
216 fibril_mutex_lock(&drivers_list->drivers_mutex);
217
218 list_foreach(drivers_list->drivers, drivers, driver_t, drv) {
219 score = get_match_score(drv, node);
220 if (score > best_score) {
221 best_score = score;
222 best_drv = drv;
223 }
224 }
225
226 fibril_mutex_unlock(&drivers_list->drivers_mutex);
227
228 return best_drv;
229}
230
231/** Assign a driver to a device.
232 *
233 * @param tree Device tree
234 * @param node The device's node in the device tree.
235 * @param drv The driver.
236 */
237void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
238{
239 log_msg(LOG_DEFAULT, LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
240 dev->pfun->pathname, drv->name);
241
242 fibril_mutex_lock(&drv->driver_mutex);
243 fibril_rwlock_write_lock(&tree->rwlock);
244
245 dev->drv = drv;
246 list_append(&dev->driver_devices, &drv->devices);
247
248 fibril_rwlock_write_unlock(&tree->rwlock);
249 fibril_mutex_unlock(&drv->driver_mutex);
250}
251
252/** Detach driver from device.
253 *
254 * @param tree Device tree
255 * @param node The device's node in the device tree.
256 * @param drv The driver.
257 */
258void detach_driver(dev_tree_t *tree, dev_node_t *dev)
259{
260 driver_t *drv = dev->drv;
261
262 assert(drv != NULL);
263
264 log_msg(LOG_DEFAULT, LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
265 dev->pfun->pathname, drv->name);
266
267 fibril_mutex_lock(&drv->driver_mutex);
268 fibril_rwlock_write_lock(&tree->rwlock);
269
270 dev->drv = NULL;
271 list_remove(&dev->driver_devices);
272
273 fibril_rwlock_write_unlock(&tree->rwlock);
274 fibril_mutex_unlock(&drv->driver_mutex);
275}
276
277/** Start a driver
278 *
279 * @param drv The driver's structure.
280 * @return True if the driver's task is successfully spawned, false
281 * otherwise.
282 */
283bool start_driver(driver_t *drv)
284{
285 errno_t rc;
286
287 assert(fibril_mutex_is_locked(&drv->driver_mutex));
288
289 log_msg(LOG_DEFAULT, LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
290
291 rc = task_spawnl(NULL, NULL, drv->binary_path, drv->binary_path, NULL);
292 if (rc != EOK) {
293 log_msg(LOG_DEFAULT, LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
294 drv->name, drv->binary_path, str_error(rc));
295 return false;
296 }
297
298 drv->state = DRIVER_STARTING;
299 return true;
300}
301
302/** Stop a driver
303 *
304 * @param drv The driver's structure.
305 * @return True if the driver's task is successfully spawned, false
306 * otherwise.
307 */
308errno_t stop_driver(driver_t *drv)
309{
310 async_exch_t *exch;
311 errno_t retval;
312
313 log_msg(LOG_DEFAULT, LVL_DEBUG, "stop_driver(drv=\"%s\")", drv->name);
314
315 exch = async_exchange_begin(drv->sess);
316 retval = async_req_0_0(exch, DRIVER_STOP);
317 loc_exchange_end(exch);
318
319 if (retval != EOK)
320 return retval;
321
322 drv->state = DRIVER_NOT_STARTED;
323 async_hangup(drv->sess);
324 drv->sess = NULL;
325 return EOK;
326}
327
328/** Find device driver by handle.
329 *
330 * @param drv_list The list of device drivers
331 * @param handle Driver handle
332 * @return The device driver, if it is in the list,
333 * NULL otherwise.
334 */
335driver_t *driver_find(driver_list_t *drv_list, devman_handle_t handle)
336{
337 driver_t *res = NULL;
338
339 fibril_mutex_lock(&drv_list->drivers_mutex);
340
341 list_foreach(drv_list->drivers, drivers, driver_t, drv) {
342 if (drv->handle == handle) {
343 res = drv;
344 break;
345 }
346 }
347
348 fibril_mutex_unlock(&drv_list->drivers_mutex);
349
350 return res;
351}
352
353
354/** Find device driver by name.
355 *
356 * @param drv_list The list of device drivers.
357 * @param drv_name The name of the device driver which is searched.
358 * @return The device driver of the specified name, if it is in the
359 * list, NULL otherwise.
360 */
361driver_t *driver_find_by_name(driver_list_t *drv_list, const char *drv_name)
362{
363 driver_t *res = NULL;
364
365 fibril_mutex_lock(&drv_list->drivers_mutex);
366
367 list_foreach(drv_list->drivers, drivers, driver_t, drv) {
368 if (str_cmp(drv->name, drv_name) == 0) {
369 res = drv;
370 break;
371 }
372 }
373
374 fibril_mutex_unlock(&drv_list->drivers_mutex);
375
376 return res;
377}
378
379/** Notify driver about the devices to which it was assigned.
380 *
381 * @param driver The driver to which the devices are passed.
382 */
383static void pass_devices_to_driver(driver_t *driver, dev_tree_t *tree)
384{
385 dev_node_t *dev;
386 link_t *link;
387
388 log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
389 driver->name);
390
391 fibril_mutex_lock(&driver->driver_mutex);
392
393 /*
394 * Go through devices list as long as there is some device
395 * that has not been passed to the driver.
396 */
397 link = driver->devices.head.next;
398 while (link != &driver->devices.head) {
399 dev = list_get_instance(link, dev_node_t, driver_devices);
400 fibril_rwlock_write_lock(&tree->rwlock);
401
402 if (dev->passed_to_driver) {
403 fibril_rwlock_write_unlock(&tree->rwlock);
404 link = link->next;
405 continue;
406 }
407
408 log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
409 (int)atomic_get(&dev->refcnt));
410 dev_add_ref(dev);
411
412 /*
413 * Unlock to avoid deadlock when adding device
414 * handled by itself.
415 */
416 fibril_mutex_unlock(&driver->driver_mutex);
417 fibril_rwlock_write_unlock(&tree->rwlock);
418
419 add_device(driver, dev, tree);
420
421 dev_del_ref(dev);
422
423 /*
424 * Lock again as we will work with driver's
425 * structure.
426 */
427 fibril_mutex_lock(&driver->driver_mutex);
428
429 /*
430 * Restart the cycle to go through all devices again.
431 */
432 link = driver->devices.head.next;
433 }
434
435 /*
436 * Once we passed all devices to the driver, we need to mark the
437 * driver as running.
438 * It is vital to do it here and inside critical section.
439 *
440 * If we would change the state earlier, other devices added to
441 * the driver would be added to the device list and started
442 * immediately and possibly started here as well.
443 */
444 log_msg(LOG_DEFAULT, LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
445 driver->state = DRIVER_RUNNING;
446
447 fibril_mutex_unlock(&driver->driver_mutex);
448}
449
450/** Finish the initialization of a driver after it has succesfully started
451 * and after it has registered itself by the device manager.
452 *
453 * Pass devices formerly matched to the driver to the driver and remember the
454 * driver is running and fully functional now.
455 *
456 * @param driver The driver which registered itself as running by the
457 * device manager.
458 */
459void initialize_running_driver(driver_t *driver, dev_tree_t *tree)
460{
461 log_msg(LOG_DEFAULT, LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
462 driver->name);
463
464 /*
465 * Pass devices which have been already assigned to the driver to the
466 * driver.
467 */
468 pass_devices_to_driver(driver, tree);
469}
470
471/** Initialize device driver structure.
472 *
473 * @param drv The device driver structure.
474 */
475void init_driver(driver_t *drv)
476{
477 assert(drv != NULL);
478
479 memset(drv, 0, sizeof(driver_t));
480 list_initialize(&drv->match_ids.ids);
481 list_initialize(&drv->devices);
482 fibril_mutex_initialize(&drv->driver_mutex);
483 drv->sess = NULL;
484}
485
486/** Device driver structure clean-up.
487 *
488 * @param drv The device driver structure.
489 */
490void clean_driver(driver_t *drv)
491{
492 assert(drv != NULL);
493
494 free(drv->name);
495 free(drv->binary_path);
496
497 clean_match_ids(&drv->match_ids);
498
499 init_driver(drv);
500}
501
502/** Delete device driver structure.
503 *
504 * @param drv The device driver structure.
505 */
506void delete_driver(driver_t *drv)
507{
508 assert(drv != NULL);
509
510 clean_driver(drv);
511 free(drv);
512}
513
514/** Find suitable driver for a device and assign the driver to it.
515 *
516 * @param node The device node of the device in the device tree.
517 * @param drivers_list The list of available drivers.
518 * @return True if the suitable driver is found and
519 * successfully assigned to the device, false otherwise.
520 */
521bool assign_driver(dev_node_t *dev, driver_list_t *drivers_list,
522 dev_tree_t *tree)
523{
524 assert(dev != NULL);
525 assert(drivers_list != NULL);
526 assert(tree != NULL);
527
528 /*
529 * Find the driver which is the most suitable for handling this device.
530 */
531 driver_t *drv = find_best_match_driver(drivers_list, dev);
532 if (drv == NULL) {
533 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver found for device `%s'.",
534 dev->pfun->pathname);
535 return false;
536 }
537
538 /* Attach the driver to the device. */
539 attach_driver(tree, dev, drv);
540
541 fibril_mutex_lock(&drv->driver_mutex);
542 if (drv->state == DRIVER_NOT_STARTED) {
543 /* Start the driver. */
544 start_driver(drv);
545 }
546 bool is_running = drv->state == DRIVER_RUNNING;
547 fibril_mutex_unlock(&drv->driver_mutex);
548
549 /* Notify the driver about the new device. */
550 if (is_running)
551 add_device(drv, dev, tree);
552
553 fibril_mutex_lock(&drv->driver_mutex);
554 fibril_mutex_unlock(&drv->driver_mutex);
555
556 fibril_rwlock_write_lock(&tree->rwlock);
557 if (dev->pfun != NULL) {
558 dev->pfun->state = FUN_ON_LINE;
559 }
560 fibril_rwlock_write_unlock(&tree->rwlock);
561 return true;
562}
563
564/** Pass a device to running driver.
565 *
566 * @param drv The driver's structure.
567 * @param node The device's node in the device tree.
568 */
569void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
570{
571 /*
572 * We do not expect to have driver's mutex locked as we do not
573 * access any structures that would affect driver_t.
574 */
575 log_msg(LOG_DEFAULT, LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
576 drv->name, dev->pfun->name);
577
578 /* Send the device to the driver. */
579 devman_handle_t parent_handle;
580 if (dev->pfun) {
581 parent_handle = dev->pfun->handle;
582 } else {
583 parent_handle = 0;
584 }
585
586 async_exch_t *exch = async_exchange_begin(drv->sess);
587
588 ipc_call_t answer;
589 aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
590 parent_handle, &answer);
591
592 /* Send the device name to the driver. */
593 errno_t rc = async_data_write_start(exch, dev->pfun->name,
594 str_size(dev->pfun->name) + 1);
595
596 async_exchange_end(exch);
597
598 if (rc != EOK) {
599 async_forget(req);
600 } else {
601 /* Wait for answer from the driver. */
602 async_wait_for(req, &rc);
603 }
604
605 switch (rc) {
606 case EOK:
607 dev->state = DEVICE_USABLE;
608 break;
609 case ENOENT:
610 dev->state = DEVICE_NOT_PRESENT;
611 break;
612 default:
613 dev->state = DEVICE_INVALID;
614 break;
615 }
616
617 dev->passed_to_driver = true;
618}
619
620errno_t driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
621{
622 async_exch_t *exch;
623 errno_t retval;
624 driver_t *drv;
625 devman_handle_t handle;
626
627 assert(dev != NULL);
628
629 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_remove(%p)", dev);
630
631 fibril_rwlock_read_lock(&tree->rwlock);
632 drv = dev->drv;
633 handle = dev->handle;
634 fibril_rwlock_read_unlock(&tree->rwlock);
635
636 exch = async_exchange_begin(drv->sess);
637 retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
638 async_exchange_end(exch);
639
640 return retval;
641}
642
643errno_t driver_dev_gone(dev_tree_t *tree, dev_node_t *dev)
644{
645 async_exch_t *exch;
646 errno_t retval;
647 driver_t *drv;
648 devman_handle_t handle;
649
650 assert(dev != NULL);
651
652 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_gone(%p)", dev);
653
654 fibril_rwlock_read_lock(&tree->rwlock);
655 drv = dev->drv;
656 handle = dev->handle;
657 fibril_rwlock_read_unlock(&tree->rwlock);
658
659 exch = async_exchange_begin(drv->sess);
660 retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle);
661 async_exchange_end(exch);
662
663 return retval;
664}
665
666errno_t driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
667{
668 async_exch_t *exch;
669 errno_t retval;
670 driver_t *drv;
671 devman_handle_t handle;
672
673 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_online(%p)", fun);
674
675 fibril_rwlock_read_lock(&tree->rwlock);
676
677 if (fun->dev == NULL) {
678 /* XXX root function? */
679 fibril_rwlock_read_unlock(&tree->rwlock);
680 return EINVAL;
681 }
682
683 drv = fun->dev->drv;
684 handle = fun->handle;
685 fibril_rwlock_read_unlock(&tree->rwlock);
686
687 exch = async_exchange_begin(drv->sess);
688 retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
689 loc_exchange_end(exch);
690
691 return retval;
692}
693
694errno_t driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
695{
696 async_exch_t *exch;
697 errno_t retval;
698 driver_t *drv;
699 devman_handle_t handle;
700
701 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_offline(%p)", fun);
702
703 fibril_rwlock_read_lock(&tree->rwlock);
704 if (fun->dev == NULL) {
705 /* XXX root function? */
706 fibril_rwlock_read_unlock(&tree->rwlock);
707 return EINVAL;
708 }
709
710 drv = fun->dev->drv;
711 handle = fun->handle;
712 fibril_rwlock_read_unlock(&tree->rwlock);
713
714 exch = async_exchange_begin(drv->sess);
715 retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
716 loc_exchange_end(exch);
717
718 return retval;
719
720}
721
722/** Get list of registered drivers. */
723errno_t driver_get_list(driver_list_t *driver_list, devman_handle_t *hdl_buf,
724 size_t buf_size, size_t *act_size)
725{
726 size_t act_cnt;
727 size_t buf_cnt;
728
729 fibril_mutex_lock(&driver_list->drivers_mutex);
730
731 buf_cnt = buf_size / sizeof(devman_handle_t);
732
733 act_cnt = list_count(&driver_list->drivers);
734 *act_size = act_cnt * sizeof(devman_handle_t);
735
736 if (buf_size % sizeof(devman_handle_t) != 0) {
737 fibril_mutex_unlock(&driver_list->drivers_mutex);
738 return EINVAL;
739 }
740
741 size_t pos = 0;
742 list_foreach(driver_list->drivers, drivers, driver_t, drv) {
743 if (pos < buf_cnt) {
744 hdl_buf[pos] = drv->handle;
745 }
746
747 pos++;
748 }
749
750 fibril_mutex_unlock(&driver_list->drivers_mutex);
751 return EOK;
752}
753
754/** Get list of device functions. */
755errno_t driver_get_devices(driver_t *driver, devman_handle_t *hdl_buf,
756 size_t buf_size, size_t *act_size)
757{
758 size_t act_cnt;
759 size_t buf_cnt;
760
761 fibril_mutex_lock(&driver->driver_mutex);
762
763 buf_cnt = buf_size / sizeof(devman_handle_t);
764
765 act_cnt = list_count(&driver->devices);
766 *act_size = act_cnt * sizeof(devman_handle_t);
767
768 if (buf_size % sizeof(devman_handle_t) != 0) {
769 fibril_mutex_unlock(&driver->driver_mutex);
770 return EINVAL;
771 }
772
773 size_t pos = 0;
774 list_foreach(driver->devices, driver_devices, dev_node_t, dev) {
775 if (pos < buf_cnt) {
776 hdl_buf[pos] = dev->handle;
777 }
778
779 pos++;
780 }
781
782 fibril_mutex_unlock(&driver->driver_mutex);
783 return EOK;
784}
785
786/** @}
787 */
Note: See TracBrowser for help on using the repository browser.