Ignore:
File:
1 edited

Legend:

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

    r80a96d2 r4022513  
    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  */
    5132
    5233#include <errno.h>
     
    5637#include <ipc/driver.h>
    5738#include <ipc/devman.h>
    58 #include <loc.h>
     39#include <devmap.h>
    5940#include <str_error.h>
    6041#include <stdio.h>
     
    6243#include "devman.h"
    6344
    64 static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
     45fun_node_t *find_node_child(fun_node_t *parent, const char *name);
    6546
    6647/* hash table operations */
     
    8566}
    8667
    87 static int loc_functions_compare(unsigned long key[], hash_count_t keys,
     68static int devmap_functions_compare(unsigned long key[], hash_count_t keys,
    8869    link_t *item)
    8970{
    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]);
     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
     75static 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]);
    9283}
    9384
     
    10899};
    109100
    110 static hash_table_operations_t loc_devices_ops = {
     101static hash_table_operations_t devmap_devices_ops = {
    111102        .hash = devices_hash,
    112         .compare = loc_functions_compare,
     103        .compare = devmap_functions_compare,
     104        .remove_callback = devices_remove_callback
     105};
     106
     107static hash_table_operations_t devmap_devices_class_ops = {
     108        .hash = devices_hash,
     109        .compare = devmap_devices_class_compare,
    113110        .remove_callback = devices_remove_callback
    114111};
     
    425422        }
    426423       
    427         fun_add_ref(fun);
    428424        insert_fun_node(tree, fun, str_dup(""), NULL);
    429        
    430425        match_id_t *id = create_match_id();
    431426        id->id = str_dup("root");
     
    443438        }
    444439       
    445         dev_add_ref(dev);
    446440        insert_dev_node(tree, dev, fun);
    447441       
     
    489483/** Assign a driver to a device.
    490484 *
    491  * @param tree          Device tree
    492485 * @param node          The device's node in the device tree.
    493486 * @param drv           The driver.
    494487 */
    495 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
     488void attach_driver(dev_node_t *dev, driver_t *drv)
    496489{
    497490        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    499492       
    500493        fibril_mutex_lock(&drv->driver_mutex);
    501         fibril_rwlock_write_lock(&tree->rwlock);
    502494       
    503495        dev->drv = drv;
    504496        list_append(&dev->driver_devices, &drv->devices);
    505497       
    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  */
    516 void 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);
    532498        fibril_mutex_unlock(&drv->driver_mutex);
    533499}
     
    598564
    599565        fibril_mutex_lock(&driver->driver_mutex);
     566       
     567        async_exch_t *exch = async_exchange_begin(driver->sess);
     568        async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
     569            DRIVER_DEVMAN, 0, 0);
     570        async_exchange_end(exch);
     571
     572        if (!sess) {
     573                fibril_mutex_unlock(&driver->driver_mutex);
     574                return;
     575        }
    600576
    601577        /*
     
    606582        while (link != &driver->devices.head) {
    607583                dev = list_get_instance(link, dev_node_t, driver_devices);
    608                 fibril_rwlock_write_lock(&tree->rwlock);
    609                
    610584                if (dev->passed_to_driver) {
    611                         fibril_rwlock_write_unlock(&tree->rwlock);
    612585                        link = link->next;
    613586                        continue;
    614587                }
    615588
    616                 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
    617                     (int)atomic_get(&dev->refcnt));
    618                 dev_add_ref(dev);
     589                /*
     590                 * We remove the device from the list to allow safe adding
     591                 * of new devices (no one will touch our item this way).
     592                 */
     593                list_remove(link);
    619594
    620595                /*
     
    623598                 */
    624599                fibril_mutex_unlock(&driver->driver_mutex);
    625                 fibril_rwlock_write_unlock(&tree->rwlock);
    626 
    627                 add_device(driver, dev, tree);
    628 
    629                 dev_del_ref(dev);
     600
     601                add_device(sess, driver, dev, tree);
    630602
    631603                /*
     
    636608
    637609                /*
     610                 * Insert the device back.
     611                 * The order is not relevant here so no harm is done
     612                 * (actually, the order would be preserved in most cases).
     613                 */
     614                list_append(link, &driver->devices);
     615
     616                /*
    638617                 * Restart the cycle to go through all devices again.
    639618                 */
    640619                link = driver->devices.head.next;
    641620        }
     621
     622        async_hangup(sess);
    642623
    643624        /*
     
    720701}
    721702
    722 /** Create loc path and name for the function. */
    723 void 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)
     703/** Create devmap path and name for the function. */
     704void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
     705{
     706        char *devmap_pathname = NULL;
     707        char *devmap_name = NULL;
     708       
     709        asprintf(&devmap_name, "%s", fun->pathname);
     710        if (devmap_name == NULL)
    732711                return;
    733712       
    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);
     713        replace_char(devmap_name, '/', DEVMAP_SEPARATOR);
     714       
     715        asprintf(&devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,
     716            devmap_name);
     717        if (devmap_pathname == NULL) {
     718                free(devmap_name);
    740719                return;
    741720        }
    742721       
    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);
     722        devmap_device_register_with_iface(devmap_pathname,
     723            &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
     724       
     725        tree_add_devmap_function(tree, fun);
     726       
     727        free(devmap_name);
     728        free(devmap_pathname);
    750729}
    751730
     
    755734 * @param node          The device's node in the device tree.
    756735 */
    757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
     736void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev,
     737    dev_tree_t *tree)
    758738{
    759739        /*
     
    772752        }
    773753       
    774         async_exch_t *exch = async_exchange_begin(drv->sess);
     754        async_exch_t *exch = async_exchange_begin(sess);
    775755       
    776756        ipc_call_t answer;
    777         aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
     757        aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
    778758            parent_handle, &answer);
    779759       
     
    832812       
    833813        /* Attach the driver to the device. */
    834         attach_driver(tree, dev, drv);
     814        attach_driver(dev, drv);
    835815       
    836816        fibril_mutex_lock(&drv->driver_mutex);
     
    842822        fibril_mutex_unlock(&drv->driver_mutex);
    843823
    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);
     824        if (is_running) {
     825                /* Notify the driver about the new device. */
     826                async_exch_t *exch = async_exchange_begin(drv->sess);
     827                async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
     828                    DRIVER_DEVMAN, 0, 0);
     829                async_exchange_end(exch);
     830               
     831                if (sess) {
     832                        add_device(sess, drv, dev, tree);
     833                        async_hangup(sess);
     834                }
     835        }
     836       
    856837        return true;
    857 }
    858 
    859 int 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 
    882 int 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 
    905 int 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 
    933 int 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 
    959838}
    960839
     
    977856        hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
    978857            &devman_functions_ops);
    979         hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
    980             &loc_devices_ops);
     858        hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
     859            &devmap_devices_ops);
    981860       
    982861        fibril_rwlock_initialize(&tree->rwlock);
     
    985864        if (!create_root_nodes(tree))
    986865                return false;
    987    
     866
    988867        /* Find suitable driver and start it. */
    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;
     868        return assign_driver(tree->root_node->child, drivers_list, tree);
    995869}
    996870
     
    1003877dev_node_t *create_dev_node(void)
    1004878{
    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;
     879        dev_node_t *res = malloc(sizeof(dev_node_t));
     880       
     881        if (res != NULL) {
     882                memset(res, 0, sizeof(dev_node_t));
     883                list_initialize(&res->functions);
     884                link_initialize(&res->driver_devices);
     885                link_initialize(&res->devman_dev);
     886        }
     887       
     888        return res;
    1017889}
    1018890
     
    1030902}
    1031903
    1032 /** Increase device node reference count.
    1033  *
    1034  * @param dev   Device node
    1035  */
    1036 void 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  */
    1047 void dev_del_ref(dev_node_t *dev)
    1048 {
    1049         if (atomic_predec(&dev->refcnt) == 0)
    1050                 delete_dev_node(dev);
    1051 }
    1052 
    1053 
    1054904/** Find the device node structure of the device witch has the specified handle.
    1055905 *
     
    1081931        fibril_rwlock_read_lock(&tree->rwlock);
    1082932        dev = find_dev_node_no_lock(tree, handle);
    1083         if (dev != NULL)
    1084                 dev_add_ref(dev);
    1085        
    1086933        fibril_rwlock_read_unlock(&tree->rwlock);
    1087934       
     
    1089936}
    1090937
    1091 /** Get list of device functions. */
    1092 int 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 
    1124938/* Function nodes */
    1125939
     
    1130944fun_node_t *create_fun_node(void)
    1131945{
    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;
     946        fun_node_t *res = malloc(sizeof(fun_node_t));
     947       
     948        if (res != NULL) {
     949                memset(res, 0, sizeof(fun_node_t));
     950                link_initialize(&res->dev_functions);
     951                list_initialize(&res->match_ids.ids);
     952                list_initialize(&res->classes);
     953                link_initialize(&res->devman_fun);
     954                link_initialize(&res->devmap_fun);
     955        }
     956       
     957        return res;
    1146958}
    1147959
     
    1161973}
    1162974
    1163 /** Increase function node reference count.
    1164  *
    1165  * @param fun   Function node
    1166  */
    1167 void 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  */
    1178 void fun_del_ref(fun_node_t *fun)
    1179 {
    1180         if (atomic_predec(&fun->refcnt) == 0)
    1181                 delete_fun_node(fun);
    1182 }
    1183 
    1184975/** Find the function node with the specified handle.
    1185976 *
     
    1192983        unsigned long key = handle;
    1193984        link_t *link;
    1194         fun_node_t *fun;
    1195985       
    1196986        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    1200990                return NULL;
    1201991       
    1202         fun = hash_table_get_instance(link, fun_node_t, devman_fun);
    1203        
    1204         return fun;
     992        return hash_table_get_instance(link, fun_node_t, devman_fun);
    1205993}
    1206994
     
    12161004       
    12171005        fibril_rwlock_read_lock(&tree->rwlock);
    1218        
    12191006        fun = find_fun_node_no_lock(tree, handle);
    1220         if (fun != NULL)
    1221                 fun_add_ref(fun);
    1222        
    12231007        fibril_rwlock_read_unlock(&tree->rwlock);
    12241008       
     
    12281012/** Create and set device's full path in device tree.
    12291013 *
    1230  * @param tree          Device tree
    12311014 * @param node          The device's device node.
    12321015 * @param parent        The parent device node.
     
    12341017 *                      resources etc.).
    12351018 */
    1236 static 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));
     1019static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
     1020{
    12391021        assert(fun->name != NULL);
    12401022       
     
    12631045 *
    12641046 * @param tree          The device tree.
    1265  * @param dev           The newly added device node.
    1266  * @param pfun          The parent function node.
     1047 * @param node          The newly added device node.
     1048 * @param dev_name      The name of the newly added device.
     1049 * @param parent        The parent device node.
    12671050 *
    12681051 * @return              True on success, false otherwise (insufficient resources
     
    12711054bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    12721055{
     1056        assert(dev != NULL);
     1057        assert(tree != NULL);
    12731058        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12741059       
     
    12881073}
    12891074
    1290 /** Remove device from device tree.
    1291  *
    1292  * @param tree          Device tree
    1293  * @param dev           Device node
    1294  */
    1295 void 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 
    13131075/** Insert new function into device tree.
    13141076 *
    13151077 * @param tree          The device tree.
    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.
     1078 * @param node          The newly added function node.
     1079 * @param dev_name      The name of the newly added function.
     1080 * @param parent        Owning device node.
    13191081 *
    13201082 * @return              True on success, false otherwise (insufficient resources
     
    13261088        fun_node_t *pfun;
    13271089       
     1090        assert(fun != NULL);
     1091        assert(tree != NULL);
    13281092        assert(fun_name != NULL);
    13291093        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    13361100       
    13371101        fun->name = fun_name;
    1338         if (!set_fun_path(tree, fun, pfun)) {
     1102        if (!set_fun_path(fun, pfun)) {
    13391103                return false;
    13401104        }
     
    13511115       
    13521116        return true;
    1353 }
    1354 
    1355 /** Remove function from device tree.
    1356  *
    1357  * @param tree          Device tree
    1358  * @param node          Function node to remove
    1359  */
    1360 void 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;
    13741117}
    13751118
     
    13931136       
    13941137        fun_node_t *fun = tree->root_node;
    1395         fun_add_ref(fun);
    13961138        /*
    13971139         * Relative path to the function from its parent (but with '/' at the
     
    14001142        char *rel_path = path;
    14011143        char *next_path_elem = NULL;
    1402         bool cont = (rel_path[1] != '\0');
     1144        bool cont = true;
    14031145       
    14041146        while (cont && fun != NULL) {
     
    14111153                }
    14121154               
    1413                 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
    1414                 fun_del_ref(fun);
    1415                 fun = cfun;
     1155                fun = find_node_child(fun, rel_path + 1);
    14161156               
    14171157                if (cont) {
     
    14311171 * Device tree rwlock should be held at least for reading.
    14321172 *
    1433  * @param tree Device tree
    14341173 * @param dev Device the function belongs to.
    14351174 * @param name Function name (not path).
     
    14371176 * @retval NULL No function with given name.
    14381177 */
    1439 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
    1440     const char *name)
    1441 {
     1178fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
     1179{
     1180        assert(dev != NULL);
    14421181        assert(name != NULL);
    1443         assert(fibril_rwlock_is_locked(&tree->rwlock));
    14441182
    14451183        fun_node_t *fun;
     
    14481186                fun = list_get_instance(link, fun_node_t, dev_functions);
    14491187
    1450                 if (str_cmp(name, fun->name) == 0) {
    1451                         fun_add_ref(fun);
     1188                if (str_cmp(name, fun->name) == 0)
    14521189                        return fun;
    1453                 }
    14541190        }
    14551191
     
    14571193}
    14581194
     1195/** Find function node by its class name and index. */
     1196fun_node_t *find_fun_node_by_class(class_list_t *class_list,
     1197    const char *class_name, const char *dev_name)
     1198{
     1199        assert(class_list != NULL);
     1200        assert(class_name != NULL);
     1201        assert(dev_name != NULL);
     1202
     1203        fibril_rwlock_read_lock(&class_list->rwlock);
     1204
     1205        dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);
     1206        if (cl == NULL) {
     1207                fibril_rwlock_read_unlock(&class_list->rwlock);
     1208                return NULL;
     1209        }
     1210
     1211        dev_class_info_t *dev = find_dev_in_class(cl, dev_name);
     1212        if (dev == NULL) {
     1213                fibril_rwlock_read_unlock(&class_list->rwlock);
     1214                return NULL;
     1215        }
     1216
     1217        fun_node_t *fun = dev->fun;
     1218
     1219        fibril_rwlock_read_unlock(&class_list->rwlock);
     1220
     1221        return fun;
     1222}
     1223
     1224
    14591225/** Find child function node with a specified name.
    14601226 *
    14611227 * Device tree rwlock should be held at least for reading.
    14621228 *
    1463  * @param tree          Device tree
    14641229 * @param parent        The parent function node.
    14651230 * @param name          The name of the child function.
    14661231 * @return              The child function node.
    14671232 */
    1468 static 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 
    1476 fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id)
     1233fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
     1234{
     1235        return find_fun_node_in_device(pfun->child, name);
     1236}
     1237
     1238/* Device classes */
     1239
     1240/** Create device class.
     1241 *
     1242 * @return      Device class.
     1243 */
     1244dev_class_t *create_dev_class(void)
     1245{
     1246        dev_class_t *cl;
     1247       
     1248        cl = (dev_class_t *) malloc(sizeof(dev_class_t));
     1249        if (cl != NULL) {
     1250                memset(cl, 0, sizeof(dev_class_t));
     1251                list_initialize(&cl->devices);
     1252                fibril_mutex_initialize(&cl->mutex);
     1253        }
     1254       
     1255        return cl;
     1256}
     1257
     1258/** Create device class info.
     1259 *
     1260 * @return              Device class info.
     1261 */
     1262dev_class_info_t *create_dev_class_info(void)
     1263{
     1264        dev_class_info_t *info;
     1265       
     1266        info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t));
     1267        if (info != NULL) {
     1268                memset(info, 0, sizeof(dev_class_info_t));
     1269                link_initialize(&info->dev_classes);
     1270                link_initialize(&info->devmap_link);
     1271                link_initialize(&info->link);
     1272        }
     1273       
     1274        return info;
     1275}
     1276
     1277size_t get_new_class_dev_idx(dev_class_t *cl)
     1278{
     1279        size_t dev_idx;
     1280       
     1281        fibril_mutex_lock(&cl->mutex);
     1282        dev_idx = ++cl->curr_dev_idx;
     1283        fibril_mutex_unlock(&cl->mutex);
     1284       
     1285        return dev_idx;
     1286}
     1287
     1288
     1289/** Create unique device name within the class.
     1290 *
     1291 * @param cl            The class.
     1292 * @param base_dev_name Contains the base name for the device if it was
     1293 *                      specified by the driver when it registered the device by
     1294 *                      the class; NULL if driver specified no base name.
     1295 * @return              The unique name for the device within the class.
     1296 */
     1297char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name)
     1298{
     1299        char *dev_name;
     1300        const char *base_name;
     1301       
     1302        if (base_dev_name != NULL)
     1303                base_name = base_dev_name;
     1304        else
     1305                base_name = cl->base_dev_name;
     1306       
     1307        size_t idx = get_new_class_dev_idx(cl);
     1308        asprintf(&dev_name, "%s%zu", base_name, idx);
     1309       
     1310        return dev_name;
     1311}
     1312
     1313/** Add the device function to the class.
     1314 *
     1315 * The device may be added to multiple classes and a class may contain multiple
     1316 * devices. The class and the device are associated with each other by the
     1317 * dev_class_info_t structure.
     1318 *
     1319 * @param dev           The device.
     1320 * @param class         The class.
     1321 * @param base_dev_name The base name of the device within the class if
     1322 *                      specified by the driver, NULL otherwise.
     1323 * @return              dev_class_info_t structure which associates the device
     1324 *                      with the class.
     1325 */
     1326dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl,
     1327    const char *base_dev_name)
     1328{
     1329        dev_class_info_t *info;
     1330
     1331        assert(fun != NULL);
     1332        assert(cl != NULL);
     1333
     1334        info = create_dev_class_info();
     1335
     1336       
     1337        if (info != NULL) {
     1338                info->dev_class = cl;
     1339                info->fun = fun;
     1340               
     1341                /* Add the device to the class. */
     1342                fibril_mutex_lock(&cl->mutex);
     1343                list_append(&info->link, &cl->devices);
     1344                fibril_mutex_unlock(&cl->mutex);
     1345               
     1346                /* Add the class to the device. */
     1347                list_append(&info->dev_classes, &fun->classes);
     1348               
     1349                /* Create unique name for the device within the class. */
     1350                info->dev_name = create_dev_name_for_class(cl, base_dev_name);
     1351        }
     1352       
     1353        return info;
     1354}
     1355
     1356dev_class_t *get_dev_class(class_list_t *class_list, char *class_name)
     1357{
     1358        dev_class_t *cl;
     1359       
     1360        fibril_rwlock_write_lock(&class_list->rwlock);
     1361        cl = find_dev_class_no_lock(class_list, class_name);
     1362        if (cl == NULL) {
     1363                cl = create_dev_class();
     1364                if (cl != NULL) {
     1365                        cl->name = class_name;
     1366                        cl->base_dev_name = "";
     1367                        add_dev_class_no_lock(class_list, cl);
     1368                }
     1369        }
     1370
     1371        fibril_rwlock_write_unlock(&class_list->rwlock);
     1372        return cl;
     1373}
     1374
     1375dev_class_t *find_dev_class_no_lock(class_list_t *class_list,
     1376    const char *class_name)
     1377{
     1378        dev_class_t *cl;
     1379       
     1380        list_foreach(class_list->classes, link) {
     1381                cl = list_get_instance(link, dev_class_t, link);
     1382                if (str_cmp(cl->name, class_name) == 0) {
     1383                        return cl;
     1384                }
     1385        }
     1386       
     1387        return NULL;
     1388}
     1389
     1390void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl)
     1391{
     1392        list_append(&cl->link, &class_list->classes);
     1393}
     1394
     1395dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name)
     1396{
     1397        assert(dev_class != NULL);
     1398        assert(dev_name != NULL);
     1399
     1400        list_foreach(dev_class->devices, link) {
     1401                dev_class_info_t *dev = list_get_instance(link,
     1402                    dev_class_info_t, link);
     1403
     1404                if (str_cmp(dev->dev_name, dev_name) == 0) {
     1405                        return dev;
     1406                }
     1407        }
     1408
     1409        return NULL;
     1410}
     1411
     1412void init_class_list(class_list_t *class_list)
     1413{
     1414        list_initialize(&class_list->classes);
     1415        fibril_rwlock_initialize(&class_list->rwlock);
     1416        hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1,
     1417            &devmap_devices_class_ops);
     1418}
     1419
     1420
     1421/* Devmap devices */
     1422
     1423fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
    14771424{
    14781425        fun_node_t *fun = NULL;
    14791426        link_t *link;
    1480         unsigned long key = (unsigned long) service_id;
     1427        unsigned long key = (unsigned long) devmap_handle;
    14811428       
    14821429        fibril_rwlock_read_lock(&tree->rwlock);
    1483         link = hash_table_find(&tree->loc_functions, &key);
     1430        link = hash_table_find(&tree->devmap_functions, &key);
     1431        if (link != NULL)
     1432                fun = hash_table_get_instance(link, fun_node_t, devmap_fun);
     1433        fibril_rwlock_read_unlock(&tree->rwlock);
     1434       
     1435        return fun;
     1436}
     1437
     1438fun_node_t *find_devmap_class_function(class_list_t *classes,
     1439    devmap_handle_t devmap_handle)
     1440{
     1441        fun_node_t *fun = NULL;
     1442        dev_class_info_t *cli;
     1443        link_t *link;
     1444        unsigned long key = (unsigned long)devmap_handle;
     1445       
     1446        fibril_rwlock_read_lock(&classes->rwlock);
     1447        link = hash_table_find(&classes->devmap_functions, &key);
    14841448        if (link != NULL) {
    1485                 fun = hash_table_get_instance(link, fun_node_t, loc_fun);
    1486                 fun_add_ref(fun);
    1487         }
    1488         fibril_rwlock_read_unlock(&tree->rwlock);
     1449                cli = hash_table_get_instance(link, dev_class_info_t,
     1450                    devmap_link);
     1451                fun = cli->fun;
     1452        }
     1453        fibril_rwlock_read_unlock(&classes->rwlock);
    14891454       
    14901455        return fun;
    14911456}
    14921457
    1493 void 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);
     1458void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli)
     1459{
     1460        unsigned long key = (unsigned long) cli->devmap_handle;
     1461       
     1462        fibril_rwlock_write_lock(&class_list->rwlock);
     1463        hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link);
     1464        fibril_rwlock_write_unlock(&class_list->rwlock);
     1465
     1466        assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL);
     1467}
     1468
     1469void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun)
     1470{
     1471        unsigned long key = (unsigned long) fun->devmap_handle;
     1472        fibril_rwlock_write_lock(&tree->rwlock);
     1473        hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun);
     1474        fibril_rwlock_write_unlock(&tree->rwlock);
    14991475}
    15001476
Note: See TracChangeset for help on using the changeset viewer.