Changeset b5e68c8 in mainline for uspace/lib/drv/generic/driver.c
- Timestamp:
- 2011-05-12T16:49:44Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f36787d7
- Parents:
- e80329d6 (diff), 750636a (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
-
uspace/lib/drv/generic/driver.c (modified) (16 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
re80329d6 rb5e68c8 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 407 "invalid interface method.", driver->name); 313 ipc_answer_0(callid, ENOTSUP);408 async_answer_0(callid, ENOTSUP); 314 409 break; 315 410 } … … 319 414 * receive parameters from the remote client and it will 320 415 * pass it to the corresponding local interface method 321 * associated with the deviceby its driver.416 * associated with the function by its driver. 322 417 */ 323 (*iface_method_ptr)( dev, iface, callid, &call);418 (*iface_method_ptr)(fun, ops, callid, &call); 324 419 break; 325 420 } … … 337 432 } 338 433 339 340 434 /** Function for handling connections to device driver. */ 341 435 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall) 342 436 { 343 437 /* Select interface */ 344 switch (( ipcarg_t) (IPC_GET_ARG1(*icall))) {438 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 345 439 case DRIVER_DEVMAN: 346 /* handle PnP eventsfrom device manager */440 /* Handle request from device manager */ 347 441 driver_connection_devman(iid, icall); 348 442 break; 349 443 case DRIVER_DRIVER: 350 /* handle request from drivers of child devices */444 /* Handle request from drivers of child devices */ 351 445 driver_connection_driver(iid, icall); 352 446 break; 353 447 case DRIVER_CLIENT: 354 /* handle requestsfrom client applications */448 /* Handle request from client applications */ 355 449 driver_connection_client(iid, icall); 356 450 break; 357 358 451 default: 359 452 /* 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 453 async_answer_0(iid, ENOENT); 454 } 455 } 456 457 /** Create new device structure. 458 * 459 * @return The device structure. 460 */ 461 static ddf_dev_t *create_device(void) 462 { 463 ddf_dev_t *dev; 464 465 dev = malloc(sizeof(ddf_dev_t)); 466 if (dev == NULL) 467 return NULL; 468 469 memset(dev, 0, sizeof(ddf_dev_t)); 470 return dev; 471 } 472 473 /** Create new function structure. 474 * 475 * @return The device structure. 476 */ 477 static ddf_fun_t *create_function(void) 478 { 479 ddf_fun_t *fun; 480 481 fun = calloc(1, sizeof(ddf_fun_t)); 482 if (fun == NULL) 483 return NULL; 484 485 init_match_ids(&fun->match_ids); 486 link_initialize(&fun->link); 487 488 return fun; 489 } 490 491 /** Delete device structure. 492 * 493 * @param dev The device structure. 494 */ 495 static void delete_device(ddf_dev_t *dev) 496 { 497 free(dev); 498 } 499 500 /** Delete device structure. 501 * 502 * @param dev The device structure. 503 */ 504 static void delete_function(ddf_fun_t *fun) 505 { 506 clean_match_ids(&fun->match_ids); 507 if (fun->name != NULL) 508 free(fun->name); 509 free(fun); 510 } 511 512 /** Create a DDF function node. 513 * 514 * Create a DDF function (in memory). Both child devices and external clients 515 * communicate with a device via its functions. 516 * 517 * The created function node is fully formed, but only exists in the memory 518 * of the client task. In order to be visible to the system, the function 519 * must be bound using ddf_fun_bind(). 520 * 521 * This function should only fail if there is not enough free memory. 522 * Specifically, this function succeeds even if @a dev already has 523 * a (bound) function with the same name. 524 * 525 * Type: A function of type fun_inner indicates that DDF should attempt 526 * to attach child devices to the function. fun_exposed means that 527 * the function should be exported to external clients (applications). 528 * 529 * @param dev Device to which we are adding function 530 * @param ftype Type of function (fun_inner or fun_exposed) 531 * @param name Name of function 532 * 533 * @return New function or @c NULL if memory is not available 534 */ 535 ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name) 536 { 537 ddf_fun_t *fun; 538 539 fun = create_function(); 540 if (fun == NULL) 541 return NULL; 542 543 fun->bound = false; 544 fun->dev = dev; 545 fun->ftype = ftype; 546 547 fun->name = str_dup(name); 548 if (fun->name == NULL) { 549 delete_function(fun); 550 return NULL; 551 } 552 553 return fun; 554 } 555 556 /** Destroy DDF function node. 557 * 558 * Destroy a function previously created with ddf_fun_create(). The function 559 * must not be bound. 560 * 561 * @param fun Function to destroy 562 */ 563 void ddf_fun_destroy(ddf_fun_t *fun) 564 { 565 assert(fun->bound == false); 566 delete_function(fun); 567 } 568 569 static void *function_get_ops(ddf_fun_t *fun, dev_inferface_idx_t idx) 570 { 571 assert(is_valid_iface_idx(idx)); 572 if (fun->ops == NULL) 573 return NULL; 574 return fun->ops->interfaces[idx]; 575 } 576 577 /** Bind a function node. 578 * 579 * Bind the specified function to the system. This effectively makes 580 * the function visible to the system (uploads it to the server). 581 * 582 * This function can fail for several reasons. Specifically, 583 * it will fail if the device already has a bound function of 584 * the same name. 585 * 586 * @param fun Function to bind 587 * @return EOK on success or negative error code 588 */ 589 int ddf_fun_bind(ddf_fun_t *fun) 590 { 591 assert(fun->name != NULL); 592 368 593 int res; 369 594 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) 595 add_to_functions_list(fun); 596 res = devman_add_function(fun->name, fun->ftype, &fun->match_ids, 597 fun->dev->handle, &fun->handle); 598 if (res != EOK) { 599 remove_from_functions_list(fun); 374 600 return res; 375 remove_from_devices_list(child); 601 } 602 603 fun->bound = true; 376 604 return res; 377 605 } 378 606 379 int driver_main(driver_t *drv) 380 { 607 /** Add single match ID to inner function. 608 * 609 * Construct and add a single match ID to the specified function. 610 * Cannot be called when the function node is bound. 611 * 612 * @param fun Function 613 * @param match_id_str Match string 614 * @param match_score Match score 615 * @return EOK on success, ENOMEM if out of memory. 616 */ 617 int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str, 618 int match_score) 619 { 620 match_id_t *match_id; 621 622 assert(fun->bound == false); 623 assert(fun->ftype == fun_inner); 624 625 match_id = create_match_id(); 626 if (match_id == NULL) 627 return ENOMEM; 628 629 match_id->id = match_id_str; 630 match_id->score = 90; 631 632 add_match_id(&fun->match_ids, match_id); 633 return EOK; 634 } 635 636 /** Get default handler for client requests */ 637 static remote_handler_t *function_get_default_handler(ddf_fun_t *fun) 638 { 639 if (fun->ops == NULL) 640 return NULL; 641 return fun->ops->default_handler; 642 } 643 644 /** Add exposed function to class. 645 * 646 * Must only be called when the function is bound. 647 */ 648 int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name) 649 { 650 assert(fun->bound == true); 651 assert(fun->ftype == fun_exposed); 652 653 return devman_add_device_to_class(fun->handle, class_name); 654 } 655 656 int ddf_driver_main(driver_t *drv) 657 { 658 int rc; 659 381 660 /* 382 661 * Remember the driver structure - driver_ops will be called by generic … … 384 663 */ 385 664 driver = drv; 386 665 387 666 /* Initialize the list of interrupt contexts. */ 388 667 init_interrupt_context_list(&interrupt_contexts); … … 392 671 393 672 /* 394 * Register driver by device manager with generic handler for incoming395 * connections.673 * Register driver with device manager using generic handler for 674 * incoming connections. 396 675 */ 397 devman_driver_register(driver->name, driver_connection); 676 rc = devman_driver_register(driver->name, driver_connection); 677 if (rc != EOK) { 678 printf("Error: Failed to register driver with device manager " 679 "(%s).\n", (rc == EEXISTS) ? "driver already started" : 680 str_error(rc)); 681 682 return 1; 683 } 684 685 /* Return success from the task since server has started. */ 686 rc = task_retval(0); 687 if (rc != EOK) 688 return 1; 398 689 399 690 async_manager(); 400 691 401 692 /* Never reached. */ 402 693 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.
