Changes in uspace/srv/devman/devman.c [b72efe8:80a96d2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
rb72efe8 r80a96d2 30 30 * @{ 31 31 */ 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 */ 32 51 33 52 #include <errno.h> … … 37 56 #include <ipc/driver.h> 38 57 #include <ipc/devman.h> 39 #include < devmap.h>58 #include <loc.h> 40 59 #include <str_error.h> 41 60 #include <stdio.h> … … 43 62 #include "devman.h" 44 63 45 fun_node_t *find_node_child(fun_node_t *parent, const char *name);64 static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *); 46 65 47 66 /* hash table operations */ … … 66 85 } 67 86 68 static int devmap_functions_compare(unsigned long key[], hash_count_t keys,87 static int loc_functions_compare(unsigned long key[], hash_count_t keys, 69 88 link_t *item) 70 89 { 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 75 static 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]); 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]); 83 92 } 84 93 … … 99 108 }; 100 109 101 static hash_table_operations_t devmap_devices_ops = {110 static hash_table_operations_t loc_devices_ops = { 102 111 .hash = devices_hash, 103 .compare = devmap_functions_compare, 104 .remove_callback = devices_remove_callback 105 }; 106 107 static hash_table_operations_t devmap_devices_class_ops = { 108 .hash = devices_hash, 109 .compare = devmap_devices_class_compare, 112 .compare = loc_functions_compare, 110 113 .remove_callback = devices_remove_callback 111 114 }; … … 270 273 } 271 274 272 ssize_t read_bytes = safe_read(fd, buf, len);275 ssize_t read_bytes = read_all(fd, buf, len); 273 276 if (read_bytes <= 0) { 274 log_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path); 277 log_msg(LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path, 278 read_bytes); 275 279 goto cleanup; 276 280 } … … 421 425 } 422 426 423 insert_fun_node(tree, fun, clone_string(""), NULL); 427 fun_add_ref(fun); 428 insert_fun_node(tree, fun, str_dup(""), NULL); 429 424 430 match_id_t *id = create_match_id(); 425 id->id = clone_string("root");431 id->id = str_dup("root"); 426 432 id->score = 100; 427 433 add_match_id(&fun->match_ids, id); … … 437 443 } 438 444 445 dev_add_ref(dev); 439 446 insert_dev_node(tree, dev, fun); 440 447 … … 482 489 /** Assign a driver to a device. 483 490 * 491 * @param tree Device tree 484 492 * @param node The device's node in the device tree. 485 493 * @param drv The driver. 486 494 */ 487 void attach_driver(dev_ node_t *dev, driver_t *drv)495 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv) 488 496 { 489 497 log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")", … … 491 499 492 500 fibril_mutex_lock(&drv->driver_mutex); 501 fibril_rwlock_write_lock(&tree->rwlock); 493 502 494 503 dev->drv = drv; 495 504 list_append(&dev->driver_devices, &drv->devices); 496 505 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); 497 532 fibril_mutex_unlock(&drv->driver_mutex); 498 533 } … … 563 598 564 599 fibril_mutex_lock(&driver->driver_mutex); 565 566 async_exch_t *exch = async_exchange_begin(driver->sess);567 async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,568 DRIVER_DEVMAN, 0, 0);569 async_exchange_end(exch);570 571 if (!sess) {572 fibril_mutex_unlock(&driver->driver_mutex);573 return;574 }575 600 576 601 /* … … 581 606 while (link != &driver->devices.head) { 582 607 dev = list_get_instance(link, dev_node_t, driver_devices); 608 fibril_rwlock_write_lock(&tree->rwlock); 609 583 610 if (dev->passed_to_driver) { 611 fibril_rwlock_write_unlock(&tree->rwlock); 584 612 link = link->next; 585 613 continue; 586 614 } 587 615 588 /* 589 * We remove the device from the list to allow safe adding 590 * of new devices (no one will touch our item this way). 591 */ 592 list_remove(link); 616 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n", 617 (int)atomic_get(&dev->refcnt)); 618 dev_add_ref(dev); 593 619 594 620 /* … … 597 623 */ 598 624 fibril_mutex_unlock(&driver->driver_mutex); 599 600 add_device(sess, driver, dev, tree); 625 fibril_rwlock_write_unlock(&tree->rwlock); 626 627 add_device(driver, dev, tree); 628 629 dev_del_ref(dev); 601 630 602 631 /* … … 607 636 608 637 /* 609 * Insert the device back.610 * The order is not relevant here so no harm is done611 * (actually, the order would be preserved in most cases).612 */613 list_append(link, &driver->devices);614 615 /*616 638 * Restart the cycle to go through all devices again. 617 639 */ 618 640 link = driver->devices.head.next; 619 641 } 620 621 async_hangup(sess);622 642 623 643 /* … … 700 720 } 701 721 702 /** Create devmap path and name for the function. */ 703 void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree) 704 { 705 char *devmap_pathname = NULL; 706 char *devmap_name = NULL; 707 708 asprintf(&devmap_name, "%s", fun->pathname); 709 if (devmap_name == NULL) 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) 710 732 return; 711 733 712 replace_char( devmap_name, '/', DEVMAP_SEPARATOR);713 714 asprintf(& devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,715 devmap_name);716 if ( devmap_pathname == NULL) {717 free( devmap_name);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 740 return; 719 741 } 720 742 721 devmap_device_register_with_iface(devmap_pathname,722 &fun-> devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);723 724 tree_add_ devmap_function(tree, fun);725 726 free( devmap_name);727 free( devmap_pathname);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); 728 750 } 729 751 … … 733 755 * @param node The device's node in the device tree. 734 756 */ 735 void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev, 736 dev_tree_t *tree) 757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree) 737 758 { 738 759 /* … … 751 772 } 752 773 753 async_exch_t *exch = async_exchange_begin( sess);774 async_exch_t *exch = async_exchange_begin(drv->sess); 754 775 755 776 ipc_call_t answer; 756 aid_t req = async_send_2(exch, DRIVER_ ADD_DEVICE, dev->handle,777 aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle, 757 778 parent_handle, &answer); 758 779 … … 811 832 812 833 /* Attach the driver to the device. */ 813 attach_driver( dev, drv);834 attach_driver(tree, dev, drv); 814 835 815 836 fibril_mutex_lock(&drv->driver_mutex); … … 821 842 fibril_mutex_unlock(&drv->driver_mutex); 822 843 823 if (is_running) { 824 /* Notify the driver about the new device. */ 825 async_exch_t *exch = async_exchange_begin(drv->sess); 826 async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch, 827 DRIVER_DEVMAN, 0, 0); 828 async_exchange_end(exch); 829 830 if (sess) { 831 add_device(sess, drv, dev, tree); 832 async_hangup(sess); 833 } 834 } 835 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); 836 856 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 837 959 } 838 960 … … 855 977 hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1, 856 978 &devman_functions_ops); 857 hash_table_create(&tree-> devmap_functions, DEVICE_BUCKETS, 1,858 & devmap_devices_ops);979 hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1, 980 &loc_devices_ops); 859 981 860 982 fibril_rwlock_initialize(&tree->rwlock); … … 863 985 if (!create_root_nodes(tree)) 864 986 return false; 865 987 866 988 /* Find suitable driver and start it. */ 867 return assign_driver(tree->root_node->child, drivers_list, tree); 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; 868 995 } 869 996 … … 876 1003 dev_node_t *create_dev_node(void) 877 1004 { 878 dev_node_t *res = malloc(sizeof(dev_node_t)); 879 880 if (res != NULL) { 881 memset(res, 0, sizeof(dev_node_t)); 882 list_initialize(&res->functions); 883 link_initialize(&res->driver_devices); 884 link_initialize(&res->devman_dev); 885 } 886 887 return res; 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; 888 1017 } 889 1018 … … 901 1030 } 902 1031 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 903 1054 /** Find the device node structure of the device witch has the specified handle. 904 1055 * … … 930 1081 fibril_rwlock_read_lock(&tree->rwlock); 931 1082 dev = find_dev_node_no_lock(tree, handle); 1083 if (dev != NULL) 1084 dev_add_ref(dev); 1085 932 1086 fibril_rwlock_read_unlock(&tree->rwlock); 933 1087 … … 935 1089 } 936 1090 1091 /** Get list of device functions. */ 1092 int dev_get_functions(dev_tree_t *tree, dev_node_t *dev, 1093 devman_handle_t *hdl_buf, size_t buf_size, size_t *act_size) 1094 { 1095 size_t act_cnt; 1096 size_t buf_cnt; 1097 1098 assert(fibril_rwlock_is_locked(&tree->rwlock)); 1099 1100 buf_cnt = buf_size / sizeof(devman_handle_t); 1101 1102 act_cnt = list_count(&dev->functions); 1103 *act_size = act_cnt * sizeof(devman_handle_t); 1104 1105 if (buf_size % sizeof(devman_handle_t) != 0) 1106 return EINVAL; 1107 1108 size_t pos = 0; 1109 list_foreach(dev->functions, item) { 1110 fun_node_t *fun = 1111 list_get_instance(item, fun_node_t, dev_functions); 1112 1113 if (pos < buf_cnt) { 1114 hdl_buf[pos] = fun->handle; 1115 } 1116 1117 pos++; 1118 } 1119 1120 return EOK; 1121 } 1122 1123 937 1124 /* Function nodes */ 938 1125 … … 943 1130 fun_node_t *create_fun_node(void) 944 1131 { 945 fun_node_t *res = malloc(sizeof(fun_node_t)); 946 947 if (res != NULL) { 948 memset(res, 0, sizeof(fun_node_t)); 949 link_initialize(&res->dev_functions); 950 list_initialize(&res->match_ids.ids); 951 list_initialize(&res->classes); 952 link_initialize(&res->devman_fun); 953 link_initialize(&res->devmap_fun); 954 } 955 956 return res; 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; 957 1146 } 958 1147 … … 972 1161 } 973 1162 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 974 1184 /** Find the function node with the specified handle. 975 1185 * … … 982 1192 unsigned long key = handle; 983 1193 link_t *link; 1194 fun_node_t *fun; 984 1195 985 1196 assert(fibril_rwlock_is_locked(&tree->rwlock)); … … 989 1200 return NULL; 990 1201 991 return hash_table_get_instance(link, fun_node_t, devman_fun); 1202 fun = hash_table_get_instance(link, fun_node_t, devman_fun); 1203 1204 return fun; 992 1205 } 993 1206 … … 1003 1216 1004 1217 fibril_rwlock_read_lock(&tree->rwlock); 1218 1005 1219 fun = find_fun_node_no_lock(tree, handle); 1220 if (fun != NULL) 1221 fun_add_ref(fun); 1222 1006 1223 fibril_rwlock_read_unlock(&tree->rwlock); 1007 1224 … … 1011 1228 /** Create and set device's full path in device tree. 1012 1229 * 1230 * @param tree Device tree 1013 1231 * @param node The device's device node. 1014 1232 * @param parent The parent device node. … … 1016 1234 * resources etc.). 1017 1235 */ 1018 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent) 1019 { 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)); 1020 1239 assert(fun->name != NULL); 1021 1240 … … 1044 1263 * 1045 1264 * @param tree The device tree. 1046 * @param node The newly added device node. 1047 * @param dev_name The name of the newly added device. 1048 * @param parent The parent device node. 1265 * @param dev The newly added device node. 1266 * @param pfun The parent function node. 1049 1267 * 1050 1268 * @return True on success, false otherwise (insufficient resources … … 1053 1271 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun) 1054 1272 { 1055 assert(dev != NULL);1056 assert(tree != NULL);1057 1273 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1058 1274 … … 1072 1288 } 1073 1289 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 1074 1313 /** Insert new function into device tree. 1075 1314 * 1076 1315 * @param tree The device tree. 1077 * @param nodeThe newly added function node.1078 * @param dev_name The name of the newly added function.1079 * @param parentOwning device node.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. 1080 1319 * 1081 1320 * @return True on success, false otherwise (insufficient resources … … 1087 1326 fun_node_t *pfun; 1088 1327 1089 assert(fun != NULL);1090 assert(tree != NULL);1091 1328 assert(fun_name != NULL); 1092 1329 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); … … 1099 1336 1100 1337 fun->name = fun_name; 1101 if (!set_fun_path( fun, pfun)) {1338 if (!set_fun_path(tree, fun, pfun)) { 1102 1339 return false; 1103 1340 } … … 1114 1351 1115 1352 return true; 1353 } 1354 1355 /** Remove function from device tree. 1356 * 1357 * @param tree Device tree 1358 * @param node Function node to remove 1359 */ 1360 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun) 1361 { 1362 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1363 1364 /* Remove the node from the handle-to-node map. */ 1365 unsigned long key = fun->handle; 1366 hash_table_remove(&tree->devman_functions, &key, 1); 1367 1368 /* Remove the node from the list of its parent's children. */ 1369 if (fun->dev != NULL) 1370 list_remove(&fun->dev_functions); 1371 1372 fun->dev = NULL; 1373 fun->state = FUN_REMOVED; 1116 1374 } 1117 1375 … … 1135 1393 1136 1394 fun_node_t *fun = tree->root_node; 1395 fun_add_ref(fun); 1137 1396 /* 1138 1397 * Relative path to the function from its parent (but with '/' at the … … 1141 1400 char *rel_path = path; 1142 1401 char *next_path_elem = NULL; 1143 bool cont = true;1402 bool cont = (rel_path[1] != '\0'); 1144 1403 1145 1404 while (cont && fun != NULL) { … … 1152 1411 } 1153 1412 1154 fun = find_node_child(fun, rel_path + 1); 1413 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1); 1414 fun_del_ref(fun); 1415 fun = cfun; 1155 1416 1156 1417 if (cont) { … … 1170 1431 * Device tree rwlock should be held at least for reading. 1171 1432 * 1433 * @param tree Device tree 1172 1434 * @param dev Device the function belongs to. 1173 1435 * @param name Function name (not path). … … 1175 1437 * @retval NULL No function with given name. 1176 1438 */ 1177 fun_node_t *find_fun_node_in_device(dev_ node_t *dev, const char *name)1178 { 1179 assert(dev != NULL); 1439 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev, 1440 const char *name) 1441 { 1180 1442 assert(name != NULL); 1443 assert(fibril_rwlock_is_locked(&tree->rwlock)); 1181 1444 1182 1445 fun_node_t *fun; … … 1185 1448 fun = list_get_instance(link, fun_node_t, dev_functions); 1186 1449 1187 if (str_cmp(name, fun->name) == 0) 1450 if (str_cmp(name, fun->name) == 0) { 1451 fun_add_ref(fun); 1188 1452 return fun; 1453 } 1189 1454 } 1190 1455 … … 1192 1457 } 1193 1458 1194 /** Find function node by its class name and index. */1195 fun_node_t *find_fun_node_by_class(class_list_t *class_list,1196 const char *class_name, const char *dev_name)1197 {1198 assert(class_list != NULL);1199 assert(class_name != NULL);1200 assert(dev_name != NULL);1201 1202 fibril_rwlock_read_lock(&class_list->rwlock);1203 1204 dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);1205 if (cl == NULL) {1206 fibril_rwlock_read_unlock(&class_list->rwlock);1207 return NULL;1208 }1209 1210 dev_class_info_t *dev = find_dev_in_class(cl, dev_name);1211 if (dev == NULL) {1212 fibril_rwlock_read_unlock(&class_list->rwlock);1213 return NULL;1214 }1215 1216 fun_node_t *fun = dev->fun;1217 1218 fibril_rwlock_read_unlock(&class_list->rwlock);1219 1220 return fun;1221 }1222 1223 1224 1459 /** Find child function node with a specified name. 1225 1460 * 1226 1461 * Device tree rwlock should be held at least for reading. 1227 1462 * 1463 * @param tree Device tree 1228 1464 * @param parent The parent function node. 1229 1465 * @param name The name of the child function. 1230 1466 * @return The child function node. 1231 1467 */ 1232 fun_node_t *find_node_child(fun_node_t *pfun, const char *name) 1233 { 1234 return find_fun_node_in_device(pfun->child, name); 1235 } 1236 1237 /* Device classes */ 1238 1239 /** Create device class. 1240 * 1241 * @return Device class. 1242 */ 1243 dev_class_t *create_dev_class(void) 1244 { 1245 dev_class_t *cl; 1246 1247 cl = (dev_class_t *) malloc(sizeof(dev_class_t)); 1248 if (cl != NULL) { 1249 memset(cl, 0, sizeof(dev_class_t)); 1250 list_initialize(&cl->devices); 1251 fibril_mutex_initialize(&cl->mutex); 1252 } 1253 1254 return cl; 1255 } 1256 1257 /** Create device class info. 1258 * 1259 * @return Device class info. 1260 */ 1261 dev_class_info_t *create_dev_class_info(void) 1262 { 1263 dev_class_info_t *info; 1264 1265 info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t)); 1266 if (info != NULL) { 1267 memset(info, 0, sizeof(dev_class_info_t)); 1268 link_initialize(&info->dev_classes); 1269 link_initialize(&info->devmap_link); 1270 link_initialize(&info->link); 1271 } 1272 1273 return info; 1274 } 1275 1276 size_t get_new_class_dev_idx(dev_class_t *cl) 1277 { 1278 size_t dev_idx; 1279 1280 fibril_mutex_lock(&cl->mutex); 1281 dev_idx = ++cl->curr_dev_idx; 1282 fibril_mutex_unlock(&cl->mutex); 1283 1284 return dev_idx; 1285 } 1286 1287 1288 /** Create unique device name within the class. 1289 * 1290 * @param cl The class. 1291 * @param base_dev_name Contains the base name for the device if it was 1292 * specified by the driver when it registered the device by 1293 * the class; NULL if driver specified no base name. 1294 * @return The unique name for the device within the class. 1295 */ 1296 char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name) 1297 { 1298 char *dev_name; 1299 const char *base_name; 1300 1301 if (base_dev_name != NULL) 1302 base_name = base_dev_name; 1303 else 1304 base_name = cl->base_dev_name; 1305 1306 size_t idx = get_new_class_dev_idx(cl); 1307 asprintf(&dev_name, "%s%zu", base_name, idx); 1308 1309 return dev_name; 1310 } 1311 1312 /** Add the device function to the class. 1313 * 1314 * The device may be added to multiple classes and a class may contain multiple 1315 * devices. The class and the device are associated with each other by the 1316 * dev_class_info_t structure. 1317 * 1318 * @param dev The device. 1319 * @param class The class. 1320 * @param base_dev_name The base name of the device within the class if 1321 * specified by the driver, NULL otherwise. 1322 * @return dev_class_info_t structure which associates the device 1323 * with the class. 1324 */ 1325 dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl, 1326 const char *base_dev_name) 1327 { 1328 dev_class_info_t *info; 1329 1330 assert(fun != NULL); 1331 assert(cl != NULL); 1332 1333 info = create_dev_class_info(); 1334 1335 1336 if (info != NULL) { 1337 info->dev_class = cl; 1338 info->fun = fun; 1339 1340 /* Add the device to the class. */ 1341 fibril_mutex_lock(&cl->mutex); 1342 list_append(&info->link, &cl->devices); 1343 fibril_mutex_unlock(&cl->mutex); 1344 1345 /* Add the class to the device. */ 1346 list_append(&info->dev_classes, &fun->classes); 1347 1348 /* Create unique name for the device within the class. */ 1349 info->dev_name = create_dev_name_for_class(cl, base_dev_name); 1350 } 1351 1352 return info; 1353 } 1354 1355 dev_class_t *get_dev_class(class_list_t *class_list, char *class_name) 1356 { 1357 dev_class_t *cl; 1358 1359 fibril_rwlock_write_lock(&class_list->rwlock); 1360 cl = find_dev_class_no_lock(class_list, class_name); 1361 if (cl == NULL) { 1362 cl = create_dev_class(); 1363 if (cl != NULL) { 1364 cl->name = class_name; 1365 cl->base_dev_name = ""; 1366 add_dev_class_no_lock(class_list, cl); 1367 } 1368 } 1369 1370 fibril_rwlock_write_unlock(&class_list->rwlock); 1371 return cl; 1372 } 1373 1374 dev_class_t *find_dev_class_no_lock(class_list_t *class_list, 1375 const char *class_name) 1376 { 1377 dev_class_t *cl; 1378 1379 list_foreach(class_list->classes, link) { 1380 cl = list_get_instance(link, dev_class_t, link); 1381 if (str_cmp(cl->name, class_name) == 0) { 1382 return cl; 1383 } 1384 } 1385 1386 return NULL; 1387 } 1388 1389 void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl) 1390 { 1391 list_append(&cl->link, &class_list->classes); 1392 } 1393 1394 dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name) 1395 { 1396 assert(dev_class != NULL); 1397 assert(dev_name != NULL); 1398 1399 list_foreach(dev_class->devices, link) { 1400 dev_class_info_t *dev = list_get_instance(link, 1401 dev_class_info_t, link); 1402 1403 if (str_cmp(dev->dev_name, dev_name) == 0) { 1404 return dev; 1405 } 1406 } 1407 1408 return NULL; 1409 } 1410 1411 void init_class_list(class_list_t *class_list) 1412 { 1413 list_initialize(&class_list->classes); 1414 fibril_rwlock_initialize(&class_list->rwlock); 1415 hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1, 1416 &devmap_devices_class_ops); 1417 } 1418 1419 1420 /* Devmap devices */ 1421 1422 fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle) 1468 static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun, 1469 const char *name) 1470 { 1471 return find_fun_node_in_device(tree, pfun->child, name); 1472 } 1473 1474 /* loc devices */ 1475 1476 fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id) 1423 1477 { 1424 1478 fun_node_t *fun = NULL; 1425 1479 link_t *link; 1426 unsigned long key = (unsigned long) devmap_handle;1480 unsigned long key = (unsigned long) service_id; 1427 1481 1428 1482 fibril_rwlock_read_lock(&tree->rwlock); 1429 link = hash_table_find(&tree->devmap_functions, &key); 1430 if (link != NULL) 1431 fun = hash_table_get_instance(link, fun_node_t, devmap_fun); 1483 link = hash_table_find(&tree->loc_functions, &key); 1484 if (link != NULL) { 1485 fun = hash_table_get_instance(link, fun_node_t, loc_fun); 1486 fun_add_ref(fun); 1487 } 1432 1488 fibril_rwlock_read_unlock(&tree->rwlock); 1433 1489 … … 1435 1491 } 1436 1492 1437 fun_node_t *find_devmap_class_function(class_list_t *classes, 1438 devmap_handle_t devmap_handle) 1439 { 1440 fun_node_t *fun = NULL; 1441 dev_class_info_t *cli; 1442 link_t *link; 1443 unsigned long key = (unsigned long)devmap_handle; 1444 1445 fibril_rwlock_read_lock(&classes->rwlock); 1446 link = hash_table_find(&classes->devmap_functions, &key); 1447 if (link != NULL) { 1448 cli = hash_table_get_instance(link, dev_class_info_t, 1449 devmap_link); 1450 fun = cli->fun; 1451 } 1452 fibril_rwlock_read_unlock(&classes->rwlock); 1453 1454 return fun; 1455 } 1456 1457 void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli) 1458 { 1459 unsigned long key = (unsigned long) cli->devmap_handle; 1460 1461 fibril_rwlock_write_lock(&class_list->rwlock); 1462 hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link); 1463 fibril_rwlock_write_unlock(&class_list->rwlock); 1464 1465 assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL); 1466 } 1467 1468 void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun) 1469 { 1470 unsigned long key = (unsigned long) fun->devmap_handle; 1471 fibril_rwlock_write_lock(&tree->rwlock); 1472 hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun); 1473 fibril_rwlock_write_unlock(&tree->rwlock); 1493 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun) 1494 { 1495 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1496 1497 unsigned long key = (unsigned long) fun->service_id; 1498 hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun); 1474 1499 } 1475 1500
Note:
See TracChangeset
for help on using the changeset viewer.