Ignore:
File:
1 edited

Legend:

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

    r2a770a35 r5fdd7c3  
    11/*
    22 * Copyright (c) 2010 Lenka Trochtova
    3  * Copyright (c) 2011 Jiri Svoboda
    43 * All rights reserved.
    54 *
     
    5049#include <errno.h>
    5150#include <inttypes.h>
    52 #include <devman.h>
    5351
    5452#include <ipc/driver.h>
    5553
    5654#include "dev_iface.h"
    57 #include "ddf/driver.h"
    58 #include "ddf/interrupt.h"
     55#include "driver.h"
    5956
    6057/** Driver structure */
     
    6259
    6360/** Devices */
    64 LIST_INITIALIZE(functions);
    65 FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     61LIST_INITIALIZE(devices);
     62FIBRIL_MUTEX_INITIALIZE(devices_mutex);
    6663
    6764/** Interrupts */
     
    7976};
    8077
    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);
    8578
    8679static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     
    157150
    158151interrupt_context_t *
    159 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)
    160153{
    161154        fibril_mutex_lock(&list->mutex);
     
    179172
    180173int
    181 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,
    182175    irq_code_t *pseudocode)
    183176{
     
    193186                pseudocode = &default_pseudocode;
    194187       
    195         int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
     188        int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode);
    196189        if (res != EOK) {
    197190                remove_interrupt_context(&interrupt_contexts, ctx);
     
    202195}
    203196
    204 int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
     197int unregister_interrupt_handler(device_t *dev, int irq)
    205198{
    206199        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
    207200            dev, irq);
    208         int res = unregister_irq(irq, dev->handle);
     201        int res = ipc_unregister_irq(irq, dev->handle);
    209202       
    210203        if (ctx != NULL) {
     
    216209}
    217210
    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;
     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;
    244237                }
    245                
    246238                link = link->next;
    247239        }
    248240       
    249         fibril_mutex_unlock(&functions_mutex);
     241        fibril_mutex_unlock(&devices_mutex);
    250242       
    251243        return NULL;
     
    258250       
    259251        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();
     252        devman_handle_t parent_dev_handle = IPC_GET_ARG2(*icall);
     253       
     254        device_t *dev = create_device();
    263255        dev->handle = dev_handle;
    264 
     256       
    265257        async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
    266258        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);
    273262       
    274263        res = driver->driver_ops->add_device(dev);
     
    279268                printf("%s: failed to add a new device with handle = %" PRIun ".\n",
    280269                    driver->name, dev_handle);
     270                remove_from_devices_list(dev);
    281271                delete_device(dev);
    282272        }
    283273       
    284         async_answer_0(iid, res);
     274        ipc_answer_0(iid, res);
    285275}
    286276
     
    288278{
    289279        /* Accept connection */
    290         async_answer_0(iid, EOK);
     280        ipc_answer_0(iid, EOK);
    291281       
    292282        bool cont = true;
     
    303293                        break;
    304294                default:
    305                         async_answer_0(callid, ENOENT);
     295                        ipc_answer_0(callid, ENOENT);
    306296                }
    307297        }
     
    321311         */
    322312        devman_handle_t handle = IPC_GET_ARG2(*icall);
    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"
     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"
    327317                    " %" PRIun " was found.\n", driver->name, handle);
    328                 async_answer_0(iid, ENOENT);
     318                ipc_answer_0(iid, ENOENT);
    329319                return;
    330320        }
     
    337327       
    338328        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);
    344334        if (ret != EOK)
    345335                return;
     
    354344                switch  (method) {
    355345                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);
    360350                        return;
    361351                default:
     
    366356                        if (!is_valid_iface_idx(iface_idx)) {
    367357                                remote_handler_t *default_handler =
    368                                     function_get_default_handler(fun);
     358                                    device_get_default_handler(dev);
    369359                                if (default_handler != NULL) {
    370                                         (*default_handler)(fun, callid, &call);
     360                                        (*default_handler)(dev, callid, &call);
    371361                                        break;
    372362                                }
    373                                
    374363                                /*
    375                                  * Function has no such interface and
     364                                 * This is not device's interface and the
    376365                                 * default handler is not provided.
    377366                                 */
     
    379368                                    "invalid interface id %d.",
    380369                                    driver->name, iface_idx);
    381                                 async_answer_0(callid, ENOTSUP);
     370                                ipc_answer_0(callid, ENOTSUP);
    382371                                break;
    383372                        }
    384373                       
    385                         /* calling one of the function's interfaces */
     374                        /* calling one of the device's interfaces */
    386375                       
    387376                        /* Get the interface ops structure. */
    388                         void *ops = function_get_ops(fun, iface_idx);
     377                        void *ops = device_get_ops(dev, iface_idx);
    389378                        if (ops == NULL) {
    390379                                printf("%s: driver_connection_gen error - ",
    391380                                    driver->name);
    392                                 printf("Function with handle %" PRIun " has no interface "
     381                                printf("device with handle %" PRIun " has no interface "
    393382                                    "with id %d.\n", handle, iface_idx);
    394                                 async_answer_0(callid, ENOTSUP);
     383                                ipc_answer_0(callid, ENOTSUP);
    395384                                break;
    396385                        }
     
    411400                                printf("%s: driver_connection_gen error - "
    412401                                    "invalid interface method.", driver->name);
    413                                 async_answer_0(callid, ENOTSUP);
     402                                ipc_answer_0(callid, ENOTSUP);
    414403                                break;
    415404                        }
     
    419408                         * receive parameters from the remote client and it will
    420409                         * pass it to the corresponding local interface method
    421                          * associated with the function by its driver.
     410                         * associated with the device by its driver.
    422411                         */
    423                         (*iface_method_ptr)(fun, ops, callid, &call);
     412                        (*iface_method_ptr)(dev, ops, callid, &call);
    424413                        break;
    425414                }
     
    436425        driver_connection_gen(iid, icall, false);
    437426}
     427
    438428
    439429/** Function for handling connections to device driver. */
     
    456446        default:
    457447                /* No such interface */
    458                 async_answer_0(iid, ENOENT);
     448                ipc_answer_0(iid, ENOENT);
    459449        }
    460450}
     
    464454 * @return              The device structure.
    465455 */
    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)
     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)
    472484                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
     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)
    488562                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
     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)
    662572{
    663573        /*
Note: See TracChangeset for help on using the changeset viewer.