Changeset 80a96d2 in mainline


Ignore:
Timestamp:
2011-09-05T21:26:47Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b33870b
Parents:
16cc9a6
Message:

DDF support for surprise removal.

Location:
uspace
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/test/test1/test1.c

    r16cc9a6 r80a96d2  
    4242static int test1_add_device(ddf_dev_t *dev);
    4343static int test1_dev_remove(ddf_dev_t *dev);
     44static int test1_dev_gone(ddf_dev_t *dev);
    4445static int test1_fun_online(ddf_fun_t *fun);
    4546static int test1_fun_offline(ddf_fun_t *fun);
     
    4849        .add_device = &test1_add_device,
    4950        .dev_remove = &test1_dev_remove,
     51        .dev_gone = &test1_dev_gone,
    5052        .fun_online = &test1_fun_online,
    5153        .fun_offline = &test1_fun_offline
     
    213215}
    214216
     217static int fun_unbind(ddf_fun_t *fun, const char *name)
     218{
     219        int rc;
     220
     221        ddf_msg(LVL_DEBUG, "fun_unbind(%p, '%s')", fun, name);
     222        rc = ddf_fun_unbind(fun);
     223        if (rc != EOK) {
     224                ddf_msg(LVL_ERROR, "Failed unbinding function '%s'.", name);
     225                return rc;
     226        }
     227
     228        ddf_fun_destroy(fun);
     229        return EOK;
     230}
     231
    215232static int test1_dev_remove(ddf_dev_t *dev)
    216233{
     
    234251        if (test1->child != NULL) {
    235252                rc = fun_remove(test1->child, "child");
     253                if (rc != EOK)
     254                        return rc;
     255        }
     256
     257        return EOK;
     258}
     259
     260static int test1_dev_gone(ddf_dev_t *dev)
     261{
     262        test1_t *test1 = (test1_t *)dev->driver_data;
     263        int rc;
     264
     265        ddf_msg(LVL_DEBUG, "test1_dev_remove(%p)", dev);
     266
     267        if (test1->fun_a != NULL) {
     268                rc = fun_unbind(test1->fun_a, "a");
     269                if (rc != EOK)
     270                        return rc;
     271        }
     272
     273        if (test1->clone != NULL) {
     274                rc = fun_unbind(test1->clone, "clone");
     275                if (rc != EOK)
     276                        return rc;
     277        }
     278
     279        if (test1->child != NULL) {
     280                rc = fun_unbind(test1->child, "child");
    236281                if (rc != EOK)
    237282                        return rc;
  • uspace/drv/test/test2/test2.c

    r16cc9a6 r80a96d2  
    4242static int test2_add_device(ddf_dev_t *dev);
    4343static int test2_dev_remove(ddf_dev_t *dev);
     44static int test2_dev_gone(ddf_dev_t *dev);
    4445static int test2_fun_online(ddf_fun_t *fun);
    4546static int test2_fun_offline(ddf_fun_t *fun);
     
    4849        .add_device = &test2_add_device,
    4950        .dev_remove = &test2_dev_remove,
     51        .dev_gone = &test2_dev_gone,
    5052        .fun_online = &test2_fun_online,
    5153        .fun_offline = &test2_fun_offline
     
    111113}
    112114
    113 /** Add child devices after some sleep.
     115/** Simulate plugging and surprise unplugging.
    114116 *
    115117 * @param arg Parent device structure (ddf_dev_t *).
    116118 * @return Always EOK.
    117119 */
    118 static int postponed_birth(void *arg)
     120static int plug_unplug(void *arg)
    119121{
    120122        test2_t *test2 = (test2_t *) arg;
     
    144146        test2->fun_a = fun_a;
    145147
     148        async_usleep(10000000);
     149
     150        ddf_msg(LVL_NOTE, "Unbinding function test1.");
     151        ddf_fun_unbind(test2->test1);
     152        async_usleep(1000000);
     153        ddf_msg(LVL_NOTE, "Unbinding function child.");
     154        ddf_fun_unbind(test2->child);
     155
    146156        return EOK;
    147157}
     
    158168        }
    159169
     170        rc = ddf_fun_unbind(fun);
     171        if (rc != EOK) {
     172                ddf_msg(LVL_ERROR, "Failed unbinding function '%s'.", name);
     173                return rc;
     174        }
     175
     176        ddf_fun_destroy(fun);
     177        return EOK;
     178}
     179
     180static int fun_unbind(ddf_fun_t *fun, const char *name)
     181{
     182        int rc;
     183
     184        ddf_msg(LVL_DEBUG, "fun_unbind(%p, '%s')", fun, name);
    160185        rc = ddf_fun_unbind(fun);
    161186        if (rc != EOK) {
     
    184209
    185210        if (str_cmp(dev->name, "child") != 0) {
    186                 fid_t postpone = fibril_create(postponed_birth, test2);
     211                fid_t postpone = fibril_create(plug_unplug, test2);
    187212                if (postpone == 0) {
    188213                        ddf_msg(LVL_ERROR, "fibril_create() failed.");
     
    232257}
    233258
     259static int test2_dev_gone(ddf_dev_t *dev)
     260{
     261        test2_t *test2 = (test2_t *)dev->driver_data;
     262        int rc;
     263
     264        ddf_msg(LVL_DEBUG, "test2_dev_gone(%p)", dev);
     265
     266        if (test2->fun_a != NULL) {
     267                rc = fun_unbind(test2->fun_a, "a");
     268                if (rc != EOK)
     269                        return rc;
     270        }
     271
     272        if (test2->fun_err != NULL) {
     273                rc = fun_unbind(test2->fun_err, "ERROR");
     274                if (rc != EOK)
     275                        return rc;
     276        }
     277
     278        if (test2->child != NULL) {
     279                rc = fun_unbind(test2->child, "child");
     280                if (rc != EOK)
     281                        return rc;
     282        }
     283
     284        if (test2->test1 != NULL) {
     285                rc = fun_unbind(test2->test1, "test1");
     286                if (rc != EOK)
     287                        return rc;
     288        }
     289
     290        return EOK;
     291}
     292
    234293
    235294static int test2_fun_online(ddf_fun_t *fun)
     
    248307{
    249308        printf(NAME ": HelenOS test2 virtual device driver\n");
    250         ddf_log_init(NAME, LVL_ERROR);
     309        ddf_log_init(NAME, LVL_NOTE);
    251310        return ddf_driver_main(&test2_driver);
    252311}
  • uspace/lib/c/include/ipc/devman.h

    r16cc9a6 r80a96d2  
    147147        DRIVER_DEV_ADD = IPC_FIRST_USER_METHOD,
    148148        DRIVER_DEV_REMOVE,
     149        DRIVER_DEV_GONE,
    149150        DRIVER_FUN_ONLINE,
    150151        DRIVER_FUN_OFFLINE,
    151 
    152152} devman_to_driver_t;
    153153
  • uspace/lib/drv/generic/driver.c

    r16cc9a6 r80a96d2  
    333333}
    334334
     335static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
     336{
     337        devman_handle_t devh;
     338        ddf_dev_t *dev;
     339        int rc;
     340       
     341        devh = IPC_GET_ARG1(*icall);
     342       
     343        fibril_mutex_lock(&devices_mutex);
     344        dev = driver_get_device(devh);
     345        if (dev != NULL)
     346                dev_add_ref(dev);
     347        fibril_mutex_unlock(&devices_mutex);
     348       
     349        if (dev == NULL) {
     350                async_answer_0(iid, ENOENT);
     351                return;
     352        }
     353       
     354        if (driver->driver_ops->dev_gone != NULL)
     355                rc = driver->driver_ops->dev_gone(dev);
     356        else
     357                rc = ENOTSUP;
     358       
     359        if (rc == EOK)
     360                dev_del_ref(dev);
     361       
     362        async_answer_0(iid, (sysarg_t) rc);
     363}
     364
    335365static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    336366{
     
    423453                case DRIVER_DEV_REMOVE:
    424454                        driver_dev_remove(callid, &call);
     455                        break;
     456                case DRIVER_DEV_GONE:
     457                        driver_dev_gone(callid, &call);
    425458                        break;
    426459                case DRIVER_FUN_ONLINE:
  • uspace/lib/drv/include/ddf/driver.h

    r16cc9a6 r80a96d2  
    139139        /** Ask driver to remove a device */
    140140        int (*dev_remove)(ddf_dev_t *);
     141        /** Inform driver a device disappeared */
     142        int (*dev_gone)(ddf_dev_t *);
    141143        /** Ask driver to online a specific function */
    142144        int (*fun_online)(ddf_fun_t *);
  • uspace/srv/devman/devman.c

    r16cc9a6 r80a96d2  
    878878       
    879879        return retval;
    880 
     880}
     881
     882int driver_dev_gone(dev_tree_t *tree, dev_node_t *dev)
     883{
     884        async_exch_t *exch;
     885        sysarg_t retval;
     886        driver_t *drv;
     887        devman_handle_t handle;
     888       
     889        assert(dev != NULL);
     890       
     891        log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev);
     892       
     893        fibril_rwlock_read_lock(&tree->rwlock);
     894        drv = dev->drv;
     895        handle = dev->handle;
     896        fibril_rwlock_read_unlock(&tree->rwlock);
     897       
     898        exch = async_exchange_begin(drv->sess);
     899        retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle);
     900        async_exchange_end(exch);
     901       
     902        return retval;
    881903}
    882904
  • uspace/srv/devman/devman.h

    r16cc9a6 r80a96d2  
    263263extern bool start_driver(driver_t *);
    264264extern int driver_dev_remove(dev_tree_t *, dev_node_t *);
     265extern int driver_dev_gone(dev_tree_t *, dev_node_t *);
    265266extern int driver_fun_online(dev_tree_t *, fun_node_t *);
    266267extern int driver_fun_offline(dev_tree_t *, fun_node_t *);
  • uspace/srv/devman/main.c

    r16cc9a6 r80a96d2  
    316316                if (fun->child != NULL) {
    317317                        dev_node_t *dev = fun->child;
     318                        device_state_t dev_state;
    318319                       
    319320                        dev_add_ref(dev);
     321                        dev_state = dev->state;
     322                       
    320323                        fibril_rwlock_write_unlock(&device_tree.rwlock);
    321                        
     324
    322325                        /* If device is owned by driver, ask driver to give it up. */
    323                         if (dev->state == DEVICE_USABLE) {
     326                        if (dev_state == DEVICE_USABLE) {
    324327                                rc = driver_dev_remove(&device_tree, dev);
    325328                                if (rc != EOK) {
     
    333336                        if (!list_empty(&dev->functions)) {
    334337                                fibril_rwlock_read_unlock(&device_tree.rwlock);
     338                                dev_del_ref(dev);
    335339                                return EIO;
    336340                        }
     341                       
    337342                        driver_t *driver = dev->drv;
    338343                        fibril_rwlock_read_unlock(&device_tree.rwlock);
     
    579584        int rc;
    580585       
    581        
    582586        fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
    583587        if (fun == NULL) {
     
    598602       
    599603        if (fun->ftype == fun_inner) {
    600                 /* Handle possible descendants */
    601                 /* TODO - This is a surprise removal */
     604                /* This is a surprise removal. Handle possible descendants */
    602605                if (fun->child != NULL) {
    603                         log_msg(LVL_WARN, "devman_remove_function(): not handling "
    604                             "descendants\n");
     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);
    605653                }
    606654        } else {
Note: See TracChangeset for help on using the changeset viewer.