Ignore:
File:
1 edited

Legend:

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

    r77ad86c r609243f4  
    7070FIBRIL_MUTEX_INITIALIZE(functions_mutex);
    7171
     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        sizeof(default_cmds) / sizeof(irq_cmd_t),
     83        default_cmds
     84};
     85
    7286static ddf_dev_t *create_device(void);
    7387static void delete_device(ddf_dev_t *);
     
    7993static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
    8094
     95static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     96{
     97        int id = (int)IPC_GET_IMETHOD(*icall);
     98        interrupt_context_t *ctx;
     99       
     100        ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
     101        if (ctx != NULL && ctx->handler != NULL)
     102                (*ctx->handler)(ctx->dev, iid, icall);
     103}
     104
     105interrupt_context_t *create_interrupt_context(void)
     106{
     107        interrupt_context_t *ctx;
     108       
     109        ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
     110        if (ctx != NULL)
     111                memset(ctx, 0, sizeof(interrupt_context_t));
     112       
     113        return ctx;
     114}
     115
     116void delete_interrupt_context(interrupt_context_t *ctx)
     117{
     118        if (ctx != NULL)
     119                free(ctx);
     120}
     121
     122void init_interrupt_context_list(interrupt_context_list_t *list)
     123{
     124        memset(list, 0, sizeof(interrupt_context_list_t));
     125        fibril_mutex_initialize(&list->mutex);
     126        list_initialize(&list->contexts);
     127}
     128
     129void
     130add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
     131{
     132        fibril_mutex_lock(&list->mutex);
     133        ctx->id = list->curr_id++;
     134        list_append(&ctx->link, &list->contexts);
     135        fibril_mutex_unlock(&list->mutex);
     136}
     137
     138void remove_interrupt_context(interrupt_context_list_t *list,
     139    interrupt_context_t *ctx)
     140{
     141        fibril_mutex_lock(&list->mutex);
     142        list_remove(&ctx->link);
     143        fibril_mutex_unlock(&list->mutex);
     144}
     145
     146interrupt_context_t *
     147find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
     148{
     149        interrupt_context_t *ctx;
     150       
     151        fibril_mutex_lock(&list->mutex);
     152       
     153        list_foreach(list->contexts, link) {
     154                ctx = list_get_instance(link, interrupt_context_t, link);
     155                if (ctx->id == id) {
     156                        fibril_mutex_unlock(&list->mutex);
     157                        return ctx;
     158                }
     159        }
     160       
     161        fibril_mutex_unlock(&list->mutex);
     162        return NULL;
     163}
     164
     165interrupt_context_t *
     166find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
     167{
     168        interrupt_context_t *ctx;
     169       
     170        fibril_mutex_lock(&list->mutex);
     171       
     172        list_foreach(list->contexts, link) {
     173                ctx = list_get_instance(link, interrupt_context_t, link);
     174                if (ctx->irq == irq && ctx->dev == dev) {
     175                        fibril_mutex_unlock(&list->mutex);
     176                        return ctx;
     177                }
     178        }
     179       
     180        fibril_mutex_unlock(&list->mutex);
     181        return NULL;
     182}
     183
     184
     185int
     186register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
     187    irq_code_t *pseudocode)
     188{
     189        interrupt_context_t *ctx = create_interrupt_context();
     190       
     191        ctx->dev = dev;
     192        ctx->irq = irq;
     193        ctx->handler = handler;
     194       
     195        add_interrupt_context(&interrupt_contexts, ctx);
     196       
     197        if (pseudocode == NULL)
     198                pseudocode = &default_pseudocode;
     199       
     200        int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
     201        if (res != EOK) {
     202                remove_interrupt_context(&interrupt_contexts, ctx);
     203                delete_interrupt_context(ctx);
     204        }
     205
     206        return res;
     207}
     208
     209int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
     210{
     211        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
     212            dev, irq);
     213        int res = unregister_irq(irq, dev->handle);
     214       
     215        if (ctx != NULL) {
     216                remove_interrupt_context(&interrupt_contexts, ctx);
     217                delete_interrupt_context(ctx);
     218        }
     219       
     220        return res;
     221}
     222
    81223static void add_to_functions_list(ddf_fun_t *fun)
    82224{
     
    125267static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
    126268{
     269        char *dev_name = NULL;
     270        int res;
     271       
    127272        devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
    128273        devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
    129274       
    130275        ddf_dev_t *dev = create_device();
    131        
     276
    132277        /* Add one reference that will be dropped by driver_dev_remove() */
    133278        dev_add_ref(dev);
    134279        dev->handle = dev_handle;
    135        
    136         char *dev_name = NULL;
     280
    137281        async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
    138282        dev->name = dev_name;
    139        
     283
    140284        /*
    141285         * Currently not used, parent fun handle is stored in context
     
    144288        (void) parent_fun_handle;
    145289       
    146         int res = driver->driver_ops->dev_add(dev);
     290        res = driver->driver_ops->add_device(dev);
    147291       
    148292        if (res != EOK) {
     
    159303}
    160304
     305static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)
     306{
     307        fibril_mutex_lock(&devices_mutex);
     308        ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall));
     309        fibril_mutex_unlock(&devices_mutex);
     310       
     311        if (dev != NULL && driver->driver_ops->device_added != NULL)
     312                driver->driver_ops->device_added(dev);
     313}
     314
    161315static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
    162316{
    163         devman_handle_t devh = IPC_GET_ARG1(*icall);
     317        devman_handle_t devh;
     318        ddf_dev_t *dev;
     319        int rc;
     320       
     321        devh = IPC_GET_ARG1(*icall);
    164322       
    165323        fibril_mutex_lock(&devices_mutex);
    166         ddf_dev_t *dev = driver_get_device(devh);
     324        dev = driver_get_device(devh);
    167325        if (dev != NULL)
    168326                dev_add_ref(dev);
     
    173331                return;
    174332        }
    175        
    176         int rc;
    177333       
    178334        if (driver->driver_ops->dev_remove != NULL)
     
    189345static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
    190346{
    191         devman_handle_t devh = IPC_GET_ARG1(*icall);
     347        devman_handle_t devh;
     348        ddf_dev_t *dev;
     349        int rc;
     350       
     351        devh = IPC_GET_ARG1(*icall);
    192352       
    193353        fibril_mutex_lock(&devices_mutex);
    194         ddf_dev_t *dev = driver_get_device(devh);
     354        dev = driver_get_device(devh);
    195355        if (dev != NULL)
    196356                dev_add_ref(dev);
     
    201361                return;
    202362        }
    203        
    204         int rc;
    205363       
    206364        if (driver->driver_ops->dev_gone != NULL)
     
    217375static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    218376{
    219         devman_handle_t funh = IPC_GET_ARG1(*icall);
     377        devman_handle_t funh;
     378        ddf_fun_t *fun;
     379        int rc;
     380       
     381        funh = IPC_GET_ARG1(*icall);
    220382       
    221383        /*
     
    226388        fibril_mutex_lock(&functions_mutex);
    227389       
    228         ddf_fun_t *fun = driver_get_function(funh);
     390        fun = driver_get_function(funh);
    229391        if (fun != NULL)
    230392                fun_add_ref(fun);
     
    238400       
    239401        /* Call driver entry point */
    240         int rc;
    241        
    242402        if (driver->driver_ops->fun_online != NULL)
    243403                rc = driver->driver_ops->fun_online(fun);
     
    252412static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    253413{
    254         devman_handle_t funh = IPC_GET_ARG1(*icall);
     414        devman_handle_t funh;
     415        ddf_fun_t *fun;
     416        int rc;
     417       
     418        funh = IPC_GET_ARG1(*icall);
    255419       
    256420        /*
     
    261425        fibril_mutex_lock(&functions_mutex);
    262426       
    263         ddf_fun_t *fun = driver_get_function(funh);
     427        fun = driver_get_function(funh);
    264428        if (fun != NULL)
    265429                fun_add_ref(fun);
     
    273437       
    274438        /* Call driver entry point */
    275         int rc;
    276        
    277439        if (driver->driver_ops->fun_offline != NULL)
    278440                rc = driver->driver_ops->fun_offline(fun);
     
    298460                case DRIVER_DEV_ADD:
    299461                        driver_dev_add(callid, &call);
     462                        break;
     463                case DRIVER_DEV_ADDED:
     464                        async_answer_0(callid, EOK);
     465                        driver_dev_added(callid, &call);
    300466                        break;
    301467                case DRIVER_DEV_REMOVE:
     
    585751
    586752/** Allocate driver-specific device data. */
    587 void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
    588 {
     753extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     754{
     755        void *data;
     756
    589757        assert(dev->driver_data == NULL);
    590        
    591         void *data = calloc(1, size);
     758
     759        data = calloc(1, size);
    592760        if (data == NULL)
    593761                return NULL;
    594        
     762
    595763        dev->driver_data = data;
    596764        return data;
     
    622790ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name)
    623791{
    624         ddf_fun_t *fun = create_function();
     792        ddf_fun_t *fun;
     793
     794        fun = create_function();
    625795        if (fun == NULL)
    626796                return NULL;
    627        
     797
    628798        /* Add one reference that will be dropped by ddf_fun_destroy() */
    629799        fun->dev = dev;
    630800        fun_add_ref(fun);
    631        
     801
    632802        fun->bound = false;
    633803        fun->ftype = ftype;
    634        
     804
    635805        fun->name = str_dup(name);
    636806        if (fun->name == NULL) {
     
    638808                return NULL;
    639809        }
    640        
     810
    641811        return fun;
    642812}
    643813
    644814/** Allocate driver-specific function data. */
    645 void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
    646 {
     815extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     816{
     817        void *data;
     818
    647819        assert(fun->bound == false);
    648820        assert(fun->driver_data == NULL);
    649        
    650         void *data = calloc(1, size);
     821
     822        data = calloc(1, size);
    651823        if (data == NULL)
    652824                return NULL;
    653        
     825
    654826        fun->driver_data = data;
    655827        return data;
     
    661833 * must not be bound.
    662834 *
    663  * @param fun Function to destroy
    664  *
     835 * @param fun           Function to destroy
    665836 */
    666837void ddf_fun_destroy(ddf_fun_t *fun)
    667838{
    668839        assert(fun->bound == false);
    669        
     840
    670841        /*
    671842         * Drop the reference added by ddf_fun_create(). This will deallocate
     
    682853        if (fun->ops == NULL)
    683854                return NULL;
    684        
    685855        return fun->ops->interfaces[idx];
    686856}
     
    695865 * the same name.
    696866 *
    697  * @param fun Function to bind
    698  *
    699  * @return EOK on success or negative error code
    700  *
     867 * @param fun           Function to bind
     868 * @return              EOK on success or negative error code
    701869 */
    702870int ddf_fun_bind(ddf_fun_t *fun)
     
    705873        assert(fun->name != NULL);
    706874       
     875        int res;
     876       
    707877        add_to_functions_list(fun);
    708         int res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
     878        res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
    709879            fun->dev->handle, &fun->handle);
    710880        if (res != EOK) {
     
    722892 * the function invisible to the system.
    723893 *
    724  * @param fun Function to unbind
    725  *
    726  * @return EOK on success or negative error code
    727  *
     894 * @param fun           Function to unbind
     895 * @return              EOK on success or negative error code
    728896 */
    729897int ddf_fun_unbind(ddf_fun_t *fun)
    730898{
     899        int res;
     900       
    731901        assert(fun->bound == true);
    732902       
    733         int res = devman_remove_function(fun->handle);
     903        res = devman_remove_function(fun->handle);
    734904        if (res != EOK)
    735905                return res;
    736        
     906
    737907        remove_from_functions_list(fun);
    738908       
     
    743913/** Online function.
    744914 *
    745  * @param fun Function to online
    746  *
    747  * @return EOK on success or negative error code
    748  *
     915 * @param fun           Function to online
     916 * @return              EOK on success or negative error code
    749917 */
    750918int ddf_fun_online(ddf_fun_t *fun)
    751919{
     920        int res;
     921       
    752922        assert(fun->bound == true);
    753923       
    754         int res = devman_drv_fun_online(fun->handle);
     924        res = devman_drv_fun_online(fun->handle);
    755925        if (res != EOK)
    756926                return res;
     
    761931/** Offline function.
    762932 *
    763  * @param fun Function to offline
    764  *
    765  * @return EOK on success or negative error code
    766  *
     933 * @param fun           Function to offline
     934 * @return              EOK on success or negative error code
    767935 */
    768936int ddf_fun_offline(ddf_fun_t *fun)
    769937{
     938        int res;
     939       
    770940        assert(fun->bound == true);
    771941       
    772         int res = devman_drv_fun_offline(fun->handle);
     942        res = devman_drv_fun_offline(fun->handle);
    773943        if (res != EOK)
    774944                return res;
     
    782952 * Cannot be called when the function node is bound.
    783953 *
    784  * @param fun          Function
    785  * @param match_id_str Match string
    786  * @param match_score  Match score
    787  *
    788  * @return EOK on success.
    789  * @return ENOMEM if out of memory.
    790  *
     954 * @param fun                   Function
     955 * @param match_id_str          Match string
     956 * @param match_score           Match score
     957 * @return                      EOK on success, ENOMEM if out of memory.
    791958 */
    792959int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str,
    793960    int match_score)
    794961{
     962        match_id_t *match_id;
     963       
    795964        assert(fun->bound == false);
    796965        assert(fun->ftype == fun_inner);
    797966       
    798         match_id_t *match_id = create_match_id();
     967        match_id = create_match_id();
    799968        if (match_id == NULL)
    800969                return ENOMEM;
    801970       
    802971        match_id->id = str_dup(match_id_str);
    803         match_id->score = match_score;
     972        match_id->score = 90;
    804973       
    805974        add_match_id(&fun->match_ids, match_id);
     
    818987 *
    819988 * Must only be called when the function is bound.
    820  *
    821989 */
    822990int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
     
    830998int ddf_driver_main(driver_t *drv)
    831999{
     1000        int rc;
     1001
    8321002        /*
    8331003         * Remember the driver structure - driver_ops will be called by generic
     
    8361006        driver = drv;
    8371007       
    838         /* Initialize interrupt module */
    839         interrupt_init();
     1008        /* Initialize the list of interrupt contexts. */
     1009        init_interrupt_context_list(&interrupt_contexts);
     1010       
     1011        /* Set generic interrupt handler. */
     1012        async_set_interrupt_received(driver_irq_handler);
    8401013       
    8411014        /*
     
    8431016         * incoming connections.
    8441017         */
    845         async_set_client_connection(driver_connection);
    846         int rc = devman_driver_register(driver->name);
     1018        rc = devman_driver_register(driver->name, driver_connection);
    8471019        if (rc != EOK) {
    8481020                printf("Error: Failed to register driver with device manager "
     
    8501022                    str_error(rc));
    8511023               
    852                 return rc;
     1024                return 1;
    8531025        }
    8541026       
     
    8561028        rc = task_retval(0);
    8571029        if (rc != EOK)
    858                 return rc;
    859        
     1030                return 1;
     1031
    8601032        async_manager();
    8611033       
    8621034        /* Never reached. */
    863         return EOK;
     1035        return 0;
    8641036}
    8651037
Note: See TracChangeset for help on using the changeset viewer.