Ignore:
File:
1 edited

Legend:

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

    r5fdd7c3 r26fa82bc  
    11/*
    22 * Copyright (c) 2010 Lenka Trochtova
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    4647#include <stdlib.h>
    4748#include <str.h>
     49#include <str_error.h>
    4850#include <ctype.h>
    4951#include <errno.h>
    5052#include <inttypes.h>
     53#include <devman.h>
    5154
    5255#include <ipc/driver.h>
    5356
    5457#include "dev_iface.h"
    55 #include "driver.h"
     58#include "ddf/driver.h"
     59#include "ddf/interrupt.h"
    5660
    5761/** Driver structure */
     
    5963
    6064/** Devices */
    61 LIST_INITIALIZE(devices);
    62 FIBRIL_MUTEX_INITIALIZE(devices_mutex);
     65LIST_INITIALIZE(functions);
     66FIBRIL_MUTEX_INITIALIZE(functions_mutex);
    6367
    6468/** Interrupts */
     
    7680};
    7781
     82static ddf_dev_t *create_device(void);
     83static void delete_device(ddf_dev_t *);
     84static remote_handler_t *function_get_default_handler(ddf_fun_t *);
     85static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
    7886
    7987static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     
    150158
    151159interrupt_context_t *
    152 find_interrupt_context(interrupt_context_list_t *list, device_t *dev, int irq)
     160find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
    153161{
    154162        fibril_mutex_lock(&list->mutex);
     
    172180
    173181int
    174 register_interrupt_handler(device_t *dev, int irq, interrupt_handler_t *handler,
     182register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
    175183    irq_code_t *pseudocode)
    176184{
     
    186194                pseudocode = &default_pseudocode;
    187195       
    188         int res = ipc_register_irq(irq, dev->handle, ctx->id, pseudocode);
     196        int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
    189197        if (res != EOK) {
    190198                remove_interrupt_context(&interrupt_contexts, ctx);
     
    195203}
    196204
    197 int unregister_interrupt_handler(device_t *dev, int irq)
     205int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
    198206{
    199207        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
    200208            dev, irq);
    201         int res = ipc_unregister_irq(irq, dev->handle);
     209        int res = unregister_irq(irq, dev->handle);
    202210       
    203211        if (ctx != NULL) {
     
    209217}
    210218
    211 static void add_to_devices_list(device_t *dev)
    212 {
    213         fibril_mutex_lock(&devices_mutex);
    214         list_append(&dev->link, &devices);
    215         fibril_mutex_unlock(&devices_mutex);
    216 }
    217 
    218 static void remove_from_devices_list(device_t *dev)
    219 {
    220         fibril_mutex_lock(&devices_mutex);
    221         list_remove(&dev->link);
    222         fibril_mutex_unlock(&devices_mutex);
    223 }
    224 
    225 static device_t *driver_get_device(link_t *devices, devman_handle_t handle)
    226 {
    227         device_t *dev = NULL;
    228        
    229         fibril_mutex_lock(&devices_mutex);
    230         link_t *link = devices->next;
    231        
    232         while (link != devices) {
    233                 dev = list_get_instance(link, device_t, link);
    234                 if (dev->handle == handle) {
    235                         fibril_mutex_unlock(&devices_mutex);
    236                         return dev;
     219static 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
     226static 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
     233static 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;
    237245                }
     246               
    238247                link = link->next;
    239248        }
    240249       
    241         fibril_mutex_unlock(&devices_mutex);
     250        fibril_mutex_unlock(&functions_mutex);
    242251       
    243252        return NULL;
     
    250259       
    251260        devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
    252         devman_handle_t parent_dev_handle = IPC_GET_ARG2(*icall);
    253        
    254         device_t *dev = create_device();
     261        devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
     262       
     263        ddf_dev_t *dev = create_device();
    255264        dev->handle = dev_handle;
    256        
     265
    257266        async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
    258267        dev->name = dev_name;
    259        
    260         add_to_devices_list(dev);
    261         dev->parent = driver_get_device(&devices, parent_dev_handle);
     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;
    262274       
    263275        res = driver->driver_ops->add_device(dev);
    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);
     276        if (res != EOK)
    271277                delete_device(dev);
    272         }
    273        
    274         ipc_answer_0(iid, res);
     278       
     279        async_answer_0(iid, res);
    275280}
    276281
     
    278283{
    279284        /* Accept connection */
    280         ipc_answer_0(iid, EOK);
     285        async_answer_0(iid, EOK);
    281286       
    282287        bool cont = true;
     
    293298                        break;
    294299                default:
    295                         ipc_answer_0(callid, ENOENT);
     300                        async_answer_0(callid, ENOENT);
    296301                }
    297302        }
     
    311316         */
    312317        devman_handle_t handle = IPC_GET_ARG2(*icall);
    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"
     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"
    317322                    " %" PRIun " was found.\n", driver->name, handle);
    318                 ipc_answer_0(iid, ENOENT);
     323                async_answer_0(iid, ENOENT);
    319324                return;
    320325        }
     
    327332       
    328333        int ret = EOK;
    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);
     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);
    334339        if (ret != EOK)
    335340                return;
     
    344349                switch  (method) {
    345350                case IPC_M_PHONE_HUNGUP:
    346                         /* close the device */
    347                         if (dev->ops != NULL && dev->ops->close != NULL)
    348                                 (*dev->ops->close)(dev);
    349                         ipc_answer_0(callid, EOK);
     351                        /* Close device function */
     352                        if (fun->ops != NULL && fun->ops->close != NULL)
     353                                (*fun->ops->close)(fun);
     354                        async_answer_0(callid, EOK);
    350355                        return;
    351356                default:
     
    356361                        if (!is_valid_iface_idx(iface_idx)) {
    357362                                remote_handler_t *default_handler =
    358                                     device_get_default_handler(dev);
     363                                    function_get_default_handler(fun);
    359364                                if (default_handler != NULL) {
    360                                         (*default_handler)(dev, callid, &call);
     365                                        (*default_handler)(fun, callid, &call);
    361366                                        break;
    362367                                }
     368                               
    363369                                /*
    364                                  * This is not device's interface and the
     370                                 * Function has no such interface and
    365371                                 * default handler is not provided.
    366372                                 */
     
    368374                                    "invalid interface id %d.",
    369375                                    driver->name, iface_idx);
    370                                 ipc_answer_0(callid, ENOTSUP);
     376                                async_answer_0(callid, ENOTSUP);
    371377                                break;
    372378                        }
    373379                       
    374                         /* calling one of the device's interfaces */
     380                        /* calling one of the function's interfaces */
    375381                       
    376382                        /* Get the interface ops structure. */
    377                         void *ops = device_get_ops(dev, iface_idx);
     383                        void *ops = function_get_ops(fun, iface_idx);
    378384                        if (ops == NULL) {
    379385                                printf("%s: driver_connection_gen error - ",
    380386                                    driver->name);
    381                                 printf("device with handle %" PRIun " has no interface "
     387                                printf("Function with handle %" PRIun " has no interface "
    382388                                    "with id %d.\n", handle, iface_idx);
    383                                 ipc_answer_0(callid, ENOTSUP);
     389                                async_answer_0(callid, ENOTSUP);
    384390                                break;
    385391                        }
     
    397403                            get_remote_method(rem_iface, iface_method_idx);
    398404                        if (iface_method_ptr == NULL) {
    399                                 // the interface has not such method
     405                                /* The interface has not such method */
    400406                                printf("%s: driver_connection_gen error - "
    401407                                    "invalid interface method.", driver->name);
    402                                 ipc_answer_0(callid, ENOTSUP);
     408                                async_answer_0(callid, ENOTSUP);
    403409                                break;
    404410                        }
     
    408414                         * receive parameters from the remote client and it will
    409415                         * pass it to the corresponding local interface method
    410                          * associated with the device by its driver.
     416                         * associated with the function by its driver.
    411417                         */
    412                         (*iface_method_ptr)(dev, ops, callid, &call);
     418                        (*iface_method_ptr)(fun, ops, callid, &call);
    413419                        break;
    414420                }
     
    425431        driver_connection_gen(iid, icall, false);
    426432}
    427 
    428433
    429434/** Function for handling connections to device driver. */
     
    446451        default:
    447452                /* No such interface */
    448                 ipc_answer_0(iid, ENOENT);
     453                async_answer_0(iid, ENOENT);
    449454        }
    450455}
     
    454459 * @return              The device structure.
    455460 */
    456 device_t *create_device(void)
    457 {
    458         device_t *dev = malloc(sizeof(device_t));
    459 
    460         if (dev != NULL) {
    461                 memset(dev, 0, sizeof(device_t));
    462                 init_match_ids(&dev->match_ids);
    463         }
    464 
     461static ddf_dev_t *create_device(void)
     462{
     463        ddf_dev_t *dev;
     464
     465        dev = malloc(sizeof(ddf_dev_t));
     466        if (dev == NULL)
     467                return NULL;
     468
     469        memset(dev, 0, sizeof(ddf_dev_t));
    465470        return dev;
    466471}
    467472
     473/** Create new function structure.
     474 *
     475 * @return              The device structure.
     476 */
     477static 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)
     483                return NULL;
     484
     485        init_match_ids(&fun->match_ids);
     486        link_initialize(&fun->link);
     487
     488        return fun;
     489}
     490
    468491/** Delete device structure.
    469492 *
    470493 * @param dev           The device structure.
    471494 */
    472 void delete_device(device_t *dev)
    473 {
    474         clean_match_ids(&dev->match_ids);
    475         if (dev->name != NULL)
    476                 free(dev->name);
     495static void delete_device(ddf_dev_t *dev)
     496{
    477497        free(dev);
    478498}
    479499
    480 void *device_get_ops(device_t *dev, dev_inferface_idx_t idx)
     500/** Delete device structure.
     501 *
     502 * @param dev           The device structure.
     503 */
     504static 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 */
     535ddf_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 */
     563void ddf_fun_destroy(ddf_fun_t *fun)
     564{
     565        assert(fun->bound == false);
     566        delete_function(fun);
     567}
     568
     569static void *function_get_ops(ddf_fun_t *fun, dev_inferface_idx_t idx)
    481570{
    482571        assert(is_valid_iface_idx(idx));
    483         if (dev->ops == NULL)
     572        if (fun->ops == NULL)
    484573                return NULL;
    485         return dev->ops->interfaces[idx];
    486 }
    487 
    488 int child_device_register(device_t *child, device_t *parent)
    489 {
    490         assert(child->name != NULL);
     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 */
     589int ddf_fun_bind(ddf_fun_t *fun)
     590{
     591        assert(fun->name != NULL);
    491592       
    492593        int res;
    493594       
    494         add_to_devices_list(child);
    495         res = devman_child_device_register(child->name, &child->match_ids,
    496             parent->handle, &child->handle);
     595        add_to_functions_list(fun);
     596        res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
     597            fun->dev->handle, &fun->handle);
    497598        if (res != EOK) {
    498                 remove_from_devices_list(child);
     599                remove_from_functions_list(fun);
    499600                return res;
    500601        }
    501602       
     603        fun->bound = true;
    502604        return res;
    503605}
    504606
    505 /** Wrapper for child_device_register for devices with single match id.
    506  *
    507  * @param parent Parent device.
    508  * @param child_name Child device name.
    509  * @param child_match_id Child device match id.
    510  * @param child_match_score Child device match score.
    511  * @return Error code.
    512  */
    513 int child_device_register_wrapper(device_t *parent, const char *child_name,
    514     const char *child_match_id, int child_match_score)
    515 {
    516         device_t *child = NULL;
    517         match_id_t *match_id = NULL;
     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 */
     617int 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 */
     637static 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 */
     648int 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
     656int ddf_driver_main(driver_t *drv)
     657{
    518658        int rc;
    519        
    520         child = create_device();
    521         if (child == NULL) {
    522                 rc = ENOMEM;
    523                 goto failure;
    524         }
    525        
    526         child->name = child_name;
    527        
    528         match_id = create_match_id();
    529         if (match_id == NULL) {
    530                 rc = ENOMEM;
    531                 goto failure;
    532         }
    533        
    534         match_id->id = child_match_id;
    535         match_id->score = child_match_score;
    536         add_match_id(&child->match_ids, match_id);
    537        
    538         rc = child_device_register(child, parent);
    539         if (rc != EOK)
    540                 goto failure;
    541        
    542         return EOK;
    543        
    544 failure:
    545         if (match_id != NULL) {
    546                 match_id->id = NULL;
    547                 delete_match_id(match_id);
    548         }
    549        
    550         if (child != NULL) {
    551                 child->name = NULL;
    552                 delete_device(child);
    553         }
    554        
    555         return rc;
    556 }
    557 
    558 /** Get default handler for client requests */
    559 remote_handler_t *device_get_default_handler(device_t *dev)
    560 {
    561         if (dev->ops == NULL)
    562                 return NULL;
    563         return dev->ops->default_handler;
    564 }
    565 
    566 int add_device_to_class(device_t *dev, const char *class_name)
    567 {
    568         return devman_add_device_to_class(dev->handle, class_name);
    569 }
    570 
    571 int driver_main(driver_t *drv)
    572 {
     659
    573660        /*
    574661         * Remember the driver structure - driver_ops will be called by generic
     
    584671       
    585672        /*
    586          * Register driver by device manager with generic handler for incoming
    587          * connections.
     673         * Register driver with device manager using generic handler for
     674         * incoming connections.
    588675         */
    589         devman_driver_register(driver->name, driver_connection);
    590        
     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
    591690        async_manager();
    592691       
Note: See TracChangeset for help on using the changeset viewer.