Ignore:
File:
1 edited

Legend:

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

    rbf31e3f rf302586  
    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 = irq_register(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 = irq_unregister(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{
     
    159301       
    160302        async_answer_0(iid, res);
     303}
     304
     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);
    161313}
    162314
     
    308460                case DRIVER_DEV_ADD:
    309461                        driver_dev_add(callid, &call);
     462                        break;
     463                case DRIVER_DEV_ADDED:
     464                        async_answer_0(callid, EOK);
     465                        driver_dev_added(callid, &call);
    310466                        break;
    311467                case DRIVER_DEV_REMOVE:
     
    595751
    596752/** Allocate driver-specific device data. */
    597 void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     753extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
    598754{
    599755        void *data;
     
    657813
    658814/** Allocate driver-specific function data. */
    659 void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     815extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
    660816{
    661817        void *data;
     
    8501006        driver = drv;
    8511007       
    852         /* Initialize interrupt module */
    853         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);
    8541013       
    8551014        /*
Note: See TracChangeset for help on using the changeset viewer.