Changes in uspace/lib/drv/generic/driver.c [79a141a:f278930] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r79a141a rf278930 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; … … 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_remove(ipc_callid_t iid, ipc_call_t *icall) 306 { 307 devman_handle_t devh; 308 ddf_dev_t *dev; 309 int rc; 310 311 devh = IPC_GET_ARG1(*icall); 312 313 fibril_mutex_lock(&devices_mutex); 314 dev = driver_get_device(devh); 315 if (dev != NULL) 316 dev_add_ref(dev); 317 fibril_mutex_unlock(&devices_mutex); 318 319 if (dev == NULL) { 320 async_answer_0(iid, ENOENT); 321 return; 322 } 323 324 if (driver->driver_ops->dev_remove != NULL) 325 rc = driver->driver_ops->dev_remove(dev); 326 else 327 rc = ENOTSUP; 328 329 if (rc == EOK) 330 dev_del_ref(dev); 331 332 async_answer_0(iid, (sysarg_t) rc); 333 } 334 335 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall) 336 { 337 devman_handle_t funh; 338 ddf_fun_t *fun; 339 int rc; 340 341 funh = IPC_GET_ARG1(*icall); 342 343 /* 344 * Look the function up. Bump reference count so that 345 * the function continues to exist until we return 346 * from the driver. 347 */ 348 fibril_mutex_lock(&functions_mutex); 349 350 fun = driver_get_function(funh); 351 if (fun != NULL) 352 fun_add_ref(fun); 353 354 fibril_mutex_unlock(&functions_mutex); 355 356 if (fun == NULL) { 357 async_answer_0(iid, ENOENT); 358 return; 359 } 360 361 /* Call driver entry point */ 362 if (driver->driver_ops->fun_online != NULL) 363 rc = driver->driver_ops->fun_online(fun); 364 else 365 rc = ENOTSUP; 366 367 fun_del_ref(fun); 368 369 async_answer_0(iid, (sysarg_t) rc); 370 } 371 372 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 373 { 374 devman_handle_t funh; 375 ddf_fun_t *fun; 376 int rc; 377 378 funh = IPC_GET_ARG1(*icall); 379 380 /* 381 * Look the function up. Bump reference count so that 382 * the function continues to exist until we return 383 * from the driver. 384 */ 385 fibril_mutex_lock(&functions_mutex); 386 387 fun = driver_get_function(funh); 388 if (fun != NULL) 389 fun_add_ref(fun); 390 391 fibril_mutex_unlock(&functions_mutex); 392 393 if (fun == NULL) { 394 async_answer_0(iid, ENOENT); 395 return; 396 } 397 398 /* Call driver entry point */ 399 if (driver->driver_ops->fun_offline != NULL) 400 rc = driver->driver_ops->fun_offline(fun); 401 else 402 rc = ENOTSUP; 403 404 async_answer_0(iid, (sysarg_t) rc); 280 405 } 281 406 … … 293 418 294 419 switch (IPC_GET_IMETHOD(call)) { 295 case DRIVER_ADD_DEVICE: 296 driver_add_device(callid, &call); 420 case DRIVER_DEV_ADD: 421 driver_dev_add(callid, &call); 422 break; 423 case DRIVER_DEV_REMOVE: 424 driver_dev_remove(callid, &call); 425 break; 426 case DRIVER_FUN_ONLINE: 427 driver_fun_online(callid, &call); 428 break; 429 case DRIVER_FUN_OFFLINE: 430 driver_fun_offline(callid, &call); 297 431 break; 298 432 default: 299 async_answer_0(callid, ENO ENT);433 async_answer_0(callid, ENOTSUP); 300 434 } 301 435 } … … 315 449 */ 316 450 devman_handle_t handle = IPC_GET_ARG2(*icall); 317 ddf_fun_t *fun = driver_get_function(&functions, handle); 451 452 fibril_mutex_lock(&functions_mutex); 453 ddf_fun_t *fun = driver_get_function(handle); 454 fibril_mutex_unlock(&functions_mutex); 455 /* XXX Need a lock on fun */ 318 456 319 457 if (fun == NULL) { … … 321 459 " %" PRIun " was found.\n", driver->name, handle); 322 460 async_answer_0(iid, ENOENT); 461 return; 462 } 463 464 if (fun->conn_handler != NULL) { 465 /* Driver has a custom connection handler. */ 466 (*fun->conn_handler)(iid, icall, (void *)fun); 323 467 return; 324 468 } … … 427 571 428 572 /** Function for handling connections to device driver. */ 429 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall) 430 { 573 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 574 { 575 sysarg_t conn_type; 576 577 if (iid == 0) { 578 /* Callback connection from devman */ 579 /* XXX Use separate handler for this type of connection */ 580 conn_type = DRIVER_DEVMAN; 581 } else { 582 conn_type = IPC_GET_ARG1(*icall); 583 } 584 431 585 /* Select interface */ 432 switch ( (sysarg_t) (IPC_GET_ARG1(*icall))) {586 switch (conn_type) { 433 587 case DRIVER_DEVMAN: 434 588 /* Handle request from device manager */ … … 457 611 ddf_dev_t *dev; 458 612 459 dev = malloc(sizeof(ddf_dev_t));613 dev = calloc(1, sizeof(ddf_dev_t)); 460 614 if (dev == NULL) 461 615 return NULL; 462 616 463 memset(dev, 0, sizeof(ddf_dev_t));464 617 return dev; 465 618 } … … 489 642 static void delete_device(ddf_dev_t *dev) 490 643 { 644 if (dev->driver_data != NULL) 645 free(dev->driver_data); 491 646 free(dev); 492 647 } 493 648 494 /** Delete devicestructure.649 /** Delete function structure. 495 650 * 496 651 * @param dev The device structure. … … 499 654 { 500 655 clean_match_ids(&fun->match_ids); 656 if (fun->driver_data != NULL) 657 free(fun->driver_data); 501 658 if (fun->name != NULL) 502 659 free(fun->name); … … 504 661 } 505 662 663 /** Increase device reference count. */ 664 static void dev_add_ref(ddf_dev_t *dev) 665 { 666 atomic_inc(&dev->refcnt); 667 } 668 669 /** Decrease device reference count. 670 * 671 * Free the device structure if the reference count drops to zero. 672 */ 673 static void dev_del_ref(ddf_dev_t *dev) 674 { 675 if (atomic_predec(&dev->refcnt) == 0) 676 delete_device(dev); 677 } 678 679 /** Increase function reference count. 680 * 681 * This also increases reference count on the device. The device structure 682 * will thus not be deallocated while there are some associated function 683 * structures. 684 */ 685 static void fun_add_ref(ddf_fun_t *fun) 686 { 687 dev_add_ref(fun->dev); 688 atomic_inc(&fun->refcnt); 689 } 690 691 /** Decrease function reference count. 692 * 693 * Free the function structure if the reference count drops to zero. 694 */ 695 static void fun_del_ref(ddf_fun_t *fun) 696 { 697 ddf_dev_t *dev = fun->dev; 698 699 if (atomic_predec(&fun->refcnt) == 0) 700 delete_function(fun); 701 702 dev_del_ref(dev); 703 } 704 705 /** Allocate driver-specific device data. */ 706 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 707 { 708 void *data; 709 710 assert(dev->driver_data == NULL); 711 712 data = calloc(1, size); 713 if (data == NULL) 714 return NULL; 715 716 dev->driver_data = data; 717 return data; 718 } 719 506 720 /** Create a DDF function node. 507 721 * … … 535 749 return NULL; 536 750 751 /* Add one reference that will be dropped by ddf_fun_destroy() */ 752 fun->dev = dev; 753 fun_add_ref(fun); 754 537 755 fun->bound = false; 538 fun->dev = dev;539 756 fun->ftype = ftype; 540 757 … … 548 765 } 549 766 767 /** Allocate driver-specific function data. */ 768 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 769 { 770 void *data; 771 772 assert(fun->bound == false); 773 assert(fun->driver_data == NULL); 774 775 data = calloc(1, size); 776 if (data == NULL) 777 return NULL; 778 779 fun->driver_data = data; 780 return data; 781 } 782 550 783 /** Destroy DDF function node. 551 784 * … … 558 791 { 559 792 assert(fun->bound == false); 560 delete_function(fun); 793 794 /* 795 * Drop the reference added by ddf_fun_create(). This will deallocate 796 * the function as soon as all other references are dropped (i.e. 797 * as soon control leaves all driver entry points called in context 798 * of this function. 799 */ 800 fun_del_ref(fun); 561 801 } 562 802 … … 583 823 int ddf_fun_bind(ddf_fun_t *fun) 584 824 { 825 assert(fun->bound == false); 585 826 assert(fun->name != NULL); 586 827 … … 599 840 } 600 841 842 /** Unbind a function node. 843 * 844 * Unbind the specified function from the system. This effectively makes 845 * the function invisible to the system. 846 * 847 * @param fun Function to unbind 848 * @return EOK on success or negative error code 849 */ 850 int ddf_fun_unbind(ddf_fun_t *fun) 851 { 852 int res; 853 854 assert(fun->bound == true); 855 856 res = devman_remove_function(fun->handle); 857 if (res != EOK) 858 return res; 859 860 remove_from_functions_list(fun); 861 862 fun->bound = false; 863 return EOK; 864 } 865 866 /** Online function. 867 * 868 * @param fun Function to online 869 * @return EOK on success or negative error code 870 */ 871 int ddf_fun_online(ddf_fun_t *fun) 872 { 873 int res; 874 875 assert(fun->bound == true); 876 877 res = devman_drv_fun_online(fun->handle); 878 if (res != EOK) 879 return res; 880 881 return EOK; 882 } 883 884 /** Offline function. 885 * 886 * @param fun Function to offline 887 * @return EOK on success or negative error code 888 */ 889 int ddf_fun_offline(ddf_fun_t *fun) 890 { 891 int res; 892 893 assert(fun->bound == true); 894 895 res = devman_drv_fun_offline(fun->handle); 896 if (res != EOK) 897 return res; 898 899 return EOK; 900 } 901 601 902 /** Add single match ID to inner function. 602 903 * … … 621 922 return ENOMEM; 622 923 623 match_id->id = match_id_str;924 match_id->id = str_dup(match_id_str); 624 925 match_id->score = 90; 625 926 … … 636 937 } 637 938 638 /** Add exposed function to c lass.939 /** Add exposed function to category. 639 940 * 640 941 * Must only be called when the function is bound. 641 942 */ 642 int ddf_fun_add_to_c lass(ddf_fun_t *fun, const char *class_name)943 int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name) 643 944 { 644 945 assert(fun->bound == true); 645 946 assert(fun->ftype == fun_exposed); 646 947 647 return devman_add_device_to_c lass(fun->handle, class_name);948 return devman_add_device_to_category(fun->handle, cat_name); 648 949 } 649 950
Note:
See TracChangeset
for help on using the changeset viewer.