Ignore:
File:
1 edited

Legend:

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

    ra996ae31 r3e6a98c5  
    3737 */
    3838
     39#define _DDF_DATA_IMPLANT
     40
    3941#include <assert.h>
    4042#include <ipc/services.h>
     
    4345#include <stdio.h>
    4446#include <errno.h>
    45 #include <bool.h>
     47#include <stdbool.h>
    4648#include <fibril_synch.h>
    4749#include <stdlib.h>
     
    5860#include "ddf/driver.h"
    5961#include "ddf/interrupt.h"
     62#include "private/driver.h"
    6063
    6164/** Driver structure */
     
    6972LIST_INITIALIZE(functions);
    7073FIBRIL_MUTEX_INITIALIZE(functions_mutex);
    71 
    72 /** Interrupts */
    73 static interrupt_context_list_t interrupt_contexts;
    74 
    75 static irq_cmd_t default_cmds[] = {
    76         {
    77                 .cmd = CMD_ACCEPT
    78         }
    79 };
    80 
    81 static irq_code_t default_pseudocode = {
    82         0,
    83         NULL,
    84         sizeof(default_cmds) / sizeof(irq_cmd_t),
    85         default_cmds
    86 };
    8774
    8875static ddf_dev_t *create_device(void);
     
    9582static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
    9683
    97 static 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 
    107 interrupt_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 
    118 void delete_interrupt_context(interrupt_context_t *ctx)
    119 {
    120         if (ctx != NULL)
    121                 free(ctx);
    122 }
    123 
    124 void 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 
    131 void
    132 add_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 
    140 void 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 
    148 interrupt_context_t *
    149 find_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 
    167 interrupt_context_t *
    168 find_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 
    187 int
    188 register_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 
    211 int 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 
    22584static void add_to_functions_list(ddf_fun_t *fun)
    22685{
     
    269128static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
    270129{
    271         char *dev_name = NULL;
    272         int res;
    273        
    274130        devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
    275131        devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
    276132       
    277133        ddf_dev_t *dev = create_device();
    278 
     134       
    279135        /* Add one reference that will be dropped by driver_dev_remove() */
    280136        dev_add_ref(dev);
    281137        dev->handle = dev_handle;
    282 
     138       
     139        char *dev_name = NULL;
    283140        async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
    284141        dev->name = dev_name;
    285 
     142       
    286143        /*
    287144         * Currently not used, parent fun handle is stored in context
     
    290147        (void) parent_fun_handle;
    291148       
    292         res = driver->driver_ops->dev_add(dev);
     149        int res = driver->driver_ops->dev_add(dev);
    293150       
    294151        if (res != EOK) {
     
    305162}
    306163
    307 static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)
    308 {
     164static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
     165{
     166        devman_handle_t devh = IPC_GET_ARG1(*icall);
     167       
    309168        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 
    317 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
    318 {
    319         devman_handle_t devh;
    320         ddf_dev_t *dev;
    321         int rc;
    322        
    323         devh = IPC_GET_ARG1(*icall);
    324        
    325         fibril_mutex_lock(&devices_mutex);
    326         dev = driver_get_device(devh);
     169        ddf_dev_t *dev = driver_get_device(devh);
    327170        if (dev != NULL)
    328171                dev_add_ref(dev);
     
    333176                return;
    334177        }
     178       
     179        int rc;
    335180       
    336181        if (driver->driver_ops->dev_remove != NULL)
     
    347192static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
    348193{
    349         devman_handle_t devh;
    350         ddf_dev_t *dev;
    351         int rc;
    352        
    353         devh = IPC_GET_ARG1(*icall);
     194        devman_handle_t devh = IPC_GET_ARG1(*icall);
    354195       
    355196        fibril_mutex_lock(&devices_mutex);
    356         dev = driver_get_device(devh);
     197        ddf_dev_t *dev = driver_get_device(devh);
    357198        if (dev != NULL)
    358199                dev_add_ref(dev);
     
    363204                return;
    364205        }
     206       
     207        int rc;
    365208       
    366209        if (driver->driver_ops->dev_gone != NULL)
     
    377220static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    378221{
    379         devman_handle_t funh;
    380         ddf_fun_t *fun;
    381         int rc;
    382        
    383         funh = IPC_GET_ARG1(*icall);
     222        devman_handle_t funh = IPC_GET_ARG1(*icall);
    384223       
    385224        /*
     
    390229        fibril_mutex_lock(&functions_mutex);
    391230       
    392         fun = driver_get_function(funh);
     231        ddf_fun_t *fun = driver_get_function(funh);
    393232        if (fun != NULL)
    394233                fun_add_ref(fun);
     
    402241       
    403242        /* Call driver entry point */
     243        int rc;
     244       
    404245        if (driver->driver_ops->fun_online != NULL)
    405246                rc = driver->driver_ops->fun_online(fun);
     
    414255static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    415256{
    416         devman_handle_t funh;
    417         ddf_fun_t *fun;
    418         int rc;
    419        
    420         funh = IPC_GET_ARG1(*icall);
     257        devman_handle_t funh = IPC_GET_ARG1(*icall);
    421258       
    422259        /*
     
    427264        fibril_mutex_lock(&functions_mutex);
    428265       
    429         fun = driver_get_function(funh);
     266        ddf_fun_t *fun = driver_get_function(funh);
    430267        if (fun != NULL)
    431268                fun_add_ref(fun);
     
    439276       
    440277        /* Call driver entry point */
     278        int rc;
     279       
    441280        if (driver->driver_ops->fun_offline != NULL)
    442281                rc = driver->driver_ops->fun_offline(fun);
     
    462301                case DRIVER_DEV_ADD:
    463302                        driver_dev_add(callid, &call);
    464                         break;
    465                 case DRIVER_DEV_ADDED:
    466                         async_answer_0(callid, EOK);
    467                         driver_dev_added(callid, &call);
    468303                        break;
    469304                case DRIVER_DEV_REMOVE:
     
    691526static void delete_device(ddf_dev_t *dev)
    692527{
     528        if (dev->parent_sess)
     529                async_hangup(dev->parent_sess);
    693530        if (dev->driver_data != NULL)
    694531                free(dev->driver_data);
     
    753590
    754591/** Allocate driver-specific device data. */
    755 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
    756 {
    757         void *data;
    758 
     592void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     593{
    759594        assert(dev->driver_data == NULL);
    760 
    761         data = calloc(1, size);
     595       
     596        void *data = calloc(1, size);
    762597        if (data == NULL)
    763598                return NULL;
    764 
     599       
    765600        dev->driver_data = data;
    766601        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 */
     609void 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. */
     616void *ddf_dev_data_get(ddf_dev_t *dev)
     617{
     618        return dev->driver_data;
     619}
     620
     621/** Get device handle. */
     622devman_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 */
     632const 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 */
     645async_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 */
     659async_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 */
     670int 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. */
     682ddf_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 */
     691devman_handle_t ddf_fun_get_handle(ddf_fun_t *fun)
     692{
     693        return fun->handle;
    767694}
    768695
     
    778705 * This function should only fail if there is not enough free memory.
    779706 * Specifically, this function succeeds even if @a dev already has
    780  * a (bound) function with the same name.
     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.
    781710 *
    782711 * Type: A function of type fun_inner indicates that DDF should attempt
     
    786715 * @param dev           Device to which we are adding function
    787716 * @param ftype         Type of function (fun_inner or fun_exposed)
    788  * @param name          Name of function
     717 * @param name          Name of function or NULL
    789718 *
    790719 * @return              New function or @c NULL if memory is not available
     
    792721ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name)
    793722{
    794         ddf_fun_t *fun;
    795 
    796         fun = create_function();
     723        ddf_fun_t *fun = create_function();
    797724        if (fun == NULL)
    798725                return NULL;
    799 
     726       
    800727        /* Add one reference that will be dropped by ddf_fun_destroy() */
    801728        fun->dev = dev;
    802729        fun_add_ref(fun);
    803 
     730       
    804731        fun->bound = false;
    805732        fun->ftype = ftype;
    806 
    807         fun->name = str_dup(name);
    808         if (fun->name == NULL) {
    809                 delete_function(fun);
    810                 return NULL;
    811         }
    812 
     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       
    813742        return fun;
    814743}
    815744
    816745/** Allocate driver-specific function data. */
    817 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
    818 {
    819         void *data;
    820 
     746void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     747{
    821748        assert(fun->bound == false);
    822749        assert(fun->driver_data == NULL);
    823 
    824         data = calloc(1, size);
     750       
     751        void *data = calloc(1, size);
    825752        if (data == NULL)
    826753                return NULL;
    827 
     754       
    828755        fun->driver_data = data;
    829756        return data;
    830757}
    831758
     759/** Return driver-specific function data. */
     760void *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 */
     770const char *ddf_fun_get_name(ddf_fun_t *fun)
     771{
     772        return fun->name;
     773}
     774
    832775/** Destroy DDF function node.
    833776 *
     
    835778 * must not be bound.
    836779 *
    837  * @param fun           Function to destroy
     780 * @param fun Function to destroy
     781 *
    838782 */
    839783void ddf_fun_destroy(ddf_fun_t *fun)
    840784{
    841785        assert(fun->bound == false);
    842 
     786       
    843787        /*
    844788         * Drop the reference added by ddf_fun_create(). This will deallocate
     
    855799        if (fun->ops == NULL)
    856800                return NULL;
     801       
    857802        return fun->ops->interfaces[idx];
    858803}
     
    867812 * the same name.
    868813 *
    869  * @param fun           Function to bind
    870  * @return              EOK on success or negative error code
     814 * @param fun Function to bind
     815 *
     816 * @return EOK on success or negative error code
     817 *
    871818 */
    872819int ddf_fun_bind(ddf_fun_t *fun)
     
    875822        assert(fun->name != NULL);
    876823       
    877         int res;
    878        
    879824        add_to_functions_list(fun);
    880         res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
     825        int res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
    881826            fun->dev->handle, &fun->handle);
    882827        if (res != EOK) {
     
    894839 * the function invisible to the system.
    895840 *
    896  * @param fun           Function to unbind
    897  * @return              EOK on success or negative error code
     841 * @param fun Function to unbind
     842 *
     843 * @return EOK on success or negative error code
     844 *
    898845 */
    899846int ddf_fun_unbind(ddf_fun_t *fun)
    900847{
    901         int res;
    902        
    903848        assert(fun->bound == true);
    904849       
    905         res = devman_remove_function(fun->handle);
     850        int res = devman_remove_function(fun->handle);
    906851        if (res != EOK)
    907852                return res;
    908 
     853       
    909854        remove_from_functions_list(fun);
    910855       
     
    915860/** Online function.
    916861 *
    917  * @param fun           Function to online
    918  * @return              EOK on success or negative error code
     862 * @param fun Function to online
     863 *
     864 * @return EOK on success or negative error code
     865 *
    919866 */
    920867int ddf_fun_online(ddf_fun_t *fun)
    921868{
    922         int res;
    923        
    924869        assert(fun->bound == true);
    925870       
    926         res = devman_drv_fun_online(fun->handle);
     871        int res = devman_drv_fun_online(fun->handle);
    927872        if (res != EOK)
    928873                return res;
     
    933878/** Offline function.
    934879 *
    935  * @param fun           Function to offline
    936  * @return              EOK on success or negative error code
     880 * @param fun Function to offline
     881 *
     882 * @return EOK on success or negative error code
     883 *
    937884 */
    938885int ddf_fun_offline(ddf_fun_t *fun)
    939886{
    940         int res;
    941        
    942887        assert(fun->bound == true);
    943888       
    944         res = devman_drv_fun_offline(fun->handle);
     889        int res = devman_drv_fun_offline(fun->handle);
    945890        if (res != EOK)
    946891                return res;
     
    954899 * Cannot be called when the function node is bound.
    955900 *
    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.
     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 *
    960908 */
    961909int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str,
    962910    int match_score)
    963911{
    964         match_id_t *match_id;
    965        
    966912        assert(fun->bound == false);
    967913        assert(fun->ftype == fun_inner);
    968914       
    969         match_id = create_match_id();
     915        match_id_t *match_id = create_match_id();
    970916        if (match_id == NULL)
    971917                return ENOMEM;
     
    976922        add_match_id(&fun->match_ids, match_id);
    977923        return EOK;
     924}
     925
     926/** Set function ops. */
     927void 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 */
     937void 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;
    978941}
    979942
     
    989952 *
    990953 * Must only be called when the function is bound.
     954 *
    991955 */
    992956int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
     
    1000964int ddf_driver_main(driver_t *drv)
    1001965{
    1002         int rc;
    1003 
    1004966        /*
    1005967         * Remember the driver structure - driver_ops will be called by generic
     
    1008970        driver = drv;
    1009971       
    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);
     972        /* Initialize interrupt module */
     973        interrupt_init();
    1015974       
    1016975        /*
     
    1019978         */
    1020979        async_set_client_connection(driver_connection);
    1021         rc = devman_driver_register(driver->name);
     980        int rc = devman_driver_register(driver->name);
    1022981        if (rc != EOK) {
    1023982                printf("Error: Failed to register driver with device manager "
     
    1025984                    str_error(rc));
    1026985               
    1027                 return 1;
     986                return rc;
    1028987        }
    1029988       
     
    1031990        rc = task_retval(0);
    1032991        if (rc != EOK)
    1033                 return 1;
    1034 
     992                return rc;
     993       
    1035994        async_manager();
    1036995       
    1037996        /* Never reached. */
    1038         return 0;
     997        return EOK;
    1039998}
    1040999
Note: See TracChangeset for help on using the changeset viewer.