Ignore:
File:
1 edited

Legend:

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

    r181c32f rc4f7bf6  
    3636 */
    3737
     38#include <inttypes.h>
    3839#include <assert.h>
    3940#include <ipc/services.h>
     
    4243#include <stdio.h>
    4344#include <errno.h>
     45#include <str_error.h>
    4446#include <stdbool.h>
    4547#include <fibril_synch.h>
    4648#include <stdlib.h>
    4749#include <str.h>
     50#include <dirent.h>
     51#include <fcntl.h>
     52#include <sys/stat.h>
    4853#include <ctype.h>
    4954#include <io/log.h>
    5055#include <ipc/devman.h>
    5156#include <ipc/driver.h>
     57#include <thread.h>
    5258#include <loc.h>
    5359
    54 #include "client_conn.h"
    55 #include "dev.h"
    5660#include "devman.h"
    57 #include "devtree.h"
    58 #include "drv_conn.h"
    59 #include "driver.h"
    60 #include "fun.h"
    61 #include "loc.h"
    6261
    6362#define DRIVER_DEFAULT_STORE  "/drv"
    6463
    65 driver_list_t drivers_list;
    66 dev_tree_t device_tree;
     64static driver_list_t drivers_list;
     65static dev_tree_t device_tree;
     66
     67static int init_running_drv(void *drv);
     68
     69/** Register running driver. */
     70static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
     71{
     72        driver_t *driver = NULL;
     73        char *drv_name = NULL;
     74
     75        log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");
     76       
     77        /* Get driver name. */
     78        int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
     79        if (rc != EOK) {
     80                async_answer_0(callid, rc);
     81                return NULL;
     82        }
     83
     84        log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",
     85            drv_name);
     86       
     87        /* Find driver structure. */
     88        driver = find_driver(&drivers_list, drv_name);
     89        if (driver == NULL) {
     90                log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);
     91                free(drv_name);
     92                drv_name = NULL;
     93                async_answer_0(callid, ENOENT);
     94                return NULL;
     95        }
     96       
     97        free(drv_name);
     98        drv_name = NULL;
     99       
     100        fibril_mutex_lock(&driver->driver_mutex);
     101       
     102        if (driver->sess) {
     103                /* We already have a connection to the driver. */
     104                log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",
     105                    driver->name);
     106                fibril_mutex_unlock(&driver->driver_mutex);
     107                async_answer_0(callid, EEXISTS);
     108                return NULL;
     109        }
     110       
     111        switch (driver->state) {
     112        case DRIVER_NOT_STARTED:
     113                /* Somebody started the driver manually. */
     114                log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",
     115                    driver->name);
     116                driver->state = DRIVER_STARTING;
     117                break;
     118        case DRIVER_STARTING:
     119                /* The expected case */
     120                break;
     121        case DRIVER_RUNNING:
     122                /* Should not happen since we do not have a connected session */
     123                assert(false);
     124        }
     125       
     126        /* Create connection to the driver. */
     127        log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",
     128            driver->name);
     129        driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
     130        if (!driver->sess) {
     131                fibril_mutex_unlock(&driver->driver_mutex);
     132                async_answer_0(callid, ENOTSUP);
     133                return NULL;
     134        }
     135        /* FIXME: Work around problem with callback sessions */
     136        async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
     137       
     138        log_msg(LOG_DEFAULT, LVL_NOTE,
     139            "The `%s' driver was successfully registered as running.",
     140            driver->name);
     141       
     142        /*
     143         * Initialize the driver as running (e.g. pass assigned devices to it)
     144         * in a separate fibril; the separate fibril is used to enable the
     145         * driver to use devman service during the driver's initialization.
     146         */
     147        fid_t fid = fibril_create(init_running_drv, driver);
     148        if (fid == 0) {
     149                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \
     150                    "for driver `%s'.", driver->name);
     151                fibril_mutex_unlock(&driver->driver_mutex);
     152                async_answer_0(callid, ENOMEM);
     153                return NULL;
     154        }
     155       
     156        fibril_add_ready(fid);
     157        fibril_mutex_unlock(&driver->driver_mutex);
     158       
     159        async_answer_0(callid, EOK);
     160        return driver;
     161}
     162
     163/** Receive device match ID from the device's parent driver and add it to the
     164 * list of devices match ids.
     165 *
     166 * @param match_ids     The list of the device's match ids.
     167 * @return              Zero on success, negative error code otherwise.
     168 */
     169static int devman_receive_match_id(match_id_list_t *match_ids)
     170{
     171        match_id_t *match_id = create_match_id();
     172        ipc_callid_t callid;
     173        ipc_call_t call;
     174        int rc = 0;
     175       
     176        callid = async_get_call(&call);
     177        if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
     178                log_msg(LOG_DEFAULT, LVL_ERROR,
     179                    "Invalid protocol when trying to receive match id.");
     180                async_answer_0(callid, EINVAL);
     181                delete_match_id(match_id);
     182                return EINVAL;
     183        }
     184       
     185        if (match_id == NULL) {
     186                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");
     187                async_answer_0(callid, ENOMEM);
     188                return ENOMEM;
     189        }
     190       
     191        async_answer_0(callid, EOK);
     192       
     193        match_id->score = IPC_GET_ARG1(call);
     194       
     195        char *match_id_str;
     196        rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
     197        match_id->id = match_id_str;
     198        if (rc != EOK) {
     199                delete_match_id(match_id);
     200                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",
     201                    str_error(rc));
     202                return rc;
     203        }
     204       
     205        list_append(&match_id->link, &match_ids->ids);
     206       
     207        log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",
     208            match_id->id, match_id->score);
     209        return rc;
     210}
     211
     212/** Receive device match IDs from the device's parent driver and add them to the
     213 * list of devices match ids.
     214 *
     215 * @param match_count   The number of device's match ids to be received.
     216 * @param match_ids     The list of the device's match ids.
     217 * @return              Zero on success, negative error code otherwise.
     218 */
     219static int devman_receive_match_ids(sysarg_t match_count,
     220    match_id_list_t *match_ids)
     221{
     222        int ret = EOK;
     223        size_t i;
     224       
     225        for (i = 0; i < match_count; i++) {
     226                if (EOK != (ret = devman_receive_match_id(match_ids)))
     227                        return ret;
     228        }
     229        return ret;
     230}
     231
     232static int assign_driver_fibril(void *arg)
     233{
     234        dev_node_t *dev_node = (dev_node_t *) arg;
     235        assign_driver(dev_node, &drivers_list, &device_tree);
     236
     237        /* Delete one reference we got from the caller. */
     238        dev_del_ref(dev_node);
     239        return EOK;
     240}
     241
     242static int online_function(fun_node_t *fun)
     243{
     244        dev_node_t *dev;
     245       
     246        fibril_rwlock_write_lock(&device_tree.rwlock);
     247       
     248        if (fun->state == FUN_ON_LINE) {
     249                fibril_rwlock_write_unlock(&device_tree.rwlock);
     250                log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",
     251                    fun->pathname);
     252                return EOK;
     253        }
     254       
     255        if (fun->ftype == fun_inner) {
     256                dev = create_dev_node();
     257                if (dev == NULL) {
     258                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     259                        return ENOMEM;
     260                }
     261               
     262                insert_dev_node(&device_tree, dev, fun);
     263                dev_add_ref(dev);
     264        }
     265       
     266        log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
     267       
     268        if (fun->ftype == fun_inner) {
     269                dev = fun->child;
     270                assert(dev != NULL);
     271               
     272                /* Give one reference over to assign_driver_fibril(). */
     273                dev_add_ref(dev);
     274               
     275                /*
     276                 * Try to find a suitable driver and assign it to the device.  We do
     277                 * not want to block the current fibril that is used for processing
     278                 * incoming calls: we will launch a separate fibril to handle the
     279                 * driver assigning. That is because assign_driver can actually include
     280                 * task spawning which could take some time.
     281                 */
     282                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
     283                if (assign_fibril == 0) {
     284                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "
     285                            "assigning driver.");
     286                        /* XXX Cleanup */
     287                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     288                        return ENOMEM;
     289                }
     290                fibril_add_ready(assign_fibril);
     291        } else
     292                loc_register_tree_function(fun, &device_tree);
     293       
     294        fibril_rwlock_write_unlock(&device_tree.rwlock);
     295       
     296        return EOK;
     297}
     298
     299static int offline_function(fun_node_t *fun)
     300{
     301        int rc;
     302       
     303        fibril_rwlock_write_lock(&device_tree.rwlock);
     304       
     305        if (fun->state == FUN_OFF_LINE) {
     306                fibril_rwlock_write_unlock(&device_tree.rwlock);
     307                log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",
     308                    fun->pathname);
     309                return EOK;
     310        }
     311       
     312        if (fun->ftype == fun_inner) {
     313                log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",
     314                    fun->pathname);
     315               
     316                if (fun->child != NULL) {
     317                        dev_node_t *dev = fun->child;
     318                        device_state_t dev_state;
     319                       
     320                        dev_add_ref(dev);
     321                        dev_state = dev->state;
     322                       
     323                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     324
     325                        /* If device is owned by driver, ask driver to give it up. */
     326                        if (dev_state == DEVICE_USABLE) {
     327                                rc = driver_dev_remove(&device_tree, dev);
     328                                if (rc != EOK) {
     329                                        dev_del_ref(dev);
     330                                        return ENOTSUP;
     331                                }
     332                        }
     333                       
     334                        /* Verify that driver removed all functions */
     335                        fibril_rwlock_read_lock(&device_tree.rwlock);
     336                        if (!list_empty(&dev->functions)) {
     337                                fibril_rwlock_read_unlock(&device_tree.rwlock);
     338                                dev_del_ref(dev);
     339                                return EIO;
     340                        }
     341                       
     342                        driver_t *driver = dev->drv;
     343                        fibril_rwlock_read_unlock(&device_tree.rwlock);
     344                       
     345                        if (driver)
     346                                detach_driver(&device_tree, dev);
     347                       
     348                        fibril_rwlock_write_lock(&device_tree.rwlock);
     349                        remove_dev_node(&device_tree, dev);
     350                       
     351                        /* Delete ref created when node was inserted */
     352                        dev_del_ref(dev);
     353                        /* Delete ref created by dev_add_ref(dev) above */
     354                        dev_del_ref(dev);
     355                }
     356        } else {
     357                /* Unregister from location service */
     358                rc = loc_service_unregister(fun->service_id);
     359                if (rc != EOK) {
     360                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     361                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");
     362                        return EIO;
     363                }
     364               
     365                fun->service_id = 0;
     366        }
     367       
     368        fun->state = FUN_OFF_LINE;
     369        fibril_rwlock_write_unlock(&device_tree.rwlock);
     370       
     371        return EOK;
     372}
     373
     374/** Handle function registration.
     375 *
     376 * Child devices are registered by their parent's device driver.
     377 */
     378static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
     379{
     380        fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
     381        devman_handle_t dev_handle = IPC_GET_ARG2(*call);
     382        sysarg_t match_count = IPC_GET_ARG3(*call);
     383        dev_tree_t *tree = &device_tree;
     384       
     385        dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
     386        if (pdev == NULL) {
     387                async_answer_0(callid, ENOENT);
     388                return;
     389        }
     390       
     391        if (ftype != fun_inner && ftype != fun_exposed) {
     392                /* Unknown function type */
     393                log_msg(LOG_DEFAULT, LVL_ERROR,
     394                    "Unknown function type %d provided by driver.",
     395                    (int) ftype);
     396
     397                dev_del_ref(pdev);
     398                async_answer_0(callid, EINVAL);
     399                return;
     400        }
     401       
     402        char *fun_name = NULL;
     403        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
     404        if (rc != EOK) {
     405                dev_del_ref(pdev);
     406                async_answer_0(callid, rc);
     407                return;
     408        }
     409       
     410        fibril_rwlock_write_lock(&tree->rwlock);
     411       
     412        /* Check device state */
     413        if (pdev->state == DEVICE_REMOVED) {
     414                fibril_rwlock_write_unlock(&tree->rwlock);
     415                dev_del_ref(pdev);
     416                async_answer_0(callid, ENOENT);
     417                return;
     418        }
     419       
     420        /* Check that function with same name is not there already. */
     421        fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name);
     422        if (tfun) {
     423                fun_del_ref(tfun);      /* drop the new unwanted reference */
     424                fibril_rwlock_write_unlock(&tree->rwlock);
     425                dev_del_ref(pdev);
     426                async_answer_0(callid, EEXISTS);
     427                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     428                    fun_name);
     429                free(fun_name);
     430                return;
     431        }
     432       
     433        fun_node_t *fun = create_fun_node();
     434        /* One reference for creation, one for us */
     435        fun_add_ref(fun);
     436        fun_add_ref(fun);
     437        fun->ftype = ftype;
     438       
     439        /*
     440         * We can lock the function here even when holding the tree because
     441         * we know it cannot be held by anyone else yet.
     442         */
     443        fun_busy_lock(fun);
     444       
     445        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     446                fibril_rwlock_write_unlock(&tree->rwlock);
     447                dev_del_ref(pdev);
     448                fun_busy_unlock(fun);
     449                fun_del_ref(fun);
     450                delete_fun_node(fun);
     451                async_answer_0(callid, ENOMEM);
     452                return;
     453        }
     454       
     455        fibril_rwlock_write_unlock(&tree->rwlock);
     456        dev_del_ref(pdev);
     457       
     458        devman_receive_match_ids(match_count, &fun->match_ids);
     459       
     460        rc = online_function(fun);
     461        if (rc != EOK) {
     462                /* XXX Set some failed state? */
     463                fun_busy_unlock(fun);
     464                fun_del_ref(fun);
     465                async_answer_0(callid, rc);
     466                return;
     467        }
     468       
     469        fun_busy_unlock(fun);
     470        fun_del_ref(fun);
     471       
     472        /* Return device handle to parent's driver. */
     473        async_answer_1(callid, EOK, fun->handle);
     474}
     475
     476static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
     477{
     478        devman_handle_t handle = IPC_GET_ARG1(*call);
     479        category_id_t cat_id;
     480        int rc;
     481       
     482        /* Get category name. */
     483        char *cat_name;
     484        rc = async_data_write_accept((void **) &cat_name, true,
     485            0, 0, 0, 0);
     486        if (rc != EOK) {
     487                async_answer_0(callid, rc);
     488                return;
     489        }
     490       
     491        fun_node_t *fun = find_fun_node(&device_tree, handle);
     492        if (fun == NULL) {
     493                async_answer_0(callid, ENOENT);
     494                return;
     495        }
     496       
     497        fibril_rwlock_read_lock(&device_tree.rwlock);
     498       
     499        /* Check function state */
     500        if (fun->state == FUN_REMOVED) {
     501                fibril_rwlock_read_unlock(&device_tree.rwlock);
     502                async_answer_0(callid, ENOENT);
     503                return;
     504        }
     505       
     506        rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
     507        if (rc == EOK) {
     508                loc_service_add_to_cat(fun->service_id, cat_id);
     509                log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",
     510                    fun->pathname, cat_name);
     511        } else {
     512                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "
     513                    "`%s'.", fun->pathname, cat_name);
     514        }
     515       
     516        fibril_rwlock_read_unlock(&device_tree.rwlock);
     517        fun_del_ref(fun);
     518       
     519        async_answer_0(callid, rc);
     520}
     521
     522/** Online function by driver request.
     523 *
     524 */
     525static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
     526    driver_t *drv)
     527{
     528        fun_node_t *fun;
     529        int rc;
     530       
     531        log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");
     532       
     533        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     534        if (fun == NULL) {
     535                async_answer_0(iid, ENOENT);
     536                return;
     537        }
     538       
     539        fun_busy_lock(fun);
     540       
     541        fibril_rwlock_read_lock(&device_tree.rwlock);
     542        if (fun->dev == NULL || fun->dev->drv != drv) {
     543                fibril_rwlock_read_unlock(&device_tree.rwlock);
     544                fun_busy_unlock(fun);
     545                fun_del_ref(fun);
     546                async_answer_0(iid, ENOENT);
     547                return;
     548        }
     549        fibril_rwlock_read_unlock(&device_tree.rwlock);
     550       
     551        rc = online_function(fun);
     552        if (rc != EOK) {
     553                fun_busy_unlock(fun);
     554                fun_del_ref(fun);
     555                async_answer_0(iid, (sysarg_t) rc);
     556                return;
     557        }
     558       
     559        fun_busy_unlock(fun);
     560        fun_del_ref(fun);
     561       
     562        async_answer_0(iid, (sysarg_t) EOK);
     563}
     564
     565
     566/** Offline function by driver request.
     567 *
     568 */
     569static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
     570    driver_t *drv)
     571{
     572        fun_node_t *fun;
     573        int rc;
     574
     575        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     576        if (fun == NULL) {
     577                async_answer_0(iid, ENOENT);
     578                return;
     579        }
     580       
     581        fun_busy_lock(fun);
     582       
     583        fibril_rwlock_write_lock(&device_tree.rwlock);
     584        if (fun->dev == NULL || fun->dev->drv != drv) {
     585                fun_busy_unlock(fun);
     586                fun_del_ref(fun);
     587                async_answer_0(iid, ENOENT);
     588                return;
     589        }
     590        fibril_rwlock_write_unlock(&device_tree.rwlock);
     591       
     592        rc = offline_function(fun);
     593        if (rc != EOK) {
     594                fun_busy_unlock(fun);
     595                fun_del_ref(fun);
     596                async_answer_0(iid, (sysarg_t) rc);
     597                return;
     598        }
     599       
     600        fun_busy_unlock(fun);
     601        fun_del_ref(fun);
     602        async_answer_0(iid, (sysarg_t) EOK);
     603}
     604
     605/** Remove function. */
     606static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
     607{
     608        devman_handle_t fun_handle = IPC_GET_ARG1(*call);
     609        dev_tree_t *tree = &device_tree;
     610        int rc;
     611       
     612        fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
     613        if (fun == NULL) {
     614                async_answer_0(callid, ENOENT);
     615                return;
     616        }
     617       
     618        fun_busy_lock(fun);
     619       
     620        fibril_rwlock_write_lock(&tree->rwlock);
     621       
     622        log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
     623       
     624        /* Check function state */
     625        if (fun->state == FUN_REMOVED) {
     626                fibril_rwlock_write_unlock(&tree->rwlock);
     627                fun_busy_unlock(fun);
     628                fun_del_ref(fun);
     629                async_answer_0(callid, ENOENT);
     630                return;
     631        }
     632       
     633        if (fun->ftype == fun_inner) {
     634                /* This is a surprise removal. Handle possible descendants */
     635                if (fun->child != NULL) {
     636                        dev_node_t *dev = fun->child;
     637                        device_state_t dev_state;
     638                        int gone_rc;
     639                       
     640                        dev_add_ref(dev);
     641                        dev_state = dev->state;
     642                       
     643                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     644                       
     645                        /* If device is owned by driver, inform driver it is gone. */
     646                        if (dev_state == DEVICE_USABLE)
     647                                gone_rc = driver_dev_gone(&device_tree, dev);
     648                        else
     649                                gone_rc = EOK;
     650                       
     651                        fibril_rwlock_read_lock(&device_tree.rwlock);
     652                       
     653                        /* Verify that driver succeeded and removed all functions */
     654                        if (gone_rc != EOK || !list_empty(&dev->functions)) {
     655                                log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "
     656                                    "functions for device that is gone. "
     657                                    "Device node is now defunct.");
     658                               
     659                                /*
     660                                 * Not much we can do but mark the device
     661                                 * node as having invalid state. This
     662                                 * is a driver bug.
     663                                 */
     664                                dev->state = DEVICE_INVALID;
     665                                fibril_rwlock_read_unlock(&device_tree.rwlock);
     666                                dev_del_ref(dev);
     667                                if (gone_rc == EOK)
     668                                        gone_rc = ENOTSUP;
     669                                fun_busy_unlock(fun);
     670                                fun_del_ref(fun);
     671                                async_answer_0(callid, gone_rc);
     672                                return;
     673                        }
     674                       
     675                        driver_t *driver = dev->drv;
     676                        fibril_rwlock_read_unlock(&device_tree.rwlock);
     677                       
     678                        if (driver)
     679                                detach_driver(&device_tree, dev);
     680                       
     681                        fibril_rwlock_write_lock(&device_tree.rwlock);
     682                        remove_dev_node(&device_tree, dev);
     683                       
     684                        /* Delete ref created when node was inserted */
     685                        dev_del_ref(dev);
     686                        /* Delete ref created by dev_add_ref(dev) above */
     687                        dev_del_ref(dev);
     688                }
     689        } else {
     690                if (fun->service_id != 0) {
     691                        /* Unregister from location service */
     692                        rc = loc_service_unregister(fun->service_id);
     693                        if (rc != EOK) {
     694                                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "
     695                                    "service.");
     696                                fibril_rwlock_write_unlock(&tree->rwlock);
     697                                fun_busy_unlock(fun);
     698                                fun_del_ref(fun);
     699                                async_answer_0(callid, EIO);
     700                                return;
     701                        }
     702                }
     703        }
     704       
     705        remove_fun_node(&device_tree, fun);
     706        fibril_rwlock_write_unlock(&tree->rwlock);
     707        fun_busy_unlock(fun);
     708       
     709        /* Delete ref added when inserting function into tree */
     710        fun_del_ref(fun);
     711        /* Delete ref added above when looking up function */
     712        fun_del_ref(fun);
     713       
     714        log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");
     715        async_answer_0(callid, EOK);
     716}
     717
     718/** Initialize driver which has registered itself as running and ready.
     719 *
     720 * The initialization is done in a separate fibril to avoid deadlocks (if the
     721 * driver needed to be served by devman during the driver's initialization).
     722 */
     723static int init_running_drv(void *drv)
     724{
     725        driver_t *driver = (driver_t *) drv;
     726       
     727        initialize_running_driver(driver, &device_tree);
     728        log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",
     729            driver->name);
     730        return 0;
     731}
     732
     733/** Function for handling connections from a driver to the device manager. */
     734static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
     735{
     736        client_t *client;
     737        driver_t *driver = NULL;
     738       
     739        /* Accept the connection. */
     740        async_answer_0(iid, EOK);
     741       
     742        client = async_get_client_data();
     743        if (client == NULL) {
     744                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");
     745                return;
     746        }
     747       
     748        while (true) {
     749                ipc_call_t call;
     750                ipc_callid_t callid = async_get_call(&call);
     751               
     752                if (!IPC_GET_IMETHOD(call))
     753                        break;
     754               
     755                if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
     756                        fibril_mutex_lock(&client->mutex);
     757                        driver = client->driver;
     758                        fibril_mutex_unlock(&client->mutex);
     759                        if (driver == NULL) {
     760                                /* First call must be to DEVMAN_DRIVER_REGISTER */
     761                                async_answer_0(callid, ENOTSUP);
     762                                continue;
     763                        }
     764                }
     765               
     766                switch (IPC_GET_IMETHOD(call)) {
     767                case DEVMAN_DRIVER_REGISTER:
     768                        fibril_mutex_lock(&client->mutex);
     769                        if (client->driver != NULL) {
     770                                fibril_mutex_unlock(&client->mutex);
     771                                async_answer_0(callid, EINVAL);
     772                                continue;
     773                        }
     774                        client->driver = devman_driver_register(callid, &call);
     775                        fibril_mutex_unlock(&client->mutex);
     776                        break;
     777                case DEVMAN_ADD_FUNCTION:
     778                        devman_add_function(callid, &call);
     779                        break;
     780                case DEVMAN_ADD_DEVICE_TO_CATEGORY:
     781                        devman_add_function_to_cat(callid, &call);
     782                        break;
     783                case DEVMAN_DRV_FUN_ONLINE:
     784                        devman_drv_fun_online(callid, &call, driver);
     785                        break;
     786                case DEVMAN_DRV_FUN_OFFLINE:
     787                        devman_drv_fun_offline(callid, &call, driver);
     788                        break;
     789                case DEVMAN_REMOVE_FUNCTION:
     790                        devman_remove_function(callid, &call);
     791                        break;
     792                default:
     793                        async_answer_0(callid, EINVAL);
     794                        break;
     795                }
     796        }
     797}
     798
     799/** Find handle for the device instance identified by the device's path in the
     800 * device tree. */
     801static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
     802{
     803        char *pathname;
     804        devman_handle_t handle;
     805       
     806        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     807        if (rc != EOK) {
     808                async_answer_0(iid, rc);
     809                return;
     810        }
     811       
     812        fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
     813       
     814        free(pathname);
     815
     816        if (fun == NULL) {
     817                async_answer_0(iid, ENOENT);
     818                return;
     819        }
     820
     821        fibril_rwlock_read_lock(&device_tree.rwlock);
     822
     823        /* Check function state */
     824        if (fun->state == FUN_REMOVED) {
     825                fibril_rwlock_read_unlock(&device_tree.rwlock);
     826                async_answer_0(iid, ENOENT);
     827                return;
     828        }
     829        handle = fun->handle;
     830
     831        fibril_rwlock_read_unlock(&device_tree.rwlock);
     832
     833        /* Delete reference created above by find_fun_node_by_path() */
     834        fun_del_ref(fun);
     835
     836        async_answer_1(iid, EOK, handle);
     837}
     838
     839/** Get device name. */
     840static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
     841{
     842        devman_handle_t handle = IPC_GET_ARG1(*icall);
     843
     844        fun_node_t *fun = find_fun_node(&device_tree, handle);
     845        if (fun == NULL) {
     846                async_answer_0(iid, ENOMEM);
     847                return;
     848        }
     849
     850        ipc_callid_t data_callid;
     851        size_t data_len;
     852        if (!async_data_read_receive(&data_callid, &data_len)) {
     853                async_answer_0(iid, EINVAL);
     854                fun_del_ref(fun);
     855                return;
     856        }
     857
     858        void *buffer = malloc(data_len);
     859        if (buffer == NULL) {
     860                async_answer_0(data_callid, ENOMEM);
     861                async_answer_0(iid, ENOMEM);
     862                fun_del_ref(fun);
     863                return;
     864        }
     865
     866        fibril_rwlock_read_lock(&device_tree.rwlock);
     867
     868        /* Check function state */
     869        if (fun->state == FUN_REMOVED) {
     870                fibril_rwlock_read_unlock(&device_tree.rwlock);
     871                free(buffer);
     872
     873                async_answer_0(data_callid, ENOENT);
     874                async_answer_0(iid, ENOENT);
     875                fun_del_ref(fun);
     876                return;
     877        }
     878
     879        size_t sent_length = str_size(fun->name);
     880        if (sent_length > data_len) {
     881                sent_length = data_len;
     882        }
     883
     884        async_data_read_finalize(data_callid, fun->name, sent_length);
     885        async_answer_0(iid, EOK);
     886
     887        fibril_rwlock_read_unlock(&device_tree.rwlock);
     888        fun_del_ref(fun);
     889        free(buffer);
     890}
     891
     892/** Get function driver name. */
     893static void devman_fun_get_driver_name(ipc_callid_t iid, ipc_call_t *icall)
     894{
     895        devman_handle_t handle = IPC_GET_ARG1(*icall);
     896
     897        fun_node_t *fun = find_fun_node(&device_tree, handle);
     898        if (fun == NULL) {
     899                async_answer_0(iid, ENOMEM);
     900                return;
     901        }
     902
     903        ipc_callid_t data_callid;
     904        size_t data_len;
     905        if (!async_data_read_receive(&data_callid, &data_len)) {
     906                async_answer_0(iid, EINVAL);
     907                fun_del_ref(fun);
     908                return;
     909        }
     910
     911        void *buffer = malloc(data_len);
     912        if (buffer == NULL) {
     913                async_answer_0(data_callid, ENOMEM);
     914                async_answer_0(iid, ENOMEM);
     915                fun_del_ref(fun);
     916                return;
     917        }
     918
     919        fibril_rwlock_read_lock(&device_tree.rwlock);
     920
     921        /* Check function state */
     922        if (fun->state == FUN_REMOVED) {
     923                fibril_rwlock_read_unlock(&device_tree.rwlock);
     924                free(buffer);
     925
     926                async_answer_0(data_callid, ENOENT);
     927                async_answer_0(iid, ENOENT);
     928                fun_del_ref(fun);
     929                return;
     930        }
     931
     932        /* Check whether function has a driver */
     933        if (fun->child == NULL || fun->child->drv == NULL) {
     934                fibril_rwlock_read_unlock(&device_tree.rwlock);
     935                free(buffer);
     936
     937                async_answer_0(data_callid, EINVAL);
     938                async_answer_0(iid, EINVAL);
     939                fun_del_ref(fun);
     940                return;
     941        }
     942
     943        size_t sent_length = str_size(fun->child->drv->name);
     944        if (sent_length > data_len) {
     945                sent_length = data_len;
     946        }
     947
     948        async_data_read_finalize(data_callid, fun->child->drv->name,
     949            sent_length);
     950        async_answer_0(iid, EOK);
     951
     952        fibril_rwlock_read_unlock(&device_tree.rwlock);
     953        fun_del_ref(fun);
     954        free(buffer);
     955}
     956
     957/** Get device path. */
     958static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall)
     959{
     960        devman_handle_t handle = IPC_GET_ARG1(*icall);
     961
     962        fun_node_t *fun = find_fun_node(&device_tree, handle);
     963        if (fun == NULL) {
     964                async_answer_0(iid, ENOMEM);
     965                return;
     966        }
     967
     968        ipc_callid_t data_callid;
     969        size_t data_len;
     970        if (!async_data_read_receive(&data_callid, &data_len)) {
     971                async_answer_0(iid, EINVAL);
     972                fun_del_ref(fun);
     973                return;
     974        }
     975
     976        void *buffer = malloc(data_len);
     977        if (buffer == NULL) {
     978                async_answer_0(data_callid, ENOMEM);
     979                async_answer_0(iid, ENOMEM);
     980                fun_del_ref(fun);
     981                return;
     982        }
     983       
     984        fibril_rwlock_read_lock(&device_tree.rwlock);
     985       
     986        /* Check function state */
     987        if (fun->state == FUN_REMOVED) {
     988                fibril_rwlock_read_unlock(&device_tree.rwlock);
     989                free(buffer);
     990
     991                async_answer_0(data_callid, ENOENT);
     992                async_answer_0(iid, ENOENT);
     993                fun_del_ref(fun);
     994                return;
     995        }
     996       
     997        size_t sent_length = str_size(fun->pathname);
     998        if (sent_length > data_len) {
     999                sent_length = data_len;
     1000        }
     1001
     1002        async_data_read_finalize(data_callid, fun->pathname, sent_length);
     1003        async_answer_0(iid, EOK);
     1004
     1005        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1006        fun_del_ref(fun);
     1007        free(buffer);
     1008}
     1009
     1010static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)
     1011{
     1012        ipc_callid_t callid;
     1013        size_t size;
     1014        size_t act_size;
     1015        int rc;
     1016       
     1017        if (!async_data_read_receive(&callid, &size)) {
     1018                async_answer_0(callid, EREFUSED);
     1019                async_answer_0(iid, EREFUSED);
     1020                return;
     1021        }
     1022       
     1023        fibril_rwlock_read_lock(&device_tree.rwlock);
     1024       
     1025        dev_node_t *dev = find_dev_node_no_lock(&device_tree,
     1026            IPC_GET_ARG1(*icall));
     1027        if (dev == NULL || dev->state == DEVICE_REMOVED) {
     1028                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1029                async_answer_0(callid, ENOENT);
     1030                async_answer_0(iid, ENOENT);
     1031                return;
     1032        }
     1033       
     1034        devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
     1035        if (hdl_buf == NULL) {
     1036                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1037                async_answer_0(callid, ENOMEM);
     1038                async_answer_0(iid, ENOMEM);
     1039                return;
     1040        }
     1041       
     1042        rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
     1043        if (rc != EOK) {
     1044                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1045                async_answer_0(callid, rc);
     1046                async_answer_0(iid, rc);
     1047                return;
     1048        }
     1049       
     1050        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1051       
     1052        sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);
     1053        free(hdl_buf);
     1054       
     1055        async_answer_1(iid, retval, act_size);
     1056}
     1057
     1058
     1059/** Get handle for child device of a function. */
     1060static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)
     1061{
     1062        fun_node_t *fun;
     1063       
     1064        fibril_rwlock_read_lock(&device_tree.rwlock);
     1065       
     1066        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     1067        if (fun == NULL || fun->state == FUN_REMOVED) {
     1068                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1069                async_answer_0(iid, ENOENT);
     1070                return;
     1071        }
     1072       
     1073        if (fun->child == NULL) {
     1074                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1075                async_answer_0(iid, ENOENT);
     1076                return;
     1077        }
     1078       
     1079        async_answer_1(iid, EOK, fun->child->handle);
     1080       
     1081        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1082}
     1083
     1084/** Online function.
     1085 *
     1086 * Send a request to online a function to the responsible driver.
     1087 * The driver may offline other functions if necessary (i.e. if the state
     1088 * of this function is linked to state of another function somehow).
     1089 */
     1090static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     1091{
     1092        fun_node_t *fun;
     1093        int rc;
     1094
     1095        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     1096        if (fun == NULL) {
     1097                async_answer_0(iid, ENOENT);
     1098                return;
     1099        }
     1100       
     1101        rc = driver_fun_online(&device_tree, fun);
     1102        fun_del_ref(fun);
     1103       
     1104        async_answer_0(iid, (sysarg_t) rc);
     1105}
     1106
     1107/** Offline function.
     1108 *
     1109 * Send a request to offline a function to the responsible driver. As
     1110 * a result the subtree rooted at that function should be cleanly
     1111 * detatched. The driver may offline other functions if necessary
     1112 * (i.e. if the state of this function is linked to state of another
     1113 * function somehow).
     1114 */
     1115static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     1116{
     1117        fun_node_t *fun;
     1118        int rc;
     1119
     1120        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     1121        if (fun == NULL) {
     1122                async_answer_0(iid, ENOENT);
     1123                return;
     1124        }
     1125       
     1126        rc = driver_fun_offline(&device_tree, fun);
     1127        fun_del_ref(fun);
     1128       
     1129        async_answer_0(iid, (sysarg_t) rc);
     1130}
     1131
     1132/** Find handle for the function instance identified by its service ID. */
     1133static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
     1134{
     1135        fun_node_t *fun;
     1136
     1137        fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
     1138       
     1139        if (fun == NULL) {
     1140                async_answer_0(iid, ENOENT);
     1141                return;
     1142        }
     1143
     1144        fibril_rwlock_read_lock(&device_tree.rwlock);
     1145
     1146        /* Check function state */
     1147        if (fun->state == FUN_REMOVED) {
     1148                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1149                async_answer_0(iid, ENOENT);
     1150                return;
     1151        }
     1152
     1153        async_answer_1(iid, EOK, fun->handle);
     1154        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1155        fun_del_ref(fun);
     1156}
     1157
     1158/** Function for handling connections from a client to the device manager. */
     1159static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall)
     1160{
     1161        /* Accept connection. */
     1162        async_answer_0(iid, EOK);
     1163       
     1164        while (true) {
     1165                ipc_call_t call;
     1166                ipc_callid_t callid = async_get_call(&call);
     1167               
     1168                if (!IPC_GET_IMETHOD(call))
     1169                        break;
     1170               
     1171                switch (IPC_GET_IMETHOD(call)) {
     1172                case DEVMAN_DEVICE_GET_HANDLE:
     1173                        devman_function_get_handle(callid, &call);
     1174                        break;
     1175                case DEVMAN_DEV_GET_FUNCTIONS:
     1176                        devman_dev_get_functions(callid, &call);
     1177                        break;
     1178                case DEVMAN_FUN_GET_CHILD:
     1179                        devman_fun_get_child(callid, &call);
     1180                        break;
     1181                case DEVMAN_FUN_GET_NAME:
     1182                        devman_fun_get_name(callid, &call);
     1183                        break;
     1184                case DEVMAN_FUN_GET_DRIVER_NAME:
     1185                        devman_fun_get_driver_name(callid, &call);
     1186                        break;
     1187                case DEVMAN_FUN_GET_PATH:
     1188                        devman_fun_get_path(callid, &call);
     1189                        break;
     1190                case DEVMAN_FUN_ONLINE:
     1191                        devman_fun_online(callid, &call);
     1192                        break;
     1193                case DEVMAN_FUN_OFFLINE:
     1194                        devman_fun_offline(callid, &call);
     1195                        break;
     1196                case DEVMAN_FUN_SID_TO_HANDLE:
     1197                        devman_fun_sid_to_handle(callid, &call);
     1198                        break;
     1199                default:
     1200                        async_answer_0(callid, ENOENT);
     1201                }
     1202        }
     1203}
    671204
    681205static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
Note: See TracChangeset for help on using the changeset viewer.