Ignore:
File:
1 edited

Legend:

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

    rc1a0488 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 
    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 
    937800}
    938801
     
    963826        if (!create_root_nodes(tree))
    964827                return false;
    965    
     828
    966829        /* 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;
     830        return assign_driver(tree->root_node->child, drivers_list, tree);
    973831}
    974832
     
    981839dev_node_t *create_dev_node(void)
    982840{
    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;
     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;
    995851}
    996852
     
    1008864}
    1009865
    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 
    1032866/** Find the device node structure of the device witch has the specified handle.
    1033867 *
     
    1059893        fibril_rwlock_read_lock(&tree->rwlock);
    1060894        dev = find_dev_node_no_lock(tree, handle);
    1061         if (dev != NULL)
    1062                 dev_add_ref(dev);
    1063        
    1064895        fibril_rwlock_read_unlock(&tree->rwlock);
    1065896       
     
    1089920                    list_get_instance(item, fun_node_t, dev_functions);
    1090921
    1091                 if (pos < buf_cnt) {
     922                if (pos < buf_cnt)
    1092923                        hdl_buf[pos] = fun->handle;
    1093                 }
    1094 
    1095924                pos++;
    1096925        }
     
    1108937fun_node_t *create_fun_node(void)
    1109938{
    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;
     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;
    1124950}
    1125951
     
    1139965}
    1140966
    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 
    1162967/** Find the function node with the specified handle.
    1163968 *
     
    1170975        unsigned long key = handle;
    1171976        link_t *link;
    1172         fun_node_t *fun;
    1173977       
    1174978        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    1178982                return NULL;
    1179983       
    1180         fun = hash_table_get_instance(link, fun_node_t, devman_fun);
    1181        
    1182         return fun;
     984        return hash_table_get_instance(link, fun_node_t, devman_fun);
    1183985}
    1184986
     
    1194996       
    1195997        fibril_rwlock_read_lock(&tree->rwlock);
    1196        
    1197998        fun = find_fun_node_no_lock(tree, handle);
    1198         if (fun != NULL)
    1199                 fun_add_ref(fun);
    1200        
    1201999        fibril_rwlock_read_unlock(&tree->rwlock);
    12021000       
     
    12061004/** Create and set device's full path in device tree.
    12071005 *
    1208  * @param tree          Device tree
    12091006 * @param node          The device's device node.
    12101007 * @param parent        The parent device node.
     
    12121009 *                      resources etc.).
    12131010 */
    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));
     1011static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
     1012{
    12171013        assert(fun->name != NULL);
    12181014       
     
    12411037 *
    12421038 * @param tree          The device tree.
    1243  * @param dev           The newly added device node.
    1244  * @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.
    12451042 *
    12461043 * @return              True on success, false otherwise (insufficient resources
     
    12491046bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    12501047{
     1048        assert(dev != NULL);
     1049        assert(tree != NULL);
    12511050        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12521051       
     
    12661065}
    12671066
    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 
    12911067/** Insert new function into device tree.
    12921068 *
    12931069 * @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.
     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.
    12971073 *
    12981074 * @return              True on success, false otherwise (insufficient resources
     
    13041080        fun_node_t *pfun;
    13051081       
     1082        assert(fun != NULL);
     1083        assert(tree != NULL);
    13061084        assert(fun_name != NULL);
    13071085        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    13141092       
    13151093        fun->name = fun_name;
    1316         if (!set_fun_path(tree, fun, pfun)) {
     1094        if (!set_fun_path(fun, pfun)) {
    13171095                return false;
    13181096        }
     
    13381116void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    13391117{
     1118        assert(tree != NULL);
     1119        assert(fun != NULL);
    13401120        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    13411121       
     
    13471127        if (fun->dev != NULL)
    13481128                list_remove(&fun->dev_functions);
    1349        
    1350         fun->dev = NULL;
    1351         fun->state = FUN_REMOVED;
    13521129}
    13531130
     
    13711148       
    13721149        fun_node_t *fun = tree->root_node;
    1373         fun_add_ref(fun);
    13741150        /*
    13751151         * Relative path to the function from its parent (but with '/' at the
     
    13891165                }
    13901166               
    1391                 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
    1392                 fun_del_ref(fun);
    1393                 fun = cfun;
     1167                fun = find_node_child(fun, rel_path + 1);
    13941168               
    13951169                if (cont) {
     
    14091183 * Device tree rwlock should be held at least for reading.
    14101184 *
    1411  * @param tree Device tree
    14121185 * @param dev Device the function belongs to.
    14131186 * @param name Function name (not path).
     
    14151188 * @retval NULL No function with given name.
    14161189 */
    1417 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
    1418     const char *name)
    1419 {
     1190fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
     1191{
     1192        assert(dev != NULL);
    14201193        assert(name != NULL);
    1421         assert(fibril_rwlock_is_locked(&tree->rwlock));
    14221194
    14231195        fun_node_t *fun;
     
    14261198                fun = list_get_instance(link, fun_node_t, dev_functions);
    14271199
    1428                 if (str_cmp(name, fun->name) == 0) {
    1429                         fun_add_ref(fun);
     1200                if (str_cmp(name, fun->name) == 0)
    14301201                        return fun;
    1431                 }
    14321202        }
    14331203
     
    14391209 * Device tree rwlock should be held at least for reading.
    14401210 *
    1441  * @param tree          Device tree
    14421211 * @param parent        The parent function node.
    14431212 * @param name          The name of the child function.
    14441213 * @return              The child function node.
    14451214 */
    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);
     1215fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
     1216{
     1217        return find_fun_node_in_device(pfun->child, name);
    14501218}
    14511219
     
    14601228        fibril_rwlock_read_lock(&tree->rwlock);
    14611229        link = hash_table_find(&tree->loc_functions, &key);
    1462         if (link != NULL) {
     1230        if (link != NULL)
    14631231                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
    1464                 fun_add_ref(fun);
    1465         }
    14661232        fibril_rwlock_read_unlock(&tree->rwlock);
    14671233       
     
    14711237void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    14721238{
    1473         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1474        
    14751239        unsigned long key = (unsigned long) fun->service_id;
     1240        fibril_rwlock_write_lock(&tree->rwlock);
    14761241        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
     1242        fibril_rwlock_write_unlock(&tree->rwlock);
    14771243}
    14781244
Note: See TracChangeset for help on using the changeset viewer.