Ignore:
File:
1 edited

Legend:

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

    ra96a982 r9934f7d  
    5656#include <ipc/driver.h>
    5757#include <thread.h>
    58 #include <loc.h>
     58#include <devmap.h>
    5959
    6060#include "devman.h"
     
    6464static driver_list_t drivers_list;
    6565static dev_tree_t device_tree;
    66 
    67 static int init_running_drv(void *drv);
     66static class_list_t class_list;
    6867
    6968/** Register running driver. */
    70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
    71 {
     69static driver_t *devman_driver_register(void)
     70{
     71        ipc_call_t icall;
     72        ipc_callid_t iid;
    7273        driver_t *driver = NULL;
     74
     75        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       
    7383        char *drv_name = NULL;
    74 
    75         log_msg(LVL_DEBUG, "devman_driver_register");
    7684       
    7785        /* Get driver name. */
    7886        int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    7987        if (rc != EOK) {
    80                 async_answer_0(callid, rc);
     88                async_answer_0(iid, rc);
    8189                return NULL;
    8290        }
     
    9199                free(drv_name);
    92100                drv_name = NULL;
    93                 async_answer_0(callid, ENOENT);
     101                async_answer_0(iid, ENOENT);
    94102                return NULL;
    95103        }
     
    105113                    driver->name);
    106114                fibril_mutex_unlock(&driver->driver_mutex);
    107                 async_answer_0(callid, EEXISTS);
     115                async_answer_0(iid, EEXISTS);
    108116                return NULL;
    109117        }
     
    127135        log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
    128136            driver->name);
    129         driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
     137        driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
    130138        if (!driver->sess) {
    131139                fibril_mutex_unlock(&driver->driver_mutex);
    132                 async_answer_0(callid, ENOTSUP);
     140                async_answer_0(iid, ENOTSUP);
    133141                return NULL;
    134142        }
    135         /* FIXME: Work around problem with callback sessions */
    136         async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
     143       
     144        fibril_mutex_unlock(&driver->driver_mutex);
    137145       
    138146        log_msg(LVL_NOTE,
    139147            "The `%s' driver was successfully registered as running.",
    140148            driver->name);
     149       
     150        async_answer_0(iid, EOK);
     151       
     152        return driver;
     153}
     154
     155/** Receive device match ID from the device's parent driver and add it to the
     156 * list of devices match ids.
     157 *
     158 * @param match_ids     The list of the device's match ids.
     159 * @return              Zero on success, negative error code otherwise.
     160 */
     161static int devman_receive_match_id(match_id_list_t *match_ids)
     162{
     163        match_id_t *match_id = create_match_id();
     164        ipc_callid_t callid;
     165        ipc_call_t call;
     166        int rc = 0;
     167       
     168        callid = async_get_call(&call);
     169        if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
     170                log_msg(LVL_ERROR,
     171                    "Invalid protocol when trying to receive match id.");
     172                async_answer_0(callid, EINVAL);
     173                delete_match_id(match_id);
     174                return EINVAL;
     175        }
     176       
     177        if (match_id == NULL) {
     178                log_msg(LVL_ERROR, "Failed to allocate match id.");
     179                async_answer_0(callid, ENOMEM);
     180                return ENOMEM;
     181        }
     182       
     183        async_answer_0(callid, EOK);
     184       
     185        match_id->score = IPC_GET_ARG1(call);
     186       
     187        char *match_id_str;
     188        rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
     189        match_id->id = match_id_str;
     190        if (rc != EOK) {
     191                delete_match_id(match_id);
     192                log_msg(LVL_ERROR, "Failed to receive match id string: %s.",
     193                    str_error(rc));
     194                return rc;
     195        }
     196       
     197        list_append(&match_id->link, &match_ids->ids);
     198       
     199        log_msg(LVL_DEBUG, "Received match id `%s', score %d.",
     200            match_id->id, match_id->score);
     201        return rc;
     202}
     203
     204/** Receive device match IDs from the device's parent driver and add them to the
     205 * list of devices match ids.
     206 *
     207 * @param match_count   The number of device's match ids to be received.
     208 * @param match_ids     The list of the device's match ids.
     209 * @return              Zero on success, negative error code otherwise.
     210 */
     211static int devman_receive_match_ids(sysarg_t match_count,
     212    match_id_list_t *match_ids)
     213{
     214        int ret = EOK;
     215        size_t i;
     216       
     217        for (i = 0; i < match_count; i++) {
     218                if (EOK != (ret = devman_receive_match_id(match_ids)))
     219                        return ret;
     220        }
     221        return ret;
     222}
     223
     224static int assign_driver_fibril(void *arg)
     225{
     226        dev_node_t *dev_node = (dev_node_t *) arg;
     227        assign_driver(dev_node, &drivers_list, &device_tree);
     228        return EOK;
     229}
     230
     231/** Handle function registration.
     232 *
     233 * Child devices are registered by their parent's device driver.
     234 */
     235static 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) {
     291                dev = create_dev_node();
     292                if (dev == NULL) {
     293                        fibril_rwlock_write_unlock(&tree->rwlock);
     294                        delete_fun_node(fun);
     295                        async_answer_0(callid, ENOMEM);
     296                        return;
     297                }
     298
     299                insert_dev_node(tree, dev, fun);
     300        }
     301
     302        fibril_rwlock_write_unlock(&tree->rwlock);
     303       
     304        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
     305       
     306        devman_receive_match_ids(match_count, &fun->match_ids);
     307
     308        if (ftype == fun_inner) {
     309                assert(dev != NULL);
     310                /*
     311                 * Try to find a suitable driver and assign it to the device.  We do
     312                 * not want to block the current fibril that is used for processing
     313                 * incoming calls: we will launch a separate fibril to handle the
     314                 * driver assigning. That is because assign_driver can actually include
     315                 * task spawning which could take some time.
     316                 */
     317                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
     318                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);
     326                }
     327        } else {
     328                devmap_register_tree_function(fun, tree);
     329        }
     330       
     331        /* Return device handle to parent's driver. */
     332        async_answer_1(callid, EOK, fun->handle);
     333}
     334
     335static 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
     361static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
     362{
     363        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,
     368            0, 0, 0, 0);
     369        if (rc != EOK) {
     370                async_answer_0(callid, rc);
     371                return;
     372        }       
     373       
     374        fun_node_t *fun = find_fun_node(&device_tree, handle);
     375        if (fun == NULL) {
     376                async_answer_0(callid, ENOENT);
     377                return;
     378        }
     379       
     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
     389        async_answer_0(callid, EOK);
     390}
     391
     392/** Initialize driver which has registered itself as running and ready.
     393 *
     394 * The initialization is done in a separate fibril to avoid deadlocks (if the
     395 * driver needed to be served by devman during the driver's initialization).
     396 */
     397static int init_running_drv(void *drv)
     398{
     399        driver_t *driver = (driver_t *) drv;
     400       
     401        initialize_running_driver(driver, &device_tree);
     402        log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
     403            driver->name);
     404        return 0;
     405}
     406
     407/** Function for handling connections from a driver to the device manager. */
     408static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
     409{
     410        /* Accept the connection. */
     411        async_answer_0(iid, EOK);
     412       
     413        driver_t *driver = devman_driver_register();
     414        if (driver == NULL)
     415                return;
    141416       
    142417        /*
     
    149424                log_msg(LVL_ERROR, "Failed to create initialization fibril " \
    150425                    "for driver `%s'.", driver->name);
    151                 fibril_mutex_unlock(&driver->driver_mutex);
    152                 async_answer_0(callid, ENOMEM);
    153                 return NULL;
    154         }
    155        
     426                return;
     427        }
    156428        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  */
    169 static 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(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(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(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(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  */
    219 static 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 
    232 static 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 
    242 static 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) {
    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(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                  * Try to find a suitable driver and assign it to the device.  We do
    276                  * not want to block the current fibril that is used for processing
    277                  * incoming calls: we will launch a separate fibril to handle the
    278                  * driver assigning. That is because assign_driver can actually include
    279                  * task spawning which could take some time.
    280                  */
    281                 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
    282                 if (assign_fibril == 0) {
    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 
    299 static 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);
    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(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  */
    378 static 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;
    453         }
    454        
    455         /* Return device handle to parent's driver. */
    456         async_answer_1(callid, EOK, fun->handle);
    457 }
    458 
    459 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
    460 {
    461         devman_handle_t handle = IPC_GET_ARG1(*call);
    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,
    468             0, 0, 0, 0);
    469         if (rc != EOK) {
    470                 async_answer_0(callid, rc);
    471                 return;
    472         }
    473        
    474         fun_node_t *fun = find_fun_node(&device_tree, handle);
    475         if (fun == NULL) {
    476                 async_answer_0(callid, ENOENT);
    477                 return;
    478         }
    479        
    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                 log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
    493                     fun->pathname, cat_name);
    494         } else {
    495                 log_msg(LVL_ERROR, "Failed adding function `%s' to category "
    496                     "`%s'.", fun->pathname, cat_name);
    497         }
    498        
    499         fibril_rwlock_read_unlock(&device_tree.rwlock);
    500         fun_del_ref(fun);
    501        
    502         async_answer_0(callid, rc);
    503 }
    504 
    505 /** Online function by driver request.
    506  *
    507  */
    508 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
    509     driver_t *drv)
    510 {
    511         fun_node_t *fun;
    512         int rc;
    513        
    514         log_msg(LVL_DEBUG, "devman_drv_fun_online()");
    515        
    516         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    517         if (fun == NULL) {
    518                 async_answer_0(iid, ENOENT);
    519                 return;
    520         }
    521        
    522         fibril_rwlock_read_lock(&device_tree.rwlock);
    523         if (fun->dev == NULL || fun->dev->drv != drv) {
    524                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    525                 fun_del_ref(fun);
    526                 async_answer_0(iid, ENOENT);
    527                 return;
    528         }
    529         fibril_rwlock_read_unlock(&device_tree.rwlock);
    530        
    531         rc = online_function(fun);
    532         if (rc != EOK) {
    533                 fun_del_ref(fun);
    534                 async_answer_0(iid, (sysarg_t) rc);
    535                 return;
    536         }
    537        
    538         fun_del_ref(fun);
    539        
    540         async_answer_0(iid, (sysarg_t) EOK);
    541 }
    542 
    543 
    544 /** Offline function by driver request.
    545  *
    546  */
    547 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
    548     driver_t *drv)
    549 {
    550         fun_node_t *fun;
    551         int rc;
    552 
    553         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    554         if (fun == NULL) {
    555                 async_answer_0(iid, ENOENT);
    556                 return;
    557         }
    558        
    559         fibril_rwlock_write_lock(&device_tree.rwlock);
    560         if (fun->dev == NULL || fun->dev->drv != drv) {
    561                 fun_del_ref(fun);
    562                 async_answer_0(iid, ENOENT);
    563                 return;
    564         }
    565         fibril_rwlock_write_unlock(&device_tree.rwlock);
    566        
    567         rc = offline_function(fun);
    568         if (rc != EOK) {
    569                 fun_del_ref(fun);
    570                 async_answer_0(iid, (sysarg_t) rc);
    571                 return;
    572         }
    573        
    574         fun_del_ref(fun);
    575         async_answer_0(iid, (sysarg_t) EOK);
    576 }
    577 
    578 /** Remove function. */
    579 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
    580 {
    581         devman_handle_t fun_handle = IPC_GET_ARG1(*call);
    582         dev_tree_t *tree = &device_tree;
    583         int rc;
    584        
    585         fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
    586         if (fun == NULL) {
    587                 async_answer_0(callid, ENOENT);
    588                 return;
    589         }
    590        
    591         fibril_rwlock_write_lock(&tree->rwlock);
    592        
    593         log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    594        
    595         /* Check function state */
    596         if (fun->state == FUN_REMOVED) {
    597                 fibril_rwlock_write_unlock(&tree->rwlock);
    598                 async_answer_0(callid, ENOENT);
    599                 return;
    600         }
    601        
    602         if (fun->ftype == fun_inner) {
    603                 /* This is a surprise removal. Handle possible descendants */
    604                 if (fun->child != NULL) {
    605                         dev_node_t *dev = fun->child;
    606                         device_state_t dev_state;
    607                         int gone_rc;
    608                        
    609                         dev_add_ref(dev);
    610                         dev_state = dev->state;
    611                        
    612                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    613                        
    614                         /* If device is owned by driver, inform driver it is gone. */
    615                         if (dev_state == DEVICE_USABLE)
    616                                 gone_rc = driver_dev_gone(&device_tree, dev);
    617                         else
    618                                 gone_rc = EOK;
    619                        
    620                         fibril_rwlock_read_lock(&device_tree.rwlock);
    621                        
    622                         /* Verify that driver succeeded and removed all functions */
    623                         if (gone_rc != EOK || !list_empty(&dev->functions)) {
    624                                 log_msg(LVL_ERROR, "Driver did not remove "
    625                                     "functions for device that is gone. "
    626                                     "Device node is now defunct.");
    627                                
    628                                 /*
    629                                  * Not much we can do but mark the device
    630                                  * node as having invalid state. This
    631                                  * is a driver bug.
    632                                  */
    633                                 dev->state = DEVICE_INVALID;
    634                                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    635                                 dev_del_ref(dev);
    636                                 return;
    637                         }
    638                        
    639                         driver_t *driver = dev->drv;
    640                         fibril_rwlock_read_unlock(&device_tree.rwlock);
    641                        
    642                         if (driver)
    643                                 detach_driver(&device_tree, dev);
    644                        
    645                         fibril_rwlock_write_lock(&device_tree.rwlock);
    646                         remove_dev_node(&device_tree, dev);
    647                        
    648                         /* Delete ref created when node was inserted */
    649                         dev_del_ref(dev);
    650                         /* Delete ref created by dev_add_ref(dev) above */
    651                         dev_del_ref(dev);
    652                 }
    653         } else {
    654                 if (fun->service_id != 0) {
    655                         /* Unregister from location service */
    656                         rc = loc_service_unregister(fun->service_id);
    657                         if (rc != EOK) {
    658                                 log_msg(LVL_ERROR, "Failed unregistering tree "
    659                                     "service.");
    660                                 fibril_rwlock_write_unlock(&tree->rwlock);
    661                                 fun_del_ref(fun);
    662                                 async_answer_0(callid, EIO);
    663                                 return;
    664                         }
    665                 }
    666         }
    667        
    668         remove_fun_node(&device_tree, fun);
    669         fibril_rwlock_write_unlock(&tree->rwlock);
    670        
    671         /* Delete ref added when inserting function into tree */
    672         fun_del_ref(fun);
    673         /* Delete ref added above when looking up function */
    674         fun_del_ref(fun);
    675        
    676         log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
    677         async_answer_0(callid, EOK);
    678 }
    679 
    680 /** Initialize driver which has registered itself as running and ready.
    681  *
    682  * The initialization is done in a separate fibril to avoid deadlocks (if the
    683  * driver needed to be served by devman during the driver's initialization).
    684  */
    685 static int init_running_drv(void *drv)
    686 {
    687         driver_t *driver = (driver_t *) drv;
    688        
    689         initialize_running_driver(driver, &device_tree);
    690         log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
    691             driver->name);
    692         return 0;
    693 }
    694 
    695 /** Function for handling connections from a driver to the device manager. */
    696 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    697 {
    698         client_t *client;
    699         driver_t *driver;
    700        
    701         /* Accept the connection. */
    702         async_answer_0(iid, EOK);
    703        
    704         client = async_get_client_data();
    705         if (client == NULL) {
    706                 log_msg(LVL_ERROR, "Failed to allocate client data.");
    707                 return;
    708         }
    709429       
    710430        while (true) {
     
    715435                        break;
    716436               
    717                 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
    718                         fibril_mutex_lock(&client->mutex);
    719                         driver = client->driver;
    720                         fibril_mutex_unlock(&client->mutex);
    721                         if (driver == NULL) {
    722                                 /* First call must be to DEVMAN_DRIVER_REGISTER */
    723                                 async_answer_0(callid, ENOTSUP);
    724                                 continue;
    725                         }
    726                 }
    727                
    728437                switch (IPC_GET_IMETHOD(call)) {
    729                 case DEVMAN_DRIVER_REGISTER:
    730                         fibril_mutex_lock(&client->mutex);
    731                         if (client->driver != NULL) {
    732                                 fibril_mutex_unlock(&client->mutex);
    733                                 async_answer_0(callid, EINVAL);
    734                                 continue;
    735                         }
    736                         client->driver = devman_driver_register(callid, &call);
    737                         fibril_mutex_unlock(&client->mutex);
    738                         break;
    739438                case DEVMAN_ADD_FUNCTION:
    740439                        devman_add_function(callid, &call);
    741440                        break;
    742                 case DEVMAN_ADD_DEVICE_TO_CATEGORY:
    743                         devman_add_function_to_cat(callid, &call);
    744                         break;
    745                 case DEVMAN_DRV_FUN_ONLINE:
    746                         devman_drv_fun_online(callid, &call, driver);
    747                         break;
    748                 case DEVMAN_DRV_FUN_OFFLINE:
    749                         devman_drv_fun_offline(callid, &call, driver);
    750                         break;
    751                 case DEVMAN_REMOVE_FUNCTION:
    752                         devman_remove_function(callid, &call);
     441                case DEVMAN_ADD_DEVICE_TO_CLASS:
     442                        devman_add_function_to_class(callid, &call);
    753443                        break;
    754444                default:
    755                         async_answer_0(callid, EINVAL);
     445                        async_answer_0(callid, EINVAL); 
    756446                        break;
    757447                }
     
    764454{
    765455        char *pathname;
    766         devman_handle_t handle;
    767456       
    768457        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     
    781470        }
    782471
    783         fibril_rwlock_read_lock(&device_tree.rwlock);
    784 
    785         /* Check function state */
    786         if (fun->state == FUN_REMOVED) {
    787                 fibril_rwlock_read_unlock(&device_tree.rwlock);
     472        async_answer_1(iid, EOK, fun->handle);
     473}
     474
     475/** Find handle for the device instance identified by device class name. */
     476static 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) {
    788502                async_answer_0(iid, ENOENT);
    789503                return;
    790504        }
    791         handle = fun->handle;
    792 
    793         fibril_rwlock_read_unlock(&device_tree.rwlock);
    794 
    795         /* Delete reference created above by find_fun_node_by_path() */
    796         fun_del_ref(fun);
    797 
    798         async_answer_1(iid, EOK, handle);
    799 }
    800 
    801 /** Get device name. */
    802 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
     505
     506        async_answer_1(iid, EOK, fun->handle);
     507}
     508
     509/** Find device path by its handle. */
     510static void devman_get_device_path_by_handle(ipc_callid_t iid,
     511    ipc_call_t *icall)
    803512{
    804513        devman_handle_t handle = IPC_GET_ARG1(*icall);
     
    814523        if (!async_data_read_receive(&data_callid, &data_len)) {
    815524                async_answer_0(iid, EINVAL);
    816                 fun_del_ref(fun);
    817525                return;
    818526        }
     
    822530                async_answer_0(data_callid, ENOMEM);
    823531                async_answer_0(iid, ENOMEM);
    824                 fun_del_ref(fun);
    825                 return;
    826         }
    827 
    828         fibril_rwlock_read_lock(&device_tree.rwlock);
    829 
    830         /* Check function state */
    831         if (fun->state == FUN_REMOVED) {
    832                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    833                 free(buffer);
    834 
    835                 async_answer_0(data_callid, ENOENT);
    836                 async_answer_0(iid, ENOENT);
    837                 fun_del_ref(fun);
    838                 return;
    839         }
    840 
    841         size_t sent_length = str_size(fun->name);
    842         if (sent_length > data_len) {
    843                 sent_length = data_len;
    844         }
    845 
    846         async_data_read_finalize(data_callid, fun->name, sent_length);
    847         async_answer_0(iid, EOK);
    848 
    849         fibril_rwlock_read_unlock(&device_tree.rwlock);
    850         fun_del_ref(fun);
    851         free(buffer);
    852 }
    853 
    854 
    855 /** Get device path. */
    856 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall)
    857 {
    858         devman_handle_t handle = IPC_GET_ARG1(*icall);
    859 
    860         fun_node_t *fun = find_fun_node(&device_tree, handle);
    861         if (fun == NULL) {
    862                 async_answer_0(iid, ENOMEM);
    863                 return;
    864         }
    865 
    866         ipc_callid_t data_callid;
    867         size_t data_len;
    868         if (!async_data_read_receive(&data_callid, &data_len)) {
    869                 async_answer_0(iid, EINVAL);
    870                 fun_del_ref(fun);
    871                 return;
    872         }
    873 
    874         void *buffer = malloc(data_len);
    875         if (buffer == NULL) {
    876                 async_answer_0(data_callid, ENOMEM);
    877                 async_answer_0(iid, ENOMEM);
    878                 fun_del_ref(fun);
    879                 return;
    880         }
    881        
    882         fibril_rwlock_read_lock(&device_tree.rwlock);
    883        
    884         /* Check function state */
    885         if (fun->state == FUN_REMOVED) {
    886                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    887                 free(buffer);
    888 
    889                 async_answer_0(data_callid, ENOENT);
    890                 async_answer_0(iid, ENOENT);
    891                 fun_del_ref(fun);
    892                 return;
    893         }
    894        
     532                return;
     533        }
     534
    895535        size_t sent_length = str_size(fun->pathname);
    896536        if (sent_length > data_len) {
     
    901541        async_answer_0(iid, EOK);
    902542
    903         fibril_rwlock_read_unlock(&device_tree.rwlock);
    904         fun_del_ref(fun);
    905543        free(buffer);
    906544}
    907545
    908 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)
    909 {
    910         ipc_callid_t callid;
    911         size_t size;
    912         size_t act_size;
    913         int rc;
    914        
    915         if (!async_data_read_receive(&callid, &size)) {
    916                 async_answer_0(callid, EREFUSED);
    917                 async_answer_0(iid, EREFUSED);
    918                 return;
    919         }
    920        
    921         fibril_rwlock_read_lock(&device_tree.rwlock);
    922        
    923         dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    924             IPC_GET_ARG1(*icall));
    925         if (dev == NULL || dev->state == DEVICE_REMOVED) {
    926                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    927                 async_answer_0(callid, ENOENT);
    928                 async_answer_0(iid, ENOENT);
    929                 return;
    930         }
    931        
    932         devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
    933         if (hdl_buf == NULL) {
    934                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    935                 async_answer_0(callid, ENOMEM);
    936                 async_answer_0(iid, ENOMEM);
    937                 return;
    938         }
    939        
    940         rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
    941         if (rc != EOK) {
    942                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    943                 async_answer_0(callid, rc);
    944                 async_answer_0(iid, rc);
    945                 return;
    946         }
    947        
    948         fibril_rwlock_read_unlock(&device_tree.rwlock);
    949        
    950         sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);
    951         free(hdl_buf);
    952        
    953         async_answer_1(iid, retval, act_size);
    954 }
    955 
    956 
    957 /** Get handle for child device of a function. */
    958 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)
    959 {
    960         fun_node_t *fun;
    961        
    962         fibril_rwlock_read_lock(&device_tree.rwlock);
    963        
    964         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    965         if (fun == NULL || fun->state == FUN_REMOVED) {
    966                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    967                 async_answer_0(iid, ENOENT);
    968                 return;
    969         }
    970        
    971         if (fun->child == NULL) {
    972                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    973                 async_answer_0(iid, ENOENT);
    974                 return;
    975         }
    976        
    977         async_answer_1(iid, EOK, fun->child->handle);
    978        
    979         fibril_rwlock_read_unlock(&device_tree.rwlock);
    980 }
    981 
    982 /** Online function.
    983  *
    984  * Send a request to online a function to the responsible driver.
    985  * The driver may offline other functions if necessary (i.e. if the state
    986  * of this function is linked to state of another function somehow).
    987  */
    988 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    989 {
    990         fun_node_t *fun;
    991         int rc;
    992 
    993         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    994         if (fun == NULL) {
    995                 async_answer_0(iid, ENOENT);
    996                 return;
    997         }
    998        
    999         rc = driver_fun_online(&device_tree, fun);
    1000         fun_del_ref(fun);
    1001        
    1002         async_answer_0(iid, (sysarg_t) rc);
    1003 }
    1004 
    1005 /** Offline function.
    1006  *
    1007  * Send a request to offline a function to the responsible driver. As
    1008  * a result the subtree rooted at that function should be cleanly
    1009  * detatched. The driver may offline other functions if necessary
    1010  * (i.e. if the state of this function is linked to state of another
    1011  * function somehow).
    1012  */
    1013 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    1014 {
    1015         fun_node_t *fun;
    1016         int rc;
    1017 
    1018         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    1019         if (fun == NULL) {
    1020                 async_answer_0(iid, ENOENT);
    1021                 return;
    1022         }
    1023        
    1024         rc = driver_fun_offline(&device_tree, fun);
    1025         fun_del_ref(fun);
    1026        
    1027         async_answer_0(iid, (sysarg_t) rc);
    1028 }
    1029 
    1030 /** Find handle for the function instance identified by its service ID. */
    1031 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
    1032 {
    1033         fun_node_t *fun;
    1034 
    1035         fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
    1036        
    1037         if (fun == NULL) {
    1038                 async_answer_0(iid, ENOENT);
    1039                 return;
    1040         }
    1041 
    1042         fibril_rwlock_read_lock(&device_tree.rwlock);
    1043 
    1044         /* Check function state */
    1045         if (fun->state == FUN_REMOVED) {
    1046                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1047                 async_answer_0(iid, ENOENT);
    1048                 return;
    1049         }
    1050 
    1051         async_answer_1(iid, EOK, fun->handle);
    1052         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1053         fun_del_ref(fun);
    1054 }
    1055546
    1056547/** Function for handling connections from a client to the device manager. */
     
    1071562                        devman_function_get_handle(callid, &call);
    1072563                        break;
    1073                 case DEVMAN_DEV_GET_FUNCTIONS:
    1074                         devman_dev_get_functions(callid, &call);
     564                case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
     565                        devman_function_get_handle_by_class(callid, &call);
    1075566                        break;
    1076                 case DEVMAN_FUN_GET_CHILD:
    1077                         devman_fun_get_child(callid, &call);
    1078                         break;
    1079                 case DEVMAN_FUN_GET_NAME:
    1080                         devman_fun_get_name(callid, &call);
    1081                         break;
    1082                 case DEVMAN_FUN_GET_PATH:
    1083                         devman_fun_get_path(callid, &call);
    1084                         break;
    1085                 case DEVMAN_FUN_ONLINE:
    1086                         devman_fun_online(callid, &call);
    1087                         break;
    1088                 case DEVMAN_FUN_OFFLINE:
    1089                         devman_fun_offline(callid, &call);
    1090                         break;
    1091                 case DEVMAN_FUN_SID_TO_HANDLE:
    1092                         devman_fun_sid_to_handle(callid, &call);
     567                case DEVMAN_DEVICE_GET_DEVICE_PATH:
     568                        devman_get_device_path_by_handle(callid, &call);
    1093569                        break;
    1094570                default:
     
    1109585        if (fun == NULL)
    1110586                dev = find_dev_node(&device_tree, handle);
    1111         else {
    1112                 fibril_rwlock_read_lock(&device_tree.rwlock);
     587        else
    1113588                dev = fun->dev;
    1114                 if (dev != NULL)
    1115                         dev_add_ref(dev);
    1116                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1117         }
    1118589
    1119590        /*
     
    1127598                    "function with handle %" PRIun " was found.", handle);
    1128599                async_answer_0(iid, ENOENT);
    1129                 goto cleanup;
     600                return;
    1130601        }
    1131602
     
    1135606                    handle);
    1136607                async_answer_0(iid, ENOENT);
    1137                 goto cleanup;
     608                return;
    1138609        }
    1139610       
    1140611        driver_t *driver = NULL;
    1141        
    1142         fibril_rwlock_read_lock(&device_tree.rwlock);
    1143612       
    1144613        if (drv_to_parent) {
     
    1155624        }
    1156625       
    1157         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1158        
    1159626        if (driver == NULL) {
    1160627                log_msg(LVL_ERROR, "IPC forwarding refused - " \
    1161628                    "the device %" PRIun " is not in usable state.", handle);
    1162629                async_answer_0(iid, ENOENT);
    1163                 goto cleanup;
     630                return;
    1164631        }
    1165632       
     
    1174641                    "Could not forward to driver `%s'.", driver->name);
    1175642                async_answer_0(iid, EINVAL);
    1176                 goto cleanup;
     643                return;
    1177644        }
    1178645
     
    1190657        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    1191658        async_exchange_end(exch);
    1192 
    1193 cleanup:
    1194         if (dev != NULL)
    1195                 dev_del_ref(dev);
    1196         if (fun != NULL)
    1197                 fun_del_ref(fun);
    1198 }
    1199 
    1200 /** Function for handling connections from a client forwarded by the location
    1201  * service to the device manager. */
    1202 static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
    1203 {
    1204         service_id_t service_id = IPC_GET_ARG2(*icall);
     659}
     660
     661/** Function for handling connections from a client forwarded by the device
     662 * mapper to the device manager. */
     663static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
     664{
     665        devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
    1205666        fun_node_t *fun;
    1206667        dev_node_t *dev;
    1207         devman_handle_t handle;
    1208         driver_t *driver;
    1209 
    1210         fun = find_loc_tree_function(&device_tree, service_id);
    1211        
    1212         fibril_rwlock_read_lock(&device_tree.rwlock);
    1213        
    1214         if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
    1215                 log_msg(LVL_WARN, "devman_connection_loc(): function "
    1216                     "not found.\n");
    1217                 fibril_rwlock_read_unlock(&device_tree.rwlock);
     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) {
    1218674                async_answer_0(iid, ENOENT);
    1219675                return;
     
    1221677       
    1222678        dev = fun->dev;
    1223         driver = dev->drv;
    1224         handle = fun->handle;
    1225        
    1226         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1227        
    1228         async_exch_t *exch = async_exchange_begin(driver->sess);
    1229         async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
     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,
    1230687            IPC_FF_NONE);
    1231688        async_exchange_end(exch);
    1232689       
    1233690        log_msg(LVL_DEBUG,
    1234             "Forwarding loc service request for `%s' function to driver `%s'.",
    1235             fun->pathname, driver->name);
    1236 
    1237         fun_del_ref(fun);
     691            "Forwarding devmapper request for `%s' function to driver `%s'.",
     692            fun->pathname, dev->drv->name);
    1238693}
    1239694
     
    1241696static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    1242697{
    1243         /* Select port. */
     698        /* Select interface. */
    1244699        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    1245700        case DEVMAN_DRIVER:
     
    1253708                devman_forward(iid, icall, false);
    1254709                break;
    1255         case DEVMAN_CONNECT_FROM_LOC:
    1256                 /* Someone connected through loc node. */
    1257                 devman_connection_loc(iid, icall);
     710        case DEVMAN_CONNECT_FROM_DEVMAP:
     711                /* Someone connected through devmap node. */
     712                devman_connection_devmapper(iid, icall);
    1258713                break;
    1259714        case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
     
    1267722}
    1268723
    1269 static void *devman_client_data_create(void)
    1270 {
    1271         client_t *client;
    1272        
    1273         client = calloc(1, sizeof(client_t));
    1274         if (client == NULL)
    1275                 return NULL;
    1276        
    1277         fibril_mutex_initialize(&client->mutex);
    1278         return client;
    1279 }
    1280 
    1281 static void devman_client_data_destroy(void *data)
    1282 {
    1283         free(data);
    1284 }
    1285 
    1286724/** Initialize device manager internal structures. */
    1287725static bool devman_init(void)
     
    1305743        }
    1306744
     745        init_class_list(&class_list);
     746       
    1307747        /*
    1308          * !!! devman_connection ... as the device manager is not a real loc
     748         * !!! devman_connection ... as the device manager is not a real devmap
    1309749         * driver (it uses a completely different ipc protocol than an ordinary
    1310          * loc driver) forwarding a connection from client to the devman by
    1311          * location service would not work.
     750         * devmap driver) forwarding a connection from client to the devman by
     751         * devmapper would not work.
    1312752         */
    1313         loc_server_register(NAME, devman_connection);
     753        devmap_driver_register(NAME, devman_connection);
    1314754       
    1315755        return true;
     
    1320760        printf(NAME ": HelenOS Device Manager\n");
    1321761
    1322         if (log_init(NAME, LVL_WARN) != EOK) {
     762        if (log_init(NAME, LVL_ERROR) != EOK) {
    1323763                printf(NAME ": Error initializing logging subsystem.\n");
    1324764                return -1;
     
    1330770        }
    1331771       
    1332         /* Set handlers for incoming connections. */
    1333         async_set_client_data_constructor(devman_client_data_create);
    1334         async_set_client_data_destructor(devman_client_data_destroy);
     772        /* Set a handler of incomming connections. */
    1335773        async_set_client_connection(devman_connection);
    1336774
Note: See TracChangeset for help on using the changeset viewer.