source: mainline/uspace/srv/devman/driver.c@ c1b2084

Last change on this file since c1b2084 was e55741e, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

sysman: Instrumented devman with autostart

  • created unit files for drivers, their processing in Makefile
  • just naïvely replaced task_spawn with sysman_unit_start in devman

Conflicts:

boot/Makefile.common
uspace/srv/devman/devman.h
uspace/srv/devman/driver.c

  • Property mode set to 100644
File size: 21.3 KB
RevLine 
[041b026]1/*
[b25970f]2 * Copyright (c) 2018 Jiri Svoboda
[041b026]3 * Copyright (c) 2010 Lenka Trochtova
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/** @addtogroup devman
31 * @{
32 */
33
[d1bafbf]34#include <dirent.h>
[041b026]35#include <errno.h>
[e55741e]36#include <fcntl.h>
[041b026]37#include <io/log.h>
[23a0368]38#include <vfs/vfs.h>
[041b026]39#include <loc.h>
40#include <stdio.h>
[e55741e]41#include <str_error.h>
42#include <sys/stat.h>
43#include <sysman/ctl.h>
[1c635d6]44#include <task.h>
[041b026]45
[d1bafbf]46#include "dev.h"
[041b026]47#include "devman.h"
48#include "driver.h"
[b25970f]49#include "fun.h"
[a60e90b]50#include "match.h"
[b25970f]51#include "main.h"
52
53static errno_t driver_reassign_fibril(void *);
[041b026]54
55/**
56 * Initialize the list of device driver's.
57 *
58 * @param drv_list the list of device driver's.
59 *
60 */
61void init_driver_list(driver_list_t *drv_list)
62{
63 assert(drv_list != NULL);
[a35b458]64
[041b026]65 list_initialize(&drv_list->drivers);
66 fibril_mutex_initialize(&drv_list->drivers_mutex);
[0511549]67 drv_list->next_handle = 1;
[041b026]68}
69
70/** Allocate and initialize a new driver structure.
71 *
72 * @return Driver structure.
73 */
74driver_t *create_driver(void)
75{
76 driver_t *res = malloc(sizeof(driver_t));
77 if (res != NULL)
78 init_driver(res);
79 return res;
80}
81
82/** Add a driver to the list of drivers.
83 *
84 * @param drivers_list List of drivers.
85 * @param drv Driver structure.
86 */
87void add_driver(driver_list_t *drivers_list, driver_t *drv)
88{
89 fibril_mutex_lock(&drivers_list->drivers_mutex);
[e5556e4a]90 list_append(&drv->drivers, &drivers_list->drivers);
[0511549]91 drv->handle = drivers_list->next_handle++;
[041b026]92 fibril_mutex_unlock(&drivers_list->drivers_mutex);
93
[de3d15b4]94 log_msg(LOG_DEFAULT, LVL_DEBUG, "Driver `%s' was added to the list of available "
[041b026]95 "drivers.", drv->name);
96}
97
98/**
99 * Get information about a driver.
100 *
101 * Each driver has its own directory in the base directory.
102 * The name of the driver's directory is the same as the name of the driver.
103 * The driver's directory contains driver's binary (named as the driver without
104 * extension) and the configuration file with match ids for device-to-driver
105 * matching (named as the driver with a special extension).
106 *
107 * This function searches for the driver's directory and containing
108 * configuration files. If all the files needed are found, they are parsed and
109 * the information about the driver is stored in the driver's structure.
110 *
111 * @param base_path The base directory, in which we look for driver's
112 * subdirectory.
113 * @param name The name of the driver.
114 * @param drv The driver structure to fill information in.
115 *
116 * @return True on success, false otherwise.
117 */
118bool get_driver_info(const char *base_path, const char *name, driver_t *drv)
119{
120 log_msg(LOG_DEFAULT, LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
121 base_path, name);
[a35b458]122
[041b026]123 assert(base_path != NULL && name != NULL && drv != NULL);
[a35b458]124
[041b026]125 bool suc = false;
126 char *match_path = NULL;
127 size_t name_size = 0;
[a35b458]128
[041b026]129 /* Read the list of match ids from the driver's configuration file. */
130 match_path = get_abs_path(base_path, name, MATCH_EXT);
131 if (match_path == NULL)
132 goto cleanup;
[a35b458]133
[041b026]134 if (!read_match_ids(match_path, &drv->match_ids))
135 goto cleanup;
[a35b458]136
[041b026]137 /* Allocate and fill driver's name. */
138 name_size = str_size(name) + 1;
139 drv->name = malloc(name_size);
140 if (drv->name == NULL)
141 goto cleanup;
142 str_cpy(drv->name, name_size, name);
[a35b458]143
[041b026]144 suc = true;
[a35b458]145
[041b026]146cleanup:
147 if (!suc) {
148 free(drv->name);
149 /* Set the driver structure to the default state. */
150 init_driver(drv);
151 }
[a35b458]152
[041b026]153 free(match_path);
[a35b458]154
[041b026]155 return suc;
156}
157
158/** Lookup drivers in the directory.
159 *
160 * @param drivers_list The list of available drivers.
161 * @param dir_path The path to the directory where we search for drivers.
162 * @return Number of drivers which were found.
163 */
164int lookup_available_drivers(driver_list_t *drivers_list, const char *dir_path)
165{
166 log_msg(LOG_DEFAULT, LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
[a35b458]167
[041b026]168 int drv_cnt = 0;
169 DIR *dir = NULL;
170 struct dirent *diren;
171
172 dir = opendir(dir_path);
[a35b458]173
[041b026]174 if (dir != NULL) {
175 driver_t *drv = create_driver();
176 while ((diren = readdir(dir))) {
177 if (get_driver_info(dir_path, diren->d_name, drv)) {
178 add_driver(drivers_list, drv);
179 drv_cnt++;
180 drv = create_driver();
181 }
182 }
183 delete_driver(drv);
184 closedir(dir);
185 }
[a35b458]186
[041b026]187 return drv_cnt;
188}
189
[b25970f]190/** Lookup the next best matching driver for a device.
[041b026]191 *
192 * A match between a device and a driver is found if one of the driver's match
193 * ids match one of the device's match ids. The score of the match is the
194 * product of the driver's and device's score associated with the matching id.
195 * The best matching driver for a device is the driver with the highest score
196 * of the match between the device and the driver.
197 *
[b25970f]198 * If a driver is already assigned to the device (node->drv != NULL),
199 * we look for the next best driver. That is either the next driver with the
200 * same score in the list of drivers, or a driver with the next best score
201 * (greater than zero).
202 *
[041b026]203 * @param drivers_list The list of drivers, where we look for the driver
204 * suitable for handling the device.
205 * @param node The device node structure of the device.
206 * @return The best matching driver or NULL if no matching driver
207 * is found.
208 */
209driver_t *find_best_match_driver(driver_list_t *drivers_list, dev_node_t *node)
210{
[08bc23d]211 driver_t *best_drv = NULL;
[041b026]212 int best_score = 0, score = 0;
[b25970f]213 int cur_score;
214 link_t *link;
[a35b458]215
[041b026]216 fibril_mutex_lock(&drivers_list->drivers_mutex);
[a35b458]217
[b25970f]218 if (node->drv != NULL) {
219 cur_score = get_match_score(node->drv, node);
220
[64f85f5]221 link = list_next(&node->drv->drivers, &drivers_list->drivers);
[b25970f]222
223 /*
224 * Find next driver with score equal to the current.
225 */
226 while (link != NULL) {
[64f85f5]227 driver_t *drv = list_get_instance(link, driver_t,
228 drivers);
[b25970f]229 score = get_match_score(drv, node);
230 if (score == cur_score) {
231 /* Found it */
232 fibril_mutex_unlock(&drivers_list->drivers_mutex);
233 return drv;
234 }
235
236 link = list_next(link, &drivers_list->drivers);
237 }
238
239 /* There is no driver with the same score */
240 } else {
241 cur_score = INT_MAX;
242 }
243
244 /*
245 * Find driver with the next best score
246 */
[08bc23d]247 list_foreach(drivers_list->drivers, drivers, driver_t, drv) {
[041b026]248 score = get_match_score(drv, node);
[b25970f]249 if (score > best_score && score < cur_score) {
[041b026]250 best_score = score;
251 best_drv = drv;
252 }
253 }
[a35b458]254
[041b026]255 fibril_mutex_unlock(&drivers_list->drivers_mutex);
256 return best_drv;
257}
258
259/** Assign a driver to a device.
260 *
261 * @param tree Device tree
[e55741e]262 * @param dev The device's node in the device tree.
[041b026]263 * @param drv The driver.
264 */
265void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
266{
267 log_msg(LOG_DEFAULT, LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
268 dev->pfun->pathname, drv->name);
[a35b458]269
[041b026]270 fibril_mutex_lock(&drv->driver_mutex);
271 fibril_rwlock_write_lock(&tree->rwlock);
[a35b458]272
[041b026]273 dev->drv = drv;
[b25970f]274 dev->passed_to_driver = false;
275 dev->state = DEVICE_NOT_INITIALIZED;
[041b026]276 list_append(&dev->driver_devices, &drv->devices);
[a35b458]277
[041b026]278 fibril_rwlock_write_unlock(&tree->rwlock);
279 fibril_mutex_unlock(&drv->driver_mutex);
280}
281
282/** Detach driver from device.
283 *
284 * @param tree Device tree
285 * @param node The device's node in the device tree.
286 * @param drv The driver.
287 */
288void detach_driver(dev_tree_t *tree, dev_node_t *dev)
289{
290 driver_t *drv = dev->drv;
[a35b458]291
[041b026]292 assert(drv != NULL);
[a35b458]293
[041b026]294 log_msg(LOG_DEFAULT, LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
295 dev->pfun->pathname, drv->name);
[a35b458]296
[041b026]297 fibril_mutex_lock(&drv->driver_mutex);
298 fibril_rwlock_write_lock(&tree->rwlock);
[a35b458]299
[041b026]300 dev->drv = NULL;
301 list_remove(&dev->driver_devices);
[a35b458]302
[041b026]303 fibril_rwlock_write_unlock(&tree->rwlock);
304 fibril_mutex_unlock(&drv->driver_mutex);
305}
306
307/** Start a driver
308 *
309 * @param drv The driver's structure.
310 * @return True if the driver's task is successfully spawned, false
311 * otherwise.
312 */
313bool start_driver(driver_t *drv)
314{
[b7fd2a0]315 errno_t rc;
[041b026]316
317 assert(fibril_mutex_is_locked(&drv->driver_mutex));
[a35b458]318
[041b026]319 log_msg(LOG_DEFAULT, LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
[a35b458]320
[e55741e]321 char *unit_name = NULL;
322 asprintf(&unit_name, "%s%c%s", drv->name, UNIT_NAME_SEPARATOR,
323 UNIT_SVC_TYPE_NAME);
324 if (unit_name == NULL) {
325 return false;
326 }
327
328 /*
329 * Non-blocking asynchronous request to start a driver
330 * FIXME See note about sysman_unit_start non-blocking (asynchronous)
331 * API
332 */
333 int flags = 0;
334 rc = sysman_unit_start(unit_name, flags);
335
[041b026]336 if (rc != EOK) {
[e55741e]337 log_msg(LOG_DEFAULT, LVL_ERROR,
338 "Request to start driver `%s' failed: %s.",
339 drv->name, str_error(rc));
340 free(unit_name);
[041b026]341 return false;
342 }
[a35b458]343
[041b026]344 drv->state = DRIVER_STARTING;
[e55741e]345 free(unit_name);
[041b026]346 return true;
347}
348
[81685dd9]349/** Stop a driver
350 *
351 * @param drv The driver's structure.
352 * @return True if the driver's task is successfully spawned, false
353 * otherwise.
354 */
[b7fd2a0]355errno_t stop_driver(driver_t *drv)
[81685dd9]356{
357 async_exch_t *exch;
[b7fd2a0]358 errno_t retval;
[a35b458]359
[81685dd9]360 log_msg(LOG_DEFAULT, LVL_DEBUG, "stop_driver(drv=\"%s\")", drv->name);
361
362 exch = async_exchange_begin(drv->sess);
363 retval = async_req_0_0(exch, DRIVER_STOP);
364 loc_exchange_end(exch);
[a35b458]365
[81685dd9]366 if (retval != EOK)
367 return retval;
[a35b458]368
[81685dd9]369 drv->state = DRIVER_NOT_STARTED;
370 async_hangup(drv->sess);
371 drv->sess = NULL;
372 return EOK;
373}
374
[0511549]375/** Find device driver by handle.
376 *
377 * @param drv_list The list of device drivers
378 * @param handle Driver handle
379 * @return The device driver, if it is in the list,
380 * NULL otherwise.
381 */
382driver_t *driver_find(driver_list_t *drv_list, devman_handle_t handle)
383{
384 driver_t *res = NULL;
[a35b458]385
[0511549]386 fibril_mutex_lock(&drv_list->drivers_mutex);
[a35b458]387
[0511549]388 list_foreach(drv_list->drivers, drivers, driver_t, drv) {
389 if (drv->handle == handle) {
390 res = drv;
391 break;
392 }
393 }
[a35b458]394
[0511549]395 fibril_mutex_unlock(&drv_list->drivers_mutex);
[a35b458]396
[0511549]397 return res;
398}
399
400/** Find device driver by name.
[041b026]401 *
402 * @param drv_list The list of device drivers.
403 * @param drv_name The name of the device driver which is searched.
404 * @return The device driver of the specified name, if it is in the
405 * list, NULL otherwise.
406 */
[0511549]407driver_t *driver_find_by_name(driver_list_t *drv_list, const char *drv_name)
[041b026]408{
409 driver_t *res = NULL;
[a35b458]410
[041b026]411 fibril_mutex_lock(&drv_list->drivers_mutex);
[a35b458]412
[08bc23d]413 list_foreach(drv_list->drivers, drivers, driver_t, drv) {
[041b026]414 if (str_cmp(drv->name, drv_name) == 0) {
415 res = drv;
416 break;
417 }
418 }
[a35b458]419
[041b026]420 fibril_mutex_unlock(&drv_list->drivers_mutex);
[a35b458]421
[041b026]422 return res;
423}
424
425/** Notify driver about the devices to which it was assigned.
426 *
427 * @param driver The driver to which the devices are passed.
428 */
429static void pass_devices_to_driver(driver_t *driver, dev_tree_t *tree)
430{
431 dev_node_t *dev;
432 link_t *link;
433
434 log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
435 driver->name);
436
437 fibril_mutex_lock(&driver->driver_mutex);
438
439 /*
440 * Go through devices list as long as there is some device
441 * that has not been passed to the driver.
442 */
443 link = driver->devices.head.next;
444 while (link != &driver->devices.head) {
445 dev = list_get_instance(link, dev_node_t, driver_devices);
446 fibril_rwlock_write_lock(&tree->rwlock);
[a35b458]447
[041b026]448 if (dev->passed_to_driver) {
449 fibril_rwlock_write_unlock(&tree->rwlock);
450 link = link->next;
451 continue;
452 }
453
454 dev_add_ref(dev);
455
456 /*
457 * Unlock to avoid deadlock when adding device
458 * handled by itself.
459 */
460 fibril_mutex_unlock(&driver->driver_mutex);
461 fibril_rwlock_write_unlock(&tree->rwlock);
462
463 add_device(driver, dev, tree);
464
[b25970f]465 /* Device probe failed, need to try next best driver */
466 if (dev->state == DEVICE_NOT_PRESENT) {
467 fibril_mutex_lock(&driver->driver_mutex);
468 list_remove(&dev->driver_devices);
469 fibril_mutex_unlock(&driver->driver_mutex);
[5aa06ad]470 /* Give an extra reference to driver_reassign_fibril */
471 dev_add_ref(dev);
[b25970f]472 fid_t fid = fibril_create(driver_reassign_fibril, dev);
473 if (fid == 0) {
474 log_msg(LOG_DEFAULT, LVL_ERROR,
475 "Error creating fibril to assign driver.");
[5aa06ad]476 dev_del_ref(dev);
[b25970f]477 }
478 fibril_add_ready(fid);
479 }
480
[041b026]481 dev_del_ref(dev);
482
483 /*
484 * Lock again as we will work with driver's
485 * structure.
486 */
487 fibril_mutex_lock(&driver->driver_mutex);
488
489 /*
490 * Restart the cycle to go through all devices again.
491 */
492 link = driver->devices.head.next;
493 }
494
495 /*
496 * Once we passed all devices to the driver, we need to mark the
497 * driver as running.
498 * It is vital to do it here and inside critical section.
499 *
500 * If we would change the state earlier, other devices added to
501 * the driver would be added to the device list and started
502 * immediately and possibly started here as well.
503 */
504 log_msg(LOG_DEFAULT, LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
505 driver->state = DRIVER_RUNNING;
506
507 fibril_mutex_unlock(&driver->driver_mutex);
508}
509
510/** Finish the initialization of a driver after it has succesfully started
511 * and after it has registered itself by the device manager.
512 *
513 * Pass devices formerly matched to the driver to the driver and remember the
514 * driver is running and fully functional now.
515 *
516 * @param driver The driver which registered itself as running by the
517 * device manager.
518 */
519void initialize_running_driver(driver_t *driver, dev_tree_t *tree)
520{
521 log_msg(LOG_DEFAULT, LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
522 driver->name);
[a35b458]523
[041b026]524 /*
525 * Pass devices which have been already assigned to the driver to the
526 * driver.
527 */
528 pass_devices_to_driver(driver, tree);
529}
530
531/** Initialize device driver structure.
532 *
533 * @param drv The device driver structure.
534 */
535void init_driver(driver_t *drv)
536{
537 assert(drv != NULL);
538
539 memset(drv, 0, sizeof(driver_t));
540 list_initialize(&drv->match_ids.ids);
541 list_initialize(&drv->devices);
542 fibril_mutex_initialize(&drv->driver_mutex);
543 drv->sess = NULL;
544}
545
546/** Device driver structure clean-up.
547 *
548 * @param drv The device driver structure.
549 */
550void clean_driver(driver_t *drv)
551{
552 assert(drv != NULL);
553
554 free(drv->name);
555
556 clean_match_ids(&drv->match_ids);
557
558 init_driver(drv);
559}
560
561/** Delete device driver structure.
562 *
563 * @param drv The device driver structure.
564 */
565void delete_driver(driver_t *drv)
566{
567 assert(drv != NULL);
[a35b458]568
[041b026]569 clean_driver(drv);
570 free(drv);
571}
572
573/** Find suitable driver for a device and assign the driver to it.
574 *
[e55741e]575 * @param dev The device node of the device in the device tree.
[041b026]576 * @param drivers_list The list of available drivers.
577 * @return True if the suitable driver is found and
578 * successfully assigned to the device, false otherwise.
579 */
580bool assign_driver(dev_node_t *dev, driver_list_t *drivers_list,
581 dev_tree_t *tree)
582{
[b25970f]583 driver_t *drv;
584
[041b026]585 assert(dev != NULL);
586 assert(drivers_list != NULL);
587 assert(tree != NULL);
[a35b458]588
[041b026]589 /*
[b25970f]590 * Find the next best driver for this device.
[041b026]591 */
[b25970f]592again:
593 drv = find_best_match_driver(drivers_list, dev);
[041b026]594 if (drv == NULL) {
595 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver found for device `%s'.",
596 dev->pfun->pathname);
597 return false;
598 }
[a35b458]599
[041b026]600 /* Attach the driver to the device. */
601 attach_driver(tree, dev, drv);
[a35b458]602
[041b026]603 fibril_mutex_lock(&drv->driver_mutex);
604 if (drv->state == DRIVER_NOT_STARTED) {
605 /* Start the driver. */
606 start_driver(drv);
607 }
608 bool is_running = drv->state == DRIVER_RUNNING;
609 fibril_mutex_unlock(&drv->driver_mutex);
610
611 /* Notify the driver about the new device. */
[b25970f]612 if (is_running) {
[041b026]613 add_device(drv, dev, tree);
[a35b458]614
[b25970f]615 /* If the device probe failed, need to try next available driver */
616 if (dev->state == DEVICE_NOT_PRESENT)
617 goto again;
618 }
619
[041b026]620 fibril_mutex_lock(&drv->driver_mutex);
621 fibril_mutex_unlock(&drv->driver_mutex);
622
623 fibril_rwlock_write_lock(&tree->rwlock);
624 if (dev->pfun != NULL) {
625 dev->pfun->state = FUN_ON_LINE;
626 }
627 fibril_rwlock_write_unlock(&tree->rwlock);
628 return true;
629}
630
[a60e90b]631/** Pass a device to running driver.
632 *
633 * @param drv The driver's structure.
[e55741e]634 * @param dev The device's node in the device tree.
[a60e90b]635 */
636void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
637{
638 /*
639 * We do not expect to have driver's mutex locked as we do not
640 * access any structures that would affect driver_t.
641 */
642 log_msg(LOG_DEFAULT, LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
643 drv->name, dev->pfun->name);
[a35b458]644
[a60e90b]645 /* Send the device to the driver. */
646 devman_handle_t parent_handle;
647 if (dev->pfun) {
648 parent_handle = dev->pfun->handle;
649 } else {
650 parent_handle = 0;
651 }
[a35b458]652
[a60e90b]653 async_exch_t *exch = async_exchange_begin(drv->sess);
[a35b458]654
[a60e90b]655 ipc_call_t answer;
656 aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
657 parent_handle, &answer);
[a35b458]658
[a60e90b]659 /* Send the device name to the driver. */
[b7fd2a0]660 errno_t rc = async_data_write_start(exch, dev->pfun->name,
[a60e90b]661 str_size(dev->pfun->name) + 1);
[a35b458]662
[a60e90b]663 async_exchange_end(exch);
[a35b458]664
[a60e90b]665 if (rc != EOK) {
[f9b2cb4c]666 async_forget(req);
667 } else {
668 /* Wait for answer from the driver. */
669 async_wait_for(req, &rc);
[a60e90b]670 }
671
[f9b2cb4c]672 switch (rc) {
[a60e90b]673 case EOK:
674 dev->state = DEVICE_USABLE;
675 break;
676 case ENOENT:
677 dev->state = DEVICE_NOT_PRESENT;
678 break;
679 default:
680 dev->state = DEVICE_INVALID;
681 break;
682 }
[a35b458]683
[a60e90b]684 dev->passed_to_driver = true;
685}
686
[b7fd2a0]687errno_t driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
[041b026]688{
689 async_exch_t *exch;
[b7fd2a0]690 errno_t retval;
[041b026]691 driver_t *drv;
692 devman_handle_t handle;
[a35b458]693
[041b026]694 assert(dev != NULL);
[a35b458]695
[041b026]696 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_remove(%p)", dev);
[a35b458]697
[041b026]698 fibril_rwlock_read_lock(&tree->rwlock);
699 drv = dev->drv;
700 handle = dev->handle;
701 fibril_rwlock_read_unlock(&tree->rwlock);
[a35b458]702
[041b026]703 exch = async_exchange_begin(drv->sess);
704 retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
705 async_exchange_end(exch);
[a35b458]706
[041b026]707 return retval;
708}
709
[b7fd2a0]710errno_t driver_dev_gone(dev_tree_t *tree, dev_node_t *dev)
[041b026]711{
712 async_exch_t *exch;
[b7fd2a0]713 errno_t retval;
[041b026]714 driver_t *drv;
715 devman_handle_t handle;
[a35b458]716
[041b026]717 assert(dev != NULL);
[a35b458]718
[041b026]719 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_gone(%p)", dev);
[a35b458]720
[041b026]721 fibril_rwlock_read_lock(&tree->rwlock);
722 drv = dev->drv;
723 handle = dev->handle;
724 fibril_rwlock_read_unlock(&tree->rwlock);
[a35b458]725
[041b026]726 exch = async_exchange_begin(drv->sess);
727 retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle);
728 async_exchange_end(exch);
[a35b458]729
[041b026]730 return retval;
731}
732
[b7fd2a0]733errno_t driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
[041b026]734{
735 async_exch_t *exch;
[b7fd2a0]736 errno_t retval;
[041b026]737 driver_t *drv;
738 devman_handle_t handle;
[a35b458]739
[041b026]740 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_online(%p)", fun);
741
742 fibril_rwlock_read_lock(&tree->rwlock);
[a35b458]743
[041b026]744 if (fun->dev == NULL) {
745 /* XXX root function? */
746 fibril_rwlock_read_unlock(&tree->rwlock);
747 return EINVAL;
748 }
[a35b458]749
[041b026]750 drv = fun->dev->drv;
751 handle = fun->handle;
752 fibril_rwlock_read_unlock(&tree->rwlock);
[a35b458]753
[041b026]754 exch = async_exchange_begin(drv->sess);
755 retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
756 loc_exchange_end(exch);
[a35b458]757
[041b026]758 return retval;
759}
760
[b7fd2a0]761errno_t driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
[041b026]762{
763 async_exch_t *exch;
[b7fd2a0]764 errno_t retval;
[041b026]765 driver_t *drv;
766 devman_handle_t handle;
[a35b458]767
[041b026]768 log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_offline(%p)", fun);
769
770 fibril_rwlock_read_lock(&tree->rwlock);
771 if (fun->dev == NULL) {
772 /* XXX root function? */
773 fibril_rwlock_read_unlock(&tree->rwlock);
774 return EINVAL;
775 }
[a35b458]776
[041b026]777 drv = fun->dev->drv;
778 handle = fun->handle;
779 fibril_rwlock_read_unlock(&tree->rwlock);
[a35b458]780
[041b026]781 exch = async_exchange_begin(drv->sess);
782 retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
783 loc_exchange_end(exch);
[a35b458]784
[041b026]785 return retval;
786
787}
788
[0511549]789/** Get list of registered drivers. */
[b7fd2a0]790errno_t driver_get_list(driver_list_t *driver_list, devman_handle_t *hdl_buf,
[0511549]791 size_t buf_size, size_t *act_size)
792{
793 size_t act_cnt;
794 size_t buf_cnt;
795
796 fibril_mutex_lock(&driver_list->drivers_mutex);
797
798 buf_cnt = buf_size / sizeof(devman_handle_t);
799
800 act_cnt = list_count(&driver_list->drivers);
801 *act_size = act_cnt * sizeof(devman_handle_t);
802
803 if (buf_size % sizeof(devman_handle_t) != 0) {
804 fibril_mutex_unlock(&driver_list->drivers_mutex);
805 return EINVAL;
806 }
807
808 size_t pos = 0;
809 list_foreach(driver_list->drivers, drivers, driver_t, drv) {
810 if (pos < buf_cnt) {
811 hdl_buf[pos] = drv->handle;
812 }
813
814 pos++;
815 }
816
817 fibril_mutex_unlock(&driver_list->drivers_mutex);
818 return EOK;
819}
820
[1db5669]821/** Get list of device functions. */
[b7fd2a0]822errno_t driver_get_devices(driver_t *driver, devman_handle_t *hdl_buf,
[1db5669]823 size_t buf_size, size_t *act_size)
824{
825 size_t act_cnt;
826 size_t buf_cnt;
827
828 fibril_mutex_lock(&driver->driver_mutex);
829
830 buf_cnt = buf_size / sizeof(devman_handle_t);
831
832 act_cnt = list_count(&driver->devices);
833 *act_size = act_cnt * sizeof(devman_handle_t);
834
835 if (buf_size % sizeof(devman_handle_t) != 0) {
836 fibril_mutex_unlock(&driver->driver_mutex);
837 return EINVAL;
838 }
839
840 size_t pos = 0;
841 list_foreach(driver->devices, driver_devices, dev_node_t, dev) {
842 if (pos < buf_cnt) {
843 hdl_buf[pos] = dev->handle;
844 }
845
846 pos++;
847 }
848
849 fibril_mutex_unlock(&driver->driver_mutex);
850 return EOK;
851}
852
[b25970f]853/** Try to find next available driver in a separate fibril.
854 *
855 * @param arg Device node (dev_node_t)
856 */
857static errno_t driver_reassign_fibril(void *arg)
858{
859 dev_node_t *dev_node = (dev_node_t *) arg;
860 assign_driver(dev_node, &drivers_list, &device_tree);
861
862 /* Delete one reference we got from the caller. */
863 dev_del_ref(dev_node);
864 return EOK;
865}
866
[041b026]867/** @}
868 */
Note: See TracBrowser for help on using the repository browser.