Changeset c05642d in mainline for uspace/lib/drv/generic/driver.c
- Timestamp:
- 2011-09-07T00:03:26Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5081276
- Parents:
- bb74dabe (diff), 038b289 (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
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
rbb74dabe rc05642d 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); … … 227 235 } 228 236 229 static ddf_fun_t *driver_get_function(list_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) 230 253 { 231 254 ddf_fun_t *fun = NULL; 232 255 233 fibril_mutex_lock(&functions_mutex);234 235 list_foreach( *functions, link) {256 assert(fibril_mutex_is_locked(&functions_mutex)); 257 258 list_foreach(functions, link) { 236 259 fun = list_get_instance(link, ddf_fun_t, link); 237 if (fun->handle == handle) { 238 fibril_mutex_unlock(&functions_mutex); 260 if (fun->handle == handle) 239 261 return fun; 240 } 241 } 242 243 fibril_mutex_unlock(&functions_mutex); 262 } 244 263 245 264 return NULL; 246 265 } 247 266 248 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) 249 268 { 250 269 char *dev_name = NULL; … … 255 274 256 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); 257 279 dev->handle = dev_handle; 258 280 … … 267 289 268 290 res = driver->driver_ops->add_device(dev); 269 if (res != EOK) 270 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); 271 301 272 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_dev_gone(ipc_callid_t iid, ipc_call_t *icall) 336 { 337 devman_handle_t devh; 338 ddf_dev_t *dev; 339 int rc; 340 341 devh = IPC_GET_ARG1(*icall); 342 343 fibril_mutex_lock(&devices_mutex); 344 dev = driver_get_device(devh); 345 if (dev != NULL) 346 dev_add_ref(dev); 347 fibril_mutex_unlock(&devices_mutex); 348 349 if (dev == NULL) { 350 async_answer_0(iid, ENOENT); 351 return; 352 } 353 354 if (driver->driver_ops->dev_gone != NULL) 355 rc = driver->driver_ops->dev_gone(dev); 356 else 357 rc = ENOTSUP; 358 359 if (rc == EOK) 360 dev_del_ref(dev); 361 362 async_answer_0(iid, (sysarg_t) rc); 363 } 364 365 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall) 366 { 367 devman_handle_t funh; 368 ddf_fun_t *fun; 369 int rc; 370 371 funh = IPC_GET_ARG1(*icall); 372 373 /* 374 * Look the function up. Bump reference count so that 375 * the function continues to exist until we return 376 * from the driver. 377 */ 378 fibril_mutex_lock(&functions_mutex); 379 380 fun = driver_get_function(funh); 381 if (fun != NULL) 382 fun_add_ref(fun); 383 384 fibril_mutex_unlock(&functions_mutex); 385 386 if (fun == NULL) { 387 async_answer_0(iid, ENOENT); 388 return; 389 } 390 391 /* Call driver entry point */ 392 if (driver->driver_ops->fun_online != NULL) 393 rc = driver->driver_ops->fun_online(fun); 394 else 395 rc = ENOTSUP; 396 397 fun_del_ref(fun); 398 399 async_answer_0(iid, (sysarg_t) rc); 400 } 401 402 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 403 { 404 devman_handle_t funh; 405 ddf_fun_t *fun; 406 int rc; 407 408 funh = IPC_GET_ARG1(*icall); 409 410 /* 411 * Look the function up. Bump reference count so that 412 * the function continues to exist until we return 413 * from the driver. 414 */ 415 fibril_mutex_lock(&functions_mutex); 416 417 fun = driver_get_function(funh); 418 if (fun != NULL) 419 fun_add_ref(fun); 420 421 fibril_mutex_unlock(&functions_mutex); 422 423 if (fun == NULL) { 424 async_answer_0(iid, ENOENT); 425 return; 426 } 427 428 /* Call driver entry point */ 429 if (driver->driver_ops->fun_offline != NULL) 430 rc = driver->driver_ops->fun_offline(fun); 431 else 432 rc = ENOTSUP; 433 434 async_answer_0(iid, (sysarg_t) rc); 273 435 } 274 436 … … 286 448 287 449 switch (IPC_GET_IMETHOD(call)) { 288 case DRIVER_ADD_DEVICE: 289 driver_add_device(callid, &call); 450 case DRIVER_DEV_ADD: 451 driver_dev_add(callid, &call); 452 break; 453 case DRIVER_DEV_REMOVE: 454 driver_dev_remove(callid, &call); 455 break; 456 case DRIVER_DEV_GONE: 457 driver_dev_gone(callid, &call); 458 break; 459 case DRIVER_FUN_ONLINE: 460 driver_fun_online(callid, &call); 461 break; 462 case DRIVER_FUN_OFFLINE: 463 driver_fun_offline(callid, &call); 290 464 break; 291 465 default: 292 async_answer_0(callid, ENO ENT);466 async_answer_0(callid, ENOTSUP); 293 467 } 294 468 } … … 308 482 */ 309 483 devman_handle_t handle = IPC_GET_ARG2(*icall); 310 ddf_fun_t *fun = driver_get_function(&functions, handle); 484 485 fibril_mutex_lock(&functions_mutex); 486 ddf_fun_t *fun = driver_get_function(handle); 487 fibril_mutex_unlock(&functions_mutex); 488 /* XXX Need a lock on fun */ 311 489 312 490 if (fun == NULL) { … … 466 644 ddf_dev_t *dev; 467 645 468 dev = malloc(sizeof(ddf_dev_t));646 dev = calloc(1, sizeof(ddf_dev_t)); 469 647 if (dev == NULL) 470 648 return NULL; 471 649 472 memset(dev, 0, sizeof(ddf_dev_t));473 650 return dev; 474 651 } … … 498 675 static void delete_device(ddf_dev_t *dev) 499 676 { 677 if (dev->driver_data != NULL) 678 free(dev->driver_data); 500 679 free(dev); 501 680 } 502 681 503 /** Delete devicestructure.682 /** Delete function structure. 504 683 * 505 684 * @param dev The device structure. … … 508 687 { 509 688 clean_match_ids(&fun->match_ids); 689 if (fun->driver_data != NULL) 690 free(fun->driver_data); 510 691 if (fun->name != NULL) 511 692 free(fun->name); … … 513 694 } 514 695 696 /** Increase device reference count. */ 697 static void dev_add_ref(ddf_dev_t *dev) 698 { 699 atomic_inc(&dev->refcnt); 700 } 701 702 /** Decrease device reference count. 703 * 704 * Free the device structure if the reference count drops to zero. 705 */ 706 static void dev_del_ref(ddf_dev_t *dev) 707 { 708 if (atomic_predec(&dev->refcnt) == 0) 709 delete_device(dev); 710 } 711 712 /** Increase function reference count. 713 * 714 * This also increases reference count on the device. The device structure 715 * will thus not be deallocated while there are some associated function 716 * structures. 717 */ 718 static void fun_add_ref(ddf_fun_t *fun) 719 { 720 dev_add_ref(fun->dev); 721 atomic_inc(&fun->refcnt); 722 } 723 724 /** Decrease function reference count. 725 * 726 * Free the function structure if the reference count drops to zero. 727 */ 728 static void fun_del_ref(ddf_fun_t *fun) 729 { 730 ddf_dev_t *dev = fun->dev; 731 732 if (atomic_predec(&fun->refcnt) == 0) 733 delete_function(fun); 734 735 dev_del_ref(dev); 736 } 737 738 /** Allocate driver-specific device data. */ 739 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 740 { 741 void *data; 742 743 assert(dev->driver_data == NULL); 744 745 data = calloc(1, size); 746 if (data == NULL) 747 return NULL; 748 749 dev->driver_data = data; 750 return data; 751 } 752 515 753 /** Create a DDF function node. 516 754 * … … 544 782 return NULL; 545 783 784 /* Add one reference that will be dropped by ddf_fun_destroy() */ 785 fun->dev = dev; 786 fun_add_ref(fun); 787 546 788 fun->bound = false; 547 fun->dev = dev;548 789 fun->ftype = ftype; 549 790 … … 557 798 } 558 799 800 /** Allocate driver-specific function data. */ 801 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 802 { 803 void *data; 804 805 assert(fun->bound == false); 806 assert(fun->driver_data == NULL); 807 808 data = calloc(1, size); 809 if (data == NULL) 810 return NULL; 811 812 fun->driver_data = data; 813 return data; 814 } 815 559 816 /** Destroy DDF function node. 560 817 * … … 567 824 { 568 825 assert(fun->bound == false); 569 delete_function(fun); 826 827 /* 828 * Drop the reference added by ddf_fun_create(). This will deallocate 829 * the function as soon as all other references are dropped (i.e. 830 * as soon control leaves all driver entry points called in context 831 * of this function. 832 */ 833 fun_del_ref(fun); 570 834 } 571 835 … … 614 878 * the function invisible to the system. 615 879 * 616 * @param fun Function to bind880 * @param fun Function to unbind 617 881 * @return EOK on success or negative error code 618 882 */ … … 623 887 assert(fun->bound == true); 624 888 625 add_to_functions_list(fun);626 889 res = devman_remove_function(fun->handle); 627 890 if (res != EOK) … … 631 894 632 895 fun->bound = false; 896 return EOK; 897 } 898 899 /** Online function. 900 * 901 * @param fun Function to online 902 * @return EOK on success or negative error code 903 */ 904 int ddf_fun_online(ddf_fun_t *fun) 905 { 906 int res; 907 908 assert(fun->bound == true); 909 910 res = devman_drv_fun_online(fun->handle); 911 if (res != EOK) 912 return res; 913 914 return EOK; 915 } 916 917 /** Offline function. 918 * 919 * @param fun Function to offline 920 * @return EOK on success or negative error code 921 */ 922 int ddf_fun_offline(ddf_fun_t *fun) 923 { 924 int res; 925 926 assert(fun->bound == true); 927 928 res = devman_drv_fun_offline(fun->handle); 929 if (res != EOK) 930 return res; 931 633 932 return EOK; 634 933 }
Note:
See TracChangeset
for help on using the changeset viewer.