Changes in uspace/srv/devman/devman.c [c1a0488:79ae36dd] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
rc1a0488 r79ae36dd 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 }; … … 273 270 } 274 271 275 ssize_t read_bytes = read_all(fd, buf, len);272 ssize_t read_bytes = safe_read(fd, buf, len); 276 273 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); 279 275 goto cleanup; 280 276 } … … 425 421 } 426 422 427 fun_add_ref(fun); 428 insert_fun_node(tree, fun, str_dup(""), NULL); 429 423 insert_fun_node(tree, fun, clone_string(""), NULL); 430 424 match_id_t *id = create_match_id(); 431 id->id = str_dup("root");425 id->id = clone_string("root"); 432 426 id->score = 100; 433 427 add_match_id(&fun->match_ids, id); … … 443 437 } 444 438 445 dev_add_ref(dev);446 439 insert_dev_node(tree, dev, fun); 447 440 … … 473 466 fibril_mutex_lock(&drivers_list->drivers_mutex); 474 467 475 list_foreach(drivers_list->drivers, link) { 468 link_t *link = drivers_list->drivers.next; 469 while (link != &drivers_list->drivers) { 476 470 drv = list_get_instance(link, driver_t, drivers); 477 471 score = get_match_score(drv, node); … … 480 474 best_drv = drv; 481 475 } 476 link = link->next; 482 477 } 483 478 … … 489 484 /** Assign a driver to a device. 490 485 * 491 * @param tree Device tree492 486 * @param node The device's node in the device tree. 493 487 * @param drv The driver. 494 488 */ 495 void attach_driver(dev_ tree_t *tree, dev_node_t *dev, driver_t *drv)489 void attach_driver(dev_node_t *dev, driver_t *drv) 496 490 { 497 491 log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")", … … 499 493 500 494 fibril_mutex_lock(&drv->driver_mutex); 501 fibril_rwlock_write_lock(&tree->rwlock);502 495 503 496 dev->drv = drv; 504 497 list_append(&dev->driver_devices, &drv->devices); 505 498 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 499 fibril_mutex_unlock(&drv->driver_mutex); 533 500 } … … 569 536 driver_t *res = NULL; 570 537 driver_t *drv = NULL; 538 link_t *link; 571 539 572 540 fibril_mutex_lock(&drv_list->drivers_mutex); 573 541 574 list_foreach(drv_list->drivers, link) { 542 link = drv_list->drivers.next; 543 while (link != &drv_list->drivers) { 575 544 drv = list_get_instance(link, driver_t, drivers); 576 545 if (str_cmp(drv->name, drv_name) == 0) { … … 578 547 break; 579 548 } 549 550 link = link->next; 580 551 } 581 552 … … 598 569 599 570 fibril_mutex_lock(&driver->driver_mutex); 571 572 async_exch_t *exch = async_exchange_begin(driver->sess); 573 async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch, 574 DRIVER_DEVMAN, 0, 0); 575 async_exchange_end(exch); 576 577 if (!sess) { 578 fibril_mutex_unlock(&driver->driver_mutex); 579 return; 580 } 600 581 601 582 /* … … 603 584 * that has not been passed to the driver. 604 585 */ 605 link = driver->devices. head.next;606 while (link != &driver->devices .head) {586 link = driver->devices.next; 587 while (link != &driver->devices) { 607 588 dev = list_get_instance(link, dev_node_t, driver_devices); 608 fibril_rwlock_write_lock(&tree->rwlock);609 610 589 if (dev->passed_to_driver) { 611 fibril_rwlock_write_unlock(&tree->rwlock);612 590 link = link->next; 613 591 continue; 614 592 } 615 593 616 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n", 617 (int)atomic_get(&dev->refcnt)); 618 dev_add_ref(dev); 594 /* 595 * We remove the device from the list to allow safe adding 596 * of new devices (no one will touch our item this way). 597 */ 598 list_remove(link); 619 599 620 600 /* … … 623 603 */ 624 604 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); 605 606 add_device(sess, driver, dev, tree); 630 607 631 608 /* … … 636 613 637 614 /* 615 * Insert the device back. 616 * The order is not relevant here so no harm is done 617 * (actually, the order would be preserved in most cases). 618 */ 619 list_append(link, &driver->devices); 620 621 /* 638 622 * Restart the cycle to go through all devices again. 639 623 */ 640 link = driver->devices.head.next; 641 } 624 link = driver->devices.next; 625 } 626 627 async_hangup(sess); 642 628 643 629 /* … … 720 706 } 721 707 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) 708 /** Create devmap path and name for the function. */ 709 void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree) 710 { 711 char *devmap_pathname = NULL; 712 char *devmap_name = NULL; 713 714 asprintf(&devmap_name, "%s", fun->pathname); 715 if (devmap_name == NULL) 732 716 return; 733 717 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 replace_char(devmap_name, '/', DEVMAP_SEPARATOR); 719 720 asprintf(&devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE, 721 devmap_name); 722 if (devmap_pathname == NULL) { 723 free(devmap_name); 740 724 return; 741 725 } 742 726 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);727 devmap_device_register_with_iface(devmap_pathname, 728 &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP); 729 730 tree_add_devmap_function(tree, fun); 731 732 free(devmap_name); 733 free(devmap_pathname); 750 734 } 751 735 … … 755 739 * @param node The device's node in the device tree. 756 740 */ 757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree) 741 void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev, 742 dev_tree_t *tree) 758 743 { 759 744 /* … … 772 757 } 773 758 774 async_exch_t *exch = async_exchange_begin( drv->sess);759 async_exch_t *exch = async_exchange_begin(sess); 775 760 776 761 ipc_call_t answer; 777 aid_t req = async_send_2(exch, DRIVER_ DEV_ADD, dev->handle,762 aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle, 778 763 parent_handle, &answer); 779 764 … … 832 817 833 818 /* Attach the driver to the device. */ 834 attach_driver( tree,dev, drv);819 attach_driver(dev, drv); 835 820 836 821 fibril_mutex_lock(&drv->driver_mutex); … … 842 827 fibril_mutex_unlock(&drv->driver_mutex); 843 828 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); 829 if (is_running) { 830 /* Notify the driver about the new device. */ 831 async_exch_t *exch = async_exchange_begin(drv->sess); 832 async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch, 833 DRIVER_DEVMAN, 0, 0); 834 async_exchange_end(exch); 835 836 if (sess) { 837 add_device(sess, drv, dev, tree); 838 async_hangup(sess); 839 } 840 } 841 856 842 return true; 857 }858 859 int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)860 {861 async_exch_t *exch;862 sysarg_t retval;863 driver_t *drv;864 devman_handle_t handle;865 866 assert(dev != NULL);867 868 log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);869 870 fibril_rwlock_read_lock(&tree->rwlock);871 drv = dev->drv;872 handle = dev->handle;873 fibril_rwlock_read_unlock(&tree->rwlock);874 875 exch = async_exchange_begin(drv->sess);876 retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);877 async_exchange_end(exch);878 879 return retval;880 881 }882 883 int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)884 {885 async_exch_t *exch;886 sysarg_t retval;887 driver_t *drv;888 devman_handle_t handle;889 890 log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);891 892 fibril_rwlock_read_lock(&tree->rwlock);893 894 if (fun->dev == NULL) {895 /* XXX root function? */896 fibril_rwlock_read_unlock(&tree->rwlock);897 return EINVAL;898 }899 900 drv = fun->dev->drv;901 handle = fun->handle;902 fibril_rwlock_read_unlock(&tree->rwlock);903 904 exch = async_exchange_begin(drv->sess);905 retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);906 loc_exchange_end(exch);907 908 return retval;909 }910 911 int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)912 {913 async_exch_t *exch;914 sysarg_t retval;915 driver_t *drv;916 devman_handle_t handle;917 918 log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);919 920 fibril_rwlock_read_lock(&tree->rwlock);921 if (fun->dev == NULL) {922 /* XXX root function? */923 fibril_rwlock_read_unlock(&tree->rwlock);924 return EINVAL;925 }926 927 drv = fun->dev->drv;928 handle = fun->handle;929 fibril_rwlock_read_unlock(&tree->rwlock);930 931 exch = async_exchange_begin(drv->sess);932 retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);933 loc_exchange_end(exch);934 935 return retval;936 937 843 } 938 844 … … 955 861 hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1, 956 862 &devman_functions_ops); 957 hash_table_create(&tree-> loc_functions, DEVICE_BUCKETS, 1,958 & loc_devices_ops);863 hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1, 864 &devmap_devices_ops); 959 865 960 866 fibril_rwlock_initialize(&tree->rwlock); … … 963 869 if (!create_root_nodes(tree)) 964 870 return false; 965 871 966 872 /* Find suitable driver and start it. */ 967 dev_node_t *rdev = tree->root_node->child; 968 dev_add_ref(rdev); 969 int rc = assign_driver(rdev, drivers_list, tree); 970 dev_del_ref(rdev); 971 972 return rc; 873 return assign_driver(tree->root_node->child, drivers_list, tree); 973 874 } 974 875 … … 981 882 dev_node_t *create_dev_node(void) 982 883 { 983 dev_node_t *dev; 984 985 dev = calloc(1, sizeof(dev_node_t)); 986 if (dev == NULL) 987 return NULL; 988 989 atomic_set(&dev->refcnt, 0); 990 list_initialize(&dev->functions); 991 link_initialize(&dev->driver_devices); 992 link_initialize(&dev->devman_dev); 993 994 return dev; 884 dev_node_t *res = malloc(sizeof(dev_node_t)); 885 886 if (res != NULL) { 887 memset(res, 0, sizeof(dev_node_t)); 888 list_initialize(&res->functions); 889 link_initialize(&res->driver_devices); 890 link_initialize(&res->devman_dev); 891 } 892 893 return res; 995 894 } 996 895 … … 1008 907 } 1009 908 1010 /** Increase device node reference count.1011 *1012 * @param dev Device node1013 */1014 void dev_add_ref(dev_node_t *dev)1015 {1016 atomic_inc(&dev->refcnt);1017 }1018 1019 /** Decrease device node reference count.1020 *1021 * When the count drops to zero the device node is freed.1022 *1023 * @param dev Device node1024 */1025 void dev_del_ref(dev_node_t *dev)1026 {1027 if (atomic_predec(&dev->refcnt) == 0)1028 delete_dev_node(dev);1029 }1030 1031 1032 909 /** Find the device node structure of the device witch has the specified handle. 1033 910 * … … 1059 936 fibril_rwlock_read_lock(&tree->rwlock); 1060 937 dev = find_dev_node_no_lock(tree, handle); 1061 if (dev != NULL)1062 dev_add_ref(dev);1063 1064 938 fibril_rwlock_read_unlock(&tree->rwlock); 1065 939 … … 1067 941 } 1068 942 1069 /** Get list of device functions. */1070 int dev_get_functions(dev_tree_t *tree, dev_node_t *dev,1071 devman_handle_t *hdl_buf, size_t buf_size, size_t *act_size)1072 {1073 size_t act_cnt;1074 size_t buf_cnt;1075 1076 assert(fibril_rwlock_is_locked(&tree->rwlock));1077 1078 buf_cnt = buf_size / sizeof(devman_handle_t);1079 1080 act_cnt = list_count(&dev->functions);1081 *act_size = act_cnt * sizeof(devman_handle_t);1082 1083 if (buf_size % sizeof(devman_handle_t) != 0)1084 return EINVAL;1085 1086 size_t pos = 0;1087 list_foreach(dev->functions, item) {1088 fun_node_t *fun =1089 list_get_instance(item, fun_node_t, dev_functions);1090 1091 if (pos < buf_cnt) {1092 hdl_buf[pos] = fun->handle;1093 }1094 1095 pos++;1096 }1097 1098 return EOK;1099 }1100 1101 1102 943 /* Function nodes */ 1103 944 … … 1108 949 fun_node_t *create_fun_node(void) 1109 950 { 1110 fun_node_t *fun; 1111 1112 fun = calloc(1, sizeof(fun_node_t)); 1113 if (fun == NULL) 1114 return NULL; 1115 1116 fun->state = FUN_INIT; 1117 atomic_set(&fun->refcnt, 0); 1118 link_initialize(&fun->dev_functions); 1119 list_initialize(&fun->match_ids.ids); 1120 link_initialize(&fun->devman_fun); 1121 link_initialize(&fun->loc_fun); 1122 1123 return fun; 951 fun_node_t *res = malloc(sizeof(fun_node_t)); 952 953 if (res != NULL) { 954 memset(res, 0, sizeof(fun_node_t)); 955 link_initialize(&res->dev_functions); 956 list_initialize(&res->match_ids.ids); 957 list_initialize(&res->classes); 958 link_initialize(&res->devman_fun); 959 link_initialize(&res->devmap_fun); 960 } 961 962 return res; 1124 963 } 1125 964 … … 1139 978 } 1140 979 1141 /** Increase function node reference count.1142 *1143 * @param fun Function node1144 */1145 void fun_add_ref(fun_node_t *fun)1146 {1147 atomic_inc(&fun->refcnt);1148 }1149 1150 /** Decrease function node reference count.1151 *1152 * When the count drops to zero the function node is freed.1153 *1154 * @param fun Function node1155 */1156 void fun_del_ref(fun_node_t *fun)1157 {1158 if (atomic_predec(&fun->refcnt) == 0)1159 delete_fun_node(fun);1160 }1161 1162 980 /** Find the function node with the specified handle. 1163 981 * … … 1170 988 unsigned long key = handle; 1171 989 link_t *link; 1172 fun_node_t *fun;1173 990 1174 991 assert(fibril_rwlock_is_locked(&tree->rwlock)); … … 1178 995 return NULL; 1179 996 1180 fun = hash_table_get_instance(link, fun_node_t, devman_fun); 1181 1182 return fun; 997 return hash_table_get_instance(link, fun_node_t, devman_fun); 1183 998 } 1184 999 … … 1194 1009 1195 1010 fibril_rwlock_read_lock(&tree->rwlock); 1196 1197 1011 fun = find_fun_node_no_lock(tree, handle); 1198 if (fun != NULL)1199 fun_add_ref(fun);1200 1201 1012 fibril_rwlock_read_unlock(&tree->rwlock); 1202 1013 … … 1206 1017 /** Create and set device's full path in device tree. 1207 1018 * 1208 * @param tree Device tree1209 1019 * @param node The device's device node. 1210 1020 * @param parent The parent device node. … … 1212 1022 * resources etc.). 1213 1023 */ 1214 static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent) 1215 { 1216 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1024 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent) 1025 { 1217 1026 assert(fun->name != NULL); 1218 1027 … … 1241 1050 * 1242 1051 * @param tree The device tree. 1243 * @param dev The newly added device node. 1244 * @param pfun The parent function node. 1052 * @param node The newly added device node. 1053 * @param dev_name The name of the newly added device. 1054 * @param parent The parent device node. 1245 1055 * 1246 1056 * @return True on success, false otherwise (insufficient resources … … 1249 1059 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun) 1250 1060 { 1061 assert(dev != NULL); 1062 assert(tree != NULL); 1251 1063 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1252 1064 … … 1266 1078 } 1267 1079 1268 /** Remove device from device tree.1269 *1270 * @param tree Device tree1271 * @param dev Device node1272 */1273 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)1274 {1275 assert(fibril_rwlock_is_write_locked(&tree->rwlock));1276 1277 log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);1278 1279 /* Remove node from the handle-to-node map. */1280 unsigned long key = dev->handle;1281 hash_table_remove(&tree->devman_devices, &key, 1);1282 1283 /* Unlink from parent function. */1284 dev->pfun->child = NULL;1285 dev->pfun = NULL;1286 1287 dev->state = DEVICE_REMOVED;1288 }1289 1290 1291 1080 /** Insert new function into device tree. 1292 1081 * 1293 1082 * @param tree The device tree. 1294 * @param funThe newly added function node.1295 * @param fun_name The name of the newly added function.1296 * @param devOwning device node.1083 * @param node The newly added function node. 1084 * @param dev_name The name of the newly added function. 1085 * @param parent Owning device node. 1297 1086 * 1298 1087 * @return True on success, false otherwise (insufficient resources … … 1304 1093 fun_node_t *pfun; 1305 1094 1095 assert(fun != NULL); 1096 assert(tree != NULL); 1306 1097 assert(fun_name != NULL); 1307 1098 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); … … 1314 1105 1315 1106 fun->name = fun_name; 1316 if (!set_fun_path( tree,fun, pfun)) {1107 if (!set_fun_path(fun, pfun)) { 1317 1108 return false; 1318 1109 } … … 1329 1120 1330 1121 return true; 1331 }1332 1333 /** Remove function from device tree.1334 *1335 * @param tree Device tree1336 * @param node Function node to remove1337 */1338 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)1339 {1340 assert(fibril_rwlock_is_write_locked(&tree->rwlock));1341 1342 /* Remove the node from the handle-to-node map. */1343 unsigned long key = fun->handle;1344 hash_table_remove(&tree->devman_functions, &key, 1);1345 1346 /* Remove the node from the list of its parent's children. */1347 if (fun->dev != NULL)1348 list_remove(&fun->dev_functions);1349 1350 fun->dev = NULL;1351 fun->state = FUN_REMOVED;1352 1122 } 1353 1123 … … 1371 1141 1372 1142 fun_node_t *fun = tree->root_node; 1373 fun_add_ref(fun);1374 1143 /* 1375 1144 * Relative path to the function from its parent (but with '/' at the … … 1378 1147 char *rel_path = path; 1379 1148 char *next_path_elem = NULL; 1380 bool cont = (rel_path[1] != '\0');1149 bool cont = true; 1381 1150 1382 1151 while (cont && fun != NULL) { … … 1389 1158 } 1390 1159 1391 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1); 1392 fun_del_ref(fun); 1393 fun = cfun; 1160 fun = find_node_child(fun, rel_path + 1); 1394 1161 1395 1162 if (cont) { … … 1409 1176 * Device tree rwlock should be held at least for reading. 1410 1177 * 1411 * @param tree Device tree1412 1178 * @param dev Device the function belongs to. 1413 1179 * @param name Function name (not path). … … 1415 1181 * @retval NULL No function with given name. 1416 1182 */ 1417 fun_node_t *find_fun_node_in_device(dev_ tree_t *tree, dev_node_t *dev,1418 const char *name) 1419 { 1183 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name) 1184 { 1185 assert(dev != NULL); 1420 1186 assert(name != NULL); 1421 assert(fibril_rwlock_is_locked(&tree->rwlock));1422 1187 1423 1188 fun_node_t *fun; 1424 1425 list_foreach(dev->functions, link) { 1189 link_t *link; 1190 1191 for (link = dev->functions.next; 1192 link != &dev->functions; 1193 link = link->next) { 1426 1194 fun = list_get_instance(link, fun_node_t, dev_functions); 1427 1195 1428 if (str_cmp(name, fun->name) == 0) { 1429 fun_add_ref(fun); 1196 if (str_cmp(name, fun->name) == 0) 1430 1197 return fun; 1431 }1432 1198 } 1433 1199 … … 1435 1201 } 1436 1202 1203 /** Find function node by its class name and index. */ 1204 fun_node_t *find_fun_node_by_class(class_list_t *class_list, 1205 const char *class_name, const char *dev_name) 1206 { 1207 assert(class_list != NULL); 1208 assert(class_name != NULL); 1209 assert(dev_name != NULL); 1210 1211 fibril_rwlock_read_lock(&class_list->rwlock); 1212 1213 dev_class_t *cl = find_dev_class_no_lock(class_list, class_name); 1214 if (cl == NULL) { 1215 fibril_rwlock_read_unlock(&class_list->rwlock); 1216 return NULL; 1217 } 1218 1219 dev_class_info_t *dev = find_dev_in_class(cl, dev_name); 1220 if (dev == NULL) { 1221 fibril_rwlock_read_unlock(&class_list->rwlock); 1222 return NULL; 1223 } 1224 1225 fun_node_t *fun = dev->fun; 1226 1227 fibril_rwlock_read_unlock(&class_list->rwlock); 1228 1229 return fun; 1230 } 1231 1232 1437 1233 /** Find child function node with a specified name. 1438 1234 * 1439 1235 * Device tree rwlock should be held at least for reading. 1440 1236 * 1441 * @param tree Device tree1442 1237 * @param parent The parent function node. 1443 1238 * @param name The name of the child function. 1444 1239 * @return The child function node. 1445 1240 */ 1446 static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun, 1447 const char *name) 1448 { 1449 return find_fun_node_in_device(tree, pfun->child, name); 1450 } 1451 1452 /* loc devices */ 1453 1454 fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id) 1241 fun_node_t *find_node_child(fun_node_t *pfun, const char *name) 1242 { 1243 return find_fun_node_in_device(pfun->child, name); 1244 } 1245 1246 /* Device classes */ 1247 1248 /** Create device class. 1249 * 1250 * @return Device class. 1251 */ 1252 dev_class_t *create_dev_class(void) 1253 { 1254 dev_class_t *cl; 1255 1256 cl = (dev_class_t *) malloc(sizeof(dev_class_t)); 1257 if (cl != NULL) { 1258 memset(cl, 0, sizeof(dev_class_t)); 1259 list_initialize(&cl->devices); 1260 fibril_mutex_initialize(&cl->mutex); 1261 } 1262 1263 return cl; 1264 } 1265 1266 /** Create device class info. 1267 * 1268 * @return Device class info. 1269 */ 1270 dev_class_info_t *create_dev_class_info(void) 1271 { 1272 dev_class_info_t *info; 1273 1274 info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t)); 1275 if (info != NULL) { 1276 memset(info, 0, sizeof(dev_class_info_t)); 1277 link_initialize(&info->dev_classes); 1278 link_initialize(&info->devmap_link); 1279 link_initialize(&info->link); 1280 } 1281 1282 return info; 1283 } 1284 1285 size_t get_new_class_dev_idx(dev_class_t *cl) 1286 { 1287 size_t dev_idx; 1288 1289 fibril_mutex_lock(&cl->mutex); 1290 dev_idx = ++cl->curr_dev_idx; 1291 fibril_mutex_unlock(&cl->mutex); 1292 1293 return dev_idx; 1294 } 1295 1296 1297 /** Create unique device name within the class. 1298 * 1299 * @param cl The class. 1300 * @param base_dev_name Contains the base name for the device if it was 1301 * specified by the driver when it registered the device by 1302 * the class; NULL if driver specified no base name. 1303 * @return The unique name for the device within the class. 1304 */ 1305 char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name) 1306 { 1307 char *dev_name; 1308 const char *base_name; 1309 1310 if (base_dev_name != NULL) 1311 base_name = base_dev_name; 1312 else 1313 base_name = cl->base_dev_name; 1314 1315 size_t idx = get_new_class_dev_idx(cl); 1316 asprintf(&dev_name, "%s%zu", base_name, idx); 1317 1318 return dev_name; 1319 } 1320 1321 /** Add the device function to the class. 1322 * 1323 * The device may be added to multiple classes and a class may contain multiple 1324 * devices. The class and the device are associated with each other by the 1325 * dev_class_info_t structure. 1326 * 1327 * @param dev The device. 1328 * @param class The class. 1329 * @param base_dev_name The base name of the device within the class if 1330 * specified by the driver, NULL otherwise. 1331 * @return dev_class_info_t structure which associates the device 1332 * with the class. 1333 */ 1334 dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl, 1335 const char *base_dev_name) 1336 { 1337 dev_class_info_t *info; 1338 1339 assert(fun != NULL); 1340 assert(cl != NULL); 1341 1342 info = create_dev_class_info(); 1343 1344 1345 if (info != NULL) { 1346 info->dev_class = cl; 1347 info->fun = fun; 1348 1349 /* Add the device to the class. */ 1350 fibril_mutex_lock(&cl->mutex); 1351 list_append(&info->link, &cl->devices); 1352 fibril_mutex_unlock(&cl->mutex); 1353 1354 /* Add the class to the device. */ 1355 list_append(&info->dev_classes, &fun->classes); 1356 1357 /* Create unique name for the device within the class. */ 1358 info->dev_name = create_dev_name_for_class(cl, base_dev_name); 1359 } 1360 1361 return info; 1362 } 1363 1364 dev_class_t *get_dev_class(class_list_t *class_list, char *class_name) 1365 { 1366 dev_class_t *cl; 1367 1368 fibril_rwlock_write_lock(&class_list->rwlock); 1369 cl = find_dev_class_no_lock(class_list, class_name); 1370 if (cl == NULL) { 1371 cl = create_dev_class(); 1372 if (cl != NULL) { 1373 cl->name = class_name; 1374 cl->base_dev_name = ""; 1375 add_dev_class_no_lock(class_list, cl); 1376 } 1377 } 1378 1379 fibril_rwlock_write_unlock(&class_list->rwlock); 1380 return cl; 1381 } 1382 1383 dev_class_t *find_dev_class_no_lock(class_list_t *class_list, 1384 const char *class_name) 1385 { 1386 dev_class_t *cl; 1387 link_t *link = class_list->classes.next; 1388 1389 while (link != &class_list->classes) { 1390 cl = list_get_instance(link, dev_class_t, link); 1391 if (str_cmp(cl->name, class_name) == 0) { 1392 return cl; 1393 } 1394 link = link->next; 1395 } 1396 1397 return NULL; 1398 } 1399 1400 void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl) 1401 { 1402 list_append(&cl->link, &class_list->classes); 1403 } 1404 1405 dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name) 1406 { 1407 assert(dev_class != NULL); 1408 assert(dev_name != NULL); 1409 1410 link_t *link; 1411 for (link = dev_class->devices.next; 1412 link != &dev_class->devices; 1413 link = link->next) { 1414 dev_class_info_t *dev = list_get_instance(link, 1415 dev_class_info_t, link); 1416 1417 if (str_cmp(dev->dev_name, dev_name) == 0) { 1418 return dev; 1419 } 1420 } 1421 1422 return NULL; 1423 } 1424 1425 void init_class_list(class_list_t *class_list) 1426 { 1427 list_initialize(&class_list->classes); 1428 fibril_rwlock_initialize(&class_list->rwlock); 1429 hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1, 1430 &devmap_devices_class_ops); 1431 } 1432 1433 1434 /* Devmap devices */ 1435 1436 fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle) 1455 1437 { 1456 1438 fun_node_t *fun = NULL; 1457 1439 link_t *link; 1458 unsigned long key = (unsigned long) service_id;1440 unsigned long key = (unsigned long) devmap_handle; 1459 1441 1460 1442 fibril_rwlock_read_lock(&tree->rwlock); 1461 link = hash_table_find(&tree->loc_functions, &key); 1443 link = hash_table_find(&tree->devmap_functions, &key); 1444 if (link != NULL) 1445 fun = hash_table_get_instance(link, fun_node_t, devmap_fun); 1446 fibril_rwlock_read_unlock(&tree->rwlock); 1447 1448 return fun; 1449 } 1450 1451 fun_node_t *find_devmap_class_function(class_list_t *classes, 1452 devmap_handle_t devmap_handle) 1453 { 1454 fun_node_t *fun = NULL; 1455 dev_class_info_t *cli; 1456 link_t *link; 1457 unsigned long key = (unsigned long)devmap_handle; 1458 1459 fibril_rwlock_read_lock(&classes->rwlock); 1460 link = hash_table_find(&classes->devmap_functions, &key); 1462 1461 if (link != NULL) { 1463 fun = hash_table_get_instance(link, fun_node_t, loc_fun); 1464 fun_add_ref(fun); 1465 } 1466 fibril_rwlock_read_unlock(&tree->rwlock); 1462 cli = hash_table_get_instance(link, dev_class_info_t, 1463 devmap_link); 1464 fun = cli->fun; 1465 } 1466 fibril_rwlock_read_unlock(&classes->rwlock); 1467 1467 1468 1468 return fun; 1469 1469 } 1470 1470 1471 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun) 1472 { 1473 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1474 1475 unsigned long key = (unsigned long) fun->service_id; 1476 hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun); 1471 void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli) 1472 { 1473 unsigned long key = (unsigned long) cli->devmap_handle; 1474 1475 fibril_rwlock_write_lock(&class_list->rwlock); 1476 hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link); 1477 fibril_rwlock_write_unlock(&class_list->rwlock); 1478 1479 assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL); 1480 } 1481 1482 void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun) 1483 { 1484 unsigned long key = (unsigned long) fun->devmap_handle; 1485 fibril_rwlock_write_lock(&tree->rwlock); 1486 hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun); 1487 fibril_rwlock_write_unlock(&tree->rwlock); 1477 1488 } 1478 1489
Note:
See TracChangeset
for help on using the changeset viewer.