Changes in uspace/lib/drv/generic/driver.c [a996ae31:3e6a98c5] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
ra996ae31 r3e6a98c5 37 37 */ 38 38 39 #define _DDF_DATA_IMPLANT 40 39 41 #include <assert.h> 40 42 #include <ipc/services.h> … … 43 45 #include <stdio.h> 44 46 #include <errno.h> 45 #include < bool.h>47 #include <stdbool.h> 46 48 #include <fibril_synch.h> 47 49 #include <stdlib.h> … … 58 60 #include "ddf/driver.h" 59 61 #include "ddf/interrupt.h" 62 #include "private/driver.h" 60 63 61 64 /** Driver structure */ … … 69 72 LIST_INITIALIZE(functions); 70 73 FIBRIL_MUTEX_INITIALIZE(functions_mutex); 71 72 /** Interrupts */73 static interrupt_context_list_t interrupt_contexts;74 75 static irq_cmd_t default_cmds[] = {76 {77 .cmd = CMD_ACCEPT78 }79 };80 81 static irq_code_t default_pseudocode = {82 0,83 NULL,84 sizeof(default_cmds) / sizeof(irq_cmd_t),85 default_cmds86 };87 74 88 75 static ddf_dev_t *create_device(void); … … 95 82 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t); 96 83 97 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)98 {99 int id = (int)IPC_GET_IMETHOD(*icall);100 interrupt_context_t *ctx;101 102 ctx = find_interrupt_context_by_id(&interrupt_contexts, id);103 if (ctx != NULL && ctx->handler != NULL)104 (*ctx->handler)(ctx->dev, iid, icall);105 }106 107 interrupt_context_t *create_interrupt_context(void)108 {109 interrupt_context_t *ctx;110 111 ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));112 if (ctx != NULL)113 memset(ctx, 0, sizeof(interrupt_context_t));114 115 return ctx;116 }117 118 void delete_interrupt_context(interrupt_context_t *ctx)119 {120 if (ctx != NULL)121 free(ctx);122 }123 124 void init_interrupt_context_list(interrupt_context_list_t *list)125 {126 memset(list, 0, sizeof(interrupt_context_list_t));127 fibril_mutex_initialize(&list->mutex);128 list_initialize(&list->contexts);129 }130 131 void132 add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)133 {134 fibril_mutex_lock(&list->mutex);135 ctx->id = list->curr_id++;136 list_append(&ctx->link, &list->contexts);137 fibril_mutex_unlock(&list->mutex);138 }139 140 void remove_interrupt_context(interrupt_context_list_t *list,141 interrupt_context_t *ctx)142 {143 fibril_mutex_lock(&list->mutex);144 list_remove(&ctx->link);145 fibril_mutex_unlock(&list->mutex);146 }147 148 interrupt_context_t *149 find_interrupt_context_by_id(interrupt_context_list_t *list, int id)150 {151 interrupt_context_t *ctx;152 153 fibril_mutex_lock(&list->mutex);154 155 list_foreach(list->contexts, link) {156 ctx = list_get_instance(link, interrupt_context_t, link);157 if (ctx->id == id) {158 fibril_mutex_unlock(&list->mutex);159 return ctx;160 }161 }162 163 fibril_mutex_unlock(&list->mutex);164 return NULL;165 }166 167 interrupt_context_t *168 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)169 {170 interrupt_context_t *ctx;171 172 fibril_mutex_lock(&list->mutex);173 174 list_foreach(list->contexts, link) {175 ctx = list_get_instance(link, interrupt_context_t, link);176 if (ctx->irq == irq && ctx->dev == dev) {177 fibril_mutex_unlock(&list->mutex);178 return ctx;179 }180 }181 182 fibril_mutex_unlock(&list->mutex);183 return NULL;184 }185 186 187 int188 register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,189 irq_code_t *pseudocode)190 {191 interrupt_context_t *ctx = create_interrupt_context();192 193 ctx->dev = dev;194 ctx->irq = irq;195 ctx->handler = handler;196 197 add_interrupt_context(&interrupt_contexts, ctx);198 199 if (pseudocode == NULL)200 pseudocode = &default_pseudocode;201 202 int res = irq_register(irq, dev->handle, ctx->id, pseudocode);203 if (res != EOK) {204 remove_interrupt_context(&interrupt_contexts, ctx);205 delete_interrupt_context(ctx);206 }207 208 return res;209 }210 211 int unregister_interrupt_handler(ddf_dev_t *dev, int irq)212 {213 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,214 dev, irq);215 int res = irq_unregister(irq, dev->handle);216 217 if (ctx != NULL) {218 remove_interrupt_context(&interrupt_contexts, ctx);219 delete_interrupt_context(ctx);220 }221 222 return res;223 }224 225 84 static void add_to_functions_list(ddf_fun_t *fun) 226 85 { … … 269 128 static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall) 270 129 { 271 char *dev_name = NULL;272 int res;273 274 130 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 275 131 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall); 276 132 277 133 ddf_dev_t *dev = create_device(); 278 134 279 135 /* Add one reference that will be dropped by driver_dev_remove() */ 280 136 dev_add_ref(dev); 281 137 dev->handle = dev_handle; 282 138 139 char *dev_name = NULL; 283 140 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0); 284 141 dev->name = dev_name; 285 142 286 143 /* 287 144 * Currently not used, parent fun handle is stored in context … … 290 147 (void) parent_fun_handle; 291 148 292 res = driver->driver_ops->dev_add(dev);149 int res = driver->driver_ops->dev_add(dev); 293 150 294 151 if (res != EOK) { … … 305 162 } 306 163 307 static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall) 308 { 164 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall) 165 { 166 devman_handle_t devh = IPC_GET_ARG1(*icall); 167 309 168 fibril_mutex_lock(&devices_mutex); 310 ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall)); 311 fibril_mutex_unlock(&devices_mutex); 312 313 if (dev != NULL && driver->driver_ops->device_added != NULL) 314 driver->driver_ops->device_added(dev); 315 } 316 317 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall) 318 { 319 devman_handle_t devh; 320 ddf_dev_t *dev; 321 int rc; 322 323 devh = IPC_GET_ARG1(*icall); 324 325 fibril_mutex_lock(&devices_mutex); 326 dev = driver_get_device(devh); 169 ddf_dev_t *dev = driver_get_device(devh); 327 170 if (dev != NULL) 328 171 dev_add_ref(dev); … … 333 176 return; 334 177 } 178 179 int rc; 335 180 336 181 if (driver->driver_ops->dev_remove != NULL) … … 347 192 static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall) 348 193 { 349 devman_handle_t devh; 350 ddf_dev_t *dev; 351 int rc; 352 353 devh = IPC_GET_ARG1(*icall); 194 devman_handle_t devh = IPC_GET_ARG1(*icall); 354 195 355 196 fibril_mutex_lock(&devices_mutex); 356 d ev = driver_get_device(devh);197 ddf_dev_t *dev = driver_get_device(devh); 357 198 if (dev != NULL) 358 199 dev_add_ref(dev); … … 363 204 return; 364 205 } 206 207 int rc; 365 208 366 209 if (driver->driver_ops->dev_gone != NULL) … … 377 220 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall) 378 221 { 379 devman_handle_t funh; 380 ddf_fun_t *fun; 381 int rc; 382 383 funh = IPC_GET_ARG1(*icall); 222 devman_handle_t funh = IPC_GET_ARG1(*icall); 384 223 385 224 /* … … 390 229 fibril_mutex_lock(&functions_mutex); 391 230 392 fun = driver_get_function(funh);231 ddf_fun_t *fun = driver_get_function(funh); 393 232 if (fun != NULL) 394 233 fun_add_ref(fun); … … 402 241 403 242 /* Call driver entry point */ 243 int rc; 244 404 245 if (driver->driver_ops->fun_online != NULL) 405 246 rc = driver->driver_ops->fun_online(fun); … … 414 255 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 415 256 { 416 devman_handle_t funh; 417 ddf_fun_t *fun; 418 int rc; 419 420 funh = IPC_GET_ARG1(*icall); 257 devman_handle_t funh = IPC_GET_ARG1(*icall); 421 258 422 259 /* … … 427 264 fibril_mutex_lock(&functions_mutex); 428 265 429 fun = driver_get_function(funh);266 ddf_fun_t *fun = driver_get_function(funh); 430 267 if (fun != NULL) 431 268 fun_add_ref(fun); … … 439 276 440 277 /* Call driver entry point */ 278 int rc; 279 441 280 if (driver->driver_ops->fun_offline != NULL) 442 281 rc = driver->driver_ops->fun_offline(fun); … … 462 301 case DRIVER_DEV_ADD: 463 302 driver_dev_add(callid, &call); 464 break;465 case DRIVER_DEV_ADDED:466 async_answer_0(callid, EOK);467 driver_dev_added(callid, &call);468 303 break; 469 304 case DRIVER_DEV_REMOVE: … … 691 526 static void delete_device(ddf_dev_t *dev) 692 527 { 528 if (dev->parent_sess) 529 async_hangup(dev->parent_sess); 693 530 if (dev->driver_data != NULL) 694 531 free(dev->driver_data); … … 753 590 754 591 /** Allocate driver-specific device data. */ 755 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 756 { 757 void *data; 758 592 void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 593 { 759 594 assert(dev->driver_data == NULL); 760 761 data = calloc(1, size);595 596 void *data = calloc(1, size); 762 597 if (data == NULL) 763 598 return NULL; 764 599 765 600 dev->driver_data = data; 766 601 return data; 602 } 603 604 /** Implant foreign driver-specific device data. 605 * 606 * XXX This is used to transition USB to new interface. Do not use 607 * in new code. Use of this function must be removed. 608 */ 609 void ddf_fun_data_implant(ddf_fun_t *fun, void *data) 610 { 611 assert(fun->driver_data == NULL); 612 fun->driver_data = data; 613 } 614 615 /** Return driver-specific device data. */ 616 void *ddf_dev_data_get(ddf_dev_t *dev) 617 { 618 return dev->driver_data; 619 } 620 621 /** Get device handle. */ 622 devman_handle_t ddf_dev_get_handle(ddf_dev_t *dev) 623 { 624 return dev->handle; 625 } 626 627 /** Return device name. 628 * 629 * @param dev Device 630 * @return Device name. Valid as long as @a dev is valid. 631 */ 632 const char *ddf_dev_get_name(ddf_dev_t *dev) 633 { 634 return dev->name; 635 } 636 637 /** Create session with the parent function. 638 * 639 * The session will be automatically closed when @a dev is destroyed. 640 * 641 * @param dev Device 642 * @param mgmt Exchange management style 643 * @return New session or NULL if session could not be created 644 */ 645 async_sess_t *ddf_dev_parent_sess_create(ddf_dev_t *dev, exch_mgmt_t mgmt) 646 { 647 assert(dev->parent_sess == NULL); 648 dev->parent_sess = devman_parent_device_connect(mgmt, dev->handle, 649 IPC_FLAG_BLOCKING); 650 651 return dev->parent_sess; 652 } 653 654 /** Return existing session with the parent function. 655 * 656 * @param dev Device 657 * @return Existing session or NULL if there is no session 658 */ 659 async_sess_t *ddf_dev_parent_sess_get(ddf_dev_t *dev) 660 { 661 return dev->parent_sess; 662 } 663 664 /** Set function name (if it was not specified when node was created.) 665 * 666 * @param dev Device whose name has not been set yet 667 * @param name Name, will be copied 668 * @return EOK on success, ENOMEM if out of memory 669 */ 670 int ddf_fun_set_name(ddf_fun_t *dev, const char *name) 671 { 672 assert(dev->name == NULL); 673 674 dev->name = str_dup(name); 675 if (dev->name == NULL) 676 return ENOENT; 677 678 return EOK; 679 } 680 681 /** Get device to which function belongs. */ 682 ddf_dev_t *ddf_fun_get_dev(ddf_fun_t *fun) 683 { 684 return fun->dev; 685 } 686 687 /** Get function handle. 688 * 689 * XXX USB uses this, but its use should be eliminated. 690 */ 691 devman_handle_t ddf_fun_get_handle(ddf_fun_t *fun) 692 { 693 return fun->handle; 767 694 } 768 695 … … 778 705 * This function should only fail if there is not enough free memory. 779 706 * Specifically, this function succeeds even if @a dev already has 780 * a (bound) function with the same name. 707 * a (bound) function with the same name. @a name can be NULL in which 708 * case the caller will set the name later using ddf_fun_set_name(). 709 * He must do this before binding the function. 781 710 * 782 711 * Type: A function of type fun_inner indicates that DDF should attempt … … 786 715 * @param dev Device to which we are adding function 787 716 * @param ftype Type of function (fun_inner or fun_exposed) 788 * @param name Name of function 717 * @param name Name of function or NULL 789 718 * 790 719 * @return New function or @c NULL if memory is not available … … 792 721 ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name) 793 722 { 794 ddf_fun_t *fun; 795 796 fun = create_function(); 723 ddf_fun_t *fun = create_function(); 797 724 if (fun == NULL) 798 725 return NULL; 799 726 800 727 /* Add one reference that will be dropped by ddf_fun_destroy() */ 801 728 fun->dev = dev; 802 729 fun_add_ref(fun); 803 730 804 731 fun->bound = false; 805 732 fun->ftype = ftype; 806 807 fun->name = str_dup(name); 808 if (fun->name == NULL) { 809 delete_function(fun); 810 return NULL; 811 } 812 733 734 if (name != NULL) { 735 fun->name = str_dup(name); 736 if (fun->name == NULL) { 737 delete_function(fun); 738 return NULL; 739 } 740 } 741 813 742 return fun; 814 743 } 815 744 816 745 /** Allocate driver-specific function data. */ 817 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 818 { 819 void *data; 820 746 void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 747 { 821 748 assert(fun->bound == false); 822 749 assert(fun->driver_data == NULL); 823 824 data = calloc(1, size);750 751 void *data = calloc(1, size); 825 752 if (data == NULL) 826 753 return NULL; 827 754 828 755 fun->driver_data = data; 829 756 return data; 830 757 } 831 758 759 /** Return driver-specific function data. */ 760 void *ddf_fun_data_get(ddf_fun_t *fun) 761 { 762 return fun->driver_data; 763 } 764 765 /** Return function name. 766 * 767 * @param fun Function 768 * @return Function name. Valid as long as @a fun is valid. 769 */ 770 const char *ddf_fun_get_name(ddf_fun_t *fun) 771 { 772 return fun->name; 773 } 774 832 775 /** Destroy DDF function node. 833 776 * … … 835 778 * must not be bound. 836 779 * 837 * @param fun Function to destroy 780 * @param fun Function to destroy 781 * 838 782 */ 839 783 void ddf_fun_destroy(ddf_fun_t *fun) 840 784 { 841 785 assert(fun->bound == false); 842 786 843 787 /* 844 788 * Drop the reference added by ddf_fun_create(). This will deallocate … … 855 799 if (fun->ops == NULL) 856 800 return NULL; 801 857 802 return fun->ops->interfaces[idx]; 858 803 } … … 867 812 * the same name. 868 813 * 869 * @param fun Function to bind 870 * @return EOK on success or negative error code 814 * @param fun Function to bind 815 * 816 * @return EOK on success or negative error code 817 * 871 818 */ 872 819 int ddf_fun_bind(ddf_fun_t *fun) … … 875 822 assert(fun->name != NULL); 876 823 877 int res;878 879 824 add_to_functions_list(fun); 880 res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,825 int res = devman_add_function(fun->name, fun->ftype, &fun->match_ids, 881 826 fun->dev->handle, &fun->handle); 882 827 if (res != EOK) { … … 894 839 * the function invisible to the system. 895 840 * 896 * @param fun Function to unbind 897 * @return EOK on success or negative error code 841 * @param fun Function to unbind 842 * 843 * @return EOK on success or negative error code 844 * 898 845 */ 899 846 int ddf_fun_unbind(ddf_fun_t *fun) 900 847 { 901 int res;902 903 848 assert(fun->bound == true); 904 849 905 res = devman_remove_function(fun->handle);850 int res = devman_remove_function(fun->handle); 906 851 if (res != EOK) 907 852 return res; 908 853 909 854 remove_from_functions_list(fun); 910 855 … … 915 860 /** Online function. 916 861 * 917 * @param fun Function to online 918 * @return EOK on success or negative error code 862 * @param fun Function to online 863 * 864 * @return EOK on success or negative error code 865 * 919 866 */ 920 867 int ddf_fun_online(ddf_fun_t *fun) 921 868 { 922 int res;923 924 869 assert(fun->bound == true); 925 870 926 res = devman_drv_fun_online(fun->handle);871 int res = devman_drv_fun_online(fun->handle); 927 872 if (res != EOK) 928 873 return res; … … 933 878 /** Offline function. 934 879 * 935 * @param fun Function to offline 936 * @return EOK on success or negative error code 880 * @param fun Function to offline 881 * 882 * @return EOK on success or negative error code 883 * 937 884 */ 938 885 int ddf_fun_offline(ddf_fun_t *fun) 939 886 { 940 int res;941 942 887 assert(fun->bound == true); 943 888 944 res = devman_drv_fun_offline(fun->handle);889 int res = devman_drv_fun_offline(fun->handle); 945 890 if (res != EOK) 946 891 return res; … … 954 899 * Cannot be called when the function node is bound. 955 900 * 956 * @param fun Function 957 * @param match_id_str Match string 958 * @param match_score Match score 959 * @return EOK on success, ENOMEM if out of memory. 901 * @param fun Function 902 * @param match_id_str Match string 903 * @param match_score Match score 904 * 905 * @return EOK on success. 906 * @return ENOMEM if out of memory. 907 * 960 908 */ 961 909 int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str, 962 910 int match_score) 963 911 { 964 match_id_t *match_id;965 966 912 assert(fun->bound == false); 967 913 assert(fun->ftype == fun_inner); 968 914 969 match_id = create_match_id();915 match_id_t *match_id = create_match_id(); 970 916 if (match_id == NULL) 971 917 return ENOMEM; … … 976 922 add_match_id(&fun->match_ids, match_id); 977 923 return EOK; 924 } 925 926 /** Set function ops. */ 927 void ddf_fun_set_ops(ddf_fun_t *fun, ddf_dev_ops_t *dev_ops) 928 { 929 assert(fun->conn_handler == NULL); 930 fun->ops = dev_ops; 931 } 932 933 /** Set user-defined connection handler. 934 * 935 * This allows handling connections the non-devman way. 936 */ 937 void ddf_fun_set_conn_handler(ddf_fun_t *fun, async_client_conn_t conn) 938 { 939 assert(fun->ops == NULL); 940 fun->conn_handler = conn; 978 941 } 979 942 … … 989 952 * 990 953 * Must only be called when the function is bound. 954 * 991 955 */ 992 956 int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name) … … 1000 964 int ddf_driver_main(driver_t *drv) 1001 965 { 1002 int rc;1003 1004 966 /* 1005 967 * Remember the driver structure - driver_ops will be called by generic … … 1008 970 driver = drv; 1009 971 1010 /* Initialize the list of interrupt contexts. */ 1011 init_interrupt_context_list(&interrupt_contexts); 1012 1013 /* Set generic interrupt handler. */ 1014 async_set_interrupt_received(driver_irq_handler); 972 /* Initialize interrupt module */ 973 interrupt_init(); 1015 974 1016 975 /* … … 1019 978 */ 1020 979 async_set_client_connection(driver_connection); 1021 rc = devman_driver_register(driver->name);980 int rc = devman_driver_register(driver->name); 1022 981 if (rc != EOK) { 1023 982 printf("Error: Failed to register driver with device manager " … … 1025 984 str_error(rc)); 1026 985 1027 return 1;986 return rc; 1028 987 } 1029 988 … … 1031 990 rc = task_retval(0); 1032 991 if (rc != EOK) 1033 return 1;1034 992 return rc; 993 1035 994 async_manager(); 1036 995 1037 996 /* Never reached. */ 1038 return 0;997 return EOK; 1039 998 } 1040 999
Note:
See TracChangeset
for help on using the changeset viewer.