Changes in uspace/lib/drv/generic/driver.c [8a363ab3:26fa82bc] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r8a363ab3 r26fa82bc 63 63 64 64 /** Devices */ 65 LIST_INITIALIZE(devices);66 FIBRIL_MUTEX_INITIALIZE(devices_mutex);67 68 /** Functions */69 65 LIST_INITIALIZE(functions); 70 66 FIBRIL_MUTEX_INITIALIZE(functions_mutex); … … 86 82 static ddf_dev_t *create_device(void); 87 83 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 *);92 84 static remote_handler_t *function_get_default_handler(ddf_fun_t *); 93 85 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t); … … 147 139 find_interrupt_context_by_id(interrupt_context_list_t *list, int id) 148 140 { 141 fibril_mutex_lock(&list->mutex); 142 143 link_t *link = list->contexts.next; 149 144 interrupt_context_t *ctx; 150 145 151 fibril_mutex_lock(&list->mutex); 152 153 list_foreach(list->contexts, link) { 146 while (link != &list->contexts) { 154 147 ctx = list_get_instance(link, interrupt_context_t, link); 155 148 if (ctx->id == id) { … … 157 150 return ctx; 158 151 } 152 link = link->next; 159 153 } 160 154 … … 166 160 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq) 167 161 { 162 fibril_mutex_lock(&list->mutex); 163 164 link_t *link = list->contexts.next; 168 165 interrupt_context_t *ctx; 169 166 170 fibril_mutex_lock(&list->mutex); 171 172 list_foreach(list->contexts, link) { 167 while (link != &list->contexts) { 173 168 ctx = list_get_instance(link, interrupt_context_t, link); 174 169 if (ctx->irq == irq && ctx->dev == dev) { … … 176 171 return ctx; 177 172 } 173 link = link->next; 178 174 } 179 175 … … 235 231 } 236 232 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 } 233 static ddf_fun_t *driver_get_function(link_t *functions, devman_handle_t handle) 234 { 235 ddf_fun_t *fun = NULL; 236 237 fibril_mutex_lock(&functions_mutex); 238 link_t *link = functions->next; 239 240 while (link != functions) { 241 fun = list_get_instance(link, ddf_fun_t, link); 242 if (fun->handle == handle) { 243 fibril_mutex_unlock(&functions_mutex); 244 return fun; 245 } 246 247 link = link->next; 248 } 249 250 fibril_mutex_unlock(&functions_mutex); 248 251 249 252 return NULL; 250 253 } 251 254 252 static ddf_fun_t *driver_get_function(devman_handle_t handle) 253 { 254 ddf_fun_t *fun = NULL; 255 256 assert(fibril_mutex_is_locked(&functions_mutex)); 257 258 list_foreach(functions, link) { 259 fun = list_get_instance(link, ddf_fun_t, link); 260 if (fun->handle == handle) 261 return fun; 262 } 263 264 return NULL; 265 } 266 267 static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall) 255 static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall) 268 256 { 269 257 char *dev_name = NULL; … … 271 259 272 260 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 273 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);261 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall); 274 262 275 263 ddf_dev_t *dev = create_device(); 276 277 /* Add one reference that will be dropped by driver_dev_remove() */278 dev_add_ref(dev);279 264 dev->handle = dev_handle; 280 265 … … 289 274 290 275 res = driver->driver_ops->add_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); 276 if (res != EOK) 277 delete_device(dev); 301 278 302 279 async_answer_0(iid, res); 303 }304 305 static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)306 {307 fibril_mutex_lock(&devices_mutex);308 ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall));309 fibril_mutex_unlock(&devices_mutex);310 311 if (dev != NULL && driver->driver_ops->device_added != NULL)312 driver->driver_ops->device_added(dev);313 }314 315 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)316 {317 devman_handle_t devh;318 ddf_dev_t *dev;319 int rc;320 321 devh = IPC_GET_ARG1(*icall);322 323 fibril_mutex_lock(&devices_mutex);324 dev = driver_get_device(devh);325 if (dev != NULL)326 dev_add_ref(dev);327 fibril_mutex_unlock(&devices_mutex);328 329 if (dev == NULL) {330 async_answer_0(iid, ENOENT);331 return;332 }333 334 if (driver->driver_ops->dev_remove != NULL)335 rc = driver->driver_ops->dev_remove(dev);336 else337 rc = ENOTSUP;338 339 if (rc == EOK)340 dev_del_ref(dev);341 342 async_answer_0(iid, (sysarg_t) rc);343 }344 345 static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)346 {347 devman_handle_t devh;348 ddf_dev_t *dev;349 int rc;350 351 devh = IPC_GET_ARG1(*icall);352 353 fibril_mutex_lock(&devices_mutex);354 dev = driver_get_device(devh);355 if (dev != NULL)356 dev_add_ref(dev);357 fibril_mutex_unlock(&devices_mutex);358 359 if (dev == NULL) {360 async_answer_0(iid, ENOENT);361 return;362 }363 364 if (driver->driver_ops->dev_gone != NULL)365 rc = driver->driver_ops->dev_gone(dev);366 else367 rc = ENOTSUP;368 369 if (rc == EOK)370 dev_del_ref(dev);371 372 async_answer_0(iid, (sysarg_t) rc);373 }374 375 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)376 {377 devman_handle_t funh;378 ddf_fun_t *fun;379 int rc;380 381 funh = IPC_GET_ARG1(*icall);382 383 /*384 * Look the function up. Bump reference count so that385 * the function continues to exist until we return386 * from the driver.387 */388 fibril_mutex_lock(&functions_mutex);389 390 fun = driver_get_function(funh);391 if (fun != NULL)392 fun_add_ref(fun);393 394 fibril_mutex_unlock(&functions_mutex);395 396 if (fun == NULL) {397 async_answer_0(iid, ENOENT);398 return;399 }400 401 /* Call driver entry point */402 if (driver->driver_ops->fun_online != NULL)403 rc = driver->driver_ops->fun_online(fun);404 else405 rc = ENOTSUP;406 407 fun_del_ref(fun);408 409 async_answer_0(iid, (sysarg_t) rc);410 }411 412 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)413 {414 devman_handle_t funh;415 ddf_fun_t *fun;416 int rc;417 418 funh = IPC_GET_ARG1(*icall);419 420 /*421 * Look the function up. Bump reference count so that422 * the function continues to exist until we return423 * from the driver.424 */425 fibril_mutex_lock(&functions_mutex);426 427 fun = driver_get_function(funh);428 if (fun != NULL)429 fun_add_ref(fun);430 431 fibril_mutex_unlock(&functions_mutex);432 433 if (fun == NULL) {434 async_answer_0(iid, ENOENT);435 return;436 }437 438 /* Call driver entry point */439 if (driver->driver_ops->fun_offline != NULL)440 rc = driver->driver_ops->fun_offline(fun);441 else442 rc = ENOTSUP;443 444 async_answer_0(iid, (sysarg_t) rc);445 280 } 446 281 … … 450 285 async_answer_0(iid, EOK); 451 286 452 while (true) { 287 bool cont = true; 288 while (cont) { 453 289 ipc_call_t call; 454 290 ipc_callid_t callid = async_get_call(&call); 455 291 456 if (!IPC_GET_IMETHOD(call))457 break;458 459 292 switch (IPC_GET_IMETHOD(call)) { 460 case DRIVER_DEV_ADD: 461 driver_dev_add(callid, &call); 462 break; 463 case DRIVER_DEV_ADDED: 464 async_answer_0(callid, EOK); 465 driver_dev_added(callid, &call); 466 break; 467 case DRIVER_DEV_REMOVE: 468 driver_dev_remove(callid, &call); 469 break; 470 case DRIVER_DEV_GONE: 471 driver_dev_gone(callid, &call); 472 break; 473 case DRIVER_FUN_ONLINE: 474 driver_fun_online(callid, &call); 475 break; 476 case DRIVER_FUN_OFFLINE: 477 driver_fun_offline(callid, &call); 293 case IPC_M_PHONE_HUNGUP: 294 cont = false; 295 continue; 296 case DRIVER_ADD_DEVICE: 297 driver_add_device(callid, &call); 478 298 break; 479 299 default: 480 async_answer_0(callid, ENO TSUP);300 async_answer_0(callid, ENOENT); 481 301 } 482 302 } 483 303 } 484 304 485 /** Generic client connection handler both for applications and drivers.486 * 487 * @param drv True for driver client, false for other clients488 * (applications, services, etc.).489 * 305 /** 306 * Generic client connection handler both for applications and drivers. 307 * 308 * @param drv True for driver client, false for other clients 309 * (applications, services etc.). 490 310 */ 491 311 static void driver_connection_gen(ipc_callid_t iid, ipc_call_t *icall, bool drv) … … 496 316 */ 497 317 devman_handle_t handle = IPC_GET_ARG2(*icall); 498 499 fibril_mutex_lock(&functions_mutex); 500 ddf_fun_t *fun = driver_get_function(handle); 501 fibril_mutex_unlock(&functions_mutex); 502 /* XXX Need a lock on fun */ 503 318 ddf_fun_t *fun = driver_get_function(&functions, handle); 319 504 320 if (fun == NULL) { 505 321 printf("%s: driver_connection_gen error - no function with handle" … … 509 325 } 510 326 511 if (fun->conn_handler != NULL) {512 /* Driver has a custom connection handler. */513 (*fun->conn_handler)(iid, icall, (void *)fun);514 return;515 }516 327 517 328 /* … … 529 340 return; 530 341 531 while ( true) {342 while (1) { 532 343 ipc_callid_t callid; 533 344 ipc_call_t call; 534 345 callid = async_get_call(&call); 535 346 sysarg_t method = IPC_GET_IMETHOD(call); 347 int iface_idx; 536 348 537 if (!method) { 349 switch (method) { 350 case IPC_M_PHONE_HUNGUP: 538 351 /* Close device function */ 539 352 if (fun->ops != NULL && fun->ops->close != NULL) … … 541 354 async_answer_0(callid, EOK); 542 355 return; 543 } 544 545 /* Convert ipc interface id to interface index */ 546 547 int iface_idx = DEV_IFACE_IDX(method); 548 549 if (!is_valid_iface_idx(iface_idx)) { 550 remote_handler_t *default_handler = 551 function_get_default_handler(fun); 552 if (default_handler != NULL) { 553 (*default_handler)(fun, callid, &call); 554 continue; 356 default: 357 /* convert ipc interface id to interface index */ 358 359 iface_idx = DEV_IFACE_IDX(method); 360 361 if (!is_valid_iface_idx(iface_idx)) { 362 remote_handler_t *default_handler = 363 function_get_default_handler(fun); 364 if (default_handler != NULL) { 365 (*default_handler)(fun, callid, &call); 366 break; 367 } 368 369 /* 370 * Function has no such interface and 371 * default handler is not provided. 372 */ 373 printf("%s: driver_connection_gen error - " 374 "invalid interface id %d.", 375 driver->name, iface_idx); 376 async_answer_0(callid, ENOTSUP); 377 break; 378 } 379 380 /* calling one of the function's interfaces */ 381 382 /* Get the interface ops structure. */ 383 void *ops = function_get_ops(fun, iface_idx); 384 if (ops == NULL) { 385 printf("%s: driver_connection_gen error - ", 386 driver->name); 387 printf("Function with handle %" PRIun " has no interface " 388 "with id %d.\n", handle, iface_idx); 389 async_answer_0(callid, ENOTSUP); 390 break; 555 391 } 556 392 557 393 /* 558 * Function has no such interface and559 * default handler is not provided.394 * Get the corresponding interface for remote request 395 * handling ("remote interface"). 560 396 */ 561 printf("%s: driver_connection_gen error - " 562 "invalid interface id %d.", 563 driver->name, iface_idx); 564 async_answer_0(callid, ENOTSUP); 565 continue; 397 remote_iface_t *rem_iface = get_remote_iface(iface_idx); 398 assert(rem_iface != NULL); 399 400 /* get the method of the remote interface */ 401 sysarg_t iface_method_idx = IPC_GET_ARG1(call); 402 remote_iface_func_ptr_t iface_method_ptr = 403 get_remote_method(rem_iface, iface_method_idx); 404 if (iface_method_ptr == NULL) { 405 /* The interface has not such method */ 406 printf("%s: driver_connection_gen error - " 407 "invalid interface method.", driver->name); 408 async_answer_0(callid, ENOTSUP); 409 break; 410 } 411 412 /* 413 * Call the remote interface's method, which will 414 * receive parameters from the remote client and it will 415 * pass it to the corresponding local interface method 416 * associated with the function by its driver. 417 */ 418 (*iface_method_ptr)(fun, ops, callid, &call); 419 break; 566 420 } 567 568 /* Calling one of the function's interfaces */569 570 /* Get the interface ops structure. */571 void *ops = function_get_ops(fun, iface_idx);572 if (ops == NULL) {573 printf("%s: driver_connection_gen error - ", driver->name);574 printf("Function with handle %" PRIun " has no interface "575 "with id %d.\n", handle, iface_idx);576 async_answer_0(callid, ENOTSUP);577 continue;578 }579 580 /*581 * Get the corresponding interface for remote request582 * handling ("remote interface").583 */584 remote_iface_t *rem_iface = get_remote_iface(iface_idx);585 assert(rem_iface != NULL);586 587 /* get the method of the remote interface */588 sysarg_t iface_method_idx = IPC_GET_ARG1(call);589 remote_iface_func_ptr_t iface_method_ptr =590 get_remote_method(rem_iface, iface_method_idx);591 if (iface_method_ptr == NULL) {592 /* The interface has not such method */593 printf("%s: driver_connection_gen error - "594 "invalid interface method.", driver->name);595 async_answer_0(callid, ENOTSUP);596 continue;597 }598 599 /*600 * Call the remote interface's method, which will601 * receive parameters from the remote client and it will602 * pass it to the corresponding local interface method603 * associated with the function by its driver.604 */605 (*iface_method_ptr)(fun, ops, callid, &call);606 421 } 607 422 } … … 618 433 619 434 /** Function for handling connections to device driver. */ 620 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 621 { 622 sysarg_t conn_type; 623 624 if (iid == 0) { 625 /* Callback connection from devman */ 626 /* XXX Use separate handler for this type of connection */ 627 conn_type = DRIVER_DEVMAN; 628 } else { 629 conn_type = IPC_GET_ARG1(*icall); 630 } 631 435 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall) 436 { 632 437 /* Select interface */ 633 switch ( conn_type) {438 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 634 439 case DRIVER_DEVMAN: 635 440 /* Handle request from device manager */ … … 658 463 ddf_dev_t *dev; 659 464 660 dev = calloc(1,sizeof(ddf_dev_t));465 dev = malloc(sizeof(ddf_dev_t)); 661 466 if (dev == NULL) 662 467 return NULL; 663 468 469 memset(dev, 0, sizeof(ddf_dev_t)); 664 470 return dev; 665 471 } … … 689 495 static void delete_device(ddf_dev_t *dev) 690 496 { 691 if (dev->driver_data != NULL)692 free(dev->driver_data);693 497 free(dev); 694 498 } 695 499 696 /** Delete functionstructure.500 /** Delete device structure. 697 501 * 698 502 * @param dev The device structure. … … 701 505 { 702 506 clean_match_ids(&fun->match_ids); 703 if (fun->driver_data != NULL)704 free(fun->driver_data);705 507 if (fun->name != NULL) 706 508 free(fun->name); … … 708 510 } 709 511 710 /** Increase device reference count. */711 static void dev_add_ref(ddf_dev_t *dev)712 {713 atomic_inc(&dev->refcnt);714 }715 716 /** Decrease device reference count.717 *718 * Free the device structure if the reference count drops to zero.719 */720 static void dev_del_ref(ddf_dev_t *dev)721 {722 if (atomic_predec(&dev->refcnt) == 0)723 delete_device(dev);724 }725 726 /** Increase function reference count.727 *728 * This also increases reference count on the device. The device structure729 * will thus not be deallocated while there are some associated function730 * structures.731 */732 static void fun_add_ref(ddf_fun_t *fun)733 {734 dev_add_ref(fun->dev);735 atomic_inc(&fun->refcnt);736 }737 738 /** Decrease function reference count.739 *740 * Free the function structure if the reference count drops to zero.741 */742 static void fun_del_ref(ddf_fun_t *fun)743 {744 ddf_dev_t *dev = fun->dev;745 746 if (atomic_predec(&fun->refcnt) == 0)747 delete_function(fun);748 749 dev_del_ref(dev);750 }751 752 /** Allocate driver-specific device data. */753 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)754 {755 void *data;756 757 assert(dev->driver_data == NULL);758 759 data = calloc(1, size);760 if (data == NULL)761 return NULL;762 763 dev->driver_data = data;764 return data;765 }766 767 512 /** Create a DDF function node. 768 513 * … … 796 541 return NULL; 797 542 798 /* Add one reference that will be dropped by ddf_fun_destroy() */543 fun->bound = false; 799 544 fun->dev = dev; 800 fun_add_ref(fun);801 802 fun->bound = false;803 545 fun->ftype = ftype; 804 546 … … 812 554 } 813 555 814 /** Allocate driver-specific function data. */815 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)816 {817 void *data;818 819 assert(fun->bound == false);820 assert(fun->driver_data == NULL);821 822 data = calloc(1, size);823 if (data == NULL)824 return NULL;825 826 fun->driver_data = data;827 return data;828 }829 830 556 /** Destroy DDF function node. 831 557 * … … 838 564 { 839 565 assert(fun->bound == false); 840 841 /* 842 * Drop the reference added by ddf_fun_create(). This will deallocate 843 * the function as soon as all other references are dropped (i.e. 844 * as soon control leaves all driver entry points called in context 845 * of this function. 846 */ 847 fun_del_ref(fun); 566 delete_function(fun); 848 567 } 849 568 … … 870 589 int ddf_fun_bind(ddf_fun_t *fun) 871 590 { 872 assert(fun->bound == false);873 591 assert(fun->name != NULL); 874 592 … … 887 605 } 888 606 889 /** Unbind a function node.890 *891 * Unbind the specified function from the system. This effectively makes892 * the function invisible to the system.893 *894 * @param fun Function to unbind895 * @return EOK on success or negative error code896 */897 int ddf_fun_unbind(ddf_fun_t *fun)898 {899 int res;900 901 assert(fun->bound == true);902 903 res = devman_remove_function(fun->handle);904 if (res != EOK)905 return res;906 907 remove_from_functions_list(fun);908 909 fun->bound = false;910 return EOK;911 }912 913 /** Online function.914 *915 * @param fun Function to online916 * @return EOK on success or negative error code917 */918 int ddf_fun_online(ddf_fun_t *fun)919 {920 int res;921 922 assert(fun->bound == true);923 924 res = devman_drv_fun_online(fun->handle);925 if (res != EOK)926 return res;927 928 return EOK;929 }930 931 /** Offline function.932 *933 * @param fun Function to offline934 * @return EOK on success or negative error code935 */936 int ddf_fun_offline(ddf_fun_t *fun)937 {938 int res;939 940 assert(fun->bound == true);941 942 res = devman_drv_fun_offline(fun->handle);943 if (res != EOK)944 return res;945 946 return EOK;947 }948 949 607 /** Add single match ID to inner function. 950 608 * … … 969 627 return ENOMEM; 970 628 971 match_id->id = str_dup(match_id_str);972 match_id->score = match_score;629 match_id->id = match_id_str; 630 match_id->score = 90; 973 631 974 632 add_match_id(&fun->match_ids, match_id); … … 984 642 } 985 643 986 /** Add exposed function to c ategory.644 /** Add exposed function to class. 987 645 * 988 646 * Must only be called when the function is bound. 989 647 */ 990 int ddf_fun_add_to_c ategory(ddf_fun_t *fun, const char *cat_name)648 int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name) 991 649 { 992 650 assert(fun->bound == true); 993 651 assert(fun->ftype == fun_exposed); 994 652 995 return devman_add_device_to_c ategory(fun->handle, cat_name);653 return devman_add_device_to_class(fun->handle, class_name); 996 654 } 997 655
Note:
See TracChangeset
for help on using the changeset viewer.