Changeset 02e5e34 in mainline for uspace/srv/devman/fun.c


Ignore:
Timestamp:
2013-09-10T21:27:30Z (11 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
a501e22c
Parents:
181c32f
Message:

Fun on-/off-line needs to go to fun.c

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devman/fun.c

    r181c32f r02e5e34  
    3333#include <errno.h>
    3434#include <io/log.h>
    35 
     35#include <loc.h>
     36
     37#include "dev.h"
    3638#include "devman.h"
     39#include "devtree.h"
     40#include "driver.h"
    3741#include "fun.h"
     42#include "main.h"
     43#include "loc.h"
    3844
    3945static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
     
    280286}
    281287
     288static int assign_driver_fibril(void *arg)
     289{
     290        dev_node_t *dev_node = (dev_node_t *) arg;
     291        assign_driver(dev_node, &drivers_list, &device_tree);
     292
     293        /* Delete one reference we got from the caller. */
     294        dev_del_ref(dev_node);
     295        return EOK;
     296}
     297
     298int fun_online(fun_node_t *fun)
     299{
     300        dev_node_t *dev;
     301       
     302        fibril_rwlock_write_lock(&device_tree.rwlock);
     303       
     304        if (fun->state == FUN_ON_LINE) {
     305                fibril_rwlock_write_unlock(&device_tree.rwlock);
     306                log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",
     307                    fun->pathname);
     308                return EOK;
     309        }
     310       
     311        if (fun->ftype == fun_inner) {
     312                dev = create_dev_node();
     313                if (dev == NULL) {
     314                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     315                        return ENOMEM;
     316                }
     317               
     318                insert_dev_node(&device_tree, dev, fun);
     319                dev_add_ref(dev);
     320        }
     321       
     322        log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
     323       
     324        if (fun->ftype == fun_inner) {
     325                dev = fun->child;
     326                assert(dev != NULL);
     327               
     328                /* Give one reference over to assign_driver_fibril(). */
     329                dev_add_ref(dev);
     330               
     331                /*
     332                 * Try to find a suitable driver and assign it to the device.  We do
     333                 * not want to block the current fibril that is used for processing
     334                 * incoming calls: we will launch a separate fibril to handle the
     335                 * driver assigning. That is because assign_driver can actually include
     336                 * task spawning which could take some time.
     337                 */
     338                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
     339                if (assign_fibril == 0) {
     340                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "
     341                            "assigning driver.");
     342                        /* XXX Cleanup */
     343                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     344                        return ENOMEM;
     345                }
     346                fibril_add_ready(assign_fibril);
     347        } else
     348                loc_register_tree_function(fun, &device_tree);
     349       
     350        fibril_rwlock_write_unlock(&device_tree.rwlock);
     351       
     352        return EOK;
     353}
     354
     355int fun_offline(fun_node_t *fun)
     356{
     357        int rc;
     358       
     359        fibril_rwlock_write_lock(&device_tree.rwlock);
     360       
     361        if (fun->state == FUN_OFF_LINE) {
     362                fibril_rwlock_write_unlock(&device_tree.rwlock);
     363                log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",
     364                    fun->pathname);
     365                return EOK;
     366        }
     367       
     368        if (fun->ftype == fun_inner) {
     369                log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",
     370                    fun->pathname);
     371               
     372                if (fun->child != NULL) {
     373                        dev_node_t *dev = fun->child;
     374                        device_state_t dev_state;
     375                       
     376                        dev_add_ref(dev);
     377                        dev_state = dev->state;
     378                       
     379                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     380
     381                        /* If device is owned by driver, ask driver to give it up. */
     382                        if (dev_state == DEVICE_USABLE) {
     383                                rc = driver_dev_remove(&device_tree, dev);
     384                                if (rc != EOK) {
     385                                        dev_del_ref(dev);
     386                                        return ENOTSUP;
     387                                }
     388                        }
     389                       
     390                        /* Verify that driver removed all functions */
     391                        fibril_rwlock_read_lock(&device_tree.rwlock);
     392                        if (!list_empty(&dev->functions)) {
     393                                fibril_rwlock_read_unlock(&device_tree.rwlock);
     394                                dev_del_ref(dev);
     395                                return EIO;
     396                        }
     397                       
     398                        driver_t *driver = dev->drv;
     399                        fibril_rwlock_read_unlock(&device_tree.rwlock);
     400                       
     401                        if (driver)
     402                                detach_driver(&device_tree, dev);
     403                       
     404                        fibril_rwlock_write_lock(&device_tree.rwlock);
     405                        remove_dev_node(&device_tree, dev);
     406                       
     407                        /* Delete ref created when node was inserted */
     408                        dev_del_ref(dev);
     409                        /* Delete ref created by dev_add_ref(dev) above */
     410                        dev_del_ref(dev);
     411                }
     412        } else {
     413                /* Unregister from location service */
     414                rc = loc_service_unregister(fun->service_id);
     415                if (rc != EOK) {
     416                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     417                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");
     418                        return EIO;
     419                }
     420               
     421                fun->service_id = 0;
     422        }
     423       
     424        fun->state = FUN_OFF_LINE;
     425        fibril_rwlock_write_unlock(&device_tree.rwlock);
     426       
     427        return EOK;
     428}
     429
    282430/** @}
    283431 */
Note: See TracChangeset for help on using the changeset viewer.