Ignore:
File:
1 edited

Legend:

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

    r9934f7d r80a96d2  
    5656#include <ipc/driver.h>
    5757#include <thread.h>
    58 #include <devmap.h>
     58#include <loc.h>
    5959
    6060#include "devman.h"
     
    6464static driver_list_t drivers_list;
    6565static dev_tree_t device_tree;
    66 static class_list_t class_list;
     66
     67static int init_running_drv(void *drv);
    6768
    6869/** Register running driver. */
    69 static driver_t *devman_driver_register(void)
    70 {
    71         ipc_call_t icall;
    72         ipc_callid_t iid;
     70static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
     71{
    7372        driver_t *driver = NULL;
     73        char *drv_name = NULL;
    7474
    7575        log_msg(LVL_DEBUG, "devman_driver_register");
    76        
    77         iid = async_get_call(&icall);
    78         if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {
    79                 async_answer_0(iid, EREFUSED);
    80                 return NULL;
    81         }
    82        
    83         char *drv_name = NULL;
    8476       
    8577        /* Get driver name. */
    8678        int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    8779        if (rc != EOK) {
    88                 async_answer_0(iid, rc);
     80                async_answer_0(callid, rc);
    8981                return NULL;
    9082        }
     
    9991                free(drv_name);
    10092                drv_name = NULL;
    101                 async_answer_0(iid, ENOENT);
     93                async_answer_0(callid, ENOENT);
    10294                return NULL;
    10395        }
     
    113105                    driver->name);
    114106                fibril_mutex_unlock(&driver->driver_mutex);
    115                 async_answer_0(iid, EEXISTS);
     107                async_answer_0(callid, EEXISTS);
    116108                return NULL;
    117109        }
     
    135127        log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
    136128            driver->name);
    137         driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
     129        driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
    138130        if (!driver->sess) {
    139131                fibril_mutex_unlock(&driver->driver_mutex);
    140                 async_answer_0(iid, ENOTSUP);
     132                async_answer_0(callid, ENOTSUP);
    141133                return NULL;
    142134        }
    143        
    144         fibril_mutex_unlock(&driver->driver_mutex);
     135        /* FIXME: Work around problem with callback sessions */
     136        async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
    145137       
    146138        log_msg(LVL_NOTE,
     
    148140            driver->name);
    149141       
    150         async_answer_0(iid, EOK);
    151        
     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(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);
    152160        return driver;
    153161}
     
    226234        dev_node_t *dev_node = (dev_node_t *) arg;
    227235        assign_driver(dev_node, &drivers_list, &device_tree);
     236
     237        /* Delete one reference we got from the caller. */
     238        dev_del_ref(dev_node);
    228239        return EOK;
    229240}
    230241
    231 /** Handle function registration.
    232  *
    233  * Child devices are registered by their parent's device driver.
    234  */
    235 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
    236 {
    237         fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
    238         devman_handle_t dev_handle = IPC_GET_ARG2(*call);
    239         sysarg_t match_count = IPC_GET_ARG3(*call);
    240         dev_tree_t *tree = &device_tree;
    241        
    242         fibril_rwlock_write_lock(&tree->rwlock);
    243 
    244         dev_node_t *dev = NULL;
    245         dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
    246        
    247         if (pdev == NULL) {
    248                 fibril_rwlock_write_unlock(&tree->rwlock);
    249                 async_answer_0(callid, ENOENT);
    250                 return;
    251         }
    252        
    253         if (ftype != fun_inner && ftype != fun_exposed) {
    254                 /* Unknown function type */
    255                 log_msg(LVL_ERROR,
    256                     "Unknown function type %d provided by driver.",
    257                     (int) ftype);
    258 
    259                 fibril_rwlock_write_unlock(&tree->rwlock);
    260                 async_answer_0(callid, EINVAL);
    261                 return;
    262         }
    263        
    264         char *fun_name = NULL;
    265         int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
    266         if (rc != EOK) {
    267                 fibril_rwlock_write_unlock(&tree->rwlock);
    268                 async_answer_0(callid, rc);
    269                 return;
    270         }
    271        
    272         /* Check that function with same name is not there already. */
    273         if (find_fun_node_in_device(pdev, fun_name) != NULL) {
    274                 fibril_rwlock_write_unlock(&tree->rwlock);
    275                 async_answer_0(callid, EEXISTS);
    276                 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
    277                     fun_name);
    278                 free(fun_name);
    279                 return;
    280         }
    281 
    282         fun_node_t *fun = create_fun_node();
    283         if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    284                 fibril_rwlock_write_unlock(&tree->rwlock);
    285                 delete_fun_node(fun);
    286                 async_answer_0(callid, ENOMEM);
    287                 return;
    288         }
    289 
    290         if (ftype == fun_inner) {
     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(LVL_WARN, "Function %s is already on line.",
     251                    fun->pathname);
     252                return EOK;
     253        }
     254       
     255        if (fun->ftype == fun_inner) {
    291256                dev = create_dev_node();
    292257                if (dev == NULL) {
    293                         fibril_rwlock_write_unlock(&tree->rwlock);
    294                         delete_fun_node(fun);
    295                         async_answer_0(callid, ENOMEM);
    296                         return;
     258                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     259                        return ENOMEM;
    297260                }
    298261
    299                 insert_dev_node(tree, dev, fun);
    300         }
    301 
    302         fibril_rwlock_write_unlock(&tree->rwlock);
     262                insert_dev_node(&device_tree, dev, fun);
     263                dev_add_ref(dev);
     264        }
    303265       
    304266        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
    305267       
    306         devman_receive_match_ids(match_count, &fun->match_ids);
    307 
    308         if (ftype == fun_inner) {
     268        if (fun->ftype == fun_inner) {
     269                dev = fun->child;
    309270                assert(dev != NULL);
     271               
     272                /* Give one reference over to assign_driver_fibril(). */
     273                dev_add_ref(dev);
    310274                /*
    311275                 * Try to find a suitable driver and assign it to the device.  We do
     
    317281                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
    318282                if (assign_fibril == 0) {
    319                         /*
    320                          * Fallback in case we are out of memory.
    321                          * Probably not needed as we will die soon anyway ;-).
    322                          */
    323                         (void) assign_driver_fibril(fun);
    324                 } else {
    325                         fibril_add_ready(assign_fibril);
     283                        log_msg(LVL_ERROR, "Failed to create fibril for "
     284                            "assigning driver.");
     285                        /* XXX Cleanup */
     286                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     287                        return ENOMEM;
     288                }
     289                fibril_add_ready(assign_fibril);
     290        } else {
     291                loc_register_tree_function(fun, &device_tree);
     292        }
     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(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(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);
    326355                }
    327356        } else {
    328                 devmap_register_tree_function(fun, tree);
     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(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(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        if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) {
     422                fibril_rwlock_write_unlock(&tree->rwlock);
     423                dev_del_ref(pdev);
     424                async_answer_0(callid, EEXISTS);
     425                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     426                    fun_name);
     427                free(fun_name);
     428                return;
     429        }
     430       
     431        fun_node_t *fun = create_fun_node();
     432        fun_add_ref(fun);
     433        fun->ftype = ftype;
     434       
     435        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     436                fibril_rwlock_write_unlock(&tree->rwlock);
     437                dev_del_ref(pdev);
     438                delete_fun_node(fun);
     439                async_answer_0(callid, ENOMEM);
     440                return;
     441        }
     442       
     443        fibril_rwlock_write_unlock(&tree->rwlock);
     444        dev_del_ref(pdev);
     445       
     446        devman_receive_match_ids(match_count, &fun->match_ids);
     447       
     448        rc = online_function(fun);
     449        if (rc != EOK) {
     450                /* XXX clean up */
     451                async_answer_0(callid, rc);
     452                return;
    329453        }
    330454       
     
    333457}
    334458
    335 static void devmap_register_class_dev(dev_class_info_t *cli)
    336 {
    337         /* Create devmap path and name for the device. */
    338         char *devmap_pathname = NULL;
    339 
    340         asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE,
    341             cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name);
    342         if (devmap_pathname == NULL)
    343                 return;
    344        
    345         /*
    346          * Register the device by the device mapper and remember its devmap
    347          * handle.
    348          */
    349         devmap_device_register_with_iface(devmap_pathname,
    350             &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
    351        
    352         /*
    353          * Add device to the hash map of class devices registered by device
    354          * mapper.
    355          */
    356         class_add_devmap_function(&class_list, cli);
    357        
    358         free(devmap_pathname);
    359 }
    360 
    361 static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
     459static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
    362460{
    363461        devman_handle_t handle = IPC_GET_ARG1(*call);
    364        
    365         /* Get class name. */
    366         char *class_name;
    367         int rc = async_data_write_accept((void **) &class_name, true,
     462        category_id_t cat_id;
     463        int rc;
     464       
     465        /* Get category name. */
     466        char *cat_name;
     467        rc = async_data_write_accept((void **) &cat_name, true,
    368468            0, 0, 0, 0);
    369469        if (rc != EOK) {
    370470                async_answer_0(callid, rc);
    371471                return;
    372         }       
     472        }
    373473       
    374474        fun_node_t *fun = find_fun_node(&device_tree, handle);
     
    378478        }
    379479       
    380         dev_class_t *cl = get_dev_class(&class_list, class_name);
    381         dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL);
    382        
    383         /* Register the device's class alias by devmapper. */
    384         devmap_register_class_dev(class_info);
    385        
    386         log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.",
    387             fun->pathname, class_name, class_info->dev_name);
    388 
     480        fibril_rwlock_read_lock(&device_tree.rwlock);
     481       
     482        /* Check function state */
     483        if (fun->state == FUN_REMOVED) {
     484                fibril_rwlock_read_unlock(&device_tree.rwlock);
     485                async_answer_0(callid, ENOENT);
     486                return;
     487        }
     488       
     489        rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
     490        if (rc == EOK) {
     491                loc_service_add_to_cat(fun->service_id, cat_id);
     492        } else {
     493                log_msg(LVL_ERROR, "Failed adding function `%s' to category "
     494                    "`%s'.", fun->pathname, cat_name);
     495        }
     496       
     497        log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
     498            fun->pathname, cat_name);
     499
     500        fibril_rwlock_read_unlock(&device_tree.rwlock);
     501        fun_del_ref(fun);
     502
     503        async_answer_0(callid, EOK);
     504}
     505
     506/** Online function by driver request.
     507 *
     508 */
     509static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
     510    driver_t *drv)
     511{
     512        fun_node_t *fun;
     513        int rc;
     514       
     515        log_msg(LVL_DEBUG, "devman_drv_fun_online()");
     516       
     517        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     518        if (fun == NULL) {
     519                async_answer_0(iid, ENOENT);
     520                return;
     521        }
     522       
     523        fibril_rwlock_read_lock(&device_tree.rwlock);
     524        if (fun->dev == NULL || fun->dev->drv != drv) {
     525                fibril_rwlock_read_unlock(&device_tree.rwlock);
     526                fun_del_ref(fun);
     527                async_answer_0(iid, ENOENT);
     528                return;
     529        }
     530        fibril_rwlock_read_unlock(&device_tree.rwlock);
     531       
     532        rc = online_function(fun);
     533        if (rc != EOK) {
     534                fun_del_ref(fun);
     535                async_answer_0(iid, (sysarg_t) rc);
     536                return;
     537        }
     538       
     539        fun_del_ref(fun);
     540       
     541        async_answer_0(iid, (sysarg_t) EOK);
     542}
     543
     544
     545/** Offline function by driver request.
     546 *
     547 */
     548static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
     549    driver_t *drv)
     550{
     551        fun_node_t *fun;
     552        int rc;
     553
     554        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     555        if (fun == NULL) {
     556                async_answer_0(iid, ENOENT);
     557                return;
     558        }
     559       
     560        fibril_rwlock_write_lock(&device_tree.rwlock);
     561        if (fun->dev == NULL || fun->dev->drv != drv) {
     562                fun_del_ref(fun);
     563                async_answer_0(iid, ENOENT);
     564                return;
     565        }
     566        fibril_rwlock_write_unlock(&device_tree.rwlock);
     567       
     568        rc = offline_function(fun);
     569        if (rc != EOK) {
     570                fun_del_ref(fun);
     571                async_answer_0(iid, (sysarg_t) rc);
     572                return;
     573        }
     574       
     575        fun_del_ref(fun);
     576        async_answer_0(iid, (sysarg_t) EOK);
     577}
     578
     579/** Remove function. */
     580static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
     581{
     582        devman_handle_t fun_handle = IPC_GET_ARG1(*call);
     583        dev_tree_t *tree = &device_tree;
     584        int rc;
     585       
     586        fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
     587        if (fun == NULL) {
     588                async_answer_0(callid, ENOENT);
     589                return;
     590        }
     591       
     592        fibril_rwlock_write_lock(&tree->rwlock);
     593       
     594        log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
     595       
     596        /* Check function state */
     597        if (fun->state == FUN_REMOVED) {
     598                fibril_rwlock_write_unlock(&tree->rwlock);
     599                async_answer_0(callid, ENOENT);
     600                return;
     601        }
     602       
     603        if (fun->ftype == fun_inner) {
     604                /* This is a surprise removal. Handle possible descendants */
     605                if (fun->child != NULL) {
     606                        dev_node_t *dev = fun->child;
     607                        device_state_t dev_state;
     608                        int gone_rc;
     609                       
     610                        dev_add_ref(dev);
     611                        dev_state = dev->state;
     612                       
     613                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     614                       
     615                        /* If device is owned by driver, inform driver it is gone. */
     616                        if (dev_state == DEVICE_USABLE)
     617                                gone_rc = driver_dev_gone(&device_tree, dev);
     618                        else
     619                                gone_rc = EOK;
     620                       
     621                        fibril_rwlock_read_lock(&device_tree.rwlock);
     622                       
     623                        /* Verify that driver succeeded and removed all functions */
     624                        if (gone_rc != EOK || !list_empty(&dev->functions)) {
     625                                log_msg(LVL_ERROR, "Driver did not remove "
     626                                    "functions for device that is gone. "
     627                                    "Device node is now defunct.");
     628                               
     629                                /*
     630                                 * Not much we can do but mark the device
     631                                 * node as having invalid state. This
     632                                 * is a driver bug.
     633                                 */
     634                                dev->state = DEVICE_INVALID;
     635                                fibril_rwlock_read_unlock(&device_tree.rwlock);
     636                                dev_del_ref(dev);
     637                                return;
     638                        }
     639                       
     640                        driver_t *driver = dev->drv;
     641                        fibril_rwlock_read_unlock(&device_tree.rwlock);
     642                       
     643                        if (driver)
     644                                detach_driver(&device_tree, dev);
     645                       
     646                        fibril_rwlock_write_lock(&device_tree.rwlock);
     647                        remove_dev_node(&device_tree, dev);
     648                       
     649                        /* Delete ref created when node was inserted */
     650                        dev_del_ref(dev);
     651                        /* Delete ref created by dev_add_ref(dev) above */
     652                        dev_del_ref(dev);
     653                }
     654        } else {
     655                if (fun->service_id != 0) {
     656                        /* Unregister from location service */
     657                        rc = loc_service_unregister(fun->service_id);
     658                        if (rc != EOK) {
     659                                log_msg(LVL_ERROR, "Failed unregistering tree "
     660                                    "service.");
     661                                fibril_rwlock_write_unlock(&tree->rwlock);
     662                                fun_del_ref(fun);
     663                                async_answer_0(callid, EIO);
     664                                return;
     665                        }
     666                }
     667        }
     668       
     669        remove_fun_node(&device_tree, fun);
     670        fibril_rwlock_write_unlock(&tree->rwlock);
     671       
     672        /* Delete ref added when inserting function into tree */
     673        fun_del_ref(fun);
     674        /* Delete ref added above when looking up function */
     675        fun_del_ref(fun);
     676       
     677        log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
    389678        async_answer_0(callid, EOK);
    390679}
     
    408697static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    409698{
     699        client_t *client;
     700        driver_t *driver;
     701       
    410702        /* Accept the connection. */
    411703        async_answer_0(iid, EOK);
    412704       
    413         driver_t *driver = devman_driver_register();
    414         if (driver == NULL)
    415                 return;
    416        
    417         /*
    418          * Initialize the driver as running (e.g. pass assigned devices to it)
    419          * in a separate fibril; the separate fibril is used to enable the
    420          * driver to use devman service during the driver's initialization.
    421          */
    422         fid_t fid = fibril_create(init_running_drv, driver);
    423         if (fid == 0) {
    424                 log_msg(LVL_ERROR, "Failed to create initialization fibril " \
    425                     "for driver `%s'.", driver->name);
    426                 return;
    427         }
    428         fibril_add_ready(fid);
     705        client = async_get_client_data();
     706        if (client == NULL) {
     707                log_msg(LVL_ERROR, "Failed to allocate client data.");
     708                return;
     709        }
    429710       
    430711        while (true) {
     
    435716                        break;
    436717               
     718                if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
     719                        fibril_mutex_lock(&client->mutex);
     720                        driver = client->driver;
     721                        fibril_mutex_unlock(&client->mutex);
     722                        if (driver == NULL) {
     723                                /* First call must be to DEVMAN_DRIVER_REGISTER */
     724                                async_answer_0(callid, ENOTSUP);
     725                                continue;
     726                        }
     727                }
     728               
    437729                switch (IPC_GET_IMETHOD(call)) {
     730                case DEVMAN_DRIVER_REGISTER:
     731                        fibril_mutex_lock(&client->mutex);
     732                        if (client->driver != NULL) {
     733                                fibril_mutex_unlock(&client->mutex);
     734                                async_answer_0(callid, EINVAL);
     735                                continue;
     736                        }
     737                        client->driver = devman_driver_register(callid, &call);
     738                        fibril_mutex_unlock(&client->mutex);
     739                        break;
    438740                case DEVMAN_ADD_FUNCTION:
    439741                        devman_add_function(callid, &call);
    440742                        break;
    441                 case DEVMAN_ADD_DEVICE_TO_CLASS:
    442                         devman_add_function_to_class(callid, &call);
     743                case DEVMAN_ADD_DEVICE_TO_CATEGORY:
     744                        devman_add_function_to_cat(callid, &call);
     745                        break;
     746                case DEVMAN_DRV_FUN_ONLINE:
     747                        devman_drv_fun_online(callid, &call, driver);
     748                        break;
     749                case DEVMAN_DRV_FUN_OFFLINE:
     750                        devman_drv_fun_offline(callid, &call, driver);
     751                        break;
     752                case DEVMAN_REMOVE_FUNCTION:
     753                        devman_remove_function(callid, &call);
    443754                        break;
    444755                default:
    445                         async_answer_0(callid, EINVAL); 
     756                        async_answer_0(callid, EINVAL);
    446757                        break;
    447758                }
     
    454765{
    455766        char *pathname;
     767        devman_handle_t handle;
    456768       
    457769        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     
    470782        }
    471783
    472         async_answer_1(iid, EOK, fun->handle);
    473 }
    474 
    475 /** Find handle for the device instance identified by device class name. */
    476 static void devman_function_get_handle_by_class(ipc_callid_t iid,
    477     ipc_call_t *icall)
    478 {
    479         char *classname;
    480         char *devname;
    481 
    482         int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0);
    483         if (rc != EOK) {
    484                 async_answer_0(iid, rc);
    485                 return;
    486         }
    487         rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0);
    488         if (rc != EOK) {
    489                 free(classname);
    490                 async_answer_0(iid, rc);
    491                 return;
    492         }
    493 
    494 
    495         fun_node_t *fun = find_fun_node_by_class(&class_list,
    496             classname, devname);
    497 
    498         free(classname);
    499         free(devname);
    500 
    501         if (fun == NULL) {
    502                 async_answer_0(iid, ENOENT);
    503                 return;
    504         }
    505 
    506         async_answer_1(iid, EOK, fun->handle);
    507 }
    508 
    509 /** Find device path by its handle. */
    510 static void devman_get_device_path_by_handle(ipc_callid_t iid,
    511     ipc_call_t *icall)
     784        fibril_rwlock_read_lock(&device_tree.rwlock);
     785
     786        /* Check function state */
     787        if (fun->state == FUN_REMOVED) {
     788                fibril_rwlock_read_unlock(&device_tree.rwlock);
     789                async_answer_0(iid, ENOENT);
     790                return;
     791        }
     792        handle = fun->handle;
     793
     794        fibril_rwlock_read_unlock(&device_tree.rwlock);
     795
     796        /* Delete reference created above by find_fun_node_by_path() */
     797        fun_del_ref(fun);
     798
     799        async_answer_1(iid, EOK, handle);
     800}
     801
     802/** Get device name. */
     803static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
    512804{
    513805        devman_handle_t handle = IPC_GET_ARG1(*icall);
     
    523815        if (!async_data_read_receive(&data_callid, &data_len)) {
    524816                async_answer_0(iid, EINVAL);
     817                fun_del_ref(fun);
    525818                return;
    526819        }
     
    530823                async_answer_0(data_callid, ENOMEM);
    531824                async_answer_0(iid, ENOMEM);
    532                 return;
    533         }
    534 
     825                fun_del_ref(fun);
     826                return;
     827        }
     828
     829        fibril_rwlock_read_lock(&device_tree.rwlock);
     830
     831        /* Check function state */
     832        if (fun->state == FUN_REMOVED) {
     833                fibril_rwlock_read_unlock(&device_tree.rwlock);
     834                free(buffer);
     835
     836                async_answer_0(data_callid, ENOENT);
     837                async_answer_0(iid, ENOENT);
     838                fun_del_ref(fun);
     839                return;
     840        }
     841
     842        size_t sent_length = str_size(fun->name);
     843        if (sent_length > data_len) {
     844                sent_length = data_len;
     845        }
     846
     847        async_data_read_finalize(data_callid, fun->name, sent_length);
     848        async_answer_0(iid, EOK);
     849
     850        fibril_rwlock_read_unlock(&device_tree.rwlock);
     851        fun_del_ref(fun);
     852        free(buffer);
     853}
     854
     855
     856/** Get device path. */
     857static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall)
     858{
     859        devman_handle_t handle = IPC_GET_ARG1(*icall);
     860
     861        fun_node_t *fun = find_fun_node(&device_tree, handle);
     862        if (fun == NULL) {
     863                async_answer_0(iid, ENOMEM);
     864                return;
     865        }
     866
     867        ipc_callid_t data_callid;
     868        size_t data_len;
     869        if (!async_data_read_receive(&data_callid, &data_len)) {
     870                async_answer_0(iid, EINVAL);
     871                fun_del_ref(fun);
     872                return;
     873        }
     874
     875        void *buffer = malloc(data_len);
     876        if (buffer == NULL) {
     877                async_answer_0(data_callid, ENOMEM);
     878                async_answer_0(iid, ENOMEM);
     879                fun_del_ref(fun);
     880                return;
     881        }
     882       
     883        fibril_rwlock_read_lock(&device_tree.rwlock);
     884       
     885        /* Check function state */
     886        if (fun->state == FUN_REMOVED) {
     887                fibril_rwlock_read_unlock(&device_tree.rwlock);
     888                free(buffer);
     889
     890                async_answer_0(data_callid, ENOENT);
     891                async_answer_0(iid, ENOENT);
     892                fun_del_ref(fun);
     893                return;
     894        }
     895       
    535896        size_t sent_length = str_size(fun->pathname);
    536897        if (sent_length > data_len) {
     
    541902        async_answer_0(iid, EOK);
    542903
     904        fibril_rwlock_read_unlock(&device_tree.rwlock);
     905        fun_del_ref(fun);
    543906        free(buffer);
    544907}
    545908
     909static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)
     910{
     911        ipc_callid_t callid;
     912        size_t size;
     913        size_t act_size;
     914        int rc;
     915       
     916        if (!async_data_read_receive(&callid, &size)) {
     917                async_answer_0(callid, EREFUSED);
     918                async_answer_0(iid, EREFUSED);
     919                return;
     920        }
     921       
     922        fibril_rwlock_read_lock(&device_tree.rwlock);
     923       
     924        dev_node_t *dev = find_dev_node_no_lock(&device_tree,
     925            IPC_GET_ARG1(*icall));
     926        if (dev == NULL || dev->state == DEVICE_REMOVED) {
     927                fibril_rwlock_read_unlock(&device_tree.rwlock);
     928                async_answer_0(callid, ENOENT);
     929                async_answer_0(iid, ENOENT);
     930                return;
     931        }
     932       
     933        devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
     934        if (hdl_buf == NULL) {
     935                fibril_rwlock_read_unlock(&device_tree.rwlock);
     936                async_answer_0(callid, ENOMEM);
     937                async_answer_0(iid, ENOMEM);
     938                return;
     939        }
     940       
     941        rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
     942        if (rc != EOK) {
     943                fibril_rwlock_read_unlock(&device_tree.rwlock);
     944                async_answer_0(callid, rc);
     945                async_answer_0(iid, rc);
     946                return;
     947        }
     948       
     949        fibril_rwlock_read_unlock(&device_tree.rwlock);
     950       
     951        sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);
     952        free(hdl_buf);
     953       
     954        async_answer_1(iid, retval, act_size);
     955}
     956
     957
     958/** Get handle for child device of a function. */
     959static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)
     960{
     961        fun_node_t *fun;
     962       
     963        fibril_rwlock_read_lock(&device_tree.rwlock);
     964       
     965        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     966        if (fun == NULL || fun->state == FUN_REMOVED) {
     967                fibril_rwlock_read_unlock(&device_tree.rwlock);
     968                async_answer_0(iid, ENOENT);
     969                return;
     970        }
     971       
     972        if (fun->child == NULL) {
     973                fibril_rwlock_read_unlock(&device_tree.rwlock);
     974                async_answer_0(iid, ENOENT);
     975                return;
     976        }
     977       
     978        async_answer_1(iid, EOK, fun->child->handle);
     979       
     980        fibril_rwlock_read_unlock(&device_tree.rwlock);
     981}
     982
     983/** Online function.
     984 *
     985 * Send a request to online a function to the responsible driver.
     986 * The driver may offline other functions if necessary (i.e. if the state
     987 * of this function is linked to state of another function somehow).
     988 */
     989static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     990{
     991        fun_node_t *fun;
     992        int rc;
     993
     994        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     995        if (fun == NULL) {
     996                async_answer_0(iid, ENOENT);
     997                return;
     998        }
     999       
     1000        rc = driver_fun_online(&device_tree, fun);
     1001        fun_del_ref(fun);
     1002       
     1003        async_answer_0(iid, (sysarg_t) rc);
     1004}
     1005
     1006/** Offline function.
     1007 *
     1008 * Send a request to offline a function to the responsible driver. As
     1009 * a result the subtree rooted at that function should be cleanly
     1010 * detatched. The driver may offline other functions if necessary
     1011 * (i.e. if the state of this function is linked to state of another
     1012 * function somehow).
     1013 */
     1014static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     1015{
     1016        fun_node_t *fun;
     1017        int rc;
     1018
     1019        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     1020        if (fun == NULL) {
     1021                async_answer_0(iid, ENOENT);
     1022                return;
     1023        }
     1024       
     1025        rc = driver_fun_offline(&device_tree, fun);
     1026        fun_del_ref(fun);
     1027       
     1028        async_answer_0(iid, (sysarg_t) rc);
     1029}
     1030
     1031/** Find handle for the function instance identified by its service ID. */
     1032static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
     1033{
     1034        fun_node_t *fun;
     1035
     1036        fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
     1037       
     1038        if (fun == NULL) {
     1039                async_answer_0(iid, ENOENT);
     1040                return;
     1041        }
     1042
     1043        fibril_rwlock_read_lock(&device_tree.rwlock);
     1044
     1045        /* Check function state */
     1046        if (fun->state == FUN_REMOVED) {
     1047                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1048                async_answer_0(iid, ENOENT);
     1049                return;
     1050        }
     1051
     1052        async_answer_1(iid, EOK, fun->handle);
     1053        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1054        fun_del_ref(fun);
     1055}
    5461056
    5471057/** Function for handling connections from a client to the device manager. */
     
    5621072                        devman_function_get_handle(callid, &call);
    5631073                        break;
    564                 case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
    565                         devman_function_get_handle_by_class(callid, &call);
    566                         break;
    567                 case DEVMAN_DEVICE_GET_DEVICE_PATH:
    568                         devman_get_device_path_by_handle(callid, &call);
     1074                case DEVMAN_DEV_GET_FUNCTIONS:
     1075                        devman_dev_get_functions(callid, &call);
     1076                        break;
     1077                case DEVMAN_FUN_GET_CHILD:
     1078                        devman_fun_get_child(callid, &call);
     1079                        break;
     1080                case DEVMAN_FUN_GET_NAME:
     1081                        devman_fun_get_name(callid, &call);
     1082                        break;
     1083                case DEVMAN_FUN_GET_PATH:
     1084                        devman_fun_get_path(callid, &call);
     1085                        break;
     1086                case DEVMAN_FUN_ONLINE:
     1087                        devman_fun_online(callid, &call);
     1088                        break;
     1089                case DEVMAN_FUN_OFFLINE:
     1090                        devman_fun_offline(callid, &call);
     1091                        break;
     1092                case DEVMAN_FUN_SID_TO_HANDLE:
     1093                        devman_fun_sid_to_handle(callid, &call);
    5691094                        break;
    5701095                default:
     
    5851110        if (fun == NULL)
    5861111                dev = find_dev_node(&device_tree, handle);
    587         else
     1112        else {
     1113                fibril_rwlock_read_lock(&device_tree.rwlock);
    5881114                dev = fun->dev;
     1115                if (dev != NULL)
     1116                        dev_add_ref(dev);
     1117                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1118        }
    5891119
    5901120        /*
     
    5981128                    "function with handle %" PRIun " was found.", handle);
    5991129                async_answer_0(iid, ENOENT);
    600                 return;
     1130                goto cleanup;
    6011131        }
    6021132
     
    6061136                    handle);
    6071137                async_answer_0(iid, ENOENT);
    608                 return;
     1138                goto cleanup;
    6091139        }
    6101140       
    6111141        driver_t *driver = NULL;
     1142       
     1143        fibril_rwlock_read_lock(&device_tree.rwlock);
    6121144       
    6131145        if (drv_to_parent) {
     
    6241156        }
    6251157       
     1158        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1159       
    6261160        if (driver == NULL) {
    6271161                log_msg(LVL_ERROR, "IPC forwarding refused - " \
    6281162                    "the device %" PRIun " is not in usable state.", handle);
    6291163                async_answer_0(iid, ENOENT);
    630                 return;
     1164                goto cleanup;
    6311165        }
    6321166       
     
    6411175                    "Could not forward to driver `%s'.", driver->name);
    6421176                async_answer_0(iid, EINVAL);
    643                 return;
     1177                goto cleanup;
    6441178        }
    6451179
     
    6571191        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    6581192        async_exchange_end(exch);
    659 }
    660 
    661 /** Function for handling connections from a client forwarded by the device
    662  * mapper to the device manager. */
    663 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
    664 {
    665         devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
     1193
     1194cleanup:
     1195        if (dev != NULL)
     1196                dev_del_ref(dev);
     1197        if (fun != NULL)
     1198                fun_del_ref(fun);
     1199}
     1200
     1201/** Function for handling connections from a client forwarded by the location
     1202 * service to the device manager. */
     1203static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
     1204{
     1205        service_id_t service_id = IPC_GET_ARG2(*icall);
    6661206        fun_node_t *fun;
    6671207        dev_node_t *dev;
    668 
    669         fun = find_devmap_tree_function(&device_tree, devmap_handle);
    670         if (fun == NULL)
    671                 fun = find_devmap_class_function(&class_list, devmap_handle);
    672        
    673         if (fun == NULL || fun->dev->drv == NULL) {
     1208        devman_handle_t handle;
     1209        driver_t *driver;
     1210
     1211        fun = find_loc_tree_function(&device_tree, service_id);
     1212       
     1213        fibril_rwlock_read_lock(&device_tree.rwlock);
     1214       
     1215        if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
     1216                log_msg(LVL_WARN, "devman_connection_loc(): function "
     1217                    "not found.\n");
     1218                fibril_rwlock_read_unlock(&device_tree.rwlock);
    6741219                async_answer_0(iid, ENOENT);
    6751220                return;
     
    6771222       
    6781223        dev = fun->dev;
    679        
    680         if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) {
    681                 async_answer_0(iid, EINVAL);
    682                 return;
    683         }
    684        
    685         async_exch_t *exch = async_exchange_begin(dev->drv->sess);
    686         async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0,
     1224        driver = dev->drv;
     1225        handle = fun->handle;
     1226       
     1227        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1228       
     1229        async_exch_t *exch = async_exchange_begin(driver->sess);
     1230        async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
    6871231            IPC_FF_NONE);
    6881232        async_exchange_end(exch);
    6891233       
    6901234        log_msg(LVL_DEBUG,
    691             "Forwarding devmapper request for `%s' function to driver `%s'.",
    692             fun->pathname, dev->drv->name);
     1235            "Forwarding loc service request for `%s' function to driver `%s'.",
     1236            fun->pathname, driver->name);
     1237
     1238        fun_del_ref(fun);
    6931239}
    6941240
     
    6961242static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    6971243{
    698         /* Select interface. */
     1244        /* Select port. */
    6991245        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    7001246        case DEVMAN_DRIVER:
     
    7081254                devman_forward(iid, icall, false);
    7091255                break;
    710         case DEVMAN_CONNECT_FROM_DEVMAP:
    711                 /* Someone connected through devmap node. */
    712                 devman_connection_devmapper(iid, icall);
     1256        case DEVMAN_CONNECT_FROM_LOC:
     1257                /* Someone connected through loc node. */
     1258                devman_connection_loc(iid, icall);
    7131259                break;
    7141260        case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
     
    7221268}
    7231269
     1270static void *devman_client_data_create(void)
     1271{
     1272        client_t *client;
     1273       
     1274        client = calloc(1, sizeof(client_t));
     1275        if (client == NULL)
     1276                return NULL;
     1277       
     1278        fibril_mutex_initialize(&client->mutex);
     1279        return client;
     1280}
     1281
     1282static void devman_client_data_destroy(void *data)
     1283{
     1284        free(data);
     1285}
     1286
    7241287/** Initialize device manager internal structures. */
    7251288static bool devman_init(void)
     
    7431306        }
    7441307
    745         init_class_list(&class_list);
    746        
    7471308        /*
    748          * !!! devman_connection ... as the device manager is not a real devmap
     1309         * !!! devman_connection ... as the device manager is not a real loc
    7491310         * driver (it uses a completely different ipc protocol than an ordinary
    750          * devmap driver) forwarding a connection from client to the devman by
    751          * devmapper would not work.
     1311         * loc driver) forwarding a connection from client to the devman by
     1312         * location service would not work.
    7521313         */
    753         devmap_driver_register(NAME, devman_connection);
     1314        loc_server_register(NAME, devman_connection);
    7541315       
    7551316        return true;
     
    7601321        printf(NAME ": HelenOS Device Manager\n");
    7611322
    762         if (log_init(NAME, LVL_ERROR) != EOK) {
     1323        if (log_init(NAME, LVL_WARN) != EOK) {
    7631324                printf(NAME ": Error initializing logging subsystem.\n");
    7641325                return -1;
     
    7701331        }
    7711332       
    772         /* Set a handler of incomming connections. */
     1333        /* Set handlers for incoming connections. */
     1334        async_set_client_data_constructor(devman_client_data_create);
     1335        async_set_client_data_destructor(devman_client_data_destroy);
    7731336        async_set_client_connection(devman_connection);
    7741337
Note: See TracChangeset for help on using the changeset viewer.