Ignore:
File:
1 edited

Legend:

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

    r3e6a98c5 ra996ae31  
    3737 */
    3838
    39 #define _DDF_DATA_IMPLANT
    40 
    4139#include <assert.h>
    4240#include <ipc/services.h>
     
    4543#include <stdio.h>
    4644#include <errno.h>
    47 #include <stdbool.h>
     45#include <bool.h>
    4846#include <fibril_synch.h>
    4947#include <stdlib.h>
     
    6058#include "ddf/driver.h"
    6159#include "ddf/interrupt.h"
    62 #include "private/driver.h"
    6360
    6461/** Driver structure */
     
    7269LIST_INITIALIZE(functions);
    7370FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     71
     72/** Interrupts */
     73static interrupt_context_list_t interrupt_contexts;
     74
     75static irq_cmd_t default_cmds[] = {
     76        {
     77                .cmd = CMD_ACCEPT
     78        }
     79};
     80
     81static irq_code_t default_pseudocode = {
     82        0,
     83        NULL,
     84        sizeof(default_cmds) / sizeof(irq_cmd_t),
     85        default_cmds
     86};
    7487
    7588static ddf_dev_t *create_device(void);
     
    8295static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
    8396
     97static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     98{
     99        int id = (int)IPC_GET_IMETHOD(*icall);
     100        interrupt_context_t *ctx;
     101       
     102        ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
     103        if (ctx != NULL && ctx->handler != NULL)
     104                (*ctx->handler)(ctx->dev, iid, icall);
     105}
     106
     107interrupt_context_t *create_interrupt_context(void)
     108{
     109        interrupt_context_t *ctx;
     110       
     111        ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
     112        if (ctx != NULL)
     113                memset(ctx, 0, sizeof(interrupt_context_t));
     114       
     115        return ctx;
     116}
     117
     118void delete_interrupt_context(interrupt_context_t *ctx)
     119{
     120        if (ctx != NULL)
     121                free(ctx);
     122}
     123
     124void init_interrupt_context_list(interrupt_context_list_t *list)
     125{
     126        memset(list, 0, sizeof(interrupt_context_list_t));
     127        fibril_mutex_initialize(&list->mutex);
     128        list_initialize(&list->contexts);
     129}
     130
     131void
     132add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
     133{
     134        fibril_mutex_lock(&list->mutex);
     135        ctx->id = list->curr_id++;
     136        list_append(&ctx->link, &list->contexts);
     137        fibril_mutex_unlock(&list->mutex);
     138}
     139
     140void remove_interrupt_context(interrupt_context_list_t *list,
     141    interrupt_context_t *ctx)
     142{
     143        fibril_mutex_lock(&list->mutex);
     144        list_remove(&ctx->link);
     145        fibril_mutex_unlock(&list->mutex);
     146}
     147
     148interrupt_context_t *
     149find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
     150{
     151        interrupt_context_t *ctx;
     152       
     153        fibril_mutex_lock(&list->mutex);
     154       
     155        list_foreach(list->contexts, link) {
     156                ctx = list_get_instance(link, interrupt_context_t, link);
     157                if (ctx->id == id) {
     158                        fibril_mutex_unlock(&list->mutex);
     159                        return ctx;
     160                }
     161        }
     162       
     163        fibril_mutex_unlock(&list->mutex);
     164        return NULL;
     165}
     166
     167interrupt_context_t *
     168find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
     169{
     170        interrupt_context_t *ctx;
     171       
     172        fibril_mutex_lock(&list->mutex);
     173       
     174        list_foreach(list->contexts, link) {
     175                ctx = list_get_instance(link, interrupt_context_t, link);
     176                if (ctx->irq == irq && ctx->dev == dev) {
     177                        fibril_mutex_unlock(&list->mutex);
     178                        return ctx;
     179                }
     180        }
     181       
     182        fibril_mutex_unlock(&list->mutex);
     183        return NULL;
     184}
     185
     186
     187int
     188register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
     189    irq_code_t *pseudocode)
     190{
     191        interrupt_context_t *ctx = create_interrupt_context();
     192       
     193        ctx->dev = dev;
     194        ctx->irq = irq;
     195        ctx->handler = handler;
     196       
     197        add_interrupt_context(&interrupt_contexts, ctx);
     198       
     199        if (pseudocode == NULL)
     200                pseudocode = &default_pseudocode;
     201       
     202        int res = irq_register(irq, dev->handle, ctx->id, pseudocode);
     203        if (res != EOK) {
     204                remove_interrupt_context(&interrupt_contexts, ctx);
     205                delete_interrupt_context(ctx);
     206        }
     207
     208        return res;
     209}
     210
     211int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
     212{
     213        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
     214            dev, irq);
     215        int res = irq_unregister(irq, dev->handle);
     216       
     217        if (ctx != NULL) {
     218                remove_interrupt_context(&interrupt_contexts, ctx);
     219                delete_interrupt_context(ctx);
     220        }
     221       
     222        return res;
     223}
     224
    84225static void add_to_functions_list(ddf_fun_t *fun)
    85226{
     
    128269static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
    129270{
     271        char *dev_name = NULL;
     272        int res;
     273       
    130274        devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
    131275        devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
    132276       
    133277        ddf_dev_t *dev = create_device();
    134        
     278
    135279        /* Add one reference that will be dropped by driver_dev_remove() */
    136280        dev_add_ref(dev);
    137281        dev->handle = dev_handle;
    138        
    139         char *dev_name = NULL;
     282
    140283        async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
    141284        dev->name = dev_name;
    142        
     285
    143286        /*
    144287         * Currently not used, parent fun handle is stored in context
     
    147290        (void) parent_fun_handle;
    148291       
    149         int res = driver->driver_ops->dev_add(dev);
     292        res = driver->driver_ops->dev_add(dev);
    150293       
    151294        if (res != EOK) {
     
    162305}
    163306
     307static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)
     308{
     309        fibril_mutex_lock(&devices_mutex);
     310        ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall));
     311        fibril_mutex_unlock(&devices_mutex);
     312       
     313        if (dev != NULL && driver->driver_ops->device_added != NULL)
     314                driver->driver_ops->device_added(dev);
     315}
     316
    164317static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
    165318{
    166         devman_handle_t devh = IPC_GET_ARG1(*icall);
     319        devman_handle_t devh;
     320        ddf_dev_t *dev;
     321        int rc;
     322       
     323        devh = IPC_GET_ARG1(*icall);
    167324       
    168325        fibril_mutex_lock(&devices_mutex);
    169         ddf_dev_t *dev = driver_get_device(devh);
     326        dev = driver_get_device(devh);
    170327        if (dev != NULL)
    171328                dev_add_ref(dev);
     
    176333                return;
    177334        }
    178        
    179         int rc;
    180335       
    181336        if (driver->driver_ops->dev_remove != NULL)
     
    192347static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
    193348{
    194         devman_handle_t devh = IPC_GET_ARG1(*icall);
     349        devman_handle_t devh;
     350        ddf_dev_t *dev;
     351        int rc;
     352       
     353        devh = IPC_GET_ARG1(*icall);
    195354       
    196355        fibril_mutex_lock(&devices_mutex);
    197         ddf_dev_t *dev = driver_get_device(devh);
     356        dev = driver_get_device(devh);
    198357        if (dev != NULL)
    199358                dev_add_ref(dev);
     
    204363                return;
    205364        }
    206        
    207         int rc;
    208365       
    209366        if (driver->driver_ops->dev_gone != NULL)
     
    220377static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    221378{
    222         devman_handle_t funh = IPC_GET_ARG1(*icall);
     379        devman_handle_t funh;
     380        ddf_fun_t *fun;
     381        int rc;
     382       
     383        funh = IPC_GET_ARG1(*icall);
    223384       
    224385        /*
     
    229390        fibril_mutex_lock(&functions_mutex);
    230391       
    231         ddf_fun_t *fun = driver_get_function(funh);
     392        fun = driver_get_function(funh);
    232393        if (fun != NULL)
    233394                fun_add_ref(fun);
     
    241402       
    242403        /* Call driver entry point */
    243         int rc;
    244        
    245404        if (driver->driver_ops->fun_online != NULL)
    246405                rc = driver->driver_ops->fun_online(fun);
     
    255414static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    256415{
    257         devman_handle_t funh = IPC_GET_ARG1(*icall);
     416        devman_handle_t funh;
     417        ddf_fun_t *fun;
     418        int rc;
     419       
     420        funh = IPC_GET_ARG1(*icall);
    258421       
    259422        /*
     
    264427        fibril_mutex_lock(&functions_mutex);
    265428       
    266         ddf_fun_t *fun = driver_get_function(funh);
     429        fun = driver_get_function(funh);
    267430        if (fun != NULL)
    268431                fun_add_ref(fun);
     
    276439       
    277440        /* Call driver entry point */
    278         int rc;
    279        
    280441        if (driver->driver_ops->fun_offline != NULL)
    281442                rc = driver->driver_ops->fun_offline(fun);
     
    301462                case DRIVER_DEV_ADD:
    302463                        driver_dev_add(callid, &call);
     464                        break;
     465                case DRIVER_DEV_ADDED:
     466                        async_answer_0(callid, EOK);
     467                        driver_dev_added(callid, &call);
    303468                        break;
    304469                case DRIVER_DEV_REMOVE:
     
    526691static void delete_device(ddf_dev_t *dev)
    527692{
    528         if (dev->parent_sess)
    529                 async_hangup(dev->parent_sess);
    530693        if (dev->driver_data != NULL)
    531694                free(dev->driver_data);
     
    590753
    591754/** Allocate driver-specific device data. */
    592 void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
    593 {
     755extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     756{
     757        void *data;
     758
    594759        assert(dev->driver_data == NULL);
    595        
    596         void *data = calloc(1, size);
     760
     761        data = calloc(1, size);
    597762        if (data == NULL)
    598763                return NULL;
    599        
     764
    600765        dev->driver_data = data;
    601766        return data;
    602 }
    603 
    604 /** Implant foreign driver-specific device data.
    605  *
    606  * XXX This is used to transition USB to new interface. Do not use
    607  * in new code. Use of this function must be removed.
    608  */
    609 void ddf_fun_data_implant(ddf_fun_t *fun, void *data)
    610 {
    611         assert(fun->driver_data == NULL);
    612         fun->driver_data = data;
    613 }
    614 
    615 /** Return driver-specific device data. */
    616 void *ddf_dev_data_get(ddf_dev_t *dev)
    617 {
    618         return dev->driver_data;
    619 }
    620 
    621 /** Get device handle. */
    622 devman_handle_t ddf_dev_get_handle(ddf_dev_t *dev)
    623 {
    624         return dev->handle;
    625 }
    626 
    627 /** Return device name.
    628  *
    629  * @param dev   Device
    630  * @return      Device name. Valid as long as @a dev is valid.
    631  */
    632 const char *ddf_dev_get_name(ddf_dev_t *dev)
    633 {
    634         return dev->name;
    635 }
    636 
    637 /** Create session with the parent function.
    638  *
    639  * The session will be automatically closed when @a dev is destroyed.
    640  *
    641  * @param dev   Device
    642  * @param mgmt  Exchange management style
    643  * @return      New session or NULL if session could not be created
    644  */
    645 async_sess_t *ddf_dev_parent_sess_create(ddf_dev_t *dev, exch_mgmt_t mgmt)
    646 {
    647         assert(dev->parent_sess == NULL);
    648         dev->parent_sess = devman_parent_device_connect(mgmt, dev->handle,
    649             IPC_FLAG_BLOCKING);
    650 
    651         return dev->parent_sess;
    652 }
    653 
    654 /** Return existing session with the parent function.
    655  *
    656  * @param dev   Device
    657  * @return      Existing session or NULL if there is no session
    658  */
    659 async_sess_t *ddf_dev_parent_sess_get(ddf_dev_t *dev)
    660 {
    661         return dev->parent_sess;
    662 }
    663 
    664 /** Set function name (if it was not specified when node was created.)
    665  *
    666  * @param dev   Device whose name has not been set yet
    667  * @param name  Name, will be copied
    668  * @return      EOK on success, ENOMEM if out of memory
    669  */
    670 int ddf_fun_set_name(ddf_fun_t *dev, const char *name)
    671 {
    672         assert(dev->name == NULL);
    673 
    674         dev->name = str_dup(name);
    675         if (dev->name == NULL)
    676                 return ENOENT;
    677 
    678         return EOK;
    679 }
    680 
    681 /** Get device to which function belongs. */
    682 ddf_dev_t *ddf_fun_get_dev(ddf_fun_t *fun)
    683 {
    684         return fun->dev;
    685 }
    686 
    687 /** Get function handle.
    688  *
    689  * XXX USB uses this, but its use should be eliminated.
    690  */
    691 devman_handle_t ddf_fun_get_handle(ddf_fun_t *fun)
    692 {
    693         return fun->handle;
    694767}
    695768
     
    705778 * This function should only fail if there is not enough free memory.
    706779 * Specifically, this function succeeds even if @a dev already has
    707  * a (bound) function with the same name. @a name can be NULL in which
    708  * case the caller will set the name later using ddf_fun_set_name().
    709  * He must do this before binding the function.
     780 * a (bound) function with the same name.
    710781 *
    711782 * Type: A function of type fun_inner indicates that DDF should attempt
     
    715786 * @param dev           Device to which we are adding function
    716787 * @param ftype         Type of function (fun_inner or fun_exposed)
    717  * @param name          Name of function or NULL
     788 * @param name          Name of function
    718789 *
    719790 * @return              New function or @c NULL if memory is not available
     
    721792ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name)
    722793{
    723         ddf_fun_t *fun = create_function();
     794        ddf_fun_t *fun;
     795
     796        fun = create_function();
    724797        if (fun == NULL)
    725798                return NULL;
    726        
     799
    727800        /* Add one reference that will be dropped by ddf_fun_destroy() */
    728801        fun->dev = dev;
    729802        fun_add_ref(fun);
    730        
     803
    731804        fun->bound = false;
    732805        fun->ftype = ftype;
    733        
    734         if (name != NULL) {
    735                 fun->name = str_dup(name);
    736                 if (fun->name == NULL) {
    737                         delete_function(fun);
    738                         return NULL;
    739                 }
    740         }
    741        
     806
     807        fun->name = str_dup(name);
     808        if (fun->name == NULL) {
     809                delete_function(fun);
     810                return NULL;
     811        }
     812
    742813        return fun;
    743814}
    744815
    745816/** Allocate driver-specific function data. */
    746 void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
    747 {
     817extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     818{
     819        void *data;
     820
    748821        assert(fun->bound == false);
    749822        assert(fun->driver_data == NULL);
    750        
    751         void *data = calloc(1, size);
     823
     824        data = calloc(1, size);
    752825        if (data == NULL)
    753826                return NULL;
    754        
     827
    755828        fun->driver_data = data;
    756829        return data;
    757830}
    758831
    759 /** Return driver-specific function data. */
    760 void *ddf_fun_data_get(ddf_fun_t *fun)
    761 {
    762         return fun->driver_data;
    763 }
    764 
    765 /** Return function name.
    766  *
    767  * @param fun   Function
    768  * @return      Function name. Valid as long as @a fun is valid.
    769  */
    770 const char *ddf_fun_get_name(ddf_fun_t *fun)
    771 {
    772         return fun->name;
    773 }
    774 
    775832/** Destroy DDF function node.
    776833 *
     
    778835 * must not be bound.
    779836 *
    780  * @param fun Function to destroy
    781  *
     837 * @param fun           Function to destroy
    782838 */
    783839void ddf_fun_destroy(ddf_fun_t *fun)
    784840{
    785841        assert(fun->bound == false);
    786        
     842
    787843        /*
    788844         * Drop the reference added by ddf_fun_create(). This will deallocate
     
    799855        if (fun->ops == NULL)
    800856                return NULL;
    801        
    802857        return fun->ops->interfaces[idx];
    803858}
     
    812867 * the same name.
    813868 *
    814  * @param fun Function to bind
    815  *
    816  * @return EOK on success or negative error code
    817  *
     869 * @param fun           Function to bind
     870 * @return              EOK on success or negative error code
    818871 */
    819872int ddf_fun_bind(ddf_fun_t *fun)
     
    822875        assert(fun->name != NULL);
    823876       
     877        int res;
     878       
    824879        add_to_functions_list(fun);
    825         int res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
     880        res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
    826881            fun->dev->handle, &fun->handle);
    827882        if (res != EOK) {
     
    839894 * the function invisible to the system.
    840895 *
    841  * @param fun Function to unbind
    842  *
    843  * @return EOK on success or negative error code
    844  *
     896 * @param fun           Function to unbind
     897 * @return              EOK on success or negative error code
    845898 */
    846899int ddf_fun_unbind(ddf_fun_t *fun)
    847900{
     901        int res;
     902       
    848903        assert(fun->bound == true);
    849904       
    850         int res = devman_remove_function(fun->handle);
     905        res = devman_remove_function(fun->handle);
    851906        if (res != EOK)
    852907                return res;
    853        
     908
    854909        remove_from_functions_list(fun);
    855910       
     
    860915/** Online function.
    861916 *
    862  * @param fun Function to online
    863  *
    864  * @return EOK on success or negative error code
    865  *
     917 * @param fun           Function to online
     918 * @return              EOK on success or negative error code
    866919 */
    867920int ddf_fun_online(ddf_fun_t *fun)
    868921{
     922        int res;
     923       
    869924        assert(fun->bound == true);
    870925       
    871         int res = devman_drv_fun_online(fun->handle);
     926        res = devman_drv_fun_online(fun->handle);
    872927        if (res != EOK)
    873928                return res;
     
    878933/** Offline function.
    879934 *
    880  * @param fun Function to offline
    881  *
    882  * @return EOK on success or negative error code
    883  *
     935 * @param fun           Function to offline
     936 * @return              EOK on success or negative error code
    884937 */
    885938int ddf_fun_offline(ddf_fun_t *fun)
    886939{
     940        int res;
     941       
    887942        assert(fun->bound == true);
    888943       
    889         int res = devman_drv_fun_offline(fun->handle);
     944        res = devman_drv_fun_offline(fun->handle);
    890945        if (res != EOK)
    891946                return res;
     
    899954 * Cannot be called when the function node is bound.
    900955 *
    901  * @param fun          Function
    902  * @param match_id_str Match string
    903  * @param match_score  Match score
    904  *
    905  * @return EOK on success.
    906  * @return ENOMEM if out of memory.
    907  *
     956 * @param fun                   Function
     957 * @param match_id_str          Match string
     958 * @param match_score           Match score
     959 * @return                      EOK on success, ENOMEM if out of memory.
    908960 */
    909961int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str,
    910962    int match_score)
    911963{
     964        match_id_t *match_id;
     965       
    912966        assert(fun->bound == false);
    913967        assert(fun->ftype == fun_inner);
    914968       
    915         match_id_t *match_id = create_match_id();
     969        match_id = create_match_id();
    916970        if (match_id == NULL)
    917971                return ENOMEM;
     
    922976        add_match_id(&fun->match_ids, match_id);
    923977        return EOK;
    924 }
    925 
    926 /** Set function ops. */
    927 void ddf_fun_set_ops(ddf_fun_t *fun, ddf_dev_ops_t *dev_ops)
    928 {
    929         assert(fun->conn_handler == NULL);
    930         fun->ops = dev_ops;
    931 }
    932 
    933 /** Set user-defined connection handler.
    934  *
    935  * This allows handling connections the non-devman way.
    936  */
    937 void ddf_fun_set_conn_handler(ddf_fun_t *fun, async_client_conn_t conn)
    938 {
    939         assert(fun->ops == NULL);
    940         fun->conn_handler = conn;
    941978}
    942979
     
    952989 *
    953990 * Must only be called when the function is bound.
    954  *
    955991 */
    956992int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
     
    9641000int ddf_driver_main(driver_t *drv)
    9651001{
     1002        int rc;
     1003
    9661004        /*
    9671005         * Remember the driver structure - driver_ops will be called by generic
     
    9701008        driver = drv;
    9711009       
    972         /* Initialize interrupt module */
    973         interrupt_init();
     1010        /* Initialize the list of interrupt contexts. */
     1011        init_interrupt_context_list(&interrupt_contexts);
     1012       
     1013        /* Set generic interrupt handler. */
     1014        async_set_interrupt_received(driver_irq_handler);
    9741015       
    9751016        /*
     
    9781019         */
    9791020        async_set_client_connection(driver_connection);
    980         int rc = devman_driver_register(driver->name);
     1021        rc = devman_driver_register(driver->name);
    9811022        if (rc != EOK) {
    9821023                printf("Error: Failed to register driver with device manager "
     
    9841025                    str_error(rc));
    9851026               
    986                 return rc;
     1027                return 1;
    9871028        }
    9881029       
     
    9901031        rc = task_retval(0);
    9911032        if (rc != EOK)
    992                 return rc;
    993        
     1033                return 1;
     1034
    9941035        async_manager();
    9951036       
    9961037        /* Never reached. */
    997         return EOK;
     1038        return 0;
    9981039}
    9991040
Note: See TracChangeset for help on using the changeset viewer.