Changeset c05642d in mainline for uspace/srv/devman/main.c


Ignore:
Timestamp:
2011-09-07T00:03:26Z (13 years ago)
Author:
Petr Koupy <petr.koupy@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5081276
Parents:
bb74dabe (diff), 038b289 (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

    rbb74dabe rc05642d  
    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);
    361475        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);
    362485                async_answer_0(callid, ENOENT);
    363486                return;
     
    375498            fun->pathname, cat_name);
    376499
     500        fibril_rwlock_read_unlock(&device_tree.rwlock);
     501        fun_del_ref(fun);
     502
    377503        async_answer_0(callid, EOK);
     504}
     505
     506/** Online function by driver request.
     507 *
     508 */
     509static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
     510    driver_t *drv)
     511{
     512        fun_node_t *fun;
     513        int rc;
     514       
     515        log_msg(LVL_DEBUG, "devman_drv_fun_online()");
     516       
     517        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     518        if (fun == NULL) {
     519                async_answer_0(iid, ENOENT);
     520                return;
     521        }
     522       
     523        fibril_rwlock_read_lock(&device_tree.rwlock);
     524        if (fun->dev == NULL || fun->dev->drv != drv) {
     525                fibril_rwlock_read_unlock(&device_tree.rwlock);
     526                fun_del_ref(fun);
     527                async_answer_0(iid, ENOENT);
     528                return;
     529        }
     530        fibril_rwlock_read_unlock(&device_tree.rwlock);
     531       
     532        rc = online_function(fun);
     533        if (rc != EOK) {
     534                fun_del_ref(fun);
     535                async_answer_0(iid, (sysarg_t) rc);
     536                return;
     537        }
     538       
     539        fun_del_ref(fun);
     540       
     541        async_answer_0(iid, (sysarg_t) EOK);
     542}
     543
     544
     545/** Offline function by driver request.
     546 *
     547 */
     548static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
     549    driver_t *drv)
     550{
     551        fun_node_t *fun;
     552        int rc;
     553
     554        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     555        if (fun == NULL) {
     556                async_answer_0(iid, ENOENT);
     557                return;
     558        }
     559       
     560        fibril_rwlock_write_lock(&device_tree.rwlock);
     561        if (fun->dev == NULL || fun->dev->drv != drv) {
     562                fun_del_ref(fun);
     563                async_answer_0(iid, ENOENT);
     564                return;
     565        }
     566        fibril_rwlock_write_unlock(&device_tree.rwlock);
     567       
     568        rc = offline_function(fun);
     569        if (rc != EOK) {
     570                fun_del_ref(fun);
     571                async_answer_0(iid, (sysarg_t) rc);
     572                return;
     573        }
     574       
     575        fun_del_ref(fun);
     576        async_answer_0(iid, (sysarg_t) EOK);
    378577}
    379578
     
    385584        int rc;
    386585       
     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       
    387592        fibril_rwlock_write_lock(&tree->rwlock);
    388593       
    389         fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
    390         if (fun == NULL) {
     594        log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
     595       
     596        /* Check function state */
     597        if (fun->state == FUN_REMOVED) {
    391598                fibril_rwlock_write_unlock(&tree->rwlock);
    392599                async_answer_0(callid, ENOENT);
     
    394601        }
    395602       
    396         log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    397        
    398603        if (fun->ftype == fun_inner) {
    399                 /* Handle possible descendants */
    400                 /* TODO */
    401                 log_msg(LVL_WARN, "devman_remove_function(): not handling "
    402                     "descendants\n");
     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                }
    403654        } 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;
     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                        }
    411666                }
    412667        }
     
    414669        remove_fun_node(&device_tree, fun);
    415670        fibril_rwlock_write_unlock(&tree->rwlock);
    416         delete_fun_node(fun);
     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);
    417676       
    418677        log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
     
    485744                        devman_add_function_to_cat(callid, &call);
    486745                        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;
    487752                case DEVMAN_REMOVE_FUNCTION:
    488753                        devman_remove_function(callid, &call);
    489754                        break;
    490755                default:
    491                         async_answer_0(callid, EINVAL); 
     756                        async_answer_0(callid, EINVAL);
    492757                        break;
    493758                }
     
    500765{
    501766        char *pathname;
     767        devman_handle_t handle;
    502768       
    503769        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     
    516782        }
    517783
    518         async_answer_1(iid, EOK, fun->handle);
     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);
    519800}
    520801
     
    534815        if (!async_data_read_receive(&data_callid, &data_len)) {
    535816                async_answer_0(iid, EINVAL);
     817                fun_del_ref(fun);
    536818                return;
    537819        }
     
    541823                async_answer_0(data_callid, ENOMEM);
    542824                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);
    543839                return;
    544840        }
     
    552848        async_answer_0(iid, EOK);
    553849
     850        fibril_rwlock_read_unlock(&device_tree.rwlock);
     851        fun_del_ref(fun);
    554852        free(buffer);
    555853}
     
    571869        if (!async_data_read_receive(&data_callid, &data_len)) {
    572870                async_answer_0(iid, EINVAL);
     871                fun_del_ref(fun);
    573872                return;
    574873        }
     
    578877                async_answer_0(data_callid, ENOMEM);
    579878                async_answer_0(iid, ENOMEM);
    580                 return;
    581         }
    582 
     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       
    583896        size_t sent_length = str_size(fun->pathname);
    584897        if (sent_length > data_len) {
     
    589902        async_answer_0(iid, EOK);
    590903
     904        fibril_rwlock_read_unlock(&device_tree.rwlock);
     905        fun_del_ref(fun);
    591906        free(buffer);
    592907}
     
    609924        dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    610925            IPC_GET_ARG1(*icall));
    611         if (dev == NULL) {
     926        if (dev == NULL || dev->state == DEVICE_REMOVED) {
    612927                fibril_rwlock_read_unlock(&device_tree.rwlock);
    613928                async_answer_0(callid, ENOENT);
     
    648963        fibril_rwlock_read_lock(&device_tree.rwlock);
    649964       
     965        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     966        if (fun == NULL || fun->state == FUN_REMOVED) {
     967                fibril_rwlock_read_unlock(&device_tree.rwlock);
     968                async_answer_0(iid, ENOENT);
     969                return;
     970        }
     971       
     972        if (fun->child == NULL) {
     973                fibril_rwlock_read_unlock(&device_tree.rwlock);
     974                async_answer_0(iid, ENOENT);
     975                return;
     976        }
     977       
     978        async_answer_1(iid, EOK, fun->child->handle);
     979       
     980        fibril_rwlock_read_unlock(&device_tree.rwlock);
     981}
     982
     983/** Online function.
     984 *
     985 * Send a request to online a function to the responsible driver.
     986 * The driver may offline other functions if necessary (i.e. if the state
     987 * of this function is linked to state of another function somehow).
     988 */
     989static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     990{
     991        fun_node_t *fun;
     992        int rc;
     993
    650994        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    651995        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);
     996                async_answer_0(iid, ENOENT);
     997                return;
     998        }
     999       
     1000        rc = driver_fun_online(&device_tree, fun);
     1001        fun_del_ref(fun);
     1002       
     1003        async_answer_0(iid, (sysarg_t) rc);
     1004}
     1005
     1006/** Offline function.
     1007 *
     1008 * Send a request to offline a function to the responsible driver. As
     1009 * a result the subtree rooted at that function should be cleanly
     1010 * detatched. The driver may offline other functions if necessary
     1011 * (i.e. if the state of this function is linked to state of another
     1012 * function somehow).
     1013 */
     1014static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     1015{
     1016        fun_node_t *fun;
     1017        int rc;
     1018
     1019        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     1020        if (fun == NULL) {
     1021                async_answer_0(iid, ENOENT);
     1022                return;
     1023        }
     1024       
     1025        rc = driver_fun_offline(&device_tree, fun);
     1026        fun_del_ref(fun);
     1027       
     1028        async_answer_0(iid, (sysarg_t) rc);
    6661029}
    6671030
     
    6781041        }
    6791042
     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
    6801052        async_answer_1(iid, EOK, fun->handle);
     1053        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1054        fun_del_ref(fun);
    6811055}
    6821056
     
    7101084                        devman_fun_get_path(callid, &call);
    7111085                        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;
    7121092                case DEVMAN_FUN_SID_TO_HANDLE:
    7131093                        devman_fun_sid_to_handle(callid, &call);
     
    7301110        if (fun == NULL)
    7311111                dev = find_dev_node(&device_tree, handle);
    732         else
     1112        else {
     1113                fibril_rwlock_read_lock(&device_tree.rwlock);
    7331114                dev = fun->dev;
     1115                if (dev != NULL)
     1116                        dev_add_ref(dev);
     1117                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1118        }
    7341119
    7351120        /*
     
    7431128                    "function with handle %" PRIun " was found.", handle);
    7441129                async_answer_0(iid, ENOENT);
    745                 return;
     1130                goto cleanup;
    7461131        }
    7471132
     
    7511136                    handle);
    7521137                async_answer_0(iid, ENOENT);
    753                 return;
     1138                goto cleanup;
    7541139        }
    7551140       
    7561141        driver_t *driver = NULL;
     1142       
     1143        fibril_rwlock_read_lock(&device_tree.rwlock);
    7571144       
    7581145        if (drv_to_parent) {
     
    7691156        }
    7701157       
     1158        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1159       
    7711160        if (driver == NULL) {
    7721161                log_msg(LVL_ERROR, "IPC forwarding refused - " \
    7731162                    "the device %" PRIun " is not in usable state.", handle);
    7741163                async_answer_0(iid, ENOENT);
    775                 return;
     1164                goto cleanup;
    7761165        }
    7771166       
     
    7861175                    "Could not forward to driver `%s'.", driver->name);
    7871176                async_answer_0(iid, EINVAL);
    788                 return;
     1177                goto cleanup;
    7891178        }
    7901179
     
    8021191        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    8031192        async_exchange_end(exch);
     1193
     1194cleanup:
     1195        if (dev != NULL)
     1196                dev_del_ref(dev);
     1197        if (fun != NULL)
     1198                fun_del_ref(fun);
    8041199}
    8051200
     
    8111206        fun_node_t *fun;
    8121207        dev_node_t *dev;
     1208        devman_handle_t handle;
     1209        driver_t *driver;
    8131210
    8141211        fun = find_loc_tree_function(&device_tree, service_id);
    8151212       
    816         if (fun == NULL || fun->dev->drv == NULL) {
     1213        fibril_rwlock_read_lock(&device_tree.rwlock);
     1214       
     1215        if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
    8171216                log_msg(LVL_WARN, "devman_connection_loc(): function "
    8181217                    "not found.\n");
     1218                fibril_rwlock_read_unlock(&device_tree.rwlock);
    8191219                async_answer_0(iid, ENOENT);
    8201220                return;
     
    8221222       
    8231223        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,
     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,
    8271231            IPC_FF_NONE);
    8281232        async_exchange_end(exch);
     
    8301234        log_msg(LVL_DEBUG,
    8311235            "Forwarding loc service request for `%s' function to driver `%s'.",
    832             fun->pathname, dev->drv->name);
     1236            fun->pathname, driver->name);
     1237
     1238        fun_del_ref(fun);
    8331239}
    8341240
Note: See TracChangeset for help on using the changeset viewer.