Changes in uspace/lib/drv/generic/driver.c [26fa82bc:8a363ab3] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r26fa82bc r8a363ab3 63 63 64 64 /** Devices */ 65 LIST_INITIALIZE(devices); 66 FIBRIL_MUTEX_INITIALIZE(devices_mutex); 67 68 /** Functions */ 65 69 LIST_INITIALIZE(functions); 66 70 FIBRIL_MUTEX_INITIALIZE(functions_mutex); … … 82 86 static ddf_dev_t *create_device(void); 83 87 static void delete_device(ddf_dev_t *); 88 static void dev_add_ref(ddf_dev_t *); 89 static void dev_del_ref(ddf_dev_t *); 90 static void fun_add_ref(ddf_fun_t *); 91 static void fun_del_ref(ddf_fun_t *); 84 92 static remote_handler_t *function_get_default_handler(ddf_fun_t *); 85 93 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t); … … 139 147 find_interrupt_context_by_id(interrupt_context_list_t *list, int id) 140 148 { 149 interrupt_context_t *ctx; 150 141 151 fibril_mutex_lock(&list->mutex); 142 152 143 link_t *link = list->contexts.next; 144 interrupt_context_t *ctx; 145 146 while (link != &list->contexts) { 153 list_foreach(list->contexts, link) { 147 154 ctx = list_get_instance(link, interrupt_context_t, link); 148 155 if (ctx->id == id) { … … 150 157 return ctx; 151 158 } 152 link = link->next;153 159 } 154 160 … … 160 166 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq) 161 167 { 168 interrupt_context_t *ctx; 169 162 170 fibril_mutex_lock(&list->mutex); 163 171 164 link_t *link = list->contexts.next; 165 interrupt_context_t *ctx; 166 167 while (link != &list->contexts) { 172 list_foreach(list->contexts, link) { 168 173 ctx = list_get_instance(link, interrupt_context_t, link); 169 174 if (ctx->irq == irq && ctx->dev == dev) { … … 171 176 return ctx; 172 177 } 173 link = link->next;174 178 } 175 179 … … 231 235 } 232 236 233 static ddf_fun_t *driver_get_function(link_t *functions, devman_handle_t handle) 237 static ddf_dev_t *driver_get_device(devman_handle_t handle) 238 { 239 ddf_dev_t *dev = NULL; 240 241 assert(fibril_mutex_is_locked(&devices_mutex)); 242 243 list_foreach(devices, link) { 244 dev = list_get_instance(link, ddf_dev_t, link); 245 if (dev->handle == handle) 246 return dev; 247 } 248 249 return NULL; 250 } 251 252 static ddf_fun_t *driver_get_function(devman_handle_t handle) 234 253 { 235 254 ddf_fun_t *fun = NULL; 236 255 237 fibril_mutex_lock(&functions_mutex); 238 link_t *link = functions->next; 239 240 while (link != functions) { 256 assert(fibril_mutex_is_locked(&functions_mutex)); 257 258 list_foreach(functions, link) { 241 259 fun = list_get_instance(link, ddf_fun_t, link); 242 if (fun->handle == handle) { 243 fibril_mutex_unlock(&functions_mutex); 260 if (fun->handle == handle) 244 261 return fun; 245 } 246 247 link = link->next; 248 } 249 250 fibril_mutex_unlock(&functions_mutex); 262 } 251 263 252 264 return NULL; 253 265 } 254 266 255 static void driver_ add_device(ipc_callid_t iid, ipc_call_t *icall)267 static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall) 256 268 { 257 269 char *dev_name = NULL; … … 259 271 260 272 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 261 273 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall); 262 274 263 275 ddf_dev_t *dev = create_device(); 276 277 /* Add one reference that will be dropped by driver_dev_remove() */ 278 dev_add_ref(dev); 264 279 dev->handle = dev_handle; 265 280 … … 274 289 275 290 res = driver->driver_ops->add_device(dev); 276 if (res != EOK) 277 delete_device(dev); 291 292 if (res != EOK) { 293 dev_del_ref(dev); 294 async_answer_0(iid, res); 295 return; 296 } 297 298 fibril_mutex_lock(&devices_mutex); 299 list_append(&dev->link, &devices); 300 fibril_mutex_unlock(&devices_mutex); 278 301 279 302 async_answer_0(iid, res); 303 } 304 305 static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall) 306 { 307 fibril_mutex_lock(&devices_mutex); 308 ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall)); 309 fibril_mutex_unlock(&devices_mutex); 310 311 if (dev != NULL && driver->driver_ops->device_added != NULL) 312 driver->driver_ops->device_added(dev); 313 } 314 315 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall) 316 { 317 devman_handle_t devh; 318 ddf_dev_t *dev; 319 int rc; 320 321 devh = IPC_GET_ARG1(*icall); 322 323 fibril_mutex_lock(&devices_mutex); 324 dev = driver_get_device(devh); 325 if (dev != NULL) 326 dev_add_ref(dev); 327 fibril_mutex_unlock(&devices_mutex); 328 329 if (dev == NULL) { 330 async_answer_0(iid, ENOENT); 331 return; 332 } 333 334 if (driver->driver_ops->dev_remove != NULL) 335 rc = driver->driver_ops->dev_remove(dev); 336 else 337 rc = ENOTSUP; 338 339 if (rc == EOK) 340 dev_del_ref(dev); 341 342 async_answer_0(iid, (sysarg_t) rc); 343 } 344 345 static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall) 346 { 347 devman_handle_t devh; 348 ddf_dev_t *dev; 349 int rc; 350 351 devh = IPC_GET_ARG1(*icall); 352 353 fibril_mutex_lock(&devices_mutex); 354 dev = driver_get_device(devh); 355 if (dev != NULL) 356 dev_add_ref(dev); 357 fibril_mutex_unlock(&devices_mutex); 358 359 if (dev == NULL) { 360 async_answer_0(iid, ENOENT); 361 return; 362 } 363 364 if (driver->driver_ops->dev_gone != NULL) 365 rc = driver->driver_ops->dev_gone(dev); 366 else 367 rc = ENOTSUP; 368 369 if (rc == EOK) 370 dev_del_ref(dev); 371 372 async_answer_0(iid, (sysarg_t) rc); 373 } 374 375 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall) 376 { 377 devman_handle_t funh; 378 ddf_fun_t *fun; 379 int rc; 380 381 funh = IPC_GET_ARG1(*icall); 382 383 /* 384 * Look the function up. Bump reference count so that 385 * the function continues to exist until we return 386 * from the driver. 387 */ 388 fibril_mutex_lock(&functions_mutex); 389 390 fun = driver_get_function(funh); 391 if (fun != NULL) 392 fun_add_ref(fun); 393 394 fibril_mutex_unlock(&functions_mutex); 395 396 if (fun == NULL) { 397 async_answer_0(iid, ENOENT); 398 return; 399 } 400 401 /* Call driver entry point */ 402 if (driver->driver_ops->fun_online != NULL) 403 rc = driver->driver_ops->fun_online(fun); 404 else 405 rc = ENOTSUP; 406 407 fun_del_ref(fun); 408 409 async_answer_0(iid, (sysarg_t) rc); 410 } 411 412 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 413 { 414 devman_handle_t funh; 415 ddf_fun_t *fun; 416 int rc; 417 418 funh = IPC_GET_ARG1(*icall); 419 420 /* 421 * Look the function up. Bump reference count so that 422 * the function continues to exist until we return 423 * from the driver. 424 */ 425 fibril_mutex_lock(&functions_mutex); 426 427 fun = driver_get_function(funh); 428 if (fun != NULL) 429 fun_add_ref(fun); 430 431 fibril_mutex_unlock(&functions_mutex); 432 433 if (fun == NULL) { 434 async_answer_0(iid, ENOENT); 435 return; 436 } 437 438 /* Call driver entry point */ 439 if (driver->driver_ops->fun_offline != NULL) 440 rc = driver->driver_ops->fun_offline(fun); 441 else 442 rc = ENOTSUP; 443 444 async_answer_0(iid, (sysarg_t) rc); 280 445 } 281 446 … … 285 450 async_answer_0(iid, EOK); 286 451 287 bool cont = true; 288 while (cont) { 452 while (true) { 289 453 ipc_call_t call; 290 454 ipc_callid_t callid = async_get_call(&call); 291 455 456 if (!IPC_GET_IMETHOD(call)) 457 break; 458 292 459 switch (IPC_GET_IMETHOD(call)) { 293 case IPC_M_PHONE_HUNGUP: 294 cont = false; 295 continue; 296 case DRIVER_ADD_DEVICE: 297 driver_add_device(callid, &call); 460 case DRIVER_DEV_ADD: 461 driver_dev_add(callid, &call); 462 break; 463 case DRIVER_DEV_ADDED: 464 async_answer_0(callid, EOK); 465 driver_dev_added(callid, &call); 466 break; 467 case DRIVER_DEV_REMOVE: 468 driver_dev_remove(callid, &call); 469 break; 470 case DRIVER_DEV_GONE: 471 driver_dev_gone(callid, &call); 472 break; 473 case DRIVER_FUN_ONLINE: 474 driver_fun_online(callid, &call); 475 break; 476 case DRIVER_FUN_OFFLINE: 477 driver_fun_offline(callid, &call); 298 478 break; 299 479 default: 300 async_answer_0(callid, ENO ENT);480 async_answer_0(callid, ENOTSUP); 301 481 } 302 482 } 303 483 } 304 484 305 /** 306 * Generic client connection handler both for applications and drivers.307 * 308 * @param drv True for driver client, false for other clients309 * (applications, services etc.).485 /** Generic client connection handler both for applications and drivers. 486 * 487 * @param drv True for driver client, false for other clients 488 * (applications, services, etc.). 489 * 310 490 */ 311 491 static void driver_connection_gen(ipc_callid_t iid, ipc_call_t *icall, bool drv) … … 316 496 */ 317 497 devman_handle_t handle = IPC_GET_ARG2(*icall); 318 ddf_fun_t *fun = driver_get_function(&functions, handle); 319 498 499 fibril_mutex_lock(&functions_mutex); 500 ddf_fun_t *fun = driver_get_function(handle); 501 fibril_mutex_unlock(&functions_mutex); 502 /* XXX Need a lock on fun */ 503 320 504 if (fun == NULL) { 321 505 printf("%s: driver_connection_gen error - no function with handle" … … 325 509 } 326 510 511 if (fun->conn_handler != NULL) { 512 /* Driver has a custom connection handler. */ 513 (*fun->conn_handler)(iid, icall, (void *)fun); 514 return; 515 } 327 516 328 517 /* … … 340 529 return; 341 530 342 while ( 1) {531 while (true) { 343 532 ipc_callid_t callid; 344 533 ipc_call_t call; 345 534 callid = async_get_call(&call); 346 535 sysarg_t method = IPC_GET_IMETHOD(call); 347 int iface_idx; 348 349 switch (method) { 350 case IPC_M_PHONE_HUNGUP: 536 537 if (!method) { 351 538 /* Close device function */ 352 539 if (fun->ops != NULL && fun->ops->close != NULL) … … 354 541 async_answer_0(callid, EOK); 355 542 return; 356 default: 357 /* convert ipc interface id to interface index */ 358 359 iface_idx = DEV_IFACE_IDX(method); 360 361 if (!is_valid_iface_idx(iface_idx)) { 362 remote_handler_t *default_handler = 363 function_get_default_handler(fun); 364 if (default_handler != NULL) { 365 (*default_handler)(fun, callid, &call); 366 break; 367 } 368 369 /* 370 * Function has no such interface and 371 * default handler is not provided. 372 */ 373 printf("%s: driver_connection_gen error - " 374 "invalid interface id %d.", 375 driver->name, iface_idx); 376 async_answer_0(callid, ENOTSUP); 377 break; 378 } 379 380 /* calling one of the function's interfaces */ 381 382 /* Get the interface ops structure. */ 383 void *ops = function_get_ops(fun, iface_idx); 384 if (ops == NULL) { 385 printf("%s: driver_connection_gen error - ", 386 driver->name); 387 printf("Function with handle %" PRIun " has no interface " 388 "with id %d.\n", handle, iface_idx); 389 async_answer_0(callid, ENOTSUP); 390 break; 543 } 544 545 /* Convert ipc interface id to interface index */ 546 547 int iface_idx = DEV_IFACE_IDX(method); 548 549 if (!is_valid_iface_idx(iface_idx)) { 550 remote_handler_t *default_handler = 551 function_get_default_handler(fun); 552 if (default_handler != NULL) { 553 (*default_handler)(fun, callid, &call); 554 continue; 391 555 } 392 556 393 557 /* 394 * Get the corresponding interface for remote request395 * handling ("remote interface").558 * Function has no such interface and 559 * default handler is not provided. 396 560 */ 397 remote_iface_t *rem_iface = get_remote_iface(iface_idx); 398 assert(rem_iface != NULL); 399 400 /* get the method of the remote interface */ 401 sysarg_t iface_method_idx = IPC_GET_ARG1(call); 402 remote_iface_func_ptr_t iface_method_ptr = 403 get_remote_method(rem_iface, iface_method_idx); 404 if (iface_method_ptr == NULL) { 405 /* The interface has not such method */ 406 printf("%s: driver_connection_gen error - " 407 "invalid interface method.", driver->name); 408 async_answer_0(callid, ENOTSUP); 409 break; 410 } 411 412 /* 413 * Call the remote interface's method, which will 414 * receive parameters from the remote client and it will 415 * pass it to the corresponding local interface method 416 * associated with the function by its driver. 417 */ 418 (*iface_method_ptr)(fun, ops, callid, &call); 419 break; 561 printf("%s: driver_connection_gen error - " 562 "invalid interface id %d.", 563 driver->name, iface_idx); 564 async_answer_0(callid, ENOTSUP); 565 continue; 420 566 } 567 568 /* Calling one of the function's interfaces */ 569 570 /* Get the interface ops structure. */ 571 void *ops = function_get_ops(fun, iface_idx); 572 if (ops == NULL) { 573 printf("%s: driver_connection_gen error - ", driver->name); 574 printf("Function with handle %" PRIun " has no interface " 575 "with id %d.\n", handle, iface_idx); 576 async_answer_0(callid, ENOTSUP); 577 continue; 578 } 579 580 /* 581 * Get the corresponding interface for remote request 582 * handling ("remote interface"). 583 */ 584 remote_iface_t *rem_iface = get_remote_iface(iface_idx); 585 assert(rem_iface != NULL); 586 587 /* get the method of the remote interface */ 588 sysarg_t iface_method_idx = IPC_GET_ARG1(call); 589 remote_iface_func_ptr_t iface_method_ptr = 590 get_remote_method(rem_iface, iface_method_idx); 591 if (iface_method_ptr == NULL) { 592 /* The interface has not such method */ 593 printf("%s: driver_connection_gen error - " 594 "invalid interface method.", driver->name); 595 async_answer_0(callid, ENOTSUP); 596 continue; 597 } 598 599 /* 600 * Call the remote interface's method, which will 601 * receive parameters from the remote client and it will 602 * pass it to the corresponding local interface method 603 * associated with the function by its driver. 604 */ 605 (*iface_method_ptr)(fun, ops, callid, &call); 421 606 } 422 607 } … … 433 618 434 619 /** Function for handling connections to device driver. */ 435 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall) 436 { 620 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 621 { 622 sysarg_t conn_type; 623 624 if (iid == 0) { 625 /* Callback connection from devman */ 626 /* XXX Use separate handler for this type of connection */ 627 conn_type = DRIVER_DEVMAN; 628 } else { 629 conn_type = IPC_GET_ARG1(*icall); 630 } 631 437 632 /* Select interface */ 438 switch ( (sysarg_t) (IPC_GET_ARG1(*icall))) {633 switch (conn_type) { 439 634 case DRIVER_DEVMAN: 440 635 /* Handle request from device manager */ … … 463 658 ddf_dev_t *dev; 464 659 465 dev = malloc(sizeof(ddf_dev_t));660 dev = calloc(1, sizeof(ddf_dev_t)); 466 661 if (dev == NULL) 467 662 return NULL; 468 663 469 memset(dev, 0, sizeof(ddf_dev_t));470 664 return dev; 471 665 } … … 495 689 static void delete_device(ddf_dev_t *dev) 496 690 { 691 if (dev->driver_data != NULL) 692 free(dev->driver_data); 497 693 free(dev); 498 694 } 499 695 500 /** Delete devicestructure.696 /** Delete function structure. 501 697 * 502 698 * @param dev The device structure. … … 505 701 { 506 702 clean_match_ids(&fun->match_ids); 703 if (fun->driver_data != NULL) 704 free(fun->driver_data); 507 705 if (fun->name != NULL) 508 706 free(fun->name); … … 510 708 } 511 709 710 /** Increase device reference count. */ 711 static void dev_add_ref(ddf_dev_t *dev) 712 { 713 atomic_inc(&dev->refcnt); 714 } 715 716 /** Decrease device reference count. 717 * 718 * Free the device structure if the reference count drops to zero. 719 */ 720 static void dev_del_ref(ddf_dev_t *dev) 721 { 722 if (atomic_predec(&dev->refcnt) == 0) 723 delete_device(dev); 724 } 725 726 /** Increase function reference count. 727 * 728 * This also increases reference count on the device. The device structure 729 * will thus not be deallocated while there are some associated function 730 * structures. 731 */ 732 static void fun_add_ref(ddf_fun_t *fun) 733 { 734 dev_add_ref(fun->dev); 735 atomic_inc(&fun->refcnt); 736 } 737 738 /** Decrease function reference count. 739 * 740 * Free the function structure if the reference count drops to zero. 741 */ 742 static void fun_del_ref(ddf_fun_t *fun) 743 { 744 ddf_dev_t *dev = fun->dev; 745 746 if (atomic_predec(&fun->refcnt) == 0) 747 delete_function(fun); 748 749 dev_del_ref(dev); 750 } 751 752 /** Allocate driver-specific device data. */ 753 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 754 { 755 void *data; 756 757 assert(dev->driver_data == NULL); 758 759 data = calloc(1, size); 760 if (data == NULL) 761 return NULL; 762 763 dev->driver_data = data; 764 return data; 765 } 766 512 767 /** Create a DDF function node. 513 768 * … … 541 796 return NULL; 542 797 798 /* Add one reference that will be dropped by ddf_fun_destroy() */ 799 fun->dev = dev; 800 fun_add_ref(fun); 801 543 802 fun->bound = false; 544 fun->dev = dev;545 803 fun->ftype = ftype; 546 804 … … 554 812 } 555 813 814 /** Allocate driver-specific function data. */ 815 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 816 { 817 void *data; 818 819 assert(fun->bound == false); 820 assert(fun->driver_data == NULL); 821 822 data = calloc(1, size); 823 if (data == NULL) 824 return NULL; 825 826 fun->driver_data = data; 827 return data; 828 } 829 556 830 /** Destroy DDF function node. 557 831 * … … 564 838 { 565 839 assert(fun->bound == false); 566 delete_function(fun); 840 841 /* 842 * Drop the reference added by ddf_fun_create(). This will deallocate 843 * the function as soon as all other references are dropped (i.e. 844 * as soon control leaves all driver entry points called in context 845 * of this function. 846 */ 847 fun_del_ref(fun); 567 848 } 568 849 … … 589 870 int ddf_fun_bind(ddf_fun_t *fun) 590 871 { 872 assert(fun->bound == false); 591 873 assert(fun->name != NULL); 592 874 … … 605 887 } 606 888 889 /** Unbind a function node. 890 * 891 * Unbind the specified function from the system. This effectively makes 892 * the function invisible to the system. 893 * 894 * @param fun Function to unbind 895 * @return EOK on success or negative error code 896 */ 897 int ddf_fun_unbind(ddf_fun_t *fun) 898 { 899 int res; 900 901 assert(fun->bound == true); 902 903 res = devman_remove_function(fun->handle); 904 if (res != EOK) 905 return res; 906 907 remove_from_functions_list(fun); 908 909 fun->bound = false; 910 return EOK; 911 } 912 913 /** Online function. 914 * 915 * @param fun Function to online 916 * @return EOK on success or negative error code 917 */ 918 int ddf_fun_online(ddf_fun_t *fun) 919 { 920 int res; 921 922 assert(fun->bound == true); 923 924 res = devman_drv_fun_online(fun->handle); 925 if (res != EOK) 926 return res; 927 928 return EOK; 929 } 930 931 /** Offline function. 932 * 933 * @param fun Function to offline 934 * @return EOK on success or negative error code 935 */ 936 int ddf_fun_offline(ddf_fun_t *fun) 937 { 938 int res; 939 940 assert(fun->bound == true); 941 942 res = devman_drv_fun_offline(fun->handle); 943 if (res != EOK) 944 return res; 945 946 return EOK; 947 } 948 607 949 /** Add single match ID to inner function. 608 950 * … … 627 969 return ENOMEM; 628 970 629 match_id->id = match_id_str;630 match_id->score = 90;971 match_id->id = str_dup(match_id_str); 972 match_id->score = match_score; 631 973 632 974 add_match_id(&fun->match_ids, match_id); … … 642 984 } 643 985 644 /** Add exposed function to c lass.986 /** Add exposed function to category. 645 987 * 646 988 * Must only be called when the function is bound. 647 989 */ 648 int ddf_fun_add_to_c lass(ddf_fun_t *fun, const char *class_name)990 int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name) 649 991 { 650 992 assert(fun->bound == true); 651 993 assert(fun->ftype == fun_exposed); 652 994 653 return devman_add_device_to_c lass(fun->handle, class_name);995 return devman_add_device_to_category(fun->handle, cat_name); 654 996 } 655 997
Note:
See TracChangeset
for help on using the changeset viewer.