Changes in uspace/lib/drv/generic/driver.c [2a770a35:228e490] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/driver.c
r2a770a35 r228e490 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 #include "dev_iface.h" 57 #include "ddf/driver.h" 58 #include "ddf/interrupt.h" 59 60 /** Driver structure */ 54 #include "driver.h" 55 56 /* driver structure */ 57 61 58 static driver_t *driver; 62 59 63 /** Devices */ 64 LIST_INITIALIZE(functions); 65 FIBRIL_MUTEX_INITIALIZE(functions_mutex); 66 67 /** Interrupts */ 60 /* devices */ 61 62 LIST_INITIALIZE(devices); 63 FIBRIL_MUTEX_INITIALIZE(devices_mutex); 64 65 /* interrupts */ 66 68 67 static interrupt_context_list_t interrupt_contexts; 69 68 … … 79 78 }; 80 79 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 80 86 81 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall) … … 90 85 91 86 ctx = find_interrupt_context_by_id(&interrupt_contexts, id); 92 if ( ctx != NULL && ctx->handler != NULL)87 if (NULL != ctx && NULL != ctx->handler) 93 88 (*ctx->handler)(ctx->dev, iid, icall); 94 89 } 95 90 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 void121 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 180 91 int 181 register_interrupt_handler(d df_dev_t *dev, int irq, interrupt_handler_t *handler,92 register_interrupt_handler(device_t *dev, int irq, interrupt_handler_t *handler, 182 93 irq_code_t *pseudocode) 183 94 { … … 190 101 add_interrupt_context(&interrupt_contexts, ctx); 191 102 192 if ( pseudocode == NULL)103 if (NULL == pseudocode) 193 104 pseudocode = &default_pseudocode; 194 105 195 int res = register_irq(irq, dev->handle, ctx->id, pseudocode);196 if ( res != EOK) {106 int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode); 107 if (0 != res) { 197 108 remove_interrupt_context(&interrupt_contexts, ctx); 198 109 delete_interrupt_context(ctx); … … 202 113 } 203 114 204 int unregister_interrupt_handler(d df_dev_t *dev, int irq)115 int unregister_interrupt_handler(device_t *dev, int irq) 205 116 { 206 117 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts, 207 118 dev, irq); 208 int res = unregister_irq(irq, dev->handle);209 210 if ( ctx != NULL) {119 int res = ipc_unregister_irq(irq, dev->handle); 120 121 if (NULL != ctx) { 211 122 remove_interrupt_context(&interrupt_contexts, ctx); 212 123 delete_interrupt_context(ctx); 213 124 } 214 215 125 return res; 216 126 } 217 127 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; 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; 244 153 } 245 246 154 link = link->next; 247 155 } 248 249 fibril_mutex_unlock(&functions_mutex); 250 156 fibril_mutex_unlock(&devices_mutex); 157 251 158 return NULL; 252 159 } … … 255 162 { 256 163 char *dev_name = NULL; 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 d df_dev_t *dev = create_device();164 int res = EOK; 165 166 devman_handle_t dev_handle = IPC_GET_ARG1(*icall); 167 devman_handle_t parent_dev_handle = IPC_GET_ARG2(*icall); 168 169 device_t *dev = create_device(); 263 170 dev->handle = dev_handle; 264 171 265 172 async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0); 266 173 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; 174 175 add_to_devices_list(dev); 176 dev->parent = driver_get_device(&devices, parent_dev_handle); 273 177 274 178 res = driver->driver_ops->add_device(dev); 275 if ( res == EOK) {179 if (0 == res) { 276 180 printf("%s: new device with handle=%" PRIun " was added.\n", 277 181 driver->name, dev_handle); … … 279 183 printf("%s: failed to add a new device with handle = %" PRIun ".\n", 280 184 driver->name, dev_handle); 185 remove_from_devices_list(dev); 281 186 delete_device(dev); 282 187 } 283 188 284 async_answer_0(iid, res);189 ipc_answer_0(iid, res); 285 190 } 286 191 … … 288 193 { 289 194 /* Accept connection */ 290 async_answer_0(iid, EOK);291 195 ipc_answer_0(iid, EOK); 196 292 197 bool cont = true; 293 198 while (cont) { 294 199 ipc_call_t call; 295 200 ipc_callid_t callid = async_get_call(&call); 296 201 297 202 switch (IPC_GET_IMETHOD(call)) { 298 203 case IPC_M_PHONE_HUNGUP: … … 303 208 break; 304 209 default: 305 async_answer_0(callid, ENOENT);210 ipc_answer_0(callid, ENOENT); 306 211 } 307 212 } … … 321 226 */ 322 227 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"228 device_t *dev = driver_get_device(&devices, handle); 229 230 if (dev == NULL) { 231 printf("%s: driver_connection_gen error - no device with handle" 327 232 " %" PRIun " was found.\n", driver->name, handle); 328 async_answer_0(iid, ENOENT);233 ipc_answer_0(iid, ENOENT); 329 234 return; 330 235 } … … 335 240 * use the device. 336 241 */ 337 242 338 243 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);344 if ( 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) 345 250 return; 346 251 347 252 while (1) { 348 253 ipc_callid_t callid; … … 353 258 354 259 switch (method) { 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);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); 360 265 return; 361 default: 266 default: 362 267 /* convert ipc interface id to interface index */ 363 268 … … 366 271 if (!is_valid_iface_idx(iface_idx)) { 367 272 remote_handler_t *default_handler = 368 function_get_default_handler(fun);369 if ( default_handler != NULL) {370 (*default_handler)( fun, callid, &call);273 device_get_default_handler(dev); 274 if (NULL != default_handler) { 275 (*default_handler)(dev, callid, &call); 371 276 break; 372 277 } 373 374 278 /* 375 * Function has no such interface and279 * This is not device's interface and the 376 280 * default handler is not provided. 377 281 */ … … 379 283 "invalid interface id %d.", 380 284 driver->name, iface_idx); 381 async_answer_0(callid, ENOTSUP);285 ipc_answer_0(callid, ENOTSUP); 382 286 break; 383 287 } 288 289 /* calling one of the device's interfaces */ 384 290 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) { 291 /* get the device interface structure */ 292 void *iface = device_get_iface(dev, iface_idx); 293 if (NULL == iface) { 390 294 printf("%s: driver_connection_gen error - ", 391 295 driver->name); 392 printf(" Functionwith handle %" PRIun " has no interface "296 printf("device with handle %" PRIun " has no interface " 393 297 "with id %d.\n", handle, iface_idx); 394 async_answer_0(callid, ENOTSUP);298 ipc_answer_0(callid, ENOTSUP); 395 299 break; 396 300 } 397 301 398 302 /* 399 303 * Get the corresponding interface for remote request 400 304 * handling ("remote interface"). 401 305 */ 402 remote_iface_t *rem_iface = get_remote_iface(iface_idx);403 assert( rem_iface != NULL);404 306 remote_iface_t* rem_iface = get_remote_iface(iface_idx); 307 assert(NULL != rem_iface); 308 405 309 /* get the method of the remote interface */ 406 310 sysarg_t iface_method_idx = IPC_GET_ARG1(call); 407 311 remote_iface_func_ptr_t iface_method_ptr = 408 312 get_remote_method(rem_iface, iface_method_idx); 409 if ( iface_method_ptr == NULL) {313 if (NULL == iface_method_ptr) { 410 314 // the interface has not such method 411 315 printf("%s: driver_connection_gen error - " 412 316 "invalid interface method.", driver->name); 413 async_answer_0(callid, ENOTSUP);317 ipc_answer_0(callid, ENOTSUP); 414 318 break; 415 319 } … … 419 323 * receive parameters from the remote client and it will 420 324 * pass it to the corresponding local interface method 421 * associated with the functionby its driver.325 * associated with the device by its driver. 422 326 */ 423 (*iface_method_ptr)( fun, ops, callid, &call);327 (*iface_method_ptr)(dev, iface, callid, &call); 424 328 break; 425 329 } … … 436 340 driver_connection_gen(iid, icall, false); 437 341 } 342 438 343 439 344 /** Function for handling connections to device driver. */ … … 443 348 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 444 349 case DRIVER_DEVMAN: 445 /* Handle requestfrom device manager */350 /* handle PnP events from device manager */ 446 351 driver_connection_devman(iid, icall); 447 352 break; 448 353 case DRIVER_DRIVER: 449 /* Handle request from drivers of child devices */354 /* handle request from drivers of child devices */ 450 355 driver_connection_driver(iid, icall); 451 356 break; 452 357 case DRIVER_CLIENT: 453 /* Handle requestfrom client applications */358 /* handle requests from client applications */ 454 359 driver_connection_client(iid, icall); 455 360 break; 361 456 362 default: 457 363 /* No such interface */ 458 async_answer_0(iid, ENOENT); 459 } 460 } 461 462 /** Create new device structure. 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 372 int res; 373 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) 378 return res; 379 remove_from_devices_list(child); 380 return res; 381 } 382 383 /** Wrapper for child_device_register for devices with single match id. 463 384 * 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 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 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 630 406 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); 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 638 420 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) 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) 662 437 { 663 438 /* … … 666 441 */ 667 442 driver = drv; 668 443 669 444 /* Initialize the list of interrupt contexts. */ 670 445 init_interrupt_context_list(&interrupt_contexts); … … 678 453 */ 679 454 devman_driver_register(driver->name, driver_connection); 680 455 681 456 async_manager(); 682 457 683 458 /* Never reached. */ 684 459 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.