Changeset 8ff0bd2 in mainline for uspace/srv/devman
- Timestamp:
- 2011-09-04T11:30:58Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 03bc76a
- Parents:
- d2c67e7 (diff), deac215e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- uspace/srv/devman
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
rd2c67e7 r8ff0bd2 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 -
uspace/srv/devman/devman.h
rd2c67e7 r8ff0bd2 1 1 /* 2 2 * Copyright (c) 2010 Lenka Trochtova 3 * Copyright (c) 2011 Jiri Svoboda 3 4 * All rights reserved. 4 5 * … … 41 42 #include <adt/hash_table.h> 42 43 #include <ipc/devman.h> 43 #include <ipc/ devmap.h>44 #include <ipc/loc.h> 44 45 #include <fibril_synch.h> 45 46 #include <atomic.h> … … 53 54 #define DEVICE_BUCKETS 256 54 55 55 #define DEVMAP_CLASS_NAMESPACE "class" 56 #define DEVMAP_DEVICE_NAMESPACE "devices" 57 #define DEVMAP_SEPARATOR '\\' 56 #define LOC_DEVICE_NAMESPACE "devices" 57 #define LOC_SEPARATOR '\\' 58 58 59 59 struct dev_node; … … 62 62 struct fun_node; 63 63 typedef struct fun_node fun_node_t; 64 65 typedef struct { 66 fibril_mutex_t mutex; 67 struct driver *driver; 68 } client_t; 64 69 65 70 typedef enum { … … 96 101 /** List of device ids for device-to-driver matching. */ 97 102 match_id_list_t match_ids; 98 /** Pointer to the linked list of devices controlled by this driver. */99 li nk_t devices;103 /** List of devices controlled by this driver. */ 104 list_t devices; 100 105 101 106 /** … … 108 113 typedef struct driver_list { 109 114 /** List of drivers */ 110 li nk_t drivers;115 list_t drivers; 111 116 /** Fibril mutex for list of drivers. */ 112 117 fibril_mutex_t drivers_mutex; 113 118 } driver_list_t; 114 119 115 /** The state of the device.*/120 /** Device state */ 116 121 typedef enum { 117 122 DEVICE_NOT_INITIALIZED = 0, 118 123 DEVICE_USABLE, 119 124 DEVICE_NOT_PRESENT, 120 DEVICE_INVALID 125 DEVICE_INVALID, 126 /** Device node has been removed from the tree */ 127 DEVICE_REMOVED 121 128 } device_state_t; 122 129 123 130 /** Device node in the device tree. */ 124 131 struct dev_node { 132 /** Reference count */ 133 atomic_t refcnt; 134 125 135 /** The global unique identifier of the device. */ 126 136 devman_handle_t handle; … … 130 140 131 141 /** List of device functions. */ 132 li nk_t functions;142 list_t functions; 133 143 /** Driver of this device. */ 134 144 driver_t *drv; … … 149 159 }; 150 160 161 /** Function state */ 162 typedef enum { 163 FUN_INIT = 0, 164 FUN_OFF_LINE, 165 FUN_ON_LINE, 166 /** Function node has been removed from the tree */ 167 FUN_REMOVED 168 } fun_state_t; 169 151 170 /** Function node in the device tree. */ 152 171 struct fun_node { 172 /** Reference count */ 173 atomic_t refcnt; 174 /** State */ 175 fun_state_t state; 176 153 177 /** The global unique identifier of the function */ 154 178 devman_handle_t handle; 155 179 /** Name of the function, assigned by the device driver */ 156 180 char *name; 181 /** Function type */ 182 fun_type_t ftype; 157 183 158 184 /** Full path and name of the device in device hierarchy */ … … 170 196 match_id_list_t match_ids; 171 197 172 /** The list of device classes to which this device function belongs. */ 173 link_t classes; 174 /** Devmap handle if the device function is registered by devmap. */ 175 devmap_handle_t devmap_handle; 198 /** Service ID if the device function is registered with loc. */ 199 service_id_t service_id; 176 200 177 201 /** … … 181 205 182 206 /** 183 * Used by the hash table of functions indexed by devmap device handles.184 */ 185 link_t devmap_fun;207 * Used by the hash table of functions indexed by service IDs. 208 */ 209 link_t loc_fun; 186 210 }; 187 211 … … 208 232 209 233 /** 210 * Hash table of devices registered by devmapper, indexed by devmap211 * handles.212 */ 213 hash_table_t devmap_functions;234 * Hash table of services registered with location service, indexed by 235 * service IDs. 236 */ 237 hash_table_t loc_functions; 214 238 } dev_tree_t; 215 216 typedef struct dev_class {217 /** The name of the class. */218 const char *name;219 220 /**221 * Pointer to the previous and next class in the list of registered222 * classes.223 */224 link_t link;225 226 /**227 * List of dev_class_info structures - one for each device registered by228 * this class.229 */230 link_t devices;231 232 /**233 * Default base name for the device within the class, might be overrided234 * by the driver.235 */236 const char *base_dev_name;237 238 /** Unique numerical identifier of the newly added device. */239 size_t curr_dev_idx;240 /** Synchronize access to the list of devices in this class. */241 fibril_mutex_t mutex;242 } dev_class_t;243 244 /**245 * Provides n-to-m mapping between function nodes and classes - each function246 * can register in an arbitrary number of classes and each class can contain247 * an arbitrary number of device functions.248 */249 typedef struct dev_class_info {250 /** The class. */251 dev_class_t *dev_class;252 /** The device. */253 fun_node_t *fun;254 255 /**256 * Pointer to the previous and next class info in the list of devices257 * registered by the class.258 */259 link_t link;260 261 /**262 * Pointer to the previous and next class info in the list of classes263 * by which the device is registered.264 */265 link_t dev_classes;266 267 /** The name of the device function within the class. */268 char *dev_name;269 /** The handle of the device by device mapper in the class namespace. */270 devmap_handle_t devmap_handle;271 272 /**273 * Link in the hash table of devices registered by the devmapper using274 * their class names.275 */276 link_t devmap_link;277 } dev_class_info_t;278 279 /** The list of device classes. */280 typedef struct class_list {281 /** List of classes. */282 link_t classes;283 284 /**285 * Hash table of devices registered by devmapper using their class name,286 * indexed by devmap handles.287 */288 hash_table_t devmap_functions;289 290 /** Fibril mutex for list of classes. */291 fibril_rwlock_t rwlock;292 } class_list_t;293 239 294 240 /* Match ids and scores */ … … 312 258 313 259 extern void add_driver(driver_list_t *, driver_t *); 314 extern void attach_driver(dev_node_t *, driver_t *); 315 extern void add_device(async_sess_t *, driver_t *, dev_node_t *, dev_tree_t *); 260 extern void attach_driver(dev_tree_t *, dev_node_t *, driver_t *); 261 extern void detach_driver(dev_tree_t *, dev_node_t *); 262 extern void add_device(driver_t *, dev_node_t *, dev_tree_t *); 316 263 extern bool start_driver(driver_t *); 264 extern int driver_dev_remove(dev_tree_t *, dev_node_t *); 265 extern int driver_fun_online(dev_tree_t *, fun_node_t *); 266 extern int driver_fun_offline(dev_tree_t *, fun_node_t *); 317 267 318 268 extern driver_t *find_driver(driver_list_t *, const char *); … … 327 277 extern dev_node_t *create_dev_node(void); 328 278 extern void delete_dev_node(dev_node_t *node); 279 extern void dev_add_ref(dev_node_t *); 280 extern void dev_del_ref(dev_node_t *); 329 281 extern dev_node_t *find_dev_node_no_lock(dev_tree_t *tree, 330 282 devman_handle_t handle); 331 283 extern dev_node_t *find_dev_node(dev_tree_t *tree, devman_handle_t handle); 332 284 extern dev_node_t *find_dev_function(dev_node_t *, const char *); 285 extern int dev_get_functions(dev_tree_t *tree, dev_node_t *, devman_handle_t *, 286 size_t, size_t *); 333 287 334 288 extern fun_node_t *create_fun_node(void); 335 289 extern void delete_fun_node(fun_node_t *); 290 extern void fun_add_ref(fun_node_t *); 291 extern void fun_del_ref(fun_node_t *); 336 292 extern fun_node_t *find_fun_node_no_lock(dev_tree_t *tree, 337 293 devman_handle_t handle); 338 294 extern fun_node_t *find_fun_node(dev_tree_t *tree, devman_handle_t handle); 339 295 extern fun_node_t *find_fun_node_by_path(dev_tree_t *, char *); 340 extern fun_node_t *find_fun_node_in_device(dev_ node_t *, const char *);341 extern fun_node_t *find_fun_node_by_class(class_list_t *, const char *,const char *);296 extern fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *, 297 const char *); 342 298 343 299 /* Device tree */ … … 346 302 extern bool create_root_nodes(dev_tree_t *); 347 303 extern bool insert_dev_node(dev_tree_t *, dev_node_t *, fun_node_t *); 304 extern void remove_dev_node(dev_tree_t *, dev_node_t *); 348 305 extern bool insert_fun_node(dev_tree_t *, fun_node_t *, char *, dev_node_t *); 349 350 /* Device classes */ 351 352 extern dev_class_t *create_dev_class(void); 353 extern dev_class_info_t *create_dev_class_info(void); 354 extern size_t get_new_class_dev_idx(dev_class_t *); 355 extern char *create_dev_name_for_class(dev_class_t *, const char *); 356 extern dev_class_info_t *add_function_to_class(fun_node_t *, dev_class_t *, 357 const char *); 358 359 extern void init_class_list(class_list_t *); 360 361 extern dev_class_t *get_dev_class(class_list_t *, char *); 362 extern dev_class_t *find_dev_class_no_lock(class_list_t *, const char *); 363 extern dev_class_info_t *find_dev_in_class(dev_class_t *, const char *); 364 extern void add_dev_class_no_lock(class_list_t *, dev_class_t *); 365 366 /* Devmap devices */ 367 368 extern void devmap_register_tree_function(fun_node_t *, dev_tree_t *); 369 370 extern fun_node_t *find_devmap_tree_function(dev_tree_t *, devmap_handle_t); 371 extern fun_node_t *find_devmap_class_function(class_list_t *, devmap_handle_t); 372 373 extern void class_add_devmap_function(class_list_t *, dev_class_info_t *); 374 extern void tree_add_devmap_function(dev_tree_t *, fun_node_t *); 306 extern void remove_fun_node(dev_tree_t *, fun_node_t *); 307 308 /* Loc services */ 309 310 extern void loc_register_tree_function(fun_node_t *, dev_tree_t *); 311 312 extern fun_node_t *find_loc_tree_function(dev_tree_t *, service_id_t); 313 314 extern void tree_add_loc_function(dev_tree_t *, fun_node_t *); 375 315 376 316 #endif -
uspace/srv/devman/main.c
rd2c67e7 r8ff0bd2 56 56 #include <ipc/driver.h> 57 57 #include <thread.h> 58 #include < devmap.h>58 #include <loc.h> 59 59 60 60 #include "devman.h" … … 64 64 static driver_list_t drivers_list; 65 65 static dev_tree_t device_tree; 66 static class_list_t class_list; 66 67 static int init_running_drv(void *drv); 67 68 68 69 /** Register running driver. */ 69 static driver_t *devman_driver_register(void) 70 { 71 ipc_call_t icall; 72 ipc_callid_t iid; 70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call) 71 { 73 72 driver_t *driver = NULL; 73 char *drv_name = NULL; 74 74 75 75 log_msg(LVL_DEBUG, "devman_driver_register"); 76 77 iid = async_get_call(&icall);78 if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {79 async_answer_0(iid, EREFUSED);80 return NULL;81 }82 83 char *drv_name = NULL;84 76 85 77 /* Get driver name. */ 86 78 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0); 87 79 if (rc != EOK) { 88 async_answer_0( iid, rc);80 async_answer_0(callid, rc); 89 81 return NULL; 90 82 } … … 99 91 free(drv_name); 100 92 drv_name = NULL; 101 async_answer_0( iid, ENOENT);93 async_answer_0(callid, ENOENT); 102 94 return NULL; 103 95 } … … 113 105 driver->name); 114 106 fibril_mutex_unlock(&driver->driver_mutex); 115 async_answer_0( iid, EEXISTS);107 async_answer_0(callid, EEXISTS); 116 108 return NULL; 117 109 } … … 135 127 log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.", 136 128 driver->name); 137 driver->sess = async_callback_receive(EXCHANGE_ SERIALIZE);129 driver->sess = async_callback_receive(EXCHANGE_PARALLEL); 138 130 if (!driver->sess) { 139 131 fibril_mutex_unlock(&driver->driver_mutex); 140 async_answer_0( iid, ENOTSUP);132 async_answer_0(callid, ENOTSUP); 141 133 return NULL; 142 134 } 143 144 fibril_mutex_unlock(&driver->driver_mutex);135 /* FIXME: Work around problem with callback sessions */ 136 async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0); 145 137 146 138 log_msg(LVL_NOTE, … … 148 140 driver->name); 149 141 150 async_answer_0(iid, EOK); 151 142 /* 143 * Initialize the driver as running (e.g. pass assigned devices to it) 144 * in a separate fibril; the separate fibril is used to enable the 145 * driver to use devman service during the driver's initialization. 146 */ 147 fid_t fid = fibril_create(init_running_drv, driver); 148 if (fid == 0) { 149 log_msg(LVL_ERROR, "Failed to create initialization fibril " \ 150 "for driver `%s'.", driver->name); 151 fibril_mutex_unlock(&driver->driver_mutex); 152 async_answer_0(callid, ENOMEM); 153 return NULL; 154 } 155 156 fibril_add_ready(fid); 157 fibril_mutex_unlock(&driver->driver_mutex); 158 159 async_answer_0(callid, EOK); 152 160 return driver; 153 161 } … … 226 234 dev_node_t *dev_node = (dev_node_t *) arg; 227 235 assign_driver(dev_node, &drivers_list, &device_tree); 236 237 /* Delete one reference we got from the caller. */ 238 dev_del_ref(dev_node); 228 239 return EOK; 229 240 } 230 241 231 /** Handle function registration. 232 * 233 * Child devices are registered by their parent's device driver. 234 */ 235 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call) 236 { 237 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call); 238 devman_handle_t dev_handle = IPC_GET_ARG2(*call); 239 sysarg_t match_count = IPC_GET_ARG3(*call); 240 dev_tree_t *tree = &device_tree; 241 242 fibril_rwlock_write_lock(&tree->rwlock); 243 244 dev_node_t *dev = NULL; 245 dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle); 246 247 if (pdev == NULL) { 248 fibril_rwlock_write_unlock(&tree->rwlock); 249 async_answer_0(callid, ENOENT); 250 return; 251 } 252 253 if (ftype != fun_inner && ftype != fun_exposed) { 254 /* Unknown function type */ 255 log_msg(LVL_ERROR, 256 "Unknown function type %d provided by driver.", 257 (int) ftype); 258 259 fibril_rwlock_write_unlock(&tree->rwlock); 260 async_answer_0(callid, EINVAL); 261 return; 262 } 263 264 char *fun_name = NULL; 265 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0); 266 if (rc != EOK) { 267 fibril_rwlock_write_unlock(&tree->rwlock); 268 async_answer_0(callid, rc); 269 return; 270 } 271 272 /* Check that function with same name is not there already. */ 273 if (find_fun_node_in_device(pdev, fun_name) != NULL) { 274 fibril_rwlock_write_unlock(&tree->rwlock); 275 async_answer_0(callid, EEXISTS); 276 printf(NAME ": Warning, driver tried to register `%s' twice.\n", 277 fun_name); 278 free(fun_name); 279 return; 280 } 281 282 fun_node_t *fun = create_fun_node(); 283 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) { 284 fibril_rwlock_write_unlock(&tree->rwlock); 285 delete_fun_node(fun); 286 async_answer_0(callid, ENOMEM); 287 return; 288 } 289 290 if (ftype == fun_inner) { 242 static int online_function(fun_node_t *fun) 243 { 244 dev_node_t *dev; 245 246 fibril_rwlock_write_lock(&device_tree.rwlock); 247 248 if (fun->state == FUN_ON_LINE) { 249 fibril_rwlock_write_unlock(&device_tree.rwlock); 250 log_msg(LVL_WARN, "Function %s is already on line.", 251 fun->pathname); 252 return EOK; 253 } 254 255 if (fun->ftype == fun_inner) { 291 256 dev = create_dev_node(); 292 257 if (dev == NULL) { 293 fibril_rwlock_write_unlock(&tree->rwlock); 294 delete_fun_node(fun); 295 async_answer_0(callid, ENOMEM); 296 return; 258 fibril_rwlock_write_unlock(&device_tree.rwlock); 259 return ENOMEM; 297 260 } 298 261 299 insert_dev_node(tree, dev, fun); 300 } 301 302 fibril_rwlock_write_unlock(&tree->rwlock); 262 insert_dev_node(&device_tree, dev, fun); 263 dev_add_ref(dev); 264 } 303 265 304 266 log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname); 305 267 306 devman_receive_match_ids(match_count, &fun->match_ids); 307 308 if (ftype == fun_inner) { 268 if (fun->ftype == fun_inner) { 269 dev = fun->child; 309 270 assert(dev != NULL); 271 272 /* Give one reference over to assign_driver_fibril(). */ 273 dev_add_ref(dev); 310 274 /* 311 275 * Try to find a suitable driver and assign it to the device. We do … … 317 281 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev); 318 282 if (assign_fibril == 0) { 319 /* 320 * Fallback in case we are out of memory. 321 * Probably not needed as we will die soon anyway ;-). 322 */ 323 (void) assign_driver_fibril(fun); 324 } else { 325 fibril_add_ready(assign_fibril); 283 log_msg(LVL_ERROR, "Failed to create fibril for " 284 "assigning driver."); 285 /* XXX Cleanup */ 286 fibril_rwlock_write_unlock(&device_tree.rwlock); 287 return ENOMEM; 288 } 289 fibril_add_ready(assign_fibril); 290 } else { 291 loc_register_tree_function(fun, &device_tree); 292 } 293 294 fibril_rwlock_write_unlock(&device_tree.rwlock); 295 296 return EOK; 297 } 298 299 static int offline_function(fun_node_t *fun) 300 { 301 int rc; 302 303 fibril_rwlock_write_lock(&device_tree.rwlock); 304 305 if (fun->state == FUN_OFF_LINE) { 306 fibril_rwlock_write_unlock(&device_tree.rwlock); 307 log_msg(LVL_WARN, "Function %s is already off line.", 308 fun->pathname); 309 return EOK; 310 } 311 312 if (fun->ftype == fun_inner) { 313 log_msg(LVL_DEBUG, "Offlining inner function %s.", 314 fun->pathname); 315 316 if (fun->child != NULL) { 317 dev_node_t *dev = fun->child; 318 319 dev_add_ref(dev); 320 fibril_rwlock_write_unlock(&device_tree.rwlock); 321 322 /* If device is owned by driver, ask driver to give it up. */ 323 if (dev->state == DEVICE_USABLE) { 324 rc = driver_dev_remove(&device_tree, dev); 325 if (rc != EOK) { 326 dev_del_ref(dev); 327 return ENOTSUP; 328 } 329 } 330 331 /* Verify that driver removed all functions */ 332 fibril_rwlock_read_lock(&device_tree.rwlock); 333 if (!list_empty(&dev->functions)) { 334 fibril_rwlock_read_unlock(&device_tree.rwlock); 335 return EIO; 336 } 337 driver_t *driver = dev->drv; 338 fibril_rwlock_read_unlock(&device_tree.rwlock); 339 340 if (driver) 341 detach_driver(&device_tree, dev); 342 343 fibril_rwlock_write_lock(&device_tree.rwlock); 344 remove_dev_node(&device_tree, dev); 345 346 /* Delete ref created when node was inserted */ 347 dev_del_ref(dev); 348 /* Delete ref created by dev_add_ref(dev) above */ 349 dev_del_ref(dev); 326 350 } 327 351 } else { 328 devmap_register_tree_function(fun, tree); 352 /* Unregister from location service */ 353 rc = loc_service_unregister(fun->service_id); 354 if (rc != EOK) { 355 fibril_rwlock_write_unlock(&device_tree.rwlock); 356 log_msg(LVL_ERROR, "Failed unregistering tree service."); 357 return EIO; 358 } 359 360 fun->service_id = 0; 361 } 362 363 fun->state = FUN_OFF_LINE; 364 fibril_rwlock_write_unlock(&device_tree.rwlock); 365 366 return EOK; 367 } 368 369 /** Handle function registration. 370 * 371 * Child devices are registered by their parent's device driver. 372 */ 373 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call) 374 { 375 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call); 376 devman_handle_t dev_handle = IPC_GET_ARG2(*call); 377 sysarg_t match_count = IPC_GET_ARG3(*call); 378 dev_tree_t *tree = &device_tree; 379 380 dev_node_t *pdev = find_dev_node(&device_tree, dev_handle); 381 if (pdev == NULL) { 382 async_answer_0(callid, ENOENT); 383 return; 384 } 385 386 if (ftype != fun_inner && ftype != fun_exposed) { 387 /* Unknown function type */ 388 log_msg(LVL_ERROR, 389 "Unknown function type %d provided by driver.", 390 (int) ftype); 391 392 dev_del_ref(pdev); 393 async_answer_0(callid, EINVAL); 394 return; 395 } 396 397 char *fun_name = NULL; 398 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0); 399 if (rc != EOK) { 400 dev_del_ref(pdev); 401 async_answer_0(callid, rc); 402 return; 403 } 404 405 fibril_rwlock_write_lock(&tree->rwlock); 406 407 /* Check device state */ 408 if (pdev->state == DEVICE_REMOVED) { 409 fibril_rwlock_write_unlock(&tree->rwlock); 410 dev_del_ref(pdev); 411 async_answer_0(callid, ENOENT); 412 return; 413 } 414 415 /* Check that function with same name is not there already. */ 416 if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) { 417 fibril_rwlock_write_unlock(&tree->rwlock); 418 dev_del_ref(pdev); 419 async_answer_0(callid, EEXISTS); 420 printf(NAME ": Warning, driver tried to register `%s' twice.\n", 421 fun_name); 422 free(fun_name); 423 return; 424 } 425 426 fun_node_t *fun = create_fun_node(); 427 fun_add_ref(fun); 428 fun->ftype = ftype; 429 430 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) { 431 fibril_rwlock_write_unlock(&tree->rwlock); 432 dev_del_ref(pdev); 433 delete_fun_node(fun); 434 async_answer_0(callid, ENOMEM); 435 return; 436 } 437 438 fibril_rwlock_write_unlock(&tree->rwlock); 439 dev_del_ref(pdev); 440 441 devman_receive_match_ids(match_count, &fun->match_ids); 442 443 rc = online_function(fun); 444 if (rc != EOK) { 445 /* XXX clean up */ 446 async_answer_0(callid, rc); 447 return; 329 448 } 330 449 … … 333 452 } 334 453 335 static void devmap_register_class_dev(dev_class_info_t *cli) 336 { 337 /* Create devmap path and name for the device. */ 338 char *devmap_pathname = NULL; 339 340 asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE, 341 cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name); 342 if (devmap_pathname == NULL) 343 return; 344 345 /* 346 * Register the device by the device mapper and remember its devmap 347 * handle. 348 */ 349 devmap_device_register_with_iface(devmap_pathname, 350 &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP); 351 352 /* 353 * Add device to the hash map of class devices registered by device 354 * mapper. 355 */ 356 class_add_devmap_function(&class_list, cli); 357 358 free(devmap_pathname); 359 } 360 361 static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call) 454 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call) 362 455 { 363 456 devman_handle_t handle = IPC_GET_ARG1(*call); 364 365 /* Get class name. */ 366 char *class_name; 367 int rc = async_data_write_accept((void **) &class_name, true, 457 category_id_t cat_id; 458 int rc; 459 460 /* Get category name. */ 461 char *cat_name; 462 rc = async_data_write_accept((void **) &cat_name, true, 368 463 0, 0, 0, 0); 369 464 if (rc != EOK) { 370 465 async_answer_0(callid, rc); 371 466 return; 372 } 467 } 373 468 374 469 fun_node_t *fun = find_fun_node(&device_tree, handle); … … 378 473 } 379 474 380 dev_class_t *cl = get_dev_class(&class_list, class_name); 381 dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL); 382 383 /* Register the device's class alias by devmapper. */ 384 devmap_register_class_dev(class_info); 385 386 log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.", 387 fun->pathname, class_name, class_info->dev_name); 388 475 fibril_rwlock_read_lock(&device_tree.rwlock); 476 477 /* Check function state */ 478 if (fun->state == FUN_REMOVED) { 479 fibril_rwlock_read_unlock(&device_tree.rwlock); 480 async_answer_0(callid, ENOENT); 481 return; 482 } 483 484 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING); 485 if (rc == EOK) { 486 loc_service_add_to_cat(fun->service_id, cat_id); 487 } else { 488 log_msg(LVL_ERROR, "Failed adding function `%s' to category " 489 "`%s'.", fun->pathname, cat_name); 490 } 491 492 log_msg(LVL_NOTE, "Function `%s' added to category `%s'.", 493 fun->pathname, cat_name); 494 495 fibril_rwlock_read_unlock(&device_tree.rwlock); 496 fun_del_ref(fun); 497 498 async_answer_0(callid, EOK); 499 } 500 501 /** Online function by driver request. 502 * 503 */ 504 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall, 505 driver_t *drv) 506 { 507 fun_node_t *fun; 508 int rc; 509 510 printf("devman_drv_fun_online()\n"); 511 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 512 if (fun == NULL) { 513 async_answer_0(iid, ENOENT); 514 return; 515 } 516 517 fibril_rwlock_read_lock(&device_tree.rwlock); 518 if (fun->dev == NULL || fun->dev->drv != drv) { 519 fibril_rwlock_read_unlock(&device_tree.rwlock); 520 fun_del_ref(fun); 521 async_answer_0(iid, ENOENT); 522 return; 523 } 524 fibril_rwlock_read_unlock(&device_tree.rwlock); 525 526 rc = online_function(fun); 527 if (rc != EOK) { 528 printf("devman_drv_fun_online() online_fun->ERROR\n"); 529 fun_del_ref(fun); 530 async_answer_0(iid, (sysarg_t) rc); 531 return; 532 } 533 534 fun_del_ref(fun); 535 printf("devman_drv_fun_online() online_fun->OK\n"); 536 537 async_answer_0(iid, (sysarg_t) EOK); 538 } 539 540 541 /** Offline function by driver request. 542 * 543 */ 544 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall, 545 driver_t *drv) 546 { 547 fun_node_t *fun; 548 int rc; 549 550 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 551 if (fun == NULL) { 552 async_answer_0(iid, ENOENT); 553 return; 554 } 555 556 fibril_rwlock_write_lock(&device_tree.rwlock); 557 if (fun->dev == NULL || fun->dev->drv != drv) { 558 fun_del_ref(fun); 559 async_answer_0(iid, ENOENT); 560 return; 561 } 562 fibril_rwlock_write_unlock(&device_tree.rwlock); 563 564 rc = offline_function(fun); 565 if (rc != EOK) { 566 fun_del_ref(fun); 567 async_answer_0(iid, (sysarg_t) rc); 568 return; 569 } 570 571 fun_del_ref(fun); 572 async_answer_0(iid, (sysarg_t) EOK); 573 } 574 575 /** Remove function. */ 576 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call) 577 { 578 devman_handle_t fun_handle = IPC_GET_ARG1(*call); 579 dev_tree_t *tree = &device_tree; 580 int rc; 581 582 583 fun_node_t *fun = find_fun_node(&device_tree, fun_handle); 584 if (fun == NULL) { 585 async_answer_0(callid, ENOENT); 586 return; 587 } 588 589 fibril_rwlock_write_lock(&tree->rwlock); 590 591 log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname); 592 593 /* Check function state */ 594 if (fun->state == FUN_REMOVED) { 595 fibril_rwlock_write_unlock(&tree->rwlock); 596 async_answer_0(callid, ENOENT); 597 return; 598 } 599 600 if (fun->ftype == fun_inner) { 601 /* Handle possible descendants */ 602 /* TODO - This is a surprise removal */ 603 if (fun->child != NULL) { 604 log_msg(LVL_WARN, "devman_remove_function(): not handling " 605 "descendants\n"); 606 } 607 } else { 608 if (fun->service_id != 0) { 609 /* Unregister from location service */ 610 rc = loc_service_unregister(fun->service_id); 611 if (rc != EOK) { 612 log_msg(LVL_ERROR, "Failed unregistering tree " 613 "service."); 614 fibril_rwlock_write_unlock(&tree->rwlock); 615 fun_del_ref(fun); 616 async_answer_0(callid, EIO); 617 return; 618 } 619 } 620 } 621 622 remove_fun_node(&device_tree, fun); 623 fibril_rwlock_write_unlock(&tree->rwlock); 624 625 /* Delete ref added when inserting function into tree */ 626 fun_del_ref(fun); 627 /* Delete ref added above when looking up function */ 628 fun_del_ref(fun); 629 630 log_msg(LVL_DEBUG, "devman_remove_function() succeeded."); 389 631 async_answer_0(callid, EOK); 390 632 } … … 408 650 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall) 409 651 { 652 client_t *client; 653 driver_t *driver; 654 410 655 /* Accept the connection. */ 411 656 async_answer_0(iid, EOK); 412 657 413 driver_t *driver = devman_driver_register(); 414 if (driver == NULL) 415 return; 416 417 /* 418 * Initialize the driver as running (e.g. pass assigned devices to it) 419 * in a separate fibril; the separate fibril is used to enable the 420 * driver to use devman service during the driver's initialization. 421 */ 422 fid_t fid = fibril_create(init_running_drv, driver); 423 if (fid == 0) { 424 log_msg(LVL_ERROR, "Failed to create initialization fibril " \ 425 "for driver `%s'.", driver->name); 426 return; 427 } 428 fibril_add_ready(fid); 658 client = async_get_client_data(); 659 if (client == NULL) { 660 log_msg(LVL_ERROR, "Failed to allocate client data."); 661 return; 662 } 429 663 430 664 while (true) { … … 435 669 break; 436 670 671 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) { 672 fibril_mutex_lock(&client->mutex); 673 driver = client->driver; 674 fibril_mutex_unlock(&client->mutex); 675 if (driver == NULL) { 676 /* First call must be to DEVMAN_DRIVER_REGISTER */ 677 async_answer_0(callid, ENOTSUP); 678 continue; 679 } 680 } 681 437 682 switch (IPC_GET_IMETHOD(call)) { 683 case DEVMAN_DRIVER_REGISTER: 684 fibril_mutex_lock(&client->mutex); 685 if (client->driver != NULL) { 686 fibril_mutex_unlock(&client->mutex); 687 async_answer_0(callid, EINVAL); 688 continue; 689 } 690 client->driver = devman_driver_register(callid, &call); 691 fibril_mutex_unlock(&client->mutex); 692 break; 438 693 case DEVMAN_ADD_FUNCTION: 439 694 devman_add_function(callid, &call); 440 695 break; 441 case DEVMAN_ADD_DEVICE_TO_CLASS: 442 devman_add_function_to_class(callid, &call); 696 case DEVMAN_ADD_DEVICE_TO_CATEGORY: 697 devman_add_function_to_cat(callid, &call); 698 break; 699 case DEVMAN_DRV_FUN_ONLINE: 700 devman_drv_fun_online(callid, &call, driver); 701 break; 702 case DEVMAN_DRV_FUN_OFFLINE: 703 devman_drv_fun_offline(callid, &call, driver); 704 break; 705 case DEVMAN_REMOVE_FUNCTION: 706 devman_remove_function(callid, &call); 443 707 break; 444 708 default: 445 async_answer_0(callid, EINVAL); 709 async_answer_0(callid, EINVAL); 446 710 break; 447 711 } … … 454 718 { 455 719 char *pathname; 720 devman_handle_t handle; 456 721 457 722 int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0); … … 470 735 } 471 736 472 async_answer_1(iid, EOK, fun->handle); 473 } 474 475 /** Find handle for the device instance identified by device class name. */ 476 static void devman_function_get_handle_by_class(ipc_callid_t iid, 477 ipc_call_t *icall) 478 { 479 char *classname; 480 char *devname; 481 482 int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0); 483 if (rc != EOK) { 484 async_answer_0(iid, rc); 485 return; 486 } 487 rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0); 488 if (rc != EOK) { 489 free(classname); 490 async_answer_0(iid, rc); 491 return; 492 } 493 494 495 fun_node_t *fun = find_fun_node_by_class(&class_list, 496 classname, devname); 497 498 free(classname); 499 free(devname); 500 501 if (fun == NULL) { 502 async_answer_0(iid, ENOENT); 503 return; 504 } 505 506 async_answer_1(iid, EOK, fun->handle); 507 } 508 509 /** Find device path by its handle. */ 510 static void devman_get_device_path_by_handle(ipc_callid_t iid, 511 ipc_call_t *icall) 737 fibril_rwlock_read_lock(&device_tree.rwlock); 738 739 /* Check function state */ 740 if (fun->state == FUN_REMOVED) { 741 fibril_rwlock_read_unlock(&device_tree.rwlock); 742 async_answer_0(iid, ENOENT); 743 return; 744 } 745 handle = fun->handle; 746 747 fibril_rwlock_read_unlock(&device_tree.rwlock); 748 749 /* Delete reference created above by find_fun_node_by_path() */ 750 fun_del_ref(fun); 751 752 async_answer_1(iid, EOK, handle); 753 } 754 755 /** Get device name. */ 756 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall) 512 757 { 513 758 devman_handle_t handle = IPC_GET_ARG1(*icall); … … 523 768 if (!async_data_read_receive(&data_callid, &data_len)) { 524 769 async_answer_0(iid, EINVAL); 770 fun_del_ref(fun); 525 771 return; 526 772 } … … 530 776 async_answer_0(data_callid, ENOMEM); 531 777 async_answer_0(iid, ENOMEM); 532 return; 533 } 534 778 fun_del_ref(fun); 779 return; 780 } 781 782 fibril_rwlock_read_lock(&device_tree.rwlock); 783 784 /* Check function state */ 785 if (fun->state == FUN_REMOVED) { 786 fibril_rwlock_read_unlock(&device_tree.rwlock); 787 free(buffer); 788 789 async_answer_0(data_callid, ENOENT); 790 async_answer_0(iid, ENOENT); 791 fun_del_ref(fun); 792 return; 793 } 794 795 size_t sent_length = str_size(fun->name); 796 if (sent_length > data_len) { 797 sent_length = data_len; 798 } 799 800 async_data_read_finalize(data_callid, fun->name, sent_length); 801 async_answer_0(iid, EOK); 802 803 fibril_rwlock_read_unlock(&device_tree.rwlock); 804 fun_del_ref(fun); 805 free(buffer); 806 } 807 808 809 /** Get device path. */ 810 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall) 811 { 812 devman_handle_t handle = IPC_GET_ARG1(*icall); 813 814 fun_node_t *fun = find_fun_node(&device_tree, handle); 815 if (fun == NULL) { 816 async_answer_0(iid, ENOMEM); 817 return; 818 } 819 820 ipc_callid_t data_callid; 821 size_t data_len; 822 if (!async_data_read_receive(&data_callid, &data_len)) { 823 async_answer_0(iid, EINVAL); 824 fun_del_ref(fun); 825 return; 826 } 827 828 void *buffer = malloc(data_len); 829 if (buffer == NULL) { 830 async_answer_0(data_callid, ENOMEM); 831 async_answer_0(iid, ENOMEM); 832 fun_del_ref(fun); 833 return; 834 } 835 836 fibril_rwlock_read_lock(&device_tree.rwlock); 837 838 /* Check function state */ 839 if (fun->state == FUN_REMOVED) { 840 fibril_rwlock_read_unlock(&device_tree.rwlock); 841 free(buffer); 842 843 async_answer_0(data_callid, ENOENT); 844 async_answer_0(iid, ENOENT); 845 fun_del_ref(fun); 846 return; 847 } 848 535 849 size_t sent_length = str_size(fun->pathname); 536 850 if (sent_length > data_len) { … … 541 855 async_answer_0(iid, EOK); 542 856 857 fibril_rwlock_read_unlock(&device_tree.rwlock); 858 fun_del_ref(fun); 543 859 free(buffer); 544 860 } 545 861 862 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall) 863 { 864 ipc_callid_t callid; 865 size_t size; 866 size_t act_size; 867 int rc; 868 869 if (!async_data_read_receive(&callid, &size)) { 870 async_answer_0(callid, EREFUSED); 871 async_answer_0(iid, EREFUSED); 872 return; 873 } 874 875 fibril_rwlock_read_lock(&device_tree.rwlock); 876 877 dev_node_t *dev = find_dev_node_no_lock(&device_tree, 878 IPC_GET_ARG1(*icall)); 879 if (dev == NULL || dev->state == DEVICE_REMOVED) { 880 fibril_rwlock_read_unlock(&device_tree.rwlock); 881 async_answer_0(callid, ENOENT); 882 async_answer_0(iid, ENOENT); 883 return; 884 } 885 886 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size); 887 if (hdl_buf == NULL) { 888 fibril_rwlock_read_unlock(&device_tree.rwlock); 889 async_answer_0(callid, ENOMEM); 890 async_answer_0(iid, ENOMEM); 891 return; 892 } 893 894 rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size); 895 if (rc != EOK) { 896 fibril_rwlock_read_unlock(&device_tree.rwlock); 897 async_answer_0(callid, rc); 898 async_answer_0(iid, rc); 899 return; 900 } 901 902 fibril_rwlock_read_unlock(&device_tree.rwlock); 903 904 sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size); 905 free(hdl_buf); 906 907 async_answer_1(iid, retval, act_size); 908 } 909 910 911 /** Get handle for child device of a function. */ 912 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall) 913 { 914 fun_node_t *fun; 915 916 fibril_rwlock_read_lock(&device_tree.rwlock); 917 918 fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall)); 919 if (fun == NULL || fun->state == FUN_REMOVED) { 920 fibril_rwlock_read_unlock(&device_tree.rwlock); 921 async_answer_0(iid, ENOENT); 922 return; 923 } 924 925 if (fun->child == NULL) { 926 fibril_rwlock_read_unlock(&device_tree.rwlock); 927 async_answer_0(iid, ENOENT); 928 return; 929 } 930 931 async_answer_1(iid, EOK, fun->child->handle); 932 933 fibril_rwlock_read_unlock(&device_tree.rwlock); 934 } 935 936 /** Online function. 937 * 938 * Send a request to online a function to the responsible driver. 939 * The driver may offline other functions if necessary (i.e. if the state 940 * of this function is linked to state of another function somehow). 941 */ 942 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall) 943 { 944 fun_node_t *fun; 945 int rc; 946 947 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 948 if (fun == NULL) { 949 async_answer_0(iid, ENOENT); 950 return; 951 } 952 953 rc = driver_fun_online(&device_tree, fun); 954 fun_del_ref(fun); 955 956 async_answer_0(iid, (sysarg_t) rc); 957 } 958 959 /** Offline function. 960 * 961 * Send a request to offline a function to the responsible driver. As 962 * a result the subtree rooted at that function should be cleanly 963 * detatched. The driver may offline other functions if necessary 964 * (i.e. if the state of this function is linked to state of another 965 * function somehow). 966 */ 967 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 968 { 969 fun_node_t *fun; 970 int rc; 971 972 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 973 if (fun == NULL) { 974 async_answer_0(iid, ENOENT); 975 return; 976 } 977 978 rc = driver_fun_offline(&device_tree, fun); 979 fun_del_ref(fun); 980 981 async_answer_0(iid, (sysarg_t) rc); 982 } 983 984 /** Find handle for the function instance identified by its service ID. */ 985 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall) 986 { 987 fun_node_t *fun; 988 989 fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall)); 990 991 if (fun == NULL) { 992 async_answer_0(iid, ENOENT); 993 return; 994 } 995 996 fibril_rwlock_read_lock(&device_tree.rwlock); 997 998 /* Check function state */ 999 if (fun->state == FUN_REMOVED) { 1000 fibril_rwlock_read_unlock(&device_tree.rwlock); 1001 async_answer_0(iid, ENOENT); 1002 return; 1003 } 1004 1005 async_answer_1(iid, EOK, fun->handle); 1006 fibril_rwlock_read_unlock(&device_tree.rwlock); 1007 fun_del_ref(fun); 1008 } 546 1009 547 1010 /** Function for handling connections from a client to the device manager. */ … … 562 1025 devman_function_get_handle(callid, &call); 563 1026 break; 564 case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS: 565 devman_function_get_handle_by_class(callid, &call); 566 break; 567 case DEVMAN_DEVICE_GET_DEVICE_PATH: 568 devman_get_device_path_by_handle(callid, &call); 1027 case DEVMAN_DEV_GET_FUNCTIONS: 1028 devman_dev_get_functions(callid, &call); 1029 break; 1030 case DEVMAN_FUN_GET_CHILD: 1031 devman_fun_get_child(callid, &call); 1032 break; 1033 case DEVMAN_FUN_GET_NAME: 1034 devman_fun_get_name(callid, &call); 1035 break; 1036 case DEVMAN_FUN_GET_PATH: 1037 devman_fun_get_path(callid, &call); 1038 break; 1039 case DEVMAN_FUN_ONLINE: 1040 devman_fun_online(callid, &call); 1041 break; 1042 case DEVMAN_FUN_OFFLINE: 1043 devman_fun_offline(callid, &call); 1044 break; 1045 case DEVMAN_FUN_SID_TO_HANDLE: 1046 devman_fun_sid_to_handle(callid, &call); 569 1047 break; 570 1048 default: … … 585 1063 if (fun == NULL) 586 1064 dev = find_dev_node(&device_tree, handle); 587 else 1065 else { 1066 fibril_rwlock_read_lock(&device_tree.rwlock); 588 1067 dev = fun->dev; 1068 if (dev != NULL) 1069 dev_add_ref(dev); 1070 fibril_rwlock_read_unlock(&device_tree.rwlock); 1071 } 589 1072 590 1073 /* … … 598 1081 "function with handle %" PRIun " was found.", handle); 599 1082 async_answer_0(iid, ENOENT); 600 return;1083 goto cleanup; 601 1084 } 602 1085 … … 606 1089 handle); 607 1090 async_answer_0(iid, ENOENT); 608 return;1091 goto cleanup; 609 1092 } 610 1093 611 1094 driver_t *driver = NULL; 1095 1096 fibril_rwlock_read_lock(&device_tree.rwlock); 612 1097 613 1098 if (drv_to_parent) { … … 624 1109 } 625 1110 1111 fibril_rwlock_read_unlock(&device_tree.rwlock); 1112 626 1113 if (driver == NULL) { 627 1114 log_msg(LVL_ERROR, "IPC forwarding refused - " \ 628 1115 "the device %" PRIun " is not in usable state.", handle); 629 1116 async_answer_0(iid, ENOENT); 630 return;1117 goto cleanup; 631 1118 } 632 1119 … … 641 1128 "Could not forward to driver `%s'.", driver->name); 642 1129 async_answer_0(iid, EINVAL); 643 return;1130 goto cleanup; 644 1131 } 645 1132 … … 657 1144 async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE); 658 1145 async_exchange_end(exch); 659 } 660 661 /** Function for handling connections from a client forwarded by the device 662 * mapper to the device manager. */ 663 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall) 664 { 665 devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall); 1146 1147 cleanup: 1148 if (dev != NULL) 1149 dev_del_ref(dev); 1150 if (fun != NULL) 1151 fun_del_ref(fun); 1152 } 1153 1154 /** Function for handling connections from a client forwarded by the location 1155 * service to the device manager. */ 1156 static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall) 1157 { 1158 service_id_t service_id = IPC_GET_ARG2(*icall); 666 1159 fun_node_t *fun; 667 1160 dev_node_t *dev; 668 669 fun = find_devmap_tree_function(&device_tree, devmap_handle); 670 if (fun == NULL) 671 fun = find_devmap_class_function(&class_list, devmap_handle); 672 673 if (fun == NULL || fun->dev->drv == NULL) { 1161 devman_handle_t handle; 1162 driver_t *driver; 1163 1164 fun = find_loc_tree_function(&device_tree, service_id); 1165 1166 fibril_rwlock_read_lock(&device_tree.rwlock); 1167 1168 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) { 1169 log_msg(LVL_WARN, "devman_connection_loc(): function " 1170 "not found.\n"); 1171 fibril_rwlock_read_unlock(&device_tree.rwlock); 674 1172 async_answer_0(iid, ENOENT); 675 1173 return; … … 677 1175 678 1176 dev = fun->dev; 679 680 if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) { 681 async_answer_0(iid, EINVAL); 682 return; 683 } 684 685 async_exch_t *exch = async_exchange_begin(dev->drv->sess); 686 async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0, 1177 driver = dev->drv; 1178 handle = fun->handle; 1179 1180 fibril_rwlock_read_unlock(&device_tree.rwlock); 1181 1182 async_exch_t *exch = async_exchange_begin(driver->sess); 1183 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0, 687 1184 IPC_FF_NONE); 688 1185 async_exchange_end(exch); 689 1186 690 1187 log_msg(LVL_DEBUG, 691 "Forwarding devmapper request for `%s' function to driver `%s'.", 692 fun->pathname, dev->drv->name); 1188 "Forwarding loc service request for `%s' function to driver `%s'.", 1189 fun->pathname, driver->name); 1190 1191 fun_del_ref(fun); 693 1192 } 694 1193 695 1194 /** Function for handling connections to device manager. */ 696 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall )697 { 698 /* Select interface. */1195 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 1196 { 1197 /* Select port. */ 699 1198 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 700 1199 case DEVMAN_DRIVER: … … 708 1207 devman_forward(iid, icall, false); 709 1208 break; 710 case DEVMAN_CONNECT_FROM_ DEVMAP:711 /* Someone connected through devmapnode. */712 devman_connection_ devmapper(iid, icall);1209 case DEVMAN_CONNECT_FROM_LOC: 1210 /* Someone connected through loc node. */ 1211 devman_connection_loc(iid, icall); 713 1212 break; 714 1213 case DEVMAN_CONNECT_TO_PARENTS_DEVICE: … … 722 1221 } 723 1222 1223 static void *devman_client_data_create(void) 1224 { 1225 client_t *client; 1226 1227 client = calloc(1, sizeof(client_t)); 1228 if (client == NULL) 1229 return NULL; 1230 1231 fibril_mutex_initialize(&client->mutex); 1232 return client; 1233 } 1234 1235 static void devman_client_data_destroy(void *data) 1236 { 1237 free(data); 1238 } 1239 724 1240 /** Initialize device manager internal structures. */ 725 1241 static bool devman_init(void) … … 743 1259 } 744 1260 745 init_class_list(&class_list);746 747 1261 /* 748 * !!! devman_connection ... as the device manager is not a real devmap1262 * !!! devman_connection ... as the device manager is not a real loc 749 1263 * driver (it uses a completely different ipc protocol than an ordinary 750 * devmapdriver) forwarding a connection from client to the devman by751 * devmapperwould not work.1264 * loc driver) forwarding a connection from client to the devman by 1265 * location service would not work. 752 1266 */ 753 devmap_driver_register(NAME, devman_connection);1267 loc_server_register(NAME, devman_connection); 754 1268 755 1269 return true; … … 760 1274 printf(NAME ": HelenOS Device Manager\n"); 761 1275 762 if (log_init(NAME, LVL_ ERROR) != EOK) {1276 if (log_init(NAME, LVL_WARN) != EOK) { 763 1277 printf(NAME ": Error initializing logging subsystem.\n"); 764 1278 return -1; … … 770 1284 } 771 1285 772 /* Set a handler of incomming connections. */ 1286 /* Set handlers for incoming connections. */ 1287 async_set_client_data_constructor(devman_client_data_create); 1288 async_set_client_data_destructor(devman_client_data_destroy); 773 1289 async_set_client_connection(devman_connection); 774 1290 -
uspace/srv/devman/match.c
rd2c67e7 r8ff0bd2 59 59 int get_match_score(driver_t *drv, dev_node_t *dev) 60 60 { 61 link_t *drv_head = &drv->match_ids.ids ;62 link_t *dev_head = &dev->pfun->match_ids.ids ;61 link_t *drv_head = &drv->match_ids.ids.head; 62 link_t *dev_head = &dev->pfun->match_ids.ids.head; 63 63 64 if (list_empty(drv_head) || list_empty(dev_head)) 64 if (list_empty(&drv->match_ids.ids) || 65 list_empty(&dev->pfun->match_ids.ids)) { 65 66 return 0; 67 } 66 68 67 69 /* … … 70 72 int highest_score = 0; 71 73 72 link_t *drv_link = drv->match_ids.ids. next;74 link_t *drv_link = drv->match_ids.ids.head.next; 73 75 while (drv_link != drv_head) { 74 76 link_t *dev_link = dev_head->next; -
uspace/srv/devman/util.c
rd2c67e7 r8ff0bd2 91 91 } 92 92 93 char *clone_string(const char *s)94 {95 size_t size = str_size(s) + 1;96 char *str;97 98 str = (char *) malloc(size);99 if (str != NULL)100 str_cpy(str, size, s);101 return str;102 }103 104 93 void replace_char(char *str, char orig, char repl) 105 94 { … … 111 100 } 112 101 113 ssize_t safe_read(int fd, void *buffer, size_t size)114 {115 if (size == 0) {116 return 0;117 }118 119 uint8_t *buf_ptr = (uint8_t *) buffer;120 121 size_t total_read = 0;122 while (total_read < size) {123 ssize_t bytes_read = read(fd, buf_ptr, size - total_read);124 if (bytes_read < 0) {125 /* Error. */126 return bytes_read;127 } else if (bytes_read == 0) {128 /* Possibly end of file. */129 break;130 } else {131 /* Read at least something. */132 buf_ptr += bytes_read;133 total_read += bytes_read;134 }135 }136 137 return (ssize_t) total_read;138 }139 140 102 /** @} 141 103 */ -
uspace/srv/devman/util.h
rd2c67e7 r8ff0bd2 44 44 extern size_t get_nonspace_len(const char *); 45 45 extern void free_not_null(const void *); 46 extern char *clone_string(const char *);47 46 extern void replace_char(char *, char, char); 48 49 extern ssize_t safe_read(int, void *, size_t);50 47 51 48 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
