Ignore:
File:
1 edited

Legend:

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

    rb72efe8 r80a96d2  
    3030 * @{
    3131 */
     32/** @file Device Manager
     33 *
     34 * Locking order:
     35 *   (1) driver_t.driver_mutex
     36 *   (2) dev_tree_t.rwlock
     37 *
     38 * Synchronization:
     39 *    - device_tree.rwlock protects:
     40 *        - tree root, complete tree topology
     41 *        - complete contents of device and function nodes
     42 *    - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from
     43 *      being deallocated
     44 *    - find_xxx() functions increase reference count of returned object
     45 *    - find_xxx_no_lock() do not increase reference count
     46 *
     47 * TODO
     48 *    - Track all steady and transient device/function states
     49 *    - Check states, wait for steady state on certain operations
     50 */
    3251
    3352#include <errno.h>
     
    3756#include <ipc/driver.h>
    3857#include <ipc/devman.h>
    39 #include <devmap.h>
     58#include <loc.h>
    4059#include <str_error.h>
    4160#include <stdio.h>
     
    4362#include "devman.h"
    4463
    45 fun_node_t *find_node_child(fun_node_t *parent, const char *name);
     64static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
    4665
    4766/* hash table operations */
     
    6685}
    6786
    68 static int devmap_functions_compare(unsigned long key[], hash_count_t keys,
     87static int loc_functions_compare(unsigned long key[], hash_count_t keys,
    6988    link_t *item)
    7089{
    71         fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devmap_fun);
    72         return (fun->devmap_handle == (devmap_handle_t) key[0]);
    73 }
    74 
    75 static int devmap_devices_class_compare(unsigned long key[], hash_count_t keys,
    76     link_t *item)
    77 {
    78         dev_class_info_t *class_info
    79             = hash_table_get_instance(item, dev_class_info_t, devmap_link);
    80         assert(class_info != NULL);
    81 
    82         return (class_info->devmap_handle == (devmap_handle_t) key[0]);
     90        fun_node_t *fun = hash_table_get_instance(item, fun_node_t, loc_fun);
     91        return (fun->service_id == (service_id_t) key[0]);
    8392}
    8493
     
    99108};
    100109
    101 static hash_table_operations_t devmap_devices_ops = {
     110static hash_table_operations_t loc_devices_ops = {
    102111        .hash = devices_hash,
    103         .compare = devmap_functions_compare,
    104         .remove_callback = devices_remove_callback
    105 };
    106 
    107 static hash_table_operations_t devmap_devices_class_ops = {
    108         .hash = devices_hash,
    109         .compare = devmap_devices_class_compare,
     112        .compare = loc_functions_compare,
    110113        .remove_callback = devices_remove_callback
    111114};
     
    270273        }
    271274       
    272         ssize_t read_bytes = safe_read(fd, buf, len);
     275        ssize_t read_bytes = read_all(fd, buf, len);
    273276        if (read_bytes <= 0) {
    274                 log_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
     277                log_msg(LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
     278                    read_bytes);
    275279                goto cleanup;
    276280        }
     
    421425        }
    422426       
    423         insert_fun_node(tree, fun, clone_string(""), NULL);
     427        fun_add_ref(fun);
     428        insert_fun_node(tree, fun, str_dup(""), NULL);
     429       
    424430        match_id_t *id = create_match_id();
    425         id->id = clone_string("root");
     431        id->id = str_dup("root");
    426432        id->score = 100;
    427433        add_match_id(&fun->match_ids, id);
     
    437443        }
    438444       
     445        dev_add_ref(dev);
    439446        insert_dev_node(tree, dev, fun);
    440447       
     
    482489/** Assign a driver to a device.
    483490 *
     491 * @param tree          Device tree
    484492 * @param node          The device's node in the device tree.
    485493 * @param drv           The driver.
    486494 */
    487 void attach_driver(dev_node_t *dev, driver_t *drv)
     495void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
    488496{
    489497        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    491499       
    492500        fibril_mutex_lock(&drv->driver_mutex);
     501        fibril_rwlock_write_lock(&tree->rwlock);
    493502       
    494503        dev->drv = drv;
    495504        list_append(&dev->driver_devices, &drv->devices);
    496505       
     506        fibril_rwlock_write_unlock(&tree->rwlock);
     507        fibril_mutex_unlock(&drv->driver_mutex);
     508}
     509
     510/** Detach driver from device.
     511 *
     512 * @param tree          Device tree
     513 * @param node          The device's node in the device tree.
     514 * @param drv           The driver.
     515 */
     516void detach_driver(dev_tree_t *tree, dev_node_t *dev)
     517{
     518        driver_t *drv = dev->drv;
     519       
     520        assert(drv != NULL);
     521       
     522        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
     523            dev->pfun->pathname, drv->name);
     524       
     525        fibril_mutex_lock(&drv->driver_mutex);
     526        fibril_rwlock_write_lock(&tree->rwlock);
     527       
     528        dev->drv = NULL;
     529        list_remove(&dev->driver_devices);
     530       
     531        fibril_rwlock_write_unlock(&tree->rwlock);
    497532        fibril_mutex_unlock(&drv->driver_mutex);
    498533}
     
    563598
    564599        fibril_mutex_lock(&driver->driver_mutex);
    565        
    566         async_exch_t *exch = async_exchange_begin(driver->sess);
    567         async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
    568             DRIVER_DEVMAN, 0, 0);
    569         async_exchange_end(exch);
    570 
    571         if (!sess) {
    572                 fibril_mutex_unlock(&driver->driver_mutex);
    573                 return;
    574         }
    575600
    576601        /*
     
    581606        while (link != &driver->devices.head) {
    582607                dev = list_get_instance(link, dev_node_t, driver_devices);
     608                fibril_rwlock_write_lock(&tree->rwlock);
     609               
    583610                if (dev->passed_to_driver) {
     611                        fibril_rwlock_write_unlock(&tree->rwlock);
    584612                        link = link->next;
    585613                        continue;
    586614                }
    587615
    588                 /*
    589                  * We remove the device from the list to allow safe adding
    590                  * of new devices (no one will touch our item this way).
    591                  */
    592                 list_remove(link);
     616                log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
     617                    (int)atomic_get(&dev->refcnt));
     618                dev_add_ref(dev);
    593619
    594620                /*
     
    597623                 */
    598624                fibril_mutex_unlock(&driver->driver_mutex);
    599 
    600                 add_device(sess, driver, dev, tree);
     625                fibril_rwlock_write_unlock(&tree->rwlock);
     626
     627                add_device(driver, dev, tree);
     628
     629                dev_del_ref(dev);
    601630
    602631                /*
     
    607636
    608637                /*
    609                  * Insert the device back.
    610                  * The order is not relevant here so no harm is done
    611                  * (actually, the order would be preserved in most cases).
    612                  */
    613                 list_append(link, &driver->devices);
    614 
    615                 /*
    616638                 * Restart the cycle to go through all devices again.
    617639                 */
    618640                link = driver->devices.head.next;
    619641        }
    620 
    621         async_hangup(sess);
    622642
    623643        /*
     
    700720}
    701721
    702 /** Create devmap path and name for the function. */
    703 void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
    704 {
    705         char *devmap_pathname = NULL;
    706         char *devmap_name = NULL;
    707        
    708         asprintf(&devmap_name, "%s", fun->pathname);
    709         if (devmap_name == NULL)
     722/** Create loc path and name for the function. */
     723void loc_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
     724{
     725        char *loc_pathname = NULL;
     726        char *loc_name = NULL;
     727       
     728        assert(fibril_rwlock_is_locked(&tree->rwlock));
     729       
     730        asprintf(&loc_name, "%s", fun->pathname);
     731        if (loc_name == NULL)
    710732                return;
    711733       
    712         replace_char(devmap_name, '/', DEVMAP_SEPARATOR);
    713        
    714         asprintf(&devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,
    715             devmap_name);
    716         if (devmap_pathname == NULL) {
    717                 free(devmap_name);
     734        replace_char(loc_name, '/', LOC_SEPARATOR);
     735       
     736        asprintf(&loc_pathname, "%s/%s", LOC_DEVICE_NAMESPACE,
     737            loc_name);
     738        if (loc_pathname == NULL) {
     739                free(loc_name);
    718740                return;
    719741        }
    720742       
    721         devmap_device_register_with_iface(devmap_pathname,
    722             &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
    723        
    724         tree_add_devmap_function(tree, fun);
    725        
    726         free(devmap_name);
    727         free(devmap_pathname);
     743        loc_service_register_with_iface(loc_pathname,
     744            &fun->service_id, DEVMAN_CONNECT_FROM_LOC);
     745       
     746        tree_add_loc_function(tree, fun);
     747       
     748        free(loc_name);
     749        free(loc_pathname);
    728750}
    729751
     
    733755 * @param node          The device's node in the device tree.
    734756 */
    735 void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev,
    736     dev_tree_t *tree)
     757void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
    737758{
    738759        /*
     
    751772        }
    752773       
    753         async_exch_t *exch = async_exchange_begin(sess);
     774        async_exch_t *exch = async_exchange_begin(drv->sess);
    754775       
    755776        ipc_call_t answer;
    756         aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
     777        aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
    757778            parent_handle, &answer);
    758779       
     
    811832       
    812833        /* Attach the driver to the device. */
    813         attach_driver(dev, drv);
     834        attach_driver(tree, dev, drv);
    814835       
    815836        fibril_mutex_lock(&drv->driver_mutex);
     
    821842        fibril_mutex_unlock(&drv->driver_mutex);
    822843
    823         if (is_running) {
    824                 /* Notify the driver about the new device. */
    825                 async_exch_t *exch = async_exchange_begin(drv->sess);
    826                 async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
    827                     DRIVER_DEVMAN, 0, 0);
    828                 async_exchange_end(exch);
    829                
    830                 if (sess) {
    831                         add_device(sess, drv, dev, tree);
    832                         async_hangup(sess);
    833                 }
    834         }
    835        
     844        /* Notify the driver about the new device. */
     845        if (is_running)
     846                add_device(drv, dev, tree);
     847       
     848        fibril_mutex_lock(&drv->driver_mutex);
     849        fibril_mutex_unlock(&drv->driver_mutex);
     850
     851        fibril_rwlock_write_lock(&tree->rwlock);
     852        if (dev->pfun != NULL) {
     853                dev->pfun->state = FUN_ON_LINE;
     854        }
     855        fibril_rwlock_write_unlock(&tree->rwlock);
    836856        return true;
     857}
     858
     859int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
     860{
     861        async_exch_t *exch;
     862        sysarg_t retval;
     863        driver_t *drv;
     864        devman_handle_t handle;
     865       
     866        assert(dev != NULL);
     867       
     868        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
     869       
     870        fibril_rwlock_read_lock(&tree->rwlock);
     871        drv = dev->drv;
     872        handle = dev->handle;
     873        fibril_rwlock_read_unlock(&tree->rwlock);
     874       
     875        exch = async_exchange_begin(drv->sess);
     876        retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
     877        async_exchange_end(exch);
     878       
     879        return retval;
     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;
     903}
     904
     905int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
     906{
     907        async_exch_t *exch;
     908        sysarg_t retval;
     909        driver_t *drv;
     910        devman_handle_t handle;
     911       
     912        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
     913
     914        fibril_rwlock_read_lock(&tree->rwlock);
     915       
     916        if (fun->dev == NULL) {
     917                /* XXX root function? */
     918                fibril_rwlock_read_unlock(&tree->rwlock);
     919                return EINVAL;
     920        }
     921       
     922        drv = fun->dev->drv;
     923        handle = fun->handle;
     924        fibril_rwlock_read_unlock(&tree->rwlock);
     925       
     926        exch = async_exchange_begin(drv->sess);
     927        retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
     928        loc_exchange_end(exch);
     929       
     930        return retval;
     931}
     932
     933int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
     934{
     935        async_exch_t *exch;
     936        sysarg_t retval;
     937        driver_t *drv;
     938        devman_handle_t handle;
     939       
     940        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
     941
     942        fibril_rwlock_read_lock(&tree->rwlock);
     943        if (fun->dev == NULL) {
     944                /* XXX root function? */
     945                fibril_rwlock_read_unlock(&tree->rwlock);
     946                return EINVAL;
     947        }
     948       
     949        drv = fun->dev->drv;
     950        handle = fun->handle;
     951        fibril_rwlock_read_unlock(&tree->rwlock);
     952       
     953        exch = async_exchange_begin(drv->sess);
     954        retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
     955        loc_exchange_end(exch);
     956       
     957        return retval;
     958
    837959}
    838960
     
    855977        hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
    856978            &devman_functions_ops);
    857         hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
    858             &devmap_devices_ops);
     979        hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
     980            &loc_devices_ops);
    859981       
    860982        fibril_rwlock_initialize(&tree->rwlock);
     
    863985        if (!create_root_nodes(tree))
    864986                return false;
    865 
     987   
    866988        /* Find suitable driver and start it. */
    867         return assign_driver(tree->root_node->child, drivers_list, tree);
     989        dev_node_t *rdev = tree->root_node->child;
     990        dev_add_ref(rdev);
     991        int rc = assign_driver(rdev, drivers_list, tree);
     992        dev_del_ref(rdev);
     993       
     994        return rc;
    868995}
    869996
     
    8761003dev_node_t *create_dev_node(void)
    8771004{
    878         dev_node_t *res = malloc(sizeof(dev_node_t));
    879        
    880         if (res != NULL) {
    881                 memset(res, 0, sizeof(dev_node_t));
    882                 list_initialize(&res->functions);
    883                 link_initialize(&res->driver_devices);
    884                 link_initialize(&res->devman_dev);
    885         }
    886        
    887         return res;
     1005        dev_node_t *dev;
     1006       
     1007        dev = calloc(1, sizeof(dev_node_t));
     1008        if (dev == NULL)
     1009                return NULL;
     1010       
     1011        atomic_set(&dev->refcnt, 0);
     1012        list_initialize(&dev->functions);
     1013        link_initialize(&dev->driver_devices);
     1014        link_initialize(&dev->devman_dev);
     1015       
     1016        return dev;
    8881017}
    8891018
     
    9011030}
    9021031
     1032/** Increase device node reference count.
     1033 *
     1034 * @param dev   Device node
     1035 */
     1036void dev_add_ref(dev_node_t *dev)
     1037{
     1038        atomic_inc(&dev->refcnt);
     1039}
     1040
     1041/** Decrease device node reference count.
     1042 *
     1043 * When the count drops to zero the device node is freed.
     1044 *
     1045 * @param dev   Device node
     1046 */
     1047void dev_del_ref(dev_node_t *dev)
     1048{
     1049        if (atomic_predec(&dev->refcnt) == 0)
     1050                delete_dev_node(dev);
     1051}
     1052
     1053
    9031054/** Find the device node structure of the device witch has the specified handle.
    9041055 *
     
    9301081        fibril_rwlock_read_lock(&tree->rwlock);
    9311082        dev = find_dev_node_no_lock(tree, handle);
     1083        if (dev != NULL)
     1084                dev_add_ref(dev);
     1085       
    9321086        fibril_rwlock_read_unlock(&tree->rwlock);
    9331087       
     
    9351089}
    9361090
     1091/** Get list of device functions. */
     1092int dev_get_functions(dev_tree_t *tree, dev_node_t *dev,
     1093    devman_handle_t *hdl_buf, size_t buf_size, size_t *act_size)
     1094{
     1095        size_t act_cnt;
     1096        size_t buf_cnt;
     1097
     1098        assert(fibril_rwlock_is_locked(&tree->rwlock));
     1099
     1100        buf_cnt = buf_size / sizeof(devman_handle_t);
     1101
     1102        act_cnt = list_count(&dev->functions);
     1103        *act_size = act_cnt * sizeof(devman_handle_t);
     1104
     1105        if (buf_size % sizeof(devman_handle_t) != 0)
     1106                return EINVAL;
     1107
     1108        size_t pos = 0;
     1109        list_foreach(dev->functions, item) {
     1110                fun_node_t *fun =
     1111                    list_get_instance(item, fun_node_t, dev_functions);
     1112
     1113                if (pos < buf_cnt) {
     1114                        hdl_buf[pos] = fun->handle;
     1115                }
     1116
     1117                pos++;
     1118        }
     1119
     1120        return EOK;
     1121}
     1122
     1123
    9371124/* Function nodes */
    9381125
     
    9431130fun_node_t *create_fun_node(void)
    9441131{
    945         fun_node_t *res = malloc(sizeof(fun_node_t));
    946        
    947         if (res != NULL) {
    948                 memset(res, 0, sizeof(fun_node_t));
    949                 link_initialize(&res->dev_functions);
    950                 list_initialize(&res->match_ids.ids);
    951                 list_initialize(&res->classes);
    952                 link_initialize(&res->devman_fun);
    953                 link_initialize(&res->devmap_fun);
    954         }
    955        
    956         return res;
     1132        fun_node_t *fun;
     1133
     1134        fun = calloc(1, sizeof(fun_node_t));
     1135        if (fun == NULL)
     1136                return NULL;
     1137       
     1138        fun->state = FUN_INIT;
     1139        atomic_set(&fun->refcnt, 0);
     1140        link_initialize(&fun->dev_functions);
     1141        list_initialize(&fun->match_ids.ids);
     1142        link_initialize(&fun->devman_fun);
     1143        link_initialize(&fun->loc_fun);
     1144       
     1145        return fun;
    9571146}
    9581147
     
    9721161}
    9731162
     1163/** Increase function node reference count.
     1164 *
     1165 * @param fun   Function node
     1166 */
     1167void fun_add_ref(fun_node_t *fun)
     1168{
     1169        atomic_inc(&fun->refcnt);
     1170}
     1171
     1172/** Decrease function node reference count.
     1173 *
     1174 * When the count drops to zero the function node is freed.
     1175 *
     1176 * @param fun   Function node
     1177 */
     1178void fun_del_ref(fun_node_t *fun)
     1179{
     1180        if (atomic_predec(&fun->refcnt) == 0)
     1181                delete_fun_node(fun);
     1182}
     1183
    9741184/** Find the function node with the specified handle.
    9751185 *
     
    9821192        unsigned long key = handle;
    9831193        link_t *link;
     1194        fun_node_t *fun;
    9841195       
    9851196        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    9891200                return NULL;
    9901201       
    991         return hash_table_get_instance(link, fun_node_t, devman_fun);
     1202        fun = hash_table_get_instance(link, fun_node_t, devman_fun);
     1203       
     1204        return fun;
    9921205}
    9931206
     
    10031216       
    10041217        fibril_rwlock_read_lock(&tree->rwlock);
     1218       
    10051219        fun = find_fun_node_no_lock(tree, handle);
     1220        if (fun != NULL)
     1221                fun_add_ref(fun);
     1222       
    10061223        fibril_rwlock_read_unlock(&tree->rwlock);
    10071224       
     
    10111228/** Create and set device's full path in device tree.
    10121229 *
     1230 * @param tree          Device tree
    10131231 * @param node          The device's device node.
    10141232 * @param parent        The parent device node.
     
    10161234 *                      resources etc.).
    10171235 */
    1018 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
    1019 {
     1236static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
     1237{
     1238        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10201239        assert(fun->name != NULL);
    10211240       
     
    10441263 *
    10451264 * @param tree          The device tree.
    1046  * @param node          The newly added device node.
    1047  * @param dev_name      The name of the newly added device.
    1048  * @param parent        The parent device node.
     1265 * @param dev           The newly added device node.
     1266 * @param pfun          The parent function node.
    10491267 *
    10501268 * @return              True on success, false otherwise (insufficient resources
     
    10531271bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    10541272{
    1055         assert(dev != NULL);
    1056         assert(tree != NULL);
    10571273        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10581274       
     
    10721288}
    10731289
     1290/** Remove device from device tree.
     1291 *
     1292 * @param tree          Device tree
     1293 * @param dev           Device node
     1294 */
     1295void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
     1296{
     1297        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1298       
     1299        log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
     1300       
     1301        /* Remove node from the handle-to-node map. */
     1302        unsigned long key = dev->handle;
     1303        hash_table_remove(&tree->devman_devices, &key, 1);
     1304       
     1305        /* Unlink from parent function. */
     1306        dev->pfun->child = NULL;
     1307        dev->pfun = NULL;
     1308       
     1309        dev->state = DEVICE_REMOVED;
     1310}
     1311
     1312
    10741313/** Insert new function into device tree.
    10751314 *
    10761315 * @param tree          The device tree.
    1077  * @param node          The newly added function node.
    1078  * @param dev_name      The name of the newly added function.
    1079  * @param parent        Owning device node.
     1316 * @param fun           The newly added function node.
     1317 * @param fun_name      The name of the newly added function.
     1318 * @param dev           Owning device node.
    10801319 *
    10811320 * @return              True on success, false otherwise (insufficient resources
     
    10871326        fun_node_t *pfun;
    10881327       
    1089         assert(fun != NULL);
    1090         assert(tree != NULL);
    10911328        assert(fun_name != NULL);
    10921329        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    10991336       
    11001337        fun->name = fun_name;
    1101         if (!set_fun_path(fun, pfun)) {
     1338        if (!set_fun_path(tree, fun, pfun)) {
    11021339                return false;
    11031340        }
     
    11141351       
    11151352        return true;
     1353}
     1354
     1355/** Remove function from device tree.
     1356 *
     1357 * @param tree          Device tree
     1358 * @param node          Function node to remove
     1359 */
     1360void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
     1361{
     1362        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1363       
     1364        /* Remove the node from the handle-to-node map. */
     1365        unsigned long key = fun->handle;
     1366        hash_table_remove(&tree->devman_functions, &key, 1);
     1367       
     1368        /* Remove the node from the list of its parent's children. */
     1369        if (fun->dev != NULL)
     1370                list_remove(&fun->dev_functions);
     1371       
     1372        fun->dev = NULL;
     1373        fun->state = FUN_REMOVED;
    11161374}
    11171375
     
    11351393       
    11361394        fun_node_t *fun = tree->root_node;
     1395        fun_add_ref(fun);
    11371396        /*
    11381397         * Relative path to the function from its parent (but with '/' at the
     
    11411400        char *rel_path = path;
    11421401        char *next_path_elem = NULL;
    1143         bool cont = true;
     1402        bool cont = (rel_path[1] != '\0');
    11441403       
    11451404        while (cont && fun != NULL) {
     
    11521411                }
    11531412               
    1154                 fun = find_node_child(fun, rel_path + 1);
     1413                fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
     1414                fun_del_ref(fun);
     1415                fun = cfun;
    11551416               
    11561417                if (cont) {
     
    11701431 * Device tree rwlock should be held at least for reading.
    11711432 *
     1433 * @param tree Device tree
    11721434 * @param dev Device the function belongs to.
    11731435 * @param name Function name (not path).
     
    11751437 * @retval NULL No function with given name.
    11761438 */
    1177 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
    1178 {
    1179         assert(dev != NULL);
     1439fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
     1440    const char *name)
     1441{
    11801442        assert(name != NULL);
     1443        assert(fibril_rwlock_is_locked(&tree->rwlock));
    11811444
    11821445        fun_node_t *fun;
     
    11851448                fun = list_get_instance(link, fun_node_t, dev_functions);
    11861449
    1187                 if (str_cmp(name, fun->name) == 0)
     1450                if (str_cmp(name, fun->name) == 0) {
     1451                        fun_add_ref(fun);
    11881452                        return fun;
     1453                }
    11891454        }
    11901455
     
    11921457}
    11931458
    1194 /** Find function node by its class name and index. */
    1195 fun_node_t *find_fun_node_by_class(class_list_t *class_list,
    1196     const char *class_name, const char *dev_name)
    1197 {
    1198         assert(class_list != NULL);
    1199         assert(class_name != NULL);
    1200         assert(dev_name != NULL);
    1201 
    1202         fibril_rwlock_read_lock(&class_list->rwlock);
    1203 
    1204         dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);
    1205         if (cl == NULL) {
    1206                 fibril_rwlock_read_unlock(&class_list->rwlock);
    1207                 return NULL;
    1208         }
    1209 
    1210         dev_class_info_t *dev = find_dev_in_class(cl, dev_name);
    1211         if (dev == NULL) {
    1212                 fibril_rwlock_read_unlock(&class_list->rwlock);
    1213                 return NULL;
    1214         }
    1215 
    1216         fun_node_t *fun = dev->fun;
    1217 
    1218         fibril_rwlock_read_unlock(&class_list->rwlock);
    1219 
    1220         return fun;
    1221 }
    1222 
    1223 
    12241459/** Find child function node with a specified name.
    12251460 *
    12261461 * Device tree rwlock should be held at least for reading.
    12271462 *
     1463 * @param tree          Device tree
    12281464 * @param parent        The parent function node.
    12291465 * @param name          The name of the child function.
    12301466 * @return              The child function node.
    12311467 */
    1232 fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
    1233 {
    1234         return find_fun_node_in_device(pfun->child, name);
    1235 }
    1236 
    1237 /* Device classes */
    1238 
    1239 /** Create device class.
    1240  *
    1241  * @return      Device class.
    1242  */
    1243 dev_class_t *create_dev_class(void)
    1244 {
    1245         dev_class_t *cl;
    1246        
    1247         cl = (dev_class_t *) malloc(sizeof(dev_class_t));
    1248         if (cl != NULL) {
    1249                 memset(cl, 0, sizeof(dev_class_t));
    1250                 list_initialize(&cl->devices);
    1251                 fibril_mutex_initialize(&cl->mutex);
    1252         }
    1253        
    1254         return cl;
    1255 }
    1256 
    1257 /** Create device class info.
    1258  *
    1259  * @return              Device class info.
    1260  */
    1261 dev_class_info_t *create_dev_class_info(void)
    1262 {
    1263         dev_class_info_t *info;
    1264        
    1265         info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t));
    1266         if (info != NULL) {
    1267                 memset(info, 0, sizeof(dev_class_info_t));
    1268                 link_initialize(&info->dev_classes);
    1269                 link_initialize(&info->devmap_link);
    1270                 link_initialize(&info->link);
    1271         }
    1272        
    1273         return info;
    1274 }
    1275 
    1276 size_t get_new_class_dev_idx(dev_class_t *cl)
    1277 {
    1278         size_t dev_idx;
    1279        
    1280         fibril_mutex_lock(&cl->mutex);
    1281         dev_idx = ++cl->curr_dev_idx;
    1282         fibril_mutex_unlock(&cl->mutex);
    1283        
    1284         return dev_idx;
    1285 }
    1286 
    1287 
    1288 /** Create unique device name within the class.
    1289  *
    1290  * @param cl            The class.
    1291  * @param base_dev_name Contains the base name for the device if it was
    1292  *                      specified by the driver when it registered the device by
    1293  *                      the class; NULL if driver specified no base name.
    1294  * @return              The unique name for the device within the class.
    1295  */
    1296 char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name)
    1297 {
    1298         char *dev_name;
    1299         const char *base_name;
    1300        
    1301         if (base_dev_name != NULL)
    1302                 base_name = base_dev_name;
    1303         else
    1304                 base_name = cl->base_dev_name;
    1305        
    1306         size_t idx = get_new_class_dev_idx(cl);
    1307         asprintf(&dev_name, "%s%zu", base_name, idx);
    1308        
    1309         return dev_name;
    1310 }
    1311 
    1312 /** Add the device function to the class.
    1313  *
    1314  * The device may be added to multiple classes and a class may contain multiple
    1315  * devices. The class and the device are associated with each other by the
    1316  * dev_class_info_t structure.
    1317  *
    1318  * @param dev           The device.
    1319  * @param class         The class.
    1320  * @param base_dev_name The base name of the device within the class if
    1321  *                      specified by the driver, NULL otherwise.
    1322  * @return              dev_class_info_t structure which associates the device
    1323  *                      with the class.
    1324  */
    1325 dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl,
    1326     const char *base_dev_name)
    1327 {
    1328         dev_class_info_t *info;
    1329 
    1330         assert(fun != NULL);
    1331         assert(cl != NULL);
    1332 
    1333         info = create_dev_class_info();
    1334 
    1335        
    1336         if (info != NULL) {
    1337                 info->dev_class = cl;
    1338                 info->fun = fun;
    1339                
    1340                 /* Add the device to the class. */
    1341                 fibril_mutex_lock(&cl->mutex);
    1342                 list_append(&info->link, &cl->devices);
    1343                 fibril_mutex_unlock(&cl->mutex);
    1344                
    1345                 /* Add the class to the device. */
    1346                 list_append(&info->dev_classes, &fun->classes);
    1347                
    1348                 /* Create unique name for the device within the class. */
    1349                 info->dev_name = create_dev_name_for_class(cl, base_dev_name);
    1350         }
    1351        
    1352         return info;
    1353 }
    1354 
    1355 dev_class_t *get_dev_class(class_list_t *class_list, char *class_name)
    1356 {
    1357         dev_class_t *cl;
    1358        
    1359         fibril_rwlock_write_lock(&class_list->rwlock);
    1360         cl = find_dev_class_no_lock(class_list, class_name);
    1361         if (cl == NULL) {
    1362                 cl = create_dev_class();
    1363                 if (cl != NULL) {
    1364                         cl->name = class_name;
    1365                         cl->base_dev_name = "";
    1366                         add_dev_class_no_lock(class_list, cl);
    1367                 }
    1368         }
    1369 
    1370         fibril_rwlock_write_unlock(&class_list->rwlock);
    1371         return cl;
    1372 }
    1373 
    1374 dev_class_t *find_dev_class_no_lock(class_list_t *class_list,
    1375     const char *class_name)
    1376 {
    1377         dev_class_t *cl;
    1378        
    1379         list_foreach(class_list->classes, link) {
    1380                 cl = list_get_instance(link, dev_class_t, link);
    1381                 if (str_cmp(cl->name, class_name) == 0) {
    1382                         return cl;
    1383                 }
    1384         }
    1385        
    1386         return NULL;
    1387 }
    1388 
    1389 void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl)
    1390 {
    1391         list_append(&cl->link, &class_list->classes);
    1392 }
    1393 
    1394 dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name)
    1395 {
    1396         assert(dev_class != NULL);
    1397         assert(dev_name != NULL);
    1398 
    1399         list_foreach(dev_class->devices, link) {
    1400                 dev_class_info_t *dev = list_get_instance(link,
    1401                     dev_class_info_t, link);
    1402 
    1403                 if (str_cmp(dev->dev_name, dev_name) == 0) {
    1404                         return dev;
    1405                 }
    1406         }
    1407 
    1408         return NULL;
    1409 }
    1410 
    1411 void init_class_list(class_list_t *class_list)
    1412 {
    1413         list_initialize(&class_list->classes);
    1414         fibril_rwlock_initialize(&class_list->rwlock);
    1415         hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1,
    1416             &devmap_devices_class_ops);
    1417 }
    1418 
    1419 
    1420 /* Devmap devices */
    1421 
    1422 fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
     1468static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
     1469    const char *name)
     1470{
     1471        return find_fun_node_in_device(tree, pfun->child, name);
     1472}
     1473
     1474/* loc devices */
     1475
     1476fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id)
    14231477{
    14241478        fun_node_t *fun = NULL;
    14251479        link_t *link;
    1426         unsigned long key = (unsigned long) devmap_handle;
     1480        unsigned long key = (unsigned long) service_id;
    14271481       
    14281482        fibril_rwlock_read_lock(&tree->rwlock);
    1429         link = hash_table_find(&tree->devmap_functions, &key);
    1430         if (link != NULL)
    1431                 fun = hash_table_get_instance(link, fun_node_t, devmap_fun);
     1483        link = hash_table_find(&tree->loc_functions, &key);
     1484        if (link != NULL) {
     1485                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
     1486                fun_add_ref(fun);
     1487        }
    14321488        fibril_rwlock_read_unlock(&tree->rwlock);
    14331489       
     
    14351491}
    14361492
    1437 fun_node_t *find_devmap_class_function(class_list_t *classes,
    1438     devmap_handle_t devmap_handle)
    1439 {
    1440         fun_node_t *fun = NULL;
    1441         dev_class_info_t *cli;
    1442         link_t *link;
    1443         unsigned long key = (unsigned long)devmap_handle;
    1444        
    1445         fibril_rwlock_read_lock(&classes->rwlock);
    1446         link = hash_table_find(&classes->devmap_functions, &key);
    1447         if (link != NULL) {
    1448                 cli = hash_table_get_instance(link, dev_class_info_t,
    1449                     devmap_link);
    1450                 fun = cli->fun;
    1451         }
    1452         fibril_rwlock_read_unlock(&classes->rwlock);
    1453        
    1454         return fun;
    1455 }
    1456 
    1457 void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli)
    1458 {
    1459         unsigned long key = (unsigned long) cli->devmap_handle;
    1460        
    1461         fibril_rwlock_write_lock(&class_list->rwlock);
    1462         hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link);
    1463         fibril_rwlock_write_unlock(&class_list->rwlock);
    1464 
    1465         assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL);
    1466 }
    1467 
    1468 void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun)
    1469 {
    1470         unsigned long key = (unsigned long) fun->devmap_handle;
    1471         fibril_rwlock_write_lock(&tree->rwlock);
    1472         hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun);
    1473         fibril_rwlock_write_unlock(&tree->rwlock);
     1493void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
     1494{
     1495        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1496       
     1497        unsigned long key = (unsigned long) fun->service_id;
     1498        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
    14741499}
    14751500
Note: See TracChangeset for help on using the changeset viewer.