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