Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/drv/generic/driver.c

    r26fa82bc r5fdd7c3  
    11/*
    22 * Copyright (c) 2010 Lenka Trochtova
    3  * Copyright (c) 2011 Jiri Svoboda
    43 * All rights reserved.
    54 *
     
    4746#include <stdlib.h>
    4847#include <str.h>
    49 #include <str_error.h>
    5048#include <ctype.h>
    5149#include <errno.h>
    5250#include <inttypes.h>
    53 #include <devman.h>
    5451
    5552#include <ipc/driver.h>
    5653
    5754#include "dev_iface.h"
    58 #include "ddf/driver.h"
    59 #include "ddf/interrupt.h"
     55#include "driver.h"
    6056
    6157/** Driver structure */
     
    6359
    6460/** Devices */
    65 LIST_INITIALIZE(functions);
    66 FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     61LIST_INITIALIZE(devices);
     62FIBRIL_MUTEX_INITIALIZE(devices_mutex);
    6763
    6864/** Interrupts */
     
    8076};
    8177
    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);
    8678
    8779static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     
    158150
    159151interrupt_context_t *
    160 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
     152find_interrupt_context(interrupt_context_list_t *list, device_t *dev, int irq)
    161153{
    162154        fibril_mutex_lock(&list->mutex);
     
    180172
    181173int
    182 register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
     174register_interrupt_handler(device_t *dev, int irq, interrupt_handler_t *handler,
    183175    irq_code_t *pseudocode)
    184176{
     
    194186                pseudocode = &default_pseudocode;
    195187       
    196         int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
     188        int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode);
    197189        if (res != EOK) {
    198190                remove_interrupt_context(&interrupt_contexts, ctx);
     
    203195}
    204196
    205 int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
     197int unregister_interrupt_handler(device_t *dev, int irq)
    206198{
    207199        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
    208200            dev, irq);
    209         int res = unregister_irq(irq, dev->handle);
     201        int res = ipc_unregister_irq(irq, dev->handle);
    210202       
    211203        if (ctx != NULL) {
     
    217209}
    218210
    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;
     211static 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
     218static 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
     225static 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;
    245237                }
    246                
    247238                link = link->next;
    248239        }
    249240       
    250         fibril_mutex_unlock(&functions_mutex);
     241        fibril_mutex_unlock(&devices_mutex);
    251242       
    252243        return NULL;
     
    259250       
    260251        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();
     252        devman_handle_t parent_dev_handle = IPC_GET_ARG2(*icall);
     253       
     254        device_t *dev = create_device();
    264255        dev->handle = dev_handle;
    265 
     256       
    266257        async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
    267258        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);
    274262       
    275263        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);
    277271                delete_device(dev);
    278        
    279         async_answer_0(iid, res);
     272        }
     273       
     274        ipc_answer_0(iid, res);
    280275}
    281276
     
    283278{
    284279        /* Accept connection */
    285         async_answer_0(iid, EOK);
     280        ipc_answer_0(iid, EOK);
    286281       
    287282        bool cont = true;
     
    298293                        break;
    299294                default:
    300                         async_answer_0(callid, ENOENT);
     295                        ipc_answer_0(callid, ENOENT);
    301296                }
    302297        }
     
    316311         */
    317312        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"
     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"
    322317                    " %" PRIun " was found.\n", driver->name, handle);
    323                 async_answer_0(iid, ENOENT);
     318                ipc_answer_0(iid, ENOENT);
    324319                return;
    325320        }
     
    332327       
    333328        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);
    339334        if (ret != EOK)
    340335                return;
     
    349344                switch  (method) {
    350345                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);
    355350                        return;
    356351                default:
     
    361356                        if (!is_valid_iface_idx(iface_idx)) {
    362357                                remote_handler_t *default_handler =
    363                                     function_get_default_handler(fun);
     358                                    device_get_default_handler(dev);
    364359                                if (default_handler != NULL) {
    365                                         (*default_handler)(fun, callid, &call);
     360                                        (*default_handler)(dev, callid, &call);
    366361                                        break;
    367362                                }
    368                                
    369363                                /*
    370                                  * Function has no such interface and
     364                                 * This is not device's interface and the
    371365                                 * default handler is not provided.
    372366                                 */
     
    374368                                    "invalid interface id %d.",
    375369                                    driver->name, iface_idx);
    376                                 async_answer_0(callid, ENOTSUP);
     370                                ipc_answer_0(callid, ENOTSUP);
    377371                                break;
    378372                        }
    379373                       
    380                         /* calling one of the function's interfaces */
     374                        /* calling one of the device's interfaces */
    381375                       
    382376                        /* Get the interface ops structure. */
    383                         void *ops = function_get_ops(fun, iface_idx);
     377                        void *ops = device_get_ops(dev, iface_idx);
    384378                        if (ops == NULL) {
    385379                                printf("%s: driver_connection_gen error - ",
    386380                                    driver->name);
    387                                 printf("Function with handle %" PRIun " has no interface "
     381                                printf("device with handle %" PRIun " has no interface "
    388382                                    "with id %d.\n", handle, iface_idx);
    389                                 async_answer_0(callid, ENOTSUP);
     383                                ipc_answer_0(callid, ENOTSUP);
    390384                                break;
    391385                        }
     
    403397                            get_remote_method(rem_iface, iface_method_idx);
    404398                        if (iface_method_ptr == NULL) {
    405                                 /* The interface has not such method */
     399                                // the interface has not such method
    406400                                printf("%s: driver_connection_gen error - "
    407401                                    "invalid interface method.", driver->name);
    408                                 async_answer_0(callid, ENOTSUP);
     402                                ipc_answer_0(callid, ENOTSUP);
    409403                                break;
    410404                        }
     
    414408                         * receive parameters from the remote client and it will
    415409                         * pass it to the corresponding local interface method
    416                          * associated with the function by its driver.
     410                         * associated with the device by its driver.
    417411                         */
    418                         (*iface_method_ptr)(fun, ops, callid, &call);
     412                        (*iface_method_ptr)(dev, ops, callid, &call);
    419413                        break;
    420414                }
     
    431425        driver_connection_gen(iid, icall, false);
    432426}
     427
    433428
    434429/** Function for handling connections to device driver. */
     
    451446        default:
    452447                /* No such interface */
    453                 async_answer_0(iid, ENOENT);
     448                ipc_answer_0(iid, ENOENT);
    454449        }
    455450}
     
    459454 * @return              The device structure.
    460455 */
    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)
     456device_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 */
     472void 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
     480void *device_get_ops(device_t *dev, dev_inferface_idx_t idx)
     481{
     482        assert(is_valid_iface_idx(idx));
     483        if (dev->ops == NULL)
    467484                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
     488int 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 */
     513int 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       
     544failure:
     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 */
     559remote_handler_t *device_get_default_handler(device_t *dev)
     560{
     561        if (dev->ops == NULL)
    483562                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
     566int 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
     571int driver_main(driver_t *drv)
     572{
    660573        /*
    661574         * Remember the driver structure - driver_ops will be called by generic
     
    671584       
    672585        /*
    673          * Register driver with device manager using generic handler for
    674          * incoming connections.
     586         * Register driver by device manager with generic handler for incoming
     587         * connections.
    675588         */
    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       
    690591        async_manager();
    691592       
Note: See TracChangeset for help on using the changeset viewer.