Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 1a5b252 in mainline


Ignore:
Timestamp:
2011-08-21T11:54:15Z (10 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master
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.

Location:
uspace
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/devctl/devctl.c

    re64df9a r1a5b252  
    3737#include <stdio.h>
    3838#include <stdlib.h>
     39#include <str_error.h>
    3940#include <sys/typefmt.h>
    4041
     
    4344#define MAX_NAME_LENGTH 1024
    4445
    45 static int fun_tree_print(devman_handle_t funh, int lvl)
     46static int fun_subtree_print(devman_handle_t funh, int lvl)
    4647{
    4748        char name[MAX_NAME_LENGTH];
     
    8485
    8586        for (i = 0; i < count; i++)
    86                 fun_tree_print(cfuns[i], lvl + 1);
     87                fun_subtree_print(cfuns[i], lvl + 1);
    8788
    8889        free(cfuns);
     
    9091}
    9192
    92 int main(int argc, char *argv[])
     93static int fun_tree_print(void)
    9394{
    9495        devman_handle_t root_fun;
     
    9899        if (rc != EOK) {
    99100                printf(NAME ": Error resolving root function.\n");
     101                return EIO;
     102        }
     103
     104        rc = fun_subtree_print(root_fun, 0);
     105        if (rc != EOK)
     106                return EIO;
     107
     108        return EOK;
     109}
     110
     111static int fun_online(const char *path)
     112{
     113        devman_handle_t funh;
     114        int rc;
     115
     116        rc = devman_fun_get_handle(path, &funh, 0);
     117        if (rc != EOK) {
     118                printf(NAME ": Error resolving device function '%s' (%s)\n",
     119                    path, str_error(rc));
     120                return rc;
     121        }
     122
     123        rc = devman_fun_online(funh);
     124        if (rc != EOK) {
     125                printf(NAME ": Failed to online function '%s'.\n", path);
     126                return rc;
     127        }
     128
     129        return EOK;
     130}
     131
     132static int fun_offline(const char *path)
     133{
     134        devman_handle_t funh;
     135        int rc;
     136
     137        rc = devman_fun_get_handle(path, &funh, 0);
     138        if (rc != EOK) {
     139                printf(NAME ": Error resolving device function '%s' (%s)\n",
     140                    path, str_error(rc));
     141                return rc;
     142        }
     143
     144        rc = devman_fun_offline(funh);
     145        if (rc != EOK) {
     146                printf(NAME ": Failed to offline function '%s'.\n", path);
     147                return rc;
     148        }
     149
     150        return EOK;
     151}
     152
     153static void print_syntax(void)
     154{
     155        printf("syntax: devctl [(online|offline) <function>]\n");
     156}
     157
     158int main(int argc, char *argv[])
     159{
     160        int rc;
     161
     162        if (argc == 1) {
     163                rc = fun_tree_print();
     164                if (rc != EOK)
     165                        return 2;
     166        } else if (str_cmp(argv[1], "online") == 0) {
     167                if (argc < 3) {
     168                        printf(NAME ": Argument missing.\n");
     169                        print_syntax();
     170                        return 1;
     171                }
     172
     173                rc = fun_online(argv[2]);
     174                if (rc != EOK) {
     175                        return 2;
     176                }
     177        } else if (str_cmp(argv[1], "offline") == 0) {
     178                if (argc < 3) {
     179                        printf(NAME ": Argument missing.\n");
     180                        print_syntax();
     181                        return 1;
     182                }
     183
     184                rc = fun_offline(argv[2]);
     185                if (rc != EOK) {
     186                        return 2;
     187                }
     188        } else {
     189                printf(NAME ": Invalid argument '%s'.\n", argv[1]);
     190                print_syntax();
    100191                return 1;
    101192        }
    102 
    103         rc = fun_tree_print(root_fun, 0);
    104         if (rc != EOK)
    105                 return 1;
    106193
    107194        return 0;
  • uspace/drv/infrastructure/rootvirt/rootvirt.c

    re64df9a r1a5b252  
    6363
    6464static int rootvirt_add_device(ddf_dev_t *dev);
     65static int rootvirt_fun_online(ddf_fun_t *fun);
     66static int rootvirt_fun_offline(ddf_fun_t *fun);
    6567
    6668static driver_ops_t rootvirt_ops = {
    67         .add_device = &rootvirt_add_device
     69        .add_device = &rootvirt_add_device,
     70        .fun_online = &rootvirt_fun_online,
     71        .fun_offline = &rootvirt_fun_offline
    6872};
    6973
     
    140144}
    141145
     146static int rootvirt_fun_online(ddf_fun_t *fun)
     147{
     148        ddf_msg(LVL_DEBUG, "rootvirt_fun_online()");
     149        return ddf_fun_online(fun);
     150}
     151
     152static int rootvirt_fun_offline(ddf_fun_t *fun)
     153{
     154        ddf_msg(LVL_DEBUG, "rootvirt_fun_offline()");
     155        return ddf_fun_offline(fun);
     156}
     157
    142158int main(int argc, char *argv[])
    143159{
  • uspace/drv/test/test1/test1.c

    re64df9a r1a5b252  
    11/*
    22 * Copyright (c) 2010 Vojtech Horky
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    4041
    4142static int test1_add_device(ddf_dev_t *dev);
     43static int test1_dev_remove(ddf_dev_t *dev);
     44static int test1_fun_online(ddf_fun_t *fun);
     45static int test1_fun_offline(ddf_fun_t *fun);
    4246
    4347static driver_ops_t driver_ops = {
    44         .add_device = &test1_add_device
     48        .add_device = &test1_add_device,
     49        .dev_remove = &test1_dev_remove,
     50        .fun_online = &test1_fun_online,
     51        .fun_offline = &test1_fun_offline
    4552};
    4653
     
    4956        .driver_ops = &driver_ops
    5057};
     58
     59typedef struct {
     60        ddf_fun_t *fun_a;
     61        ddf_fun_t *clone;
     62        ddf_fun_t *child;
     63} test1_t;
    5164
    5265/** Register child and inform user about it.
     
    6073static int register_fun_verbose(ddf_dev_t *parent, const char *message,
    6174    const char *name, const char *match_id, int match_score,
    62     int expected_rc)
     75    int expected_rc, ddf_fun_t **pfun)
    6376{
    6477        ddf_fun_t *fun = NULL;
     
    103116        }
    104117
     118        if (pfun != NULL)
     119                *pfun = fun;
     120
    105121        return rc;
    106122}
     
    126142{
    127143        ddf_fun_t *fun_a;
     144        test1_t *test1;
    128145        int rc;
    129146
    130147        ddf_msg(LVL_DEBUG, "add_device(name=\"%s\", handle=%d)",
    131148            dev->name, (int) dev->handle);
     149
     150        test1 = calloc(1, sizeof(test1_t));
     151        if (test1 == NULL) {
     152                ddf_msg(LVL_ERROR, "Failed allocating softstate.\n");
     153                return ENOMEM;
     154        }
    132155
    133156        fun_a = ddf_fun_create(dev, fun_exposed, "a");
     
    140163        if (rc != EOK) {
    141164                ddf_msg(LVL_ERROR, "Failed binding function 'a'.");
     165                ddf_fun_destroy(fun_a);
    142166                return rc;
    143167        }
     
    151175                (void) register_fun_verbose(dev,
    152176                    "cloning myself ;-)", "clone",
    153                     "virtual&test1", 10, EOK);
     177                    "virtual&test1", 10, EOK, &test1->clone);
    154178                (void) register_fun_verbose(dev,
    155179                    "cloning myself twice ;-)", "clone",
    156                     "virtual&test1", 10, EEXISTS);
     180                    "virtual&test1", 10, EEXISTS, NULL);
    157181        } else if (str_cmp(dev->name, "clone") == 0) {
    158182                (void) register_fun_verbose(dev,
    159183                    "run by the same task", "child",
    160                     "virtual&test1&child", 10, EOK);
     184                    "virtual&test1&child", 10, EOK, &test1->child);
    161185        }
    162186
    163187        ddf_msg(LVL_DEBUG, "Device `%s' accepted.", dev->name);
    164188
     189        test1->fun_a = fun_a;
     190        dev->driver_data = test1;
    165191        return EOK;
     192}
     193
     194static int fun_remove(ddf_fun_t *fun, const char *name)
     195{
     196        int rc;
     197
     198        ddf_msg(LVL_DEBUG, "fun_remove(%p, '%s')\n", fun, name);
     199        rc = ddf_fun_offline(fun);
     200        if (rc != EOK) {
     201                ddf_msg(LVL_ERROR, "Error offlining function '%s'.", name);
     202                return rc;
     203        }
     204
     205        rc = ddf_fun_unbind(fun);
     206        if (rc != EOK) {
     207                ddf_msg(LVL_ERROR, "Failed offlining function '%s'.", name);
     208                return rc;
     209        }
     210
     211        ddf_fun_destroy(fun);
     212        return EOK;
     213}
     214
     215static int test1_dev_remove(ddf_dev_t *dev)
     216{
     217        test1_t *test1 = (test1_t *)dev->driver_data;
     218        int rc;
     219
     220        ddf_msg(LVL_DEBUG, "test1_dev_remove(%p)", dev);
     221
     222        if (test1->fun_a != NULL) {
     223                rc = fun_remove(test1->fun_a, "a");
     224                if (rc != EOK)
     225                        return rc;
     226        }
     227
     228        if (test1->clone != NULL) {
     229                rc = fun_remove(test1->clone, "clone");
     230                if (rc != EOK)
     231                        return rc;
     232        }
     233
     234        if (test1->child != NULL) {
     235                rc = fun_remove(test1->child, "child");
     236                if (rc != EOK)
     237                        return rc;
     238        }
     239
     240        return EOK;
     241}
     242
     243static int test1_fun_online(ddf_fun_t *fun)
     244{
     245        ddf_msg(LVL_DEBUG, "test1_fun_online()");
     246        return ddf_fun_online(fun);
     247}
     248
     249static int test1_fun_offline(ddf_fun_t *fun)
     250{
     251        ddf_msg(LVL_DEBUG, "test1_fun_offline()");
     252        return ddf_fun_offline(fun);
    166253}
    167254
  • uspace/lib/c/generic/devman.c

    re64df9a r1a5b252  
    327327}
    328328
     329int devman_drv_fun_online(devman_handle_t funh)
     330{
     331        async_exch_t *exch = devman_exchange_begin(DEVMAN_DRIVER);
     332        if (exch == NULL)
     333                return ENOMEM;
     334       
     335        sysarg_t retval = async_req_1_0(exch, DEVMAN_DRV_FUN_ONLINE, funh);
     336       
     337        devman_exchange_end(exch);
     338        return (int) retval;
     339}
     340
     341int devman_drv_fun_offline(devman_handle_t funh)
     342{
     343        async_exch_t *exch = devman_exchange_begin(DEVMAN_DRIVER);
     344        if (exch == NULL)
     345                return ENOMEM;
     346       
     347        sysarg_t retval = async_req_1_0(exch, DEVMAN_DRV_FUN_OFFLINE, funh);
     348       
     349        devman_exchange_end(exch);
     350        return (int) retval;
     351}
     352
    329353async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt,
    330354    devman_handle_t handle, unsigned int flags)
     
    430454}
    431455
     456int devman_fun_online(devman_handle_t funh)
     457{
     458        async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
     459        if (exch == NULL)
     460                return ENOMEM;
     461       
     462        sysarg_t retval = async_req_1_0(exch, DEVMAN_FUN_ONLINE, funh);
     463       
     464        devman_exchange_end(exch);
     465        return (int) retval;
     466}
     467
     468int devman_fun_offline(devman_handle_t funh)
     469{
     470        async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
     471        if (exch == NULL)
     472                return ENOMEM;
     473       
     474        sysarg_t retval = async_req_1_0(exch, DEVMAN_FUN_OFFLINE, funh);
     475       
     476        devman_exchange_end(exch);
     477        return (int) retval;
     478}
     479
    432480static int devman_get_handles_once(sysarg_t method, sysarg_t arg1,
    433481    devman_handle_t *handle_buf, size_t buf_size, size_t *act_size)
  • uspace/lib/c/include/devman.h

    re64df9a r1a5b252  
    5050    devman_handle_t, devman_handle_t *);
    5151extern int devman_remove_function(devman_handle_t);
     52extern int devman_drv_fun_online(devman_handle_t);
     53extern int devman_drv_fun_offline(devman_handle_t);
    5254
    5355extern async_sess_t *devman_device_connect(exch_mgmt_t, devman_handle_t,
     
    6365extern int devman_fun_get_name(devman_handle_t, char *, size_t);
    6466extern int devman_fun_get_path(devman_handle_t, char *, size_t);
     67extern int devman_fun_online(devman_handle_t);
     68extern int devman_fun_offline(devman_handle_t);
    6569
    6670extern int devman_add_device_to_category(devman_handle_t, const char *);
  • uspace/lib/c/include/ipc/devman.h

    re64df9a r1a5b252  
    139139        DEVMAN_ADD_MATCH_ID,
    140140        DEVMAN_ADD_DEVICE_TO_CATEGORY,
     141        DEVMAN_DRV_FUN_ONLINE,
     142        DEVMAN_DRV_FUN_OFFLINE,
    141143        DEVMAN_REMOVE_FUNCTION
    142144} driver_to_devman_t;
    143145
    144146typedef enum {
    145         DRIVER_ADD_DEVICE = IPC_FIRST_USER_METHOD
     147        DRIVER_DEV_ADD = IPC_FIRST_USER_METHOD,
     148        DRIVER_DEV_REMOVE,
     149        DRIVER_FUN_ONLINE,
     150        DRIVER_FUN_OFFLINE,
    146151
    147152} devman_to_driver_t;
     
    152157        DEVMAN_FUN_GET_CHILD,
    153158        DEVMAN_FUN_GET_NAME,
     159        DEVMAN_FUN_ONLINE,
     160        DEVMAN_FUN_OFFLINE,
    154161        DEVMAN_FUN_GET_PATH,
    155162        DEVMAN_FUN_SID_TO_HANDLE
  • uspace/lib/drv/generic/driver.c

    re64df9a r1a5b252  
    6363
    6464/** Devices */
     65LIST_INITIALIZE(devices);
     66FIBRIL_MUTEX_INITIALIZE(devices_mutex);
     67
     68/** Functions */
    6569LIST_INITIALIZE(functions);
    6670FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     
    227231}
    228232
    229 static ddf_fun_t *driver_get_function(list_t *functions, devman_handle_t handle)
     233static ddf_dev_t *driver_get_device(devman_handle_t handle)
     234{
     235        ddf_dev_t *dev = NULL;
     236       
     237        assert(fibril_mutex_is_locked(&devices_mutex));
     238       
     239        list_foreach(devices, link) {
     240                dev = list_get_instance(link, ddf_dev_t, link);
     241                if (dev->handle == handle)
     242                        return dev;
     243        }
     244       
     245        return NULL;
     246}
     247
     248static ddf_fun_t *driver_get_function(devman_handle_t handle)
    230249{
    231250        ddf_fun_t *fun = NULL;
    232251       
    233         fibril_mutex_lock(&functions_mutex);
    234        
    235         list_foreach(*functions, link) {
     252        assert(fibril_mutex_is_locked(&functions_mutex));
     253       
     254        list_foreach(functions, link) {
    236255                fun = list_get_instance(link, ddf_fun_t, link);
    237                 if (fun->handle == handle) {
    238                         fibril_mutex_unlock(&functions_mutex);
     256                if (fun->handle == handle)
    239257                        return fun;
    240                 }
    241         }
    242        
    243         fibril_mutex_unlock(&functions_mutex);
     258        }
    244259       
    245260        return NULL;
     
    270285                delete_device(dev);
    271286       
     287        fibril_mutex_lock(&devices_mutex);
     288        list_append(&dev->link, &devices);
     289        fibril_mutex_unlock(&devices_mutex);
     290       
    272291        async_answer_0(iid, res);
     292}
     293
     294static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
     295{
     296        devman_handle_t devh;
     297        ddf_dev_t *dev;
     298        int rc;
     299       
     300        printf("libdrv: driver_dev_offline()\n");
     301        devh = IPC_GET_ARG1(*icall);
     302       
     303        fibril_mutex_lock(&devices_mutex);
     304        dev = driver_get_device(devh);
     305        fibril_mutex_unlock(&devices_mutex);
     306        /* XXX need lock on dev */
     307       
     308        if (dev == NULL) {
     309                async_answer_0(iid, ENOENT);
     310                return;
     311        }
     312       
     313        if (driver->driver_ops->dev_remove != NULL)
     314                rc = driver->driver_ops->dev_remove(dev);
     315        else
     316                rc = ENOTSUP;
     317       
     318        async_answer_0(iid, (sysarg_t) rc);
     319}
     320
     321static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     322{
     323        devman_handle_t funh;
     324        ddf_fun_t *fun;
     325        int rc;
     326       
     327        funh = IPC_GET_ARG1(*icall);
     328        fibril_mutex_lock(&functions_mutex);
     329        fun = driver_get_function(funh);
     330        fibril_mutex_unlock(&functions_mutex);
     331        /* XXX Need lock on fun */
     332       
     333        if (fun == NULL) {
     334                async_answer_0(iid, ENOENT);
     335                return;
     336        }
     337       
     338        if (driver->driver_ops->fun_online != NULL)
     339                rc = driver->driver_ops->fun_online(fun);
     340        else
     341                rc = ENOTSUP;
     342       
     343        async_answer_0(iid, (sysarg_t) rc);
     344}
     345
     346static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     347{
     348        devman_handle_t funh;
     349        ddf_fun_t *fun;
     350        int rc;
     351       
     352        funh = IPC_GET_ARG1(*icall);
     353        fibril_mutex_lock(&functions_mutex);
     354        fun = driver_get_function(funh);
     355        fibril_mutex_unlock(&functions_mutex);
     356        /* XXX Need lock on fun */
     357       
     358        if (fun == NULL) {
     359                async_answer_0(iid, ENOENT);
     360                return;
     361        }
     362       
     363        if (driver->driver_ops->fun_offline != NULL)
     364                rc = driver->driver_ops->fun_offline(fun);
     365        else
     366                rc = ENOTSUP;
     367       
     368        async_answer_0(iid, (sysarg_t) rc);
    273369}
    274370
     
    286382               
    287383                switch (IPC_GET_IMETHOD(call)) {
    288                 case DRIVER_ADD_DEVICE:
     384                case DRIVER_DEV_ADD:
    289385                        driver_add_device(callid, &call);
    290386                        break;
     387                case DRIVER_DEV_REMOVE:
     388                        driver_dev_remove(callid, &call);
     389                        break;
     390                case DRIVER_FUN_ONLINE:
     391                        driver_fun_online(callid, &call);
     392                        break;
     393                case DRIVER_FUN_OFFLINE:
     394                        driver_fun_offline(callid, &call);
     395                        break;
    291396                default:
    292                         async_answer_0(callid, ENOENT);
     397                        async_answer_0(callid, ENOTSUP);
    293398                }
    294399        }
     
    308413         */
    309414        devman_handle_t handle = IPC_GET_ARG2(*icall);
    310         ddf_fun_t *fun = driver_get_function(&functions, handle);
     415
     416        fibril_mutex_lock(&functions_mutex);
     417        ddf_fun_t *fun = driver_get_function(handle);
     418        fibril_mutex_unlock(&functions_mutex);
     419        /* XXX Need a lock on fun */
    311420       
    312421        if (fun == NULL) {
     
    614723 * the function invisible to the system.
    615724 *
    616  * @param fun           Function to bind
     725 * @param fun           Function to unbind
    617726 * @return              EOK on success or negative error code
    618727 */
     
    623732        assert(fun->bound == true);
    624733       
    625         add_to_functions_list(fun);
    626734        res = devman_remove_function(fun->handle);
    627735        if (res != EOK)
     
    631739       
    632740        fun->bound = false;
     741        return EOK;
     742}
     743
     744/** Online function.
     745 *
     746 * @param fun           Function to online
     747 * @return              EOK on success or negative error code
     748 */
     749int ddf_fun_online(ddf_fun_t *fun)
     750{
     751        int res;
     752       
     753        assert(fun->bound == true);
     754       
     755        res = devman_drv_fun_online(fun->handle);
     756        if (res != EOK)
     757                return res;
     758       
     759        return EOK;
     760}
     761
     762/** Offline function.
     763 *
     764 * @param fun           Function to offline
     765 * @return              EOK on success or negative error code
     766 */
     767int ddf_fun_offline(ddf_fun_t *fun)
     768{
     769        int res;
     770       
     771        assert(fun->bound == true);
     772       
     773        res = devman_drv_fun_offline(fun->handle);
     774        if (res != EOK)
     775                return res;
     776       
    633777        return EOK;
    634778}
  • uspace/lib/drv/include/ddf/driver.h

    re64df9a r1a5b252  
    132132typedef struct driver_ops {
    133133        /** Callback method for passing a new device to the device driver */
    134         int (*add_device)(ddf_dev_t *dev);
    135         /* TODO: add other generic driver operations */
     134        int (*add_device)(ddf_dev_t *);
     135        /** Ask driver to remove a device */
     136        int (*dev_remove)(ddf_dev_t *);
     137        /** Ask driver to online a specific function */
     138        int (*fun_online)(ddf_fun_t *);
     139        /** Ask driver to offline a specific function */
     140        int (*fun_offline)(ddf_fun_t *);
    136141} driver_ops_t;
    137142
     
    150155extern int ddf_fun_bind(ddf_fun_t *);
    151156extern int ddf_fun_unbind(ddf_fun_t *);
     157extern int ddf_fun_online(ddf_fun_t *);
     158extern int ddf_fun_offline(ddf_fun_t *);
    152159extern int ddf_fun_add_match_id(ddf_fun_t *, const char *, int);
    153160
  • uspace/srv/devman/devman.c

    re64df9a r1a5b252  
    483483}
    484484
     485/** Detach driver from device.
     486 *
     487 * @param node          The device's node in the device tree.
     488 * @param drv           The driver.
     489 */
     490void detach_driver(dev_node_t *dev)
     491{
     492        /* XXX need lock on dev */
     493        driver_t *drv = dev->drv;
     494       
     495        assert(drv != NULL);
     496        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
     497            dev->pfun->pathname, drv->name);
     498       
     499        fibril_mutex_lock(&drv->driver_mutex);
     500       
     501        dev->drv = NULL;
     502        list_remove(&dev->driver_devices);
     503       
     504        fibril_mutex_unlock(&drv->driver_mutex);
     505}
     506
    485507/** Start a driver
    486508 *
     
    726748       
    727749        ipc_call_t answer;
    728         aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
     750        aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
    729751            parent_handle, &answer);
    730752       
     
    800822}
    801823
     824int driver_dev_remove(dev_node_t *dev)
     825{
     826        async_exch_t *exch;
     827        sysarg_t retval;
     828        driver_t *drv;
     829       
     830        assert(dev != NULL);
     831        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
     832        drv = dev->drv;
     833       
     834        exch = async_exchange_begin(drv->sess);
     835        retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, dev->handle);
     836        async_exchange_end(exch);
     837       
     838        return retval;
     839
     840}
     841
     842int driver_fun_online(fun_node_t *fun)
     843{
     844        async_exch_t *exch;
     845        sysarg_t retval;
     846        driver_t *drv;
     847       
     848        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
     849        if (fun->dev == NULL) {
     850                /* XXX root function? */
     851                return EINVAL;
     852        }
     853       
     854        drv = fun->dev->drv;
     855       
     856        exch = async_exchange_begin(drv->sess);
     857        retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, fun->handle);
     858        loc_exchange_end(exch);
     859       
     860        return retval;
     861}
     862
     863int driver_fun_offline(fun_node_t *fun)
     864{
     865        async_exch_t *exch;
     866        sysarg_t retval;
     867        driver_t *drv;
     868       
     869        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
     870        if (fun->dev == NULL) {
     871                /* XXX root function? */
     872                return EINVAL;
     873        }
     874       
     875        drv = fun->dev->drv;
     876       
     877        exch = async_exchange_begin(drv->sess);
     878        retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, fun->handle);
     879        loc_exchange_end(exch);
     880       
     881        return retval;
     882
     883}
     884
    802885/** Initialize the device tree.
    803886 *
     
    10651148}
    10661149
     1150/** Remove device from device tree.
     1151 *
     1152 * @param tree          Device tree
     1153 * @param dev           Device node
     1154 */
     1155void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
     1156{
     1157        assert(tree != NULL);
     1158        assert(dev != NULL);
     1159        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1160       
     1161        log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
     1162       
     1163        /* Remove node from the handle-to-node map. */
     1164        unsigned long key = dev->handle;
     1165        hash_table_remove(&tree->devman_devices, &key, 1);
     1166       
     1167        /* Unlink from parent function. */
     1168        dev->pfun->child = NULL;
     1169        dev->pfun = NULL;
     1170}
     1171
     1172
    10671173/** Insert new function into device tree.
    10681174 *
     
    11271233        if (fun->dev != NULL)
    11281234                list_remove(&fun->dev_functions);
     1235       
     1236        fun->dev = NULL;
    11291237}
    11301238
  • uspace/srv/devman/devman.h

    re64df9a r1a5b252  
    240240extern void add_driver(driver_list_t *, driver_t *);
    241241extern void attach_driver(dev_node_t *, driver_t *);
     242extern void detach_driver(dev_node_t *);
    242243extern void add_device(driver_t *, dev_node_t *, dev_tree_t *);
    243244extern bool start_driver(driver_t *);
     245extern int driver_dev_remove(dev_node_t *);
     246extern int driver_fun_online(fun_node_t *);
     247extern int driver_fun_offline(fun_node_t *);
    244248
    245249extern driver_t *find_driver(driver_list_t *, const char *);
     
    274278extern bool create_root_nodes(dev_tree_t *);
    275279extern bool insert_dev_node(dev_tree_t *, dev_node_t *, fun_node_t *);
     280extern void remove_dev_node(dev_tree_t *, dev_node_t *);
    276281extern bool insert_fun_node(dev_tree_t *, fun_node_t *, char *, dev_node_t *);
    277282extern void remove_fun_node(dev_tree_t *, fun_node_t *);
  • 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.