Changeset 00aece0 in mainline for uspace/lib/drv/generic/driver.c
- Timestamp:
- 2012-02-18T16:47:38Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 4449c6c
- Parents:
- bd5f3b7 (diff), f943dd3 (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
-
uspace/lib/drv/generic/driver.c (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
rbd5f3b7 r00aece0 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); 67 71 68 /** Interrupts */69 static interrupt_context_list_t interrupt_contexts;70 71 static irq_cmd_t default_cmds[] = {72 {73 .cmd = CMD_ACCEPT74 }75 };76 77 static irq_code_t default_pseudocode = {78 sizeof(default_cmds) / sizeof(irq_cmd_t),79 default_cmds80 };81 82 72 static ddf_dev_t *create_device(void); 83 73 static void delete_device(ddf_dev_t *); 74 static void dev_add_ref(ddf_dev_t *); 75 static void dev_del_ref(ddf_dev_t *); 76 static void fun_add_ref(ddf_fun_t *); 77 static void fun_del_ref(ddf_fun_t *); 84 78 static remote_handler_t *function_get_default_handler(ddf_fun_t *); 85 79 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t); 86 87 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)88 {89 int id = (int)IPC_GET_IMETHOD(*icall);90 interrupt_context_t *ctx;91 92 ctx = find_interrupt_context_by_id(&interrupt_contexts, id);93 if (ctx != NULL && ctx->handler != NULL)94 (*ctx->handler)(ctx->dev, iid, icall);95 }96 97 interrupt_context_t *create_interrupt_context(void)98 {99 interrupt_context_t *ctx;100 101 ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));102 if (ctx != NULL)103 memset(ctx, 0, sizeof(interrupt_context_t));104 105 return ctx;106 }107 108 void delete_interrupt_context(interrupt_context_t *ctx)109 {110 if (ctx != NULL)111 free(ctx);112 }113 114 void init_interrupt_context_list(interrupt_context_list_t *list)115 {116 memset(list, 0, sizeof(interrupt_context_list_t));117 fibril_mutex_initialize(&list->mutex);118 list_initialize(&list->contexts);119 }120 121 void122 add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)123 {124 fibril_mutex_lock(&list->mutex);125 ctx->id = list->curr_id++;126 list_append(&ctx->link, &list->contexts);127 fibril_mutex_unlock(&list->mutex);128 }129 130 void remove_interrupt_context(interrupt_context_list_t *list,131 interrupt_context_t *ctx)132 {133 fibril_mutex_lock(&list->mutex);134 list_remove(&ctx->link);135 fibril_mutex_unlock(&list->mutex);136 }137 138 interrupt_context_t *139 find_interrupt_context_by_id(interrupt_context_list_t *list, int id)140 {141 interrupt_context_t *ctx;142 143 fibril_mutex_lock(&list->mutex);144 145 list_foreach(list->contexts, link) {146 ctx = list_get_instance(link, interrupt_context_t, link);147 if (ctx->id == id) {148 fibril_mutex_unlock(&list->mutex);149 return ctx;150 }151 }152 153 fibril_mutex_unlock(&list->mutex);154 return NULL;155 }156 157 interrupt_context_t *158 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)159 {160 interrupt_context_t *ctx;161 162 fibril_mutex_lock(&list->mutex);163 164 list_foreach(list->contexts, link) {165 ctx = list_get_instance(link, interrupt_context_t, link);166 if (ctx->irq == irq && ctx->dev == dev) {167 fibril_mutex_unlock(&list->mutex);168 return ctx;169 }170 }171 172 fibril_mutex_unlock(&list->mutex);173 return NULL;174 }175 176 177 int178 register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,179 irq_code_t *pseudocode)180 {181 interrupt_context_t *ctx = create_interrupt_context();182 183 ctx->dev = dev;184 ctx->irq = irq;185 ctx->handler = handler;186 187 add_interrupt_context(&interrupt_contexts, ctx);188 189 if (pseudocode == NULL)190 pseudocode = &default_pseudocode;191 192 int res = register_irq(irq, dev->handle, ctx->id, pseudocode);193 if (res != EOK) {194 remove_interrupt_context(&interrupt_contexts, ctx);195 delete_interrupt_context(ctx);196 }197 198 return res;199 }200 201 int unregister_interrupt_handler(ddf_dev_t *dev, int irq)202 {203 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,204 dev, irq);205 int res = unregister_irq(irq, dev->handle);206 207 if (ctx != NULL) {208 remove_interrupt_context(&interrupt_contexts, ctx);209 delete_interrupt_context(ctx);210 }211 212 return res;213 }214 80 215 81 static void add_to_functions_list(ddf_fun_t *fun) … … 227 93 } 228 94 229 static ddf_fun_t *driver_get_function(list_t *functions, devman_handle_t handle) 95 static ddf_dev_t *driver_get_device(devman_handle_t handle) 96 { 97 ddf_dev_t *dev = NULL; 98 99 assert(fibril_mutex_is_locked(&devices_mutex)); 100 101 list_foreach(devices, link) { 102 dev = list_get_instance(link, ddf_dev_t, link); 103 if (dev->handle == handle) 104 return dev; 105 } 106 107 return NULL; 108 } 109 110 static ddf_fun_t *driver_get_function(devman_handle_t handle) 230 111 { 231 112 ddf_fun_t *fun = NULL; 232 113 233 fibril_mutex_lock(&functions_mutex);234 235 list_foreach( *functions, link) {114 assert(fibril_mutex_is_locked(&functions_mutex)); 115 116 list_foreach(functions, link) { 236 117 fun = list_get_instance(link, ddf_fun_t, link); 237 if (fun->handle == handle) { 238 fibril_mutex_unlock(&functions_mutex); 118 if (fun->handle == handle) 239 119 return fun; 240 } 241 } 242 243 fibril_mutex_unlock(&functions_mutex); 120 } 244 121 245 122 return NULL; 246 123 } 247 124 248 static void driver_ add_device(ipc_callid_t iid, ipc_call_t *icall)125 static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall) 249 126 { 250 127 char *dev_name = NULL; … … 252 129 253 130 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 254 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);131 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall); 255 132 256 133 ddf_dev_t *dev = create_device(); 134 135 /* Add one reference that will be dropped by driver_dev_remove() */ 136 dev_add_ref(dev); 257 137 dev->handle = dev_handle; 258 138 … … 266 146 (void) parent_fun_handle; 267 147 268 res = driver->driver_ops->add_device(dev); 269 if (res != EOK) 270 delete_device(dev); 148 res = driver->driver_ops->dev_add(dev); 149 150 if (res != EOK) { 151 dev_del_ref(dev); 152 async_answer_0(iid, res); 153 return; 154 } 155 156 fibril_mutex_lock(&devices_mutex); 157 list_append(&dev->link, &devices); 158 fibril_mutex_unlock(&devices_mutex); 271 159 272 160 async_answer_0(iid, res); 161 } 162 163 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall) 164 { 165 devman_handle_t devh; 166 ddf_dev_t *dev; 167 int rc; 168 169 devh = IPC_GET_ARG1(*icall); 170 171 fibril_mutex_lock(&devices_mutex); 172 dev = driver_get_device(devh); 173 if (dev != NULL) 174 dev_add_ref(dev); 175 fibril_mutex_unlock(&devices_mutex); 176 177 if (dev == NULL) { 178 async_answer_0(iid, ENOENT); 179 return; 180 } 181 182 if (driver->driver_ops->dev_remove != NULL) 183 rc = driver->driver_ops->dev_remove(dev); 184 else 185 rc = ENOTSUP; 186 187 if (rc == EOK) 188 dev_del_ref(dev); 189 190 async_answer_0(iid, (sysarg_t) rc); 191 } 192 193 static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall) 194 { 195 devman_handle_t devh; 196 ddf_dev_t *dev; 197 int rc; 198 199 devh = IPC_GET_ARG1(*icall); 200 201 fibril_mutex_lock(&devices_mutex); 202 dev = driver_get_device(devh); 203 if (dev != NULL) 204 dev_add_ref(dev); 205 fibril_mutex_unlock(&devices_mutex); 206 207 if (dev == NULL) { 208 async_answer_0(iid, ENOENT); 209 return; 210 } 211 212 if (driver->driver_ops->dev_gone != NULL) 213 rc = driver->driver_ops->dev_gone(dev); 214 else 215 rc = ENOTSUP; 216 217 if (rc == EOK) 218 dev_del_ref(dev); 219 220 async_answer_0(iid, (sysarg_t) rc); 221 } 222 223 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall) 224 { 225 devman_handle_t funh; 226 ddf_fun_t *fun; 227 int rc; 228 229 funh = IPC_GET_ARG1(*icall); 230 231 /* 232 * Look the function up. Bump reference count so that 233 * the function continues to exist until we return 234 * from the driver. 235 */ 236 fibril_mutex_lock(&functions_mutex); 237 238 fun = driver_get_function(funh); 239 if (fun != NULL) 240 fun_add_ref(fun); 241 242 fibril_mutex_unlock(&functions_mutex); 243 244 if (fun == NULL) { 245 async_answer_0(iid, ENOENT); 246 return; 247 } 248 249 /* Call driver entry point */ 250 if (driver->driver_ops->fun_online != NULL) 251 rc = driver->driver_ops->fun_online(fun); 252 else 253 rc = ENOTSUP; 254 255 fun_del_ref(fun); 256 257 async_answer_0(iid, (sysarg_t) rc); 258 } 259 260 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 261 { 262 devman_handle_t funh; 263 ddf_fun_t *fun; 264 int rc; 265 266 funh = IPC_GET_ARG1(*icall); 267 268 /* 269 * Look the function up. Bump reference count so that 270 * the function continues to exist until we return 271 * from the driver. 272 */ 273 fibril_mutex_lock(&functions_mutex); 274 275 fun = driver_get_function(funh); 276 if (fun != NULL) 277 fun_add_ref(fun); 278 279 fibril_mutex_unlock(&functions_mutex); 280 281 if (fun == NULL) { 282 async_answer_0(iid, ENOENT); 283 return; 284 } 285 286 /* Call driver entry point */ 287 if (driver->driver_ops->fun_offline != NULL) 288 rc = driver->driver_ops->fun_offline(fun); 289 else 290 rc = ENOTSUP; 291 292 async_answer_0(iid, (sysarg_t) rc); 273 293 } 274 294 … … 286 306 287 307 switch (IPC_GET_IMETHOD(call)) { 288 case DRIVER_ADD_DEVICE: 289 driver_add_device(callid, &call); 308 case DRIVER_DEV_ADD: 309 driver_dev_add(callid, &call); 310 break; 311 case DRIVER_DEV_REMOVE: 312 driver_dev_remove(callid, &call); 313 break; 314 case DRIVER_DEV_GONE: 315 driver_dev_gone(callid, &call); 316 break; 317 case DRIVER_FUN_ONLINE: 318 driver_fun_online(callid, &call); 319 break; 320 case DRIVER_FUN_OFFLINE: 321 driver_fun_offline(callid, &call); 290 322 break; 291 323 default: 292 async_answer_0(callid, ENO ENT);324 async_answer_0(callid, ENOTSUP); 293 325 } 294 326 } … … 308 340 */ 309 341 devman_handle_t handle = IPC_GET_ARG2(*icall); 310 ddf_fun_t *fun = driver_get_function(&functions, handle); 342 343 fibril_mutex_lock(&functions_mutex); 344 ddf_fun_t *fun = driver_get_function(handle); 345 fibril_mutex_unlock(&functions_mutex); 346 /* XXX Need a lock on fun */ 311 347 312 348 if (fun == NULL) { … … 466 502 ddf_dev_t *dev; 467 503 468 dev = malloc(sizeof(ddf_dev_t));504 dev = calloc(1, sizeof(ddf_dev_t)); 469 505 if (dev == NULL) 470 506 return NULL; 471 507 472 memset(dev, 0, sizeof(ddf_dev_t));473 508 return dev; 474 509 } … … 498 533 static void delete_device(ddf_dev_t *dev) 499 534 { 535 if (dev->driver_data != NULL) 536 free(dev->driver_data); 500 537 free(dev); 501 538 } 502 539 503 /** Delete devicestructure.540 /** Delete function structure. 504 541 * 505 542 * @param dev The device structure. … … 508 545 { 509 546 clean_match_ids(&fun->match_ids); 547 if (fun->driver_data != NULL) 548 free(fun->driver_data); 510 549 if (fun->name != NULL) 511 550 free(fun->name); … … 513 552 } 514 553 554 /** Increase device reference count. */ 555 static void dev_add_ref(ddf_dev_t *dev) 556 { 557 atomic_inc(&dev->refcnt); 558 } 559 560 /** Decrease device reference count. 561 * 562 * Free the device structure if the reference count drops to zero. 563 */ 564 static void dev_del_ref(ddf_dev_t *dev) 565 { 566 if (atomic_predec(&dev->refcnt) == 0) 567 delete_device(dev); 568 } 569 570 /** Increase function reference count. 571 * 572 * This also increases reference count on the device. The device structure 573 * will thus not be deallocated while there are some associated function 574 * structures. 575 */ 576 static void fun_add_ref(ddf_fun_t *fun) 577 { 578 dev_add_ref(fun->dev); 579 atomic_inc(&fun->refcnt); 580 } 581 582 /** Decrease function reference count. 583 * 584 * Free the function structure if the reference count drops to zero. 585 */ 586 static void fun_del_ref(ddf_fun_t *fun) 587 { 588 ddf_dev_t *dev = fun->dev; 589 590 if (atomic_predec(&fun->refcnt) == 0) 591 delete_function(fun); 592 593 dev_del_ref(dev); 594 } 595 596 /** Allocate driver-specific device data. */ 597 void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 598 { 599 void *data; 600 601 assert(dev->driver_data == NULL); 602 603 data = calloc(1, size); 604 if (data == NULL) 605 return NULL; 606 607 dev->driver_data = data; 608 return data; 609 } 610 515 611 /** Create a DDF function node. 516 612 * … … 544 640 return NULL; 545 641 642 /* Add one reference that will be dropped by ddf_fun_destroy() */ 643 fun->dev = dev; 644 fun_add_ref(fun); 645 546 646 fun->bound = false; 547 fun->dev = dev;548 647 fun->ftype = ftype; 549 648 … … 557 656 } 558 657 658 /** Allocate driver-specific function data. */ 659 void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 660 { 661 void *data; 662 663 assert(fun->bound == false); 664 assert(fun->driver_data == NULL); 665 666 data = calloc(1, size); 667 if (data == NULL) 668 return NULL; 669 670 fun->driver_data = data; 671 return data; 672 } 673 559 674 /** Destroy DDF function node. 560 675 * … … 567 682 { 568 683 assert(fun->bound == false); 569 delete_function(fun); 684 685 /* 686 * Drop the reference added by ddf_fun_create(). This will deallocate 687 * the function as soon as all other references are dropped (i.e. 688 * as soon control leaves all driver entry points called in context 689 * of this function. 690 */ 691 fun_del_ref(fun); 570 692 } 571 693 … … 614 736 * the function invisible to the system. 615 737 * 616 * @param fun Function to bind738 * @param fun Function to unbind 617 739 * @return EOK on success or negative error code 618 740 */ … … 623 745 assert(fun->bound == true); 624 746 625 add_to_functions_list(fun);626 747 res = devman_remove_function(fun->handle); 627 748 if (res != EOK) … … 631 752 632 753 fun->bound = false; 754 return EOK; 755 } 756 757 /** Online function. 758 * 759 * @param fun Function to online 760 * @return EOK on success or negative error code 761 */ 762 int ddf_fun_online(ddf_fun_t *fun) 763 { 764 int res; 765 766 assert(fun->bound == true); 767 768 res = devman_drv_fun_online(fun->handle); 769 if (res != EOK) 770 return res; 771 772 return EOK; 773 } 774 775 /** Offline function. 776 * 777 * @param fun Function to offline 778 * @return EOK on success or negative error code 779 */ 780 int ddf_fun_offline(ddf_fun_t *fun) 781 { 782 int res; 783 784 assert(fun->bound == true); 785 786 res = devman_drv_fun_offline(fun->handle); 787 if (res != EOK) 788 return res; 789 633 790 return EOK; 634 791 } … … 657 814 658 815 match_id->id = str_dup(match_id_str); 659 match_id->score = 90;816 match_id->score = match_score; 660 817 661 818 add_match_id(&fun->match_ids, match_id); … … 693 850 driver = drv; 694 851 695 /* Initialize the list of interrupt contexts. */ 696 init_interrupt_context_list(&interrupt_contexts); 697 698 /* Set generic interrupt handler. */ 699 async_set_interrupt_received(driver_irq_handler); 852 /* Initialize interrupt module */ 853 interrupt_init(); 700 854 701 855 /* … … 703 857 * incoming connections. 704 858 */ 705 rc = devman_driver_register(driver->name, driver_connection); 859 async_set_client_connection(driver_connection); 860 rc = devman_driver_register(driver->name); 706 861 if (rc != EOK) { 707 862 printf("Error: Failed to register driver with device manager "
Note:
See TracChangeset
for help on using the changeset viewer.
