Ignore:
File:
1 edited

Legend:

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

    r80a96d2 r7beb220  
    6565static dev_tree_t device_tree;
    6666
    67 static int init_running_drv(void *drv);
    68 
    6967/** Register running driver. */
    70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
    71 {
     68static driver_t *devman_driver_register(void)
     69{
     70        ipc_call_t icall;
     71        ipc_callid_t iid;
    7272        driver_t *driver = NULL;
     73
     74        log_msg(LVL_DEBUG, "devman_driver_register");
     75       
     76        iid = async_get_call(&icall);
     77        if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {
     78                async_answer_0(iid, EREFUSED);
     79                return NULL;
     80        }
     81       
    7382        char *drv_name = NULL;
    74 
    75         log_msg(LVL_DEBUG, "devman_driver_register");
    7683       
    7784        /* Get driver name. */
    7885        int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    7986        if (rc != EOK) {
    80                 async_answer_0(callid, rc);
     87                async_answer_0(iid, rc);
    8188                return NULL;
    8289        }
     
    9198                free(drv_name);
    9299                drv_name = NULL;
    93                 async_answer_0(callid, ENOENT);
     100                async_answer_0(iid, ENOENT);
    94101                return NULL;
    95102        }
     
    105112                    driver->name);
    106113                fibril_mutex_unlock(&driver->driver_mutex);
    107                 async_answer_0(callid, EEXISTS);
     114                async_answer_0(iid, EEXISTS);
    108115                return NULL;
    109116        }
     
    127134        log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
    128135            driver->name);
    129         driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
     136        driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
    130137        if (!driver->sess) {
    131138                fibril_mutex_unlock(&driver->driver_mutex);
    132                 async_answer_0(callid, ENOTSUP);
     139                async_answer_0(iid, ENOTSUP);
    133140                return NULL;
    134141        }
    135         /* FIXME: Work around problem with callback sessions */
    136         async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
     142       
     143        fibril_mutex_unlock(&driver->driver_mutex);
    137144       
    138145        log_msg(LVL_NOTE,
    139146            "The `%s' driver was successfully registered as running.",
    140147            driver->name);
     148       
     149        async_answer_0(iid, EOK);
     150       
     151        return driver;
     152}
     153
     154/** Receive device match ID from the device's parent driver and add it to the
     155 * list of devices match ids.
     156 *
     157 * @param match_ids     The list of the device's match ids.
     158 * @return              Zero on success, negative error code otherwise.
     159 */
     160static int devman_receive_match_id(match_id_list_t *match_ids)
     161{
     162        match_id_t *match_id = create_match_id();
     163        ipc_callid_t callid;
     164        ipc_call_t call;
     165        int rc = 0;
     166       
     167        callid = async_get_call(&call);
     168        if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
     169                log_msg(LVL_ERROR,
     170                    "Invalid protocol when trying to receive match id.");
     171                async_answer_0(callid, EINVAL);
     172                delete_match_id(match_id);
     173                return EINVAL;
     174        }
     175       
     176        if (match_id == NULL) {
     177                log_msg(LVL_ERROR, "Failed to allocate match id.");
     178                async_answer_0(callid, ENOMEM);
     179                return ENOMEM;
     180        }
     181       
     182        async_answer_0(callid, EOK);
     183       
     184        match_id->score = IPC_GET_ARG1(call);
     185       
     186        char *match_id_str;
     187        rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
     188        match_id->id = match_id_str;
     189        if (rc != EOK) {
     190                delete_match_id(match_id);
     191                log_msg(LVL_ERROR, "Failed to receive match id string: %s.",
     192                    str_error(rc));
     193                return rc;
     194        }
     195       
     196        list_append(&match_id->link, &match_ids->ids);
     197       
     198        log_msg(LVL_DEBUG, "Received match id `%s', score %d.",
     199            match_id->id, match_id->score);
     200        return rc;
     201}
     202
     203/** Receive device match IDs from the device's parent driver and add them to the
     204 * list of devices match ids.
     205 *
     206 * @param match_count   The number of device's match ids to be received.
     207 * @param match_ids     The list of the device's match ids.
     208 * @return              Zero on success, negative error code otherwise.
     209 */
     210static int devman_receive_match_ids(sysarg_t match_count,
     211    match_id_list_t *match_ids)
     212{
     213        int ret = EOK;
     214        size_t i;
     215       
     216        for (i = 0; i < match_count; i++) {
     217                if (EOK != (ret = devman_receive_match_id(match_ids)))
     218                        return ret;
     219        }
     220        return ret;
     221}
     222
     223static int assign_driver_fibril(void *arg)
     224{
     225        dev_node_t *dev_node = (dev_node_t *) arg;
     226        assign_driver(dev_node, &drivers_list, &device_tree);
     227        return EOK;
     228}
     229
     230/** Handle function registration.
     231 *
     232 * Child devices are registered by their parent's device driver.
     233 */
     234static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
     235{
     236        fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
     237        devman_handle_t dev_handle = IPC_GET_ARG2(*call);
     238        sysarg_t match_count = IPC_GET_ARG3(*call);
     239        dev_tree_t *tree = &device_tree;
     240       
     241        fibril_rwlock_write_lock(&tree->rwlock);
     242
     243        dev_node_t *dev = NULL;
     244        dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
     245       
     246        if (pdev == NULL) {
     247                fibril_rwlock_write_unlock(&tree->rwlock);
     248                async_answer_0(callid, ENOENT);
     249                return;
     250        }
     251       
     252        if (ftype != fun_inner && ftype != fun_exposed) {
     253                /* Unknown function type */
     254                log_msg(LVL_ERROR,
     255                    "Unknown function type %d provided by driver.",
     256                    (int) ftype);
     257
     258                fibril_rwlock_write_unlock(&tree->rwlock);
     259                async_answer_0(callid, EINVAL);
     260                return;
     261        }
     262       
     263        char *fun_name = NULL;
     264        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
     265        if (rc != EOK) {
     266                fibril_rwlock_write_unlock(&tree->rwlock);
     267                async_answer_0(callid, rc);
     268                return;
     269        }
     270       
     271        /* Check that function with same name is not there already. */
     272        if (find_fun_node_in_device(pdev, fun_name) != NULL) {
     273                fibril_rwlock_write_unlock(&tree->rwlock);
     274                async_answer_0(callid, EEXISTS);
     275                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     276                    fun_name);
     277                free(fun_name);
     278                return;
     279        }
     280       
     281        fun_node_t *fun = create_fun_node();
     282        fun->ftype = ftype;
     283       
     284        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     285                fibril_rwlock_write_unlock(&tree->rwlock);
     286                delete_fun_node(fun);
     287                async_answer_0(callid, ENOMEM);
     288                return;
     289        }
     290
     291        if (ftype == fun_inner) {
     292                dev = create_dev_node();
     293                if (dev == NULL) {
     294                        fibril_rwlock_write_unlock(&tree->rwlock);
     295                        delete_fun_node(fun);
     296                        async_answer_0(callid, ENOMEM);
     297                        return;
     298                }
     299
     300                insert_dev_node(tree, dev, fun);
     301        }
     302
     303        fibril_rwlock_write_unlock(&tree->rwlock);
     304       
     305        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
     306       
     307        devman_receive_match_ids(match_count, &fun->match_ids);
     308
     309        if (ftype == fun_inner) {
     310                assert(dev != NULL);
     311                /*
     312                 * Try to find a suitable driver and assign it to the device.  We do
     313                 * not want to block the current fibril that is used for processing
     314                 * incoming calls: we will launch a separate fibril to handle the
     315                 * driver assigning. That is because assign_driver can actually include
     316                 * task spawning which could take some time.
     317                 */
     318                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
     319                if (assign_fibril == 0) {
     320                        /*
     321                         * Fallback in case we are out of memory.
     322                         * Probably not needed as we will die soon anyway ;-).
     323                         */
     324                        (void) assign_driver_fibril(fun);
     325                } else {
     326                        fibril_add_ready(assign_fibril);
     327                }
     328        } else {
     329                loc_register_tree_function(fun, tree);
     330        }
     331       
     332        /* Return device handle to parent's driver. */
     333        async_answer_1(callid, EOK, fun->handle);
     334}
     335
     336static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
     337{
     338        devman_handle_t handle = IPC_GET_ARG1(*call);
     339        category_id_t cat_id;
     340        int rc;
     341       
     342        /* Get category name. */
     343        char *cat_name;
     344        rc = async_data_write_accept((void **) &cat_name, true,
     345            0, 0, 0, 0);
     346        if (rc != EOK) {
     347                async_answer_0(callid, rc);
     348                return;
     349        }       
     350       
     351        fun_node_t *fun = find_fun_node(&device_tree, handle);
     352        if (fun == NULL) {
     353                async_answer_0(callid, ENOENT);
     354                return;
     355        }
     356       
     357        rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
     358        if (rc == EOK) {
     359                loc_service_add_to_cat(fun->service_id, cat_id);
     360        } else {
     361                log_msg(LVL_ERROR, "Failed adding function `%s' to category "
     362                    "`%s'.", fun->pathname, cat_name);
     363        }
     364       
     365        log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
     366            fun->pathname, cat_name);
     367
     368        async_answer_0(callid, EOK);
     369}
     370
     371/** Remove function. */
     372static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
     373{
     374        devman_handle_t fun_handle = IPC_GET_ARG1(*call);
     375        dev_tree_t *tree = &device_tree;
     376        int rc;
     377       
     378        fibril_rwlock_write_lock(&tree->rwlock);
     379       
     380        fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
     381        if (fun == NULL) {
     382                fibril_rwlock_write_unlock(&tree->rwlock);
     383                async_answer_0(callid, ENOENT);
     384                return;
     385        }
     386       
     387        log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
     388       
     389        if (fun->ftype == fun_inner) {
     390                /* Handle possible descendants */
     391                /* TODO */
     392                log_msg(LVL_WARN, "devman_remove_function(): not handling "
     393                    "descendants\n");
     394        } else {
     395                /* Unregister from location service */
     396                rc = loc_service_unregister(fun->service_id);
     397                if (rc != EOK) {
     398                        log_msg(LVL_ERROR, "Failed unregistering tree service.");
     399                        fibril_rwlock_write_unlock(&tree->rwlock);
     400                        async_answer_0(callid, EIO);
     401                        return;
     402                }
     403        }
     404       
     405        remove_fun_node(&device_tree, fun);
     406        fibril_rwlock_write_unlock(&tree->rwlock);
     407        delete_fun_node(fun);
     408       
     409        log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
     410        async_answer_0(callid, EOK);
     411}
     412
     413/** Initialize driver which has registered itself as running and ready.
     414 *
     415 * The initialization is done in a separate fibril to avoid deadlocks (if the
     416 * driver needed to be served by devman during the driver's initialization).
     417 */
     418static int init_running_drv(void *drv)
     419{
     420        driver_t *driver = (driver_t *) drv;
     421       
     422        initialize_running_driver(driver, &device_tree);
     423        log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
     424            driver->name);
     425        return 0;
     426}
     427
     428/** Function for handling connections from a driver to the device manager. */
     429static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
     430{
     431        /* Accept the connection. */
     432        async_answer_0(iid, EOK);
     433       
     434        driver_t *driver = devman_driver_register();
     435        if (driver == NULL)
     436                return;
    141437       
    142438        /*
     
    149445                log_msg(LVL_ERROR, "Failed to create initialization fibril " \
    150446                    "for driver `%s'.", driver->name);
    151                 fibril_mutex_unlock(&driver->driver_mutex);
    152                 async_answer_0(callid, ENOMEM);
    153                 return NULL;
    154         }
    155        
     447                return;
     448        }
    156449        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         } else {
    493                 log_msg(LVL_ERROR, "Failed adding function `%s' to category "
    494                     "`%s'.", fun->pathname, cat_name);
    495         }
    496        
    497         log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
    498             fun->pathname, cat_name);
    499 
    500         fibril_rwlock_read_unlock(&device_tree.rwlock);
    501         fun_del_ref(fun);
    502 
    503         async_answer_0(callid, EOK);
    504 }
    505 
    506 /** Online function by driver request.
    507  *
    508  */
    509 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
    510     driver_t *drv)
    511 {
    512         fun_node_t *fun;
    513         int rc;
    514        
    515         log_msg(LVL_DEBUG, "devman_drv_fun_online()");
    516        
    517         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    518         if (fun == NULL) {
    519                 async_answer_0(iid, ENOENT);
    520                 return;
    521         }
    522        
    523         fibril_rwlock_read_lock(&device_tree.rwlock);
    524         if (fun->dev == NULL || fun->dev->drv != drv) {
    525                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    526                 fun_del_ref(fun);
    527                 async_answer_0(iid, ENOENT);
    528                 return;
    529         }
    530         fibril_rwlock_read_unlock(&device_tree.rwlock);
    531        
    532         rc = online_function(fun);
    533         if (rc != EOK) {
    534                 fun_del_ref(fun);
    535                 async_answer_0(iid, (sysarg_t) rc);
    536                 return;
    537         }
    538        
    539         fun_del_ref(fun);
    540        
    541         async_answer_0(iid, (sysarg_t) EOK);
    542 }
    543 
    544 
    545 /** Offline function by driver request.
    546  *
    547  */
    548 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
    549     driver_t *drv)
    550 {
    551         fun_node_t *fun;
    552         int rc;
    553 
    554         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    555         if (fun == NULL) {
    556                 async_answer_0(iid, ENOENT);
    557                 return;
    558         }
    559        
    560         fibril_rwlock_write_lock(&device_tree.rwlock);
    561         if (fun->dev == NULL || fun->dev->drv != drv) {
    562                 fun_del_ref(fun);
    563                 async_answer_0(iid, ENOENT);
    564                 return;
    565         }
    566         fibril_rwlock_write_unlock(&device_tree.rwlock);
    567        
    568         rc = offline_function(fun);
    569         if (rc != EOK) {
    570                 fun_del_ref(fun);
    571                 async_answer_0(iid, (sysarg_t) rc);
    572                 return;
    573         }
    574        
    575         fun_del_ref(fun);
    576         async_answer_0(iid, (sysarg_t) EOK);
    577 }
    578 
    579 /** Remove function. */
    580 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
    581 {
    582         devman_handle_t fun_handle = IPC_GET_ARG1(*call);
    583         dev_tree_t *tree = &device_tree;
    584         int rc;
    585        
    586         fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
    587         if (fun == NULL) {
    588                 async_answer_0(callid, ENOENT);
    589                 return;
    590         }
    591        
    592         fibril_rwlock_write_lock(&tree->rwlock);
    593        
    594         log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    595        
    596         /* Check function state */
    597         if (fun->state == FUN_REMOVED) {
    598                 fibril_rwlock_write_unlock(&tree->rwlock);
    599                 async_answer_0(callid, ENOENT);
    600                 return;
    601         }
    602        
    603         if (fun->ftype == fun_inner) {
    604                 /* This is a surprise removal. Handle possible descendants */
    605                 if (fun->child != NULL) {
    606                         dev_node_t *dev = fun->child;
    607                         device_state_t dev_state;
    608                         int gone_rc;
    609                        
    610                         dev_add_ref(dev);
    611                         dev_state = dev->state;
    612                        
    613                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    614                        
    615                         /* If device is owned by driver, inform driver it is gone. */
    616                         if (dev_state == DEVICE_USABLE)
    617                                 gone_rc = driver_dev_gone(&device_tree, dev);
    618                         else
    619                                 gone_rc = EOK;
    620                        
    621                         fibril_rwlock_read_lock(&device_tree.rwlock);
    622                        
    623                         /* Verify that driver succeeded and removed all functions */
    624                         if (gone_rc != EOK || !list_empty(&dev->functions)) {
    625                                 log_msg(LVL_ERROR, "Driver did not remove "
    626                                     "functions for device that is gone. "
    627                                     "Device node is now defunct.");
    628                                
    629                                 /*
    630                                  * Not much we can do but mark the device
    631                                  * node as having invalid state. This
    632                                  * is a driver bug.
    633                                  */
    634                                 dev->state = DEVICE_INVALID;
    635                                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    636                                 dev_del_ref(dev);
    637                                 return;
    638                         }
    639                        
    640                         driver_t *driver = dev->drv;
    641                         fibril_rwlock_read_unlock(&device_tree.rwlock);
    642                        
    643                         if (driver)
    644                                 detach_driver(&device_tree, dev);
    645                        
    646                         fibril_rwlock_write_lock(&device_tree.rwlock);
    647                         remove_dev_node(&device_tree, dev);
    648                        
    649                         /* Delete ref created when node was inserted */
    650                         dev_del_ref(dev);
    651                         /* Delete ref created by dev_add_ref(dev) above */
    652                         dev_del_ref(dev);
    653                 }
    654         } else {
    655                 if (fun->service_id != 0) {
    656                         /* Unregister from location service */
    657                         rc = loc_service_unregister(fun->service_id);
    658                         if (rc != EOK) {
    659                                 log_msg(LVL_ERROR, "Failed unregistering tree "
    660                                     "service.");
    661                                 fibril_rwlock_write_unlock(&tree->rwlock);
    662                                 fun_del_ref(fun);
    663                                 async_answer_0(callid, EIO);
    664                                 return;
    665                         }
    666                 }
    667         }
    668        
    669         remove_fun_node(&device_tree, fun);
    670         fibril_rwlock_write_unlock(&tree->rwlock);
    671        
    672         /* Delete ref added when inserting function into tree */
    673         fun_del_ref(fun);
    674         /* Delete ref added above when looking up function */
    675         fun_del_ref(fun);
    676        
    677         log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
    678         async_answer_0(callid, EOK);
    679 }
    680 
    681 /** Initialize driver which has registered itself as running and ready.
    682  *
    683  * The initialization is done in a separate fibril to avoid deadlocks (if the
    684  * driver needed to be served by devman during the driver's initialization).
    685  */
    686 static int init_running_drv(void *drv)
    687 {
    688         driver_t *driver = (driver_t *) drv;
    689        
    690         initialize_running_driver(driver, &device_tree);
    691         log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
    692             driver->name);
    693         return 0;
    694 }
    695 
    696 /** Function for handling connections from a driver to the device manager. */
    697 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    698 {
    699         client_t *client;
    700         driver_t *driver;
    701        
    702         /* Accept the connection. */
    703         async_answer_0(iid, EOK);
    704        
    705         client = async_get_client_data();
    706         if (client == NULL) {
    707                 log_msg(LVL_ERROR, "Failed to allocate client data.");
    708                 return;
    709         }
    710450       
    711451        while (true) {
     
    716456                        break;
    717457               
    718                 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
    719                         fibril_mutex_lock(&client->mutex);
    720                         driver = client->driver;
    721                         fibril_mutex_unlock(&client->mutex);
    722                         if (driver == NULL) {
    723                                 /* First call must be to DEVMAN_DRIVER_REGISTER */
    724                                 async_answer_0(callid, ENOTSUP);
    725                                 continue;
    726                         }
    727                 }
    728                
    729458                switch (IPC_GET_IMETHOD(call)) {
    730                 case DEVMAN_DRIVER_REGISTER:
    731                         fibril_mutex_lock(&client->mutex);
    732                         if (client->driver != NULL) {
    733                                 fibril_mutex_unlock(&client->mutex);
    734                                 async_answer_0(callid, EINVAL);
    735                                 continue;
    736                         }
    737                         client->driver = devman_driver_register(callid, &call);
    738                         fibril_mutex_unlock(&client->mutex);
    739                         break;
    740459                case DEVMAN_ADD_FUNCTION:
    741460                        devman_add_function(callid, &call);
     
    744463                        devman_add_function_to_cat(callid, &call);
    745464                        break;
    746                 case DEVMAN_DRV_FUN_ONLINE:
    747                         devman_drv_fun_online(callid, &call, driver);
    748                         break;
    749                 case DEVMAN_DRV_FUN_OFFLINE:
    750                         devman_drv_fun_offline(callid, &call, driver);
    751                         break;
    752465                case DEVMAN_REMOVE_FUNCTION:
    753466                        devman_remove_function(callid, &call);
    754467                        break;
    755468                default:
    756                         async_answer_0(callid, EINVAL);
     469                        async_answer_0(callid, EINVAL); 
    757470                        break;
    758471                }
     
    765478{
    766479        char *pathname;
    767         devman_handle_t handle;
    768480       
    769481        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     
    782494        }
    783495
    784         fibril_rwlock_read_lock(&device_tree.rwlock);
    785 
    786         /* Check function state */
    787         if (fun->state == FUN_REMOVED) {
    788                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    789                 async_answer_0(iid, ENOENT);
    790                 return;
    791         }
    792         handle = fun->handle;
    793 
    794         fibril_rwlock_read_unlock(&device_tree.rwlock);
    795 
    796         /* Delete reference created above by find_fun_node_by_path() */
    797         fun_del_ref(fun);
    798 
    799         async_answer_1(iid, EOK, handle);
     496        async_answer_1(iid, EOK, fun->handle);
    800497}
    801498
     
    815512        if (!async_data_read_receive(&data_callid, &data_len)) {
    816513                async_answer_0(iid, EINVAL);
    817                 fun_del_ref(fun);
    818514                return;
    819515        }
     
    823519                async_answer_0(data_callid, ENOMEM);
    824520                async_answer_0(iid, ENOMEM);
    825                 fun_del_ref(fun);
    826                 return;
    827         }
    828 
    829         fibril_rwlock_read_lock(&device_tree.rwlock);
    830 
    831         /* Check function state */
    832         if (fun->state == FUN_REMOVED) {
    833                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    834                 free(buffer);
    835 
    836                 async_answer_0(data_callid, ENOENT);
    837                 async_answer_0(iid, ENOENT);
    838                 fun_del_ref(fun);
    839521                return;
    840522        }
     
    848530        async_answer_0(iid, EOK);
    849531
    850         fibril_rwlock_read_unlock(&device_tree.rwlock);
    851         fun_del_ref(fun);
    852532        free(buffer);
    853533}
     
    869549        if (!async_data_read_receive(&data_callid, &data_len)) {
    870550                async_answer_0(iid, EINVAL);
    871                 fun_del_ref(fun);
    872551                return;
    873552        }
     
    877556                async_answer_0(data_callid, ENOMEM);
    878557                async_answer_0(iid, ENOMEM);
    879                 fun_del_ref(fun);
    880                 return;
    881         }
    882        
    883         fibril_rwlock_read_lock(&device_tree.rwlock);
    884        
    885         /* Check function state */
    886         if (fun->state == FUN_REMOVED) {
    887                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    888                 free(buffer);
    889 
    890                 async_answer_0(data_callid, ENOENT);
    891                 async_answer_0(iid, ENOENT);
    892                 fun_del_ref(fun);
    893                 return;
    894         }
    895        
     558                return;
     559        }
     560
    896561        size_t sent_length = str_size(fun->pathname);
    897562        if (sent_length > data_len) {
     
    902567        async_answer_0(iid, EOK);
    903568
    904         fibril_rwlock_read_unlock(&device_tree.rwlock);
    905         fun_del_ref(fun);
    906569        free(buffer);
    907570}
     
    924587        dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    925588            IPC_GET_ARG1(*icall));
    926         if (dev == NULL || dev->state == DEVICE_REMOVED) {
     589        if (dev == NULL) {
    927590                fibril_rwlock_read_unlock(&device_tree.rwlock);
    928591                async_answer_0(callid, ENOENT);
     
    963626        fibril_rwlock_read_lock(&device_tree.rwlock);
    964627       
    965         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    966         if (fun == NULL || fun->state == FUN_REMOVED) {
     628        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     629        if (fun == NULL) {
    967630                fibril_rwlock_read_unlock(&device_tree.rwlock);
    968631                async_answer_0(iid, ENOENT);
     
    981644}
    982645
    983 /** Online function.
    984  *
    985  * Send a request to online a function to the responsible driver.
    986  * The driver may offline other functions if necessary (i.e. if the state
    987  * of this function is linked to state of another function somehow).
    988  */
    989 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    990 {
    991         fun_node_t *fun;
    992         int rc;
    993 
    994         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    995         if (fun == NULL) {
    996                 async_answer_0(iid, ENOENT);
    997                 return;
    998         }
    999        
    1000         rc = driver_fun_online(&device_tree, fun);
    1001         fun_del_ref(fun);
    1002        
    1003         async_answer_0(iid, (sysarg_t) rc);
    1004 }
    1005 
    1006 /** Offline function.
    1007  *
    1008  * Send a request to offline a function to the responsible driver. As
    1009  * a result the subtree rooted at that function should be cleanly
    1010  * detatched. The driver may offline other functions if necessary
    1011  * (i.e. if the state of this function is linked to state of another
    1012  * function somehow).
    1013  */
    1014 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    1015 {
    1016         fun_node_t *fun;
    1017         int rc;
    1018 
    1019         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    1020         if (fun == NULL) {
    1021                 async_answer_0(iid, ENOENT);
    1022                 return;
    1023         }
    1024        
    1025         rc = driver_fun_offline(&device_tree, fun);
    1026         fun_del_ref(fun);
    1027        
    1028         async_answer_0(iid, (sysarg_t) rc);
    1029 }
    1030 
    1031646/** Find handle for the function instance identified by its service ID. */
    1032647static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
     
    1041656        }
    1042657
    1043         fibril_rwlock_read_lock(&device_tree.rwlock);
    1044 
    1045         /* Check function state */
    1046         if (fun->state == FUN_REMOVED) {
    1047                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1048                 async_answer_0(iid, ENOENT);
    1049                 return;
    1050         }
    1051 
    1052658        async_answer_1(iid, EOK, fun->handle);
    1053         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1054         fun_del_ref(fun);
    1055659}
    1056660
     
    1084688                        devman_fun_get_path(callid, &call);
    1085689                        break;
    1086                 case DEVMAN_FUN_ONLINE:
    1087                         devman_fun_online(callid, &call);
    1088                         break;
    1089                 case DEVMAN_FUN_OFFLINE:
    1090                         devman_fun_offline(callid, &call);
    1091                         break;
    1092690                case DEVMAN_FUN_SID_TO_HANDLE:
    1093691                        devman_fun_sid_to_handle(callid, &call);
     
    1110708        if (fun == NULL)
    1111709                dev = find_dev_node(&device_tree, handle);
    1112         else {
    1113                 fibril_rwlock_read_lock(&device_tree.rwlock);
     710        else
    1114711                dev = fun->dev;
    1115                 if (dev != NULL)
    1116                         dev_add_ref(dev);
    1117                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1118         }
    1119712
    1120713        /*
     
    1128721                    "function with handle %" PRIun " was found.", handle);
    1129722                async_answer_0(iid, ENOENT);
    1130                 goto cleanup;
     723                return;
    1131724        }
    1132725
     
    1136729                    handle);
    1137730                async_answer_0(iid, ENOENT);
    1138                 goto cleanup;
     731                return;
    1139732        }
    1140733       
    1141734        driver_t *driver = NULL;
    1142        
    1143         fibril_rwlock_read_lock(&device_tree.rwlock);
    1144735       
    1145736        if (drv_to_parent) {
     
    1156747        }
    1157748       
    1158         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1159        
    1160749        if (driver == NULL) {
    1161750                log_msg(LVL_ERROR, "IPC forwarding refused - " \
    1162751                    "the device %" PRIun " is not in usable state.", handle);
    1163752                async_answer_0(iid, ENOENT);
    1164                 goto cleanup;
     753                return;
    1165754        }
    1166755       
     
    1175764                    "Could not forward to driver `%s'.", driver->name);
    1176765                async_answer_0(iid, EINVAL);
    1177                 goto cleanup;
     766                return;
    1178767        }
    1179768
     
    1191780        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    1192781        async_exchange_end(exch);
    1193 
    1194 cleanup:
    1195         if (dev != NULL)
    1196                 dev_del_ref(dev);
    1197         if (fun != NULL)
    1198                 fun_del_ref(fun);
    1199782}
    1200783
     
    1206789        fun_node_t *fun;
    1207790        dev_node_t *dev;
    1208         devman_handle_t handle;
    1209         driver_t *driver;
    1210791
    1211792        fun = find_loc_tree_function(&device_tree, service_id);
    1212793       
    1213         fibril_rwlock_read_lock(&device_tree.rwlock);
    1214        
    1215         if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
     794        if (fun == NULL || fun->dev->drv == NULL) {
    1216795                log_msg(LVL_WARN, "devman_connection_loc(): function "
    1217796                    "not found.\n");
    1218                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1219797                async_answer_0(iid, ENOENT);
    1220798                return;
     
    1222800       
    1223801        dev = fun->dev;
    1224         driver = dev->drv;
    1225         handle = fun->handle;
    1226        
    1227         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1228        
    1229         async_exch_t *exch = async_exchange_begin(driver->sess);
    1230         async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
     802       
     803        async_exch_t *exch = async_exchange_begin(dev->drv->sess);
     804        async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0,
    1231805            IPC_FF_NONE);
    1232806        async_exchange_end(exch);
     
    1234808        log_msg(LVL_DEBUG,
    1235809            "Forwarding loc service request for `%s' function to driver `%s'.",
    1236             fun->pathname, driver->name);
    1237 
    1238         fun_del_ref(fun);
     810            fun->pathname, dev->drv->name);
    1239811}
    1240812
     
    1242814static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    1243815{
    1244         /* Select port. */
     816        /* Select interface. */
    1245817        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    1246818        case DEVMAN_DRIVER:
     
    1268840}
    1269841
    1270 static void *devman_client_data_create(void)
    1271 {
    1272         client_t *client;
    1273        
    1274         client = calloc(1, sizeof(client_t));
    1275         if (client == NULL)
    1276                 return NULL;
    1277        
    1278         fibril_mutex_initialize(&client->mutex);
    1279         return client;
    1280 }
    1281 
    1282 static void devman_client_data_destroy(void *data)
    1283 {
    1284         free(data);
    1285 }
    1286 
    1287842/** Initialize device manager internal structures. */
    1288843static bool devman_init(void)
     
    1331886        }
    1332887       
    1333         /* Set handlers for incoming connections. */
    1334         async_set_client_data_constructor(devman_client_data_create);
    1335         async_set_client_data_destructor(devman_client_data_destroy);
     888        /* Set a handler of incomming connections. */
    1336889        async_set_client_connection(devman_connection);
    1337890
Note: See TracChangeset for help on using the changeset viewer.