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
00038 #include <inttypes.h>
00039 #include <assert.h>
00040 #include <ipc/services.h>
00041 #include <ipc/ns.h>
00042 #include <async.h>
00043 #include <stdio.h>
00044 #include <errno.h>
00045 #include <str_error.h>
00046 #include <bool.h>
00047 #include <fibril_synch.h>
00048 #include <stdlib.h>
00049 #include <str.h>
00050 #include <dirent.h>
00051 #include <fcntl.h>
00052 #include <sys/stat.h>
00053 #include <ctype.h>
00054 #include <io/log.h>
00055 #include <ipc/devman.h>
00056 #include <ipc/driver.h>
00057 #include <thread.h>
00058 #include <devmap.h>
00059
00060 #include "devman.h"
00061
00062 #define DRIVER_DEFAULT_STORE "/drv"
00063
00064 static driver_list_t drivers_list;
00065 static dev_tree_t device_tree;
00066 static class_list_t class_list;
00067
00069 static driver_t *devman_driver_register(void)
00070 {
00071 ipc_call_t icall;
00072 ipc_callid_t iid;
00073 driver_t *driver = NULL;
00074
00075 log_msg(LVL_DEBUG, "devman_driver_register");
00076
00077 iid = async_get_call(&icall);
00078 if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {
00079 async_answer_0(iid, EREFUSED);
00080 return NULL;
00081 }
00082
00083 char *drv_name = NULL;
00084
00085
00086 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
00087 if (rc != EOK) {
00088 async_answer_0(iid, rc);
00089 return NULL;
00090 }
00091
00092 log_msg(LVL_DEBUG, "The `%s' driver is trying to register.",
00093 drv_name);
00094
00095
00096 driver = find_driver(&drivers_list, drv_name);
00097 if (driver == NULL) {
00098 log_msg(LVL_ERROR, "No driver named `%s' was found.", drv_name);
00099 free(drv_name);
00100 drv_name = NULL;
00101 async_answer_0(iid, ENOENT);
00102 return NULL;
00103 }
00104
00105 free(drv_name);
00106 drv_name = NULL;
00107
00108 fibril_mutex_lock(&driver->driver_mutex);
00109
00110 if (driver->phone >= 0) {
00111
00112 log_msg(LVL_ERROR, "Driver '%s' already started.\n",
00113 driver->name);
00114 fibril_mutex_unlock(&driver->driver_mutex);
00115 async_answer_0(iid, EEXISTS);
00116 return NULL;
00117 }
00118
00119 switch (driver->state) {
00120 case DRIVER_NOT_STARTED:
00121
00122 log_msg(LVL_NOTE, "Driver '%s' started manually.\n",
00123 driver->name);
00124 driver->state = DRIVER_STARTING;
00125 break;
00126 case DRIVER_STARTING:
00127
00128 break;
00129 case DRIVER_RUNNING:
00130
00131 assert(false);
00132 }
00133
00134
00135 log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
00136 driver->name);
00137 ipc_call_t call;
00138 ipc_callid_t callid = async_get_call(&call);
00139 if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
00140 fibril_mutex_unlock(&driver->driver_mutex);
00141 async_answer_0(callid, ENOTSUP);
00142 async_answer_0(iid, ENOTSUP);
00143 return NULL;
00144 }
00145
00146
00147 driver->phone = IPC_GET_ARG5(call);
00148
00149 fibril_mutex_unlock(&driver->driver_mutex);
00150
00151 log_msg(LVL_NOTE,
00152 "The `%s' driver was successfully registered as running.",
00153 driver->name);
00154
00155 async_answer_0(callid, EOK);
00156 async_answer_0(iid, EOK);
00157
00158 return driver;
00159 }
00160
00167 static int devman_receive_match_id(match_id_list_t *match_ids)
00168 {
00169 match_id_t *match_id = create_match_id();
00170 ipc_callid_t callid;
00171 ipc_call_t call;
00172 int rc = 0;
00173
00174 callid = async_get_call(&call);
00175 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
00176 log_msg(LVL_ERROR,
00177 "Invalid protocol when trying to receive match id.");
00178 async_answer_0(callid, EINVAL);
00179 delete_match_id(match_id);
00180 return EINVAL;
00181 }
00182
00183 if (match_id == NULL) {
00184 log_msg(LVL_ERROR, "Failed to allocate match id.");
00185 async_answer_0(callid, ENOMEM);
00186 return ENOMEM;
00187 }
00188
00189 async_answer_0(callid, EOK);
00190
00191 match_id->score = IPC_GET_ARG1(call);
00192
00193 char *match_id_str;
00194 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
00195 match_id->id = match_id_str;
00196 if (rc != EOK) {
00197 delete_match_id(match_id);
00198 log_msg(LVL_ERROR, "Failed to receive match id string: %s.",
00199 str_error(rc));
00200 return rc;
00201 }
00202
00203 list_append(&match_id->link, &match_ids->ids);
00204
00205 log_msg(LVL_DEBUG, "Received match id `%s', score %d.",
00206 match_id->id, match_id->score);
00207 return rc;
00208 }
00209
00217 static int devman_receive_match_ids(sysarg_t match_count,
00218 match_id_list_t *match_ids)
00219 {
00220 int ret = EOK;
00221 size_t i;
00222
00223 for (i = 0; i < match_count; i++) {
00224 if (EOK != (ret = devman_receive_match_id(match_ids)))
00225 return ret;
00226 }
00227 return ret;
00228 }
00229
00230 static int assign_driver_fibril(void *arg)
00231 {
00232 dev_node_t *dev_node = (dev_node_t *) arg;
00233 assign_driver(dev_node, &drivers_list, &device_tree);
00234 return EOK;
00235 }
00236
00241 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
00242 {
00243 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
00244 devman_handle_t dev_handle = IPC_GET_ARG2(*call);
00245 sysarg_t match_count = IPC_GET_ARG3(*call);
00246 dev_tree_t *tree = &device_tree;
00247
00248 fibril_rwlock_write_lock(&tree->rwlock);
00249
00250 dev_node_t *dev = NULL;
00251 dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
00252
00253 if (pdev == NULL) {
00254 fibril_rwlock_write_unlock(&tree->rwlock);
00255 async_answer_0(callid, ENOENT);
00256 return;
00257 }
00258
00259 if (ftype != fun_inner && ftype != fun_exposed) {
00260
00261 log_msg(LVL_ERROR,
00262 "Unknown function type %d provided by driver.",
00263 (int) ftype);
00264
00265 fibril_rwlock_write_unlock(&tree->rwlock);
00266 async_answer_0(callid, EINVAL);
00267 return;
00268 }
00269
00270 char *fun_name = NULL;
00271 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
00272 if (rc != EOK) {
00273 fibril_rwlock_write_unlock(&tree->rwlock);
00274 async_answer_0(callid, rc);
00275 return;
00276 }
00277
00278
00279 if (find_fun_node_in_device(pdev, fun_name) != NULL) {
00280 fibril_rwlock_write_unlock(&tree->rwlock);
00281 async_answer_0(callid, EEXISTS);
00282 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
00283 fun_name);
00284 free(fun_name);
00285 return;
00286 }
00287
00288 fun_node_t *fun = create_fun_node();
00289 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
00290 fibril_rwlock_write_unlock(&tree->rwlock);
00291 delete_fun_node(fun);
00292 async_answer_0(callid, ENOMEM);
00293 return;
00294 }
00295
00296 if (ftype == fun_inner) {
00297 dev = create_dev_node();
00298 if (dev == NULL) {
00299 fibril_rwlock_write_unlock(&tree->rwlock);
00300 delete_fun_node(fun);
00301 async_answer_0(callid, ENOMEM);
00302 return;
00303 }
00304
00305 insert_dev_node(tree, dev, fun);
00306 }
00307
00308 fibril_rwlock_write_unlock(&tree->rwlock);
00309
00310 log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
00311
00312 devman_receive_match_ids(match_count, &fun->match_ids);
00313
00314 if (ftype == fun_inner) {
00315 assert(dev != NULL);
00316
00317
00318
00319
00320
00321
00322
00323 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
00324 if (assign_fibril == 0) {
00325
00326
00327
00328
00329 (void) assign_driver_fibril(fun);
00330 } else {
00331 fibril_add_ready(assign_fibril);
00332 }
00333 } else {
00334 devmap_register_tree_function(fun, tree);
00335 }
00336
00337
00338 async_answer_1(callid, EOK, fun->handle);
00339 }
00340
00341 static void devmap_register_class_dev(dev_class_info_t *cli)
00342 {
00343
00344 char *devmap_pathname = NULL;
00345
00346 asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE,
00347 cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name);
00348 if (devmap_pathname == NULL)
00349 return;
00350
00351
00352
00353
00354
00355 devmap_device_register_with_iface(devmap_pathname,
00356 &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
00357
00358
00359
00360
00361
00362 class_add_devmap_function(&class_list, cli);
00363
00364 free(devmap_pathname);
00365 }
00366
00367 static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
00368 {
00369 devman_handle_t handle = IPC_GET_ARG1(*call);
00370
00371
00372 char *class_name;
00373 int rc = async_data_write_accept((void **) &class_name, true,
00374 0, 0, 0, 0);
00375 if (rc != EOK) {
00376 async_answer_0(callid, rc);
00377 return;
00378 }
00379
00380 fun_node_t *fun = find_fun_node(&device_tree, handle);
00381 if (fun == NULL) {
00382 async_answer_0(callid, ENOENT);
00383 return;
00384 }
00385
00386 dev_class_t *cl = get_dev_class(&class_list, class_name);
00387 dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL);
00388
00389
00390 devmap_register_class_dev(class_info);
00391
00392 log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.",
00393 fun->pathname, class_name, class_info->dev_name);
00394
00395 async_answer_0(callid, EOK);
00396 }
00397
00403 static int init_running_drv(void *drv)
00404 {
00405 driver_t *driver = (driver_t *) drv;
00406
00407 initialize_running_driver(driver, &device_tree);
00408 log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
00409 driver->name);
00410 return 0;
00411 }
00412
00414 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
00415 {
00416
00417 async_answer_0(iid, EOK);
00418
00419 driver_t *driver = devman_driver_register();
00420 if (driver == NULL)
00421 return;
00422
00423
00424
00425
00426
00427
00428 fid_t fid = fibril_create(init_running_drv, driver);
00429 if (fid == 0) {
00430 log_msg(LVL_ERROR, "Failed to create initialization fibril " \
00431 "for driver `%s'.", driver->name);
00432 return;
00433 }
00434 fibril_add_ready(fid);
00435
00436 ipc_callid_t callid;
00437 ipc_call_t call;
00438 bool cont = true;
00439 while (cont) {
00440 callid = async_get_call(&call);
00441
00442 switch (IPC_GET_IMETHOD(call)) {
00443 case IPC_M_PHONE_HUNGUP:
00444 cont = false;
00445 continue;
00446 case DEVMAN_ADD_FUNCTION:
00447 devman_add_function(callid, &call);
00448 break;
00449 case DEVMAN_ADD_DEVICE_TO_CLASS:
00450 devman_add_function_to_class(callid, &call);
00451 break;
00452 default:
00453 async_answer_0(callid, EINVAL);
00454 break;
00455 }
00456 }
00457 }
00458
00461 static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
00462 {
00463 char *pathname;
00464
00465 int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
00466 if (rc != EOK) {
00467 async_answer_0(iid, rc);
00468 return;
00469 }
00470
00471 fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
00472
00473 free(pathname);
00474
00475 if (fun == NULL) {
00476 async_answer_0(iid, ENOENT);
00477 return;
00478 }
00479
00480 async_answer_1(iid, EOK, fun->handle);
00481 }
00482
00484 static void devman_function_get_handle_by_class(ipc_callid_t iid,
00485 ipc_call_t *icall)
00486 {
00487 char *classname;
00488 char *devname;
00489
00490 int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0);
00491 if (rc != EOK) {
00492 async_answer_0(iid, rc);
00493 return;
00494 }
00495 rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0);
00496 if (rc != EOK) {
00497 free(classname);
00498 async_answer_0(iid, rc);
00499 return;
00500 }
00501
00502
00503 fun_node_t *fun = find_fun_node_by_class(&class_list,
00504 classname, devname);
00505
00506 free(classname);
00507 free(devname);
00508
00509 if (fun == NULL) {
00510 async_answer_0(iid, ENOENT);
00511 return;
00512 }
00513
00514 async_answer_1(iid, EOK, fun->handle);
00515 }
00516
00518 static void devman_get_device_path_by_handle(ipc_callid_t iid,
00519 ipc_call_t *icall)
00520 {
00521 devman_handle_t handle = IPC_GET_ARG1(*icall);
00522
00523 fun_node_t *fun = find_fun_node(&device_tree, handle);
00524 if (fun == NULL) {
00525 async_answer_0(iid, ENOMEM);
00526 return;
00527 }
00528
00529 ipc_callid_t data_callid;
00530 size_t data_len;
00531 if (!async_data_read_receive(&data_callid, &data_len)) {
00532 async_answer_0(iid, EINVAL);
00533 return;
00534 }
00535
00536 void *buffer = malloc(data_len);
00537 if (buffer == NULL) {
00538 async_answer_0(data_callid, ENOMEM);
00539 async_answer_0(iid, ENOMEM);
00540 return;
00541 }
00542
00543 size_t sent_length = str_size(fun->pathname);
00544 if (sent_length > data_len) {
00545 sent_length = data_len;
00546 }
00547
00548 async_data_read_finalize(data_callid, fun->pathname, sent_length);
00549 async_answer_0(iid, EOK);
00550
00551 free(buffer);
00552 }
00553
00554
00556 static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall)
00557 {
00558
00559 async_answer_0(iid, EOK);
00560
00561 bool cont = true;
00562 while (cont) {
00563 ipc_call_t call;
00564 ipc_callid_t callid = async_get_call(&call);
00565
00566 switch (IPC_GET_IMETHOD(call)) {
00567 case IPC_M_PHONE_HUNGUP:
00568 cont = false;
00569 continue;
00570 case DEVMAN_DEVICE_GET_HANDLE:
00571 devman_function_get_handle(callid, &call);
00572 break;
00573 case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
00574 devman_function_get_handle_by_class(callid, &call);
00575 break;
00576 case DEVMAN_DEVICE_GET_DEVICE_PATH:
00577 devman_get_device_path_by_handle(callid, &call);
00578 break;
00579 default:
00580 async_answer_0(callid, ENOENT);
00581 }
00582 }
00583 }
00584
00585 static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
00586 bool drv_to_parent)
00587 {
00588 devman_handle_t handle = IPC_GET_ARG2(*icall);
00589 devman_handle_t fwd_h;
00590 fun_node_t *fun = NULL;
00591 dev_node_t *dev = NULL;
00592
00593 fun = find_fun_node(&device_tree, handle);
00594 if (fun == NULL)
00595 dev = find_dev_node(&device_tree, handle);
00596 else
00597 dev = fun->dev;
00598
00599
00600
00601
00602
00603
00604
00605 if (dev == NULL) {
00606 log_msg(LVL_ERROR, "IPC forwarding failed - no device or "
00607 "function with handle %" PRIun " was found.", handle);
00608 async_answer_0(iid, ENOENT);
00609 return;
00610 }
00611
00612 if (fun == NULL && !drv_to_parent) {
00613 log_msg(LVL_ERROR, NAME ": devman_forward error - cannot "
00614 "connect to handle %" PRIun ", refers to a device.",
00615 handle);
00616 async_answer_0(iid, ENOENT);
00617 return;
00618 }
00619
00620 driver_t *driver = NULL;
00621
00622 if (drv_to_parent) {
00623
00624 if (dev->pfun->dev != NULL)
00625 driver = dev->pfun->dev->drv;
00626 fwd_h = dev->pfun->handle;
00627 } else if (dev->state == DEVICE_USABLE) {
00628
00629 driver = dev->drv;
00630 assert(driver != NULL);
00631
00632 fwd_h = handle;
00633 }
00634
00635 if (driver == NULL) {
00636 log_msg(LVL_ERROR, "IPC forwarding refused - " \
00637 "the device %" PRIun "(%s) is not in usable state.",
00638 handle, dev->pfun->pathname);
00639 async_answer_0(iid, ENOENT);
00640 return;
00641 }
00642
00643 int method;
00644 if (drv_to_parent)
00645 method = DRIVER_DRIVER;
00646 else
00647 method = DRIVER_CLIENT;
00648
00649 if (driver->phone < 0) {
00650 log_msg(LVL_ERROR,
00651 "Could not forward to driver `%s' (phone is %d).",
00652 driver->name, (int) driver->phone);
00653 async_answer_0(iid, EINVAL);
00654 return;
00655 }
00656
00657 if (fun != NULL) {
00658 log_msg(LVL_DEBUG,
00659 "Forwarding request for `%s' function to driver `%s'.",
00660 fun->pathname, driver->name);
00661 } else {
00662 log_msg(LVL_DEBUG,
00663 "Forwarding request for `%s' device to driver `%s'.",
00664 dev->pfun->pathname, driver->name);
00665 }
00666
00667 async_forward_fast(iid, driver->phone, method, fwd_h, 0, IPC_FF_NONE);
00668 }
00669
00672 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
00673 {
00674 devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
00675 fun_node_t *fun;
00676 dev_node_t *dev;
00677
00678 fun = find_devmap_tree_function(&device_tree, devmap_handle);
00679 if (fun == NULL)
00680 fun = find_devmap_class_function(&class_list, devmap_handle);
00681
00682 if (fun == NULL || fun->dev->drv == NULL) {
00683 async_answer_0(iid, ENOENT);
00684 return;
00685 }
00686
00687 dev = fun->dev;
00688
00689 if (dev->state != DEVICE_USABLE || dev->drv->phone < 0) {
00690 async_answer_0(iid, EINVAL);
00691 return;
00692 }
00693
00694 async_forward_fast(iid, dev->drv->phone, DRIVER_CLIENT, fun->handle, 0,
00695 IPC_FF_NONE);
00696 log_msg(LVL_DEBUG,
00697 "Forwarding devmapper request for `%s' function to driver `%s'.",
00698 fun->pathname, dev->drv->name);
00699 }
00700
00702 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall)
00703 {
00704
00705 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
00706 case DEVMAN_DRIVER:
00707 devman_connection_driver(iid, icall);
00708 break;
00709 case DEVMAN_CLIENT:
00710 devman_connection_client(iid, icall);
00711 break;
00712 case DEVMAN_CONNECT_TO_DEVICE:
00713
00714 devman_forward(iid, icall, false);
00715 break;
00716 case DEVMAN_CONNECT_FROM_DEVMAP:
00717
00718 devman_connection_devmapper(iid, icall);
00719 break;
00720 case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
00721
00722 devman_forward(iid, icall, true);
00723 break;
00724 default:
00725
00726 async_answer_0(iid, ENOENT);
00727 }
00728 }
00729
00731 static bool devman_init(void)
00732 {
00733 log_msg(LVL_DEBUG, "devman_init - looking for available drivers.");
00734
00735
00736 init_driver_list(&drivers_list);
00737 if (lookup_available_drivers(&drivers_list,
00738 DRIVER_DEFAULT_STORE) == 0) {
00739 log_msg(LVL_FATAL, "No drivers found.");
00740 return false;
00741 }
00742
00743 log_msg(LVL_DEBUG, "devman_init - list of drivers has been initialized.");
00744
00745
00746 if (!init_device_tree(&device_tree, &drivers_list)) {
00747 log_msg(LVL_FATAL, "Failed to initialize device tree.");
00748 return false;
00749 }
00750
00751 init_class_list(&class_list);
00752
00753
00754
00755
00756
00757
00758
00759 devmap_driver_register(NAME, devman_connection);
00760
00761 return true;
00762 }
00763
00764 int main(int argc, char *argv[])
00765 {
00766 printf(NAME ": HelenOS Device Manager\n");
00767
00768 if (log_init(NAME, LVL_ERROR) != EOK) {
00769 printf(NAME ": Error initializing logging subsystem.\n");
00770 return -1;
00771 }
00772
00773 if (!devman_init()) {
00774 log_msg(LVL_ERROR, "Error while initializing service.");
00775 return -1;
00776 }
00777
00778
00779 async_set_client_connection(devman_connection);
00780
00781
00782 if (service_register(SERVICE_DEVMAN) != EOK) {
00783 log_msg(LVL_ERROR, "Failed registering as a service.");
00784 return -1;
00785 }
00786
00787 printf(NAME ": Accepting connections.\n");
00788 async_manager();
00789
00790
00791 return 0;
00792 }
00793