Ignore:
File:
1 edited

Legend:

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

    r655cc56 r3ad7b1c  
    3939#include <assert.h>
    4040#include <ipc/services.h>
    41 #include <ns.h>
     41#include <ipc/ns.h>
    4242#include <async.h>
    4343#include <stdio.h>
     
    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        }
     
    100108        fibril_mutex_lock(&driver->driver_mutex);
    101109       
    102         if (driver->sess) {
     110        if (driver->phone >= 0) {
    103111                /* We already have a connection to the driver. */
    104112                log_msg(LVL_ERROR, "Driver '%s' already started.\n",
    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        }
     
    120128                break;
    121129        case DRIVER_RUNNING:
    122                 /* Should not happen since we do not have a connected session */
     130                /* Should not happen since we do not have a connected phone */
    123131                assert(false);
    124132        }
     
    127135        log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
    128136            driver->name);
    129         driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
    130         if (!driver->sess) {
     137        ipc_call_t call;
     138        ipc_callid_t callid = async_get_call(&call);
     139        if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
    131140                fibril_mutex_unlock(&driver->driver_mutex);
    132141                async_answer_0(callid, ENOTSUP);
     142                async_answer_0(iid, ENOTSUP);
    133143                return NULL;
    134144        }
    135         /* FIXME: Work around problem with callback sessions */
    136         async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
    137        
    138         log_msg(LVL_NOTE,
     145       
     146        /* Remember driver's phone. */
     147        driver->phone = IPC_GET_ARG5(call);
     148       
     149        fibril_mutex_unlock(&driver->driver_mutex);
     150       
     151        log_msg(LVL_NOTE,
    139152            "The `%s' driver was successfully registered as running.",
    140153            driver->name);
     154       
     155        async_answer_0(callid, EOK);
     156        async_answer_0(iid, EOK);
     157       
     158        return driver;
     159}
     160
     161/** Receive device match ID from the device's parent driver and add it to the
     162 * list of devices match ids.
     163 *
     164 * @param match_ids     The list of the device's match ids.
     165 * @return              Zero on success, negative error code otherwise.
     166 */
     167static int devman_receive_match_id(match_id_list_t *match_ids)
     168{
     169        match_id_t *match_id = create_match_id();
     170        ipc_callid_t callid;
     171        ipc_call_t call;
     172        int rc = 0;
     173       
     174        callid = async_get_call(&call);
     175        if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
     176                log_msg(LVL_ERROR,
     177                    "Invalid protocol when trying to receive match id.");
     178                async_answer_0(callid, EINVAL);
     179                delete_match_id(match_id);
     180                return EINVAL;
     181        }
     182       
     183        if (match_id == NULL) {
     184                log_msg(LVL_ERROR, "Failed to allocate match id.");
     185                async_answer_0(callid, ENOMEM);
     186                return ENOMEM;
     187        }
     188       
     189        async_answer_0(callid, EOK);
     190       
     191        match_id->score = IPC_GET_ARG1(call);
     192       
     193        char *match_id_str;
     194        rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
     195        match_id->id = match_id_str;
     196        if (rc != EOK) {
     197                delete_match_id(match_id);
     198                log_msg(LVL_ERROR, "Failed to receive match id string: %s.",
     199                    str_error(rc));
     200                return rc;
     201        }
     202       
     203        list_append(&match_id->link, &match_ids->ids);
     204       
     205        log_msg(LVL_DEBUG, "Received match id `%s', score %d.",
     206            match_id->id, match_id->score);
     207        return rc;
     208}
     209
     210/** Receive device match IDs from the device's parent driver and add them to the
     211 * list of devices match ids.
     212 *
     213 * @param match_count   The number of device's match ids to be received.
     214 * @param match_ids     The list of the device's match ids.
     215 * @return              Zero on success, negative error code otherwise.
     216 */
     217static int devman_receive_match_ids(sysarg_t match_count,
     218    match_id_list_t *match_ids)
     219{
     220        int ret = EOK;
     221        size_t i;
     222       
     223        for (i = 0; i < match_count; i++) {
     224                if (EOK != (ret = devman_receive_match_id(match_ids)))
     225                        return ret;
     226        }
     227        return ret;
     228}
     229
     230static int assign_driver_fibril(void *arg)
     231{
     232        dev_node_t *dev_node = (dev_node_t *) arg;
     233        assign_driver(dev_node, &drivers_list, &device_tree);
     234        return EOK;
     235}
     236
     237/** Handle function registration.
     238 *
     239 * Child devices are registered by their parent's device driver.
     240 */
     241static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
     242{
     243        fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
     244        devman_handle_t dev_handle = IPC_GET_ARG2(*call);
     245        sysarg_t match_count = IPC_GET_ARG3(*call);
     246        dev_tree_t *tree = &device_tree;
     247       
     248        fibril_rwlock_write_lock(&tree->rwlock);
     249
     250        dev_node_t *dev = NULL;
     251        dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
     252       
     253        if (pdev == NULL) {
     254                fibril_rwlock_write_unlock(&tree->rwlock);
     255                async_answer_0(callid, ENOENT);
     256                return;
     257        }
     258       
     259        if (ftype != fun_inner && ftype != fun_exposed) {
     260                /* Unknown function type */
     261                log_msg(LVL_ERROR,
     262                    "Unknown function type %d provided by driver.",
     263                    (int) ftype);
     264
     265                fibril_rwlock_write_unlock(&tree->rwlock);
     266                async_answer_0(callid, EINVAL);
     267                return;
     268        }
     269       
     270        char *fun_name = NULL;
     271        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
     272        if (rc != EOK) {
     273                fibril_rwlock_write_unlock(&tree->rwlock);
     274                async_answer_0(callid, rc);
     275                return;
     276        }
     277       
     278        /* Check that function with same name is not there already. */
     279        if (find_fun_node_in_device(pdev, fun_name) != NULL) {
     280                fibril_rwlock_write_unlock(&tree->rwlock);
     281                async_answer_0(callid, EEXISTS);
     282                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     283                    fun_name);
     284                free(fun_name);
     285                return;
     286        }
     287
     288        fun_node_t *fun = create_fun_node();
     289        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     290                fibril_rwlock_write_unlock(&tree->rwlock);
     291                delete_fun_node(fun);
     292                async_answer_0(callid, ENOMEM);
     293                return;
     294        }
     295
     296        if (ftype == fun_inner) {
     297                dev = create_dev_node();
     298                if (dev == NULL) {
     299                        fibril_rwlock_write_unlock(&tree->rwlock);
     300                        delete_fun_node(fun);
     301                        async_answer_0(callid, ENOMEM);
     302                        return;
     303                }
     304
     305                insert_dev_node(tree, dev, fun);
     306        }
     307
     308        fibril_rwlock_write_unlock(&tree->rwlock);
     309       
     310        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
     311       
     312        devman_receive_match_ids(match_count, &fun->match_ids);
     313
     314        if (ftype == fun_inner) {
     315                assert(dev != NULL);
     316                /*
     317                 * Try to find a suitable driver and assign it to the device.  We do
     318                 * not want to block the current fibril that is used for processing
     319                 * incoming calls: we will launch a separate fibril to handle the
     320                 * driver assigning. That is because assign_driver can actually include
     321                 * task spawning which could take some time.
     322                 */
     323                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
     324                if (assign_fibril == 0) {
     325                        /*
     326                         * Fallback in case we are out of memory.
     327                         * Probably not needed as we will die soon anyway ;-).
     328                         */
     329                        (void) assign_driver_fibril(fun);
     330                } else {
     331                        fibril_add_ready(assign_fibril);
     332                }
     333        } else {
     334                devmap_register_tree_function(fun, tree);
     335        }
     336       
     337        /* Return device handle to parent's driver. */
     338        async_answer_1(callid, EOK, fun->handle);
     339}
     340
     341static void devmap_register_class_dev(dev_class_info_t *cli)
     342{
     343        /* Create devmap path and name for the device. */
     344        char *devmap_pathname = NULL;
     345
     346        asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE,
     347            cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name);
     348        if (devmap_pathname == NULL)
     349                return;
     350       
     351        /*
     352         * Register the device by the device mapper and remember its devmap
     353         * handle.
     354         */
     355        devmap_device_register_with_iface(devmap_pathname,
     356            &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
     357       
     358        /*
     359         * Add device to the hash map of class devices registered by device
     360         * mapper.
     361         */
     362        class_add_devmap_function(&class_list, cli);
     363       
     364        free(devmap_pathname);
     365}
     366
     367static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
     368{
     369        devman_handle_t handle = IPC_GET_ARG1(*call);
     370       
     371        /* Get class name. */
     372        char *class_name;
     373        int rc = async_data_write_accept((void **) &class_name, true,
     374            0, 0, 0, 0);
     375        if (rc != EOK) {
     376                async_answer_0(callid, rc);
     377                return;
     378        }       
     379       
     380        fun_node_t *fun = find_fun_node(&device_tree, handle);
     381        if (fun == NULL) {
     382                async_answer_0(callid, ENOENT);
     383                return;
     384        }
     385       
     386        dev_class_t *cl = get_dev_class(&class_list, class_name);
     387        dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL);
     388       
     389        /* Register the device's class alias by devmapper. */
     390        devmap_register_class_dev(class_info);
     391       
     392        log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.",
     393            fun->pathname, class_name, class_info->dev_name);
     394
     395        async_answer_0(callid, EOK);
     396}
     397
     398/** Initialize driver which has registered itself as running and ready.
     399 *
     400 * The initialization is done in a separate fibril to avoid deadlocks (if the
     401 * driver needed to be served by devman during the driver's initialization).
     402 */
     403static int init_running_drv(void *drv)
     404{
     405        driver_t *driver = (driver_t *) drv;
     406       
     407        initialize_running_driver(driver, &device_tree);
     408        log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
     409            driver->name);
     410        return 0;
     411}
     412
     413/** Function for handling connections from a driver to the device manager. */
     414static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
     415{
     416        /* Accept the connection. */
     417        async_answer_0(iid, EOK);
     418       
     419        driver_t *driver = devman_driver_register();
     420        if (driver == NULL)
     421                return;
    141422       
    142423        /*
     
    149430                log_msg(LVL_ERROR, "Failed to create initialization fibril " \
    150431                    "for driver `%s'.", driver->name);
    151                 fibril_mutex_unlock(&driver->driver_mutex);
    152                 async_answer_0(callid, ENOMEM);
    153                 return NULL;
    154         }
    155        
     432                return;
     433        }
    156434        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();
     435       
    172436        ipc_callid_t callid;
    173437        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;
     438        bool cont = true;
     439        while (cont) {
     440                callid = async_get_call(&call);
     441               
     442                switch (IPC_GET_IMETHOD(call)) {
     443                case IPC_M_PHONE_HUNGUP:
     444                        cont = false;
     445                        continue;
     446                case DEVMAN_ADD_FUNCTION:
     447                        devman_add_function(callid, &call);
     448                        break;
     449                case DEVMAN_ADD_DEVICE_TO_CLASS:
     450                        devman_add_function_to_class(callid, &call);
     451                        break;
     452                default:
     453                        async_answer_0(callid, EINVAL);
     454                        break;
     455                }
     456        }
     457}
     458
     459/** Find handle for the device instance identified by the device's path in the
     460 * device tree. */
     461static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
     462{
     463        char *pathname;
     464       
     465        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
    198466        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));
     467                async_answer_0(iid, rc);
     468                return;
     469        }
     470       
     471        fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
     472       
     473        free(pathname);
     474
    517475        if (fun == NULL) {
    518476                async_answer_0(iid, ENOENT);
    519477                return;
    520478        }
    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);
     479
     480        async_answer_1(iid, EOK, fun->handle);
     481}
     482
     483/** Find handle for the device instance identified by device class name. */
     484static void devman_function_get_handle_by_class(ipc_callid_t iid,
     485    ipc_call_t *icall)
     486{
     487        char *classname;
     488        char *devname;
     489
     490        int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0);
    532491        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));
     492                async_answer_0(iid, rc);
     493                return;
     494        }
     495        rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0);
     496        if (rc != EOK) {
     497                free(classname);
     498                async_answer_0(iid, rc);
     499                return;
     500        }
     501
     502
     503        fun_node_t *fun = find_fun_node_by_class(&class_list,
     504            classname, devname);
     505
     506        free(classname);
     507        free(devname);
     508
    554509        if (fun == NULL) {
    555510                async_answer_0(iid, ENOENT);
    556511                return;
    557512        }
    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                                 if (gone_rc == EOK)
    637                                         gone_rc = ENOTSUP;
    638                                 async_answer_0(callid, gone_rc);
    639                                 return;
    640                         }
    641                        
    642                         driver_t *driver = dev->drv;
    643                         fibril_rwlock_read_unlock(&device_tree.rwlock);
    644                        
    645                         if (driver)
    646                                 detach_driver(&device_tree, dev);
    647                        
    648                         fibril_rwlock_write_lock(&device_tree.rwlock);
    649                         remove_dev_node(&device_tree, dev);
    650                        
    651                         /* Delete ref created when node was inserted */
    652                         dev_del_ref(dev);
    653                         /* Delete ref created by dev_add_ref(dev) above */
    654                         dev_del_ref(dev);
    655                 }
    656         } else {
    657                 if (fun->service_id != 0) {
    658                         /* Unregister from location service */
    659                         rc = loc_service_unregister(fun->service_id);
    660                         if (rc != EOK) {
    661                                 log_msg(LVL_ERROR, "Failed unregistering tree "
    662                                     "service.");
    663                                 fibril_rwlock_write_unlock(&tree->rwlock);
    664                                 fun_del_ref(fun);
    665                                 async_answer_0(callid, EIO);
    666                                 return;
    667                         }
    668                 }
    669         }
    670        
    671         remove_fun_node(&device_tree, fun);
    672         fibril_rwlock_write_unlock(&tree->rwlock);
    673        
    674         /* Delete ref added when inserting function into tree */
    675         fun_del_ref(fun);
    676         /* Delete ref added above when looking up function */
    677         fun_del_ref(fun);
    678        
    679         log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
    680         async_answer_0(callid, EOK);
    681 }
    682 
    683 /** Initialize driver which has registered itself as running and ready.
    684  *
    685  * The initialization is done in a separate fibril to avoid deadlocks (if the
    686  * driver needed to be served by devman during the driver's initialization).
    687  */
    688 static int init_running_drv(void *drv)
    689 {
    690         driver_t *driver = (driver_t *) drv;
    691        
    692         initialize_running_driver(driver, &device_tree);
    693         log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
    694             driver->name);
    695         return 0;
    696 }
    697 
    698 /** Function for handling connections from a driver to the device manager. */
    699 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    700 {
    701         client_t *client;
    702         driver_t *driver;
    703        
    704         /* Accept the connection. */
     513
     514        async_answer_1(iid, EOK, fun->handle);
     515}
     516
     517
     518/** Function for handling connections from a client to the device manager. */
     519static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall)
     520{
     521        /* Accept connection. */
    705522        async_answer_0(iid, EOK);
    706523       
    707         client = async_get_client_data();
    708         if (client == NULL) {
    709                 log_msg(LVL_ERROR, "Failed to allocate client data.");
    710                 return;
    711         }
    712        
    713         while (true) {
     524        bool cont = true;
     525        while (cont) {
    714526                ipc_call_t call;
    715527                ipc_callid_t callid = async_get_call(&call);
    716528               
    717                 if (!IPC_GET_IMETHOD(call))
    718                         break;
    719                
    720                 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
    721                         fibril_mutex_lock(&client->mutex);
    722                         driver = client->driver;
    723                         fibril_mutex_unlock(&client->mutex);
    724                         if (driver == NULL) {
    725                                 /* First call must be to DEVMAN_DRIVER_REGISTER */
    726                                 async_answer_0(callid, ENOTSUP);
    727                                 continue;
    728                         }
    729                 }
    730                
    731529                switch (IPC_GET_IMETHOD(call)) {
    732                 case DEVMAN_DRIVER_REGISTER:
    733                         fibril_mutex_lock(&client->mutex);
    734                         if (client->driver != NULL) {
    735                                 fibril_mutex_unlock(&client->mutex);
    736                                 async_answer_0(callid, EINVAL);
    737                                 continue;
    738                         }
    739                         client->driver = devman_driver_register(callid, &call);
    740                         fibril_mutex_unlock(&client->mutex);
    741                         break;
    742                 case DEVMAN_ADD_FUNCTION:
    743                         devman_add_function(callid, &call);
    744                         break;
    745                 case DEVMAN_ADD_DEVICE_TO_CATEGORY:
    746                         devman_add_function_to_cat(callid, &call);
    747                         break;
    748                 case DEVMAN_DRV_FUN_ONLINE:
    749                         devman_drv_fun_online(callid, &call, driver);
    750                         break;
    751                 case DEVMAN_DRV_FUN_OFFLINE:
    752                         devman_drv_fun_offline(callid, &call, driver);
    753                         break;
    754                 case DEVMAN_REMOVE_FUNCTION:
    755                         devman_remove_function(callid, &call);
    756                         break;
    757                 default:
    758                         async_answer_0(callid, EINVAL);
    759                         break;
    760                 }
    761         }
    762 }
    763 
    764 /** Find handle for the device instance identified by the device's path in the
    765  * device tree. */
    766 static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
    767 {
    768         char *pathname;
    769         devman_handle_t handle;
    770        
    771         int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
    772         if (rc != EOK) {
    773                 async_answer_0(iid, rc);
    774                 return;
    775         }
    776        
    777         fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
    778        
    779         free(pathname);
    780 
    781         if (fun == NULL) {
    782                 async_answer_0(iid, ENOENT);
    783                 return;
    784         }
    785 
    786         fibril_rwlock_read_lock(&device_tree.rwlock);
    787 
    788         /* Check function state */
    789         if (fun->state == FUN_REMOVED) {
    790                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    791                 async_answer_0(iid, ENOENT);
    792                 return;
    793         }
    794         handle = fun->handle;
    795 
    796         fibril_rwlock_read_unlock(&device_tree.rwlock);
    797 
    798         /* Delete reference created above by find_fun_node_by_path() */
    799         fun_del_ref(fun);
    800 
    801         async_answer_1(iid, EOK, handle);
    802 }
    803 
    804 /** Get device name. */
    805 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
    806 {
    807         devman_handle_t handle = IPC_GET_ARG1(*icall);
    808 
    809         fun_node_t *fun = find_fun_node(&device_tree, handle);
    810         if (fun == NULL) {
    811                 async_answer_0(iid, ENOMEM);
    812                 return;
    813         }
    814 
    815         ipc_callid_t data_callid;
    816         size_t data_len;
    817         if (!async_data_read_receive(&data_callid, &data_len)) {
    818                 async_answer_0(iid, EINVAL);
    819                 fun_del_ref(fun);
    820                 return;
    821         }
    822 
    823         void *buffer = malloc(data_len);
    824         if (buffer == NULL) {
    825                 async_answer_0(data_callid, ENOMEM);
    826                 async_answer_0(iid, ENOMEM);
    827                 fun_del_ref(fun);
    828                 return;
    829         }
    830 
    831         fibril_rwlock_read_lock(&device_tree.rwlock);
    832 
    833         /* Check function state */
    834         if (fun->state == FUN_REMOVED) {
    835                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    836                 free(buffer);
    837 
    838                 async_answer_0(data_callid, ENOENT);
    839                 async_answer_0(iid, ENOENT);
    840                 fun_del_ref(fun);
    841                 return;
    842         }
    843 
    844         size_t sent_length = str_size(fun->name);
    845         if (sent_length > data_len) {
    846                 sent_length = data_len;
    847         }
    848 
    849         async_data_read_finalize(data_callid, fun->name, sent_length);
    850         async_answer_0(iid, EOK);
    851 
    852         fibril_rwlock_read_unlock(&device_tree.rwlock);
    853         fun_del_ref(fun);
    854         free(buffer);
    855 }
    856 
    857 
    858 /** Get device path. */
    859 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall)
    860 {
    861         devman_handle_t handle = IPC_GET_ARG1(*icall);
    862 
    863         fun_node_t *fun = find_fun_node(&device_tree, handle);
    864         if (fun == NULL) {
    865                 async_answer_0(iid, ENOMEM);
    866                 return;
    867         }
    868 
    869         ipc_callid_t data_callid;
    870         size_t data_len;
    871         if (!async_data_read_receive(&data_callid, &data_len)) {
    872                 async_answer_0(iid, EINVAL);
    873                 fun_del_ref(fun);
    874                 return;
    875         }
    876 
    877         void *buffer = malloc(data_len);
    878         if (buffer == NULL) {
    879                 async_answer_0(data_callid, ENOMEM);
    880                 async_answer_0(iid, ENOMEM);
    881                 fun_del_ref(fun);
    882                 return;
    883         }
    884        
    885         fibril_rwlock_read_lock(&device_tree.rwlock);
    886        
    887         /* Check function state */
    888         if (fun->state == FUN_REMOVED) {
    889                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    890                 free(buffer);
    891 
    892                 async_answer_0(data_callid, ENOENT);
    893                 async_answer_0(iid, ENOENT);
    894                 fun_del_ref(fun);
    895                 return;
    896         }
    897        
    898         size_t sent_length = str_size(fun->pathname);
    899         if (sent_length > data_len) {
    900                 sent_length = data_len;
    901         }
    902 
    903         async_data_read_finalize(data_callid, fun->pathname, sent_length);
    904         async_answer_0(iid, EOK);
    905 
    906         fibril_rwlock_read_unlock(&device_tree.rwlock);
    907         fun_del_ref(fun);
    908         free(buffer);
    909 }
    910 
    911 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)
    912 {
    913         ipc_callid_t callid;
    914         size_t size;
    915         size_t act_size;
    916         int rc;
    917        
    918         if (!async_data_read_receive(&callid, &size)) {
    919                 async_answer_0(callid, EREFUSED);
    920                 async_answer_0(iid, EREFUSED);
    921                 return;
    922         }
    923        
    924         fibril_rwlock_read_lock(&device_tree.rwlock);
    925        
    926         dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    927             IPC_GET_ARG1(*icall));
    928         if (dev == NULL || dev->state == DEVICE_REMOVED) {
    929                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    930                 async_answer_0(callid, ENOENT);
    931                 async_answer_0(iid, ENOENT);
    932                 return;
    933         }
    934        
    935         devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
    936         if (hdl_buf == NULL) {
    937                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    938                 async_answer_0(callid, ENOMEM);
    939                 async_answer_0(iid, ENOMEM);
    940                 return;
    941         }
    942        
    943         rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
    944         if (rc != EOK) {
    945                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    946                 async_answer_0(callid, rc);
    947                 async_answer_0(iid, rc);
    948                 return;
    949         }
    950        
    951         fibril_rwlock_read_unlock(&device_tree.rwlock);
    952        
    953         sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);
    954         free(hdl_buf);
    955        
    956         async_answer_1(iid, retval, act_size);
    957 }
    958 
    959 
    960 /** Get handle for child device of a function. */
    961 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)
    962 {
    963         fun_node_t *fun;
    964        
    965         fibril_rwlock_read_lock(&device_tree.rwlock);
    966        
    967         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    968         if (fun == NULL || fun->state == FUN_REMOVED) {
    969                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    970                 async_answer_0(iid, ENOENT);
    971                 return;
    972         }
    973        
    974         if (fun->child == NULL) {
    975                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    976                 async_answer_0(iid, ENOENT);
    977                 return;
    978         }
    979        
    980         async_answer_1(iid, EOK, fun->child->handle);
    981        
    982         fibril_rwlock_read_unlock(&device_tree.rwlock);
    983 }
    984 
    985 /** Online function.
    986  *
    987  * Send a request to online a function to the responsible driver.
    988  * The driver may offline other functions if necessary (i.e. if the state
    989  * of this function is linked to state of another function somehow).
    990  */
    991 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    992 {
    993         fun_node_t *fun;
    994         int rc;
    995 
    996         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    997         if (fun == NULL) {
    998                 async_answer_0(iid, ENOENT);
    999                 return;
    1000         }
    1001        
    1002         rc = driver_fun_online(&device_tree, fun);
    1003         fun_del_ref(fun);
    1004        
    1005         async_answer_0(iid, (sysarg_t) rc);
    1006 }
    1007 
    1008 /** Offline function.
    1009  *
    1010  * Send a request to offline a function to the responsible driver. As
    1011  * a result the subtree rooted at that function should be cleanly
    1012  * detatched. The driver may offline other functions if necessary
    1013  * (i.e. if the state of this function is linked to state of another
    1014  * function somehow).
    1015  */
    1016 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    1017 {
    1018         fun_node_t *fun;
    1019         int rc;
    1020 
    1021         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    1022         if (fun == NULL) {
    1023                 async_answer_0(iid, ENOENT);
    1024                 return;
    1025         }
    1026        
    1027         rc = driver_fun_offline(&device_tree, fun);
    1028         fun_del_ref(fun);
    1029        
    1030         async_answer_0(iid, (sysarg_t) rc);
    1031 }
    1032 
    1033 /** Find handle for the function instance identified by its service ID. */
    1034 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
    1035 {
    1036         fun_node_t *fun;
    1037 
    1038         fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
    1039        
    1040         if (fun == NULL) {
    1041                 async_answer_0(iid, ENOENT);
    1042                 return;
    1043         }
    1044 
    1045         fibril_rwlock_read_lock(&device_tree.rwlock);
    1046 
    1047         /* Check function state */
    1048         if (fun->state == FUN_REMOVED) {
    1049                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1050                 async_answer_0(iid, ENOENT);
    1051                 return;
    1052         }
    1053 
    1054         async_answer_1(iid, EOK, fun->handle);
    1055         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1056         fun_del_ref(fun);
    1057 }
    1058 
    1059 /** Function for handling connections from a client to the device manager. */
    1060 static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall)
    1061 {
    1062         /* Accept connection. */
    1063         async_answer_0(iid, EOK);
    1064        
    1065         while (true) {
    1066                 ipc_call_t call;
    1067                 ipc_callid_t callid = async_get_call(&call);
    1068                
    1069                 if (!IPC_GET_IMETHOD(call))
    1070                         break;
    1071                
    1072                 switch (IPC_GET_IMETHOD(call)) {
     530                case IPC_M_PHONE_HUNGUP:
     531                        cont = false;
     532                        continue;
    1073533                case DEVMAN_DEVICE_GET_HANDLE:
    1074534                        devman_function_get_handle(callid, &call);
    1075535                        break;
    1076                 case DEVMAN_DEV_GET_FUNCTIONS:
    1077                         devman_dev_get_functions(callid, &call);
    1078                         break;
    1079                 case DEVMAN_FUN_GET_CHILD:
    1080                         devman_fun_get_child(callid, &call);
    1081                         break;
    1082                 case DEVMAN_FUN_GET_NAME:
    1083                         devman_fun_get_name(callid, &call);
    1084                         break;
    1085                 case DEVMAN_FUN_GET_PATH:
    1086                         devman_fun_get_path(callid, &call);
    1087                         break;
    1088                 case DEVMAN_FUN_ONLINE:
    1089                         devman_fun_online(callid, &call);
    1090                         break;
    1091                 case DEVMAN_FUN_OFFLINE:
    1092                         devman_fun_offline(callid, &call);
    1093                         break;
    1094                 case DEVMAN_FUN_SID_TO_HANDLE:
    1095                         devman_fun_sid_to_handle(callid, &call);
     536                case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
     537                        devman_function_get_handle_by_class(callid, &call);
    1096538                        break;
    1097539                default:
     
    1112554        if (fun == NULL)
    1113555                dev = find_dev_node(&device_tree, handle);
    1114         else {
    1115                 fibril_rwlock_read_lock(&device_tree.rwlock);
     556        else
    1116557                dev = fun->dev;
    1117                 if (dev != NULL)
    1118                         dev_add_ref(dev);
    1119                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1120         }
    1121558
    1122559        /*
     
    1130567                    "function with handle %" PRIun " was found.", handle);
    1131568                async_answer_0(iid, ENOENT);
    1132                 goto cleanup;
     569                return;
    1133570        }
    1134571
     
    1138575                    handle);
    1139576                async_answer_0(iid, ENOENT);
    1140                 goto cleanup;
     577                return;
    1141578        }
    1142579       
    1143580        driver_t *driver = NULL;
    1144        
    1145         fibril_rwlock_read_lock(&device_tree.rwlock);
    1146581       
    1147582        if (drv_to_parent) {
     
    1158593        }
    1159594       
    1160         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1161        
    1162595        if (driver == NULL) {
    1163596                log_msg(LVL_ERROR, "IPC forwarding refused - " \
    1164597                    "the device %" PRIun " is not in usable state.", handle);
    1165598                async_answer_0(iid, ENOENT);
    1166                 goto cleanup;
     599                return;
    1167600        }
    1168601       
     
    1173606                method = DRIVER_CLIENT;
    1174607       
    1175         if (!driver->sess) {
    1176                 log_msg(LVL_ERROR,
    1177                     "Could not forward to driver `%s'.", driver->name);
     608        if (driver->phone < 0) {
     609                log_msg(LVL_ERROR,
     610                    "Could not forward to driver `%s' (phone is %d).",
     611                    driver->name, (int) driver->phone);
    1178612                async_answer_0(iid, EINVAL);
    1179                 goto cleanup;
     613                return;
    1180614        }
    1181615
     
    1189623                    dev->pfun->pathname, driver->name);
    1190624        }
    1191        
    1192         async_exch_t *exch = async_exchange_begin(driver->sess);
    1193         async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    1194         async_exchange_end(exch);
    1195 
    1196 cleanup:
    1197         if (dev != NULL)
    1198                 dev_del_ref(dev);
    1199         if (fun != NULL)
    1200                 fun_del_ref(fun);
    1201 }
    1202 
    1203 /** Function for handling connections from a client forwarded by the location
    1204  * service to the device manager. */
    1205 static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
    1206 {
    1207         service_id_t service_id = IPC_GET_ARG2(*icall);
     625
     626        async_forward_fast(iid, driver->phone, method, fwd_h, 0, IPC_FF_NONE);
     627}
     628
     629/** Function for handling connections from a client forwarded by the device
     630 * mapper to the device manager. */
     631static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
     632{
     633        devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
    1208634        fun_node_t *fun;
    1209635        dev_node_t *dev;
    1210         devman_handle_t handle;
    1211         driver_t *driver;
    1212 
    1213         fun = find_loc_tree_function(&device_tree, service_id);
    1214        
    1215         fibril_rwlock_read_lock(&device_tree.rwlock);
    1216        
    1217         if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
    1218                 log_msg(LVL_WARN, "devman_connection_loc(): function "
    1219                     "not found.\n");
    1220                 fibril_rwlock_read_unlock(&device_tree.rwlock);
     636
     637        fun = find_devmap_tree_function(&device_tree, devmap_handle);
     638        if (fun == NULL)
     639                fun = find_devmap_class_function(&class_list, devmap_handle);
     640       
     641        if (fun == NULL || fun->dev->drv == NULL) {
    1221642                async_answer_0(iid, ENOENT);
    1222643                return;
     
    1224645       
    1225646        dev = fun->dev;
    1226         driver = dev->drv;
    1227         handle = fun->handle;
    1228        
    1229         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1230        
    1231         async_exch_t *exch = async_exchange_begin(driver->sess);
    1232         async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
     647       
     648        if (dev->state != DEVICE_USABLE || dev->drv->phone < 0) {
     649                async_answer_0(iid, EINVAL);
     650                return;
     651        }
     652       
     653        async_forward_fast(iid, dev->drv->phone, DRIVER_CLIENT, fun->handle, 0,
    1233654            IPC_FF_NONE);
    1234         async_exchange_end(exch);
    1235        
    1236         log_msg(LVL_DEBUG,
    1237             "Forwarding loc service request for `%s' function to driver `%s'.",
    1238             fun->pathname, driver->name);
    1239 
    1240         fun_del_ref(fun);
     655        log_msg(LVL_DEBUG,
     656            "Forwarding devmapper request for `%s' function to driver `%s'.",
     657            fun->pathname, dev->drv->name);
    1241658}
    1242659
    1243660/** Function for handling connections to device manager. */
    1244 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    1245 {
    1246         /* Select port. */
     661static void devman_connection(ipc_callid_t iid, ipc_call_t *icall)
     662{
     663        /* Select interface. */
    1247664        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    1248665        case DEVMAN_DRIVER:
     
    1256673                devman_forward(iid, icall, false);
    1257674                break;
    1258         case DEVMAN_CONNECT_FROM_LOC:
    1259                 /* Someone connected through loc node. */
    1260                 devman_connection_loc(iid, icall);
     675        case DEVMAN_CONNECT_FROM_DEVMAP:
     676                /* Someone connected through devmap node. */
     677                devman_connection_devmapper(iid, icall);
    1261678                break;
    1262679        case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
     
    1270687}
    1271688
    1272 static void *devman_client_data_create(void)
    1273 {
    1274         client_t *client;
    1275        
    1276         client = calloc(1, sizeof(client_t));
    1277         if (client == NULL)
    1278                 return NULL;
    1279        
    1280         fibril_mutex_initialize(&client->mutex);
    1281         return client;
    1282 }
    1283 
    1284 static void devman_client_data_destroy(void *data)
    1285 {
    1286         free(data);
    1287 }
    1288 
    1289689/** Initialize device manager internal structures. */
    1290690static bool devman_init(void)
     
    1308708        }
    1309709
     710        init_class_list(&class_list);
     711       
    1310712        /*
    1311          * !!! devman_connection ... as the device manager is not a real loc
     713         * !!! devman_connection ... as the device manager is not a real devmap
    1312714         * driver (it uses a completely different ipc protocol than an ordinary
    1313          * loc driver) forwarding a connection from client to the devman by
    1314          * location service would not work.
     715         * devmap driver) forwarding a connection from client to the devman by
     716         * devmapper would not work.
    1315717         */
    1316         loc_server_register(NAME, devman_connection);
     718        devmap_driver_register(NAME, devman_connection);
    1317719       
    1318720        return true;
     
    1323725        printf(NAME ": HelenOS Device Manager\n");
    1324726
    1325         if (log_init(NAME, LVL_WARN) != EOK) {
     727        if (log_init(NAME, LVL_ERROR) != EOK) {
    1326728                printf(NAME ": Error initializing logging subsystem.\n");
    1327729                return -1;
     
    1333735        }
    1334736       
    1335         /* Set handlers for incoming connections. */
    1336         async_set_client_data_constructor(devman_client_data_create);
    1337         async_set_client_data_destructor(devman_client_data_destroy);
     737        /* Set a handler of incomming connections. */
    1338738        async_set_client_connection(devman_connection);
    1339739
     
    1345745
    1346746        printf(NAME ": Accepting connections.\n");
    1347         task_retval(0);
    1348747        async_manager();
    1349748
Note: See TracChangeset for help on using the changeset viewer.