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