Changes in uspace/srv/devman/main.c [c4f7bf6:181c32f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/main.c
rc4f7bf6 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 54 #include "client_conn.h" 55 #include "dev.h" 60 56 #include "devman.h" 57 #include "devtree.h" 58 #include "drv_conn.h" 59 #include "driver.h" 60 #include "fun.h" 61 #include "loc.h" 61 62 62 63 #define DRIVER_DEFAULT_STORE "/drv" 63 64 64 static driver_list_t drivers_list; 65 static dev_tree_t device_tree; 66 67 static int init_running_drv(void *drv); 68 69 /** Register running driver. */ 70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call) 71 { 72 driver_t *driver = NULL; 73 char *drv_name = NULL; 74 75 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register"); 76 77 /* Get driver name. */ 78 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0); 79 if (rc != EOK) { 80 async_answer_0(callid, rc); 81 return NULL; 82 } 83 84 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.", 85 drv_name); 86 87 /* Find driver structure. */ 88 driver = find_driver(&drivers_list, drv_name); 89 if (driver == NULL) { 90 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name); 91 free(drv_name); 92 drv_name = NULL; 93 async_answer_0(callid, ENOENT); 94 return NULL; 95 } 96 97 free(drv_name); 98 drv_name = NULL; 99 100 fibril_mutex_lock(&driver->driver_mutex); 101 102 if (driver->sess) { 103 /* We already have a connection to the driver. */ 104 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n", 105 driver->name); 106 fibril_mutex_unlock(&driver->driver_mutex); 107 async_answer_0(callid, EEXISTS); 108 return NULL; 109 } 110 111 switch (driver->state) { 112 case DRIVER_NOT_STARTED: 113 /* Somebody started the driver manually. */ 114 log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n", 115 driver->name); 116 driver->state = DRIVER_STARTING; 117 break; 118 case DRIVER_STARTING: 119 /* The expected case */ 120 break; 121 case DRIVER_RUNNING: 122 /* Should not happen since we do not have a connected session */ 123 assert(false); 124 } 125 126 /* Create connection to the driver. */ 127 log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.", 128 driver->name); 129 driver->sess = async_callback_receive(EXCHANGE_PARALLEL); 130 if (!driver->sess) { 131 fibril_mutex_unlock(&driver->driver_mutex); 132 async_answer_0(callid, ENOTSUP); 133 return NULL; 134 } 135 /* FIXME: Work around problem with callback sessions */ 136 async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0); 137 138 log_msg(LOG_DEFAULT, LVL_NOTE, 139 "The `%s' driver was successfully registered as running.", 140 driver->name); 141 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(LOG_DEFAULT, 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); 160 return driver; 161 } 162 163 /** Receive device match ID from the device's parent driver and add it to the 164 * list of devices match ids. 165 * 166 * @param match_ids The list of the device's match ids. 167 * @return Zero on success, negative error code otherwise. 168 */ 169 static int devman_receive_match_id(match_id_list_t *match_ids) 170 { 171 match_id_t *match_id = create_match_id(); 172 ipc_callid_t callid; 173 ipc_call_t call; 174 int rc = 0; 175 176 callid = async_get_call(&call); 177 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) { 178 log_msg(LOG_DEFAULT, LVL_ERROR, 179 "Invalid protocol when trying to receive match id."); 180 async_answer_0(callid, EINVAL); 181 delete_match_id(match_id); 182 return EINVAL; 183 } 184 185 if (match_id == NULL) { 186 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id."); 187 async_answer_0(callid, ENOMEM); 188 return ENOMEM; 189 } 190 191 async_answer_0(callid, EOK); 192 193 match_id->score = IPC_GET_ARG1(call); 194 195 char *match_id_str; 196 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0); 197 match_id->id = match_id_str; 198 if (rc != EOK) { 199 delete_match_id(match_id); 200 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.", 201 str_error(rc)); 202 return rc; 203 } 204 205 list_append(&match_id->link, &match_ids->ids); 206 207 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.", 208 match_id->id, match_id->score); 209 return rc; 210 } 211 212 /** Receive device match IDs from the device's parent driver and add them to the 213 * list of devices match ids. 214 * 215 * @param match_count The number of device's match ids to be received. 216 * @param match_ids The list of the device's match ids. 217 * @return Zero on success, negative error code otherwise. 218 */ 219 static int devman_receive_match_ids(sysarg_t match_count, 220 match_id_list_t *match_ids) 221 { 222 int ret = EOK; 223 size_t i; 224 225 for (i = 0; i < match_count; i++) { 226 if (EOK != (ret = devman_receive_match_id(match_ids))) 227 return ret; 228 } 229 return ret; 230 } 231 232 static int assign_driver_fibril(void *arg) 233 { 234 dev_node_t *dev_node = (dev_node_t *) arg; 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); 239 return EOK; 240 } 241 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(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.", 251 fun->pathname); 252 return EOK; 253 } 254 255 if (fun->ftype == fun_inner) { 256 dev = create_dev_node(); 257 if (dev == NULL) { 258 fibril_rwlock_write_unlock(&device_tree.rwlock); 259 return ENOMEM; 260 } 261 262 insert_dev_node(&device_tree, dev, fun); 263 dev_add_ref(dev); 264 } 265 266 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname); 267 268 if (fun->ftype == fun_inner) { 269 dev = fun->child; 270 assert(dev != NULL); 271 272 /* Give one reference over to assign_driver_fibril(). */ 273 dev_add_ref(dev); 274 275 /* 276 * Try to find a suitable driver and assign it to the device. We do 277 * not want to block the current fibril that is used for processing 278 * incoming calls: we will launch a separate fibril to handle the 279 * driver assigning. That is because assign_driver can actually include 280 * task spawning which could take some time. 281 */ 282 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev); 283 if (assign_fibril == 0) { 284 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for " 285 "assigning driver."); 286 /* XXX Cleanup */ 287 fibril_rwlock_write_unlock(&device_tree.rwlock); 288 return ENOMEM; 289 } 290 fibril_add_ready(assign_fibril); 291 } else 292 loc_register_tree_function(fun, &device_tree); 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(LOG_DEFAULT, 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(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.", 314 fun->pathname); 315 316 if (fun->child != NULL) { 317 dev_node_t *dev = fun->child; 318 device_state_t dev_state; 319 320 dev_add_ref(dev); 321 dev_state = dev->state; 322 323 fibril_rwlock_write_unlock(&device_tree.rwlock); 324 325 /* If device is owned by driver, ask driver to give it up. */ 326 if (dev_state == DEVICE_USABLE) { 327 rc = driver_dev_remove(&device_tree, dev); 328 if (rc != EOK) { 329 dev_del_ref(dev); 330 return ENOTSUP; 331 } 332 } 333 334 /* Verify that driver removed all functions */ 335 fibril_rwlock_read_lock(&device_tree.rwlock); 336 if (!list_empty(&dev->functions)) { 337 fibril_rwlock_read_unlock(&device_tree.rwlock); 338 dev_del_ref(dev); 339 return EIO; 340 } 341 342 driver_t *driver = dev->drv; 343 fibril_rwlock_read_unlock(&device_tree.rwlock); 344 345 if (driver) 346 detach_driver(&device_tree, dev); 347 348 fibril_rwlock_write_lock(&device_tree.rwlock); 349 remove_dev_node(&device_tree, dev); 350 351 /* Delete ref created when node was inserted */ 352 dev_del_ref(dev); 353 /* Delete ref created by dev_add_ref(dev) above */ 354 dev_del_ref(dev); 355 } 356 } else { 357 /* Unregister from location service */ 358 rc = loc_service_unregister(fun->service_id); 359 if (rc != EOK) { 360 fibril_rwlock_write_unlock(&device_tree.rwlock); 361 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service."); 362 return EIO; 363 } 364 365 fun->service_id = 0; 366 } 367 368 fun->state = FUN_OFF_LINE; 369 fibril_rwlock_write_unlock(&device_tree.rwlock); 370 371 return EOK; 372 } 373 374 /** Handle function registration. 375 * 376 * Child devices are registered by their parent's device driver. 377 */ 378 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call) 379 { 380 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call); 381 devman_handle_t dev_handle = IPC_GET_ARG2(*call); 382 sysarg_t match_count = IPC_GET_ARG3(*call); 383 dev_tree_t *tree = &device_tree; 384 385 dev_node_t *pdev = find_dev_node(&device_tree, dev_handle); 386 if (pdev == NULL) { 387 async_answer_0(callid, ENOENT); 388 return; 389 } 390 391 if (ftype != fun_inner && ftype != fun_exposed) { 392 /* Unknown function type */ 393 log_msg(LOG_DEFAULT, LVL_ERROR, 394 "Unknown function type %d provided by driver.", 395 (int) ftype); 396 397 dev_del_ref(pdev); 398 async_answer_0(callid, EINVAL); 399 return; 400 } 401 402 char *fun_name = NULL; 403 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0); 404 if (rc != EOK) { 405 dev_del_ref(pdev); 406 async_answer_0(callid, rc); 407 return; 408 } 409 410 fibril_rwlock_write_lock(&tree->rwlock); 411 412 /* Check device state */ 413 if (pdev->state == DEVICE_REMOVED) { 414 fibril_rwlock_write_unlock(&tree->rwlock); 415 dev_del_ref(pdev); 416 async_answer_0(callid, ENOENT); 417 return; 418 } 419 420 /* Check that function with same name is not there already. */ 421 fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name); 422 if (tfun) { 423 fun_del_ref(tfun); /* drop the new unwanted reference */ 424 fibril_rwlock_write_unlock(&tree->rwlock); 425 dev_del_ref(pdev); 426 async_answer_0(callid, EEXISTS); 427 printf(NAME ": Warning, driver tried to register `%s' twice.\n", 428 fun_name); 429 free(fun_name); 430 return; 431 } 432 433 fun_node_t *fun = create_fun_node(); 434 /* One reference for creation, one for us */ 435 fun_add_ref(fun); 436 fun_add_ref(fun); 437 fun->ftype = ftype; 438 439 /* 440 * We can lock the function here even when holding the tree because 441 * we know it cannot be held by anyone else yet. 442 */ 443 fun_busy_lock(fun); 444 445 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) { 446 fibril_rwlock_write_unlock(&tree->rwlock); 447 dev_del_ref(pdev); 448 fun_busy_unlock(fun); 449 fun_del_ref(fun); 450 delete_fun_node(fun); 451 async_answer_0(callid, ENOMEM); 452 return; 453 } 454 455 fibril_rwlock_write_unlock(&tree->rwlock); 456 dev_del_ref(pdev); 457 458 devman_receive_match_ids(match_count, &fun->match_ids); 459 460 rc = online_function(fun); 461 if (rc != EOK) { 462 /* XXX Set some failed state? */ 463 fun_busy_unlock(fun); 464 fun_del_ref(fun); 465 async_answer_0(callid, rc); 466 return; 467 } 468 469 fun_busy_unlock(fun); 470 fun_del_ref(fun); 471 472 /* Return device handle to parent's driver. */ 473 async_answer_1(callid, EOK, fun->handle); 474 } 475 476 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call) 477 { 478 devman_handle_t handle = IPC_GET_ARG1(*call); 479 category_id_t cat_id; 480 int rc; 481 482 /* Get category name. */ 483 char *cat_name; 484 rc = async_data_write_accept((void **) &cat_name, true, 485 0, 0, 0, 0); 486 if (rc != EOK) { 487 async_answer_0(callid, rc); 488 return; 489 } 490 491 fun_node_t *fun = find_fun_node(&device_tree, handle); 492 if (fun == NULL) { 493 async_answer_0(callid, ENOENT); 494 return; 495 } 496 497 fibril_rwlock_read_lock(&device_tree.rwlock); 498 499 /* Check function state */ 500 if (fun->state == FUN_REMOVED) { 501 fibril_rwlock_read_unlock(&device_tree.rwlock); 502 async_answer_0(callid, ENOENT); 503 return; 504 } 505 506 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING); 507 if (rc == EOK) { 508 loc_service_add_to_cat(fun->service_id, cat_id); 509 log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.", 510 fun->pathname, cat_name); 511 } else { 512 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category " 513 "`%s'.", fun->pathname, cat_name); 514 } 515 516 fibril_rwlock_read_unlock(&device_tree.rwlock); 517 fun_del_ref(fun); 518 519 async_answer_0(callid, rc); 520 } 521 522 /** Online function by driver request. 523 * 524 */ 525 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall, 526 driver_t *drv) 527 { 528 fun_node_t *fun; 529 int rc; 530 531 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()"); 532 533 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 534 if (fun == NULL) { 535 async_answer_0(iid, ENOENT); 536 return; 537 } 538 539 fun_busy_lock(fun); 540 541 fibril_rwlock_read_lock(&device_tree.rwlock); 542 if (fun->dev == NULL || fun->dev->drv != drv) { 543 fibril_rwlock_read_unlock(&device_tree.rwlock); 544 fun_busy_unlock(fun); 545 fun_del_ref(fun); 546 async_answer_0(iid, ENOENT); 547 return; 548 } 549 fibril_rwlock_read_unlock(&device_tree.rwlock); 550 551 rc = online_function(fun); 552 if (rc != EOK) { 553 fun_busy_unlock(fun); 554 fun_del_ref(fun); 555 async_answer_0(iid, (sysarg_t) rc); 556 return; 557 } 558 559 fun_busy_unlock(fun); 560 fun_del_ref(fun); 561 562 async_answer_0(iid, (sysarg_t) EOK); 563 } 564 565 566 /** Offline function by driver request. 567 * 568 */ 569 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall, 570 driver_t *drv) 571 { 572 fun_node_t *fun; 573 int rc; 574 575 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 576 if (fun == NULL) { 577 async_answer_0(iid, ENOENT); 578 return; 579 } 580 581 fun_busy_lock(fun); 582 583 fibril_rwlock_write_lock(&device_tree.rwlock); 584 if (fun->dev == NULL || fun->dev->drv != drv) { 585 fun_busy_unlock(fun); 586 fun_del_ref(fun); 587 async_answer_0(iid, ENOENT); 588 return; 589 } 590 fibril_rwlock_write_unlock(&device_tree.rwlock); 591 592 rc = offline_function(fun); 593 if (rc != EOK) { 594 fun_busy_unlock(fun); 595 fun_del_ref(fun); 596 async_answer_0(iid, (sysarg_t) rc); 597 return; 598 } 599 600 fun_busy_unlock(fun); 601 fun_del_ref(fun); 602 async_answer_0(iid, (sysarg_t) EOK); 603 } 604 605 /** Remove function. */ 606 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call) 607 { 608 devman_handle_t fun_handle = IPC_GET_ARG1(*call); 609 dev_tree_t *tree = &device_tree; 610 int rc; 611 612 fun_node_t *fun = find_fun_node(&device_tree, fun_handle); 613 if (fun == NULL) { 614 async_answer_0(callid, ENOENT); 615 return; 616 } 617 618 fun_busy_lock(fun); 619 620 fibril_rwlock_write_lock(&tree->rwlock); 621 622 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname); 623 624 /* Check function state */ 625 if (fun->state == FUN_REMOVED) { 626 fibril_rwlock_write_unlock(&tree->rwlock); 627 fun_busy_unlock(fun); 628 fun_del_ref(fun); 629 async_answer_0(callid, ENOENT); 630 return; 631 } 632 633 if (fun->ftype == fun_inner) { 634 /* This is a surprise removal. Handle possible descendants */ 635 if (fun->child != NULL) { 636 dev_node_t *dev = fun->child; 637 device_state_t dev_state; 638 int gone_rc; 639 640 dev_add_ref(dev); 641 dev_state = dev->state; 642 643 fibril_rwlock_write_unlock(&device_tree.rwlock); 644 645 /* If device is owned by driver, inform driver it is gone. */ 646 if (dev_state == DEVICE_USABLE) 647 gone_rc = driver_dev_gone(&device_tree, dev); 648 else 649 gone_rc = EOK; 650 651 fibril_rwlock_read_lock(&device_tree.rwlock); 652 653 /* Verify that driver succeeded and removed all functions */ 654 if (gone_rc != EOK || !list_empty(&dev->functions)) { 655 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove " 656 "functions for device that is gone. " 657 "Device node is now defunct."); 658 659 /* 660 * Not much we can do but mark the device 661 * node as having invalid state. This 662 * is a driver bug. 663 */ 664 dev->state = DEVICE_INVALID; 665 fibril_rwlock_read_unlock(&device_tree.rwlock); 666 dev_del_ref(dev); 667 if (gone_rc == EOK) 668 gone_rc = ENOTSUP; 669 fun_busy_unlock(fun); 670 fun_del_ref(fun); 671 async_answer_0(callid, gone_rc); 672 return; 673 } 674 675 driver_t *driver = dev->drv; 676 fibril_rwlock_read_unlock(&device_tree.rwlock); 677 678 if (driver) 679 detach_driver(&device_tree, dev); 680 681 fibril_rwlock_write_lock(&device_tree.rwlock); 682 remove_dev_node(&device_tree, dev); 683 684 /* Delete ref created when node was inserted */ 685 dev_del_ref(dev); 686 /* Delete ref created by dev_add_ref(dev) above */ 687 dev_del_ref(dev); 688 } 689 } else { 690 if (fun->service_id != 0) { 691 /* Unregister from location service */ 692 rc = loc_service_unregister(fun->service_id); 693 if (rc != EOK) { 694 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree " 695 "service."); 696 fibril_rwlock_write_unlock(&tree->rwlock); 697 fun_busy_unlock(fun); 698 fun_del_ref(fun); 699 async_answer_0(callid, EIO); 700 return; 701 } 702 } 703 } 704 705 remove_fun_node(&device_tree, fun); 706 fibril_rwlock_write_unlock(&tree->rwlock); 707 fun_busy_unlock(fun); 708 709 /* Delete ref added when inserting function into tree */ 710 fun_del_ref(fun); 711 /* Delete ref added above when looking up function */ 712 fun_del_ref(fun); 713 714 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded."); 715 async_answer_0(callid, EOK); 716 } 717 718 /** Initialize driver which has registered itself as running and ready. 719 * 720 * The initialization is done in a separate fibril to avoid deadlocks (if the 721 * driver needed to be served by devman during the driver's initialization). 722 */ 723 static int init_running_drv(void *drv) 724 { 725 driver_t *driver = (driver_t *) drv; 726 727 initialize_running_driver(driver, &device_tree); 728 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.", 729 driver->name); 730 return 0; 731 } 732 733 /** Function for handling connections from a driver to the device manager. */ 734 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall) 735 { 736 client_t *client; 737 driver_t *driver = NULL; 738 739 /* Accept the connection. */ 740 async_answer_0(iid, EOK); 741 742 client = async_get_client_data(); 743 if (client == NULL) { 744 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data."); 745 return; 746 } 747 748 while (true) { 749 ipc_call_t call; 750 ipc_callid_t callid = async_get_call(&call); 751 752 if (!IPC_GET_IMETHOD(call)) 753 break; 754 755 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) { 756 fibril_mutex_lock(&client->mutex); 757 driver = client->driver; 758 fibril_mutex_unlock(&client->mutex); 759 if (driver == NULL) { 760 /* First call must be to DEVMAN_DRIVER_REGISTER */ 761 async_answer_0(callid, ENOTSUP); 762 continue; 763 } 764 } 765 766 switch (IPC_GET_IMETHOD(call)) { 767 case DEVMAN_DRIVER_REGISTER: 768 fibril_mutex_lock(&client->mutex); 769 if (client->driver != NULL) { 770 fibril_mutex_unlock(&client->mutex); 771 async_answer_0(callid, EINVAL); 772 continue; 773 } 774 client->driver = devman_driver_register(callid, &call); 775 fibril_mutex_unlock(&client->mutex); 776 break; 777 case DEVMAN_ADD_FUNCTION: 778 devman_add_function(callid, &call); 779 break; 780 case DEVMAN_ADD_DEVICE_TO_CATEGORY: 781 devman_add_function_to_cat(callid, &call); 782 break; 783 case DEVMAN_DRV_FUN_ONLINE: 784 devman_drv_fun_online(callid, &call, driver); 785 break; 786 case DEVMAN_DRV_FUN_OFFLINE: 787 devman_drv_fun_offline(callid, &call, driver); 788 break; 789 case DEVMAN_REMOVE_FUNCTION: 790 devman_remove_function(callid, &call); 791 break; 792 default: 793 async_answer_0(callid, EINVAL); 794 break; 795 } 796 } 797 } 798 799 /** Find handle for the device instance identified by the device's path in the 800 * device tree. */ 801 static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall) 802 { 803 char *pathname; 804 devman_handle_t handle; 805 806 int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0); 807 if (rc != EOK) { 808 async_answer_0(iid, rc); 809 return; 810 } 811 812 fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname); 813 814 free(pathname); 815 816 if (fun == NULL) { 817 async_answer_0(iid, ENOENT); 818 return; 819 } 820 821 fibril_rwlock_read_lock(&device_tree.rwlock); 822 823 /* Check function state */ 824 if (fun->state == FUN_REMOVED) { 825 fibril_rwlock_read_unlock(&device_tree.rwlock); 826 async_answer_0(iid, ENOENT); 827 return; 828 } 829 handle = fun->handle; 830 831 fibril_rwlock_read_unlock(&device_tree.rwlock); 832 833 /* Delete reference created above by find_fun_node_by_path() */ 834 fun_del_ref(fun); 835 836 async_answer_1(iid, EOK, handle); 837 } 838 839 /** Get device name. */ 840 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall) 841 { 842 devman_handle_t handle = IPC_GET_ARG1(*icall); 843 844 fun_node_t *fun = find_fun_node(&device_tree, handle); 845 if (fun == NULL) { 846 async_answer_0(iid, ENOMEM); 847 return; 848 } 849 850 ipc_callid_t data_callid; 851 size_t data_len; 852 if (!async_data_read_receive(&data_callid, &data_len)) { 853 async_answer_0(iid, EINVAL); 854 fun_del_ref(fun); 855 return; 856 } 857 858 void *buffer = malloc(data_len); 859 if (buffer == NULL) { 860 async_answer_0(data_callid, ENOMEM); 861 async_answer_0(iid, ENOMEM); 862 fun_del_ref(fun); 863 return; 864 } 865 866 fibril_rwlock_read_lock(&device_tree.rwlock); 867 868 /* Check function state */ 869 if (fun->state == FUN_REMOVED) { 870 fibril_rwlock_read_unlock(&device_tree.rwlock); 871 free(buffer); 872 873 async_answer_0(data_callid, ENOENT); 874 async_answer_0(iid, ENOENT); 875 fun_del_ref(fun); 876 return; 877 } 878 879 size_t sent_length = str_size(fun->name); 880 if (sent_length > data_len) { 881 sent_length = data_len; 882 } 883 884 async_data_read_finalize(data_callid, fun->name, sent_length); 885 async_answer_0(iid, EOK); 886 887 fibril_rwlock_read_unlock(&device_tree.rwlock); 888 fun_del_ref(fun); 889 free(buffer); 890 } 891 892 /** Get function driver name. */ 893 static void devman_fun_get_driver_name(ipc_callid_t iid, ipc_call_t *icall) 894 { 895 devman_handle_t handle = IPC_GET_ARG1(*icall); 896 897 fun_node_t *fun = find_fun_node(&device_tree, handle); 898 if (fun == NULL) { 899 async_answer_0(iid, ENOMEM); 900 return; 901 } 902 903 ipc_callid_t data_callid; 904 size_t data_len; 905 if (!async_data_read_receive(&data_callid, &data_len)) { 906 async_answer_0(iid, EINVAL); 907 fun_del_ref(fun); 908 return; 909 } 910 911 void *buffer = malloc(data_len); 912 if (buffer == NULL) { 913 async_answer_0(data_callid, ENOMEM); 914 async_answer_0(iid, ENOMEM); 915 fun_del_ref(fun); 916 return; 917 } 918 919 fibril_rwlock_read_lock(&device_tree.rwlock); 920 921 /* Check function state */ 922 if (fun->state == FUN_REMOVED) { 923 fibril_rwlock_read_unlock(&device_tree.rwlock); 924 free(buffer); 925 926 async_answer_0(data_callid, ENOENT); 927 async_answer_0(iid, ENOENT); 928 fun_del_ref(fun); 929 return; 930 } 931 932 /* Check whether function has a driver */ 933 if (fun->child == NULL || fun->child->drv == NULL) { 934 fibril_rwlock_read_unlock(&device_tree.rwlock); 935 free(buffer); 936 937 async_answer_0(data_callid, EINVAL); 938 async_answer_0(iid, EINVAL); 939 fun_del_ref(fun); 940 return; 941 } 942 943 size_t sent_length = str_size(fun->child->drv->name); 944 if (sent_length > data_len) { 945 sent_length = data_len; 946 } 947 948 async_data_read_finalize(data_callid, fun->child->drv->name, 949 sent_length); 950 async_answer_0(iid, EOK); 951 952 fibril_rwlock_read_unlock(&device_tree.rwlock); 953 fun_del_ref(fun); 954 free(buffer); 955 } 956 957 /** Get device path. */ 958 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall) 959 { 960 devman_handle_t handle = IPC_GET_ARG1(*icall); 961 962 fun_node_t *fun = find_fun_node(&device_tree, handle); 963 if (fun == NULL) { 964 async_answer_0(iid, ENOMEM); 965 return; 966 } 967 968 ipc_callid_t data_callid; 969 size_t data_len; 970 if (!async_data_read_receive(&data_callid, &data_len)) { 971 async_answer_0(iid, EINVAL); 972 fun_del_ref(fun); 973 return; 974 } 975 976 void *buffer = malloc(data_len); 977 if (buffer == NULL) { 978 async_answer_0(data_callid, ENOMEM); 979 async_answer_0(iid, ENOMEM); 980 fun_del_ref(fun); 981 return; 982 } 983 984 fibril_rwlock_read_lock(&device_tree.rwlock); 985 986 /* Check function state */ 987 if (fun->state == FUN_REMOVED) { 988 fibril_rwlock_read_unlock(&device_tree.rwlock); 989 free(buffer); 990 991 async_answer_0(data_callid, ENOENT); 992 async_answer_0(iid, ENOENT); 993 fun_del_ref(fun); 994 return; 995 } 996 997 size_t sent_length = str_size(fun->pathname); 998 if (sent_length > data_len) { 999 sent_length = data_len; 1000 } 1001 1002 async_data_read_finalize(data_callid, fun->pathname, sent_length); 1003 async_answer_0(iid, EOK); 1004 1005 fibril_rwlock_read_unlock(&device_tree.rwlock); 1006 fun_del_ref(fun); 1007 free(buffer); 1008 } 1009 1010 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall) 1011 { 1012 ipc_callid_t callid; 1013 size_t size; 1014 size_t act_size; 1015 int rc; 1016 1017 if (!async_data_read_receive(&callid, &size)) { 1018 async_answer_0(callid, EREFUSED); 1019 async_answer_0(iid, EREFUSED); 1020 return; 1021 } 1022 1023 fibril_rwlock_read_lock(&device_tree.rwlock); 1024 1025 dev_node_t *dev = find_dev_node_no_lock(&device_tree, 1026 IPC_GET_ARG1(*icall)); 1027 if (dev == NULL || dev->state == DEVICE_REMOVED) { 1028 fibril_rwlock_read_unlock(&device_tree.rwlock); 1029 async_answer_0(callid, ENOENT); 1030 async_answer_0(iid, ENOENT); 1031 return; 1032 } 1033 1034 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size); 1035 if (hdl_buf == NULL) { 1036 fibril_rwlock_read_unlock(&device_tree.rwlock); 1037 async_answer_0(callid, ENOMEM); 1038 async_answer_0(iid, ENOMEM); 1039 return; 1040 } 1041 1042 rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size); 1043 if (rc != EOK) { 1044 fibril_rwlock_read_unlock(&device_tree.rwlock); 1045 async_answer_0(callid, rc); 1046 async_answer_0(iid, rc); 1047 return; 1048 } 1049 1050 fibril_rwlock_read_unlock(&device_tree.rwlock); 1051 1052 sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size); 1053 free(hdl_buf); 1054 1055 async_answer_1(iid, retval, act_size); 1056 } 1057 1058 1059 /** Get handle for child device of a function. */ 1060 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall) 1061 { 1062 fun_node_t *fun; 1063 1064 fibril_rwlock_read_lock(&device_tree.rwlock); 1065 1066 fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall)); 1067 if (fun == NULL || fun->state == FUN_REMOVED) { 1068 fibril_rwlock_read_unlock(&device_tree.rwlock); 1069 async_answer_0(iid, ENOENT); 1070 return; 1071 } 1072 1073 if (fun->child == NULL) { 1074 fibril_rwlock_read_unlock(&device_tree.rwlock); 1075 async_answer_0(iid, ENOENT); 1076 return; 1077 } 1078 1079 async_answer_1(iid, EOK, fun->child->handle); 1080 1081 fibril_rwlock_read_unlock(&device_tree.rwlock); 1082 } 1083 1084 /** Online function. 1085 * 1086 * Send a request to online a function to the responsible driver. 1087 * The driver may offline other functions if necessary (i.e. if the state 1088 * of this function is linked to state of another function somehow). 1089 */ 1090 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall) 1091 { 1092 fun_node_t *fun; 1093 int rc; 1094 1095 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 1096 if (fun == NULL) { 1097 async_answer_0(iid, ENOENT); 1098 return; 1099 } 1100 1101 rc = driver_fun_online(&device_tree, fun); 1102 fun_del_ref(fun); 1103 1104 async_answer_0(iid, (sysarg_t) rc); 1105 } 1106 1107 /** Offline function. 1108 * 1109 * Send a request to offline a function to the responsible driver. As 1110 * a result the subtree rooted at that function should be cleanly 1111 * detatched. The driver may offline other functions if necessary 1112 * (i.e. if the state of this function is linked to state of another 1113 * function somehow). 1114 */ 1115 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 1116 { 1117 fun_node_t *fun; 1118 int rc; 1119 1120 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 1121 if (fun == NULL) { 1122 async_answer_0(iid, ENOENT); 1123 return; 1124 } 1125 1126 rc = driver_fun_offline(&device_tree, fun); 1127 fun_del_ref(fun); 1128 1129 async_answer_0(iid, (sysarg_t) rc); 1130 } 1131 1132 /** Find handle for the function instance identified by its service ID. */ 1133 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall) 1134 { 1135 fun_node_t *fun; 1136 1137 fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall)); 1138 1139 if (fun == NULL) { 1140 async_answer_0(iid, ENOENT); 1141 return; 1142 } 1143 1144 fibril_rwlock_read_lock(&device_tree.rwlock); 1145 1146 /* Check function state */ 1147 if (fun->state == FUN_REMOVED) { 1148 fibril_rwlock_read_unlock(&device_tree.rwlock); 1149 async_answer_0(iid, ENOENT); 1150 return; 1151 } 1152 1153 async_answer_1(iid, EOK, fun->handle); 1154 fibril_rwlock_read_unlock(&device_tree.rwlock); 1155 fun_del_ref(fun); 1156 } 1157 1158 /** Function for handling connections from a client to the device manager. */ 1159 static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall) 1160 { 1161 /* Accept connection. */ 1162 async_answer_0(iid, EOK); 1163 1164 while (true) { 1165 ipc_call_t call; 1166 ipc_callid_t callid = async_get_call(&call); 1167 1168 if (!IPC_GET_IMETHOD(call)) 1169 break; 1170 1171 switch (IPC_GET_IMETHOD(call)) { 1172 case DEVMAN_DEVICE_GET_HANDLE: 1173 devman_function_get_handle(callid, &call); 1174 break; 1175 case DEVMAN_DEV_GET_FUNCTIONS: 1176 devman_dev_get_functions(callid, &call); 1177 break; 1178 case DEVMAN_FUN_GET_CHILD: 1179 devman_fun_get_child(callid, &call); 1180 break; 1181 case DEVMAN_FUN_GET_NAME: 1182 devman_fun_get_name(callid, &call); 1183 break; 1184 case DEVMAN_FUN_GET_DRIVER_NAME: 1185 devman_fun_get_driver_name(callid, &call); 1186 break; 1187 case DEVMAN_FUN_GET_PATH: 1188 devman_fun_get_path(callid, &call); 1189 break; 1190 case DEVMAN_FUN_ONLINE: 1191 devman_fun_online(callid, &call); 1192 break; 1193 case DEVMAN_FUN_OFFLINE: 1194 devman_fun_offline(callid, &call); 1195 break; 1196 case DEVMAN_FUN_SID_TO_HANDLE: 1197 devman_fun_sid_to_handle(callid, &call); 1198 break; 1199 default: 1200 async_answer_0(callid, ENOENT); 1201 } 1202 } 1203 } 65 driver_list_t drivers_list; 66 dev_tree_t device_tree; 1204 67 1205 68 static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
Note:
See TracChangeset
for help on using the changeset viewer.