Changes in uspace/lib/drv/generic/driver.c [5fdd7c3:26fa82bc] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r5fdd7c3 r26fa82bc 1 1 /* 2 2 * Copyright (c) 2010 Lenka Trochtova 3 * Copyright (c) 2011 Jiri Svoboda 3 4 * All rights reserved. 4 5 * … … 46 47 #include <stdlib.h> 47 48 #include <str.h> 49 #include <str_error.h> 48 50 #include <ctype.h> 49 51 #include <errno.h> 50 52 #include <inttypes.h> 53 #include <devman.h> 51 54 52 55 #include <ipc/driver.h> 53 56 54 57 #include "dev_iface.h" 55 #include "driver.h" 58 #include "ddf/driver.h" 59 #include "ddf/interrupt.h" 56 60 57 61 /** Driver structure */ … … 59 63 60 64 /** Devices */ 61 LIST_INITIALIZE( devices);62 FIBRIL_MUTEX_INITIALIZE( devices_mutex);65 LIST_INITIALIZE(functions); 66 FIBRIL_MUTEX_INITIALIZE(functions_mutex); 63 67 64 68 /** Interrupts */ … … 76 80 }; 77 81 82 static ddf_dev_t *create_device(void); 83 static void delete_device(ddf_dev_t *); 84 static remote_handler_t *function_get_default_handler(ddf_fun_t *); 85 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t); 78 86 79 87 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall) … … 150 158 151 159 interrupt_context_t * 152 find_interrupt_context(interrupt_context_list_t *list, d evice_t *dev, int irq)160 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq) 153 161 { 154 162 fibril_mutex_lock(&list->mutex); … … 172 180 173 181 int 174 register_interrupt_handler(d evice_t *dev, int irq, interrupt_handler_t *handler,182 register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler, 175 183 irq_code_t *pseudocode) 176 184 { … … 186 194 pseudocode = &default_pseudocode; 187 195 188 int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode);196 int res = register_irq(irq, dev->handle, ctx->id, pseudocode); 189 197 if (res != EOK) { 190 198 remove_interrupt_context(&interrupt_contexts, ctx); … … 195 203 } 196 204 197 int unregister_interrupt_handler(d evice_t *dev, int irq)205 int unregister_interrupt_handler(ddf_dev_t *dev, int irq) 198 206 { 199 207 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts, 200 208 dev, irq); 201 int res = ipc_unregister_irq(irq, dev->handle);209 int res = unregister_irq(irq, dev->handle); 202 210 203 211 if (ctx != NULL) { … … 209 217 } 210 218 211 static void add_to_ devices_list(device_t *dev)212 { 213 fibril_mutex_lock(& devices_mutex);214 list_append(& dev->link, &devices);215 fibril_mutex_unlock(& devices_mutex);216 } 217 218 static void remove_from_ devices_list(device_t *dev)219 { 220 fibril_mutex_lock(& devices_mutex);221 list_remove(& dev->link);222 fibril_mutex_unlock(& devices_mutex);223 } 224 225 static d evice_t *driver_get_device(link_t *devices, devman_handle_t handle)226 { 227 d evice_t *dev= NULL;228 229 fibril_mutex_lock(& devices_mutex);230 link_t *link = devices->next;231 232 while (link != devices) {233 dev = list_get_instance(link, device_t, link);234 if ( dev->handle == handle) {235 fibril_mutex_unlock(& devices_mutex);236 return dev;219 static void add_to_functions_list(ddf_fun_t *fun) 220 { 221 fibril_mutex_lock(&functions_mutex); 222 list_append(&fun->link, &functions); 223 fibril_mutex_unlock(&functions_mutex); 224 } 225 226 static void remove_from_functions_list(ddf_fun_t *fun) 227 { 228 fibril_mutex_lock(&functions_mutex); 229 list_remove(&fun->link); 230 fibril_mutex_unlock(&functions_mutex); 231 } 232 233 static ddf_fun_t *driver_get_function(link_t *functions, devman_handle_t handle) 234 { 235 ddf_fun_t *fun = NULL; 236 237 fibril_mutex_lock(&functions_mutex); 238 link_t *link = functions->next; 239 240 while (link != functions) { 241 fun = list_get_instance(link, ddf_fun_t, link); 242 if (fun->handle == handle) { 243 fibril_mutex_unlock(&functions_mutex); 244 return fun; 237 245 } 246 238 247 link = link->next; 239 248 } 240 249 241 fibril_mutex_unlock(& devices_mutex);250 fibril_mutex_unlock(&functions_mutex); 242 251 243 252 return NULL; … … 250 259 251 260 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 252 devman_handle_t parent_ dev_handle = IPC_GET_ARG2(*icall);253 254 d evice_t *dev = create_device();261 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall); 262 263 ddf_dev_t *dev = create_device(); 255 264 dev->handle = dev_handle; 256 265 257 266 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0); 258 267 dev->name = dev_name; 259 260 add_to_devices_list(dev); 261 dev->parent = driver_get_device(&devices, parent_dev_handle); 268 269 /* 270 * Currently not used, parent fun handle is stored in context 271 * of the connection to the parent device driver. 272 */ 273 (void) parent_fun_handle; 262 274 263 275 res = driver->driver_ops->add_device(dev); 264 if (res == EOK) { 265 printf("%s: new device with handle=%" PRIun " was added.\n", 266 driver->name, dev_handle); 267 } else { 268 printf("%s: failed to add a new device with handle = %" PRIun ".\n", 269 driver->name, dev_handle); 270 remove_from_devices_list(dev); 276 if (res != EOK) 271 277 delete_device(dev); 272 } 273 274 ipc_answer_0(iid, res); 278 279 async_answer_0(iid, res); 275 280 } 276 281 … … 278 283 { 279 284 /* Accept connection */ 280 ipc_answer_0(iid, EOK);285 async_answer_0(iid, EOK); 281 286 282 287 bool cont = true; … … 293 298 break; 294 299 default: 295 ipc_answer_0(callid, ENOENT);300 async_answer_0(callid, ENOENT); 296 301 } 297 302 } … … 311 316 */ 312 317 devman_handle_t handle = IPC_GET_ARG2(*icall); 313 d evice_t *dev = driver_get_device(&devices, handle);314 315 if ( dev== NULL) {316 printf("%s: driver_connection_gen error - no devicewith handle"318 ddf_fun_t *fun = driver_get_function(&functions, handle); 319 320 if (fun == NULL) { 321 printf("%s: driver_connection_gen error - no function with handle" 317 322 " %" PRIun " was found.\n", driver->name, handle); 318 ipc_answer_0(iid, ENOENT);323 async_answer_0(iid, ENOENT); 319 324 return; 320 325 } … … 327 332 328 333 int ret = EOK; 329 /* open the device*/330 if ( dev->ops != NULL && dev->ops->open != NULL)331 ret = (* dev->ops->open)(dev);332 333 ipc_answer_0(iid, ret);334 /* Open device function */ 335 if (fun->ops != NULL && fun->ops->open != NULL) 336 ret = (*fun->ops->open)(fun); 337 338 async_answer_0(iid, ret); 334 339 if (ret != EOK) 335 340 return; … … 344 349 switch (method) { 345 350 case IPC_M_PHONE_HUNGUP: 346 /* close the device*/347 if ( dev->ops != NULL && dev->ops->close != NULL)348 (* dev->ops->close)(dev);349 ipc_answer_0(callid, EOK);351 /* Close device function */ 352 if (fun->ops != NULL && fun->ops->close != NULL) 353 (*fun->ops->close)(fun); 354 async_answer_0(callid, EOK); 350 355 return; 351 356 default: … … 356 361 if (!is_valid_iface_idx(iface_idx)) { 357 362 remote_handler_t *default_handler = 358 device_get_default_handler(dev);363 function_get_default_handler(fun); 359 364 if (default_handler != NULL) { 360 (*default_handler)( dev, callid, &call);365 (*default_handler)(fun, callid, &call); 361 366 break; 362 367 } 368 363 369 /* 364 * This is not device's interface and the370 * Function has no such interface and 365 371 * default handler is not provided. 366 372 */ … … 368 374 "invalid interface id %d.", 369 375 driver->name, iface_idx); 370 ipc_answer_0(callid, ENOTSUP);376 async_answer_0(callid, ENOTSUP); 371 377 break; 372 378 } 373 379 374 /* calling one of the device's interfaces */380 /* calling one of the function's interfaces */ 375 381 376 382 /* Get the interface ops structure. */ 377 void *ops = device_get_ops(dev, iface_idx);383 void *ops = function_get_ops(fun, iface_idx); 378 384 if (ops == NULL) { 379 385 printf("%s: driver_connection_gen error - ", 380 386 driver->name); 381 printf(" devicewith handle %" PRIun " has no interface "387 printf("Function with handle %" PRIun " has no interface " 382 388 "with id %d.\n", handle, iface_idx); 383 ipc_answer_0(callid, ENOTSUP);389 async_answer_0(callid, ENOTSUP); 384 390 break; 385 391 } … … 397 403 get_remote_method(rem_iface, iface_method_idx); 398 404 if (iface_method_ptr == NULL) { 399 / / the interface has not such method405 /* The interface has not such method */ 400 406 printf("%s: driver_connection_gen error - " 401 407 "invalid interface method.", driver->name); 402 ipc_answer_0(callid, ENOTSUP);408 async_answer_0(callid, ENOTSUP); 403 409 break; 404 410 } … … 408 414 * receive parameters from the remote client and it will 409 415 * pass it to the corresponding local interface method 410 * associated with the deviceby its driver.416 * associated with the function by its driver. 411 417 */ 412 (*iface_method_ptr)( dev, ops, callid, &call);418 (*iface_method_ptr)(fun, ops, callid, &call); 413 419 break; 414 420 } … … 425 431 driver_connection_gen(iid, icall, false); 426 432 } 427 428 433 429 434 /** Function for handling connections to device driver. */ … … 446 451 default: 447 452 /* No such interface */ 448 ipc_answer_0(iid, ENOENT);453 async_answer_0(iid, ENOENT); 449 454 } 450 455 } … … 454 459 * @return The device structure. 455 460 */ 456 device_t *create_device(void)457 { 458 d evice_t *dev = malloc(sizeof(device_t));459 460 if (dev != NULL) {461 memset(dev, 0, sizeof(device_t));462 init_match_ids(&dev->match_ids);463 } 464 461 static ddf_dev_t *create_device(void) 462 { 463 ddf_dev_t *dev; 464 465 dev = malloc(sizeof(ddf_dev_t)); 466 if (dev == NULL) 467 return NULL; 468 469 memset(dev, 0, sizeof(ddf_dev_t)); 465 470 return dev; 466 471 } 467 472 473 /** Create new function structure. 474 * 475 * @return The device structure. 476 */ 477 static ddf_fun_t *create_function(void) 478 { 479 ddf_fun_t *fun; 480 481 fun = calloc(1, sizeof(ddf_fun_t)); 482 if (fun == NULL) 483 return NULL; 484 485 init_match_ids(&fun->match_ids); 486 link_initialize(&fun->link); 487 488 return fun; 489 } 490 468 491 /** Delete device structure. 469 492 * 470 493 * @param dev The device structure. 471 494 */ 472 void delete_device(device_t *dev) 473 { 474 clean_match_ids(&dev->match_ids); 475 if (dev->name != NULL) 476 free(dev->name); 495 static void delete_device(ddf_dev_t *dev) 496 { 477 497 free(dev); 478 498 } 479 499 480 void *device_get_ops(device_t *dev, dev_inferface_idx_t idx) 500 /** Delete device structure. 501 * 502 * @param dev The device structure. 503 */ 504 static void delete_function(ddf_fun_t *fun) 505 { 506 clean_match_ids(&fun->match_ids); 507 if (fun->name != NULL) 508 free(fun->name); 509 free(fun); 510 } 511 512 /** Create a DDF function node. 513 * 514 * Create a DDF function (in memory). Both child devices and external clients 515 * communicate with a device via its functions. 516 * 517 * The created function node is fully formed, but only exists in the memory 518 * of the client task. In order to be visible to the system, the function 519 * must be bound using ddf_fun_bind(). 520 * 521 * This function should only fail if there is not enough free memory. 522 * Specifically, this function succeeds even if @a dev already has 523 * a (bound) function with the same name. 524 * 525 * Type: A function of type fun_inner indicates that DDF should attempt 526 * to attach child devices to the function. fun_exposed means that 527 * the function should be exported to external clients (applications). 528 * 529 * @param dev Device to which we are adding function 530 * @param ftype Type of function (fun_inner or fun_exposed) 531 * @param name Name of function 532 * 533 * @return New function or @c NULL if memory is not available 534 */ 535 ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name) 536 { 537 ddf_fun_t *fun; 538 539 fun = create_function(); 540 if (fun == NULL) 541 return NULL; 542 543 fun->bound = false; 544 fun->dev = dev; 545 fun->ftype = ftype; 546 547 fun->name = str_dup(name); 548 if (fun->name == NULL) { 549 delete_function(fun); 550 return NULL; 551 } 552 553 return fun; 554 } 555 556 /** Destroy DDF function node. 557 * 558 * Destroy a function previously created with ddf_fun_create(). The function 559 * must not be bound. 560 * 561 * @param fun Function to destroy 562 */ 563 void ddf_fun_destroy(ddf_fun_t *fun) 564 { 565 assert(fun->bound == false); 566 delete_function(fun); 567 } 568 569 static void *function_get_ops(ddf_fun_t *fun, dev_inferface_idx_t idx) 481 570 { 482 571 assert(is_valid_iface_idx(idx)); 483 if ( dev->ops == NULL)572 if (fun->ops == NULL) 484 573 return NULL; 485 return dev->ops->interfaces[idx]; 486 } 487 488 int child_device_register(device_t *child, device_t *parent) 489 { 490 assert(child->name != NULL); 574 return fun->ops->interfaces[idx]; 575 } 576 577 /** Bind a function node. 578 * 579 * Bind the specified function to the system. This effectively makes 580 * the function visible to the system (uploads it to the server). 581 * 582 * This function can fail for several reasons. Specifically, 583 * it will fail if the device already has a bound function of 584 * the same name. 585 * 586 * @param fun Function to bind 587 * @return EOK on success or negative error code 588 */ 589 int ddf_fun_bind(ddf_fun_t *fun) 590 { 591 assert(fun->name != NULL); 491 592 492 593 int res; 493 594 494 add_to_ devices_list(child);495 res = devman_ child_device_register(child->name, &child->match_ids,496 parent->handle, &child->handle);595 add_to_functions_list(fun); 596 res = devman_add_function(fun->name, fun->ftype, &fun->match_ids, 597 fun->dev->handle, &fun->handle); 497 598 if (res != EOK) { 498 remove_from_ devices_list(child);599 remove_from_functions_list(fun); 499 600 return res; 500 601 } 501 602 603 fun->bound = true; 502 604 return res; 503 605 } 504 606 505 /** Wrapper for child_device_register for devices with single match id. 506 * 507 * @param parent Parent device. 508 * @param child_name Child device name. 509 * @param child_match_id Child device match id. 510 * @param child_match_score Child device match score. 511 * @return Error code. 512 */ 513 int child_device_register_wrapper(device_t *parent, const char *child_name, 514 const char *child_match_id, int child_match_score) 515 { 516 device_t *child = NULL; 517 match_id_t *match_id = NULL; 607 /** Add single match ID to inner function. 608 * 609 * Construct and add a single match ID to the specified function. 610 * Cannot be called when the function node is bound. 611 * 612 * @param fun Function 613 * @param match_id_str Match string 614 * @param match_score Match score 615 * @return EOK on success, ENOMEM if out of memory. 616 */ 617 int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str, 618 int match_score) 619 { 620 match_id_t *match_id; 621 622 assert(fun->bound == false); 623 assert(fun->ftype == fun_inner); 624 625 match_id = create_match_id(); 626 if (match_id == NULL) 627 return ENOMEM; 628 629 match_id->id = match_id_str; 630 match_id->score = 90; 631 632 add_match_id(&fun->match_ids, match_id); 633 return EOK; 634 } 635 636 /** Get default handler for client requests */ 637 static remote_handler_t *function_get_default_handler(ddf_fun_t *fun) 638 { 639 if (fun->ops == NULL) 640 return NULL; 641 return fun->ops->default_handler; 642 } 643 644 /** Add exposed function to class. 645 * 646 * Must only be called when the function is bound. 647 */ 648 int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name) 649 { 650 assert(fun->bound == true); 651 assert(fun->ftype == fun_exposed); 652 653 return devman_add_device_to_class(fun->handle, class_name); 654 } 655 656 int ddf_driver_main(driver_t *drv) 657 { 518 658 int rc; 519 520 child = create_device(); 521 if (child == NULL) { 522 rc = ENOMEM; 523 goto failure; 524 } 525 526 child->name = child_name; 527 528 match_id = create_match_id(); 529 if (match_id == NULL) { 530 rc = ENOMEM; 531 goto failure; 532 } 533 534 match_id->id = child_match_id; 535 match_id->score = child_match_score; 536 add_match_id(&child->match_ids, match_id); 537 538 rc = child_device_register(child, parent); 539 if (rc != EOK) 540 goto failure; 541 542 return EOK; 543 544 failure: 545 if (match_id != NULL) { 546 match_id->id = NULL; 547 delete_match_id(match_id); 548 } 549 550 if (child != NULL) { 551 child->name = NULL; 552 delete_device(child); 553 } 554 555 return rc; 556 } 557 558 /** Get default handler for client requests */ 559 remote_handler_t *device_get_default_handler(device_t *dev) 560 { 561 if (dev->ops == NULL) 562 return NULL; 563 return dev->ops->default_handler; 564 } 565 566 int add_device_to_class(device_t *dev, const char *class_name) 567 { 568 return devman_add_device_to_class(dev->handle, class_name); 569 } 570 571 int driver_main(driver_t *drv) 572 { 659 573 660 /* 574 661 * Remember the driver structure - driver_ops will be called by generic … … 584 671 585 672 /* 586 * Register driver by device manager with generic handler for incoming587 * connections.673 * Register driver with device manager using generic handler for 674 * incoming connections. 588 675 */ 589 devman_driver_register(driver->name, driver_connection); 590 676 rc = devman_driver_register(driver->name, driver_connection); 677 if (rc != EOK) { 678 printf("Error: Failed to register driver with device manager " 679 "(%s).\n", (rc == EEXISTS) ? "driver already started" : 680 str_error(rc)); 681 682 return 1; 683 } 684 685 /* Return success from the task since server has started. */ 686 rc = task_retval(0); 687 if (rc != EOK) 688 return 1; 689 591 690 async_manager(); 592 691
Note:
See TracChangeset
for help on using the changeset viewer.