Changes in uspace/srv/devman/devman.c [609243f4:c7bbf029] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
r609243f4 rc7bbf029 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 … … 593 564 dev_node_t *dev; 594 565 link_t *link; 566 int phone; 595 567 596 568 log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")", … … 598 570 599 571 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 } 600 579 601 580 /* … … 603 582 * that has not been passed to the driver. 604 583 */ 605 link = driver->devices. head.next;606 while (link != &driver->devices .head) {584 link = driver->devices.next; 585 while (link != &driver->devices) { 607 586 dev = list_get_instance(link, dev_node_t, driver_devices); 608 fibril_rwlock_write_lock(&tree->rwlock);609 610 587 if (dev->passed_to_driver) { 611 fibril_rwlock_write_unlock(&tree->rwlock);612 588 link = link->next; 613 589 continue; 614 590 } 615 591 616 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n", 617 (int)atomic_get(&dev->refcnt)); 618 dev_add_ref(dev); 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); 619 597 620 598 /* … … 623 601 */ 624 602 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); 603 604 add_device(phone, driver, dev, tree); 630 605 631 606 /* … … 636 611 637 612 /* 613 * Insert the device back. 614 * The order is not relevant here so no harm is done 615 * (actually, the order would be preserved in most cases). 616 */ 617 list_append(link, &driver->devices); 618 619 /* 638 620 * Restart the cycle to go through all devices again. 639 621 */ 640 link = driver->devices.head.next; 641 } 622 link = driver->devices.next; 623 } 624 625 async_hangup(phone); 642 626 643 627 /* … … 689 673 list_initialize(&drv->devices); 690 674 fibril_mutex_initialize(&drv->driver_mutex); 691 drv-> sess = NULL;675 drv->phone = -1; 692 676 } 693 677 … … 720 704 } 721 705 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) 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) 732 714 return; 733 715 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);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); 740 722 return; 741 723 } 742 724 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);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); 750 732 } 751 733 … … 755 737 * @param node The device's node in the device tree. 756 738 */ 757 void add_device( driver_t *drv, dev_node_t *dev, dev_tree_t *tree)739 void add_device(int phone, driver_t *drv, dev_node_t *dev, dev_tree_t *tree) 758 740 { 759 741 /* … … 764 746 drv->name, dev->pfun->name); 765 747 748 sysarg_t rc; 749 ipc_call_t answer; 750 766 751 /* Send the device to the driver. */ 767 752 devman_handle_t parent_handle; … … 771 756 parent_handle = 0; 772 757 } 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, 758 759 aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, dev->handle, 778 760 parent_handle, &answer); 779 761 780 /* Send the device name to the driver. */781 sysarg_t rc = async_data_write_start(exch, dev->pfun->name,762 /* Send the device's name to the driver. */ 763 rc = async_data_write_start(phone, dev->pfun->name, 782 764 str_size(dev->pfun->name) + 1); 783 784 async_exchange_end(exch);785 786 765 if (rc != EOK) { 787 766 /* TODO handle error */ … … 794 773 case EOK: 795 774 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);799 775 break; 800 776 case ENOENT: … … 835 811 836 812 /* Attach the driver to the device. */ 837 attach_driver( tree,dev, drv);813 attach_driver(dev, drv); 838 814 839 815 fibril_mutex_lock(&drv->driver_mutex); … … 845 821 fibril_mutex_unlock(&drv->driver_mutex); 846 822 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); 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 859 832 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 962 833 } 963 834 … … 980 851 hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1, 981 852 &devman_functions_ops); 982 hash_table_create(&tree-> loc_functions, DEVICE_BUCKETS, 1,983 & loc_devices_ops);853 hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1, 854 &devmap_devices_ops); 984 855 985 856 fibril_rwlock_initialize(&tree->rwlock); … … 988 859 if (!create_root_nodes(tree)) 989 860 return false; 990 861 991 862 /* Find suitable driver and start it. */ 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; 863 return assign_driver(tree->root_node->child, drivers_list, tree); 998 864 } 999 865 … … 1006 872 dev_node_t *create_dev_node(void) 1007 873 { 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; 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; 1020 884 } 1021 885 … … 1033 897 } 1034 898 1035 /** Increase device node reference count.1036 *1037 * @param dev Device node1038 */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 node1049 */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 1057 899 /** Find the device node structure of the device witch has the specified handle. 1058 900 * … … 1069 911 1070 912 link = hash_table_find(&tree->devman_devices, &key); 1071 if (link == NULL)1072 return NULL;1073 1074 913 return hash_table_get_instance(link, dev_node_t, devman_dev); 1075 914 } … … 1087 926 fibril_rwlock_read_lock(&tree->rwlock); 1088 927 dev = find_dev_node_no_lock(tree, handle); 1089 if (dev != NULL)1090 dev_add_ref(dev);1091 1092 928 fibril_rwlock_read_unlock(&tree->rwlock); 1093 929 … … 1095 931 } 1096 932 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 1130 933 /* Function nodes */ 1131 934 … … 1136 939 fun_node_t *create_fun_node(void) 1137 940 { 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; 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; 1152 953 } 1153 954 … … 1167 968 } 1168 969 1169 /** Increase function node reference count.1170 *1171 * @param fun Function node1172 */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 node1183 */1184 void fun_del_ref(fun_node_t *fun)1185 {1186 if (atomic_predec(&fun->refcnt) == 0)1187 delete_fun_node(fun);1188 }1189 1190 970 /** Find the function node with the specified handle. 1191 971 * … … 1198 978 unsigned long key = handle; 1199 979 link_t *link; 1200 fun_node_t *fun;1201 980 1202 981 assert(fibril_rwlock_is_locked(&tree->rwlock)); … … 1206 985 return NULL; 1207 986 1208 fun = hash_table_get_instance(link, fun_node_t, devman_fun); 1209 1210 return fun; 987 return hash_table_get_instance(link, fun_node_t, devman_fun); 1211 988 } 1212 989 … … 1222 999 1223 1000 fibril_rwlock_read_lock(&tree->rwlock); 1224 1225 1001 fun = find_fun_node_no_lock(tree, handle); 1226 if (fun != NULL)1227 fun_add_ref(fun);1228 1229 1002 fibril_rwlock_read_unlock(&tree->rwlock); 1230 1003 … … 1234 1007 /** Create and set device's full path in device tree. 1235 1008 * 1236 * @param tree Device tree1237 1009 * @param node The device's device node. 1238 1010 * @param parent The parent device node. … … 1240 1012 * resources etc.). 1241 1013 */ 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)); 1014 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent) 1015 { 1245 1016 assert(fun->name != NULL); 1246 1017 … … 1269 1040 * 1270 1041 * @param tree The device tree. 1271 * @param dev The newly added device node. 1272 * @param pfun The parent function node. 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. 1273 1045 * 1274 1046 * @return True on success, false otherwise (insufficient resources … … 1277 1049 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun) 1278 1050 { 1051 assert(dev != NULL); 1052 assert(tree != NULL); 1279 1053 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1280 1054 … … 1294 1068 } 1295 1069 1296 /** Remove device from device tree.1297 *1298 * @param tree Device tree1299 * @param dev Device node1300 */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 1319 1070 /** Insert new function into device tree. 1320 1071 * 1321 1072 * @param tree The device tree. 1322 * @param funThe newly added function node.1323 * @param fun_name The name of the newly added function.1324 * @param devOwning device node.1073 * @param node The newly added function node. 1074 * @param dev_name The name of the newly added function. 1075 * @param parent Owning device node. 1325 1076 * 1326 1077 * @return True on success, false otherwise (insufficient resources … … 1332 1083 fun_node_t *pfun; 1333 1084 1085 assert(fun != NULL); 1086 assert(tree != NULL); 1334 1087 assert(fun_name != NULL); 1335 1088 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); … … 1342 1095 1343 1096 fun->name = fun_name; 1344 if (!set_fun_path( tree,fun, pfun)) {1097 if (!set_fun_path(fun, pfun)) { 1345 1098 return false; 1346 1099 } … … 1357 1110 1358 1111 return true; 1359 }1360 1361 /** Remove function from device tree.1362 *1363 * @param tree Device tree1364 * @param node Function node to remove1365 */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;1380 1112 } 1381 1113 … … 1399 1131 1400 1132 fun_node_t *fun = tree->root_node; 1401 fun_add_ref(fun);1402 1133 /* 1403 1134 * Relative path to the function from its parent (but with '/' at the … … 1406 1137 char *rel_path = path; 1407 1138 char *next_path_elem = NULL; 1408 bool cont = (rel_path[1] != '\0');1139 bool cont = true; 1409 1140 1410 1141 while (cont && fun != NULL) { … … 1417 1148 } 1418 1149 1419 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1); 1420 fun_del_ref(fun); 1421 fun = cfun; 1150 fun = find_node_child(fun, rel_path + 1); 1422 1151 1423 1152 if (cont) { … … 1437 1166 * Device tree rwlock should be held at least for reading. 1438 1167 * 1439 * @param tree Device tree1440 1168 * @param dev Device the function belongs to. 1441 1169 * @param name Function name (not path). … … 1443 1171 * @retval NULL No function with given name. 1444 1172 */ 1445 fun_node_t *find_fun_node_in_device(dev_ tree_t *tree, dev_node_t *dev,1446 const char *name) 1447 { 1173 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name) 1174 { 1175 assert(dev != NULL); 1448 1176 assert(name != NULL); 1449 assert(fibril_rwlock_is_locked(&tree->rwlock));1450 1177 1451 1178 fun_node_t *fun; 1452 1453 list_foreach(dev->functions, link) { 1179 link_t *link; 1180 1181 for (link = dev->functions.next; 1182 link != &dev->functions; 1183 link = link->next) { 1454 1184 fun = list_get_instance(link, fun_node_t, dev_functions); 1455 1185 1456 if (str_cmp(name, fun->name) == 0) { 1457 fun_add_ref(fun); 1186 if (str_cmp(name, fun->name) == 0) 1458 1187 return fun; 1459 }1460 1188 } 1461 1189 … … 1463 1191 } 1464 1192 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 1465 1223 /** Find child function node with a specified name. 1466 1224 * 1467 1225 * Device tree rwlock should be held at least for reading. 1468 1226 * 1469 * @param tree Device tree1470 1227 * @param parent The parent function node. 1471 1228 * @param name The name of the child function. 1472 1229 * @return The child function node. 1473 1230 */ 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) 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) 1483 1427 { 1484 1428 fun_node_t *fun = NULL; 1485 1429 link_t *link; 1486 unsigned long key = (unsigned long) service_id;1430 unsigned long key = (unsigned long) devmap_handle; 1487 1431 1488 1432 fibril_rwlock_read_lock(&tree->rwlock); 1489 link = hash_table_find(&tree->loc_functions, &key); 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); 1436 fibril_rwlock_read_unlock(&tree->rwlock); 1437 1438 return fun; 1439 } 1440 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); 1490 1451 if (link != NULL) { 1491 fun = hash_table_get_instance(link, fun_node_t, loc_fun); 1492 fun_add_ref(fun); 1493 } 1494 fibril_rwlock_read_unlock(&tree->rwlock); 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); 1495 1457 1496 1458 return fun; 1497 1459 } 1498 1460 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); 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); 1505 1478 } 1506 1479
Note:
See TracChangeset
for help on using the changeset viewer.