Ignore:
File:
1 edited

Legend:

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

    r7edfde9 r56fd7cf  
    3939#include <errno.h>
    4040#include <sys/types.h>
    41 #include <macros.h>
    4241
    4342#include "ddf/interrupt.h"
    4443#include "private/driver.h"
    4544
     45static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall);
     46static interrupt_context_t *create_interrupt_context(void);
     47static void delete_interrupt_context(interrupt_context_t *ctx);
     48static void init_interrupt_context_list(interrupt_context_list_t *list);
     49static void add_interrupt_context(interrupt_context_list_t *list,
     50    interrupt_context_t *ctx);
     51static void remove_interrupt_context(interrupt_context_list_t *list,
     52    interrupt_context_t *ctx);
     53static interrupt_context_t *find_interrupt_context_by_id(
     54    interrupt_context_list_t *list, int id);
     55static interrupt_context_t *find_interrupt_context(
     56    interrupt_context_list_t *list, ddf_dev_t *dev, int irq);
    4657int register_interrupt_handler(ddf_dev_t *dev, int irq,
    47     interrupt_handler_t *handler, const irq_code_t *pseudocode)
    48 {
    49         return async_irq_subscribe(irq, dev->handle,
    50             (async_notification_handler_t) handler, dev, pseudocode);
     58    interrupt_handler_t *handler, irq_code_t *pseudocode);
     59int unregister_interrupt_handler(ddf_dev_t *dev, int irq);
     60
     61/** Interrupts */
     62static interrupt_context_list_t interrupt_contexts;
     63
     64static irq_cmd_t default_cmds[] = {
     65        {
     66                .cmd = CMD_ACCEPT
     67        }
     68};
     69
     70static irq_code_t default_pseudocode = {
     71        0,
     72        NULL,
     73        sizeof(default_cmds) / sizeof(irq_cmd_t),
     74        default_cmds
     75};
     76
     77void interrupt_init(void)
     78{
     79        /* Initialize the list of interrupt contexts. */
     80        init_interrupt_context_list(&interrupt_contexts);
     81       
     82        /* Set generic interrupt handler. */
     83        async_set_interrupt_received(driver_irq_handler);
     84}
     85
     86static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     87{
     88        int id = (int)IPC_GET_IMETHOD(*icall);
     89        interrupt_context_t *ctx;
     90       
     91        ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
     92        if (ctx != NULL && ctx->handler != NULL)
     93                (*ctx->handler)(ctx->dev, iid, icall);
     94}
     95
     96static interrupt_context_t *create_interrupt_context(void)
     97{
     98        interrupt_context_t *ctx;
     99       
     100        ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
     101        if (ctx != NULL)
     102                memset(ctx, 0, sizeof(interrupt_context_t));
     103       
     104        return ctx;
     105}
     106
     107static void delete_interrupt_context(interrupt_context_t *ctx)
     108{
     109        if (ctx != NULL)
     110                free(ctx);
     111}
     112
     113static void init_interrupt_context_list(interrupt_context_list_t *list)
     114{
     115        memset(list, 0, sizeof(interrupt_context_list_t));
     116        fibril_mutex_initialize(&list->mutex);
     117        list_initialize(&list->contexts);
     118}
     119
     120static void add_interrupt_context(interrupt_context_list_t *list,
     121    interrupt_context_t *ctx)
     122{
     123        fibril_mutex_lock(&list->mutex);
     124        ctx->id = list->curr_id++;
     125        list_append(&ctx->link, &list->contexts);
     126        fibril_mutex_unlock(&list->mutex);
     127}
     128
     129static void remove_interrupt_context(interrupt_context_list_t *list,
     130    interrupt_context_t *ctx)
     131{
     132        fibril_mutex_lock(&list->mutex);
     133        list_remove(&ctx->link);
     134        fibril_mutex_unlock(&list->mutex);
     135}
     136
     137static interrupt_context_t *find_interrupt_context_by_id(
     138    interrupt_context_list_t *list, int id)
     139{
     140        interrupt_context_t *ctx;
     141       
     142        fibril_mutex_lock(&list->mutex);
     143       
     144        list_foreach(list->contexts, link) {
     145                ctx = list_get_instance(link, interrupt_context_t, link);
     146                if (ctx->id == id) {
     147                        fibril_mutex_unlock(&list->mutex);
     148                        return ctx;
     149                }
     150        }
     151       
     152        fibril_mutex_unlock(&list->mutex);
     153        return NULL;
     154}
     155
     156static interrupt_context_t *find_interrupt_context(
     157    interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
     158{
     159        interrupt_context_t *ctx;
     160       
     161        fibril_mutex_lock(&list->mutex);
     162       
     163        list_foreach(list->contexts, link) {
     164                ctx = list_get_instance(link, interrupt_context_t, link);
     165                if (ctx->irq == irq && ctx->dev == dev) {
     166                        fibril_mutex_unlock(&list->mutex);
     167                        return ctx;
     168                }
     169        }
     170       
     171        fibril_mutex_unlock(&list->mutex);
     172        return NULL;
     173}
     174
     175
     176int register_interrupt_handler(ddf_dev_t *dev, int irq,
     177    interrupt_handler_t *handler, irq_code_t *pseudocode)
     178{
     179        interrupt_context_t *ctx = create_interrupt_context();
     180       
     181        ctx->dev = dev;
     182        ctx->irq = irq;
     183        ctx->handler = handler;
     184       
     185        add_interrupt_context(&interrupt_contexts, ctx);
     186       
     187        if (pseudocode == NULL)
     188                pseudocode = &default_pseudocode;
     189       
     190        int res = irq_register(irq, dev->handle, ctx->id, pseudocode);
     191        if (res != EOK) {
     192                remove_interrupt_context(&interrupt_contexts, ctx);
     193                delete_interrupt_context(ctx);
     194        }
     195       
     196        return res;
    51197}
    52198
    53199int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
    54200{
    55         return async_irq_unsubscribe(irq, dev->handle);
     201        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
     202            dev, irq);
     203        int res = irq_unregister(irq, dev->handle);
     204       
     205        if (ctx != NULL) {
     206                remove_interrupt_context(&interrupt_contexts, ctx);
     207                delete_interrupt_context(ctx);
     208        }
     209       
     210        return res;
    56211}
    57212
Note: See TracChangeset for help on using the changeset viewer.