Changeset 925a21e in mainline for uspace/srv/devman/main.c
- Timestamp:
- 2011-09-24T14:20:29Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5bf76c1
- Parents:
- 867e2555 (diff), 1ab4aca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/main.c
r867e2555 r925a21e 56 56 #include <ipc/driver.h> 57 57 #include <thread.h> 58 #include < devmap.h>58 #include <loc.h> 59 59 60 60 #include "devman.h" … … 64 64 static driver_list_t drivers_list; 65 65 static dev_tree_t device_tree; 66 static class_list_t class_list; 66 67 static int init_running_drv(void *drv); 67 68 68 69 /** Register running driver. */ 69 static driver_t *devman_driver_register(void) 70 { 71 ipc_call_t icall; 72 ipc_callid_t iid; 70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call) 71 { 73 72 driver_t *driver = NULL; 73 char *drv_name = NULL; 74 74 75 75 log_msg(LVL_DEBUG, "devman_driver_register"); 76 77 iid = async_get_call(&icall);78 if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {79 async_answer_0(iid, EREFUSED);80 return NULL;81 }82 83 char *drv_name = NULL;84 76 85 77 /* Get driver name. */ 86 78 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0); 87 79 if (rc != EOK) { 88 async_answer_0( iid, rc);80 async_answer_0(callid, rc); 89 81 return NULL; 90 82 } … … 99 91 free(drv_name); 100 92 drv_name = NULL; 101 async_answer_0( iid, ENOENT);93 async_answer_0(callid, ENOENT); 102 94 return NULL; 103 95 } … … 113 105 driver->name); 114 106 fibril_mutex_unlock(&driver->driver_mutex); 115 async_answer_0( iid, EEXISTS);107 async_answer_0(callid, EEXISTS); 116 108 return NULL; 117 109 } … … 135 127 log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.", 136 128 driver->name); 137 driver->sess = async_callback_receive(EXCHANGE_ SERIALIZE);129 driver->sess = async_callback_receive(EXCHANGE_PARALLEL); 138 130 if (!driver->sess) { 139 131 fibril_mutex_unlock(&driver->driver_mutex); 140 async_answer_0( iid, ENOTSUP);132 async_answer_0(callid, ENOTSUP); 141 133 return NULL; 142 134 } 143 144 fibril_mutex_unlock(&driver->driver_mutex);135 /* FIXME: Work around problem with callback sessions */ 136 async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0); 145 137 146 138 log_msg(LVL_NOTE, … … 148 140 driver->name); 149 141 150 async_answer_0(iid, EOK); 151 142 /* 143 * Initialize the driver as running (e.g. pass assigned devices to it) 144 * in a separate fibril; the separate fibril is used to enable the 145 * driver to use devman service during the driver's initialization. 146 */ 147 fid_t fid = fibril_create(init_running_drv, driver); 148 if (fid == 0) { 149 log_msg(LVL_ERROR, "Failed to create initialization fibril " \ 150 "for driver `%s'.", driver->name); 151 fibril_mutex_unlock(&driver->driver_mutex); 152 async_answer_0(callid, ENOMEM); 153 return NULL; 154 } 155 156 fibril_add_ready(fid); 157 fibril_mutex_unlock(&driver->driver_mutex); 158 159 async_answer_0(callid, EOK); 152 160 return driver; 153 161 } … … 226 234 dev_node_t *dev_node = (dev_node_t *) arg; 227 235 assign_driver(dev_node, &drivers_list, &device_tree); 236 237 /* Delete one reference we got from the caller. */ 238 dev_del_ref(dev_node); 228 239 return EOK; 229 240 } 230 241 231 /** Handle function registration. 232 * 233 * Child devices are registered by their parent's device driver. 234 */ 235 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call) 236 { 237 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call); 238 devman_handle_t dev_handle = IPC_GET_ARG2(*call); 239 sysarg_t match_count = IPC_GET_ARG3(*call); 240 dev_tree_t *tree = &device_tree; 241 242 fibril_rwlock_write_lock(&tree->rwlock); 243 244 dev_node_t *dev = NULL; 245 dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle); 246 247 if (pdev == NULL) { 248 fibril_rwlock_write_unlock(&tree->rwlock); 249 async_answer_0(callid, ENOENT); 250 return; 251 } 252 253 if (ftype != fun_inner && ftype != fun_exposed) { 254 /* Unknown function type */ 255 log_msg(LVL_ERROR, 256 "Unknown function type %d provided by driver.", 257 (int) ftype); 258 259 fibril_rwlock_write_unlock(&tree->rwlock); 260 async_answer_0(callid, EINVAL); 261 return; 262 } 263 264 char *fun_name = NULL; 265 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0); 266 if (rc != EOK) { 267 fibril_rwlock_write_unlock(&tree->rwlock); 268 async_answer_0(callid, rc); 269 return; 270 } 271 272 /* Check that function with same name is not there already. */ 273 if (find_fun_node_in_device(pdev, fun_name) != NULL) { 274 fibril_rwlock_write_unlock(&tree->rwlock); 275 async_answer_0(callid, EEXISTS); 276 printf(NAME ": Warning, driver tried to register `%s' twice.\n", 277 fun_name); 278 free(fun_name); 279 return; 280 } 281 282 fun_node_t *fun = create_fun_node(); 283 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) { 284 fibril_rwlock_write_unlock(&tree->rwlock); 285 delete_fun_node(fun); 286 async_answer_0(callid, ENOMEM); 287 return; 288 } 289 290 if (ftype == fun_inner) { 242 static int online_function(fun_node_t *fun) 243 { 244 dev_node_t *dev; 245 246 fibril_rwlock_write_lock(&device_tree.rwlock); 247 248 if (fun->state == FUN_ON_LINE) { 249 fibril_rwlock_write_unlock(&device_tree.rwlock); 250 log_msg(LVL_WARN, "Function %s is already on line.", 251 fun->pathname); 252 return EOK; 253 } 254 255 if (fun->ftype == fun_inner) { 291 256 dev = create_dev_node(); 292 257 if (dev == NULL) { 293 fibril_rwlock_write_unlock(&tree->rwlock); 294 delete_fun_node(fun); 295 async_answer_0(callid, ENOMEM); 296 return; 258 fibril_rwlock_write_unlock(&device_tree.rwlock); 259 return ENOMEM; 297 260 } 298 261 299 insert_dev_node(tree, dev, fun); 300 } 301 302 fibril_rwlock_write_unlock(&tree->rwlock); 262 insert_dev_node(&device_tree, dev, fun); 263 dev_add_ref(dev); 264 } 303 265 304 266 log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname); 305 267 306 devman_receive_match_ids(match_count, &fun->match_ids); 307 308 if (ftype == fun_inner) { 268 if (fun->ftype == fun_inner) { 269 dev = fun->child; 309 270 assert(dev != NULL); 271 272 /* Give one reference over to assign_driver_fibril(). */ 273 dev_add_ref(dev); 310 274 /* 311 275 * Try to find a suitable driver and assign it to the device. We do … … 317 281 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev); 318 282 if (assign_fibril == 0) { 319 /* 320 * Fallback in case we are out of memory. 321 * Probably not needed as we will die soon anyway ;-). 322 */ 323 (void) assign_driver_fibril(fun); 324 } else { 325 fibril_add_ready(assign_fibril); 283 log_msg(LVL_ERROR, "Failed to create fibril for " 284 "assigning driver."); 285 /* XXX Cleanup */ 286 fibril_rwlock_write_unlock(&device_tree.rwlock); 287 return ENOMEM; 288 } 289 fibril_add_ready(assign_fibril); 290 } else { 291 loc_register_tree_function(fun, &device_tree); 292 } 293 294 fibril_rwlock_write_unlock(&device_tree.rwlock); 295 296 return EOK; 297 } 298 299 static int offline_function(fun_node_t *fun) 300 { 301 int rc; 302 303 fibril_rwlock_write_lock(&device_tree.rwlock); 304 305 if (fun->state == FUN_OFF_LINE) { 306 fibril_rwlock_write_unlock(&device_tree.rwlock); 307 log_msg(LVL_WARN, "Function %s is already off line.", 308 fun->pathname); 309 return EOK; 310 } 311 312 if (fun->ftype == fun_inner) { 313 log_msg(LVL_DEBUG, "Offlining inner function %s.", 314 fun->pathname); 315 316 if (fun->child != NULL) { 317 dev_node_t *dev = fun->child; 318 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); 326 355 } 327 356 } else { 328 devmap_register_tree_function(fun, tree); 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(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(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 if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) { 422 fibril_rwlock_write_unlock(&tree->rwlock); 423 dev_del_ref(pdev); 424 async_answer_0(callid, EEXISTS); 425 printf(NAME ": Warning, driver tried to register `%s' twice.\n", 426 fun_name); 427 free(fun_name); 428 return; 429 } 430 431 fun_node_t *fun = create_fun_node(); 432 fun_add_ref(fun); 433 fun->ftype = ftype; 434 435 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) { 436 fibril_rwlock_write_unlock(&tree->rwlock); 437 dev_del_ref(pdev); 438 delete_fun_node(fun); 439 async_answer_0(callid, ENOMEM); 440 return; 441 } 442 443 fibril_rwlock_write_unlock(&tree->rwlock); 444 dev_del_ref(pdev); 445 446 devman_receive_match_ids(match_count, &fun->match_ids); 447 448 rc = online_function(fun); 449 if (rc != EOK) { 450 /* XXX clean up */ 451 async_answer_0(callid, rc); 452 return; 329 453 } 330 454 … … 333 457 } 334 458 335 static void devmap_register_class_dev(dev_class_info_t *cli) 336 { 337 /* Create devmap path and name for the device. */ 338 char *devmap_pathname = NULL; 339 340 asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE, 341 cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name); 342 if (devmap_pathname == NULL) 343 return; 344 345 /* 346 * Register the device by the device mapper and remember its devmap 347 * handle. 348 */ 349 devmap_device_register_with_iface(devmap_pathname, 350 &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP); 351 352 /* 353 * Add device to the hash map of class devices registered by device 354 * mapper. 355 */ 356 class_add_devmap_function(&class_list, cli); 357 358 free(devmap_pathname); 359 } 360 361 static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call) 459 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call) 362 460 { 363 461 devman_handle_t handle = IPC_GET_ARG1(*call); 364 365 /* Get class name. */ 366 char *class_name; 367 int rc = async_data_write_accept((void **) &class_name, true, 462 category_id_t cat_id; 463 int rc; 464 465 /* Get category name. */ 466 char *cat_name; 467 rc = async_data_write_accept((void **) &cat_name, true, 368 468 0, 0, 0, 0); 369 469 if (rc != EOK) { 370 470 async_answer_0(callid, rc); 371 471 return; 372 } 472 } 373 473 374 474 fun_node_t *fun = find_fun_node(&device_tree, handle); … … 378 478 } 379 479 380 dev_class_t *cl = get_dev_class(&class_list, class_name); 381 dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL); 382 383 /* Register the device's class alias by devmapper. */ 384 devmap_register_class_dev(class_info); 385 386 log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.", 387 fun->pathname, class_name, class_info->dev_name); 388 480 fibril_rwlock_read_lock(&device_tree.rwlock); 481 482 /* Check function state */ 483 if (fun->state == FUN_REMOVED) { 484 fibril_rwlock_read_unlock(&device_tree.rwlock); 485 async_answer_0(callid, ENOENT); 486 return; 487 } 488 489 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING); 490 if (rc == EOK) { 491 loc_service_add_to_cat(fun->service_id, cat_id); 492 log_msg(LVL_NOTE, "Function `%s' added to category `%s'.", 493 fun->pathname, cat_name); 494 } else { 495 log_msg(LVL_ERROR, "Failed adding function `%s' to category " 496 "`%s'.", fun->pathname, cat_name); 497 } 498 499 fibril_rwlock_read_unlock(&device_tree.rwlock); 500 fun_del_ref(fun); 501 502 async_answer_0(callid, rc); 503 } 504 505 /** Online function by driver request. 506 * 507 */ 508 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall, 509 driver_t *drv) 510 { 511 fun_node_t *fun; 512 int rc; 513 514 log_msg(LVL_DEBUG, "devman_drv_fun_online()"); 515 516 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 517 if (fun == NULL) { 518 async_answer_0(iid, ENOENT); 519 return; 520 } 521 522 fibril_rwlock_read_lock(&device_tree.rwlock); 523 if (fun->dev == NULL || fun->dev->drv != drv) { 524 fibril_rwlock_read_unlock(&device_tree.rwlock); 525 fun_del_ref(fun); 526 async_answer_0(iid, ENOENT); 527 return; 528 } 529 fibril_rwlock_read_unlock(&device_tree.rwlock); 530 531 rc = online_function(fun); 532 if (rc != EOK) { 533 fun_del_ref(fun); 534 async_answer_0(iid, (sysarg_t) rc); 535 return; 536 } 537 538 fun_del_ref(fun); 539 540 async_answer_0(iid, (sysarg_t) EOK); 541 } 542 543 544 /** Offline function by driver request. 545 * 546 */ 547 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall, 548 driver_t *drv) 549 { 550 fun_node_t *fun; 551 int rc; 552 553 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 554 if (fun == NULL) { 555 async_answer_0(iid, ENOENT); 556 return; 557 } 558 559 fibril_rwlock_write_lock(&device_tree.rwlock); 560 if (fun->dev == NULL || fun->dev->drv != drv) { 561 fun_del_ref(fun); 562 async_answer_0(iid, ENOENT); 563 return; 564 } 565 fibril_rwlock_write_unlock(&device_tree.rwlock); 566 567 rc = offline_function(fun); 568 if (rc != EOK) { 569 fun_del_ref(fun); 570 async_answer_0(iid, (sysarg_t) rc); 571 return; 572 } 573 574 fun_del_ref(fun); 575 async_answer_0(iid, (sysarg_t) EOK); 576 } 577 578 /** Remove function. */ 579 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call) 580 { 581 devman_handle_t fun_handle = IPC_GET_ARG1(*call); 582 dev_tree_t *tree = &device_tree; 583 int rc; 584 585 fun_node_t *fun = find_fun_node(&device_tree, fun_handle); 586 if (fun == NULL) { 587 async_answer_0(callid, ENOENT); 588 return; 589 } 590 591 fibril_rwlock_write_lock(&tree->rwlock); 592 593 log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname); 594 595 /* Check function state */ 596 if (fun->state == FUN_REMOVED) { 597 fibril_rwlock_write_unlock(&tree->rwlock); 598 async_answer_0(callid, ENOENT); 599 return; 600 } 601 602 if (fun->ftype == fun_inner) { 603 /* This is a surprise removal. Handle possible descendants */ 604 if (fun->child != NULL) { 605 dev_node_t *dev = fun->child; 606 device_state_t dev_state; 607 int gone_rc; 608 609 dev_add_ref(dev); 610 dev_state = dev->state; 611 612 fibril_rwlock_write_unlock(&device_tree.rwlock); 613 614 /* If device is owned by driver, inform driver it is gone. */ 615 if (dev_state == DEVICE_USABLE) 616 gone_rc = driver_dev_gone(&device_tree, dev); 617 else 618 gone_rc = EOK; 619 620 fibril_rwlock_read_lock(&device_tree.rwlock); 621 622 /* Verify that driver succeeded and removed all functions */ 623 if (gone_rc != EOK || !list_empty(&dev->functions)) { 624 log_msg(LVL_ERROR, "Driver did not remove " 625 "functions for device that is gone. " 626 "Device node is now defunct."); 627 628 /* 629 * Not much we can do but mark the device 630 * node as having invalid state. This 631 * is a driver bug. 632 */ 633 dev->state = DEVICE_INVALID; 634 fibril_rwlock_read_unlock(&device_tree.rwlock); 635 dev_del_ref(dev); 636 return; 637 } 638 639 driver_t *driver = dev->drv; 640 fibril_rwlock_read_unlock(&device_tree.rwlock); 641 642 if (driver) 643 detach_driver(&device_tree, dev); 644 645 fibril_rwlock_write_lock(&device_tree.rwlock); 646 remove_dev_node(&device_tree, dev); 647 648 /* Delete ref created when node was inserted */ 649 dev_del_ref(dev); 650 /* Delete ref created by dev_add_ref(dev) above */ 651 dev_del_ref(dev); 652 } 653 } else { 654 if (fun->service_id != 0) { 655 /* Unregister from location service */ 656 rc = loc_service_unregister(fun->service_id); 657 if (rc != EOK) { 658 log_msg(LVL_ERROR, "Failed unregistering tree " 659 "service."); 660 fibril_rwlock_write_unlock(&tree->rwlock); 661 fun_del_ref(fun); 662 async_answer_0(callid, EIO); 663 return; 664 } 665 } 666 } 667 668 remove_fun_node(&device_tree, fun); 669 fibril_rwlock_write_unlock(&tree->rwlock); 670 671 /* Delete ref added when inserting function into tree */ 672 fun_del_ref(fun); 673 /* Delete ref added above when looking up function */ 674 fun_del_ref(fun); 675 676 log_msg(LVL_DEBUG, "devman_remove_function() succeeded."); 389 677 async_answer_0(callid, EOK); 390 678 } … … 408 696 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall) 409 697 { 698 client_t *client; 699 driver_t *driver; 700 410 701 /* Accept the connection. */ 411 702 async_answer_0(iid, EOK); 412 703 413 driver_t *driver = devman_driver_register(); 414 if (driver == NULL) 415 return; 416 417 /* 418 * Initialize the driver as running (e.g. pass assigned devices to it) 419 * in a separate fibril; the separate fibril is used to enable the 420 * driver to use devman service during the driver's initialization. 421 */ 422 fid_t fid = fibril_create(init_running_drv, driver); 423 if (fid == 0) { 424 log_msg(LVL_ERROR, "Failed to create initialization fibril " \ 425 "for driver `%s'.", driver->name); 426 return; 427 } 428 fibril_add_ready(fid); 704 client = async_get_client_data(); 705 if (client == NULL) { 706 log_msg(LVL_ERROR, "Failed to allocate client data."); 707 return; 708 } 429 709 430 710 while (true) { … … 435 715 break; 436 716 717 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) { 718 fibril_mutex_lock(&client->mutex); 719 driver = client->driver; 720 fibril_mutex_unlock(&client->mutex); 721 if (driver == NULL) { 722 /* First call must be to DEVMAN_DRIVER_REGISTER */ 723 async_answer_0(callid, ENOTSUP); 724 continue; 725 } 726 } 727 437 728 switch (IPC_GET_IMETHOD(call)) { 729 case DEVMAN_DRIVER_REGISTER: 730 fibril_mutex_lock(&client->mutex); 731 if (client->driver != NULL) { 732 fibril_mutex_unlock(&client->mutex); 733 async_answer_0(callid, EINVAL); 734 continue; 735 } 736 client->driver = devman_driver_register(callid, &call); 737 fibril_mutex_unlock(&client->mutex); 738 break; 438 739 case DEVMAN_ADD_FUNCTION: 439 740 devman_add_function(callid, &call); 440 741 break; 441 case DEVMAN_ADD_DEVICE_TO_CLASS: 442 devman_add_function_to_class(callid, &call); 742 case DEVMAN_ADD_DEVICE_TO_CATEGORY: 743 devman_add_function_to_cat(callid, &call); 744 break; 745 case DEVMAN_DRV_FUN_ONLINE: 746 devman_drv_fun_online(callid, &call, driver); 747 break; 748 case DEVMAN_DRV_FUN_OFFLINE: 749 devman_drv_fun_offline(callid, &call, driver); 750 break; 751 case DEVMAN_REMOVE_FUNCTION: 752 devman_remove_function(callid, &call); 443 753 break; 444 754 default: 445 async_answer_0(callid, EINVAL); 755 async_answer_0(callid, EINVAL); 446 756 break; 447 757 } … … 454 764 { 455 765 char *pathname; 766 devman_handle_t handle; 456 767 457 768 int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0); … … 470 781 } 471 782 472 async_answer_1(iid, EOK, fun->handle); 473 } 474 475 /** Find handle for the device instance identified by device class name. */ 476 static void devman_function_get_handle_by_class(ipc_callid_t iid, 477 ipc_call_t *icall) 478 { 479 char *classname; 480 char *devname; 481 482 int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0); 483 if (rc != EOK) { 484 async_answer_0(iid, rc); 485 return; 486 } 487 rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0); 488 if (rc != EOK) { 489 free(classname); 490 async_answer_0(iid, rc); 491 return; 492 } 493 494 495 fun_node_t *fun = find_fun_node_by_class(&class_list, 496 classname, devname); 497 498 free(classname); 499 free(devname); 500 501 if (fun == NULL) { 502 async_answer_0(iid, ENOENT); 503 return; 504 } 505 506 async_answer_1(iid, EOK, fun->handle); 507 } 508 509 /** Find device path by its handle. */ 510 static void devman_get_device_path_by_handle(ipc_callid_t iid, 511 ipc_call_t *icall) 783 fibril_rwlock_read_lock(&device_tree.rwlock); 784 785 /* Check function state */ 786 if (fun->state == FUN_REMOVED) { 787 fibril_rwlock_read_unlock(&device_tree.rwlock); 788 async_answer_0(iid, ENOENT); 789 return; 790 } 791 handle = fun->handle; 792 793 fibril_rwlock_read_unlock(&device_tree.rwlock); 794 795 /* Delete reference created above by find_fun_node_by_path() */ 796 fun_del_ref(fun); 797 798 async_answer_1(iid, EOK, handle); 799 } 800 801 /** Get device name. */ 802 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall) 512 803 { 513 804 devman_handle_t handle = IPC_GET_ARG1(*icall); … … 523 814 if (!async_data_read_receive(&data_callid, &data_len)) { 524 815 async_answer_0(iid, EINVAL); 816 fun_del_ref(fun); 525 817 return; 526 818 } … … 530 822 async_answer_0(data_callid, ENOMEM); 531 823 async_answer_0(iid, ENOMEM); 532 return; 533 } 534 824 fun_del_ref(fun); 825 return; 826 } 827 828 fibril_rwlock_read_lock(&device_tree.rwlock); 829 830 /* Check function state */ 831 if (fun->state == FUN_REMOVED) { 832 fibril_rwlock_read_unlock(&device_tree.rwlock); 833 free(buffer); 834 835 async_answer_0(data_callid, ENOENT); 836 async_answer_0(iid, ENOENT); 837 fun_del_ref(fun); 838 return; 839 } 840 841 size_t sent_length = str_size(fun->name); 842 if (sent_length > data_len) { 843 sent_length = data_len; 844 } 845 846 async_data_read_finalize(data_callid, fun->name, sent_length); 847 async_answer_0(iid, EOK); 848 849 fibril_rwlock_read_unlock(&device_tree.rwlock); 850 fun_del_ref(fun); 851 free(buffer); 852 } 853 854 855 /** Get device path. */ 856 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall) 857 { 858 devman_handle_t handle = IPC_GET_ARG1(*icall); 859 860 fun_node_t *fun = find_fun_node(&device_tree, handle); 861 if (fun == NULL) { 862 async_answer_0(iid, ENOMEM); 863 return; 864 } 865 866 ipc_callid_t data_callid; 867 size_t data_len; 868 if (!async_data_read_receive(&data_callid, &data_len)) { 869 async_answer_0(iid, EINVAL); 870 fun_del_ref(fun); 871 return; 872 } 873 874 void *buffer = malloc(data_len); 875 if (buffer == NULL) { 876 async_answer_0(data_callid, ENOMEM); 877 async_answer_0(iid, ENOMEM); 878 fun_del_ref(fun); 879 return; 880 } 881 882 fibril_rwlock_read_lock(&device_tree.rwlock); 883 884 /* Check function state */ 885 if (fun->state == FUN_REMOVED) { 886 fibril_rwlock_read_unlock(&device_tree.rwlock); 887 free(buffer); 888 889 async_answer_0(data_callid, ENOENT); 890 async_answer_0(iid, ENOENT); 891 fun_del_ref(fun); 892 return; 893 } 894 535 895 size_t sent_length = str_size(fun->pathname); 536 896 if (sent_length > data_len) { … … 541 901 async_answer_0(iid, EOK); 542 902 903 fibril_rwlock_read_unlock(&device_tree.rwlock); 904 fun_del_ref(fun); 543 905 free(buffer); 544 906 } 545 907 908 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall) 909 { 910 ipc_callid_t callid; 911 size_t size; 912 size_t act_size; 913 int rc; 914 915 if (!async_data_read_receive(&callid, &size)) { 916 async_answer_0(callid, EREFUSED); 917 async_answer_0(iid, EREFUSED); 918 return; 919 } 920 921 fibril_rwlock_read_lock(&device_tree.rwlock); 922 923 dev_node_t *dev = find_dev_node_no_lock(&device_tree, 924 IPC_GET_ARG1(*icall)); 925 if (dev == NULL || dev->state == DEVICE_REMOVED) { 926 fibril_rwlock_read_unlock(&device_tree.rwlock); 927 async_answer_0(callid, ENOENT); 928 async_answer_0(iid, ENOENT); 929 return; 930 } 931 932 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size); 933 if (hdl_buf == NULL) { 934 fibril_rwlock_read_unlock(&device_tree.rwlock); 935 async_answer_0(callid, ENOMEM); 936 async_answer_0(iid, ENOMEM); 937 return; 938 } 939 940 rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size); 941 if (rc != EOK) { 942 fibril_rwlock_read_unlock(&device_tree.rwlock); 943 async_answer_0(callid, rc); 944 async_answer_0(iid, rc); 945 return; 946 } 947 948 fibril_rwlock_read_unlock(&device_tree.rwlock); 949 950 sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size); 951 free(hdl_buf); 952 953 async_answer_1(iid, retval, act_size); 954 } 955 956 957 /** Get handle for child device of a function. */ 958 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall) 959 { 960 fun_node_t *fun; 961 962 fibril_rwlock_read_lock(&device_tree.rwlock); 963 964 fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall)); 965 if (fun == NULL || fun->state == FUN_REMOVED) { 966 fibril_rwlock_read_unlock(&device_tree.rwlock); 967 async_answer_0(iid, ENOENT); 968 return; 969 } 970 971 if (fun->child == NULL) { 972 fibril_rwlock_read_unlock(&device_tree.rwlock); 973 async_answer_0(iid, ENOENT); 974 return; 975 } 976 977 async_answer_1(iid, EOK, fun->child->handle); 978 979 fibril_rwlock_read_unlock(&device_tree.rwlock); 980 } 981 982 /** Online function. 983 * 984 * Send a request to online a function to the responsible driver. 985 * The driver may offline other functions if necessary (i.e. if the state 986 * of this function is linked to state of another function somehow). 987 */ 988 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall) 989 { 990 fun_node_t *fun; 991 int rc; 992 993 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 994 if (fun == NULL) { 995 async_answer_0(iid, ENOENT); 996 return; 997 } 998 999 rc = driver_fun_online(&device_tree, fun); 1000 fun_del_ref(fun); 1001 1002 async_answer_0(iid, (sysarg_t) rc); 1003 } 1004 1005 /** Offline function. 1006 * 1007 * Send a request to offline a function to the responsible driver. As 1008 * a result the subtree rooted at that function should be cleanly 1009 * detatched. The driver may offline other functions if necessary 1010 * (i.e. if the state of this function is linked to state of another 1011 * function somehow). 1012 */ 1013 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 1014 { 1015 fun_node_t *fun; 1016 int rc; 1017 1018 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 1019 if (fun == NULL) { 1020 async_answer_0(iid, ENOENT); 1021 return; 1022 } 1023 1024 rc = driver_fun_offline(&device_tree, fun); 1025 fun_del_ref(fun); 1026 1027 async_answer_0(iid, (sysarg_t) rc); 1028 } 1029 1030 /** Find handle for the function instance identified by its service ID. */ 1031 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall) 1032 { 1033 fun_node_t *fun; 1034 1035 fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall)); 1036 1037 if (fun == NULL) { 1038 async_answer_0(iid, ENOENT); 1039 return; 1040 } 1041 1042 fibril_rwlock_read_lock(&device_tree.rwlock); 1043 1044 /* Check function state */ 1045 if (fun->state == FUN_REMOVED) { 1046 fibril_rwlock_read_unlock(&device_tree.rwlock); 1047 async_answer_0(iid, ENOENT); 1048 return; 1049 } 1050 1051 async_answer_1(iid, EOK, fun->handle); 1052 fibril_rwlock_read_unlock(&device_tree.rwlock); 1053 fun_del_ref(fun); 1054 } 546 1055 547 1056 /** Function for handling connections from a client to the device manager. */ … … 562 1071 devman_function_get_handle(callid, &call); 563 1072 break; 564 case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS: 565 devman_function_get_handle_by_class(callid, &call); 566 break; 567 case DEVMAN_DEVICE_GET_DEVICE_PATH: 568 devman_get_device_path_by_handle(callid, &call); 1073 case DEVMAN_DEV_GET_FUNCTIONS: 1074 devman_dev_get_functions(callid, &call); 1075 break; 1076 case DEVMAN_FUN_GET_CHILD: 1077 devman_fun_get_child(callid, &call); 1078 break; 1079 case DEVMAN_FUN_GET_NAME: 1080 devman_fun_get_name(callid, &call); 1081 break; 1082 case DEVMAN_FUN_GET_PATH: 1083 devman_fun_get_path(callid, &call); 1084 break; 1085 case DEVMAN_FUN_ONLINE: 1086 devman_fun_online(callid, &call); 1087 break; 1088 case DEVMAN_FUN_OFFLINE: 1089 devman_fun_offline(callid, &call); 1090 break; 1091 case DEVMAN_FUN_SID_TO_HANDLE: 1092 devman_fun_sid_to_handle(callid, &call); 569 1093 break; 570 1094 default: … … 585 1109 if (fun == NULL) 586 1110 dev = find_dev_node(&device_tree, handle); 587 else 1111 else { 1112 fibril_rwlock_read_lock(&device_tree.rwlock); 588 1113 dev = fun->dev; 1114 if (dev != NULL) 1115 dev_add_ref(dev); 1116 fibril_rwlock_read_unlock(&device_tree.rwlock); 1117 } 589 1118 590 1119 /* … … 598 1127 "function with handle %" PRIun " was found.", handle); 599 1128 async_answer_0(iid, ENOENT); 600 return;1129 goto cleanup; 601 1130 } 602 1131 … … 606 1135 handle); 607 1136 async_answer_0(iid, ENOENT); 608 return;1137 goto cleanup; 609 1138 } 610 1139 611 1140 driver_t *driver = NULL; 1141 1142 fibril_rwlock_read_lock(&device_tree.rwlock); 612 1143 613 1144 if (drv_to_parent) { … … 624 1155 } 625 1156 1157 fibril_rwlock_read_unlock(&device_tree.rwlock); 1158 626 1159 if (driver == NULL) { 627 1160 log_msg(LVL_ERROR, "IPC forwarding refused - " \ 628 1161 "the device %" PRIun " is not in usable state.", handle); 629 1162 async_answer_0(iid, ENOENT); 630 return;1163 goto cleanup; 631 1164 } 632 1165 … … 641 1174 "Could not forward to driver `%s'.", driver->name); 642 1175 async_answer_0(iid, EINVAL); 643 return;1176 goto cleanup; 644 1177 } 645 1178 … … 657 1190 async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE); 658 1191 async_exchange_end(exch); 659 } 660 661 /** Function for handling connections from a client forwarded by the device 662 * mapper to the device manager. */ 663 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall) 664 { 665 devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall); 1192 1193 cleanup: 1194 if (dev != NULL) 1195 dev_del_ref(dev); 1196 if (fun != NULL) 1197 fun_del_ref(fun); 1198 } 1199 1200 /** Function for handling connections from a client forwarded by the location 1201 * service to the device manager. */ 1202 static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall) 1203 { 1204 service_id_t service_id = IPC_GET_ARG2(*icall); 666 1205 fun_node_t *fun; 667 1206 dev_node_t *dev; 668 669 fun = find_devmap_tree_function(&device_tree, devmap_handle); 670 if (fun == NULL) 671 fun = find_devmap_class_function(&class_list, devmap_handle); 672 673 if (fun == NULL || fun->dev->drv == NULL) { 1207 devman_handle_t handle; 1208 driver_t *driver; 1209 1210 fun = find_loc_tree_function(&device_tree, service_id); 1211 1212 fibril_rwlock_read_lock(&device_tree.rwlock); 1213 1214 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) { 1215 log_msg(LVL_WARN, "devman_connection_loc(): function " 1216 "not found.\n"); 1217 fibril_rwlock_read_unlock(&device_tree.rwlock); 674 1218 async_answer_0(iid, ENOENT); 675 1219 return; … … 677 1221 678 1222 dev = fun->dev; 679 680 if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) { 681 async_answer_0(iid, EINVAL); 682 return; 683 } 684 685 async_exch_t *exch = async_exchange_begin(dev->drv->sess); 686 async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0, 1223 driver = dev->drv; 1224 handle = fun->handle; 1225 1226 fibril_rwlock_read_unlock(&device_tree.rwlock); 1227 1228 async_exch_t *exch = async_exchange_begin(driver->sess); 1229 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0, 687 1230 IPC_FF_NONE); 688 1231 async_exchange_end(exch); 689 1232 690 1233 log_msg(LVL_DEBUG, 691 "Forwarding devmapper request for `%s' function to driver `%s'.", 692 fun->pathname, dev->drv->name); 1234 "Forwarding loc service request for `%s' function to driver `%s'.", 1235 fun->pathname, driver->name); 1236 1237 fun_del_ref(fun); 693 1238 } 694 1239 … … 696 1241 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 697 1242 { 698 /* Select interface. */1243 /* Select port. */ 699 1244 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 700 1245 case DEVMAN_DRIVER: … … 708 1253 devman_forward(iid, icall, false); 709 1254 break; 710 case DEVMAN_CONNECT_FROM_ DEVMAP:711 /* Someone connected through devmapnode. */712 devman_connection_ devmapper(iid, icall);1255 case DEVMAN_CONNECT_FROM_LOC: 1256 /* Someone connected through loc node. */ 1257 devman_connection_loc(iid, icall); 713 1258 break; 714 1259 case DEVMAN_CONNECT_TO_PARENTS_DEVICE: … … 722 1267 } 723 1268 1269 static void *devman_client_data_create(void) 1270 { 1271 client_t *client; 1272 1273 client = calloc(1, sizeof(client_t)); 1274 if (client == NULL) 1275 return NULL; 1276 1277 fibril_mutex_initialize(&client->mutex); 1278 return client; 1279 } 1280 1281 static void devman_client_data_destroy(void *data) 1282 { 1283 free(data); 1284 } 1285 724 1286 /** Initialize device manager internal structures. */ 725 1287 static bool devman_init(void) … … 743 1305 } 744 1306 745 init_class_list(&class_list);746 747 1307 /* 748 * !!! devman_connection ... as the device manager is not a real devmap1308 * !!! devman_connection ... as the device manager is not a real loc 749 1309 * driver (it uses a completely different ipc protocol than an ordinary 750 * devmapdriver) forwarding a connection from client to the devman by751 * devmapperwould not work.1310 * loc driver) forwarding a connection from client to the devman by 1311 * location service would not work. 752 1312 */ 753 devmap_driver_register(NAME, devman_connection);1313 loc_server_register(NAME, devman_connection); 754 1314 755 1315 return true; … … 760 1320 printf(NAME ": HelenOS Device Manager\n"); 761 1321 762 if (log_init(NAME, LVL_ ERROR) != EOK) {1322 if (log_init(NAME, LVL_WARN) != EOK) { 763 1323 printf(NAME ": Error initializing logging subsystem.\n"); 764 1324 return -1; … … 770 1330 } 771 1331 772 /* Set a handler of incomming connections. */ 1332 /* Set handlers for incoming connections. */ 1333 async_set_client_data_constructor(devman_client_data_create); 1334 async_set_client_data_destructor(devman_client_data_destroy); 773 1335 async_set_client_connection(devman_connection); 774 1336
Note:
See TracChangeset
for help on using the changeset viewer.