Changeset 181c32f in mainline
- Timestamp:
- 2013-09-10T21:12:23Z (11 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 02e5e34
- Parents:
- d80d7a8
- Location:
- uspace/srv/devman
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/Makefile
rd80d7a8 r181c32f 36 36 dev.c \ 37 37 devtree.c \ 38 drv_conn.c \ 38 39 driver.c \ 39 40 loc.c \ -
uspace/srv/devman/main.c
rd80d7a8 r181c32f 36 36 */ 37 37 38 #include <inttypes.h>39 38 #include <assert.h> 40 39 #include <ipc/services.h> … … 43 42 #include <stdio.h> 44 43 #include <errno.h> 45 #include <str_error.h>46 44 #include <stdbool.h> 47 45 #include <fibril_synch.h> 48 46 #include <stdlib.h> 49 47 #include <str.h> 50 #include <dirent.h>51 #include <fcntl.h>52 #include <sys/stat.h>53 48 #include <ctype.h> 54 49 #include <io/log.h> 55 50 #include <ipc/devman.h> 56 51 #include <ipc/driver.h> 57 #include <thread.h>58 52 #include <loc.h> 59 53 … … 62 56 #include "devman.h" 63 57 #include "devtree.h" 58 #include "drv_conn.h" 64 59 #include "driver.h" 65 60 #include "fun.h" … … 68 63 #define DRIVER_DEFAULT_STORE "/drv" 69 64 70 staticdriver_list_t drivers_list;65 driver_list_t drivers_list; 71 66 dev_tree_t device_tree; 72 73 static int init_running_drv(void *drv);74 75 /** Register running driver. */76 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)77 {78 driver_t *driver = NULL;79 char *drv_name = NULL;80 81 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");82 83 /* Get driver name. */84 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);85 if (rc != EOK) {86 async_answer_0(callid, rc);87 return NULL;88 }89 90 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",91 drv_name);92 93 /* Find driver structure. */94 driver = find_driver(&drivers_list, drv_name);95 if (driver == NULL) {96 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);97 free(drv_name);98 drv_name = NULL;99 async_answer_0(callid, ENOENT);100 return NULL;101 }102 103 free(drv_name);104 drv_name = NULL;105 106 fibril_mutex_lock(&driver->driver_mutex);107 108 if (driver->sess) {109 /* We already have a connection to the driver. */110 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",111 driver->name);112 fibril_mutex_unlock(&driver->driver_mutex);113 async_answer_0(callid, EEXISTS);114 return NULL;115 }116 117 switch (driver->state) {118 case DRIVER_NOT_STARTED:119 /* Somebody started the driver manually. */120 log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",121 driver->name);122 driver->state = DRIVER_STARTING;123 break;124 case DRIVER_STARTING:125 /* The expected case */126 break;127 case DRIVER_RUNNING:128 /* Should not happen since we do not have a connected session */129 assert(false);130 }131 132 /* Create connection to the driver. */133 log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",134 driver->name);135 driver->sess = async_callback_receive(EXCHANGE_PARALLEL);136 if (!driver->sess) {137 fibril_mutex_unlock(&driver->driver_mutex);138 async_answer_0(callid, ENOTSUP);139 return NULL;140 }141 /* FIXME: Work around problem with callback sessions */142 async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);143 144 log_msg(LOG_DEFAULT, LVL_NOTE,145 "The `%s' driver was successfully registered as running.",146 driver->name);147 148 /*149 * Initialize the driver as running (e.g. pass assigned devices to it)150 * in a separate fibril; the separate fibril is used to enable the151 * driver to use devman service during the driver's initialization.152 */153 fid_t fid = fibril_create(init_running_drv, driver);154 if (fid == 0) {155 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \156 "for driver `%s'.", driver->name);157 fibril_mutex_unlock(&driver->driver_mutex);158 async_answer_0(callid, ENOMEM);159 return NULL;160 }161 162 fibril_add_ready(fid);163 fibril_mutex_unlock(&driver->driver_mutex);164 165 async_answer_0(callid, EOK);166 return driver;167 }168 169 /** Receive device match ID from the device's parent driver and add it to the170 * list of devices match ids.171 *172 * @param match_ids The list of the device's match ids.173 * @return Zero on success, negative error code otherwise.174 */175 static int devman_receive_match_id(match_id_list_t *match_ids)176 {177 match_id_t *match_id = create_match_id();178 ipc_callid_t callid;179 ipc_call_t call;180 int rc = 0;181 182 callid = async_get_call(&call);183 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {184 log_msg(LOG_DEFAULT, LVL_ERROR,185 "Invalid protocol when trying to receive match id.");186 async_answer_0(callid, EINVAL);187 delete_match_id(match_id);188 return EINVAL;189 }190 191 if (match_id == NULL) {192 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");193 async_answer_0(callid, ENOMEM);194 return ENOMEM;195 }196 197 async_answer_0(callid, EOK);198 199 match_id->score = IPC_GET_ARG1(call);200 201 char *match_id_str;202 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);203 match_id->id = match_id_str;204 if (rc != EOK) {205 delete_match_id(match_id);206 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",207 str_error(rc));208 return rc;209 }210 211 list_append(&match_id->link, &match_ids->ids);212 213 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",214 match_id->id, match_id->score);215 return rc;216 }217 218 /** Receive device match IDs from the device's parent driver and add them to the219 * list of devices match ids.220 *221 * @param match_count The number of device's match ids to be received.222 * @param match_ids The list of the device's match ids.223 * @return Zero on success, negative error code otherwise.224 */225 static int devman_receive_match_ids(sysarg_t match_count,226 match_id_list_t *match_ids)227 {228 int ret = EOK;229 size_t i;230 231 for (i = 0; i < match_count; i++) {232 if (EOK != (ret = devman_receive_match_id(match_ids)))233 return ret;234 }235 return ret;236 }237 238 static int assign_driver_fibril(void *arg)239 {240 dev_node_t *dev_node = (dev_node_t *) arg;241 assign_driver(dev_node, &drivers_list, &device_tree);242 243 /* Delete one reference we got from the caller. */244 dev_del_ref(dev_node);245 return EOK;246 }247 248 static int online_function(fun_node_t *fun)249 {250 dev_node_t *dev;251 252 fibril_rwlock_write_lock(&device_tree.rwlock);253 254 if (fun->state == FUN_ON_LINE) {255 fibril_rwlock_write_unlock(&device_tree.rwlock);256 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",257 fun->pathname);258 return EOK;259 }260 261 if (fun->ftype == fun_inner) {262 dev = create_dev_node();263 if (dev == NULL) {264 fibril_rwlock_write_unlock(&device_tree.rwlock);265 return ENOMEM;266 }267 268 insert_dev_node(&device_tree, dev, fun);269 dev_add_ref(dev);270 }271 272 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);273 274 if (fun->ftype == fun_inner) {275 dev = fun->child;276 assert(dev != NULL);277 278 /* Give one reference over to assign_driver_fibril(). */279 dev_add_ref(dev);280 281 /*282 * Try to find a suitable driver and assign it to the device. We do283 * not want to block the current fibril that is used for processing284 * incoming calls: we will launch a separate fibril to handle the285 * driver assigning. That is because assign_driver can actually include286 * task spawning which could take some time.287 */288 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);289 if (assign_fibril == 0) {290 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "291 "assigning driver.");292 /* XXX Cleanup */293 fibril_rwlock_write_unlock(&device_tree.rwlock);294 return ENOMEM;295 }296 fibril_add_ready(assign_fibril);297 } else298 loc_register_tree_function(fun, &device_tree);299 300 fibril_rwlock_write_unlock(&device_tree.rwlock);301 302 return EOK;303 }304 305 static int offline_function(fun_node_t *fun)306 {307 int rc;308 309 fibril_rwlock_write_lock(&device_tree.rwlock);310 311 if (fun->state == FUN_OFF_LINE) {312 fibril_rwlock_write_unlock(&device_tree.rwlock);313 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",314 fun->pathname);315 return EOK;316 }317 318 if (fun->ftype == fun_inner) {319 log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",320 fun->pathname);321 322 if (fun->child != NULL) {323 dev_node_t *dev = fun->child;324 device_state_t dev_state;325 326 dev_add_ref(dev);327 dev_state = dev->state;328 329 fibril_rwlock_write_unlock(&device_tree.rwlock);330 331 /* If device is owned by driver, ask driver to give it up. */332 if (dev_state == DEVICE_USABLE) {333 rc = driver_dev_remove(&device_tree, dev);334 if (rc != EOK) {335 dev_del_ref(dev);336 return ENOTSUP;337 }338 }339 340 /* Verify that driver removed all functions */341 fibril_rwlock_read_lock(&device_tree.rwlock);342 if (!list_empty(&dev->functions)) {343 fibril_rwlock_read_unlock(&device_tree.rwlock);344 dev_del_ref(dev);345 return EIO;346 }347 348 driver_t *driver = dev->drv;349 fibril_rwlock_read_unlock(&device_tree.rwlock);350 351 if (driver)352 detach_driver(&device_tree, dev);353 354 fibril_rwlock_write_lock(&device_tree.rwlock);355 remove_dev_node(&device_tree, dev);356 357 /* Delete ref created when node was inserted */358 dev_del_ref(dev);359 /* Delete ref created by dev_add_ref(dev) above */360 dev_del_ref(dev);361 }362 } else {363 /* Unregister from location service */364 rc = loc_service_unregister(fun->service_id);365 if (rc != EOK) {366 fibril_rwlock_write_unlock(&device_tree.rwlock);367 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");368 return EIO;369 }370 371 fun->service_id = 0;372 }373 374 fun->state = FUN_OFF_LINE;375 fibril_rwlock_write_unlock(&device_tree.rwlock);376 377 return EOK;378 }379 380 /** Handle function registration.381 *382 * Child devices are registered by their parent's device driver.383 */384 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)385 {386 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);387 devman_handle_t dev_handle = IPC_GET_ARG2(*call);388 sysarg_t match_count = IPC_GET_ARG3(*call);389 dev_tree_t *tree = &device_tree;390 391 dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);392 if (pdev == NULL) {393 async_answer_0(callid, ENOENT);394 return;395 }396 397 if (ftype != fun_inner && ftype != fun_exposed) {398 /* Unknown function type */399 log_msg(LOG_DEFAULT, LVL_ERROR,400 "Unknown function type %d provided by driver.",401 (int) ftype);402 403 dev_del_ref(pdev);404 async_answer_0(callid, EINVAL);405 return;406 }407 408 char *fun_name = NULL;409 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);410 if (rc != EOK) {411 dev_del_ref(pdev);412 async_answer_0(callid, rc);413 return;414 }415 416 fibril_rwlock_write_lock(&tree->rwlock);417 418 /* Check device state */419 if (pdev->state == DEVICE_REMOVED) {420 fibril_rwlock_write_unlock(&tree->rwlock);421 dev_del_ref(pdev);422 async_answer_0(callid, ENOENT);423 return;424 }425 426 /* Check that function with same name is not there already. */427 fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name);428 if (tfun) {429 fun_del_ref(tfun); /* drop the new unwanted reference */430 fibril_rwlock_write_unlock(&tree->rwlock);431 dev_del_ref(pdev);432 async_answer_0(callid, EEXISTS);433 printf(NAME ": Warning, driver tried to register `%s' twice.\n",434 fun_name);435 free(fun_name);436 return;437 }438 439 fun_node_t *fun = create_fun_node();440 /* One reference for creation, one for us */441 fun_add_ref(fun);442 fun_add_ref(fun);443 fun->ftype = ftype;444 445 /*446 * We can lock the function here even when holding the tree because447 * we know it cannot be held by anyone else yet.448 */449 fun_busy_lock(fun);450 451 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {452 fibril_rwlock_write_unlock(&tree->rwlock);453 dev_del_ref(pdev);454 fun_busy_unlock(fun);455 fun_del_ref(fun);456 delete_fun_node(fun);457 async_answer_0(callid, ENOMEM);458 return;459 }460 461 fibril_rwlock_write_unlock(&tree->rwlock);462 dev_del_ref(pdev);463 464 devman_receive_match_ids(match_count, &fun->match_ids);465 466 rc = online_function(fun);467 if (rc != EOK) {468 /* XXX Set some failed state? */469 fun_busy_unlock(fun);470 fun_del_ref(fun);471 async_answer_0(callid, rc);472 return;473 }474 475 fun_busy_unlock(fun);476 fun_del_ref(fun);477 478 /* Return device handle to parent's driver. */479 async_answer_1(callid, EOK, fun->handle);480 }481 482 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)483 {484 devman_handle_t handle = IPC_GET_ARG1(*call);485 category_id_t cat_id;486 int rc;487 488 /* Get category name. */489 char *cat_name;490 rc = async_data_write_accept((void **) &cat_name, true,491 0, 0, 0, 0);492 if (rc != EOK) {493 async_answer_0(callid, rc);494 return;495 }496 497 fun_node_t *fun = find_fun_node(&device_tree, handle);498 if (fun == NULL) {499 async_answer_0(callid, ENOENT);500 return;501 }502 503 fibril_rwlock_read_lock(&device_tree.rwlock);504 505 /* Check function state */506 if (fun->state == FUN_REMOVED) {507 fibril_rwlock_read_unlock(&device_tree.rwlock);508 async_answer_0(callid, ENOENT);509 return;510 }511 512 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);513 if (rc == EOK) {514 loc_service_add_to_cat(fun->service_id, cat_id);515 log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",516 fun->pathname, cat_name);517 } else {518 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "519 "`%s'.", fun->pathname, cat_name);520 }521 522 fibril_rwlock_read_unlock(&device_tree.rwlock);523 fun_del_ref(fun);524 525 async_answer_0(callid, rc);526 }527 528 /** Online function by driver request.529 *530 */531 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,532 driver_t *drv)533 {534 fun_node_t *fun;535 int rc;536 537 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");538 539 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));540 if (fun == NULL) {541 async_answer_0(iid, ENOENT);542 return;543 }544 545 fun_busy_lock(fun);546 547 fibril_rwlock_read_lock(&device_tree.rwlock);548 if (fun->dev == NULL || fun->dev->drv != drv) {549 fibril_rwlock_read_unlock(&device_tree.rwlock);550 fun_busy_unlock(fun);551 fun_del_ref(fun);552 async_answer_0(iid, ENOENT);553 return;554 }555 fibril_rwlock_read_unlock(&device_tree.rwlock);556 557 rc = online_function(fun);558 if (rc != EOK) {559 fun_busy_unlock(fun);560 fun_del_ref(fun);561 async_answer_0(iid, (sysarg_t) rc);562 return;563 }564 565 fun_busy_unlock(fun);566 fun_del_ref(fun);567 568 async_answer_0(iid, (sysarg_t) EOK);569 }570 571 572 /** Offline function by driver request.573 *574 */575 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,576 driver_t *drv)577 {578 fun_node_t *fun;579 int rc;580 581 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));582 if (fun == NULL) {583 async_answer_0(iid, ENOENT);584 return;585 }586 587 fun_busy_lock(fun);588 589 fibril_rwlock_write_lock(&device_tree.rwlock);590 if (fun->dev == NULL || fun->dev->drv != drv) {591 fun_busy_unlock(fun);592 fun_del_ref(fun);593 async_answer_0(iid, ENOENT);594 return;595 }596 fibril_rwlock_write_unlock(&device_tree.rwlock);597 598 rc = offline_function(fun);599 if (rc != EOK) {600 fun_busy_unlock(fun);601 fun_del_ref(fun);602 async_answer_0(iid, (sysarg_t) rc);603 return;604 }605 606 fun_busy_unlock(fun);607 fun_del_ref(fun);608 async_answer_0(iid, (sysarg_t) EOK);609 }610 611 /** Remove function. */612 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)613 {614 devman_handle_t fun_handle = IPC_GET_ARG1(*call);615 dev_tree_t *tree = &device_tree;616 int rc;617 618 fun_node_t *fun = find_fun_node(&device_tree, fun_handle);619 if (fun == NULL) {620 async_answer_0(callid, ENOENT);621 return;622 }623 624 fun_busy_lock(fun);625 626 fibril_rwlock_write_lock(&tree->rwlock);627 628 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);629 630 /* Check function state */631 if (fun->state == FUN_REMOVED) {632 fibril_rwlock_write_unlock(&tree->rwlock);633 fun_busy_unlock(fun);634 fun_del_ref(fun);635 async_answer_0(callid, ENOENT);636 return;637 }638 639 if (fun->ftype == fun_inner) {640 /* This is a surprise removal. Handle possible descendants */641 if (fun->child != NULL) {642 dev_node_t *dev = fun->child;643 device_state_t dev_state;644 int gone_rc;645 646 dev_add_ref(dev);647 dev_state = dev->state;648 649 fibril_rwlock_write_unlock(&device_tree.rwlock);650 651 /* If device is owned by driver, inform driver it is gone. */652 if (dev_state == DEVICE_USABLE)653 gone_rc = driver_dev_gone(&device_tree, dev);654 else655 gone_rc = EOK;656 657 fibril_rwlock_read_lock(&device_tree.rwlock);658 659 /* Verify that driver succeeded and removed all functions */660 if (gone_rc != EOK || !list_empty(&dev->functions)) {661 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "662 "functions for device that is gone. "663 "Device node is now defunct.");664 665 /*666 * Not much we can do but mark the device667 * node as having invalid state. This668 * is a driver bug.669 */670 dev->state = DEVICE_INVALID;671 fibril_rwlock_read_unlock(&device_tree.rwlock);672 dev_del_ref(dev);673 if (gone_rc == EOK)674 gone_rc = ENOTSUP;675 fun_busy_unlock(fun);676 fun_del_ref(fun);677 async_answer_0(callid, gone_rc);678 return;679 }680 681 driver_t *driver = dev->drv;682 fibril_rwlock_read_unlock(&device_tree.rwlock);683 684 if (driver)685 detach_driver(&device_tree, dev);686 687 fibril_rwlock_write_lock(&device_tree.rwlock);688 remove_dev_node(&device_tree, dev);689 690 /* Delete ref created when node was inserted */691 dev_del_ref(dev);692 /* Delete ref created by dev_add_ref(dev) above */693 dev_del_ref(dev);694 }695 } else {696 if (fun->service_id != 0) {697 /* Unregister from location service */698 rc = loc_service_unregister(fun->service_id);699 if (rc != EOK) {700 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "701 "service.");702 fibril_rwlock_write_unlock(&tree->rwlock);703 fun_busy_unlock(fun);704 fun_del_ref(fun);705 async_answer_0(callid, EIO);706 return;707 }708 }709 }710 711 remove_fun_node(&device_tree, fun);712 fibril_rwlock_write_unlock(&tree->rwlock);713 fun_busy_unlock(fun);714 715 /* Delete ref added when inserting function into tree */716 fun_del_ref(fun);717 /* Delete ref added above when looking up function */718 fun_del_ref(fun);719 720 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");721 async_answer_0(callid, EOK);722 }723 724 /** Initialize driver which has registered itself as running and ready.725 *726 * The initialization is done in a separate fibril to avoid deadlocks (if the727 * driver needed to be served by devman during the driver's initialization).728 */729 static int init_running_drv(void *drv)730 {731 driver_t *driver = (driver_t *) drv;732 733 initialize_running_driver(driver, &device_tree);734 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",735 driver->name);736 return 0;737 }738 739 /** Function for handling connections from a driver to the device manager. */740 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)741 {742 client_t *client;743 driver_t *driver = NULL;744 745 /* Accept the connection. */746 async_answer_0(iid, EOK);747 748 client = async_get_client_data();749 if (client == NULL) {750 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");751 return;752 }753 754 while (true) {755 ipc_call_t call;756 ipc_callid_t callid = async_get_call(&call);757 758 if (!IPC_GET_IMETHOD(call))759 break;760 761 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {762 fibril_mutex_lock(&client->mutex);763 driver = client->driver;764 fibril_mutex_unlock(&client->mutex);765 if (driver == NULL) {766 /* First call must be to DEVMAN_DRIVER_REGISTER */767 async_answer_0(callid, ENOTSUP);768 continue;769 }770 }771 772 switch (IPC_GET_IMETHOD(call)) {773 case DEVMAN_DRIVER_REGISTER:774 fibril_mutex_lock(&client->mutex);775 if (client->driver != NULL) {776 fibril_mutex_unlock(&client->mutex);777 async_answer_0(callid, EINVAL);778 continue;779 }780 client->driver = devman_driver_register(callid, &call);781 fibril_mutex_unlock(&client->mutex);782 break;783 case DEVMAN_ADD_FUNCTION:784 devman_add_function(callid, &call);785 break;786 case DEVMAN_ADD_DEVICE_TO_CATEGORY:787 devman_add_function_to_cat(callid, &call);788 break;789 case DEVMAN_DRV_FUN_ONLINE:790 devman_drv_fun_online(callid, &call, driver);791 break;792 case DEVMAN_DRV_FUN_OFFLINE:793 devman_drv_fun_offline(callid, &call, driver);794 break;795 case DEVMAN_REMOVE_FUNCTION:796 devman_remove_function(callid, &call);797 break;798 default:799 async_answer_0(callid, EINVAL);800 break;801 }802 }803 }804 67 805 68 static void devman_forward(ipc_callid_t iid, ipc_call_t *icall, -
uspace/srv/devman/main.h
rd80d7a8 r181c32f 36 36 #include "devman.h" 37 37 38 extern driver_list_t drivers_list; 38 39 extern dev_tree_t device_tree; 39 40
Note:
See TracChangeset
for help on using the changeset viewer.