Ignore:
File:
1 edited

Legend:

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

    r609243f4 rc7bbf029  
    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       
     
    593564        dev_node_t *dev;
    594565        link_t *link;
     566        int phone;
    595567
    596568        log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
     
    598570
    599571        fibril_mutex_lock(&driver->driver_mutex);
     572
     573        phone = async_connect_me_to(driver->phone, DRIVER_DEVMAN, 0, 0);
     574
     575        if (phone < 0) {
     576                fibril_mutex_unlock(&driver->driver_mutex);
     577                return;
     578        }
    600579
    601580        /*
     
    603582         * that has not been passed to the driver.
    604583         */
    605         link = driver->devices.head.next;
    606         while (link != &driver->devices.head) {
     584        link = driver->devices.next;
     585        while (link != &driver->devices) {
    607586                dev = list_get_instance(link, dev_node_t, driver_devices);
    608                 fibril_rwlock_write_lock(&tree->rwlock);
    609                
    610587                if (dev->passed_to_driver) {
    611                         fibril_rwlock_write_unlock(&tree->rwlock);
    612588                        link = link->next;
    613589                        continue;
    614590                }
    615591
    616                 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
    617                     (int)atomic_get(&dev->refcnt));
    618                 dev_add_ref(dev);
     592                /*
     593                 * We remove the device from the list to allow safe adding
     594                 * of new devices (no one will touch our item this way).
     595                 */
     596                list_remove(link);
    619597
    620598                /*
     
    623601                 */
    624602                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);
     603
     604                add_device(phone, driver, dev, tree);
    630605
    631606                /*
     
    636611
    637612                /*
     613                 * Insert the device back.
     614                 * The order is not relevant here so no harm is done
     615                 * (actually, the order would be preserved in most cases).
     616                 */
     617                list_append(link, &driver->devices);
     618
     619                /*
    638620                 * Restart the cycle to go through all devices again.
    639621                 */
    640                 link = driver->devices.head.next;
    641         }
     622                link = driver->devices.next;
     623        }
     624
     625        async_hangup(phone);
    642626
    643627        /*
     
    689673        list_initialize(&drv->devices);
    690674        fibril_mutex_initialize(&drv->driver_mutex);
    691         drv->sess = NULL;
     675        drv->phone = -1;
    692676}
    693677
     
    720704}
    721705
    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)
     706/** Create devmap path and name for the function. */
     707void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
     708{
     709        char *devmap_pathname = NULL;
     710        char *devmap_name = NULL;
     711       
     712        asprintf(&devmap_name, "%s", fun->pathname);
     713        if (devmap_name == NULL)
    732714                return;
    733715       
    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);
     716        replace_char(devmap_name, '/', DEVMAP_SEPARATOR);
     717       
     718        asprintf(&devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,
     719            devmap_name);
     720        if (devmap_pathname == NULL) {
     721                free(devmap_name);
    740722                return;
    741723        }
    742724       
    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);
     725        devmap_device_register_with_iface(devmap_pathname,
     726            &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
     727       
     728        tree_add_devmap_function(tree, fun);
     729       
     730        free(devmap_name);
     731        free(devmap_pathname);
    750732}
    751733
     
    755737 * @param node          The device's node in the device tree.
    756738 */
    757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
     739void add_device(int phone, driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
    758740{
    759741        /*
     
    764746            drv->name, dev->pfun->name);
    765747       
     748        sysarg_t rc;
     749        ipc_call_t answer;
     750       
    766751        /* Send the device to the driver. */
    767752        devman_handle_t parent_handle;
     
    771756                parent_handle = 0;
    772757        }
    773        
    774         async_exch_t *exch = async_exchange_begin(drv->sess);
    775        
    776         ipc_call_t answer;
    777         aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
     758
     759        aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, dev->handle,
    778760            parent_handle, &answer);
    779761       
    780         /* Send the device name to the driver. */
    781         sysarg_t rc = async_data_write_start(exch, dev->pfun->name,
     762        /* Send the device's name to the driver. */
     763        rc = async_data_write_start(phone, dev->pfun->name,
    782764            str_size(dev->pfun->name) + 1);
    783        
    784         async_exchange_end(exch);
    785        
    786765        if (rc != EOK) {
    787766                /* TODO handle error */
     
    794773        case EOK:
    795774                dev->state = DEVICE_USABLE;
    796                 exch = async_exchange_begin(drv->sess);
    797                 async_msg_1(exch, DRIVER_DEV_ADDED, dev->handle);
    798                 async_exchange_end(exch);
    799775                break;
    800776        case ENOENT:
     
    835811       
    836812        /* Attach the driver to the device. */
    837         attach_driver(tree, dev, drv);
     813        attach_driver(dev, drv);
    838814       
    839815        fibril_mutex_lock(&drv->driver_mutex);
     
    845821        fibril_mutex_unlock(&drv->driver_mutex);
    846822
    847         /* Notify the driver about the new device. */
    848         if (is_running)
    849                 add_device(drv, dev, tree);
    850        
    851         fibril_mutex_lock(&drv->driver_mutex);
    852         fibril_mutex_unlock(&drv->driver_mutex);
    853 
    854         fibril_rwlock_write_lock(&tree->rwlock);
    855         if (dev->pfun != NULL) {
    856                 dev->pfun->state = FUN_ON_LINE;
    857         }
    858         fibril_rwlock_write_unlock(&tree->rwlock);
     823        if (is_running) {
     824                /* Notify the driver about the new device. */
     825                int phone = async_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0);
     826                if (phone >= 0) {
     827                        add_device(phone, drv, dev, tree);
     828                        async_hangup(phone);
     829                }
     830        }
     831       
    859832        return true;
    860 }
    861 
    862 int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
    863 {
    864         async_exch_t *exch;
    865         sysarg_t retval;
    866         driver_t *drv;
    867         devman_handle_t handle;
    868        
    869         assert(dev != NULL);
    870        
    871         log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
    872        
    873         fibril_rwlock_read_lock(&tree->rwlock);
    874         drv = dev->drv;
    875         handle = dev->handle;
    876         fibril_rwlock_read_unlock(&tree->rwlock);
    877        
    878         exch = async_exchange_begin(drv->sess);
    879         retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
    880         async_exchange_end(exch);
    881        
    882         return retval;
    883 }
    884 
    885 int driver_dev_gone(dev_tree_t *tree, dev_node_t *dev)
    886 {
    887         async_exch_t *exch;
    888         sysarg_t retval;
    889         driver_t *drv;
    890         devman_handle_t handle;
    891        
    892         assert(dev != NULL);
    893        
    894         log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev);
    895        
    896         fibril_rwlock_read_lock(&tree->rwlock);
    897         drv = dev->drv;
    898         handle = dev->handle;
    899         fibril_rwlock_read_unlock(&tree->rwlock);
    900        
    901         exch = async_exchange_begin(drv->sess);
    902         retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle);
    903         async_exchange_end(exch);
    904        
    905         return retval;
    906 }
    907 
    908 int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
    909 {
    910         async_exch_t *exch;
    911         sysarg_t retval;
    912         driver_t *drv;
    913         devman_handle_t handle;
    914        
    915         log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
    916 
    917         fibril_rwlock_read_lock(&tree->rwlock);
    918        
    919         if (fun->dev == NULL) {
    920                 /* XXX root function? */
    921                 fibril_rwlock_read_unlock(&tree->rwlock);
    922                 return EINVAL;
    923         }
    924        
    925         drv = fun->dev->drv;
    926         handle = fun->handle;
    927         fibril_rwlock_read_unlock(&tree->rwlock);
    928        
    929         exch = async_exchange_begin(drv->sess);
    930         retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
    931         loc_exchange_end(exch);
    932        
    933         return retval;
    934 }
    935 
    936 int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
    937 {
    938         async_exch_t *exch;
    939         sysarg_t retval;
    940         driver_t *drv;
    941         devman_handle_t handle;
    942        
    943         log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
    944 
    945         fibril_rwlock_read_lock(&tree->rwlock);
    946         if (fun->dev == NULL) {
    947                 /* XXX root function? */
    948                 fibril_rwlock_read_unlock(&tree->rwlock);
    949                 return EINVAL;
    950         }
    951        
    952         drv = fun->dev->drv;
    953         handle = fun->handle;
    954         fibril_rwlock_read_unlock(&tree->rwlock);
    955        
    956         exch = async_exchange_begin(drv->sess);
    957         retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
    958         loc_exchange_end(exch);
    959        
    960         return retval;
    961 
    962833}
    963834
     
    980851        hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
    981852            &devman_functions_ops);
    982         hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
    983             &loc_devices_ops);
     853        hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
     854            &devmap_devices_ops);
    984855       
    985856        fibril_rwlock_initialize(&tree->rwlock);
     
    988859        if (!create_root_nodes(tree))
    989860                return false;
    990    
     861
    991862        /* Find suitable driver and start it. */
    992         dev_node_t *rdev = tree->root_node->child;
    993         dev_add_ref(rdev);
    994         int rc = assign_driver(rdev, drivers_list, tree);
    995         dev_del_ref(rdev);
    996        
    997         return rc;
     863        return assign_driver(tree->root_node->child, drivers_list, tree);
    998864}
    999865
     
    1006872dev_node_t *create_dev_node(void)
    1007873{
    1008         dev_node_t *dev;
    1009        
    1010         dev = calloc(1, sizeof(dev_node_t));
    1011         if (dev == NULL)
    1012                 return NULL;
    1013        
    1014         atomic_set(&dev->refcnt, 0);
    1015         list_initialize(&dev->functions);
    1016         link_initialize(&dev->driver_devices);
    1017         link_initialize(&dev->devman_dev);
    1018        
    1019         return dev;
     874        dev_node_t *res = malloc(sizeof(dev_node_t));
     875       
     876        if (res != NULL) {
     877                memset(res, 0, sizeof(dev_node_t));
     878                list_initialize(&res->functions);
     879                link_initialize(&res->driver_devices);
     880                link_initialize(&res->devman_dev);
     881        }
     882       
     883        return res;
    1020884}
    1021885
     
    1033897}
    1034898
    1035 /** Increase device node reference count.
    1036  *
    1037  * @param dev   Device node
    1038  */
    1039 void dev_add_ref(dev_node_t *dev)
    1040 {
    1041         atomic_inc(&dev->refcnt);
    1042 }
    1043 
    1044 /** Decrease device node reference count.
    1045  *
    1046  * When the count drops to zero the device node is freed.
    1047  *
    1048  * @param dev   Device node
    1049  */
    1050 void dev_del_ref(dev_node_t *dev)
    1051 {
    1052         if (atomic_predec(&dev->refcnt) == 0)
    1053                 delete_dev_node(dev);
    1054 }
    1055 
    1056 
    1057899/** Find the device node structure of the device witch has the specified handle.
    1058900 *
     
    1069911       
    1070912        link = hash_table_find(&tree->devman_devices, &key);
    1071         if (link == NULL)
    1072                 return NULL;
    1073        
    1074913        return hash_table_get_instance(link, dev_node_t, devman_dev);
    1075914}
     
    1087926        fibril_rwlock_read_lock(&tree->rwlock);
    1088927        dev = find_dev_node_no_lock(tree, handle);
    1089         if (dev != NULL)
    1090                 dev_add_ref(dev);
    1091        
    1092928        fibril_rwlock_read_unlock(&tree->rwlock);
    1093929       
     
    1095931}
    1096932
    1097 /** Get list of device functions. */
    1098 int dev_get_functions(dev_tree_t *tree, dev_node_t *dev,
    1099     devman_handle_t *hdl_buf, size_t buf_size, size_t *act_size)
    1100 {
    1101         size_t act_cnt;
    1102         size_t buf_cnt;
    1103 
    1104         assert(fibril_rwlock_is_locked(&tree->rwlock));
    1105 
    1106         buf_cnt = buf_size / sizeof(devman_handle_t);
    1107 
    1108         act_cnt = list_count(&dev->functions);
    1109         *act_size = act_cnt * sizeof(devman_handle_t);
    1110 
    1111         if (buf_size % sizeof(devman_handle_t) != 0)
    1112                 return EINVAL;
    1113 
    1114         size_t pos = 0;
    1115         list_foreach(dev->functions, item) {
    1116                 fun_node_t *fun =
    1117                     list_get_instance(item, fun_node_t, dev_functions);
    1118 
    1119                 if (pos < buf_cnt) {
    1120                         hdl_buf[pos] = fun->handle;
    1121                 }
    1122 
    1123                 pos++;
    1124         }
    1125 
    1126         return EOK;
    1127 }
    1128 
    1129 
    1130933/* Function nodes */
    1131934
     
    1136939fun_node_t *create_fun_node(void)
    1137940{
    1138         fun_node_t *fun;
    1139 
    1140         fun = calloc(1, sizeof(fun_node_t));
    1141         if (fun == NULL)
    1142                 return NULL;
    1143        
    1144         fun->state = FUN_INIT;
    1145         atomic_set(&fun->refcnt, 0);
    1146         link_initialize(&fun->dev_functions);
    1147         list_initialize(&fun->match_ids.ids);
    1148         link_initialize(&fun->devman_fun);
    1149         link_initialize(&fun->loc_fun);
    1150        
    1151         return fun;
     941        fun_node_t *res = malloc(sizeof(fun_node_t));
     942       
     943        if (res != NULL) {
     944                memset(res, 0, sizeof(fun_node_t));
     945                link_initialize(&res->dev_functions);
     946                list_initialize(&res->match_ids.ids);
     947                list_initialize(&res->classes);
     948                link_initialize(&res->devman_fun);
     949                link_initialize(&res->devmap_fun);
     950        }
     951       
     952        return res;
    1152953}
    1153954
     
    1167968}
    1168969
    1169 /** Increase function node reference count.
    1170  *
    1171  * @param fun   Function node
    1172  */
    1173 void fun_add_ref(fun_node_t *fun)
    1174 {
    1175         atomic_inc(&fun->refcnt);
    1176 }
    1177 
    1178 /** Decrease function node reference count.
    1179  *
    1180  * When the count drops to zero the function node is freed.
    1181  *
    1182  * @param fun   Function node
    1183  */
    1184 void fun_del_ref(fun_node_t *fun)
    1185 {
    1186         if (atomic_predec(&fun->refcnt) == 0)
    1187                 delete_fun_node(fun);
    1188 }
    1189 
    1190970/** Find the function node with the specified handle.
    1191971 *
     
    1198978        unsigned long key = handle;
    1199979        link_t *link;
    1200         fun_node_t *fun;
    1201980       
    1202981        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    1206985                return NULL;
    1207986       
    1208         fun = hash_table_get_instance(link, fun_node_t, devman_fun);
    1209        
    1210         return fun;
     987        return hash_table_get_instance(link, fun_node_t, devman_fun);
    1211988}
    1212989
     
    1222999       
    12231000        fibril_rwlock_read_lock(&tree->rwlock);
    1224        
    12251001        fun = find_fun_node_no_lock(tree, handle);
    1226         if (fun != NULL)
    1227                 fun_add_ref(fun);
    1228        
    12291002        fibril_rwlock_read_unlock(&tree->rwlock);
    12301003       
     
    12341007/** Create and set device's full path in device tree.
    12351008 *
    1236  * @param tree          Device tree
    12371009 * @param node          The device's device node.
    12381010 * @param parent        The parent device node.
     
    12401012 *                      resources etc.).
    12411013 */
    1242 static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
    1243 {
    1244         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1014static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
     1015{
    12451016        assert(fun->name != NULL);
    12461017       
     
    12691040 *
    12701041 * @param tree          The device tree.
    1271  * @param dev           The newly added device node.
    1272  * @param pfun          The parent function node.
     1042 * @param node          The newly added device node.
     1043 * @param dev_name      The name of the newly added device.
     1044 * @param parent        The parent device node.
    12731045 *
    12741046 * @return              True on success, false otherwise (insufficient resources
     
    12771049bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    12781050{
     1051        assert(dev != NULL);
     1052        assert(tree != NULL);
    12791053        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12801054       
     
    12941068}
    12951069
    1296 /** Remove device from device tree.
    1297  *
    1298  * @param tree          Device tree
    1299  * @param dev           Device node
    1300  */
    1301 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
    1302 {
    1303         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1304        
    1305         log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
    1306        
    1307         /* Remove node from the handle-to-node map. */
    1308         unsigned long key = dev->handle;
    1309         hash_table_remove(&tree->devman_devices, &key, 1);
    1310        
    1311         /* Unlink from parent function. */
    1312         dev->pfun->child = NULL;
    1313         dev->pfun = NULL;
    1314        
    1315         dev->state = DEVICE_REMOVED;
    1316 }
    1317 
    1318 
    13191070/** Insert new function into device tree.
    13201071 *
    13211072 * @param tree          The device tree.
    1322  * @param fun           The newly added function node.
    1323  * @param fun_name      The name of the newly added function.
    1324  * @param dev           Owning device node.
     1073 * @param node          The newly added function node.
     1074 * @param dev_name      The name of the newly added function.
     1075 * @param parent        Owning device node.
    13251076 *
    13261077 * @return              True on success, false otherwise (insufficient resources
     
    13321083        fun_node_t *pfun;
    13331084       
     1085        assert(fun != NULL);
     1086        assert(tree != NULL);
    13341087        assert(fun_name != NULL);
    13351088        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    13421095       
    13431096        fun->name = fun_name;
    1344         if (!set_fun_path(tree, fun, pfun)) {
     1097        if (!set_fun_path(fun, pfun)) {
    13451098                return false;
    13461099        }
     
    13571110       
    13581111        return true;
    1359 }
    1360 
    1361 /** Remove function from device tree.
    1362  *
    1363  * @param tree          Device tree
    1364  * @param node          Function node to remove
    1365  */
    1366 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    1367 {
    1368         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1369        
    1370         /* Remove the node from the handle-to-node map. */
    1371         unsigned long key = fun->handle;
    1372         hash_table_remove(&tree->devman_functions, &key, 1);
    1373        
    1374         /* Remove the node from the list of its parent's children. */
    1375         if (fun->dev != NULL)
    1376                 list_remove(&fun->dev_functions);
    1377        
    1378         fun->dev = NULL;
    1379         fun->state = FUN_REMOVED;
    13801112}
    13811113
     
    13991131       
    14001132        fun_node_t *fun = tree->root_node;
    1401         fun_add_ref(fun);
    14021133        /*
    14031134         * Relative path to the function from its parent (but with '/' at the
     
    14061137        char *rel_path = path;
    14071138        char *next_path_elem = NULL;
    1408         bool cont = (rel_path[1] != '\0');
     1139        bool cont = true;
    14091140       
    14101141        while (cont && fun != NULL) {
     
    14171148                }
    14181149               
    1419                 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
    1420                 fun_del_ref(fun);
    1421                 fun = cfun;
     1150                fun = find_node_child(fun, rel_path + 1);
    14221151               
    14231152                if (cont) {
     
    14371166 * Device tree rwlock should be held at least for reading.
    14381167 *
    1439  * @param tree Device tree
    14401168 * @param dev Device the function belongs to.
    14411169 * @param name Function name (not path).
     
    14431171 * @retval NULL No function with given name.
    14441172 */
    1445 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
    1446     const char *name)
    1447 {
     1173fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
     1174{
     1175        assert(dev != NULL);
    14481176        assert(name != NULL);
    1449         assert(fibril_rwlock_is_locked(&tree->rwlock));
    14501177
    14511178        fun_node_t *fun;
    1452 
    1453         list_foreach(dev->functions, link) {
     1179        link_t *link;
     1180
     1181        for (link = dev->functions.next;
     1182            link != &dev->functions;
     1183            link = link->next) {
    14541184                fun = list_get_instance(link, fun_node_t, dev_functions);
    14551185
    1456                 if (str_cmp(name, fun->name) == 0) {
    1457                         fun_add_ref(fun);
     1186                if (str_cmp(name, fun->name) == 0)
    14581187                        return fun;
    1459                 }
    14601188        }
    14611189
     
    14631191}
    14641192
     1193/** Find function node by its class name and index. */
     1194fun_node_t *find_fun_node_by_class(class_list_t *class_list,
     1195    const char *class_name, const char *dev_name)
     1196{
     1197        assert(class_list != NULL);
     1198        assert(class_name != NULL);
     1199        assert(dev_name != NULL);
     1200
     1201        fibril_rwlock_read_lock(&class_list->rwlock);
     1202
     1203        dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);
     1204        if (cl == NULL) {
     1205                fibril_rwlock_read_unlock(&class_list->rwlock);
     1206                return NULL;
     1207        }
     1208
     1209        dev_class_info_t *dev = find_dev_in_class(cl, dev_name);
     1210        if (dev == NULL) {
     1211                fibril_rwlock_read_unlock(&class_list->rwlock);
     1212                return NULL;
     1213        }
     1214
     1215        fun_node_t *fun = dev->fun;
     1216
     1217        fibril_rwlock_read_unlock(&class_list->rwlock);
     1218
     1219        return fun;
     1220}
     1221
     1222
    14651223/** Find child function node with a specified name.
    14661224 *
    14671225 * Device tree rwlock should be held at least for reading.
    14681226 *
    1469  * @param tree          Device tree
    14701227 * @param parent        The parent function node.
    14711228 * @param name          The name of the child function.
    14721229 * @return              The child function node.
    14731230 */
    1474 static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
    1475     const char *name)
    1476 {
    1477         return find_fun_node_in_device(tree, pfun->child, name);
    1478 }
    1479 
    1480 /* loc devices */
    1481 
    1482 fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id)
     1231fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
     1232{
     1233        return find_fun_node_in_device(pfun->child, name);
     1234}
     1235
     1236/* Device classes */
     1237
     1238/** Create device class.
     1239 *
     1240 * @return      Device class.
     1241 */
     1242dev_class_t *create_dev_class(void)
     1243{
     1244        dev_class_t *cl;
     1245       
     1246        cl = (dev_class_t *) malloc(sizeof(dev_class_t));
     1247        if (cl != NULL) {
     1248                memset(cl, 0, sizeof(dev_class_t));
     1249                list_initialize(&cl->devices);
     1250                fibril_mutex_initialize(&cl->mutex);
     1251        }
     1252       
     1253        return cl;
     1254}
     1255
     1256/** Create device class info.
     1257 *
     1258 * @return              Device class info.
     1259 */
     1260dev_class_info_t *create_dev_class_info(void)
     1261{
     1262        dev_class_info_t *info;
     1263       
     1264        info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t));
     1265        if (info != NULL) {
     1266                memset(info, 0, sizeof(dev_class_info_t));
     1267                link_initialize(&info->dev_classes);
     1268                link_initialize(&info->devmap_link);
     1269                link_initialize(&info->link);
     1270        }
     1271       
     1272        return info;
     1273}
     1274
     1275size_t get_new_class_dev_idx(dev_class_t *cl)
     1276{
     1277        size_t dev_idx;
     1278       
     1279        fibril_mutex_lock(&cl->mutex);
     1280        dev_idx = ++cl->curr_dev_idx;
     1281        fibril_mutex_unlock(&cl->mutex);
     1282       
     1283        return dev_idx;
     1284}
     1285
     1286
     1287/** Create unique device name within the class.
     1288 *
     1289 * @param cl            The class.
     1290 * @param base_dev_name Contains the base name for the device if it was
     1291 *                      specified by the driver when it registered the device by
     1292 *                      the class; NULL if driver specified no base name.
     1293 * @return              The unique name for the device within the class.
     1294 */
     1295char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name)
     1296{
     1297        char *dev_name;
     1298        const char *base_name;
     1299       
     1300        if (base_dev_name != NULL)
     1301                base_name = base_dev_name;
     1302        else
     1303                base_name = cl->base_dev_name;
     1304       
     1305        size_t idx = get_new_class_dev_idx(cl);
     1306        asprintf(&dev_name, "%s%zu", base_name, idx);
     1307       
     1308        return dev_name;
     1309}
     1310
     1311/** Add the device function to the class.
     1312 *
     1313 * The device may be added to multiple classes and a class may contain multiple
     1314 * devices. The class and the device are associated with each other by the
     1315 * dev_class_info_t structure.
     1316 *
     1317 * @param dev           The device.
     1318 * @param class         The class.
     1319 * @param base_dev_name The base name of the device within the class if
     1320 *                      specified by the driver, NULL otherwise.
     1321 * @return              dev_class_info_t structure which associates the device
     1322 *                      with the class.
     1323 */
     1324dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl,
     1325    const char *base_dev_name)
     1326{
     1327        dev_class_info_t *info;
     1328
     1329        assert(fun != NULL);
     1330        assert(cl != NULL);
     1331
     1332        info = create_dev_class_info();
     1333
     1334       
     1335        if (info != NULL) {
     1336                info->dev_class = cl;
     1337                info->fun = fun;
     1338               
     1339                /* Add the device to the class. */
     1340                fibril_mutex_lock(&cl->mutex);
     1341                list_append(&info->link, &cl->devices);
     1342                fibril_mutex_unlock(&cl->mutex);
     1343               
     1344                /* Add the class to the device. */
     1345                list_append(&info->dev_classes, &fun->classes);
     1346               
     1347                /* Create unique name for the device within the class. */
     1348                info->dev_name = create_dev_name_for_class(cl, base_dev_name);
     1349        }
     1350       
     1351        return info;
     1352}
     1353
     1354dev_class_t *get_dev_class(class_list_t *class_list, char *class_name)
     1355{
     1356        dev_class_t *cl;
     1357       
     1358        fibril_rwlock_write_lock(&class_list->rwlock);
     1359        cl = find_dev_class_no_lock(class_list, class_name);
     1360        if (cl == NULL) {
     1361                cl = create_dev_class();
     1362                if (cl != NULL) {
     1363                        cl->name = class_name;
     1364                        cl->base_dev_name = "";
     1365                        add_dev_class_no_lock(class_list, cl);
     1366                }
     1367        }
     1368
     1369        fibril_rwlock_write_unlock(&class_list->rwlock);
     1370        return cl;
     1371}
     1372
     1373dev_class_t *find_dev_class_no_lock(class_list_t *class_list,
     1374    const char *class_name)
     1375{
     1376        dev_class_t *cl;
     1377        link_t *link = class_list->classes.next;
     1378       
     1379        while (link != &class_list->classes) {
     1380                cl = list_get_instance(link, dev_class_t, link);
     1381                if (str_cmp(cl->name, class_name) == 0) {
     1382                        return cl;
     1383                }
     1384                link = link->next;
     1385        }
     1386       
     1387        return NULL;
     1388}
     1389
     1390void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl)
     1391{
     1392        list_append(&cl->link, &class_list->classes);
     1393}
     1394
     1395dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name)
     1396{
     1397        assert(dev_class != NULL);
     1398        assert(dev_name != NULL);
     1399
     1400        link_t *link;
     1401        for (link = dev_class->devices.next;
     1402            link != &dev_class->devices;
     1403            link = link->next) {
     1404                dev_class_info_t *dev = list_get_instance(link,
     1405                    dev_class_info_t, link);
     1406
     1407                if (str_cmp(dev->dev_name, dev_name) == 0) {
     1408                        return dev;
     1409                }
     1410        }
     1411
     1412        return NULL;
     1413}
     1414
     1415void init_class_list(class_list_t *class_list)
     1416{
     1417        list_initialize(&class_list->classes);
     1418        fibril_rwlock_initialize(&class_list->rwlock);
     1419        hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1,
     1420            &devmap_devices_class_ops);
     1421}
     1422
     1423
     1424/* Devmap devices */
     1425
     1426fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
    14831427{
    14841428        fun_node_t *fun = NULL;
    14851429        link_t *link;
    1486         unsigned long key = (unsigned long) service_id;
     1430        unsigned long key = (unsigned long) devmap_handle;
    14871431       
    14881432        fibril_rwlock_read_lock(&tree->rwlock);
    1489         link = hash_table_find(&tree->loc_functions, &key);
     1433        link = hash_table_find(&tree->devmap_functions, &key);
     1434        if (link != NULL)
     1435                fun = hash_table_get_instance(link, fun_node_t, devmap_fun);
     1436        fibril_rwlock_read_unlock(&tree->rwlock);
     1437       
     1438        return fun;
     1439}
     1440
     1441fun_node_t *find_devmap_class_function(class_list_t *classes,
     1442    devmap_handle_t devmap_handle)
     1443{
     1444        fun_node_t *fun = NULL;
     1445        dev_class_info_t *cli;
     1446        link_t *link;
     1447        unsigned long key = (unsigned long)devmap_handle;
     1448       
     1449        fibril_rwlock_read_lock(&classes->rwlock);
     1450        link = hash_table_find(&classes->devmap_functions, &key);
    14901451        if (link != NULL) {
    1491                 fun = hash_table_get_instance(link, fun_node_t, loc_fun);
    1492                 fun_add_ref(fun);
    1493         }
    1494         fibril_rwlock_read_unlock(&tree->rwlock);
     1452                cli = hash_table_get_instance(link, dev_class_info_t,
     1453                    devmap_link);
     1454                fun = cli->fun;
     1455        }
     1456        fibril_rwlock_read_unlock(&classes->rwlock);
    14951457       
    14961458        return fun;
    14971459}
    14981460
    1499 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    1500 {
    1501         assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    1502        
    1503         unsigned long key = (unsigned long) fun->service_id;
    1504         hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
     1461void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli)
     1462{
     1463        unsigned long key = (unsigned long) cli->devmap_handle;
     1464       
     1465        fibril_rwlock_write_lock(&class_list->rwlock);
     1466        hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link);
     1467        fibril_rwlock_write_unlock(&class_list->rwlock);
     1468
     1469        assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL);
     1470}
     1471
     1472void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun)
     1473{
     1474        unsigned long key = (unsigned long) fun->devmap_handle;
     1475        fibril_rwlock_write_lock(&tree->rwlock);
     1476        hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun);
     1477        fibril_rwlock_write_unlock(&tree->rwlock);
    15051478}
    15061479
Note: See TracChangeset for help on using the changeset viewer.