Ignore:
File:
1 edited

Legend:

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

    r228e490 r2a770a35  
    11/*
    22 * Copyright (c) 2010 Lenka Trochtova
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    4950#include <errno.h>
    5051#include <inttypes.h>
     52#include <devman.h>
    5153
    5254#include <ipc/driver.h>
    5355
    54 #include "driver.h"
    55 
    56 /* driver structure */
    57 
     56#include "dev_iface.h"
     57#include "ddf/driver.h"
     58#include "ddf/interrupt.h"
     59
     60/** Driver structure */
    5861static driver_t *driver;
    5962
    60 /* devices */
    61 
    62 LIST_INITIALIZE(devices);
    63 FIBRIL_MUTEX_INITIALIZE(devices_mutex);
    64 
    65 /* interrupts */
    66 
     63/** Devices */
     64LIST_INITIALIZE(functions);
     65FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     66
     67/** Interrupts */
    6768static interrupt_context_list_t interrupt_contexts;
    6869
     
    7879};
    7980
     81static ddf_dev_t *create_device(void);
     82static void delete_device(ddf_dev_t *);
     83static remote_handler_t *function_get_default_handler(ddf_fun_t *);
     84static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
    8085
    8186static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     
    8590       
    8691        ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
    87         if (NULL != ctx && NULL != ctx->handler)
     92        if (ctx != NULL && ctx->handler != NULL)
    8893                (*ctx->handler)(ctx->dev, iid, icall);
    8994}
    9095
     96interrupt_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
     107void delete_interrupt_context(interrupt_context_t *ctx)
     108{
     109        if (ctx != NULL)
     110                free(ctx);
     111}
     112
     113void 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
     120void
     121add_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
     129void 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
     137interrupt_context_t *
     138find_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
     158interrupt_context_t *
     159find_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
    91180int
    92 register_interrupt_handler(device_t *dev, int irq, interrupt_handler_t *handler,
     181register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
    93182    irq_code_t *pseudocode)
    94183{
     
    101190        add_interrupt_context(&interrupt_contexts, ctx);
    102191       
    103         if (NULL == pseudocode)
     192        if (pseudocode == NULL)
    104193                pseudocode = &default_pseudocode;
    105194       
    106         int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode);
    107         if (0 != res) {
     195        int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
     196        if (res != EOK) {
    108197                remove_interrupt_context(&interrupt_contexts, ctx);
    109198                delete_interrupt_context(ctx);
     
    113202}
    114203
    115 int unregister_interrupt_handler(device_t *dev, int irq)
     204int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
    116205{
    117206        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
    118207            dev, irq);
    119         int res = ipc_unregister_irq(irq, dev->handle);
    120 
    121         if (NULL != ctx) {
     208        int res = unregister_irq(irq, dev->handle);
     209       
     210        if (ctx != NULL) {
    122211                remove_interrupt_context(&interrupt_contexts, ctx);
    123212                delete_interrupt_context(ctx);
    124213        }
     214       
    125215        return res;
    126216}
    127217
    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;
     218static 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
     225static 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
     232static 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;
    153244                }
     245               
    154246                link = link->next;
    155247        }
    156         fibril_mutex_unlock(&devices_mutex);
    157 
     248       
     249        fibril_mutex_unlock(&functions_mutex);
     250       
    158251        return NULL;
    159252}
     
    162255{
    163256        char *dev_name = NULL;
    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();
     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        ddf_dev_t *dev = create_device();
    170263        dev->handle = dev_handle;
    171        
     264
    172265        async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
    173266        dev->name = dev_name;
    174        
    175         add_to_devices_list(dev);
    176         dev->parent = driver_get_device(&devices, parent_dev_handle);
     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;
    177273       
    178274        res = driver->driver_ops->add_device(dev);
    179         if (0 == res) {
     275        if (res == EOK) {
    180276                printf("%s: new device with handle=%" PRIun " was added.\n",
    181277                    driver->name, dev_handle);
     
    183279                printf("%s: failed to add a new device with handle = %" PRIun ".\n",
    184280                    driver->name, dev_handle);
    185                 remove_from_devices_list(dev);
    186281                delete_device(dev);
    187282        }
    188283       
    189         ipc_answer_0(iid, res);
     284        async_answer_0(iid, res);
    190285}
    191286
     
    193288{
    194289        /* Accept connection */
    195         ipc_answer_0(iid, EOK);
    196 
     290        async_answer_0(iid, EOK);
     291       
    197292        bool cont = true;
    198293        while (cont) {
    199294                ipc_call_t call;
    200295                ipc_callid_t callid = async_get_call(&call);
    201 
     296               
    202297                switch (IPC_GET_IMETHOD(call)) {
    203298                case IPC_M_PHONE_HUNGUP:
     
    208303                        break;
    209304                default:
    210                         ipc_answer_0(callid, ENOENT);
     305                        async_answer_0(callid, ENOENT);
    211306                }
    212307        }
     
    226321         */
    227322        devman_handle_t handle = IPC_GET_ARG2(*icall);
    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"
     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"
    232327                    " %" PRIun " was found.\n", driver->name, handle);
    233                 ipc_answer_0(iid, ENOENT);
     328                async_answer_0(iid, ENOENT);
    234329                return;
    235330        }
     
    240335         * use the device.
    241336         */
    242 
     337       
    243338        int 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)
     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)
    250345                return;
    251 
     346       
    252347        while (1) {
    253348                ipc_callid_t callid;
     
    258353               
    259354                switch  (method) {
    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);
     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);
    265360                        return;
    266                 default:               
     361                default:
    267362                        /* convert ipc interface id to interface index */
    268363                       
     
    271366                        if (!is_valid_iface_idx(iface_idx)) {
    272367                                remote_handler_t *default_handler =
    273                                     device_get_default_handler(dev);
    274                                 if (NULL != default_handler) {
    275                                         (*default_handler)(dev, callid, &call);
     368                                    function_get_default_handler(fun);
     369                                if (default_handler != NULL) {
     370                                        (*default_handler)(fun, callid, &call);
    276371                                        break;
    277372                                }
     373                               
    278374                                /*
    279                                  * This is not device's interface and the
     375                                 * Function has no such interface and
    280376                                 * default handler is not provided.
    281377                                 */
     
    283379                                    "invalid interface id %d.",
    284380                                    driver->name, iface_idx);
    285                                 ipc_answer_0(callid, ENOTSUP);
     381                                async_answer_0(callid, ENOTSUP);
    286382                                break;
    287383                        }
    288 
    289                         /* calling one of the device's interfaces */
    290384                       
    291                         /* get the device interface structure */
    292                         void *iface = device_get_iface(dev, iface_idx);
    293                         if (NULL == iface) {
     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) {
    294390                                printf("%s: driver_connection_gen error - ",
    295391                                    driver->name);
    296                                 printf("device with handle %" PRIun " has no interface "
     392                                printf("Function with handle %" PRIun " has no interface "
    297393                                    "with id %d.\n", handle, iface_idx);
    298                                 ipc_answer_0(callid, ENOTSUP);
     394                                async_answer_0(callid, ENOTSUP);
    299395                                break;
    300396                        }
    301 
     397                       
    302398                        /*
    303399                         * Get the corresponding interface for remote request
    304400                         * handling ("remote interface").
    305401                         */
    306                         remote_iface_t* rem_iface = get_remote_iface(iface_idx);
    307                         assert(NULL != rem_iface);
    308 
     402                        remote_iface_t *rem_iface = get_remote_iface(iface_idx);
     403                        assert(rem_iface != NULL);
     404                       
    309405                        /* get the method of the remote interface */
    310406                        sysarg_t iface_method_idx = IPC_GET_ARG1(call);
    311407                        remote_iface_func_ptr_t iface_method_ptr =
    312408                            get_remote_method(rem_iface, iface_method_idx);
    313                         if (NULL == iface_method_ptr) {
     409                        if (iface_method_ptr == NULL) {
    314410                                // the interface has not such method
    315411                                printf("%s: driver_connection_gen error - "
    316412                                    "invalid interface method.", driver->name);
    317                                 ipc_answer_0(callid, ENOTSUP);
     413                                async_answer_0(callid, ENOTSUP);
    318414                                break;
    319415                        }
     
    323419                         * receive parameters from the remote client and it will
    324420                         * pass it to the corresponding local interface method
    325                          * associated with the device by its driver.
     421                         * associated with the function by its driver.
    326422                         */
    327                         (*iface_method_ptr)(dev, iface, callid, &call);
     423                        (*iface_method_ptr)(fun, ops, callid, &call);
    328424                        break;
    329425                }
     
    340436        driver_connection_gen(iid, icall, false);
    341437}
    342 
    343438
    344439/** Function for handling connections to device driver. */
     
    348443        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    349444        case DRIVER_DEVMAN:
    350                 /* handle PnP events from device manager */
     445                /* Handle request from device manager */
    351446                driver_connection_devman(iid, icall);
    352447                break;
    353448        case DRIVER_DRIVER:
    354                 /* handle request from drivers of child devices */
     449                /* Handle request from drivers of child devices */
    355450                driver_connection_driver(iid, icall);
    356451                break;
    357452        case DRIVER_CLIENT:
    358                 /* handle requests from client applications */
     453                /* Handle request from client applications */
    359454                driver_connection_client(iid, icall);
    360455                break;
    361 
    362456        default:
    363457                /* No such interface */
    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 
     458                async_answer_0(iid, ENOENT);
     459        }
     460}
     461
     462/** Create new device structure.
     463 *
     464 * @return              The device structure.
     465 */
     466static 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 */
     482static 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 */
     500static 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 */
     509static 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 */
     540ddf_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 */
     568void ddf_fun_destroy(ddf_fun_t *fun)
     569{
     570        assert(fun->bound == false);
     571        delete_function(fun);
     572}
     573
     574static 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 */
     594int ddf_fun_bind(ddf_fun_t *fun)
     595{
     596        assert(fun->name != NULL);
     597       
    372598        int res;
    373599       
    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)
     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);
    378605                return res;
    379         remove_from_devices_list(child);       
     606        }
     607       
     608        fun->bound = true;
    380609        return res;
    381610}
    382611
    383 /** Wrapper for child_device_register for devices with single match id.
    384  *
    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 
     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 */
     622int 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       
    406630        match_id = create_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 
     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);
    420638        return EOK;
    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)
     639}
     640
     641/** Get default handler for client requests */
     642static 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 */
     653int 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
     661int ddf_driver_main(driver_t *drv)
    437662{
    438663        /*
     
    441666         */
    442667        driver = drv;
    443 
     668       
    444669        /* Initialize the list of interrupt contexts. */
    445670        init_interrupt_context_list(&interrupt_contexts);
     
    453678         */
    454679        devman_driver_register(driver->name, driver_connection);
    455 
     680       
    456681        async_manager();
    457 
     682       
    458683        /* Never reached. */
    459684        return 0;
Note: See TracChangeset for help on using the changeset viewer.