Changes in uspace/srv/devman/devman.c [79ae36dd:c1a0488] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
r79ae36dd rc1a0488 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 … … 466 473 fibril_mutex_lock(&drivers_list->drivers_mutex); 467 474 468 link_t *link = drivers_list->drivers.next; 469 while (link != &drivers_list->drivers) { 475 list_foreach(drivers_list->drivers, link) { 470 476 drv = list_get_instance(link, driver_t, drivers); 471 477 score = get_match_score(drv, node); … … 474 480 best_drv = drv; 475 481 } 476 link = link->next;477 482 } 478 483 … … 484 489 /** Assign a driver to a device. 485 490 * 491 * @param tree Device tree 486 492 * @param node The device's node in the device tree. 487 493 * @param drv The driver. 488 494 */ 489 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) 490 496 { 491 497 log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")", … … 493 499 494 500 fibril_mutex_lock(&drv->driver_mutex); 501 fibril_rwlock_write_lock(&tree->rwlock); 495 502 496 503 dev->drv = drv; 497 504 list_append(&dev->driver_devices, &drv->devices); 498 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); 499 532 fibril_mutex_unlock(&drv->driver_mutex); 500 533 } … … 536 569 driver_t *res = NULL; 537 570 driver_t *drv = NULL; 538 link_t *link;539 571 540 572 fibril_mutex_lock(&drv_list->drivers_mutex); 541 573 542 link = drv_list->drivers.next; 543 while (link != &drv_list->drivers) { 574 list_foreach(drv_list->drivers, link) { 544 575 drv = list_get_instance(link, driver_t, drivers); 545 576 if (str_cmp(drv->name, drv_name) == 0) { … … 547 578 break; 548 579 } 549 550 link = link->next;551 580 } 552 581 … … 569 598 570 599 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 }581 600 582 601 /* … … 584 603 * that has not been passed to the driver. 585 604 */ 586 link = driver->devices. next;587 while (link != &driver->devices ) {605 link = driver->devices.head.next; 606 while (link != &driver->devices.head) { 588 607 dev = list_get_instance(link, dev_node_t, driver_devices); 608 fibril_rwlock_write_lock(&tree->rwlock); 609 589 610 if (dev->passed_to_driver) { 611 fibril_rwlock_write_unlock(&tree->rwlock); 590 612 link = link->next; 591 613 continue; 592 614 } 593 615 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); 616 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n", 617 (int)atomic_get(&dev->refcnt)); 618 dev_add_ref(dev); 599 619 600 620 /* … … 603 623 */ 604 624 fibril_mutex_unlock(&driver->driver_mutex); 605 606 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); 607 630 608 631 /* … … 613 636 614 637 /* 615 * Insert the device back.616 * The order is not relevant here so no harm is done617 * (actually, the order would be preserved in most cases).618 */619 list_append(link, &driver->devices);620 621 /*622 638 * Restart the cycle to go through all devices again. 623 639 */ 624 link = driver->devices.next; 625 } 626 627 async_hangup(sess); 640 link = driver->devices.head.next; 641 } 628 642 629 643 /* … … 706 720 } 707 721 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) 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) 716 732 return; 717 733 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);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); 724 740 return; 725 741 } 726 742 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);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); 734 750 } 735 751 … … 739 755 * @param node The device's node in the device tree. 740 756 */ 741 void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev, 742 dev_tree_t *tree) 757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree) 743 758 { 744 759 /* … … 757 772 } 758 773 759 async_exch_t *exch = async_exchange_begin( sess);774 async_exch_t *exch = async_exchange_begin(drv->sess); 760 775 761 776 ipc_call_t answer; 762 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, 763 778 parent_handle, &answer); 764 779 … … 817 832 818 833 /* Attach the driver to the device. */ 819 attach_driver( dev, drv);834 attach_driver(tree, dev, drv); 820 835 821 836 fibril_mutex_lock(&drv->driver_mutex); … … 827 842 fibril_mutex_unlock(&drv->driver_mutex); 828 843 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 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); 842 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 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 843 937 } 844 938 … … 861 955 hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1, 862 956 &devman_functions_ops); 863 hash_table_create(&tree-> devmap_functions, DEVICE_BUCKETS, 1,864 & devmap_devices_ops);957 hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1, 958 &loc_devices_ops); 865 959 866 960 fibril_rwlock_initialize(&tree->rwlock); … … 869 963 if (!create_root_nodes(tree)) 870 964 return false; 871 965 872 966 /* Find suitable driver and start it. */ 873 return assign_driver(tree->root_node->child, drivers_list, tree); 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; 874 973 } 875 974 … … 882 981 dev_node_t *create_dev_node(void) 883 982 { 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; 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; 894 995 } 895 996 … … 907 1008 } 908 1009 1010 /** Increase device node reference count. 1011 * 1012 * @param dev Device node 1013 */ 1014 void dev_add_ref(dev_node_t *dev) 1015 { 1016 atomic_inc(&dev->refcnt); 1017 } 1018 1019 /** Decrease device node reference count. 1020 * 1021 * When the count drops to zero the device node is freed. 1022 * 1023 * @param dev Device node 1024 */ 1025 void dev_del_ref(dev_node_t *dev) 1026 { 1027 if (atomic_predec(&dev->refcnt) == 0) 1028 delete_dev_node(dev); 1029 } 1030 1031 909 1032 /** Find the device node structure of the device witch has the specified handle. 910 1033 * … … 936 1059 fibril_rwlock_read_lock(&tree->rwlock); 937 1060 dev = find_dev_node_no_lock(tree, handle); 1061 if (dev != NULL) 1062 dev_add_ref(dev); 1063 938 1064 fibril_rwlock_read_unlock(&tree->rwlock); 939 1065 … … 941 1067 } 942 1068 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 943 1102 /* Function nodes */ 944 1103 … … 949 1108 fun_node_t *create_fun_node(void) 950 1109 { 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; 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; 963 1124 } 964 1125 … … 978 1139 } 979 1140 1141 /** Increase function node reference count. 1142 * 1143 * @param fun Function node 1144 */ 1145 void fun_add_ref(fun_node_t *fun) 1146 { 1147 atomic_inc(&fun->refcnt); 1148 } 1149 1150 /** Decrease function node reference count. 1151 * 1152 * When the count drops to zero the function node is freed. 1153 * 1154 * @param fun Function node 1155 */ 1156 void fun_del_ref(fun_node_t *fun) 1157 { 1158 if (atomic_predec(&fun->refcnt) == 0) 1159 delete_fun_node(fun); 1160 } 1161 980 1162 /** Find the function node with the specified handle. 981 1163 * … … 988 1170 unsigned long key = handle; 989 1171 link_t *link; 1172 fun_node_t *fun; 990 1173 991 1174 assert(fibril_rwlock_is_locked(&tree->rwlock)); … … 995 1178 return NULL; 996 1179 997 return hash_table_get_instance(link, fun_node_t, devman_fun); 1180 fun = hash_table_get_instance(link, fun_node_t, devman_fun); 1181 1182 return fun; 998 1183 } 999 1184 … … 1009 1194 1010 1195 fibril_rwlock_read_lock(&tree->rwlock); 1196 1011 1197 fun = find_fun_node_no_lock(tree, handle); 1198 if (fun != NULL) 1199 fun_add_ref(fun); 1200 1012 1201 fibril_rwlock_read_unlock(&tree->rwlock); 1013 1202 … … 1017 1206 /** Create and set device's full path in device tree. 1018 1207 * 1208 * @param tree Device tree 1019 1209 * @param node The device's device node. 1020 1210 * @param parent The parent device node. … … 1022 1212 * resources etc.). 1023 1213 */ 1024 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent) 1025 { 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)); 1026 1217 assert(fun->name != NULL); 1027 1218 … … 1050 1241 * 1051 1242 * @param tree The device tree. 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. 1243 * @param dev The newly added device node. 1244 * @param pfun The parent function node. 1055 1245 * 1056 1246 * @return True on success, false otherwise (insufficient resources … … 1059 1249 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun) 1060 1250 { 1061 assert(dev != NULL);1062 assert(tree != NULL);1063 1251 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1064 1252 … … 1078 1266 } 1079 1267 1268 /** Remove device from device tree. 1269 * 1270 * @param tree Device tree 1271 * @param dev Device node 1272 */ 1273 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev) 1274 { 1275 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1276 1277 log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev); 1278 1279 /* Remove node from the handle-to-node map. */ 1280 unsigned long key = dev->handle; 1281 hash_table_remove(&tree->devman_devices, &key, 1); 1282 1283 /* Unlink from parent function. */ 1284 dev->pfun->child = NULL; 1285 dev->pfun = NULL; 1286 1287 dev->state = DEVICE_REMOVED; 1288 } 1289 1290 1080 1291 /** Insert new function into device tree. 1081 1292 * 1082 1293 * @param tree The device tree. 1083 * @param nodeThe newly added function node.1084 * @param dev_name The name of the newly added function.1085 * @param parentOwning device node.1294 * @param fun The newly added function node. 1295 * @param fun_name The name of the newly added function. 1296 * @param dev Owning device node. 1086 1297 * 1087 1298 * @return True on success, false otherwise (insufficient resources … … 1093 1304 fun_node_t *pfun; 1094 1305 1095 assert(fun != NULL);1096 assert(tree != NULL);1097 1306 assert(fun_name != NULL); 1098 1307 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); … … 1105 1314 1106 1315 fun->name = fun_name; 1107 if (!set_fun_path( fun, pfun)) {1316 if (!set_fun_path(tree, fun, pfun)) { 1108 1317 return false; 1109 1318 } … … 1120 1329 1121 1330 return true; 1331 } 1332 1333 /** Remove function from device tree. 1334 * 1335 * @param tree Device tree 1336 * @param node Function node to remove 1337 */ 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; 1122 1352 } 1123 1353 … … 1141 1371 1142 1372 fun_node_t *fun = tree->root_node; 1373 fun_add_ref(fun); 1143 1374 /* 1144 1375 * Relative path to the function from its parent (but with '/' at the … … 1147 1378 char *rel_path = path; 1148 1379 char *next_path_elem = NULL; 1149 bool cont = true;1380 bool cont = (rel_path[1] != '\0'); 1150 1381 1151 1382 while (cont && fun != NULL) { … … 1158 1389 } 1159 1390 1160 fun = find_node_child(fun, rel_path + 1); 1391 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1); 1392 fun_del_ref(fun); 1393 fun = cfun; 1161 1394 1162 1395 if (cont) { … … 1176 1409 * Device tree rwlock should be held at least for reading. 1177 1410 * 1411 * @param tree Device tree 1178 1412 * @param dev Device the function belongs to. 1179 1413 * @param name Function name (not path). … … 1181 1415 * @retval NULL No function with given name. 1182 1416 */ 1183 fun_node_t *find_fun_node_in_device(dev_ node_t *dev, const char *name)1184 { 1185 assert(dev != NULL); 1417 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev, 1418 const char *name) 1419 { 1186 1420 assert(name != NULL); 1421 assert(fibril_rwlock_is_locked(&tree->rwlock)); 1187 1422 1188 1423 fun_node_t *fun; 1189 link_t *link; 1190 1191 for (link = dev->functions.next; 1192 link != &dev->functions; 1193 link = link->next) { 1424 1425 list_foreach(dev->functions, link) { 1194 1426 fun = list_get_instance(link, fun_node_t, dev_functions); 1195 1427 1196 if (str_cmp(name, fun->name) == 0) 1428 if (str_cmp(name, fun->name) == 0) { 1429 fun_add_ref(fun); 1197 1430 return fun; 1431 } 1198 1432 } 1199 1433 … … 1201 1435 } 1202 1436 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 1233 1437 /** Find child function node with a specified name. 1234 1438 * 1235 1439 * Device tree rwlock should be held at least for reading. 1236 1440 * 1441 * @param tree Device tree 1237 1442 * @param parent The parent function node. 1238 1443 * @param name The name of the child function. 1239 1444 * @return The child function node. 1240 1445 */ 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) 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) 1437 1455 { 1438 1456 fun_node_t *fun = NULL; 1439 1457 link_t *link; 1440 unsigned long key = (unsigned long) devmap_handle;1458 unsigned long key = (unsigned long) service_id; 1441 1459 1442 1460 fibril_rwlock_read_lock(&tree->rwlock); 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); 1461 link = hash_table_find(&tree->loc_functions, &key); 1462 if (link != NULL) { 1463 fun = hash_table_get_instance(link, fun_node_t, loc_fun); 1464 fun_add_ref(fun); 1465 } 1446 1466 fibril_rwlock_read_unlock(&tree->rwlock); 1447 1467 … … 1449 1469 } 1450 1470 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); 1461 if (link != NULL) { 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 1468 return fun; 1469 } 1470 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); 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); 1488 1477 } 1489 1478
Note:
See TracChangeset
for help on using the changeset viewer.