Ignore:
File:
1 edited

Legend:

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

    rc1a0488 r79ae36dd  
    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       
     
    473466        fibril_mutex_lock(&drivers_list->drivers_mutex);
    474467       
    475         list_foreach(drivers_list->drivers, link) {
     468        link_t *link = drivers_list->drivers.next;
     469        while (link != &drivers_list->drivers) {
    476470                drv = list_get_instance(link, driver_t, drivers);
    477471                score = get_match_score(drv, node);
     
    480474                        best_drv = drv;
    481475                }
     476                link = link->next;
    482477        }
    483478       
     
    489484/** Assign a driver to a device.
    490485 *
    491  * @param tree          Device tree
    492486 * @param node          The device's node in the device tree.
    493487 * @param drv           The driver.
    494488 */
    495 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
     489void attach_driver(dev_node_t *dev, driver_t *drv)
    496490{
    497491        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    499493       
    500494        fibril_mutex_lock(&drv->driver_mutex);
    501         fibril_rwlock_write_lock(&tree->rwlock);
    502495       
    503496        dev->drv = drv;
    504497        list_append(&dev->driver_devices, &drv->devices);
    505498       
    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);
    532499        fibril_mutex_unlock(&drv->driver_mutex);
    533500}
     
    569536        driver_t *res = NULL;
    570537        driver_t *drv = NULL;
     538        link_t *link;
    571539       
    572540        fibril_mutex_lock(&drv_list->drivers_mutex);
    573541       
    574         list_foreach(drv_list->drivers, link) {
     542        link = drv_list->drivers.next;
     543        while (link != &drv_list->drivers) {
    575544                drv = list_get_instance(link, driver_t, drivers);
    576545                if (str_cmp(drv->name, drv_name) == 0) {
     
    578547                        break;
    579548                }
     549
     550                link = link->next;
    580551        }
    581552       
     
    598569
    599570        fibril_mutex_lock(&driver->driver_mutex);
     571       
     572        async_exch_t *exch = async_exchange_begin(driver->sess);
     573        async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
     574            DRIVER_DEVMAN, 0, 0);
     575        async_exchange_end(exch);
     576
     577        if (!sess) {
     578                fibril_mutex_unlock(&driver->driver_mutex);
     579                return;
     580        }
    600581
    601582        /*
     
    603584         * that has not been passed to the driver.
    604585         */
    605         link = driver->devices.head.next;
    606         while (link != &driver->devices.head) {
     586        link = driver->devices.next;
     587        while (link != &driver->devices) {
    607588                dev = list_get_instance(link, dev_node_t, driver_devices);
    608                 fibril_rwlock_write_lock(&tree->rwlock);
    609                
    610589                if (dev->passed_to_driver) {
    611                         fibril_rwlock_write_unlock(&tree->rwlock);
    612590                        link = link->next;
    613591                        continue;
    614592                }
    615593
    616                 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
    617                     (int)atomic_get(&dev->refcnt));
    618                 dev_add_ref(dev);
     594                /*
     595                 * We remove the device from the list to allow safe adding
     596                 * of new devices (no one will touch our item this way).
     597                 */
     598                list_remove(link);
    619599
    620600                /*
     
    623603                 */
    624604                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);
     605
     606                add_device(sess, driver, dev, tree);
    630607
    631608                /*
     
    636613
    637614                /*
     615                 * Insert the device back.
     616                 * The order is not relevant here so no harm is done
     617                 * (actually, the order would be preserved in most cases).
     618                 */
     619                list_append(link, &driver->devices);
     620
     621                /*
    638622                 * Restart the cycle to go through all devices again.
    639623                 */
    640                 link = driver->devices.head.next;
    641         }
     624                link = driver->devices.next;
     625        }
     626
     627        async_hangup(sess);
    642628
    643629        /*
     
    720706}
    721707
    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)
     708/** Create devmap path and name for the function. */
     709void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
     710{
     711        char *devmap_pathname = NULL;
     712        char *devmap_name = NULL;
     713       
     714        asprintf(&devmap_name, "%s", fun->pathname);
     715        if (devmap_name == NULL)
    732716                return;
    733717       
    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);
     718        replace_char(devmap_name, '/', DEVMAP_SEPARATOR);
     719       
     720        asprintf(&devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,
     721            devmap_name);
     722        if (devmap_pathname == NULL) {
     723                free(devmap_name);
    740724                return;
    741725        }
    742726       
    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);
     727        devmap_device_register_with_iface(devmap_pathname,
     728            &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
     729       
     730        tree_add_devmap_function(tree, fun);
     731       
     732        free(devmap_name);
     733        free(devmap_pathname);
    750734}
    751735
     
    755739 * @param node          The device's node in the device tree.
    756740 */
    757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
     741void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev,
     742    dev_tree_t *tree)
    758743{
    759744        /*
     
    772757        }
    773758       
    774         async_exch_t *exch = async_exchange_begin(drv->sess);
     759        async_exch_t *exch = async_exchange_begin(sess);
    775760       
    776761        ipc_call_t answer;
    777         aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
     762        aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
    778763            parent_handle, &answer);
    779764       
     
    832817       
    833818        /* Attach the driver to the device. */
    834         attach_driver(tree, dev, drv);
     819        attach_driver(dev, drv);
    835820       
    836821        fibril_mutex_lock(&drv->driver_mutex);
     
    842827        fibril_mutex_unlock(&drv->driver_mutex);
    843828
    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);
     829        if (is_running) {
     830                /* Notify the driver about the new device. */
     831                async_exch_t *exch = async_exchange_begin(drv->sess);
     832                async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
     833                    DRIVER_DEVMAN, 0, 0);
     834                async_exchange_end(exch);
     835               
     836                if (sess) {
     837                        add_device(sess, drv, dev, tree);
     838                        async_hangup(sess);
     839                }
     840        }
     841       
    856842        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 
    883 int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
    884 {
    885         async_exch_t *exch;
    886         sysarg_t retval;
    887         driver_t *drv;
    888         devman_handle_t handle;
    889        
    890         log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
    891 
    892         fibril_rwlock_read_lock(&tree->rwlock);
    893        
    894         if (fun->dev == NULL) {
    895                 /* XXX root function? */
    896                 fibril_rwlock_read_unlock(&tree->rwlock);
    897                 return EINVAL;
    898         }
    899        
    900         drv = fun->dev->drv;
    901         handle = fun->handle;
    902         fibril_rwlock_read_unlock(&tree->rwlock);
    903        
    904         exch = async_exchange_begin(drv->sess);
    905         retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
    906         loc_exchange_end(exch);
    907        
    908         return retval;
    909 }
    910 
    911 int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
    912 {
    913         async_exch_t *exch;
    914         sysarg_t retval;
    915         driver_t *drv;
    916         devman_handle_t handle;
    917        
    918         log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
    919 
    920         fibril_rwlock_read_lock(&tree->rwlock);
    921         if (fun->dev == NULL) {
    922                 /* XXX root function? */
    923                 fibril_rwlock_read_unlock(&tree->rwlock);
    924                 return EINVAL;
    925         }
    926        
    927         drv = fun->dev->drv;
    928         handle = fun->handle;
    929         fibril_rwlock_read_unlock(&tree->rwlock);
    930        
    931         exch = async_exchange_begin(drv->sess);
    932         retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
    933         loc_exchange_end(exch);
    934        
    935         return retval;
    936 
    937843}
    938844
     
    955861        hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
    956862            &devman_functions_ops);
    957         hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
    958             &loc_devices_ops);
     863        hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
     864            &devmap_devices_ops);
    959865       
    960866        fibril_rwlock_initialize(&tree->rwlock);
     
    963869        if (!create_root_nodes(tree))
    964870                return false;
    965    
     871
    966872        /* Find suitable driver and start it. */
    967         dev_node_t *rdev = tree->root_node->child;
    968         dev_add_ref(rdev);
    969         int rc = assign_driver(rdev, drivers_list, tree);
    970         dev_del_ref(rdev);
    971        
    972         return rc;
     873        return assign_driver(tree->root_node->child, drivers_list, tree);
    973874}
    974875
     
    981882dev_node_t *create_dev_node(void)
    982883{
    983         dev_node_t *dev;
    984        
    985         dev = calloc(1, sizeof(dev_node_t));
    986         if (dev == NULL)
    987                 return NULL;
    988        
    989         atomic_set(&dev->refcnt, 0);
    990         list_initialize(&dev->functions);
    991         link_initialize(&dev->driver_devices);
    992         link_initialize(&dev->devman_dev);
    993        
    994         return dev;
     884        dev_node_t *res = malloc(sizeof(dev_node_t));
     885       
     886        if (res != NULL) {
     887                memset(res, 0, sizeof(dev_node_t));
     888                list_initialize(&res->functions);
     889                link_initialize(&res->driver_devices);
     890                link_initialize(&res->devman_dev);
     891        }
     892       
     893        return res;
    995894}
    996895
     
    1008907}
    1009908
    1010 /** Increase device node reference count.
    1011  *
    1012  * @param dev   Device node
    1013  */
    1014 void dev_add_ref(dev_node_t *dev)
    1015 {
    1016         atomic_inc(&dev->refcnt);
    1017 }
    1018 
    1019 /** Decrease device node reference count.
    1020  *
    1021  * When the count drops to zero the device node is freed.
    1022  *
    1023  * @param dev   Device node
    1024  */
    1025 void dev_del_ref(dev_node_t *dev)
    1026 {
    1027         if (atomic_predec(&dev->refcnt) == 0)
    1028                 delete_dev_node(dev);
    1029 }
    1030 
    1031 
    1032909/** Find the device node structure of the device witch has the specified handle.
    1033910 *
     
    1059936        fibril_rwlock_read_lock(&tree->rwlock);
    1060937        dev = find_dev_node_no_lock(tree, handle);
    1061         if (dev != NULL)
    1062                 dev_add_ref(dev);
    1063        
    1064938        fibril_rwlock_read_unlock(&tree->rwlock);
    1065939       
     
    1067941}
    1068942
    1069 /** Get list of device functions. */
    1070 int dev_get_functions(dev_tree_t *tree, dev_node_t *dev,
    1071     devman_handle_t *hdl_buf, size_t buf_size, size_t *act_size)
    1072 {
    1073         size_t act_cnt;
    1074         size_t buf_cnt;
    1075 
    1076         assert(fibril_rwlock_is_locked(&tree->rwlock));
    1077 
    1078         buf_cnt = buf_size / sizeof(devman_handle_t);
    1079 
    1080         act_cnt = list_count(&dev->functions);
    1081         *act_size = act_cnt * sizeof(devman_handle_t);
    1082 
    1083         if (buf_size % sizeof(devman_handle_t) != 0)
    1084                 return EINVAL;
    1085 
    1086         size_t pos = 0;
    1087         list_foreach(dev->functions, item) {
    1088                 fun_node_t *fun =
    1089                     list_get_instance(item, fun_node_t, dev_functions);
    1090 
    1091                 if (pos < buf_cnt) {
    1092                         hdl_buf[pos] = fun->handle;
    1093                 }
    1094 
    1095                 pos++;
    1096         }
    1097 
    1098         return EOK;
    1099 }
    1100 
    1101 
    1102943/* Function nodes */
    1103944
     
    1108949fun_node_t *create_fun_node(void)
    1109950{
    1110         fun_node_t *fun;
    1111 
    1112         fun = calloc(1, sizeof(fun_node_t));
    1113         if (fun == NULL)
    1114                 return NULL;
    1115        
    1116         fun->state = FUN_INIT;
    1117         atomic_set(&fun->refcnt, 0);
    1118         link_initialize(&fun->dev_functions);
    1119         list_initialize(&fun->match_ids.ids);
    1120         link_initialize(&fun->devman_fun);
    1121         link_initialize(&fun->loc_fun);
    1122        
    1123         return fun;
     951        fun_node_t *res = malloc(sizeof(fun_node_t));
     952       
     953        if (res != NULL) {
     954                memset(res, 0, sizeof(fun_node_t));
     955                link_initialize(&res->dev_functions);
     956                list_initialize(&res->match_ids.ids);
     957                list_initialize(&res->classes);
     958                link_initialize(&res->devman_fun);
     959                link_initialize(&res->devmap_fun);
     960        }
     961       
     962        return res;
    1124963}
    1125964
     
    1139978}
    1140979
    1141 /** Increase function node reference count.
    1142  *
    1143  * @param fun   Function node
    1144  */
    1145 void fun_add_ref(fun_node_t *fun)
    1146 {
    1147         atomic_inc(&fun->refcnt);
    1148 }
    1149 
    1150 /** Decrease function node reference count.
    1151  *
    1152  * When the count drops to zero the function node is freed.
    1153  *
    1154  * @param fun   Function node
    1155  */
    1156 void fun_del_ref(fun_node_t *fun)
    1157 {
    1158         if (atomic_predec(&fun->refcnt) == 0)
    1159                 delete_fun_node(fun);
    1160 }
    1161 
    1162980/** Find the function node with the specified handle.
    1163981 *
     
    1170988        unsigned long key = handle;
    1171989        link_t *link;
    1172         fun_node_t *fun;
    1173990       
    1174991        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    1178995                return NULL;
    1179996       
    1180         fun = hash_table_get_instance(link, fun_node_t, devman_fun);
    1181        
    1182         return fun;
     997        return hash_table_get_instance(link, fun_node_t, devman_fun);
    1183998}
    1184999
     
    11941009       
    11951010        fibril_rwlock_read_lock(&tree->rwlock);
    1196        
    11971011        fun = find_fun_node_no_lock(tree, handle);
    1198         if (fun != NULL)
    1199                 fun_add_ref(fun);
    1200        
    12011012        fibril_rwlock_read_unlock(&tree->rwlock);
    12021013       
     
    12061017/** Create and set device's full path in device tree.
    12071018 *
    1208  * @param tree          Device tree
    12091019 * @param node          The device's device node.
    12101020 * @param parent        The parent device node.
     
    12121022 *                      resources etc.).
    12131023 */
    1214 static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
    1215 {
    1216         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1024static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
     1025{
    12171026        assert(fun->name != NULL);
    12181027       
     
    12411050 *
    12421051 * @param tree          The device tree.
    1243  * @param dev           The newly added device node.
    1244  * @param pfun          The parent function node.
     1052 * @param node          The newly added device node.
     1053 * @param dev_name      The name of the newly added device.
     1054 * @param parent        The parent device node.
    12451055 *
    12461056 * @return              True on success, false otherwise (insufficient resources
     
    12491059bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    12501060{
     1061        assert(dev != NULL);
     1062        assert(tree != NULL);
    12511063        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12521064       
     
    12661078}
    12671079
    1268 /** Remove device from device tree.
    1269  *
    1270  * @param tree          Device tree
    1271  * @param dev           Device node
    1272  */
    1273 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
    1274 {
    1275         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1276        
    1277         log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
    1278        
    1279         /* Remove node from the handle-to-node map. */
    1280         unsigned long key = dev->handle;
    1281         hash_table_remove(&tree->devman_devices, &key, 1);
    1282        
    1283         /* Unlink from parent function. */
    1284         dev->pfun->child = NULL;
    1285         dev->pfun = NULL;
    1286        
    1287         dev->state = DEVICE_REMOVED;
    1288 }
    1289 
    1290 
    12911080/** Insert new function into device tree.
    12921081 *
    12931082 * @param tree          The device tree.
    1294  * @param fun           The newly added function node.
    1295  * @param fun_name      The name of the newly added function.
    1296  * @param dev           Owning device node.
     1083 * @param node          The newly added function node.
     1084 * @param dev_name      The name of the newly added function.
     1085 * @param parent        Owning device node.
    12971086 *
    12981087 * @return              True on success, false otherwise (insufficient resources
     
    13041093        fun_node_t *pfun;
    13051094       
     1095        assert(fun != NULL);
     1096        assert(tree != NULL);
    13061097        assert(fun_name != NULL);
    13071098        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    13141105       
    13151106        fun->name = fun_name;
    1316         if (!set_fun_path(tree, fun, pfun)) {
     1107        if (!set_fun_path(fun, pfun)) {
    13171108                return false;
    13181109        }
     
    13291120       
    13301121        return true;
    1331 }
    1332 
    1333 /** Remove function from device tree.
    1334  *
    1335  * @param tree          Device tree
    1336  * @param node          Function node to remove
    1337  */
    1338 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    1339 {
    1340         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1341        
    1342         /* Remove the node from the handle-to-node map. */
    1343         unsigned long key = fun->handle;
    1344         hash_table_remove(&tree->devman_functions, &key, 1);
    1345        
    1346         /* Remove the node from the list of its parent's children. */
    1347         if (fun->dev != NULL)
    1348                 list_remove(&fun->dev_functions);
    1349        
    1350         fun->dev = NULL;
    1351         fun->state = FUN_REMOVED;
    13521122}
    13531123
     
    13711141       
    13721142        fun_node_t *fun = tree->root_node;
    1373         fun_add_ref(fun);
    13741143        /*
    13751144         * Relative path to the function from its parent (but with '/' at the
     
    13781147        char *rel_path = path;
    13791148        char *next_path_elem = NULL;
    1380         bool cont = (rel_path[1] != '\0');
     1149        bool cont = true;
    13811150       
    13821151        while (cont && fun != NULL) {
     
    13891158                }
    13901159               
    1391                 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
    1392                 fun_del_ref(fun);
    1393                 fun = cfun;
     1160                fun = find_node_child(fun, rel_path + 1);
    13941161               
    13951162                if (cont) {
     
    14091176 * Device tree rwlock should be held at least for reading.
    14101177 *
    1411  * @param tree Device tree
    14121178 * @param dev Device the function belongs to.
    14131179 * @param name Function name (not path).
     
    14151181 * @retval NULL No function with given name.
    14161182 */
    1417 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
    1418     const char *name)
    1419 {
     1183fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
     1184{
     1185        assert(dev != NULL);
    14201186        assert(name != NULL);
    1421         assert(fibril_rwlock_is_locked(&tree->rwlock));
    14221187
    14231188        fun_node_t *fun;
    1424 
    1425         list_foreach(dev->functions, link) {
     1189        link_t *link;
     1190
     1191        for (link = dev->functions.next;
     1192            link != &dev->functions;
     1193            link = link->next) {
    14261194                fun = list_get_instance(link, fun_node_t, dev_functions);
    14271195
    1428                 if (str_cmp(name, fun->name) == 0) {
    1429                         fun_add_ref(fun);
     1196                if (str_cmp(name, fun->name) == 0)
    14301197                        return fun;
    1431                 }
    14321198        }
    14331199
     
    14351201}
    14361202
     1203/** Find function node by its class name and index. */
     1204fun_node_t *find_fun_node_by_class(class_list_t *class_list,
     1205    const char *class_name, const char *dev_name)
     1206{
     1207        assert(class_list != NULL);
     1208        assert(class_name != NULL);
     1209        assert(dev_name != NULL);
     1210
     1211        fibril_rwlock_read_lock(&class_list->rwlock);
     1212
     1213        dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);
     1214        if (cl == NULL) {
     1215                fibril_rwlock_read_unlock(&class_list->rwlock);
     1216                return NULL;
     1217        }
     1218
     1219        dev_class_info_t *dev = find_dev_in_class(cl, dev_name);
     1220        if (dev == NULL) {
     1221                fibril_rwlock_read_unlock(&class_list->rwlock);
     1222                return NULL;
     1223        }
     1224
     1225        fun_node_t *fun = dev->fun;
     1226
     1227        fibril_rwlock_read_unlock(&class_list->rwlock);
     1228
     1229        return fun;
     1230}
     1231
     1232
    14371233/** Find child function node with a specified name.
    14381234 *
    14391235 * Device tree rwlock should be held at least for reading.
    14401236 *
    1441  * @param tree          Device tree
    14421237 * @param parent        The parent function node.
    14431238 * @param name          The name of the child function.
    14441239 * @return              The child function node.
    14451240 */
    1446 static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
    1447     const char *name)
    1448 {
    1449         return find_fun_node_in_device(tree, pfun->child, name);
    1450 }
    1451 
    1452 /* loc devices */
    1453 
    1454 fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id)
     1241fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
     1242{
     1243        return find_fun_node_in_device(pfun->child, name);
     1244}
     1245
     1246/* Device classes */
     1247
     1248/** Create device class.
     1249 *
     1250 * @return      Device class.
     1251 */
     1252dev_class_t *create_dev_class(void)
     1253{
     1254        dev_class_t *cl;
     1255       
     1256        cl = (dev_class_t *) malloc(sizeof(dev_class_t));
     1257        if (cl != NULL) {
     1258                memset(cl, 0, sizeof(dev_class_t));
     1259                list_initialize(&cl->devices);
     1260                fibril_mutex_initialize(&cl->mutex);
     1261        }
     1262       
     1263        return cl;
     1264}
     1265
     1266/** Create device class info.
     1267 *
     1268 * @return              Device class info.
     1269 */
     1270dev_class_info_t *create_dev_class_info(void)
     1271{
     1272        dev_class_info_t *info;
     1273       
     1274        info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t));
     1275        if (info != NULL) {
     1276                memset(info, 0, sizeof(dev_class_info_t));
     1277                link_initialize(&info->dev_classes);
     1278                link_initialize(&info->devmap_link);
     1279                link_initialize(&info->link);
     1280        }
     1281       
     1282        return info;
     1283}
     1284
     1285size_t get_new_class_dev_idx(dev_class_t *cl)
     1286{
     1287        size_t dev_idx;
     1288       
     1289        fibril_mutex_lock(&cl->mutex);
     1290        dev_idx = ++cl->curr_dev_idx;
     1291        fibril_mutex_unlock(&cl->mutex);
     1292       
     1293        return dev_idx;
     1294}
     1295
     1296
     1297/** Create unique device name within the class.
     1298 *
     1299 * @param cl            The class.
     1300 * @param base_dev_name Contains the base name for the device if it was
     1301 *                      specified by the driver when it registered the device by
     1302 *                      the class; NULL if driver specified no base name.
     1303 * @return              The unique name for the device within the class.
     1304 */
     1305char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name)
     1306{
     1307        char *dev_name;
     1308        const char *base_name;
     1309       
     1310        if (base_dev_name != NULL)
     1311                base_name = base_dev_name;
     1312        else
     1313                base_name = cl->base_dev_name;
     1314       
     1315        size_t idx = get_new_class_dev_idx(cl);
     1316        asprintf(&dev_name, "%s%zu", base_name, idx);
     1317       
     1318        return dev_name;
     1319}
     1320
     1321/** Add the device function to the class.
     1322 *
     1323 * The device may be added to multiple classes and a class may contain multiple
     1324 * devices. The class and the device are associated with each other by the
     1325 * dev_class_info_t structure.
     1326 *
     1327 * @param dev           The device.
     1328 * @param class         The class.
     1329 * @param base_dev_name The base name of the device within the class if
     1330 *                      specified by the driver, NULL otherwise.
     1331 * @return              dev_class_info_t structure which associates the device
     1332 *                      with the class.
     1333 */
     1334dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl,
     1335    const char *base_dev_name)
     1336{
     1337        dev_class_info_t *info;
     1338
     1339        assert(fun != NULL);
     1340        assert(cl != NULL);
     1341
     1342        info = create_dev_class_info();
     1343
     1344       
     1345        if (info != NULL) {
     1346                info->dev_class = cl;
     1347                info->fun = fun;
     1348               
     1349                /* Add the device to the class. */
     1350                fibril_mutex_lock(&cl->mutex);
     1351                list_append(&info->link, &cl->devices);
     1352                fibril_mutex_unlock(&cl->mutex);
     1353               
     1354                /* Add the class to the device. */
     1355                list_append(&info->dev_classes, &fun->classes);
     1356               
     1357                /* Create unique name for the device within the class. */
     1358                info->dev_name = create_dev_name_for_class(cl, base_dev_name);
     1359        }
     1360       
     1361        return info;
     1362}
     1363
     1364dev_class_t *get_dev_class(class_list_t *class_list, char *class_name)
     1365{
     1366        dev_class_t *cl;
     1367       
     1368        fibril_rwlock_write_lock(&class_list->rwlock);
     1369        cl = find_dev_class_no_lock(class_list, class_name);
     1370        if (cl == NULL) {
     1371                cl = create_dev_class();
     1372                if (cl != NULL) {
     1373                        cl->name = class_name;
     1374                        cl->base_dev_name = "";
     1375                        add_dev_class_no_lock(class_list, cl);
     1376                }
     1377        }
     1378
     1379        fibril_rwlock_write_unlock(&class_list->rwlock);
     1380        return cl;
     1381}
     1382
     1383dev_class_t *find_dev_class_no_lock(class_list_t *class_list,
     1384    const char *class_name)
     1385{
     1386        dev_class_t *cl;
     1387        link_t *link = class_list->classes.next;
     1388       
     1389        while (link != &class_list->classes) {
     1390                cl = list_get_instance(link, dev_class_t, link);
     1391                if (str_cmp(cl->name, class_name) == 0) {
     1392                        return cl;
     1393                }
     1394                link = link->next;
     1395        }
     1396       
     1397        return NULL;
     1398}
     1399
     1400void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl)
     1401{
     1402        list_append(&cl->link, &class_list->classes);
     1403}
     1404
     1405dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name)
     1406{
     1407        assert(dev_class != NULL);
     1408        assert(dev_name != NULL);
     1409
     1410        link_t *link;
     1411        for (link = dev_class->devices.next;
     1412            link != &dev_class->devices;
     1413            link = link->next) {
     1414                dev_class_info_t *dev = list_get_instance(link,
     1415                    dev_class_info_t, link);
     1416
     1417                if (str_cmp(dev->dev_name, dev_name) == 0) {
     1418                        return dev;
     1419                }
     1420        }
     1421
     1422        return NULL;
     1423}
     1424
     1425void init_class_list(class_list_t *class_list)
     1426{
     1427        list_initialize(&class_list->classes);
     1428        fibril_rwlock_initialize(&class_list->rwlock);
     1429        hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1,
     1430            &devmap_devices_class_ops);
     1431}
     1432
     1433
     1434/* Devmap devices */
     1435
     1436fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
    14551437{
    14561438        fun_node_t *fun = NULL;
    14571439        link_t *link;
    1458         unsigned long key = (unsigned long) service_id;
     1440        unsigned long key = (unsigned long) devmap_handle;
    14591441       
    14601442        fibril_rwlock_read_lock(&tree->rwlock);
    1461         link = hash_table_find(&tree->loc_functions, &key);
     1443        link = hash_table_find(&tree->devmap_functions, &key);
     1444        if (link != NULL)
     1445                fun = hash_table_get_instance(link, fun_node_t, devmap_fun);
     1446        fibril_rwlock_read_unlock(&tree->rwlock);
     1447       
     1448        return fun;
     1449}
     1450
     1451fun_node_t *find_devmap_class_function(class_list_t *classes,
     1452    devmap_handle_t devmap_handle)
     1453{
     1454        fun_node_t *fun = NULL;
     1455        dev_class_info_t *cli;
     1456        link_t *link;
     1457        unsigned long key = (unsigned long)devmap_handle;
     1458       
     1459        fibril_rwlock_read_lock(&classes->rwlock);
     1460        link = hash_table_find(&classes->devmap_functions, &key);
    14621461        if (link != NULL) {
    1463                 fun = hash_table_get_instance(link, fun_node_t, loc_fun);
    1464                 fun_add_ref(fun);
    1465         }
    1466         fibril_rwlock_read_unlock(&tree->rwlock);
     1462                cli = hash_table_get_instance(link, dev_class_info_t,
     1463                    devmap_link);
     1464                fun = cli->fun;
     1465        }
     1466        fibril_rwlock_read_unlock(&classes->rwlock);
    14671467       
    14681468        return fun;
    14691469}
    14701470
    1471 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    1472 {
    1473         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1474        
    1475         unsigned long key = (unsigned long) fun->service_id;
    1476         hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
     1471void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli)
     1472{
     1473        unsigned long key = (unsigned long) cli->devmap_handle;
     1474       
     1475        fibril_rwlock_write_lock(&class_list->rwlock);
     1476        hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link);
     1477        fibril_rwlock_write_unlock(&class_list->rwlock);
     1478
     1479        assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL);
     1480}
     1481
     1482void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun)
     1483{
     1484        unsigned long key = (unsigned long) fun->devmap_handle;
     1485        fibril_rwlock_write_lock(&tree->rwlock);
     1486        hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun);
     1487        fibril_rwlock_write_unlock(&tree->rwlock);
    14771488}
    14781489
Note: See TracChangeset for help on using the changeset viewer.