Changeset a1b7e80 in mainline for uspace/lib/drv/generic/driver.c
- Timestamp:
- 2011-09-02T16:54:18Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f480d7e
- Parents:
- 7a72ce1a (diff), 224c0e7 (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
r7a72ce1a ra1b7e80 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 dev_add_ref(dev); 316 fibril_mutex_unlock(&devices_mutex); 317 318 if (dev == NULL) { 319 async_answer_0(iid, ENOENT); 320 return; 321 } 322 323 if (driver->driver_ops->dev_remove != NULL) 324 rc = driver->driver_ops->dev_remove(dev); 325 else 326 rc = ENOTSUP; 327 328 if (rc == EOK) 329 dev_del_ref(dev); 330 331 async_answer_0(iid, (sysarg_t) rc); 332 } 333 334 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall) 335 { 336 devman_handle_t funh; 337 ddf_fun_t *fun; 338 int rc; 339 340 funh = IPC_GET_ARG1(*icall); 341 342 /* 343 * Look the function up. Bump reference count so that 344 * the function continues to exist until we return 345 * from the driver. 346 */ 347 fibril_mutex_lock(&functions_mutex); 348 349 fun = driver_get_function(funh); 350 if (fun != NULL) 351 fun_add_ref(fun); 352 353 fibril_mutex_unlock(&functions_mutex); 354 355 if (fun == NULL) { 356 async_answer_0(iid, ENOENT); 357 return; 358 } 359 360 /* Call driver entry point */ 361 if (driver->driver_ops->fun_online != NULL) 362 rc = driver->driver_ops->fun_online(fun); 363 else 364 rc = ENOTSUP; 365 366 fun_del_ref(fun); 367 368 async_answer_0(iid, (sysarg_t) rc); 369 } 370 371 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall) 372 { 373 devman_handle_t funh; 374 ddf_fun_t *fun; 375 int rc; 376 377 funh = IPC_GET_ARG1(*icall); 378 379 /* 380 * Look the function up. Bump reference count so that 381 * the function continues to exist until we return 382 * from the driver. 383 */ 384 fibril_mutex_lock(&functions_mutex); 385 386 fun = driver_get_function(funh); 387 if (fun != NULL) 388 fun_add_ref(fun); 389 390 fibril_mutex_unlock(&functions_mutex); 391 392 if (fun == NULL) { 393 async_answer_0(iid, ENOENT); 394 return; 395 } 396 397 /* Call driver entry point */ 398 if (driver->driver_ops->fun_offline != NULL) 399 rc = driver->driver_ops->fun_offline(fun); 400 else 401 rc = ENOTSUP; 402 403 async_answer_0(iid, (sysarg_t) rc); 273 404 } 274 405 … … 286 417 287 418 switch (IPC_GET_IMETHOD(call)) { 288 case DRIVER_ADD_DEVICE: 289 driver_add_device(callid, &call); 419 case DRIVER_DEV_ADD: 420 driver_dev_add(callid, &call); 421 break; 422 case DRIVER_DEV_REMOVE: 423 driver_dev_remove(callid, &call); 424 break; 425 case DRIVER_FUN_ONLINE: 426 driver_fun_online(callid, &call); 427 break; 428 case DRIVER_FUN_OFFLINE: 429 driver_fun_offline(callid, &call); 290 430 break; 291 431 default: 292 async_answer_0(callid, ENO ENT);432 async_answer_0(callid, ENOTSUP); 293 433 } 294 434 } … … 308 448 */ 309 449 devman_handle_t handle = IPC_GET_ARG2(*icall); 310 ddf_fun_t *fun = driver_get_function(&functions, handle); 450 451 fibril_mutex_lock(&functions_mutex); 452 ddf_fun_t *fun = driver_get_function(handle); 453 fibril_mutex_unlock(&functions_mutex); 454 /* XXX Need a lock on fun */ 311 455 312 456 if (fun == NULL) { … … 466 610 ddf_dev_t *dev; 467 611 468 dev = malloc(sizeof(ddf_dev_t));612 dev = calloc(1, sizeof(ddf_dev_t)); 469 613 if (dev == NULL) 470 614 return NULL; 471 615 472 memset(dev, 0, sizeof(ddf_dev_t));473 616 return dev; 474 617 } … … 498 641 static void delete_device(ddf_dev_t *dev) 499 642 { 643 if (dev->driver_data != NULL) 644 free(dev->driver_data); 500 645 free(dev); 501 646 } 502 647 503 /** Delete devicestructure.648 /** Delete function structure. 504 649 * 505 650 * @param dev The device structure. … … 508 653 { 509 654 clean_match_ids(&fun->match_ids); 655 if (fun->driver_data != NULL) 656 free(fun->driver_data); 510 657 if (fun->name != NULL) 511 658 free(fun->name); … … 513 660 } 514 661 662 /** Increase device reference count. */ 663 static void dev_add_ref(ddf_dev_t *dev) 664 { 665 atomic_inc(&dev->refcnt); 666 } 667 668 /** Decrease device reference count. 669 * 670 * Free the device structure if the reference count drops to zero. 671 */ 672 static void dev_del_ref(ddf_dev_t *dev) 673 { 674 if (atomic_predec(&dev->refcnt) == 0) 675 delete_device(dev); 676 } 677 678 /** Increase function reference count. 679 * 680 * This also increases reference count on the device. The device structure 681 * will thus not be deallocated while there are some associated function 682 * structures. 683 */ 684 static void fun_add_ref(ddf_fun_t *fun) 685 { 686 dev_add_ref(fun->dev); 687 atomic_inc(&fun->refcnt); 688 } 689 690 /** Decrease function reference count. 691 * 692 * Free the function structure if the reference count drops to zero. 693 */ 694 static void fun_del_ref(ddf_fun_t *fun) 695 { 696 ddf_dev_t *dev = fun->dev; 697 698 if (atomic_predec(&fun->refcnt) == 0) 699 delete_function(fun); 700 701 dev_del_ref(dev); 702 } 703 704 /** Allocate driver-specific device data. */ 705 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size) 706 { 707 void *data; 708 709 assert(dev->driver_data == NULL); 710 711 data = calloc(1, size); 712 if (data == NULL) 713 return NULL; 714 715 dev->driver_data = data; 716 return data; 717 } 718 515 719 /** Create a DDF function node. 516 720 * … … 544 748 return NULL; 545 749 750 /* Add one reference that will be dropped by ddf_fun_destroy() */ 751 fun->dev = dev; 752 fun_add_ref(fun); 753 546 754 fun->bound = false; 547 fun->dev = dev;548 755 fun->ftype = ftype; 549 756 … … 557 764 } 558 765 766 /** Allocate driver-specific function data. */ 767 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size) 768 { 769 void *data; 770 771 assert(fun->bound == false); 772 assert(fun->driver_data == NULL); 773 774 data = calloc(1, size); 775 if (data == NULL) 776 return NULL; 777 778 fun->driver_data = data; 779 return data; 780 } 781 559 782 /** Destroy DDF function node. 560 783 * … … 567 790 { 568 791 assert(fun->bound == false); 569 delete_function(fun); 792 793 /* 794 * Drop the reference added by ddf_fun_create(). This will deallocate 795 * the function as soon as all other references are dropped (i.e. 796 * as soon control leaves all driver entry points called in context 797 * of this function. 798 */ 799 fun_del_ref(fun); 570 800 } 571 801 … … 614 844 * the function invisible to the system. 615 845 * 616 * @param fun Function to bind846 * @param fun Function to unbind 617 847 * @return EOK on success or negative error code 618 848 */ … … 623 853 assert(fun->bound == true); 624 854 625 add_to_functions_list(fun);626 855 res = devman_remove_function(fun->handle); 627 856 if (res != EOK) … … 631 860 632 861 fun->bound = false; 862 return EOK; 863 } 864 865 /** Online function. 866 * 867 * @param fun Function to online 868 * @return EOK on success or negative error code 869 */ 870 int ddf_fun_online(ddf_fun_t *fun) 871 { 872 int res; 873 874 assert(fun->bound == true); 875 876 res = devman_drv_fun_online(fun->handle); 877 if (res != EOK) 878 return res; 879 880 return EOK; 881 } 882 883 /** Offline function. 884 * 885 * @param fun Function to offline 886 * @return EOK on success or negative error code 887 */ 888 int ddf_fun_offline(ddf_fun_t *fun) 889 { 890 int res; 891 892 assert(fun->bound == true); 893 894 res = devman_drv_fun_offline(fun->handle); 895 if (res != EOK) 896 return res; 897 633 898 return EOK; 634 899 }
Note:
See TracChangeset
for help on using the changeset viewer.