Changes in uspace/lib/drv/generic/driver.c [26fa82bc:5fdd7c3] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r26fa82bc r5fdd7c3 1 1 /* 2 2 * Copyright (c) 2010 Lenka Trochtova 3 * Copyright (c) 2011 Jiri Svoboda4 3 * All rights reserved. 5 4 * … … 47 46 #include <stdlib.h> 48 47 #include <str.h> 49 #include <str_error.h>50 48 #include <ctype.h> 51 49 #include <errno.h> 52 50 #include <inttypes.h> 53 #include <devman.h>54 51 55 52 #include <ipc/driver.h> 56 53 57 54 #include "dev_iface.h" 58 #include "ddf/driver.h" 59 #include "ddf/interrupt.h" 55 #include "driver.h" 60 56 61 57 /** Driver structure */ … … 63 59 64 60 /** Devices */ 65 LIST_INITIALIZE( functions);66 FIBRIL_MUTEX_INITIALIZE( functions_mutex);61 LIST_INITIALIZE(devices); 62 FIBRIL_MUTEX_INITIALIZE(devices_mutex); 67 63 68 64 /** Interrupts */ … … 80 76 }; 81 77 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);86 78 87 79 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall) … … 158 150 159 151 interrupt_context_t * 160 find_interrupt_context(interrupt_context_list_t *list, d df_dev_t *dev, int irq)152 find_interrupt_context(interrupt_context_list_t *list, device_t *dev, int irq) 161 153 { 162 154 fibril_mutex_lock(&list->mutex); … … 180 172 181 173 int 182 register_interrupt_handler(d df_dev_t *dev, int irq, interrupt_handler_t *handler,174 register_interrupt_handler(device_t *dev, int irq, interrupt_handler_t *handler, 183 175 irq_code_t *pseudocode) 184 176 { … … 194 186 pseudocode = &default_pseudocode; 195 187 196 int res = register_irq(irq, dev->handle, ctx->id, pseudocode);188 int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode); 197 189 if (res != EOK) { 198 190 remove_interrupt_context(&interrupt_contexts, ctx); … … 203 195 } 204 196 205 int unregister_interrupt_handler(d df_dev_t *dev, int irq)197 int unregister_interrupt_handler(device_t *dev, int irq) 206 198 { 207 199 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts, 208 200 dev, irq); 209 int res = unregister_irq(irq, dev->handle);201 int res = ipc_unregister_irq(irq, dev->handle); 210 202 211 203 if (ctx != NULL) { … … 217 209 } 218 210 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 d df_fun_t *driver_get_function(link_t *functions, devman_handle_t handle)234 { 235 d df_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;211 static void add_to_devices_list(device_t *dev) 212 { 213 fibril_mutex_lock(&devices_mutex); 214 list_append(&dev->link, &devices); 215 fibril_mutex_unlock(&devices_mutex); 216 } 217 218 static void remove_from_devices_list(device_t *dev) 219 { 220 fibril_mutex_lock(&devices_mutex); 221 list_remove(&dev->link); 222 fibril_mutex_unlock(&devices_mutex); 223 } 224 225 static device_t *driver_get_device(link_t *devices, devman_handle_t handle) 226 { 227 device_t *dev = NULL; 228 229 fibril_mutex_lock(&devices_mutex); 230 link_t *link = devices->next; 231 232 while (link != devices) { 233 dev = list_get_instance(link, device_t, link); 234 if (dev->handle == handle) { 235 fibril_mutex_unlock(&devices_mutex); 236 return dev; 245 237 } 246 247 238 link = link->next; 248 239 } 249 240 250 fibril_mutex_unlock(& functions_mutex);241 fibril_mutex_unlock(&devices_mutex); 251 242 252 243 return NULL; … … 259 250 260 251 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 261 devman_handle_t parent_ fun_handle = IPC_GET_ARG2(*icall);262 263 d df_dev_t *dev = create_device();252 devman_handle_t parent_dev_handle = IPC_GET_ARG2(*icall); 253 254 device_t *dev = create_device(); 264 255 dev->handle = dev_handle; 265 256 266 257 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0); 267 258 dev->name = dev_name; 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; 259 260 add_to_devices_list(dev); 261 dev->parent = driver_get_device(&devices, parent_dev_handle); 274 262 275 263 res = driver->driver_ops->add_device(dev); 276 if (res != EOK) 264 if (res == EOK) { 265 printf("%s: new device with handle=%" PRIun " was added.\n", 266 driver->name, dev_handle); 267 } else { 268 printf("%s: failed to add a new device with handle = %" PRIun ".\n", 269 driver->name, dev_handle); 270 remove_from_devices_list(dev); 277 271 delete_device(dev); 278 279 async_answer_0(iid, res); 272 } 273 274 ipc_answer_0(iid, res); 280 275 } 281 276 … … 283 278 { 284 279 /* Accept connection */ 285 async_answer_0(iid, EOK);280 ipc_answer_0(iid, EOK); 286 281 287 282 bool cont = true; … … 298 293 break; 299 294 default: 300 async_answer_0(callid, ENOENT);295 ipc_answer_0(callid, ENOENT); 301 296 } 302 297 } … … 316 311 */ 317 312 devman_handle_t handle = IPC_GET_ARG2(*icall); 318 d df_fun_t *fun = driver_get_function(&functions, handle);319 320 if ( fun== NULL) {321 printf("%s: driver_connection_gen error - no functionwith handle"313 device_t *dev = driver_get_device(&devices, handle); 314 315 if (dev == NULL) { 316 printf("%s: driver_connection_gen error - no device with handle" 322 317 " %" PRIun " was found.\n", driver->name, handle); 323 async_answer_0(iid, ENOENT);318 ipc_answer_0(iid, ENOENT); 324 319 return; 325 320 } … … 332 327 333 328 int ret = EOK; 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);329 /* open the device */ 330 if (dev->ops != NULL && dev->ops->open != NULL) 331 ret = (*dev->ops->open)(dev); 332 333 ipc_answer_0(iid, ret); 339 334 if (ret != EOK) 340 335 return; … … 349 344 switch (method) { 350 345 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);346 /* close the device */ 347 if (dev->ops != NULL && dev->ops->close != NULL) 348 (*dev->ops->close)(dev); 349 ipc_answer_0(callid, EOK); 355 350 return; 356 351 default: … … 361 356 if (!is_valid_iface_idx(iface_idx)) { 362 357 remote_handler_t *default_handler = 363 function_get_default_handler(fun);358 device_get_default_handler(dev); 364 359 if (default_handler != NULL) { 365 (*default_handler)( fun, callid, &call);360 (*default_handler)(dev, callid, &call); 366 361 break; 367 362 } 368 369 363 /* 370 * Function has no such interface and364 * This is not device's interface and the 371 365 * default handler is not provided. 372 366 */ … … 374 368 "invalid interface id %d.", 375 369 driver->name, iface_idx); 376 async_answer_0(callid, ENOTSUP);370 ipc_answer_0(callid, ENOTSUP); 377 371 break; 378 372 } 379 373 380 /* calling one of the function's interfaces */374 /* calling one of the device's interfaces */ 381 375 382 376 /* Get the interface ops structure. */ 383 void *ops = function_get_ops(fun, iface_idx);377 void *ops = device_get_ops(dev, iface_idx); 384 378 if (ops == NULL) { 385 379 printf("%s: driver_connection_gen error - ", 386 380 driver->name); 387 printf(" Functionwith handle %" PRIun " has no interface "381 printf("device with handle %" PRIun " has no interface " 388 382 "with id %d.\n", handle, iface_idx); 389 async_answer_0(callid, ENOTSUP);383 ipc_answer_0(callid, ENOTSUP); 390 384 break; 391 385 } … … 403 397 get_remote_method(rem_iface, iface_method_idx); 404 398 if (iface_method_ptr == NULL) { 405 / * The interface has not such method */399 // the interface has not such method 406 400 printf("%s: driver_connection_gen error - " 407 401 "invalid interface method.", driver->name); 408 async_answer_0(callid, ENOTSUP);402 ipc_answer_0(callid, ENOTSUP); 409 403 break; 410 404 } … … 414 408 * receive parameters from the remote client and it will 415 409 * pass it to the corresponding local interface method 416 * associated with the functionby its driver.410 * associated with the device by its driver. 417 411 */ 418 (*iface_method_ptr)( fun, ops, callid, &call);412 (*iface_method_ptr)(dev, ops, callid, &call); 419 413 break; 420 414 } … … 431 425 driver_connection_gen(iid, icall, false); 432 426 } 427 433 428 434 429 /** Function for handling connections to device driver. */ … … 451 446 default: 452 447 /* No such interface */ 453 async_answer_0(iid, ENOENT);448 ipc_answer_0(iid, ENOENT); 454 449 } 455 450 } … … 459 454 * @return The device structure. 460 455 */ 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) 456 device_t *create_device(void) 457 { 458 device_t *dev = malloc(sizeof(device_t)); 459 460 if (dev != NULL) { 461 memset(dev, 0, sizeof(device_t)); 462 init_match_ids(&dev->match_ids); 463 } 464 465 return dev; 466 } 467 468 /** Delete device structure. 469 * 470 * @param dev The device structure. 471 */ 472 void delete_device(device_t *dev) 473 { 474 clean_match_ids(&dev->match_ids); 475 if (dev->name != NULL) 476 free(dev->name); 477 free(dev); 478 } 479 480 void *device_get_ops(device_t *dev, dev_inferface_idx_t idx) 481 { 482 assert(is_valid_iface_idx(idx)); 483 if (dev->ops == NULL) 467 484 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) 485 return dev->ops->interfaces[idx]; 486 } 487 488 int child_device_register(device_t *child, device_t *parent) 489 { 490 assert(child->name != NULL); 491 492 int res; 493 494 add_to_devices_list(child); 495 res = devman_child_device_register(child->name, &child->match_ids, 496 parent->handle, &child->handle); 497 if (res != EOK) { 498 remove_from_devices_list(child); 499 return res; 500 } 501 502 return res; 503 } 504 505 /** Wrapper for child_device_register for devices with single match id. 506 * 507 * @param parent Parent device. 508 * @param child_name Child device name. 509 * @param child_match_id Child device match id. 510 * @param child_match_score Child device match score. 511 * @return Error code. 512 */ 513 int child_device_register_wrapper(device_t *parent, const char *child_name, 514 const char *child_match_id, int child_match_score) 515 { 516 device_t *child = NULL; 517 match_id_t *match_id = NULL; 518 int rc; 519 520 child = create_device(); 521 if (child == NULL) { 522 rc = ENOMEM; 523 goto failure; 524 } 525 526 child->name = child_name; 527 528 match_id = create_match_id(); 529 if (match_id == NULL) { 530 rc = ENOMEM; 531 goto failure; 532 } 533 534 match_id->id = child_match_id; 535 match_id->score = child_match_score; 536 add_match_id(&child->match_ids, match_id); 537 538 rc = child_device_register(child, parent); 539 if (rc != EOK) 540 goto failure; 541 542 return EOK; 543 544 failure: 545 if (match_id != NULL) { 546 match_id->id = NULL; 547 delete_match_id(match_id); 548 } 549 550 if (child != NULL) { 551 child->name = NULL; 552 delete_device(child); 553 } 554 555 return rc; 556 } 557 558 /** Get default handler for client requests */ 559 remote_handler_t *device_get_default_handler(device_t *dev) 560 { 561 if (dev->ops == NULL) 483 562 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 593 int res; 594 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); 600 return res; 601 } 602 603 fun->bound = true; 604 return res; 605 } 606 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 563 return dev->ops->default_handler; 564 } 565 566 int add_device_to_class(device_t *dev, const char *class_name) 567 { 568 return devman_add_device_to_class(dev->handle, class_name); 569 } 570 571 int driver_main(driver_t *drv) 572 { 660 573 /* 661 574 * Remember the driver structure - driver_ops will be called by generic … … 671 584 672 585 /* 673 * Register driver with device manager using generic handler for674 * incomingconnections.586 * Register driver by device manager with generic handler for incoming 587 * connections. 675 588 */ 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; 689 589 devman_driver_register(driver->name, driver_connection); 590 690 591 async_manager(); 691 592
Note:
See TracChangeset
for help on using the changeset viewer.