Ignore:
File:
1 edited

Legend:

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

    r80a96d2 rb72efe8  
    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};
     
    273270        }
    274271       
    275         ssize_t read_bytes = read_all(fd, buf, len);
     272        ssize_t read_bytes = safe_read(fd, buf, len);
    276273        if (read_bytes <= 0) {
    277                 log_msg(LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
    278                     read_bytes);
     274                log_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
    279275                goto cleanup;
    280276        }
     
    425421        }
    426422       
    427         fun_add_ref(fun);
    428         insert_fun_node(tree, fun, str_dup(""), NULL);
    429        
     423        insert_fun_node(tree, fun, clone_string(""), NULL);
    430424        match_id_t *id = create_match_id();
    431         id->id = str_dup("root");
     425        id->id = clone_string("root");
    432426        id->score = 100;
    433427        add_match_id(&fun->match_ids, id);
     
    443437        }
    444438       
    445         dev_add_ref(dev);
    446439        insert_dev_node(tree, dev, fun);
    447440       
     
    489482/** Assign a driver to a device.
    490483 *
    491  * @param tree          Device tree
    492484 * @param node          The device's node in the device tree.
    493485 * @param drv           The driver.
    494486 */
    495 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
     487void attach_driver(dev_node_t *dev, driver_t *drv)
    496488{
    497489        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    499491       
    500492        fibril_mutex_lock(&drv->driver_mutex);
    501         fibril_rwlock_write_lock(&tree->rwlock);
    502493       
    503494        dev->drv = drv;
    504495        list_append(&dev->driver_devices, &drv->devices);
    505496       
    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);
    532497        fibril_mutex_unlock(&drv->driver_mutex);
    533498}
     
    598563
    599564        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        }
    600575
    601576        /*
     
    606581        while (link != &driver->devices.head) {
    607582                dev = list_get_instance(link, dev_node_t, driver_devices);
    608                 fibril_rwlock_write_lock(&tree->rwlock);
    609                
    610583                if (dev->passed_to_driver) {
    611                         fibril_rwlock_write_unlock(&tree->rwlock);
    612584                        link = link->next;
    613585                        continue;
    614586                }
    615587
    616                 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
    617                     (int)atomic_get(&dev->refcnt));
    618                 dev_add_ref(dev);
     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);
    619593
    620594                /*
     
    623597                 */
    624598                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);
     599
     600                add_device(sess, driver, dev, tree);
    630601
    631602                /*
     
    636607
    637608                /*
     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                /*
    638616                 * Restart the cycle to go through all devices again.
    639617                 */
    640618                link = driver->devices.head.next;
    641619        }
     620
     621        async_hangup(sess);
    642622
    643623        /*
     
    720700}
    721701
    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)
     702/** Create devmap path and name for the function. */
     703void 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)
    732710                return;
    733711       
    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);
     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);
    740718                return;
    741719        }
    742720       
    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);
     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);
    750728}
    751729
     
    755733 * @param node          The device's node in the device tree.
    756734 */
    757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
     735void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev,
     736    dev_tree_t *tree)
    758737{
    759738        /*
     
    772751        }
    773752       
    774         async_exch_t *exch = async_exchange_begin(drv->sess);
     753        async_exch_t *exch = async_exchange_begin(sess);
    775754       
    776755        ipc_call_t answer;
    777         aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
     756        aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
    778757            parent_handle, &answer);
    779758       
     
    832811       
    833812        /* Attach the driver to the device. */
    834         attach_driver(tree, dev, drv);
     813        attach_driver(dev, drv);
    835814       
    836815        fibril_mutex_lock(&drv->driver_mutex);
     
    842821        fibril_mutex_unlock(&drv->driver_mutex);
    843822
    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);
     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       
    856836        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 
    959837}
    960838
     
    977855        hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
    978856            &devman_functions_ops);
    979         hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
    980             &loc_devices_ops);
     857        hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
     858            &devmap_devices_ops);
    981859       
    982860        fibril_rwlock_initialize(&tree->rwlock);
     
    985863        if (!create_root_nodes(tree))
    986864                return false;
    987    
     865
    988866        /* 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;
     867        return assign_driver(tree->root_node->child, drivers_list, tree);
    995868}
    996869
     
    1003876dev_node_t *create_dev_node(void)
    1004877{
    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;
     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;
    1017888}
    1018889
     
    1030901}
    1031902
    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 
    1054903/** Find the device node structure of the device witch has the specified handle.
    1055904 *
     
    1081930        fibril_rwlock_read_lock(&tree->rwlock);
    1082931        dev = find_dev_node_no_lock(tree, handle);
    1083         if (dev != NULL)
    1084                 dev_add_ref(dev);
    1085        
    1086932        fibril_rwlock_read_unlock(&tree->rwlock);
    1087933       
     
    1089935}
    1090936
    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 
    1124937/* Function nodes */
    1125938
     
    1130943fun_node_t *create_fun_node(void)
    1131944{
    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;
     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;
    1146957}
    1147958
     
    1161972}
    1162973
    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 
    1184974/** Find the function node with the specified handle.
    1185975 *
     
    1192982        unsigned long key = handle;
    1193983        link_t *link;
    1194         fun_node_t *fun;
    1195984       
    1196985        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    1200989                return NULL;
    1201990       
    1202         fun = hash_table_get_instance(link, fun_node_t, devman_fun);
    1203        
    1204         return fun;
     991        return hash_table_get_instance(link, fun_node_t, devman_fun);
    1205992}
    1206993
     
    12161003       
    12171004        fibril_rwlock_read_lock(&tree->rwlock);
    1218        
    12191005        fun = find_fun_node_no_lock(tree, handle);
    1220         if (fun != NULL)
    1221                 fun_add_ref(fun);
    1222        
    12231006        fibril_rwlock_read_unlock(&tree->rwlock);
    12241007       
     
    12281011/** Create and set device's full path in device tree.
    12291012 *
    1230  * @param tree          Device tree
    12311013 * @param node          The device's device node.
    12321014 * @param parent        The parent device node.
     
    12341016 *                      resources etc.).
    12351017 */
    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));
     1018static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
     1019{
    12391020        assert(fun->name != NULL);
    12401021       
     
    12631044 *
    12641045 * @param tree          The device tree.
    1265  * @param dev           The newly added device node.
    1266  * @param pfun          The parent function node.
     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.
    12671049 *
    12681050 * @return              True on success, false otherwise (insufficient resources
     
    12711053bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    12721054{
     1055        assert(dev != NULL);
     1056        assert(tree != NULL);
    12731057        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12741058       
     
    12881072}
    12891073
    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 
    13131074/** Insert new function into device tree.
    13141075 *
    13151076 * @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.
     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.
    13191080 *
    13201081 * @return              True on success, false otherwise (insufficient resources
     
    13261087        fun_node_t *pfun;
    13271088       
     1089        assert(fun != NULL);
     1090        assert(tree != NULL);
    13281091        assert(fun_name != NULL);
    13291092        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    13361099       
    13371100        fun->name = fun_name;
    1338         if (!set_fun_path(tree, fun, pfun)) {
     1101        if (!set_fun_path(fun, pfun)) {
    13391102                return false;
    13401103        }
     
    13511114       
    13521115        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;
    13741116}
    13751117
     
    13931135       
    13941136        fun_node_t *fun = tree->root_node;
    1395         fun_add_ref(fun);
    13961137        /*
    13971138         * Relative path to the function from its parent (but with '/' at the
     
    14001141        char *rel_path = path;
    14011142        char *next_path_elem = NULL;
    1402         bool cont = (rel_path[1] != '\0');
     1143        bool cont = true;
    14031144       
    14041145        while (cont && fun != NULL) {
     
    14111152                }
    14121153               
    1413                 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
    1414                 fun_del_ref(fun);
    1415                 fun = cfun;
     1154                fun = find_node_child(fun, rel_path + 1);
    14161155               
    14171156                if (cont) {
     
    14311170 * Device tree rwlock should be held at least for reading.
    14321171 *
    1433  * @param tree Device tree
    14341172 * @param dev Device the function belongs to.
    14351173 * @param name Function name (not path).
     
    14371175 * @retval NULL No function with given name.
    14381176 */
    1439 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
    1440     const char *name)
    1441 {
     1177fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
     1178{
     1179        assert(dev != NULL);
    14421180        assert(name != NULL);
    1443         assert(fibril_rwlock_is_locked(&tree->rwlock));
    14441181
    14451182        fun_node_t *fun;
     
    14481185                fun = list_get_instance(link, fun_node_t, dev_functions);
    14491186
    1450                 if (str_cmp(name, fun->name) == 0) {
    1451                         fun_add_ref(fun);
     1187                if (str_cmp(name, fun->name) == 0)
    14521188                        return fun;
    1453                 }
    14541189        }
    14551190
     
    14571192}
    14581193
     1194/** Find function node by its class name and index. */
     1195fun_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
    14591224/** Find child function node with a specified name.
    14601225 *
    14611226 * Device tree rwlock should be held at least for reading.
    14621227 *
    1463  * @param tree          Device tree
    14641228 * @param parent        The parent function node.
    14651229 * @param name          The name of the child function.
    14661230 * @return              The child function node.
    14671231 */
    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)
     1232fun_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 */
     1243dev_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 */
     1261dev_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
     1276size_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 */
     1296char *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 */
     1325dev_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
     1355dev_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
     1374dev_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
     1389void 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
     1394dev_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
     1411void 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
     1422fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
    14771423{
    14781424        fun_node_t *fun = NULL;
    14791425        link_t *link;
    1480         unsigned long key = (unsigned long) service_id;
     1426        unsigned long key = (unsigned long) devmap_handle;
    14811427       
    14821428        fibril_rwlock_read_lock(&tree->rwlock);
    1483         link = hash_table_find(&tree->loc_functions, &key);
     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);
     1432        fibril_rwlock_read_unlock(&tree->rwlock);
     1433       
     1434        return fun;
     1435}
     1436
     1437fun_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);
    14841447        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);
     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);
    14891453       
    14901454        return fun;
    14911455}
    14921456
    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);
     1457void 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
     1468void 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);
    14991474}
    15001475
Note: See TracChangeset for help on using the changeset viewer.