00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00033 #include <errno.h>
00034 #include <fcntl.h>
00035 #include <sys/stat.h>
00036 #include <io/log.h>
00037 #include <ipc/driver.h>
00038 #include <ipc/devman.h>
00039 #include <devmap.h>
00040 #include <str_error.h>
00041 #include <stdio.h>
00042
00043 #include "devman.h"
00044
00045 fun_node_t *find_node_child(fun_node_t *parent, const char *name);
00046
00047
00048
00049 static hash_index_t devices_hash(unsigned long key[])
00050 {
00051 return key[0] % DEVICE_BUCKETS;
00052 }
00053
00054 static int devman_devices_compare(unsigned long key[], hash_count_t keys,
00055 link_t *item)
00056 {
00057 dev_node_t *dev = hash_table_get_instance(item, dev_node_t, devman_dev);
00058 return (dev->handle == (devman_handle_t) key[0]);
00059 }
00060
00061 static int devman_functions_compare(unsigned long key[], hash_count_t keys,
00062 link_t *item)
00063 {
00064 fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devman_fun);
00065 return (fun->handle == (devman_handle_t) key[0]);
00066 }
00067
00068 static int devmap_functions_compare(unsigned long key[], hash_count_t keys,
00069 link_t *item)
00070 {
00071 fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devmap_fun);
00072 return (fun->devmap_handle == (devmap_handle_t) key[0]);
00073 }
00074
00075 static int devmap_devices_class_compare(unsigned long key[], hash_count_t keys,
00076 link_t *item)
00077 {
00078 dev_class_info_t *class_info
00079 = hash_table_get_instance(item, dev_class_info_t, devmap_link);
00080 assert(class_info != NULL);
00081
00082 return (class_info->devmap_handle == (devmap_handle_t) key[0]);
00083 }
00084
00085 static void devices_remove_callback(link_t *item)
00086 {
00087 }
00088
00089 static hash_table_operations_t devman_devices_ops = {
00090 .hash = devices_hash,
00091 .compare = devman_devices_compare,
00092 .remove_callback = devices_remove_callback
00093 };
00094
00095 static hash_table_operations_t devman_functions_ops = {
00096 .hash = devices_hash,
00097 .compare = devman_functions_compare,
00098 .remove_callback = devices_remove_callback
00099 };
00100
00101 static hash_table_operations_t devmap_devices_ops = {
00102 .hash = devices_hash,
00103 .compare = devmap_functions_compare,
00104 .remove_callback = devices_remove_callback
00105 };
00106
00107 static hash_table_operations_t devmap_devices_class_ops = {
00108 .hash = devices_hash,
00109 .compare = devmap_devices_class_compare,
00110 .remove_callback = devices_remove_callback
00111 };
00112
00119 void init_driver_list(driver_list_t *drv_list)
00120 {
00121 assert(drv_list != NULL);
00122
00123 list_initialize(&drv_list->drivers);
00124 fibril_mutex_initialize(&drv_list->drivers_mutex);
00125 }
00126
00131 driver_t *create_driver(void)
00132 {
00133 driver_t *res = malloc(sizeof(driver_t));
00134 if (res != NULL)
00135 init_driver(res);
00136 return res;
00137 }
00138
00144 void add_driver(driver_list_t *drivers_list, driver_t *drv)
00145 {
00146 fibril_mutex_lock(&drivers_list->drivers_mutex);
00147 list_prepend(&drv->drivers, &drivers_list->drivers);
00148 fibril_mutex_unlock(&drivers_list->drivers_mutex);
00149
00150 log_msg(LVL_NOTE, "Driver `%s' was added to the list of available "
00151 "drivers.", drv->name);
00152 }
00153
00160 char *read_match_id(char **buf)
00161 {
00162 char *res = NULL;
00163 size_t len = get_nonspace_len(*buf);
00164
00165 if (len > 0) {
00166 res = malloc(len + 1);
00167 if (res != NULL) {
00168 str_ncpy(res, len + 1, *buf, len);
00169 *buf += len;
00170 }
00171 }
00172
00173 return res;
00174 }
00175
00189 bool parse_match_ids(char *buf, match_id_list_t *ids)
00190 {
00191 int score = 0;
00192 char *id = NULL;
00193 int ids_read = 0;
00194
00195 while (true) {
00196
00197 if (!skip_spaces(&buf))
00198 break;
00199
00200
00201 score = strtoul(buf, &buf, 10);
00202
00203
00204 if (!skip_spaces(&buf))
00205 break;
00206
00207
00208 id = read_match_id(&buf);
00209 if (NULL == id)
00210 break;
00211
00212
00213 match_id_t *mid = create_match_id();
00214 mid->id = id;
00215 mid->score = score;
00216
00217
00218 add_match_id(ids, mid);
00219
00220 ids_read++;
00221 }
00222
00223 return ids_read > 0;
00224 }
00225
00239 bool read_match_ids(const char *conf_path, match_id_list_t *ids)
00240 {
00241 log_msg(LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
00242
00243 bool suc = false;
00244 char *buf = NULL;
00245 bool opened = false;
00246 int fd;
00247 size_t len = 0;
00248
00249 fd = open(conf_path, O_RDONLY);
00250 if (fd < 0) {
00251 log_msg(LVL_ERROR, "Unable to open `%s' for reading: %s.",
00252 conf_path, str_error(fd));
00253 goto cleanup;
00254 }
00255 opened = true;
00256
00257 len = lseek(fd, 0, SEEK_END);
00258 lseek(fd, 0, SEEK_SET);
00259 if (len == 0) {
00260 log_msg(LVL_ERROR, "Configuration file '%s' is empty.",
00261 conf_path);
00262 goto cleanup;
00263 }
00264
00265 buf = malloc(len + 1);
00266 if (buf == NULL) {
00267 log_msg(LVL_ERROR, "Memory allocation failed when parsing file "
00268 "'%s'.", conf_path);
00269 goto cleanup;
00270 }
00271
00272 ssize_t read_bytes = safe_read(fd, buf, len);
00273 if (read_bytes <= 0) {
00274 log_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
00275 goto cleanup;
00276 }
00277 buf[read_bytes] = 0;
00278
00279 suc = parse_match_ids(buf, ids);
00280
00281 cleanup:
00282 free(buf);
00283
00284 if (opened)
00285 close(fd);
00286
00287 return suc;
00288 }
00289
00310 bool get_driver_info(const char *base_path, const char *name, driver_t *drv)
00311 {
00312 log_msg(LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
00313 base_path, name);
00314
00315 assert(base_path != NULL && name != NULL && drv != NULL);
00316
00317 bool suc = false;
00318 char *match_path = NULL;
00319 size_t name_size = 0;
00320
00321
00322 match_path = get_abs_path(base_path, name, MATCH_EXT);
00323 if (match_path == NULL)
00324 goto cleanup;
00325
00326 if (!read_match_ids(match_path, &drv->match_ids))
00327 goto cleanup;
00328
00329
00330 name_size = str_size(name) + 1;
00331 drv->name = malloc(name_size);
00332 if (drv->name == NULL)
00333 goto cleanup;
00334 str_cpy(drv->name, name_size, name);
00335
00336
00337 drv->binary_path = get_abs_path(base_path, name, "");
00338 if (drv->binary_path == NULL)
00339 goto cleanup;
00340
00341
00342 struct stat s;
00343 if (stat(drv->binary_path, &s) == ENOENT) {
00344 log_msg(LVL_ERROR, "Driver not found at path `%s'.",
00345 drv->binary_path);
00346 goto cleanup;
00347 }
00348
00349 suc = true;
00350
00351 cleanup:
00352 if (!suc) {
00353 free(drv->binary_path);
00354 free(drv->name);
00355
00356 init_driver(drv);
00357 }
00358
00359 free(match_path);
00360
00361 return suc;
00362 }
00363
00370 int lookup_available_drivers(driver_list_t *drivers_list, const char *dir_path)
00371 {
00372 log_msg(LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
00373
00374 int drv_cnt = 0;
00375 DIR *dir = NULL;
00376 struct dirent *diren;
00377
00378 dir = opendir(dir_path);
00379
00380 if (dir != NULL) {
00381 driver_t *drv = create_driver();
00382 while ((diren = readdir(dir))) {
00383 if (get_driver_info(dir_path, diren->d_name, drv)) {
00384 add_driver(drivers_list, drv);
00385 drv_cnt++;
00386 drv = create_driver();
00387 }
00388 }
00389 delete_driver(drv);
00390 closedir(dir);
00391 }
00392
00393 return drv_cnt;
00394 }
00395
00401 bool create_root_nodes(dev_tree_t *tree)
00402 {
00403 fun_node_t *fun;
00404 dev_node_t *dev;
00405
00406 log_msg(LVL_DEBUG, "create_root_nodes()");
00407
00408 fibril_rwlock_write_lock(&tree->rwlock);
00409
00410
00411
00412
00413
00414
00415
00416
00417 fun = create_fun_node();
00418 if (fun == NULL) {
00419 fibril_rwlock_write_unlock(&tree->rwlock);
00420 return false;
00421 }
00422
00423 insert_fun_node(tree, fun, clone_string(""), NULL);
00424 match_id_t *id = create_match_id();
00425 id->id = clone_string("root");
00426 id->score = 100;
00427 add_match_id(&fun->match_ids, id);
00428 tree->root_node = fun;
00429
00430
00431
00432
00433 dev = create_dev_node();
00434 if (dev == NULL) {
00435 fibril_rwlock_write_unlock(&tree->rwlock);
00436 return false;
00437 }
00438
00439 insert_dev_node(tree, dev, fun);
00440
00441 fibril_rwlock_write_unlock(&tree->rwlock);
00442
00443 return dev != NULL;
00444 }
00445
00461 driver_t *find_best_match_driver(driver_list_t *drivers_list, dev_node_t *node)
00462 {
00463 driver_t *best_drv = NULL, *drv = NULL;
00464 int best_score = 0, score = 0;
00465
00466 fibril_mutex_lock(&drivers_list->drivers_mutex);
00467
00468 link_t *link = drivers_list->drivers.next;
00469 while (link != &drivers_list->drivers) {
00470 drv = list_get_instance(link, driver_t, drivers);
00471 score = get_match_score(drv, node);
00472 if (score > best_score) {
00473 best_score = score;
00474 best_drv = drv;
00475 }
00476 link = link->next;
00477 }
00478
00479 fibril_mutex_unlock(&drivers_list->drivers_mutex);
00480
00481 return best_drv;
00482 }
00483
00489 void attach_driver(dev_node_t *dev, driver_t *drv)
00490 {
00491 log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
00492 dev->pfun->pathname, drv->name);
00493
00494 fibril_mutex_lock(&drv->driver_mutex);
00495
00496 dev->drv = drv;
00497 list_append(&dev->driver_devices, &drv->devices);
00498
00499 fibril_mutex_unlock(&drv->driver_mutex);
00500 }
00501
00508 bool start_driver(driver_t *drv)
00509 {
00510 int rc;
00511
00512 assert(fibril_mutex_is_locked(&drv->driver_mutex));
00513
00514 log_msg(LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
00515
00516 rc = task_spawnl(NULL, drv->binary_path, drv->binary_path, NULL);
00517 if (rc != EOK) {
00518 log_msg(LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
00519 drv->name, drv->binary_path, str_error(rc));
00520 return false;
00521 }
00522
00523 drv->state = DRIVER_STARTING;
00524 return true;
00525 }
00526
00534 driver_t *find_driver(driver_list_t *drv_list, const char *drv_name)
00535 {
00536 driver_t *res = NULL;
00537 driver_t *drv = NULL;
00538 link_t *link;
00539
00540 fibril_mutex_lock(&drv_list->drivers_mutex);
00541
00542 link = drv_list->drivers.next;
00543 while (link != &drv_list->drivers) {
00544 drv = list_get_instance(link, driver_t, drivers);
00545 if (str_cmp(drv->name, drv_name) == 0) {
00546 res = drv;
00547 break;
00548 }
00549
00550 link = link->next;
00551 }
00552
00553 fibril_mutex_unlock(&drv_list->drivers_mutex);
00554
00555 return res;
00556 }
00557
00562 static void pass_devices_to_driver(driver_t *driver, dev_tree_t *tree)
00563 {
00564 dev_node_t *dev;
00565 link_t *link;
00566 int phone;
00567
00568 log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
00569 driver->name);
00570
00571 fibril_mutex_lock(&driver->driver_mutex);
00572
00573 phone = async_connect_me_to(driver->phone, DRIVER_DEVMAN, 0, 0);
00574
00575 if (phone < 0) {
00576 fibril_mutex_unlock(&driver->driver_mutex);
00577 return;
00578 }
00579
00580
00581
00582
00583
00584 link = driver->devices.next;
00585 while (link != &driver->devices) {
00586 dev = list_get_instance(link, dev_node_t, driver_devices);
00587 if (dev->passed_to_driver) {
00588 link = link->next;
00589 continue;
00590 }
00591
00592
00593
00594
00595
00596 list_remove(link);
00597
00598
00599
00600
00601
00602 fibril_mutex_unlock(&driver->driver_mutex);
00603
00604 add_device(phone, driver, dev, tree);
00605
00606
00607
00608
00609
00610 fibril_mutex_lock(&driver->driver_mutex);
00611
00612
00613
00614
00615
00616
00617 list_append(link, &driver->devices);
00618
00619
00620
00621
00622 link = driver->devices.next;
00623 }
00624
00625 async_hangup(phone);
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636 log_msg(LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
00637 driver->state = DRIVER_RUNNING;
00638
00639 fibril_mutex_unlock(&driver->driver_mutex);
00640 }
00641
00651 void initialize_running_driver(driver_t *driver, dev_tree_t *tree)
00652 {
00653 log_msg(LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
00654 driver->name);
00655
00656
00657
00658
00659
00660 pass_devices_to_driver(driver, tree);
00661 }
00662
00667 void init_driver(driver_t *drv)
00668 {
00669 assert(drv != NULL);
00670
00671 memset(drv, 0, sizeof(driver_t));
00672 list_initialize(&drv->match_ids.ids);
00673 list_initialize(&drv->devices);
00674 fibril_mutex_initialize(&drv->driver_mutex);
00675 drv->phone = -1;
00676 }
00677
00682 void clean_driver(driver_t *drv)
00683 {
00684 assert(drv != NULL);
00685
00686 free_not_null(drv->name);
00687 free_not_null(drv->binary_path);
00688
00689 clean_match_ids(&drv->match_ids);
00690
00691 init_driver(drv);
00692 }
00693
00698 void delete_driver(driver_t *drv)
00699 {
00700 assert(drv != NULL);
00701
00702 clean_driver(drv);
00703 free(drv);
00704 }
00705
00707 void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
00708 {
00709 char *devmap_pathname = NULL;
00710 char *devmap_name = NULL;
00711
00712 asprintf(&devmap_name, "%s", fun->pathname);
00713 if (devmap_name == NULL)
00714 return;
00715
00716 replace_char(devmap_name, '/', DEVMAP_SEPARATOR);
00717
00718 asprintf(&devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,
00719 devmap_name);
00720 if (devmap_pathname == NULL) {
00721 free(devmap_name);
00722 return;
00723 }
00724
00725 devmap_device_register_with_iface(devmap_pathname,
00726 &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
00727
00728 tree_add_devmap_function(tree, fun);
00729
00730 free(devmap_name);
00731 free(devmap_pathname);
00732 }
00733
00739 void add_device(int phone, driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
00740 {
00741
00742
00743
00744
00745 log_msg(LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
00746 drv->name, dev->pfun->name);
00747
00748 sysarg_t rc;
00749 ipc_call_t answer;
00750
00751
00752 devman_handle_t parent_handle;
00753 if (dev->pfun) {
00754 parent_handle = dev->pfun->handle;
00755 } else {
00756 parent_handle = 0;
00757 }
00758
00759 aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, dev->handle,
00760 parent_handle, &answer);
00761
00762
00763 rc = async_data_write_start(phone, dev->pfun->name,
00764 str_size(dev->pfun->name) + 1);
00765 if (rc != EOK) {
00766
00767 }
00768
00769
00770 async_wait_for(req, &rc);
00771
00772 switch(rc) {
00773 case EOK:
00774 dev->state = DEVICE_USABLE;
00775 break;
00776 case ENOENT:
00777 dev->state = DEVICE_NOT_PRESENT;
00778 break;
00779 default:
00780 dev->state = DEVICE_INVALID;
00781 }
00782
00783 dev->passed_to_driver = true;
00784
00785 return;
00786 }
00787
00795 bool assign_driver(dev_node_t *dev, driver_list_t *drivers_list,
00796 dev_tree_t *tree)
00797 {
00798 assert(dev != NULL);
00799 assert(drivers_list != NULL);
00800 assert(tree != NULL);
00801
00802
00803
00804
00805 driver_t *drv = find_best_match_driver(drivers_list, dev);
00806 if (drv == NULL) {
00807 log_msg(LVL_ERROR, "No driver found for device `%s'.",
00808 dev->pfun->pathname);
00809 return false;
00810 }
00811
00812
00813 attach_driver(dev, drv);
00814
00815 fibril_mutex_lock(&drv->driver_mutex);
00816 if (drv->state == DRIVER_NOT_STARTED) {
00817
00818 start_driver(drv);
00819 }
00820 bool is_running = drv->state == DRIVER_RUNNING;
00821 fibril_mutex_unlock(&drv->driver_mutex);
00822
00823 if (is_running) {
00824
00825 int phone = async_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0);
00826 if (phone >= 0) {
00827 add_device(phone, drv, dev, tree);
00828 async_hangup(phone);
00829 }
00830 }
00831
00832 return true;
00833 }
00834
00843 bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
00844 {
00845 log_msg(LVL_DEBUG, "init_device_tree()");
00846
00847 tree->current_handle = 0;
00848
00849 hash_table_create(&tree->devman_devices, DEVICE_BUCKETS, 1,
00850 &devman_devices_ops);
00851 hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
00852 &devman_functions_ops);
00853 hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
00854 &devmap_devices_ops);
00855
00856 fibril_rwlock_initialize(&tree->rwlock);
00857
00858
00859 if (!create_root_nodes(tree))
00860 return false;
00861
00862
00863 return assign_driver(tree->root_node->child, drivers_list, tree);
00864 }
00865
00866
00867
00872 dev_node_t *create_dev_node(void)
00873 {
00874 dev_node_t *res = malloc(sizeof(dev_node_t));
00875
00876 if (res != NULL) {
00877 memset(res, 0, sizeof(dev_node_t));
00878 list_initialize(&res->functions);
00879 link_initialize(&res->driver_devices);
00880 link_initialize(&res->devman_dev);
00881 }
00882
00883 return res;
00884 }
00885
00890 void delete_dev_node(dev_node_t *dev)
00891 {
00892 assert(list_empty(&dev->functions));
00893 assert(dev->pfun == NULL);
00894 assert(dev->drv == NULL);
00895
00896 free(dev);
00897 }
00898
00905 dev_node_t *find_dev_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
00906 {
00907 unsigned long key = handle;
00908 link_t *link;
00909
00910 assert(fibril_rwlock_is_locked(&tree->rwlock));
00911
00912 link = hash_table_find(&tree->devman_devices, &key);
00913 return hash_table_get_instance(link, dev_node_t, devman_dev);
00914 }
00915
00922 dev_node_t *find_dev_node(dev_tree_t *tree, devman_handle_t handle)
00923 {
00924 dev_node_t *dev = NULL;
00925
00926 fibril_rwlock_read_lock(&tree->rwlock);
00927 dev = find_dev_node_no_lock(tree, handle);
00928 fibril_rwlock_read_unlock(&tree->rwlock);
00929
00930 return dev;
00931 }
00932
00933
00934
00939 fun_node_t *create_fun_node(void)
00940 {
00941 fun_node_t *res = malloc(sizeof(fun_node_t));
00942
00943 if (res != NULL) {
00944 memset(res, 0, sizeof(fun_node_t));
00945 link_initialize(&res->dev_functions);
00946 list_initialize(&res->match_ids.ids);
00947 list_initialize(&res->classes);
00948 link_initialize(&res->devman_fun);
00949 link_initialize(&res->devmap_fun);
00950 }
00951
00952 return res;
00953 }
00954
00959 void delete_fun_node(fun_node_t *fun)
00960 {
00961 assert(fun->dev == NULL);
00962 assert(fun->child == NULL);
00963
00964 clean_match_ids(&fun->match_ids);
00965 free_not_null(fun->name);
00966 free_not_null(fun->pathname);
00967 free(fun);
00968 }
00969
00976 fun_node_t *find_fun_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
00977 {
00978 unsigned long key = handle;
00979 link_t *link;
00980
00981 assert(fibril_rwlock_is_locked(&tree->rwlock));
00982
00983 link = hash_table_find(&tree->devman_functions, &key);
00984 if (link == NULL)
00985 return NULL;
00986
00987 return hash_table_get_instance(link, fun_node_t, devman_fun);
00988 }
00989
00996 fun_node_t *find_fun_node(dev_tree_t *tree, devman_handle_t handle)
00997 {
00998 fun_node_t *fun = NULL;
00999
01000 fibril_rwlock_read_lock(&tree->rwlock);
01001 fun = find_fun_node_no_lock(tree, handle);
01002 fibril_rwlock_read_unlock(&tree->rwlock);
01003
01004 return fun;
01005 }
01006
01014 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
01015 {
01016 assert(fun->name != NULL);
01017
01018 size_t pathsize = (str_size(fun->name) + 1);
01019 if (parent != NULL)
01020 pathsize += str_size(parent->pathname) + 1;
01021
01022 fun->pathname = (char *) malloc(pathsize);
01023 if (fun->pathname == NULL) {
01024 log_msg(LVL_ERROR, "Failed to allocate device path.");
01025 return false;
01026 }
01027
01028 if (parent != NULL) {
01029 str_cpy(fun->pathname, pathsize, parent->pathname);
01030 str_append(fun->pathname, pathsize, "/");
01031 str_append(fun->pathname, pathsize, fun->name);
01032 } else {
01033 str_cpy(fun->pathname, pathsize, fun->name);
01034 }
01035
01036 return true;
01037 }
01038
01049 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
01050 {
01051 assert(dev != NULL);
01052 assert(tree != NULL);
01053 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
01054
01055 log_msg(LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
01056 dev, pfun, pfun->pathname);
01057
01058
01059 dev->handle = ++tree->current_handle;
01060 unsigned long key = dev->handle;
01061 hash_table_insert(&tree->devman_devices, &key, &dev->devman_dev);
01062
01063
01064 dev->pfun = pfun;
01065 pfun->child = dev;
01066
01067 return true;
01068 }
01069
01080 bool insert_fun_node(dev_tree_t *tree, fun_node_t *fun, char *fun_name,
01081 dev_node_t *dev)
01082 {
01083 fun_node_t *pfun;
01084
01085 assert(fun != NULL);
01086 assert(tree != NULL);
01087 assert(fun_name != NULL);
01088 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
01089
01090
01091
01092
01093
01094 pfun = (dev != NULL) ? dev->pfun : NULL;
01095
01096 fun->name = fun_name;
01097 if (!set_fun_path(fun, pfun)) {
01098 return false;
01099 }
01100
01101
01102 fun->handle = ++tree->current_handle;
01103 unsigned long key = fun->handle;
01104 hash_table_insert(&tree->devman_functions, &key, &fun->devman_fun);
01105
01106
01107 fun->dev = dev;
01108 if (dev != NULL)
01109 list_append(&fun->dev_functions, &dev->functions);
01110
01111 return true;
01112 }
01113
01121 fun_node_t *find_fun_node_by_path(dev_tree_t *tree, char *path)
01122 {
01123 assert(path != NULL);
01124
01125 bool is_absolute = path[0] == '/';
01126 if (!is_absolute) {
01127 return NULL;
01128 }
01129
01130 fibril_rwlock_read_lock(&tree->rwlock);
01131
01132 fun_node_t *fun = tree->root_node;
01133
01134
01135
01136
01137 char *rel_path = path;
01138 char *next_path_elem = NULL;
01139 bool cont = true;
01140
01141 while (cont && fun != NULL) {
01142 next_path_elem = get_path_elem_end(rel_path + 1);
01143 if (next_path_elem[0] == '/') {
01144 cont = true;
01145 next_path_elem[0] = 0;
01146 } else {
01147 cont = false;
01148 }
01149
01150 fun = find_node_child(fun, rel_path + 1);
01151
01152 if (cont) {
01153
01154 next_path_elem[0] = '/';
01155 }
01156 rel_path = next_path_elem;
01157 }
01158
01159 fibril_rwlock_read_unlock(&tree->rwlock);
01160
01161 return fun;
01162 }
01163
01173 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
01174 {
01175 assert(dev != NULL);
01176 assert(name != NULL);
01177
01178 fun_node_t *fun;
01179 link_t *link;
01180
01181 for (link = dev->functions.next;
01182 link != &dev->functions;
01183 link = link->next) {
01184 fun = list_get_instance(link, fun_node_t, dev_functions);
01185
01186 if (str_cmp(name, fun->name) == 0)
01187 return fun;
01188 }
01189
01190 return NULL;
01191 }
01192
01194 fun_node_t *find_fun_node_by_class(class_list_t *class_list,
01195 const char *class_name, const char *dev_name)
01196 {
01197 assert(class_list != NULL);
01198 assert(class_name != NULL);
01199 assert(dev_name != NULL);
01200
01201 fibril_rwlock_read_lock(&class_list->rwlock);
01202
01203 dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);
01204 if (cl == NULL) {
01205 fibril_rwlock_read_unlock(&class_list->rwlock);
01206 return NULL;
01207 }
01208
01209 dev_class_info_t *dev = find_dev_in_class(cl, dev_name);
01210 if (dev == NULL) {
01211 fibril_rwlock_read_unlock(&class_list->rwlock);
01212 return NULL;
01213 }
01214
01215 fun_node_t *fun = dev->fun;
01216
01217 fibril_rwlock_read_unlock(&class_list->rwlock);
01218
01219 return fun;
01220 }
01221
01222
01231 fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
01232 {
01233 return find_fun_node_in_device(pfun->child, name);
01234 }
01235
01236
01237
01242 dev_class_t *create_dev_class(void)
01243 {
01244 dev_class_t *cl;
01245
01246 cl = (dev_class_t *) malloc(sizeof(dev_class_t));
01247 if (cl != NULL) {
01248 memset(cl, 0, sizeof(dev_class_t));
01249 list_initialize(&cl->devices);
01250 fibril_mutex_initialize(&cl->mutex);
01251 }
01252
01253 return cl;
01254 }
01255
01260 dev_class_info_t *create_dev_class_info(void)
01261 {
01262 dev_class_info_t *info;
01263
01264 info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t));
01265 if (info != NULL) {
01266 memset(info, 0, sizeof(dev_class_info_t));
01267 link_initialize(&info->dev_classes);
01268 link_initialize(&info->devmap_link);
01269 link_initialize(&info->link);
01270 }
01271
01272 return info;
01273 }
01274
01275 size_t get_new_class_dev_idx(dev_class_t *cl)
01276 {
01277 size_t dev_idx;
01278
01279 fibril_mutex_lock(&cl->mutex);
01280 dev_idx = ++cl->curr_dev_idx;
01281 fibril_mutex_unlock(&cl->mutex);
01282
01283 return dev_idx;
01284 }
01285
01286
01295 char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name)
01296 {
01297 char *dev_name;
01298 const char *base_name;
01299
01300 if (base_dev_name != NULL)
01301 base_name = base_dev_name;
01302 else
01303 base_name = cl->base_dev_name;
01304
01305 size_t idx = get_new_class_dev_idx(cl);
01306 asprintf(&dev_name, "%s%zu", base_name, idx);
01307
01308 return dev_name;
01309 }
01310
01324 dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl,
01325 const char *base_dev_name)
01326 {
01327 dev_class_info_t *info;
01328
01329 assert(fun != NULL);
01330 assert(cl != NULL);
01331
01332 info = create_dev_class_info();
01333
01334
01335 if (info != NULL) {
01336 info->dev_class = cl;
01337 info->fun = fun;
01338
01339
01340 fibril_mutex_lock(&cl->mutex);
01341 list_append(&info->link, &cl->devices);
01342 fibril_mutex_unlock(&cl->mutex);
01343
01344
01345 list_append(&info->dev_classes, &fun->classes);
01346
01347
01348 info->dev_name = create_dev_name_for_class(cl, base_dev_name);
01349 }
01350
01351 return info;
01352 }
01353
01354 dev_class_t *get_dev_class(class_list_t *class_list, char *class_name)
01355 {
01356 dev_class_t *cl;
01357
01358 fibril_rwlock_write_lock(&class_list->rwlock);
01359 cl = find_dev_class_no_lock(class_list, class_name);
01360 if (cl == NULL) {
01361 cl = create_dev_class();
01362 if (cl != NULL) {
01363 cl->name = class_name;
01364 cl->base_dev_name = "";
01365 add_dev_class_no_lock(class_list, cl);
01366 }
01367 }
01368
01369 fibril_rwlock_write_unlock(&class_list->rwlock);
01370 return cl;
01371 }
01372
01373 dev_class_t *find_dev_class_no_lock(class_list_t *class_list,
01374 const char *class_name)
01375 {
01376 dev_class_t *cl;
01377 link_t *link = class_list->classes.next;
01378
01379 while (link != &class_list->classes) {
01380 cl = list_get_instance(link, dev_class_t, link);
01381 if (str_cmp(cl->name, class_name) == 0) {
01382 return cl;
01383 }
01384 link = link->next;
01385 }
01386
01387 return NULL;
01388 }
01389
01390 void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl)
01391 {
01392 list_append(&cl->link, &class_list->classes);
01393 }
01394
01395 dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name)
01396 {
01397 assert(dev_class != NULL);
01398 assert(dev_name != NULL);
01399
01400 link_t *link;
01401 for (link = dev_class->devices.next;
01402 link != &dev_class->devices;
01403 link = link->next) {
01404 dev_class_info_t *dev = list_get_instance(link,
01405 dev_class_info_t, link);
01406
01407 if (str_cmp(dev->dev_name, dev_name) == 0) {
01408 return dev;
01409 }
01410 }
01411
01412 return NULL;
01413 }
01414
01415 void init_class_list(class_list_t *class_list)
01416 {
01417 list_initialize(&class_list->classes);
01418 fibril_rwlock_initialize(&class_list->rwlock);
01419 hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1,
01420 &devmap_devices_class_ops);
01421 }
01422
01423
01424
01425
01426 fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
01427 {
01428 fun_node_t *fun = NULL;
01429 link_t *link;
01430 unsigned long key = (unsigned long) devmap_handle;
01431
01432 fibril_rwlock_read_lock(&tree->rwlock);
01433 link = hash_table_find(&tree->devmap_functions, &key);
01434 if (link != NULL)
01435 fun = hash_table_get_instance(link, fun_node_t, devmap_fun);
01436 fibril_rwlock_read_unlock(&tree->rwlock);
01437
01438 return fun;
01439 }
01440
01441 fun_node_t *find_devmap_class_function(class_list_t *classes,
01442 devmap_handle_t devmap_handle)
01443 {
01444 fun_node_t *fun = NULL;
01445 dev_class_info_t *cli;
01446 link_t *link;
01447 unsigned long key = (unsigned long)devmap_handle;
01448
01449 fibril_rwlock_read_lock(&classes->rwlock);
01450 link = hash_table_find(&classes->devmap_functions, &key);
01451 if (link != NULL) {
01452 cli = hash_table_get_instance(link, dev_class_info_t,
01453 devmap_link);
01454 fun = cli->fun;
01455 }
01456 fibril_rwlock_read_unlock(&classes->rwlock);
01457
01458 return fun;
01459 }
01460
01461 void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli)
01462 {
01463 unsigned long key = (unsigned long) cli->devmap_handle;
01464
01465 fibril_rwlock_write_lock(&class_list->rwlock);
01466 hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link);
01467 fibril_rwlock_write_unlock(&class_list->rwlock);
01468
01469 assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL);
01470 }
01471
01472 void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun)
01473 {
01474 unsigned long key = (unsigned long) fun->devmap_handle;
01475 fibril_rwlock_write_lock(&tree->rwlock);
01476 hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun);
01477 fibril_rwlock_write_unlock(&tree->rwlock);
01478 }
01479