Changes in uspace/srv/devman/devman.c [c7bbf029:609243f4] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
rc7bbf029 r609243f4 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 … … 564 593 dev_node_t *dev; 565 594 link_t *link; 566 int phone;567 595 568 596 log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")", … … 570 598 571 599 fibril_mutex_lock(&driver->driver_mutex); 572 573 phone = async_connect_me_to(driver->phone, DRIVER_DEVMAN, 0, 0);574 575 if (phone < 0) {576 fibril_mutex_unlock(&driver->driver_mutex);577 return;578 }579 600 580 601 /* … … 582 603 * that has not been passed to the driver. 583 604 */ 584 link = driver->devices. next;585 while (link != &driver->devices ) {605 link = driver->devices.head.next; 606 while (link != &driver->devices.head) { 586 607 dev = list_get_instance(link, dev_node_t, driver_devices); 608 fibril_rwlock_write_lock(&tree->rwlock); 609 587 610 if (dev->passed_to_driver) { 611 fibril_rwlock_write_unlock(&tree->rwlock); 588 612 link = link->next; 589 613 continue; 590 614 } 591 615 592 /* 593 * We remove the device from the list to allow safe adding 594 * of new devices (no one will touch our item this way). 595 */ 596 list_remove(link); 616 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n", 617 (int)atomic_get(&dev->refcnt)); 618 dev_add_ref(dev); 597 619 598 620 /* … … 601 623 */ 602 624 fibril_mutex_unlock(&driver->driver_mutex); 603 604 add_device(phone, driver, dev, tree); 625 fibril_rwlock_write_unlock(&tree->rwlock); 626 627 add_device(driver, dev, tree); 628 629 dev_del_ref(dev); 605 630 606 631 /* … … 611 636 612 637 /* 613 * Insert the device back.614 * The order is not relevant here so no harm is done615 * (actually, the order would be preserved in most cases).616 */617 list_append(link, &driver->devices);618 619 /*620 638 * Restart the cycle to go through all devices again. 621 639 */ 622 link = driver->devices.next; 623 } 624 625 async_hangup(phone); 640 link = driver->devices.head.next; 641 } 626 642 627 643 /* … … 673 689 list_initialize(&drv->devices); 674 690 fibril_mutex_initialize(&drv->driver_mutex); 675 drv-> phone = -1;691 drv->sess = NULL; 676 692 } 677 693 … … 704 720 } 705 721 706 /** Create devmap path and name for the function. */ 707 void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree) 708 { 709 char *devmap_pathname = NULL; 710 char *devmap_name = NULL; 711 712 asprintf(&devmap_name, "%s", fun->pathname); 713 if (devmap_name == NULL) 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) 714 732 return; 715 733 716 replace_char( devmap_name, '/', DEVMAP_SEPARATOR);717 718 asprintf(& devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,719 devmap_name);720 if ( devmap_pathname == NULL) {721 free( devmap_name);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); 722 740 return; 723 741 } 724 742 725 devmap_device_register_with_iface(devmap_pathname,726 &fun-> devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);727 728 tree_add_ devmap_function(tree, fun);729 730 free( devmap_name);731 free( devmap_pathname);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); 732 750 } 733 751 … … 737 755 * @param node The device's node in the device tree. 738 756 */ 739 void add_device( int phone,driver_t *drv, dev_node_t *dev, dev_tree_t *tree)757 void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree) 740 758 { 741 759 /* … … 746 764 drv->name, dev->pfun->name); 747 765 748 sysarg_t rc;749 ipc_call_t answer;750 751 766 /* Send the device to the driver. */ 752 767 devman_handle_t parent_handle; … … 756 771 parent_handle = 0; 757 772 } 758 759 aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, dev->handle, 773 774 async_exch_t *exch = async_exchange_begin(drv->sess); 775 776 ipc_call_t answer; 777 aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle, 760 778 parent_handle, &answer); 761 779 762 /* Send the device 'sname to the driver. */763 rc = async_data_write_start(phone, dev->pfun->name,780 /* Send the device name to the driver. */ 781 sysarg_t rc = async_data_write_start(exch, dev->pfun->name, 764 782 str_size(dev->pfun->name) + 1); 783 784 async_exchange_end(exch); 785 765 786 if (rc != EOK) { 766 787 /* TODO handle error */ … … 773 794 case EOK: 774 795 dev->state = DEVICE_USABLE; 796 exch = async_exchange_begin(drv->sess); 797 async_msg_1(exch, DRIVER_DEV_ADDED, dev->handle); 798 async_exchange_end(exch); 775 799 break; 776 800 case ENOENT: … … 811 835 812 836 /* Attach the driver to the device. */ 813 attach_driver( dev, drv);837 attach_driver(tree, dev, drv); 814 838 815 839 fibril_mutex_lock(&drv->driver_mutex); … … 821 845 fibril_mutex_unlock(&drv->driver_mutex); 822 846 823 if (is_running) { 824 /* Notify the driver about the new device. */ 825 int phone = async_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0); 826 if (phone >= 0) { 827 add_device(phone, drv, dev, tree); 828 async_hangup(phone); 829 } 830 } 831 847 /* Notify the driver about the new device. */ 848 if (is_running) 849 add_device(drv, dev, tree); 850 851 fibril_mutex_lock(&drv->driver_mutex); 852 fibril_mutex_unlock(&drv->driver_mutex); 853 854 fibril_rwlock_write_lock(&tree->rwlock); 855 if (dev->pfun != NULL) { 856 dev->pfun->state = FUN_ON_LINE; 857 } 858 fibril_rwlock_write_unlock(&tree->rwlock); 832 859 return true; 860 } 861 862 int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev) 863 { 864 async_exch_t *exch; 865 sysarg_t retval; 866 driver_t *drv; 867 devman_handle_t handle; 868 869 assert(dev != NULL); 870 871 log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev); 872 873 fibril_rwlock_read_lock(&tree->rwlock); 874 drv = dev->drv; 875 handle = dev->handle; 876 fibril_rwlock_read_unlock(&tree->rwlock); 877 878 exch = async_exchange_begin(drv->sess); 879 retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle); 880 async_exchange_end(exch); 881 882 return retval; 883 } 884 885 int driver_dev_gone(dev_tree_t *tree, dev_node_t *dev) 886 { 887 async_exch_t *exch; 888 sysarg_t retval; 889 driver_t *drv; 890 devman_handle_t handle; 891 892 assert(dev != NULL); 893 894 log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev); 895 896 fibril_rwlock_read_lock(&tree->rwlock); 897 drv = dev->drv; 898 handle = dev->handle; 899 fibril_rwlock_read_unlock(&tree->rwlock); 900 901 exch = async_exchange_begin(drv->sess); 902 retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle); 903 async_exchange_end(exch); 904 905 return retval; 906 } 907 908 int driver_fun_online(dev_tree_t *tree, fun_node_t *fun) 909 { 910 async_exch_t *exch; 911 sysarg_t retval; 912 driver_t *drv; 913 devman_handle_t handle; 914 915 log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun); 916 917 fibril_rwlock_read_lock(&tree->rwlock); 918 919 if (fun->dev == NULL) { 920 /* XXX root function? */ 921 fibril_rwlock_read_unlock(&tree->rwlock); 922 return EINVAL; 923 } 924 925 drv = fun->dev->drv; 926 handle = fun->handle; 927 fibril_rwlock_read_unlock(&tree->rwlock); 928 929 exch = async_exchange_begin(drv->sess); 930 retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle); 931 loc_exchange_end(exch); 932 933 return retval; 934 } 935 936 int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun) 937 { 938 async_exch_t *exch; 939 sysarg_t retval; 940 driver_t *drv; 941 devman_handle_t handle; 942 943 log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun); 944 945 fibril_rwlock_read_lock(&tree->rwlock); 946 if (fun->dev == NULL) { 947 /* XXX root function? */ 948 fibril_rwlock_read_unlock(&tree->rwlock); 949 return EINVAL; 950 } 951 952 drv = fun->dev->drv; 953 handle = fun->handle; 954 fibril_rwlock_read_unlock(&tree->rwlock); 955 956 exch = async_exchange_begin(drv->sess); 957 retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle); 958 loc_exchange_end(exch); 959 960 return retval; 961 833 962 } 834 963 … … 851 980 hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1, 852 981 &devman_functions_ops); 853 hash_table_create(&tree-> devmap_functions, DEVICE_BUCKETS, 1,854 & devmap_devices_ops);982 hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1, 983 &loc_devices_ops); 855 984 856 985 fibril_rwlock_initialize(&tree->rwlock); … … 859 988 if (!create_root_nodes(tree)) 860 989 return false; 861 990 862 991 /* Find suitable driver and start it. */ 863 return assign_driver(tree->root_node->child, drivers_list, tree); 992 dev_node_t *rdev = tree->root_node->child; 993 dev_add_ref(rdev); 994 int rc = assign_driver(rdev, drivers_list, tree); 995 dev_del_ref(rdev); 996 997 return rc; 864 998 } 865 999 … … 872 1006 dev_node_t *create_dev_node(void) 873 1007 { 874 dev_node_t *res = malloc(sizeof(dev_node_t)); 875 876 if (res != NULL) { 877 memset(res, 0, sizeof(dev_node_t)); 878 list_initialize(&res->functions); 879 link_initialize(&res->driver_devices); 880 link_initialize(&res->devman_dev); 881 } 882 883 return res; 1008 dev_node_t *dev; 1009 1010 dev = calloc(1, sizeof(dev_node_t)); 1011 if (dev == NULL) 1012 return NULL; 1013 1014 atomic_set(&dev->refcnt, 0); 1015 list_initialize(&dev->functions); 1016 link_initialize(&dev->driver_devices); 1017 link_initialize(&dev->devman_dev); 1018 1019 return dev; 884 1020 } 885 1021 … … 897 1033 } 898 1034 1035 /** Increase device node reference count. 1036 * 1037 * @param dev Device node 1038 */ 1039 void dev_add_ref(dev_node_t *dev) 1040 { 1041 atomic_inc(&dev->refcnt); 1042 } 1043 1044 /** Decrease device node reference count. 1045 * 1046 * When the count drops to zero the device node is freed. 1047 * 1048 * @param dev Device node 1049 */ 1050 void dev_del_ref(dev_node_t *dev) 1051 { 1052 if (atomic_predec(&dev->refcnt) == 0) 1053 delete_dev_node(dev); 1054 } 1055 1056 899 1057 /** Find the device node structure of the device witch has the specified handle. 900 1058 * … … 911 1069 912 1070 link = hash_table_find(&tree->devman_devices, &key); 1071 if (link == NULL) 1072 return NULL; 1073 913 1074 return hash_table_get_instance(link, dev_node_t, devman_dev); 914 1075 } … … 926 1087 fibril_rwlock_read_lock(&tree->rwlock); 927 1088 dev = find_dev_node_no_lock(tree, handle); 1089 if (dev != NULL) 1090 dev_add_ref(dev); 1091 928 1092 fibril_rwlock_read_unlock(&tree->rwlock); 929 1093 … … 931 1095 } 932 1096 1097 /** Get list of device functions. */ 1098 int dev_get_functions(dev_tree_t *tree, dev_node_t *dev, 1099 devman_handle_t *hdl_buf, size_t buf_size, size_t *act_size) 1100 { 1101 size_t act_cnt; 1102 size_t buf_cnt; 1103 1104 assert(fibril_rwlock_is_locked(&tree->rwlock)); 1105 1106 buf_cnt = buf_size / sizeof(devman_handle_t); 1107 1108 act_cnt = list_count(&dev->functions); 1109 *act_size = act_cnt * sizeof(devman_handle_t); 1110 1111 if (buf_size % sizeof(devman_handle_t) != 0) 1112 return EINVAL; 1113 1114 size_t pos = 0; 1115 list_foreach(dev->functions, item) { 1116 fun_node_t *fun = 1117 list_get_instance(item, fun_node_t, dev_functions); 1118 1119 if (pos < buf_cnt) { 1120 hdl_buf[pos] = fun->handle; 1121 } 1122 1123 pos++; 1124 } 1125 1126 return EOK; 1127 } 1128 1129 933 1130 /* Function nodes */ 934 1131 … … 939 1136 fun_node_t *create_fun_node(void) 940 1137 { 941 fun_node_t *res = malloc(sizeof(fun_node_t)); 942 943 if (res != NULL) { 944 memset(res, 0, sizeof(fun_node_t)); 945 link_initialize(&res->dev_functions); 946 list_initialize(&res->match_ids.ids); 947 list_initialize(&res->classes); 948 link_initialize(&res->devman_fun); 949 link_initialize(&res->devmap_fun); 950 } 951 952 return res; 1138 fun_node_t *fun; 1139 1140 fun = calloc(1, sizeof(fun_node_t)); 1141 if (fun == NULL) 1142 return NULL; 1143 1144 fun->state = FUN_INIT; 1145 atomic_set(&fun->refcnt, 0); 1146 link_initialize(&fun->dev_functions); 1147 list_initialize(&fun->match_ids.ids); 1148 link_initialize(&fun->devman_fun); 1149 link_initialize(&fun->loc_fun); 1150 1151 return fun; 953 1152 } 954 1153 … … 968 1167 } 969 1168 1169 /** Increase function node reference count. 1170 * 1171 * @param fun Function node 1172 */ 1173 void fun_add_ref(fun_node_t *fun) 1174 { 1175 atomic_inc(&fun->refcnt); 1176 } 1177 1178 /** Decrease function node reference count. 1179 * 1180 * When the count drops to zero the function node is freed. 1181 * 1182 * @param fun Function node 1183 */ 1184 void fun_del_ref(fun_node_t *fun) 1185 { 1186 if (atomic_predec(&fun->refcnt) == 0) 1187 delete_fun_node(fun); 1188 } 1189 970 1190 /** Find the function node with the specified handle. 971 1191 * … … 978 1198 unsigned long key = handle; 979 1199 link_t *link; 1200 fun_node_t *fun; 980 1201 981 1202 assert(fibril_rwlock_is_locked(&tree->rwlock)); … … 985 1206 return NULL; 986 1207 987 return hash_table_get_instance(link, fun_node_t, devman_fun); 1208 fun = hash_table_get_instance(link, fun_node_t, devman_fun); 1209 1210 return fun; 988 1211 } 989 1212 … … 999 1222 1000 1223 fibril_rwlock_read_lock(&tree->rwlock); 1224 1001 1225 fun = find_fun_node_no_lock(tree, handle); 1226 if (fun != NULL) 1227 fun_add_ref(fun); 1228 1002 1229 fibril_rwlock_read_unlock(&tree->rwlock); 1003 1230 … … 1007 1234 /** Create and set device's full path in device tree. 1008 1235 * 1236 * @param tree Device tree 1009 1237 * @param node The device's device node. 1010 1238 * @param parent The parent device node. … … 1012 1240 * resources etc.). 1013 1241 */ 1014 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent) 1015 { 1242 static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent) 1243 { 1244 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1016 1245 assert(fun->name != NULL); 1017 1246 … … 1040 1269 * 1041 1270 * @param tree The device tree. 1042 * @param node The newly added device node. 1043 * @param dev_name The name of the newly added device. 1044 * @param parent The parent device node. 1271 * @param dev The newly added device node. 1272 * @param pfun The parent function node. 1045 1273 * 1046 1274 * @return True on success, false otherwise (insufficient resources … … 1049 1277 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun) 1050 1278 { 1051 assert(dev != NULL);1052 assert(tree != NULL);1053 1279 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1054 1280 … … 1068 1294 } 1069 1295 1296 /** Remove device from device tree. 1297 * 1298 * @param tree Device tree 1299 * @param dev Device node 1300 */ 1301 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev) 1302 { 1303 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1304 1305 log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev); 1306 1307 /* Remove node from the handle-to-node map. */ 1308 unsigned long key = dev->handle; 1309 hash_table_remove(&tree->devman_devices, &key, 1); 1310 1311 /* Unlink from parent function. */ 1312 dev->pfun->child = NULL; 1313 dev->pfun = NULL; 1314 1315 dev->state = DEVICE_REMOVED; 1316 } 1317 1318 1070 1319 /** Insert new function into device tree. 1071 1320 * 1072 1321 * @param tree The device tree. 1073 * @param nodeThe newly added function node.1074 * @param dev_name The name of the newly added function.1075 * @param parentOwning device node.1322 * @param fun The newly added function node. 1323 * @param fun_name The name of the newly added function. 1324 * @param dev Owning device node. 1076 1325 * 1077 1326 * @return True on success, false otherwise (insufficient resources … … 1083 1332 fun_node_t *pfun; 1084 1333 1085 assert(fun != NULL);1086 assert(tree != NULL);1087 1334 assert(fun_name != NULL); 1088 1335 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); … … 1095 1342 1096 1343 fun->name = fun_name; 1097 if (!set_fun_path( fun, pfun)) {1344 if (!set_fun_path(tree, fun, pfun)) { 1098 1345 return false; 1099 1346 } … … 1110 1357 1111 1358 return true; 1359 } 1360 1361 /** Remove function from device tree. 1362 * 1363 * @param tree Device tree 1364 * @param node Function node to remove 1365 */ 1366 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun) 1367 { 1368 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1369 1370 /* Remove the node from the handle-to-node map. */ 1371 unsigned long key = fun->handle; 1372 hash_table_remove(&tree->devman_functions, &key, 1); 1373 1374 /* Remove the node from the list of its parent's children. */ 1375 if (fun->dev != NULL) 1376 list_remove(&fun->dev_functions); 1377 1378 fun->dev = NULL; 1379 fun->state = FUN_REMOVED; 1112 1380 } 1113 1381 … … 1131 1399 1132 1400 fun_node_t *fun = tree->root_node; 1401 fun_add_ref(fun); 1133 1402 /* 1134 1403 * Relative path to the function from its parent (but with '/' at the … … 1137 1406 char *rel_path = path; 1138 1407 char *next_path_elem = NULL; 1139 bool cont = true;1408 bool cont = (rel_path[1] != '\0'); 1140 1409 1141 1410 while (cont && fun != NULL) { … … 1148 1417 } 1149 1418 1150 fun = find_node_child(fun, rel_path + 1); 1419 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1); 1420 fun_del_ref(fun); 1421 fun = cfun; 1151 1422 1152 1423 if (cont) { … … 1166 1437 * Device tree rwlock should be held at least for reading. 1167 1438 * 1439 * @param tree Device tree 1168 1440 * @param dev Device the function belongs to. 1169 1441 * @param name Function name (not path). … … 1171 1443 * @retval NULL No function with given name. 1172 1444 */ 1173 fun_node_t *find_fun_node_in_device(dev_ node_t *dev, const char *name)1174 { 1175 assert(dev != NULL); 1445 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev, 1446 const char *name) 1447 { 1176 1448 assert(name != NULL); 1449 assert(fibril_rwlock_is_locked(&tree->rwlock)); 1177 1450 1178 1451 fun_node_t *fun; 1179 link_t *link; 1180 1181 for (link = dev->functions.next; 1182 link != &dev->functions; 1183 link = link->next) { 1452 1453 list_foreach(dev->functions, link) { 1184 1454 fun = list_get_instance(link, fun_node_t, dev_functions); 1185 1455 1186 if (str_cmp(name, fun->name) == 0) 1456 if (str_cmp(name, fun->name) == 0) { 1457 fun_add_ref(fun); 1187 1458 return fun; 1459 } 1188 1460 } 1189 1461 … … 1191 1463 } 1192 1464 1193 /** Find function node by its class name and index. */1194 fun_node_t *find_fun_node_by_class(class_list_t *class_list,1195 const char *class_name, const char *dev_name)1196 {1197 assert(class_list != NULL);1198 assert(class_name != NULL);1199 assert(dev_name != NULL);1200 1201 fibril_rwlock_read_lock(&class_list->rwlock);1202 1203 dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);1204 if (cl == NULL) {1205 fibril_rwlock_read_unlock(&class_list->rwlock);1206 return NULL;1207 }1208 1209 dev_class_info_t *dev = find_dev_in_class(cl, dev_name);1210 if (dev == NULL) {1211 fibril_rwlock_read_unlock(&class_list->rwlock);1212 return NULL;1213 }1214 1215 fun_node_t *fun = dev->fun;1216 1217 fibril_rwlock_read_unlock(&class_list->rwlock);1218 1219 return fun;1220 }1221 1222 1223 1465 /** Find child function node with a specified name. 1224 1466 * 1225 1467 * Device tree rwlock should be held at least for reading. 1226 1468 * 1469 * @param tree Device tree 1227 1470 * @param parent The parent function node. 1228 1471 * @param name The name of the child function. 1229 1472 * @return The child function node. 1230 1473 */ 1231 fun_node_t *find_node_child(fun_node_t *pfun, const char *name) 1232 { 1233 return find_fun_node_in_device(pfun->child, name); 1234 } 1235 1236 /* Device classes */ 1237 1238 /** Create device class. 1239 * 1240 * @return Device class. 1241 */ 1242 dev_class_t *create_dev_class(void) 1243 { 1244 dev_class_t *cl; 1245 1246 cl = (dev_class_t *) malloc(sizeof(dev_class_t)); 1247 if (cl != NULL) { 1248 memset(cl, 0, sizeof(dev_class_t)); 1249 list_initialize(&cl->devices); 1250 fibril_mutex_initialize(&cl->mutex); 1251 } 1252 1253 return cl; 1254 } 1255 1256 /** Create device class info. 1257 * 1258 * @return Device class info. 1259 */ 1260 dev_class_info_t *create_dev_class_info(void) 1261 { 1262 dev_class_info_t *info; 1263 1264 info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t)); 1265 if (info != NULL) { 1266 memset(info, 0, sizeof(dev_class_info_t)); 1267 link_initialize(&info->dev_classes); 1268 link_initialize(&info->devmap_link); 1269 link_initialize(&info->link); 1270 } 1271 1272 return info; 1273 } 1274 1275 size_t get_new_class_dev_idx(dev_class_t *cl) 1276 { 1277 size_t dev_idx; 1278 1279 fibril_mutex_lock(&cl->mutex); 1280 dev_idx = ++cl->curr_dev_idx; 1281 fibril_mutex_unlock(&cl->mutex); 1282 1283 return dev_idx; 1284 } 1285 1286 1287 /** Create unique device name within the class. 1288 * 1289 * @param cl The class. 1290 * @param base_dev_name Contains the base name for the device if it was 1291 * specified by the driver when it registered the device by 1292 * the class; NULL if driver specified no base name. 1293 * @return The unique name for the device within the class. 1294 */ 1295 char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name) 1296 { 1297 char *dev_name; 1298 const char *base_name; 1299 1300 if (base_dev_name != NULL) 1301 base_name = base_dev_name; 1302 else 1303 base_name = cl->base_dev_name; 1304 1305 size_t idx = get_new_class_dev_idx(cl); 1306 asprintf(&dev_name, "%s%zu", base_name, idx); 1307 1308 return dev_name; 1309 } 1310 1311 /** Add the device function to the class. 1312 * 1313 * The device may be added to multiple classes and a class may contain multiple 1314 * devices. The class and the device are associated with each other by the 1315 * dev_class_info_t structure. 1316 * 1317 * @param dev The device. 1318 * @param class The class. 1319 * @param base_dev_name The base name of the device within the class if 1320 * specified by the driver, NULL otherwise. 1321 * @return dev_class_info_t structure which associates the device 1322 * with the class. 1323 */ 1324 dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl, 1325 const char *base_dev_name) 1326 { 1327 dev_class_info_t *info; 1328 1329 assert(fun != NULL); 1330 assert(cl != NULL); 1331 1332 info = create_dev_class_info(); 1333 1334 1335 if (info != NULL) { 1336 info->dev_class = cl; 1337 info->fun = fun; 1338 1339 /* Add the device to the class. */ 1340 fibril_mutex_lock(&cl->mutex); 1341 list_append(&info->link, &cl->devices); 1342 fibril_mutex_unlock(&cl->mutex); 1343 1344 /* Add the class to the device. */ 1345 list_append(&info->dev_classes, &fun->classes); 1346 1347 /* Create unique name for the device within the class. */ 1348 info->dev_name = create_dev_name_for_class(cl, base_dev_name); 1349 } 1350 1351 return info; 1352 } 1353 1354 dev_class_t *get_dev_class(class_list_t *class_list, char *class_name) 1355 { 1356 dev_class_t *cl; 1357 1358 fibril_rwlock_write_lock(&class_list->rwlock); 1359 cl = find_dev_class_no_lock(class_list, class_name); 1360 if (cl == NULL) { 1361 cl = create_dev_class(); 1362 if (cl != NULL) { 1363 cl->name = class_name; 1364 cl->base_dev_name = ""; 1365 add_dev_class_no_lock(class_list, cl); 1366 } 1367 } 1368 1369 fibril_rwlock_write_unlock(&class_list->rwlock); 1370 return cl; 1371 } 1372 1373 dev_class_t *find_dev_class_no_lock(class_list_t *class_list, 1374 const char *class_name) 1375 { 1376 dev_class_t *cl; 1377 link_t *link = class_list->classes.next; 1378 1379 while (link != &class_list->classes) { 1380 cl = list_get_instance(link, dev_class_t, link); 1381 if (str_cmp(cl->name, class_name) == 0) { 1382 return cl; 1383 } 1384 link = link->next; 1385 } 1386 1387 return NULL; 1388 } 1389 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 link_t *link; 1401 for (link = dev_class->devices.next; 1402 link != &dev_class->devices; 1403 link = link->next) { 1404 dev_class_info_t *dev = list_get_instance(link, 1405 dev_class_info_t, link); 1406 1407 if (str_cmp(dev->dev_name, dev_name) == 0) { 1408 return dev; 1409 } 1410 } 1411 1412 return NULL; 1413 } 1414 1415 void init_class_list(class_list_t *class_list) 1416 { 1417 list_initialize(&class_list->classes); 1418 fibril_rwlock_initialize(&class_list->rwlock); 1419 hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1, 1420 &devmap_devices_class_ops); 1421 } 1422 1423 1424 /* Devmap devices */ 1425 1426 fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle) 1474 static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun, 1475 const char *name) 1476 { 1477 return find_fun_node_in_device(tree, pfun->child, name); 1478 } 1479 1480 /* loc devices */ 1481 1482 fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id) 1427 1483 { 1428 1484 fun_node_t *fun = NULL; 1429 1485 link_t *link; 1430 unsigned long key = (unsigned long) devmap_handle;1486 unsigned long key = (unsigned long) service_id; 1431 1487 1432 1488 fibril_rwlock_read_lock(&tree->rwlock); 1433 link = hash_table_find(&tree->devmap_functions, &key); 1434 if (link != NULL) 1435 fun = hash_table_get_instance(link, fun_node_t, devmap_fun); 1489 link = hash_table_find(&tree->loc_functions, &key); 1490 if (link != NULL) { 1491 fun = hash_table_get_instance(link, fun_node_t, loc_fun); 1492 fun_add_ref(fun); 1493 } 1436 1494 fibril_rwlock_read_unlock(&tree->rwlock); 1437 1495 … … 1439 1497 } 1440 1498 1441 fun_node_t *find_devmap_class_function(class_list_t *classes, 1442 devmap_handle_t devmap_handle) 1443 { 1444 fun_node_t *fun = NULL; 1445 dev_class_info_t *cli; 1446 link_t *link; 1447 unsigned long key = (unsigned long)devmap_handle; 1448 1449 fibril_rwlock_read_lock(&classes->rwlock); 1450 link = hash_table_find(&classes->devmap_functions, &key); 1451 if (link != NULL) { 1452 cli = hash_table_get_instance(link, dev_class_info_t, 1453 devmap_link); 1454 fun = cli->fun; 1455 } 1456 fibril_rwlock_read_unlock(&classes->rwlock); 1457 1458 return fun; 1459 } 1460 1461 void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli) 1462 { 1463 unsigned long key = (unsigned long) cli->devmap_handle; 1464 1465 fibril_rwlock_write_lock(&class_list->rwlock); 1466 hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link); 1467 fibril_rwlock_write_unlock(&class_list->rwlock); 1468 1469 assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL); 1470 } 1471 1472 void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun) 1473 { 1474 unsigned long key = (unsigned long) fun->devmap_handle; 1475 fibril_rwlock_write_lock(&tree->rwlock); 1476 hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun); 1477 fibril_rwlock_write_unlock(&tree->rwlock); 1499 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun) 1500 { 1501 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1502 1503 unsigned long key = (unsigned long) fun->service_id; 1504 hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun); 1478 1505 } 1479 1506
Note:
See TracChangeset
for help on using the changeset viewer.