Ignore:
File:
1 edited

Legend:

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

    r80a96d2 r45059d6b  
    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>
     
    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 */
     
    425406        }
    426407       
    427         fun_add_ref(fun);
    428408        insert_fun_node(tree, fun, str_dup(""), NULL);
    429        
    430409        match_id_t *id = create_match_id();
    431410        id->id = str_dup("root");
     
    443422        }
    444423       
    445         dev_add_ref(dev);
    446424        insert_dev_node(tree, dev, fun);
    447425       
     
    489467/** Assign a driver to a device.
    490468 *
    491  * @param tree          Device tree
    492469 * @param node          The device's node in the device tree.
    493470 * @param drv           The driver.
    494471 */
    495 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
     472void attach_driver(dev_node_t *dev, driver_t *drv)
    496473{
    497474        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    499476       
    500477        fibril_mutex_lock(&drv->driver_mutex);
    501         fibril_rwlock_write_lock(&tree->rwlock);
    502478       
    503479        dev->drv = drv;
    504480        list_append(&dev->driver_devices, &drv->devices);
    505481       
    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);
    532482        fibril_mutex_unlock(&drv->driver_mutex);
    533483}
     
    606556        while (link != &driver->devices.head) {
    607557                dev = list_get_instance(link, dev_node_t, driver_devices);
    608                 fibril_rwlock_write_lock(&tree->rwlock);
    609                
    610558                if (dev->passed_to_driver) {
    611                         fibril_rwlock_write_unlock(&tree->rwlock);
    612559                        link = link->next;
    613560                        continue;
    614561                }
    615562
    616                 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
    617                     (int)atomic_get(&dev->refcnt));
    618                 dev_add_ref(dev);
     563                /*
     564                 * We remove the device from the list to allow safe adding
     565                 * of new devices (no one will touch our item this way).
     566                 */
     567                list_remove(link);
    619568
    620569                /*
     
    623572                 */
    624573                fibril_mutex_unlock(&driver->driver_mutex);
    625                 fibril_rwlock_write_unlock(&tree->rwlock);
    626574
    627575                add_device(driver, dev, tree);
    628 
    629                 dev_del_ref(dev);
    630576
    631577                /*
     
    634580                 */
    635581                fibril_mutex_lock(&driver->driver_mutex);
     582
     583                /*
     584                 * Insert the device back.
     585                 * The order is not relevant here so no harm is done
     586                 * (actually, the order would be preserved in most cases).
     587                 */
     588                list_append(link, &driver->devices);
    636589
    637590                /*
     
    726679        char *loc_name = NULL;
    727680       
    728         assert(fibril_rwlock_is_locked(&tree->rwlock));
    729        
    730681        asprintf(&loc_name, "%s", fun->pathname);
    731682        if (loc_name == NULL)
     
    775726       
    776727        ipc_call_t answer;
    777         aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
     728        aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
    778729            parent_handle, &answer);
    779730       
     
    832783       
    833784        /* Attach the driver to the device. */
    834         attach_driver(tree, dev, drv);
     785        attach_driver(dev, drv);
    835786       
    836787        fibril_mutex_lock(&drv->driver_mutex);
     
    846797                add_device(drv, dev, tree);
    847798       
    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);
    856799        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 
    959800}
    960801
     
    985826        if (!create_root_nodes(tree))
    986827                return false;
    987    
     828
    988829        /* 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;
     830        return assign_driver(tree->root_node->child, drivers_list, tree);
    995831}
    996832
     
    1003839dev_node_t *create_dev_node(void)
    1004840{
    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;
     841        dev_node_t *res = malloc(sizeof(dev_node_t));
     842       
     843        if (res != NULL) {
     844                memset(res, 0, sizeof(dev_node_t));
     845                list_initialize(&res->functions);
     846                link_initialize(&res->driver_devices);
     847                link_initialize(&res->devman_dev);
     848        }
     849       
     850        return res;
    1017851}
    1018852
     
    1030864}
    1031865
    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 
    1054866/** Find the device node structure of the device witch has the specified handle.
    1055867 *
     
    1081893        fibril_rwlock_read_lock(&tree->rwlock);
    1082894        dev = find_dev_node_no_lock(tree, handle);
    1083         if (dev != NULL)
    1084                 dev_add_ref(dev);
    1085        
    1086895        fibril_rwlock_read_unlock(&tree->rwlock);
    1087896       
     
    1111920                    list_get_instance(item, fun_node_t, dev_functions);
    1112921
    1113                 if (pos < buf_cnt) {
     922                if (pos < buf_cnt)
    1114923                        hdl_buf[pos] = fun->handle;
    1115                 }
    1116 
    1117924                pos++;
    1118925        }
     
    1130937fun_node_t *create_fun_node(void)
    1131938{
    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;
     939        fun_node_t *res = malloc(sizeof(fun_node_t));
     940       
     941        if (res != NULL) {
     942                memset(res, 0, sizeof(fun_node_t));
     943                link_initialize(&res->dev_functions);
     944                list_initialize(&res->match_ids.ids);
     945                link_initialize(&res->devman_fun);
     946                link_initialize(&res->loc_fun);
     947        }
     948       
     949        return res;
    1146950}
    1147951
     
    1161965}
    1162966
    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 
    1184967/** Find the function node with the specified handle.
    1185968 *
     
    1192975        unsigned long key = handle;
    1193976        link_t *link;
    1194         fun_node_t *fun;
    1195977       
    1196978        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    1200982                return NULL;
    1201983       
    1202         fun = hash_table_get_instance(link, fun_node_t, devman_fun);
    1203        
    1204         return fun;
     984        return hash_table_get_instance(link, fun_node_t, devman_fun);
    1205985}
    1206986
     
    1216996       
    1217997        fibril_rwlock_read_lock(&tree->rwlock);
    1218        
    1219998        fun = find_fun_node_no_lock(tree, handle);
    1220         if (fun != NULL)
    1221                 fun_add_ref(fun);
    1222        
    1223999        fibril_rwlock_read_unlock(&tree->rwlock);
    12241000       
     
    12281004/** Create and set device's full path in device tree.
    12291005 *
    1230  * @param tree          Device tree
    12311006 * @param node          The device's device node.
    12321007 * @param parent        The parent device node.
     
    12341009 *                      resources etc.).
    12351010 */
    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));
     1011static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
     1012{
    12391013        assert(fun->name != NULL);
    12401014       
     
    12631037 *
    12641038 * @param tree          The device tree.
    1265  * @param dev           The newly added device node.
    1266  * @param pfun          The parent function node.
     1039 * @param node          The newly added device node.
     1040 * @param dev_name      The name of the newly added device.
     1041 * @param parent        The parent device node.
    12671042 *
    12681043 * @return              True on success, false otherwise (insufficient resources
     
    12711046bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    12721047{
     1048        assert(dev != NULL);
     1049        assert(tree != NULL);
    12731050        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12741051       
     
    12881065}
    12891066
    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 
    13131067/** Insert new function into device tree.
    13141068 *
    13151069 * @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.
     1070 * @param node          The newly added function node.
     1071 * @param dev_name      The name of the newly added function.
     1072 * @param parent        Owning device node.
    13191073 *
    13201074 * @return              True on success, false otherwise (insufficient resources
     
    13261080        fun_node_t *pfun;
    13271081       
     1082        assert(fun != NULL);
     1083        assert(tree != NULL);
    13281084        assert(fun_name != NULL);
    13291085        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    13361092       
    13371093        fun->name = fun_name;
    1338         if (!set_fun_path(tree, fun, pfun)) {
     1094        if (!set_fun_path(fun, pfun)) {
    13391095                return false;
    13401096        }
     
    13601116void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    13611117{
     1118        assert(tree != NULL);
     1119        assert(fun != NULL);
    13621120        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    13631121       
     
    13691127        if (fun->dev != NULL)
    13701128                list_remove(&fun->dev_functions);
    1371        
    1372         fun->dev = NULL;
    1373         fun->state = FUN_REMOVED;
    13741129}
    13751130
     
    13931148       
    13941149        fun_node_t *fun = tree->root_node;
    1395         fun_add_ref(fun);
    13961150        /*
    13971151         * Relative path to the function from its parent (but with '/' at the
     
    14111165                }
    14121166               
    1413                 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
    1414                 fun_del_ref(fun);
    1415                 fun = cfun;
     1167                fun = find_node_child(fun, rel_path + 1);
    14161168               
    14171169                if (cont) {
     
    14311183 * Device tree rwlock should be held at least for reading.
    14321184 *
    1433  * @param tree Device tree
    14341185 * @param dev Device the function belongs to.
    14351186 * @param name Function name (not path).
     
    14371188 * @retval NULL No function with given name.
    14381189 */
    1439 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
    1440     const char *name)
    1441 {
     1190fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
     1191{
     1192        assert(dev != NULL);
    14421193        assert(name != NULL);
    1443         assert(fibril_rwlock_is_locked(&tree->rwlock));
    14441194
    14451195        fun_node_t *fun;
     
    14481198                fun = list_get_instance(link, fun_node_t, dev_functions);
    14491199
    1450                 if (str_cmp(name, fun->name) == 0) {
    1451                         fun_add_ref(fun);
     1200                if (str_cmp(name, fun->name) == 0)
    14521201                        return fun;
    1453                 }
    14541202        }
    14551203
     
    14611209 * Device tree rwlock should be held at least for reading.
    14621210 *
    1463  * @param tree          Device tree
    14641211 * @param parent        The parent function node.
    14651212 * @param name          The name of the child function.
    14661213 * @return              The child function node.
    14671214 */
    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);
     1215fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
     1216{
     1217        return find_fun_node_in_device(pfun->child, name);
    14721218}
    14731219
     
    14821228        fibril_rwlock_read_lock(&tree->rwlock);
    14831229        link = hash_table_find(&tree->loc_functions, &key);
    1484         if (link != NULL) {
     1230        if (link != NULL)
    14851231                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
    1486                 fun_add_ref(fun);
    1487         }
    14881232        fibril_rwlock_read_unlock(&tree->rwlock);
    14891233       
     
    14931237void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    14941238{
    1495         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1496        
    14971239        unsigned long key = (unsigned long) fun->service_id;
     1240        fibril_rwlock_write_lock(&tree->rwlock);
    14981241        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
     1242        fibril_rwlock_write_unlock(&tree->rwlock);
    14991243}
    15001244
Note: See TracChangeset for help on using the changeset viewer.