Changeset 00aece0 in mainline for uspace/srv/devman/main.c


Ignore:
Timestamp:
2012-02-18T16:47:38Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4449c6c
Parents:
bd5f3b7 (diff), f943dd3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

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

    rbd5f3b7 r00aece0  
    234234        dev_node_t *dev_node = (dev_node_t *) arg;
    235235        assign_driver(dev_node, &drivers_list, &device_tree);
     236
     237        /* Delete one reference we got from the caller. */
     238        dev_del_ref(dev_node);
    236239        return EOK;
    237240}
    238241
    239 /** Handle function registration.
    240  *
    241  * Child devices are registered by their parent's device driver.
    242  */
    243 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
    244 {
    245         fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
    246         devman_handle_t dev_handle = IPC_GET_ARG2(*call);
    247         sysarg_t match_count = IPC_GET_ARG3(*call);
    248         dev_tree_t *tree = &device_tree;
    249        
    250         fibril_rwlock_write_lock(&tree->rwlock);
    251 
    252         dev_node_t *dev = NULL;
    253         dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
    254        
    255         if (pdev == NULL) {
    256                 fibril_rwlock_write_unlock(&tree->rwlock);
    257                 async_answer_0(callid, ENOENT);
    258                 return;
    259         }
    260        
    261         if (ftype != fun_inner && ftype != fun_exposed) {
    262                 /* Unknown function type */
    263                 log_msg(LVL_ERROR,
    264                     "Unknown function type %d provided by driver.",
    265                     (int) ftype);
    266 
    267                 fibril_rwlock_write_unlock(&tree->rwlock);
    268                 async_answer_0(callid, EINVAL);
    269                 return;
    270         }
    271        
    272         char *fun_name = NULL;
    273         int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
    274         if (rc != EOK) {
    275                 fibril_rwlock_write_unlock(&tree->rwlock);
    276                 async_answer_0(callid, rc);
    277                 return;
    278         }
    279        
    280         /* Check that function with same name is not there already. */
    281         if (find_fun_node_in_device(pdev, fun_name) != NULL) {
    282                 fibril_rwlock_write_unlock(&tree->rwlock);
    283                 async_answer_0(callid, EEXISTS);
    284                 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
    285                     fun_name);
    286                 free(fun_name);
    287                 return;
    288         }
    289        
    290         fun_node_t *fun = create_fun_node();
    291         fun->ftype = ftype;
    292        
    293         if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    294                 fibril_rwlock_write_unlock(&tree->rwlock);
    295                 delete_fun_node(fun);
    296                 async_answer_0(callid, ENOMEM);
    297                 return;
    298         }
    299 
    300         if (ftype == fun_inner) {
     242static int online_function(fun_node_t *fun)
     243{
     244        dev_node_t *dev;
     245       
     246        fibril_rwlock_write_lock(&device_tree.rwlock);
     247
     248        if (fun->state == FUN_ON_LINE) {
     249                fibril_rwlock_write_unlock(&device_tree.rwlock);
     250                log_msg(LVL_WARN, "Function %s is already on line.",
     251                    fun->pathname);
     252                return EOK;
     253        }
     254       
     255        if (fun->ftype == fun_inner) {
    301256                dev = create_dev_node();
    302257                if (dev == NULL) {
    303                         fibril_rwlock_write_unlock(&tree->rwlock);
    304                         delete_fun_node(fun);
    305                         async_answer_0(callid, ENOMEM);
    306                         return;
     258                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     259                        return ENOMEM;
    307260                }
    308261
    309                 insert_dev_node(tree, dev, fun);
    310         }
    311 
    312         fibril_rwlock_write_unlock(&tree->rwlock);
     262                insert_dev_node(&device_tree, dev, fun);
     263                dev_add_ref(dev);
     264        }
    313265       
    314266        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
    315267       
    316         devman_receive_match_ids(match_count, &fun->match_ids);
    317 
    318         if (ftype == fun_inner) {
     268        if (fun->ftype == fun_inner) {
     269                dev = fun->child;
    319270                assert(dev != NULL);
     271               
     272                /* Give one reference over to assign_driver_fibril(). */
     273                dev_add_ref(dev);
    320274                /*
    321275                 * Try to find a suitable driver and assign it to the device.  We do
     
    327281                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
    328282                if (assign_fibril == 0) {
    329                         /*
    330                          * Fallback in case we are out of memory.
    331                          * Probably not needed as we will die soon anyway ;-).
    332                          */
    333                         (void) assign_driver_fibril(fun);
    334                 } else {
    335                         fibril_add_ready(assign_fibril);
     283                        log_msg(LVL_ERROR, "Failed to create fibril for "
     284                            "assigning driver.");
     285                        /* XXX Cleanup */
     286                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     287                        return ENOMEM;
     288                }
     289                fibril_add_ready(assign_fibril);
     290        } else {
     291                loc_register_tree_function(fun, &device_tree);
     292        }
     293       
     294        fibril_rwlock_write_unlock(&device_tree.rwlock);
     295       
     296        return EOK;
     297}
     298
     299static int offline_function(fun_node_t *fun)
     300{
     301        int rc;
     302       
     303        fibril_rwlock_write_lock(&device_tree.rwlock);
     304       
     305        if (fun->state == FUN_OFF_LINE) {
     306                fibril_rwlock_write_unlock(&device_tree.rwlock);
     307                log_msg(LVL_WARN, "Function %s is already off line.",
     308                    fun->pathname);
     309                return EOK;
     310        }
     311       
     312        if (fun->ftype == fun_inner) {
     313                log_msg(LVL_DEBUG, "Offlining inner function %s.",
     314                    fun->pathname);
     315               
     316                if (fun->child != NULL) {
     317                        dev_node_t *dev = fun->child;
     318                        device_state_t dev_state;
     319                       
     320                        dev_add_ref(dev);
     321                        dev_state = dev->state;
     322                       
     323                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     324
     325                        /* If device is owned by driver, ask driver to give it up. */
     326                        if (dev_state == DEVICE_USABLE) {
     327                                rc = driver_dev_remove(&device_tree, dev);
     328                                if (rc != EOK) {
     329                                        dev_del_ref(dev);
     330                                        return ENOTSUP;
     331                                }
     332                        }
     333                       
     334                        /* Verify that driver removed all functions */
     335                        fibril_rwlock_read_lock(&device_tree.rwlock);
     336                        if (!list_empty(&dev->functions)) {
     337                                fibril_rwlock_read_unlock(&device_tree.rwlock);
     338                                dev_del_ref(dev);
     339                                return EIO;
     340                        }
     341                       
     342                        driver_t *driver = dev->drv;
     343                        fibril_rwlock_read_unlock(&device_tree.rwlock);
     344                       
     345                        if (driver)
     346                                detach_driver(&device_tree, dev);
     347                       
     348                        fibril_rwlock_write_lock(&device_tree.rwlock);
     349                        remove_dev_node(&device_tree, dev);
     350                       
     351                        /* Delete ref created when node was inserted */
     352                        dev_del_ref(dev);
     353                        /* Delete ref created by dev_add_ref(dev) above */
     354                        dev_del_ref(dev);
    336355                }
    337356        } else {
    338                 loc_register_tree_function(fun, tree);
     357                /* Unregister from location service */
     358                rc = loc_service_unregister(fun->service_id);
     359                if (rc != EOK) {
     360                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     361                        log_msg(LVL_ERROR, "Failed unregistering tree service.");
     362                        return EIO;
     363                }
     364               
     365                fun->service_id = 0;
     366        }
     367       
     368        fun->state = FUN_OFF_LINE;
     369        fibril_rwlock_write_unlock(&device_tree.rwlock);
     370       
     371        return EOK;
     372}
     373
     374/** Handle function registration.
     375 *
     376 * Child devices are registered by their parent's device driver.
     377 */
     378static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
     379{
     380        fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
     381        devman_handle_t dev_handle = IPC_GET_ARG2(*call);
     382        sysarg_t match_count = IPC_GET_ARG3(*call);
     383        dev_tree_t *tree = &device_tree;
     384       
     385        dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
     386        if (pdev == NULL) {
     387                async_answer_0(callid, ENOENT);
     388                return;
     389        }
     390       
     391        if (ftype != fun_inner && ftype != fun_exposed) {
     392                /* Unknown function type */
     393                log_msg(LVL_ERROR,
     394                    "Unknown function type %d provided by driver.",
     395                    (int) ftype);
     396
     397                dev_del_ref(pdev);
     398                async_answer_0(callid, EINVAL);
     399                return;
     400        }
     401       
     402        char *fun_name = NULL;
     403        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
     404        if (rc != EOK) {
     405                dev_del_ref(pdev);
     406                async_answer_0(callid, rc);
     407                return;
     408        }
     409       
     410        fibril_rwlock_write_lock(&tree->rwlock);
     411       
     412        /* Check device state */
     413        if (pdev->state == DEVICE_REMOVED) {
     414                fibril_rwlock_write_unlock(&tree->rwlock);
     415                dev_del_ref(pdev);
     416                async_answer_0(callid, ENOENT);
     417                return;
     418        }
     419       
     420        /* Check that function with same name is not there already. */
     421        if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) {
     422                fibril_rwlock_write_unlock(&tree->rwlock);
     423                dev_del_ref(pdev);
     424                async_answer_0(callid, EEXISTS);
     425                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     426                    fun_name);
     427                free(fun_name);
     428                return;
     429        }
     430       
     431        fun_node_t *fun = create_fun_node();
     432        fun_add_ref(fun);
     433        fun->ftype = ftype;
     434       
     435        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     436                fibril_rwlock_write_unlock(&tree->rwlock);
     437                dev_del_ref(pdev);
     438                delete_fun_node(fun);
     439                async_answer_0(callid, ENOMEM);
     440                return;
     441        }
     442       
     443        fibril_rwlock_write_unlock(&tree->rwlock);
     444        dev_del_ref(pdev);
     445       
     446        devman_receive_match_ids(match_count, &fun->match_ids);
     447       
     448        rc = online_function(fun);
     449        if (rc != EOK) {
     450                /* XXX clean up */
     451                async_answer_0(callid, rc);
     452                return;
    339453        }
    340454       
     
    356470                async_answer_0(callid, rc);
    357471                return;
    358         }       
     472        }
    359473       
    360474        fun_node_t *fun = find_fun_node(&device_tree, handle);
     
    364478        }
    365479       
     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       
    366489        rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
    367490        if (rc == EOK) {
    368491                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);
    369494        } else {
    370495                log_msg(LVL_ERROR, "Failed adding function `%s' to category "
     
    372497        }
    373498       
    374         log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
    375             fun->pathname, cat_name);
    376 
    377         async_answer_0(callid, EOK);
     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 */
     508static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
     509    driver_t *drv)
     510{
     511        fun_node_t *fun;
     512        int rc;
     513       
     514        log_msg(LVL_DEBUG, "devman_drv_fun_online()");
     515       
     516        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     517        if (fun == NULL) {
     518                async_answer_0(iid, ENOENT);
     519                return;
     520        }
     521       
     522        fibril_rwlock_read_lock(&device_tree.rwlock);
     523        if (fun->dev == NULL || fun->dev->drv != drv) {
     524                fibril_rwlock_read_unlock(&device_tree.rwlock);
     525                fun_del_ref(fun);
     526                async_answer_0(iid, ENOENT);
     527                return;
     528        }
     529        fibril_rwlock_read_unlock(&device_tree.rwlock);
     530       
     531        rc = online_function(fun);
     532        if (rc != EOK) {
     533                fun_del_ref(fun);
     534                async_answer_0(iid, (sysarg_t) rc);
     535                return;
     536        }
     537       
     538        fun_del_ref(fun);
     539       
     540        async_answer_0(iid, (sysarg_t) EOK);
     541}
     542
     543
     544/** Offline function by driver request.
     545 *
     546 */
     547static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
     548    driver_t *drv)
     549{
     550        fun_node_t *fun;
     551        int rc;
     552
     553        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     554        if (fun == NULL) {
     555                async_answer_0(iid, ENOENT);
     556                return;
     557        }
     558       
     559        fibril_rwlock_write_lock(&device_tree.rwlock);
     560        if (fun->dev == NULL || fun->dev->drv != drv) {
     561                fun_del_ref(fun);
     562                async_answer_0(iid, ENOENT);
     563                return;
     564        }
     565        fibril_rwlock_write_unlock(&device_tree.rwlock);
     566       
     567        rc = offline_function(fun);
     568        if (rc != EOK) {
     569                fun_del_ref(fun);
     570                async_answer_0(iid, (sysarg_t) rc);
     571                return;
     572        }
     573       
     574        fun_del_ref(fun);
     575        async_answer_0(iid, (sysarg_t) EOK);
    378576}
    379577
     
    385583        int rc;
    386584       
     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       
    387591        fibril_rwlock_write_lock(&tree->rwlock);
    388592       
    389         fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
    390         if (fun == NULL) {
     593        log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
     594       
     595        /* Check function state */
     596        if (fun->state == FUN_REMOVED) {
    391597                fibril_rwlock_write_unlock(&tree->rwlock);
    392598                async_answer_0(callid, ENOENT);
     
    394600        }
    395601       
    396         log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    397        
    398602        if (fun->ftype == fun_inner) {
    399                 /* Handle possible descendants */
    400                 /* TODO */
    401                 log_msg(LVL_WARN, "devman_remove_function(): not handling "
    402                     "descendants\n");
     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                }
    403656        } else {
    404                 /* Unregister from location service */
    405                 rc = loc_service_unregister(fun->service_id);
    406                 if (rc != EOK) {
    407                         log_msg(LVL_ERROR, "Failed unregistering tree service.");
    408                         fibril_rwlock_write_unlock(&tree->rwlock);
    409                         async_answer_0(callid, EIO);
    410                         return;
     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                        }
    411668                }
    412669        }
     
    414671        remove_fun_node(&device_tree, fun);
    415672        fibril_rwlock_write_unlock(&tree->rwlock);
    416         delete_fun_node(fun);
     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);
    417678       
    418679        log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
     
    485746                        devman_add_function_to_cat(callid, &call);
    486747                        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;
    487754                case DEVMAN_REMOVE_FUNCTION:
    488755                        devman_remove_function(callid, &call);
    489756                        break;
    490757                default:
    491                         async_answer_0(callid, EINVAL); 
     758                        async_answer_0(callid, EINVAL);
    492759                        break;
    493760                }
     
    500767{
    501768        char *pathname;
     769        devman_handle_t handle;
    502770       
    503771        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     
    516784        }
    517785
    518         async_answer_1(iid, EOK, fun->handle);
     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);
    519802}
    520803
     
    534817        if (!async_data_read_receive(&data_callid, &data_len)) {
    535818                async_answer_0(iid, EINVAL);
     819                fun_del_ref(fun);
    536820                return;
    537821        }
     
    541825                async_answer_0(data_callid, ENOMEM);
    542826                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);
    543841                return;
    544842        }
     
    552850        async_answer_0(iid, EOK);
    553851
     852        fibril_rwlock_read_unlock(&device_tree.rwlock);
     853        fun_del_ref(fun);
    554854        free(buffer);
    555855}
     
    571871        if (!async_data_read_receive(&data_callid, &data_len)) {
    572872                async_answer_0(iid, EINVAL);
     873                fun_del_ref(fun);
    573874                return;
    574875        }
     
    578879                async_answer_0(data_callid, ENOMEM);
    579880                async_answer_0(iid, ENOMEM);
    580                 return;
    581         }
    582 
     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       
    583898        size_t sent_length = str_size(fun->pathname);
    584899        if (sent_length > data_len) {
     
    589904        async_answer_0(iid, EOK);
    590905
     906        fibril_rwlock_read_unlock(&device_tree.rwlock);
     907        fun_del_ref(fun);
    591908        free(buffer);
    592909}
     
    609926        dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    610927            IPC_GET_ARG1(*icall));
    611         if (dev == NULL) {
     928        if (dev == NULL || dev->state == DEVICE_REMOVED) {
    612929                fibril_rwlock_read_unlock(&device_tree.rwlock);
    613930                async_answer_0(callid, ENOENT);
     
    648965        fibril_rwlock_read_lock(&device_tree.rwlock);
    649966       
     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 */
     991static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     992{
     993        fun_node_t *fun;
     994        int rc;
     995
    650996        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    651997        if (fun == NULL) {
    652                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    653                 async_answer_0(iid, ENOENT);
    654                 return;
    655         }
    656        
    657         if (fun->child == NULL) {
    658                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    659                 async_answer_0(iid, ENOENT);
    660                 return;
    661         }
    662        
    663         async_answer_1(iid, EOK, fun->child->handle);
    664        
    665         fibril_rwlock_read_unlock(&device_tree.rwlock);
     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 */
     1016static 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);
    6661031}
    6671032
     
    6781043        }
    6791044
     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
    6801054        async_answer_1(iid, EOK, fun->handle);
     1055        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1056        fun_del_ref(fun);
    6811057}
    6821058
     
    7101086                        devman_fun_get_path(callid, &call);
    7111087                        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;
    7121094                case DEVMAN_FUN_SID_TO_HANDLE:
    7131095                        devman_fun_sid_to_handle(callid, &call);
     
    7301112        if (fun == NULL)
    7311113                dev = find_dev_node(&device_tree, handle);
    732         else
     1114        else {
     1115                fibril_rwlock_read_lock(&device_tree.rwlock);
    7331116                dev = fun->dev;
     1117                if (dev != NULL)
     1118                        dev_add_ref(dev);
     1119                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1120        }
    7341121
    7351122        /*
     
    7431130                    "function with handle %" PRIun " was found.", handle);
    7441131                async_answer_0(iid, ENOENT);
    745                 return;
     1132                goto cleanup;
    7461133        }
    7471134
     
    7511138                    handle);
    7521139                async_answer_0(iid, ENOENT);
    753                 return;
     1140                goto cleanup;
    7541141        }
    7551142       
    7561143        driver_t *driver = NULL;
     1144       
     1145        fibril_rwlock_read_lock(&device_tree.rwlock);
    7571146       
    7581147        if (drv_to_parent) {
     
    7691158        }
    7701159       
     1160        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1161       
    7711162        if (driver == NULL) {
    7721163                log_msg(LVL_ERROR, "IPC forwarding refused - " \
    7731164                    "the device %" PRIun " is not in usable state.", handle);
    7741165                async_answer_0(iid, ENOENT);
    775                 return;
     1166                goto cleanup;
    7761167        }
    7771168       
     
    7861177                    "Could not forward to driver `%s'.", driver->name);
    7871178                async_answer_0(iid, EINVAL);
    788                 return;
     1179                goto cleanup;
    7891180        }
    7901181
     
    8021193        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    8031194        async_exchange_end(exch);
     1195
     1196cleanup:
     1197        if (dev != NULL)
     1198                dev_del_ref(dev);
     1199        if (fun != NULL)
     1200                fun_del_ref(fun);
    8041201}
    8051202
     
    8111208        fun_node_t *fun;
    8121209        dev_node_t *dev;
     1210        devman_handle_t handle;
     1211        driver_t *driver;
    8131212
    8141213        fun = find_loc_tree_function(&device_tree, service_id);
    8151214       
    816         if (fun == NULL || fun->dev->drv == NULL) {
     1215        fibril_rwlock_read_lock(&device_tree.rwlock);
     1216       
     1217        if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
    8171218                log_msg(LVL_WARN, "devman_connection_loc(): function "
    8181219                    "not found.\n");
     1220                fibril_rwlock_read_unlock(&device_tree.rwlock);
    8191221                async_answer_0(iid, ENOENT);
    8201222                return;
     
    8221224       
    8231225        dev = fun->dev;
    824        
    825         async_exch_t *exch = async_exchange_begin(dev->drv->sess);
    826         async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0,
     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,
    8271233            IPC_FF_NONE);
    8281234        async_exchange_end(exch);
     
    8301236        log_msg(LVL_DEBUG,
    8311237            "Forwarding loc service request for `%s' function to driver `%s'.",
    832             fun->pathname, dev->drv->name);
     1238            fun->pathname, driver->name);
     1239
     1240        fun_del_ref(fun);
    8331241}
    8341242
     
    9011309
    9021310        /*
    903          * !!! devman_connection ... as the device manager is not a real loc
    904          * driver (it uses a completely different ipc protocol than an ordinary
    905          * loc driver) forwarding a connection from client to the devman by
    906          * location service would not work.
     1311         * Caution: As the device manager is not a real loc
     1312         * driver (it uses a completely different IPC protocol
     1313         * than an ordinary loc driver), forwarding a connection
     1314         * from client to the devman by location service will
     1315         * not work.
    9071316         */
    908         loc_server_register(NAME, devman_connection);
     1317        loc_server_register(NAME);
    9091318       
    9101319        return true;
     
    9171326        if (log_init(NAME, LVL_WARN) != EOK) {
    9181327                printf(NAME ": Error initializing logging subsystem.\n");
    919                 return -1;
    920         }
    921 
    922         if (!devman_init()) {
    923                 log_msg(LVL_ERROR, "Error while initializing service.");
    9241328                return -1;
    9251329        }
     
    9301334        async_set_client_connection(devman_connection);
    9311335
     1336        if (!devman_init()) {
     1337                log_msg(LVL_ERROR, "Error while initializing service.");
     1338                return -1;
     1339        }
     1340
    9321341        /* Register device manager at naming service. */
    9331342        if (service_register(SERVICE_DEVMAN) != EOK) {
Note: See TracChangeset for help on using the changeset viewer.