Changes in uspace/lib/drv/generic/driver.c [3e6a98c5:a996ae31] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r3e6a98c5 ra996ae31 37 37 */ 38 38 39 #define _DDF_DATA_IMPLANT40 41 39 #include <assert.h> 42 40 #include <ipc/services.h> … … 45 43 #include <stdio.h> 46 44 #include <errno.h> 47 #include < stdbool.h>45 #include <bool.h> 48 46 #include <fibril_synch.h> 49 47 #include <stdlib.h> … … 60 58 #include "ddf/driver.h" 61 59 #include "ddf/interrupt.h" 62 #include "private/driver.h"63 60 64 61 /** Driver structure */ … … 72 69 LIST_INITIALIZE(functions); 73 70 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_ACCEPT 78 } 79 }; 80 81 static irq_code_t default_pseudocode = { 82 0, 83 NULL, 84 sizeof(default_cmds) / sizeof(irq_cmd_t), 85 default_cmds 86 }; 74 87 75 88 static ddf_dev_t *create_device(void); … … 82 95 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t); 83 96 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 void 132 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 int 188 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 84 225 static void add_to_functions_list(ddf_fun_t *fun) 85 226 { … … 128 269 static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall) 129 270 { 271 char *dev_name = NULL; 272 int res; 273 130 274 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 131 275 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall); 132 276 133 277 ddf_dev_t *dev = create_device(); 134 278 135 279 /* Add one reference that will be dropped by driver_dev_remove() */ 136 280 dev_add_ref(dev); 137 281 dev->handle = dev_handle; 138 139 char *dev_name = NULL; 282 140 283 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0); 141 284 dev->name = dev_name; 142 285 143 286 /* 144 287 * Currently not used, parent fun handle is stored in context … … 147 290 (void) parent_fun_handle; 148 291 149 intres = driver->driver_ops->dev_add(dev);292 res = driver->driver_ops->dev_add(dev); 150 293 151 294 if (res != EOK) { … … 162 305 } 163 306 307 static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall) 308 { 309 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 164 317 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall) 165 318 { 166 devman_handle_t devh = IPC_GET_ARG1(*icall); 319 devman_handle_t devh; 320 ddf_dev_t *dev; 321 int rc; 322 323 devh = IPC_GET_ARG1(*icall); 167 324 168 325 fibril_mutex_lock(&devices_mutex); 169 d df_dev_t *dev = driver_get_device(devh);326 dev = driver_get_device(devh); 170 327 if (dev != NULL) 171 328 dev_add_ref(dev); … … 176 333 return; 177 334 } 178 179 int rc;180 335 181 336 if (driver->driver_ops->dev_remove != NULL) … … 192 347 static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall) 193 348 { 194 devman_handle_t devh = IPC_GET_ARG1(*icall); 349 devman_handle_t devh; 350 ddf_dev_t *dev; 351 int rc; 352 353 devh = IPC_GET_ARG1(*icall); 195 354 196 355 fibril_mutex_lock(&devices_mutex); 197 d df_dev_t *dev = driver_get_device(devh);356 dev = driver_get_device(devh); 198 357 if (dev != NULL) 199 358 dev_add_ref(dev); … … 204 363 return; 205 364 } 206 207 int rc;208 365 209 366 if (driver->driver_ops->dev_gone != NULL) … … 220 377 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall) 221 378 { 222 devman_handle_t funh = IPC_GET_ARG1(*icall); 379 devman_handle_t funh; 380 ddf_fun_t *fun; 381 int rc; 382 383 funh = IPC_GET_ARG1(*icall); 223 384 224 385 /* … … 229 390 fibril_mutex_lock(&functions_mutex); 230 391 231 ddf_fun_t *fun = driver_get_function(funh);392 fun = driver_get_function(funh); 232 393 if (fun != NULL) 233 394 fun_add_ref(fun); … … 241 402 242 403 /* Call driver entry point */ 243 int rc;244 245 404 if (driver->driver_ops->fun_online != NULL) 246 405 rc = driver->driver_ops->fun_online(fun); … … 255 414 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 256 415 { 257 devman_handle_t funh = IPC_GET_ARG1(*icall); 416 devman_handle_t funh; 417 ddf_fun_t *fun; 418 int rc; 419 420 funh = IPC_GET_ARG1(*icall); 258 421 259 422 /* … … 264 427 fibril_mutex_lock(&functions_mutex); 265 428 266 ddf_fun_t *fun = driver_get_function(funh);429 fun = driver_get_function(funh); 267 430 if (fun != NULL) 268 431 fun_add_ref(fun); … … 276 439 277 440 /* Call driver entry point */ 278 int rc;279 280 441 if (driver->driver_ops->fun_offline != NULL) 281 442 rc = driver->driver_ops->fun_offline(fun); … … 301 462 case DRIVER_DEV_ADD: 302 463 driver_dev_add(callid, &call); 464 break; 465 case DRIVER_DEV_ADDED: 466 async_answer_0(callid, EOK); 467 driver_dev_added(callid, &call); 303 468 break; 304 469 case DRIVER_DEV_REMOVE: … … 526 691 static void delete_device(ddf_dev_t *dev) 527 692 { 528 if (dev->parent_sess)529 async_hangup(dev->parent_sess);530 693 if (dev->driver_data != NULL) 531 694 free(dev->driver_data); … … 590 753 591 754 /** Allocate driver-specific device data. */ 592 void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 593 { 755 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 756 { 757 void *data; 758 594 759 assert(dev->driver_data == NULL); 595 596 void *data = calloc(1, size);760 761 data = calloc(1, size); 597 762 if (data == NULL) 598 763 return NULL; 599 764 600 765 dev->driver_data = data; 601 766 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 use607 * 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 Device630 * @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 Device642 * @param mgmt Exchange management style643 * @return New session or NULL if session could not be created644 */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 Device657 * @return Existing session or NULL if there is no session658 */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 yet667 * @param name Name, will be copied668 * @return EOK on success, ENOMEM if out of memory669 */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;694 767 } 695 768 … … 705 778 * This function should only fail if there is not enough free memory. 706 779 * Specifically, this function succeeds even if @a dev already has 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. 780 * a (bound) function with the same name. 710 781 * 711 782 * Type: A function of type fun_inner indicates that DDF should attempt … … 715 786 * @param dev Device to which we are adding function 716 787 * @param ftype Type of function (fun_inner or fun_exposed) 717 * @param name Name of function or NULL788 * @param name Name of function 718 789 * 719 790 * @return New function or @c NULL if memory is not available … … 721 792 ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name) 722 793 { 723 ddf_fun_t *fun = create_function(); 794 ddf_fun_t *fun; 795 796 fun = create_function(); 724 797 if (fun == NULL) 725 798 return NULL; 726 799 727 800 /* Add one reference that will be dropped by ddf_fun_destroy() */ 728 801 fun->dev = dev; 729 802 fun_add_ref(fun); 730 803 731 804 fun->bound = false; 732 805 fun->ftype = ftype; 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 806 807 fun->name = str_dup(name); 808 if (fun->name == NULL) { 809 delete_function(fun); 810 return NULL; 811 } 812 742 813 return fun; 743 814 } 744 815 745 816 /** Allocate driver-specific function data. */ 746 void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 747 { 817 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 818 { 819 void *data; 820 748 821 assert(fun->bound == false); 749 822 assert(fun->driver_data == NULL); 750 751 void *data = calloc(1, size);823 824 data = calloc(1, size); 752 825 if (data == NULL) 753 826 return NULL; 754 827 755 828 fun->driver_data = data; 756 829 return data; 757 830 } 758 831 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 Function768 * @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 775 832 /** Destroy DDF function node. 776 833 * … … 778 835 * must not be bound. 779 836 * 780 * @param fun Function to destroy 781 * 837 * @param fun Function to destroy 782 838 */ 783 839 void ddf_fun_destroy(ddf_fun_t *fun) 784 840 { 785 841 assert(fun->bound == false); 786 842 787 843 /* 788 844 * Drop the reference added by ddf_fun_create(). This will deallocate … … 799 855 if (fun->ops == NULL) 800 856 return NULL; 801 802 857 return fun->ops->interfaces[idx]; 803 858 } … … 812 867 * the same name. 813 868 * 814 * @param fun Function to bind 815 * 816 * @return EOK on success or negative error code 817 * 869 * @param fun Function to bind 870 * @return EOK on success or negative error code 818 871 */ 819 872 int ddf_fun_bind(ddf_fun_t *fun) … … 822 875 assert(fun->name != NULL); 823 876 877 int res; 878 824 879 add_to_functions_list(fun); 825 intres = devman_add_function(fun->name, fun->ftype, &fun->match_ids,880 res = devman_add_function(fun->name, fun->ftype, &fun->match_ids, 826 881 fun->dev->handle, &fun->handle); 827 882 if (res != EOK) { … … 839 894 * the function invisible to the system. 840 895 * 841 * @param fun Function to unbind 842 * 843 * @return EOK on success or negative error code 844 * 896 * @param fun Function to unbind 897 * @return EOK on success or negative error code 845 898 */ 846 899 int ddf_fun_unbind(ddf_fun_t *fun) 847 900 { 901 int res; 902 848 903 assert(fun->bound == true); 849 904 850 intres = devman_remove_function(fun->handle);905 res = devman_remove_function(fun->handle); 851 906 if (res != EOK) 852 907 return res; 853 908 854 909 remove_from_functions_list(fun); 855 910 … … 860 915 /** Online function. 861 916 * 862 * @param fun Function to online 863 * 864 * @return EOK on success or negative error code 865 * 917 * @param fun Function to online 918 * @return EOK on success or negative error code 866 919 */ 867 920 int ddf_fun_online(ddf_fun_t *fun) 868 921 { 922 int res; 923 869 924 assert(fun->bound == true); 870 925 871 intres = devman_drv_fun_online(fun->handle);926 res = devman_drv_fun_online(fun->handle); 872 927 if (res != EOK) 873 928 return res; … … 878 933 /** Offline function. 879 934 * 880 * @param fun Function to offline 881 * 882 * @return EOK on success or negative error code 883 * 935 * @param fun Function to offline 936 * @return EOK on success or negative error code 884 937 */ 885 938 int ddf_fun_offline(ddf_fun_t *fun) 886 939 { 940 int res; 941 887 942 assert(fun->bound == true); 888 943 889 intres = devman_drv_fun_offline(fun->handle);944 res = devman_drv_fun_offline(fun->handle); 890 945 if (res != EOK) 891 946 return res; … … 899 954 * Cannot be called when the function node is bound. 900 955 * 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 * 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. 908 960 */ 909 961 int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str, 910 962 int match_score) 911 963 { 964 match_id_t *match_id; 965 912 966 assert(fun->bound == false); 913 967 assert(fun->ftype == fun_inner); 914 968 915 match_id _t *match_id= create_match_id();969 match_id = create_match_id(); 916 970 if (match_id == NULL) 917 971 return ENOMEM; … … 922 976 add_match_id(&fun->match_ids, match_id); 923 977 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;941 978 } 942 979 … … 952 989 * 953 990 * Must only be called when the function is bound. 954 *955 991 */ 956 992 int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name) … … 964 1000 int ddf_driver_main(driver_t *drv) 965 1001 { 1002 int rc; 1003 966 1004 /* 967 1005 * Remember the driver structure - driver_ops will be called by generic … … 970 1008 driver = drv; 971 1009 972 /* Initialize interrupt module */ 973 interrupt_init(); 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); 974 1015 975 1016 /* … … 978 1019 */ 979 1020 async_set_client_connection(driver_connection); 980 intrc = devman_driver_register(driver->name);1021 rc = devman_driver_register(driver->name); 981 1022 if (rc != EOK) { 982 1023 printf("Error: Failed to register driver with device manager " … … 984 1025 str_error(rc)); 985 1026 986 return rc;1027 return 1; 987 1028 } 988 1029 … … 990 1031 rc = task_retval(0); 991 1032 if (rc != EOK) 992 return rc;993 1033 return 1; 1034 994 1035 async_manager(); 995 1036 996 1037 /* Never reached. */ 997 return EOK;1038 return 0; 998 1039 } 999 1040
Note:
See TracChangeset
for help on using the changeset viewer.