Changeset 1a5b252 in mainline for uspace/srv/devman/main.c


Ignore:
Timestamp:
2011-08-21T11:54:15Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8cc4ddb
Parents:
e64df9a
Message:

DDF support for function offlining and onlining. This allows
(anticipated) hot removal — support needs to be added in individual
drivers, currently there is support in test1 and partially in rootvirt.
Surprise removal is not supported. TODO: synchronization.

File:
1 edited

Legend:

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

    re64df9a r1a5b252  
    237237}
    238238
    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) {
     239static int online_function(fun_node_t *fun)
     240{
     241        dev_node_t *dev;
     242       
     243        fibril_rwlock_write_lock(&device_tree.rwlock);
     244       
     245        if (fun->ftype == fun_inner) {
    301246                dev = create_dev_node();
    302247                if (dev == NULL) {
    303                         fibril_rwlock_write_unlock(&tree->rwlock);
     248                        fibril_rwlock_write_unlock(&device_tree.rwlock);
    304249                        delete_fun_node(fun);
    305                         async_answer_0(callid, ENOMEM);
    306                         return;
     250                        return ENOMEM;
    307251                }
    308252
    309                 insert_dev_node(tree, dev, fun);
    310         }
    311 
    312         fibril_rwlock_write_unlock(&tree->rwlock);
     253                insert_dev_node(&device_tree, dev, fun);
     254        }
     255       
     256        fibril_rwlock_write_unlock(&device_tree.rwlock);
    313257       
    314258        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
    315259       
    316         devman_receive_match_ids(match_count, &fun->match_ids);
    317 
    318         if (ftype == fun_inner) {
     260        if (fun->ftype == fun_inner) {
     261                dev = fun->child;
    319262                assert(dev != NULL);
     263               
    320264                /*
    321265                 * Try to find a suitable driver and assign it to the device.  We do
     
    336280                }
    337281        } else {
    338                 loc_register_tree_function(fun, tree);
     282                loc_register_tree_function(fun, &device_tree);
     283        }
     284       
     285        return EOK;
     286}
     287
     288static int offline_function(fun_node_t *fun)
     289{
     290        int rc;
     291       
     292        if (fun->ftype == fun_inner) {
     293                printf("devman_drv_fun_offline(): %p is inner fun, removing "
     294                    "child dev.\n", fun);
     295                if (fun->child != NULL) {
     296                        dev_node_t *dev = fun->child;
     297                       
     298                        rc = driver_dev_remove(dev);
     299                        if (rc != EOK) {
     300                                return ENOTSUP;
     301                        }
     302                        detach_driver(dev);
     303                        fibril_rwlock_write_lock(&device_tree.rwlock);
     304                        remove_dev_node(&device_tree, dev);
     305                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     306                        delete_dev_node(dev);
     307                }
     308        } else {
     309                /* Unregister from location service */
     310                rc = loc_service_unregister(fun->service_id);
     311                if (rc != EOK) {
     312                        log_msg(LVL_ERROR, "Failed unregistering tree service.");
     313                        return EIO;
     314                }
     315               
     316                fun->service_id = 0;
     317        }
     318       
     319        return EOK;
     320}
     321
     322/** Handle function registration.
     323 *
     324 * Child devices are registered by their parent's device driver.
     325 */
     326static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
     327{
     328        fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
     329        devman_handle_t dev_handle = IPC_GET_ARG2(*call);
     330        sysarg_t match_count = IPC_GET_ARG3(*call);
     331        dev_tree_t *tree = &device_tree;
     332       
     333        fibril_rwlock_write_lock(&tree->rwlock);
     334
     335        dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
     336       
     337        if (pdev == NULL) {
     338                fibril_rwlock_write_unlock(&tree->rwlock);
     339                async_answer_0(callid, ENOENT);
     340                return;
     341        }
     342       
     343        if (ftype != fun_inner && ftype != fun_exposed) {
     344                /* Unknown function type */
     345                log_msg(LVL_ERROR,
     346                    "Unknown function type %d provided by driver.",
     347                    (int) ftype);
     348
     349                fibril_rwlock_write_unlock(&tree->rwlock);
     350                async_answer_0(callid, EINVAL);
     351                return;
     352        }
     353       
     354        char *fun_name = NULL;
     355        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
     356        if (rc != EOK) {
     357                fibril_rwlock_write_unlock(&tree->rwlock);
     358                async_answer_0(callid, rc);
     359                return;
     360        }
     361       
     362        /* Check that function with same name is not there already. */
     363        if (find_fun_node_in_device(pdev, fun_name) != NULL) {
     364                fibril_rwlock_write_unlock(&tree->rwlock);
     365                async_answer_0(callid, EEXISTS);
     366                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     367                    fun_name);
     368                free(fun_name);
     369                return;
     370        }
     371       
     372        fun_node_t *fun = create_fun_node();
     373        fun->ftype = ftype;
     374       
     375        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     376                fibril_rwlock_write_unlock(&tree->rwlock);
     377                delete_fun_node(fun);
     378                async_answer_0(callid, ENOMEM);
     379                return;
     380        }
     381       
     382        fibril_rwlock_write_unlock(&tree->rwlock);
     383       
     384        devman_receive_match_ids(match_count, &fun->match_ids);
     385       
     386        rc = online_function(fun);
     387        if (rc != EOK) {
     388                /* XXX clean up */
     389                async_answer_0(callid, rc);
     390                return;
    339391        }
    340392       
     
    378430}
    379431
     432/** Online function by driver request.
     433 *
     434 */
     435static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
     436    driver_t *drv)
     437{
     438        fun_node_t *fun;
     439        int rc;
     440
     441        printf("devman_drv_fun_online()\n");
     442        fibril_rwlock_write_lock(&device_tree.rwlock);
     443        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     444        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     445       
     446        if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
     447                async_answer_0(iid, ENOENT);
     448                return;
     449        }
     450       
     451        rc = online_function(fun);
     452        if (rc != EOK) {
     453                printf("devman_drv_fun_online() online_fun->ERROR\n");
     454                async_answer_0(iid, (sysarg_t) rc);
     455                return;
     456        }
     457        printf("devman_drv_fun_online() online_fun->OK\n");
     458       
     459        async_answer_0(iid, (sysarg_t) EOK);
     460}
     461
     462
     463/** Offline function by driver request.
     464 *
     465 */
     466static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
     467    driver_t *drv)
     468{
     469        fun_node_t *fun;
     470        int rc;
     471
     472        fibril_rwlock_write_lock(&device_tree.rwlock);
     473        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     474        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     475       
     476        if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
     477                async_answer_0(iid, ENOENT);
     478                return;
     479        }
     480       
     481        rc = offline_function(fun);
     482        if (rc != EOK) {
     483                async_answer_0(iid, (sysarg_t) rc);
     484                return;
     485        }
     486       
     487        async_answer_0(iid, (sysarg_t) EOK);
     488}
     489
    380490/** Remove function. */
    381491static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
     
    399509                /* Handle possible descendants */
    400510                /* TODO */
    401                 log_msg(LVL_WARN, "devman_remove_function(): not handling "
    402                     "descendants\n");
     511                if (fun->child != NULL) {
     512                        log_msg(LVL_WARN, "devman_remove_function(): not handling "
     513                            "descendants\n");
     514                }
    403515        } 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;
     516                if (fun->service_id != 0) {
     517                        /* Unregister from location service */
     518                        rc = loc_service_unregister(fun->service_id);
     519                        if (rc != EOK) {
     520                                log_msg(LVL_ERROR, "Failed unregistering tree "
     521                                    "service.");
     522                                fibril_rwlock_write_unlock(&tree->rwlock);
     523                                async_answer_0(callid, EIO);
     524                                return;
     525                        }
    411526                }
    412527        }
     
    485600                        devman_add_function_to_cat(callid, &call);
    486601                        break;
     602                case DEVMAN_DRV_FUN_ONLINE:
     603                        devman_drv_fun_online(callid, &call, driver);
     604                        break;
     605                case DEVMAN_DRV_FUN_OFFLINE:
     606                        devman_drv_fun_offline(callid, &call, driver);
     607                        break;
    487608                case DEVMAN_REMOVE_FUNCTION:
    488609                        devman_remove_function(callid, &call);
    489610                        break;
    490611                default:
    491                         async_answer_0(callid, EINVAL); 
     612                        async_answer_0(callid, EINVAL);
    492613                        break;
    493614                }
     
    666787}
    667788
     789/** Online function.
     790 *
     791 * Send a request to online a function to the responsible driver.
     792 * The driver may offline other functions if necessary (i.e. if the state
     793 * of this function is linked to state of another function somehow).
     794 */
     795static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     796{
     797        fun_node_t *fun;
     798        int rc;
     799
     800        fibril_rwlock_write_lock(&device_tree.rwlock);
     801        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     802        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     803       
     804        if (fun == NULL) {
     805                async_answer_0(iid, ENOENT);
     806                return;
     807        }
     808       
     809        rc = driver_fun_online(fun);
     810       
     811        async_answer_0(iid, (sysarg_t) rc);
     812}
     813
     814/** Offline function.
     815 *
     816 * Send a request to offline a function to the responsible driver. As
     817 * a result the subtree rooted at that function should be cleanly
     818 * detatched. The driver may offline other functions if necessary
     819 * (i.e. if the state of this function is linked to state of another
     820 * function somehow).
     821 */
     822static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     823{
     824        fun_node_t *fun;
     825        int rc;
     826
     827        fibril_rwlock_write_lock(&device_tree.rwlock);
     828        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     829        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     830       
     831        if (fun == NULL) {
     832                async_answer_0(iid, ENOENT);
     833                return;
     834        }
     835       
     836        rc = driver_fun_offline(fun);
     837       
     838        async_answer_0(iid, (sysarg_t) rc);
     839}
     840
    668841/** Find handle for the function instance identified by its service ID. */
    669842static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
     
    709882                case DEVMAN_FUN_GET_PATH:
    710883                        devman_fun_get_path(callid, &call);
     884                        break;
     885                case DEVMAN_FUN_ONLINE:
     886                        devman_fun_online(callid, &call);
     887                        break;
     888                case DEVMAN_FUN_OFFLINE:
     889                        devman_fun_offline(callid, &call);
    711890                        break;
    712891                case DEVMAN_FUN_SID_TO_HANDLE:
Note: See TracChangeset for help on using the changeset viewer.