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