Changes in uspace/lib/drv/generic/driver.c [2a770a35:5fdd7c3] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r2a770a35 r5fdd7c3 1 1 /* 2 2 * Copyright (c) 2010 Lenka Trochtova 3 * Copyright (c) 2011 Jiri Svoboda4 3 * All rights reserved. 5 4 * … … 50 49 #include <errno.h> 51 50 #include <inttypes.h> 52 #include <devman.h>53 51 54 52 #include <ipc/driver.h> 55 53 56 54 #include "dev_iface.h" 57 #include "ddf/driver.h" 58 #include "ddf/interrupt.h" 55 #include "driver.h" 59 56 60 57 /** Driver structure */ … … 62 59 63 60 /** Devices */ 64 LIST_INITIALIZE( functions);65 FIBRIL_MUTEX_INITIALIZE( functions_mutex);61 LIST_INITIALIZE(devices); 62 FIBRIL_MUTEX_INITIALIZE(devices_mutex); 66 63 67 64 /** Interrupts */ … … 79 76 }; 80 77 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);85 78 86 79 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall) … … 157 150 158 151 interrupt_context_t * 159 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) 160 153 { 161 154 fibril_mutex_lock(&list->mutex); … … 179 172 180 173 int 181 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, 182 175 irq_code_t *pseudocode) 183 176 { … … 193 186 pseudocode = &default_pseudocode; 194 187 195 int res = register_irq(irq, dev->handle, ctx->id, pseudocode);188 int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode); 196 189 if (res != EOK) { 197 190 remove_interrupt_context(&interrupt_contexts, ctx); … … 202 195 } 203 196 204 int unregister_interrupt_handler(d df_dev_t *dev, int irq)197 int unregister_interrupt_handler(device_t *dev, int irq) 205 198 { 206 199 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts, 207 200 dev, irq); 208 int res = unregister_irq(irq, dev->handle);201 int res = ipc_unregister_irq(irq, dev->handle); 209 202 210 203 if (ctx != NULL) { … … 216 209 } 217 210 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 d df_fun_t *driver_get_function(link_t *functions, devman_handle_t handle)233 { 234 d df_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;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; 244 237 } 245 246 238 link = link->next; 247 239 } 248 240 249 fibril_mutex_unlock(& functions_mutex);241 fibril_mutex_unlock(&devices_mutex); 250 242 251 243 return NULL; … … 258 250 259 251 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 260 devman_handle_t parent_ fun_handle = IPC_GET_ARG2(*icall);261 262 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(); 263 255 dev->handle = dev_handle; 264 256 265 257 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0); 266 258 dev->name = dev_name; 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; 259 260 add_to_devices_list(dev); 261 dev->parent = driver_get_device(&devices, parent_dev_handle); 273 262 274 263 res = driver->driver_ops->add_device(dev); … … 279 268 printf("%s: failed to add a new device with handle = %" PRIun ".\n", 280 269 driver->name, dev_handle); 270 remove_from_devices_list(dev); 281 271 delete_device(dev); 282 272 } 283 273 284 async_answer_0(iid, res);274 ipc_answer_0(iid, res); 285 275 } 286 276 … … 288 278 { 289 279 /* Accept connection */ 290 async_answer_0(iid, EOK);280 ipc_answer_0(iid, EOK); 291 281 292 282 bool cont = true; … … 303 293 break; 304 294 default: 305 async_answer_0(callid, ENOENT);295 ipc_answer_0(callid, ENOENT); 306 296 } 307 297 } … … 321 311 */ 322 312 devman_handle_t handle = IPC_GET_ARG2(*icall); 323 d df_fun_t *fun = driver_get_function(&functions, handle);324 325 if ( fun== NULL) {326 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" 327 317 " %" PRIun " was found.\n", driver->name, handle); 328 async_answer_0(iid, ENOENT);318 ipc_answer_0(iid, ENOENT); 329 319 return; 330 320 } … … 337 327 338 328 int ret = EOK; 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);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); 344 334 if (ret != EOK) 345 335 return; … … 354 344 switch (method) { 355 345 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);346 /* close the device */ 347 if (dev->ops != NULL && dev->ops->close != NULL) 348 (*dev->ops->close)(dev); 349 ipc_answer_0(callid, EOK); 360 350 return; 361 351 default: … … 366 356 if (!is_valid_iface_idx(iface_idx)) { 367 357 remote_handler_t *default_handler = 368 function_get_default_handler(fun);358 device_get_default_handler(dev); 369 359 if (default_handler != NULL) { 370 (*default_handler)( fun, callid, &call);360 (*default_handler)(dev, callid, &call); 371 361 break; 372 362 } 373 374 363 /* 375 * Function has no such interface and364 * This is not device's interface and the 376 365 * default handler is not provided. 377 366 */ … … 379 368 "invalid interface id %d.", 380 369 driver->name, iface_idx); 381 async_answer_0(callid, ENOTSUP);370 ipc_answer_0(callid, ENOTSUP); 382 371 break; 383 372 } 384 373 385 /* calling one of the function's interfaces */374 /* calling one of the device's interfaces */ 386 375 387 376 /* Get the interface ops structure. */ 388 void *ops = function_get_ops(fun, iface_idx);377 void *ops = device_get_ops(dev, iface_idx); 389 378 if (ops == NULL) { 390 379 printf("%s: driver_connection_gen error - ", 391 380 driver->name); 392 printf(" Functionwith handle %" PRIun " has no interface "381 printf("device with handle %" PRIun " has no interface " 393 382 "with id %d.\n", handle, iface_idx); 394 async_answer_0(callid, ENOTSUP);383 ipc_answer_0(callid, ENOTSUP); 395 384 break; 396 385 } … … 411 400 printf("%s: driver_connection_gen error - " 412 401 "invalid interface method.", driver->name); 413 async_answer_0(callid, ENOTSUP);402 ipc_answer_0(callid, ENOTSUP); 414 403 break; 415 404 } … … 419 408 * receive parameters from the remote client and it will 420 409 * pass it to the corresponding local interface method 421 * associated with the functionby its driver.410 * associated with the device by its driver. 422 411 */ 423 (*iface_method_ptr)( fun, ops, callid, &call);412 (*iface_method_ptr)(dev, ops, callid, &call); 424 413 break; 425 414 } … … 436 425 driver_connection_gen(iid, icall, false); 437 426 } 427 438 428 439 429 /** Function for handling connections to device driver. */ … … 456 446 default: 457 447 /* No such interface */ 458 async_answer_0(iid, ENOENT);448 ipc_answer_0(iid, ENOENT); 459 449 } 460 450 } … … 464 454 * @return The device structure. 465 455 */ 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) 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) 472 484 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) 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) 488 562 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 598 int res; 599 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); 605 return res; 606 } 607 608 fun->bound = true; 609 return res; 610 } 611 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 630 match_id = create_match_id(); 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); 638 return EOK; 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) 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) 662 572 { 663 573 /*
Note:
See TracChangeset
for help on using the changeset viewer.