Changeset eb522e8 in mainline for uspace/lib/drv/generic/driver.c
- Timestamp:
- 2011-06-01T08:43:42Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 8d6c1f1
- Parents:
- 9e2e715 (diff), e51a514 (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
r9e2e715 reb522e8 1 1 /* 2 2 * Copyright (c) 2010 Lenka Trochtova 3 * Copyright (c) 2011 Jiri Svoboda 3 4 * All rights reserved. 4 5 * … … 46 47 #include <stdlib.h> 47 48 #include <str.h> 49 #include <str_error.h> 48 50 #include <ctype.h> 49 51 #include <errno.h> 52 #include <inttypes.h> 53 #include <devman.h> 50 54 51 55 #include <ipc/driver.h> 52 56 53 #include "driver.h" 54 55 /* driver structure */ 56 57 #include "dev_iface.h" 58 #include "ddf/driver.h" 59 #include "ddf/interrupt.h" 60 61 /** Driver structure */ 57 62 static driver_t *driver; 58 63 59 /* devices */ 60 61 LIST_INITIALIZE(devices); 62 FIBRIL_MUTEX_INITIALIZE(devices_mutex); 63 64 /* interrupts */ 65 64 /** Devices */ 65 LIST_INITIALIZE(functions); 66 FIBRIL_MUTEX_INITIALIZE(functions_mutex); 67 68 /** Interrupts */ 66 69 static interrupt_context_list_t interrupt_contexts; 67 70 … … 77 80 }; 78 81 82 static ddf_dev_t *create_device(void); 83 static void delete_device(ddf_dev_t *); 84 static remote_handler_t *function_get_default_handler(ddf_fun_t *); 85 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t); 79 86 80 87 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall) 81 88 { 82 int id = (int)IPC_GET_ METHOD(*icall);89 int id = (int)IPC_GET_IMETHOD(*icall); 83 90 interrupt_context_t *ctx; 84 91 85 92 ctx = find_interrupt_context_by_id(&interrupt_contexts, id); 86 if ( NULL != ctx && NULL != ctx->handler)93 if (ctx != NULL && ctx->handler != NULL) 87 94 (*ctx->handler)(ctx->dev, iid, icall); 88 95 } 89 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 void 122 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 fibril_mutex_lock(&list->mutex); 142 143 link_t *link = list->contexts.next; 144 interrupt_context_t *ctx; 145 146 while (link != &list->contexts) { 147 ctx = list_get_instance(link, interrupt_context_t, link); 148 if (ctx->id == id) { 149 fibril_mutex_unlock(&list->mutex); 150 return ctx; 151 } 152 link = link->next; 153 } 154 155 fibril_mutex_unlock(&list->mutex); 156 return NULL; 157 } 158 159 interrupt_context_t * 160 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq) 161 { 162 fibril_mutex_lock(&list->mutex); 163 164 link_t *link = list->contexts.next; 165 interrupt_context_t *ctx; 166 167 while (link != &list->contexts) { 168 ctx = list_get_instance(link, interrupt_context_t, link); 169 if (ctx->irq == irq && ctx->dev == dev) { 170 fibril_mutex_unlock(&list->mutex); 171 return ctx; 172 } 173 link = link->next; 174 } 175 176 fibril_mutex_unlock(&list->mutex); 177 return NULL; 178 } 179 180 90 181 int 91 register_interrupt_handler(d evice_t *dev, int irq, interrupt_handler_t *handler,182 register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler, 92 183 irq_code_t *pseudocode) 93 184 { … … 100 191 add_interrupt_context(&interrupt_contexts, ctx); 101 192 102 if ( NULL == pseudocode)193 if (pseudocode == NULL) 103 194 pseudocode = &default_pseudocode; 104 195 105 int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode);106 if ( 0 != res) {196 int res = register_irq(irq, dev->handle, ctx->id, pseudocode); 197 if (res != EOK) { 107 198 remove_interrupt_context(&interrupt_contexts, ctx); 108 199 delete_interrupt_context(ctx); … … 112 203 } 113 204 114 int unregister_interrupt_handler(d evice_t *dev, int irq)205 int unregister_interrupt_handler(ddf_dev_t *dev, int irq) 115 206 { 116 207 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts, 117 208 dev, irq); 118 int res = ipc_unregister_irq(irq, dev->handle);119 120 if ( NULL != ctx) {209 int res = unregister_irq(irq, dev->handle); 210 211 if (ctx != NULL) { 121 212 remove_interrupt_context(&interrupt_contexts, ctx); 122 213 delete_interrupt_context(ctx); 123 214 } 215 124 216 return res; 125 217 } 126 218 127 static void add_to_devices_list(device_t *dev) 128 { 129 fibril_mutex_lock(&devices_mutex); 130 list_append(&dev->link, &devices); 131 fibril_mutex_unlock(&devices_mutex); 132 } 133 134 static void remove_from_devices_list(device_t *dev) 135 { 136 fibril_mutex_lock(&devices_mutex); 137 list_remove(&dev->link); 138 fibril_mutex_unlock(&devices_mutex); 139 } 140 141 static device_t * driver_get_device(link_t *devices, device_handle_t handle) 142 { 143 device_t *dev = NULL; 144 145 fibril_mutex_lock(&devices_mutex); 146 link_t *link = devices->next; 147 while (link != devices) { 148 dev = list_get_instance(link, device_t, link); 149 if (handle == dev->handle) { 150 fibril_mutex_unlock(&devices_mutex); 151 return dev; 219 static void add_to_functions_list(ddf_fun_t *fun) 220 { 221 fibril_mutex_lock(&functions_mutex); 222 list_append(&fun->link, &functions); 223 fibril_mutex_unlock(&functions_mutex); 224 } 225 226 static void remove_from_functions_list(ddf_fun_t *fun) 227 { 228 fibril_mutex_lock(&functions_mutex); 229 list_remove(&fun->link); 230 fibril_mutex_unlock(&functions_mutex); 231 } 232 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; 152 245 } 246 153 247 link = link->next; 154 248 } 155 fibril_mutex_unlock(&devices_mutex); 156 249 250 fibril_mutex_unlock(&functions_mutex); 251 157 252 return NULL; 158 253 } … … 161 256 { 162 257 char *dev_name = NULL; 163 int res = EOK; 164 165 device_handle_t dev_handle = IPC_GET_ARG1(*icall); 166 device_t *dev = create_device(); 258 int res; 259 260 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 261 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall); 262 263 ddf_dev_t *dev = create_device(); 167 264 dev->handle = dev_handle; 168 265 169 266 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0); 170 267 dev->name = dev_name; 171 172 add_to_devices_list(dev); 268 269 /* 270 * Currently not used, parent fun handle is stored in context 271 * of the connection to the parent device driver. 272 */ 273 (void) parent_fun_handle; 274 173 275 res = driver->driver_ops->add_device(dev); 174 if (0 == res) { 175 printf("%s: new device with handle = %x was added.\n", 176 driver->name, dev_handle); 177 } else { 178 printf("%s: failed to add a new device with handle = %d.\n", 179 driver->name, dev_handle); 180 remove_from_devices_list(dev); 276 if (res != EOK) 181 277 delete_device(dev); 182 } 183 184 ipc_answer_0(iid, res); 278 279 async_answer_0(iid, res); 185 280 } 186 281 … … 188 283 { 189 284 /* Accept connection */ 190 ipc_answer_0(iid, EOK);191 285 async_answer_0(iid, EOK); 286 192 287 bool cont = true; 193 288 while (cont) { 194 289 ipc_call_t call; 195 290 ipc_callid_t callid = async_get_call(&call); 196 197 switch (IPC_GET_ METHOD(call)) {291 292 switch (IPC_GET_IMETHOD(call)) { 198 293 case IPC_M_PHONE_HUNGUP: 199 294 cont = false; … … 203 298 break; 204 299 default: 205 if (!(callid & IPC_CALLID_NOTIFICATION)) 206 ipc_answer_0(callid, ENOENT); 300 async_answer_0(callid, ENOENT); 207 301 } 208 302 } … … 221 315 * the device to which the client connected. 222 316 */ 223 dev ice_handle_t handle = IPC_GET_ARG2(*icall);224 d evice_t *dev = driver_get_device(&devices, handle);225 226 if ( dev== NULL) {227 printf("%s: driver_connection_gen error - no devicewith handle"228 " % xwas found.\n", driver->name, handle);229 ipc_answer_0(iid, ENOENT);317 devman_handle_t handle = IPC_GET_ARG2(*icall); 318 ddf_fun_t *fun = driver_get_function(&functions, handle); 319 320 if (fun == NULL) { 321 printf("%s: driver_connection_gen error - no function with handle" 322 " %" PRIun " was found.\n", driver->name, handle); 323 async_answer_0(iid, ENOENT); 230 324 return; 231 325 } … … 236 330 * use the device. 237 331 */ 238 332 239 333 int ret = EOK; 240 /* open the device*/241 if ( NULL != dev->ops && NULL != dev->ops->open)242 ret = (* dev->ops->open)(dev);243 244 ipc_answer_0(iid, ret);245 if ( EOK != ret)334 /* Open device function */ 335 if (fun->ops != NULL && fun->ops->open != NULL) 336 ret = (*fun->ops->open)(fun); 337 338 async_answer_0(iid, ret); 339 if (ret != EOK) 246 340 return; 247 341 248 342 while (1) { 249 343 ipc_callid_t callid; 250 344 ipc_call_t call; 251 345 callid = async_get_call(&call); 252 ipcarg_t method = IPC_GET_METHOD(call);346 sysarg_t method = IPC_GET_IMETHOD(call); 253 347 int iface_idx; 254 348 255 349 switch (method) { 256 case IPC_M_PHONE_HUNGUP: 257 /* close the device*/258 if ( NULL != dev->ops && NULL != dev->ops->close)259 (* dev->ops->close)(dev);260 ipc_answer_0(callid, EOK);350 case IPC_M_PHONE_HUNGUP: 351 /* Close device function */ 352 if (fun->ops != NULL && fun->ops->close != NULL) 353 (*fun->ops->close)(fun); 354 async_answer_0(callid, EOK); 261 355 return; 262 default: 356 default: 263 357 /* convert ipc interface id to interface index */ 264 358 … … 267 361 if (!is_valid_iface_idx(iface_idx)) { 268 362 remote_handler_t *default_handler = 269 device_get_default_handler(dev);270 if ( NULL != default_handler) {271 (*default_handler)( dev, callid, &call);363 function_get_default_handler(fun); 364 if (default_handler != NULL) { 365 (*default_handler)(fun, callid, &call); 272 366 break; 273 367 } 368 274 369 /* 275 * This is not device's interface and the370 * Function has no such interface and 276 371 * default handler is not provided. 277 372 */ … … 279 374 "invalid interface id %d.", 280 375 driver->name, iface_idx); 281 ipc_answer_0(callid, ENOTSUP);376 async_answer_0(callid, ENOTSUP); 282 377 break; 283 378 } 284 285 /* calling one of the device's interfaces */286 379 287 /* get the device interface structure */ 288 void *iface = device_get_iface(dev, iface_idx); 289 if (NULL == iface) { 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) { 290 385 printf("%s: driver_connection_gen error - ", 291 386 driver->name); 292 printf(" device with handle %dhas no interface "387 printf("Function with handle %" PRIun " has no interface " 293 388 "with id %d.\n", handle, iface_idx); 294 ipc_answer_0(callid, ENOTSUP);389 async_answer_0(callid, ENOTSUP); 295 390 break; 296 391 } 297 392 298 393 /* 299 394 * Get the corresponding interface for remote request 300 395 * handling ("remote interface"). 301 396 */ 302 remote_iface_t *rem_iface = get_remote_iface(iface_idx);303 assert( NULL != rem_iface);304 397 remote_iface_t *rem_iface = get_remote_iface(iface_idx); 398 assert(rem_iface != NULL); 399 305 400 /* get the method of the remote interface */ 306 ipcarg_t iface_method_idx = IPC_GET_ARG1(call);401 sysarg_t iface_method_idx = IPC_GET_ARG1(call); 307 402 remote_iface_func_ptr_t iface_method_ptr = 308 403 get_remote_method(rem_iface, iface_method_idx); 309 if ( NULL == iface_method_ptr) {310 / / the interface has not such method404 if (iface_method_ptr == NULL) { 405 /* The interface has not such method */ 311 406 printf("%s: driver_connection_gen error - " 312 "invalid interface method.", driver->name); 313 ipc_answer_0(callid, ENOTSUP); 407 "invalid interface method " 408 "(index %" PRIun ").\n", 409 driver->name, iface_method_idx); 410 async_answer_0(callid, ENOTSUP); 314 411 break; 315 412 } … … 319 416 * receive parameters from the remote client and it will 320 417 * pass it to the corresponding local interface method 321 * associated with the deviceby its driver.418 * associated with the function by its driver. 322 419 */ 323 (*iface_method_ptr)( dev, iface, callid, &call);420 (*iface_method_ptr)(fun, ops, callid, &call); 324 421 break; 325 422 } … … 337 434 } 338 435 339 340 436 /** Function for handling connections to device driver. */ 341 437 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall) 342 438 { 343 439 /* Select interface */ 344 switch (( ipcarg_t) (IPC_GET_ARG1(*icall))) {440 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 345 441 case DRIVER_DEVMAN: 346 /* handle PnP eventsfrom device manager */442 /* Handle request from device manager */ 347 443 driver_connection_devman(iid, icall); 348 444 break; 349 445 case DRIVER_DRIVER: 350 /* handle request from drivers of child devices */446 /* Handle request from drivers of child devices */ 351 447 driver_connection_driver(iid, icall); 352 448 break; 353 449 case DRIVER_CLIENT: 354 /* handle requestsfrom client applications */450 /* Handle request from client applications */ 355 451 driver_connection_client(iid, icall); 356 452 break; 357 358 453 default: 359 454 /* No such interface */ 360 ipc_answer_0(iid, ENOENT); 361 } 362 } 363 364 int child_device_register(device_t *child, device_t *parent) 365 { 366 assert(NULL != child->name); 367 455 async_answer_0(iid, ENOENT); 456 } 457 } 458 459 /** Create new device structure. 460 * 461 * @return The device structure. 462 */ 463 static ddf_dev_t *create_device(void) 464 { 465 ddf_dev_t *dev; 466 467 dev = malloc(sizeof(ddf_dev_t)); 468 if (dev == NULL) 469 return NULL; 470 471 memset(dev, 0, sizeof(ddf_dev_t)); 472 return dev; 473 } 474 475 /** Create new function structure. 476 * 477 * @return The device structure. 478 */ 479 static ddf_fun_t *create_function(void) 480 { 481 ddf_fun_t *fun; 482 483 fun = calloc(1, sizeof(ddf_fun_t)); 484 if (fun == NULL) 485 return NULL; 486 487 init_match_ids(&fun->match_ids); 488 link_initialize(&fun->link); 489 490 return fun; 491 } 492 493 /** Delete device structure. 494 * 495 * @param dev The device structure. 496 */ 497 static void delete_device(ddf_dev_t *dev) 498 { 499 free(dev); 500 } 501 502 /** Delete device structure. 503 * 504 * @param dev The device structure. 505 */ 506 static void delete_function(ddf_fun_t *fun) 507 { 508 clean_match_ids(&fun->match_ids); 509 if (fun->name != NULL) 510 free(fun->name); 511 free(fun); 512 } 513 514 /** Create a DDF function node. 515 * 516 * Create a DDF function (in memory). Both child devices and external clients 517 * communicate with a device via its functions. 518 * 519 * The created function node is fully formed, but only exists in the memory 520 * of the client task. In order to be visible to the system, the function 521 * must be bound using ddf_fun_bind(). 522 * 523 * This function should only fail if there is not enough free memory. 524 * Specifically, this function succeeds even if @a dev already has 525 * a (bound) function with the same name. 526 * 527 * Type: A function of type fun_inner indicates that DDF should attempt 528 * to attach child devices to the function. fun_exposed means that 529 * the function should be exported to external clients (applications). 530 * 531 * @param dev Device to which we are adding function 532 * @param ftype Type of function (fun_inner or fun_exposed) 533 * @param name Name of function 534 * 535 * @return New function or @c NULL if memory is not available 536 */ 537 ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name) 538 { 539 ddf_fun_t *fun; 540 541 fun = create_function(); 542 if (fun == NULL) 543 return NULL; 544 545 fun->bound = false; 546 fun->dev = dev; 547 fun->ftype = ftype; 548 549 fun->name = str_dup(name); 550 if (fun->name == NULL) { 551 delete_function(fun); 552 return NULL; 553 } 554 555 return fun; 556 } 557 558 /** Destroy DDF function node. 559 * 560 * Destroy a function previously created with ddf_fun_create(). The function 561 * must not be bound. 562 * 563 * @param fun Function to destroy 564 */ 565 void ddf_fun_destroy(ddf_fun_t *fun) 566 { 567 assert(fun->bound == false); 568 delete_function(fun); 569 } 570 571 static void *function_get_ops(ddf_fun_t *fun, dev_inferface_idx_t idx) 572 { 573 assert(is_valid_iface_idx(idx)); 574 if (fun->ops == NULL) 575 return NULL; 576 return fun->ops->interfaces[idx]; 577 } 578 579 /** Bind a function node. 580 * 581 * Bind the specified function to the system. This effectively makes 582 * the function visible to the system (uploads it to the server). 583 * 584 * This function can fail for several reasons. Specifically, 585 * it will fail if the device already has a bound function of 586 * the same name. 587 * 588 * @param fun Function to bind 589 * @return EOK on success or negative error code 590 */ 591 int ddf_fun_bind(ddf_fun_t *fun) 592 { 593 assert(fun->name != NULL); 594 368 595 int res; 369 596 370 add_to_devices_list(child); 371 res = devman_child_device_register(child->name, &child->match_ids, 372 parent->handle, &child->handle); 373 if (EOK == res) 597 add_to_functions_list(fun); 598 res = devman_add_function(fun->name, fun->ftype, &fun->match_ids, 599 fun->dev->handle, &fun->handle); 600 if (res != EOK) { 601 remove_from_functions_list(fun); 374 602 return res; 375 remove_from_devices_list(child); 603 } 604 605 fun->bound = true; 376 606 return res; 377 607 } 378 608 379 int driver_main(driver_t *drv) 380 { 609 /** Add single match ID to inner function. 610 * 611 * Construct and add a single match ID to the specified function. 612 * Cannot be called when the function node is bound. 613 * 614 * @param fun Function 615 * @param match_id_str Match string 616 * @param match_score Match score 617 * @return EOK on success, ENOMEM if out of memory. 618 */ 619 int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str, 620 int match_score) 621 { 622 match_id_t *match_id; 623 624 assert(fun->bound == false); 625 assert(fun->ftype == fun_inner); 626 627 match_id = create_match_id(); 628 if (match_id == NULL) 629 return ENOMEM; 630 631 match_id->id = match_id_str; 632 match_id->score = 90; 633 634 add_match_id(&fun->match_ids, match_id); 635 return EOK; 636 } 637 638 /** Get default handler for client requests */ 639 static remote_handler_t *function_get_default_handler(ddf_fun_t *fun) 640 { 641 if (fun->ops == NULL) 642 return NULL; 643 return fun->ops->default_handler; 644 } 645 646 /** Add exposed function to class. 647 * 648 * Must only be called when the function is bound. 649 */ 650 int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name) 651 { 652 assert(fun->bound == true); 653 assert(fun->ftype == fun_exposed); 654 655 return devman_add_device_to_class(fun->handle, class_name); 656 } 657 658 int ddf_driver_main(driver_t *drv) 659 { 660 int rc; 661 381 662 /* 382 663 * Remember the driver structure - driver_ops will be called by generic … … 384 665 */ 385 666 driver = drv; 386 667 387 668 /* Initialize the list of interrupt contexts. */ 388 669 init_interrupt_context_list(&interrupt_contexts); … … 392 673 393 674 /* 394 * Register driver by device manager with generic handler for incoming395 * connections.675 * Register driver with device manager using generic handler for 676 * incoming connections. 396 677 */ 397 devman_driver_register(driver->name, driver_connection); 678 rc = devman_driver_register(driver->name, driver_connection); 679 if (rc != EOK) { 680 printf("Error: Failed to register driver with device manager " 681 "(%s).\n", (rc == EEXISTS) ? "driver already started" : 682 str_error(rc)); 683 684 return 1; 685 } 686 687 /* Return success from the task since server has started. */ 688 rc = task_retval(0); 689 if (rc != EOK) 690 return 1; 398 691 399 692 async_manager(); 400 693 401 694 /* Never reached. */ 402 695 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.