source: mainline/uspace/lib/drv/generic/interrupt.c@ b0b4592e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b0b4592e was 9359aae, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libc,libdrv: Pass around const pointer to irq code.

We don't modify it at this point.

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup libdrv generic device driver support.
31 * @brief HelenOS generic device driver support.
32 * @{
33 */
34
35/** @file
36 */
37
38#include <async.h>
39#include <errno.h>
40#include <sys/types.h>
41#include <macros.h>
42
43#include "ddf/interrupt.h"
44#include "private/driver.h"
45
46static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall);
47static interrupt_context_t *create_interrupt_context(void);
48static void delete_interrupt_context(interrupt_context_t *ctx);
49static void init_interrupt_context_list(interrupt_context_list_t *list);
50static void add_interrupt_context(interrupt_context_list_t *list,
51 interrupt_context_t *ctx);
52static void remove_interrupt_context(interrupt_context_list_t *list,
53 interrupt_context_t *ctx);
54static interrupt_context_t *find_interrupt_context_by_id(
55 interrupt_context_list_t *list, int id);
56static interrupt_context_t *find_interrupt_context(
57 interrupt_context_list_t *list, ddf_dev_t *dev, int irq);
58
59/** Interrupts */
60static interrupt_context_list_t interrupt_contexts;
61
62static irq_cmd_t default_cmds[] = {
63 {
64 .cmd = CMD_ACCEPT
65 }
66};
67
68static const irq_code_t default_pseudocode = {
69 0,
70 NULL,
71 ARRAY_SIZE(default_cmds),
72 default_cmds
73};
74
75void interrupt_init(void)
76{
77 /* Initialize the list of interrupt contexts. */
78 init_interrupt_context_list(&interrupt_contexts);
79
80 /* Set generic interrupt handler. */
81 async_set_interrupt_received(driver_irq_handler);
82}
83
84static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
85{
86 int id = (int)IPC_GET_IMETHOD(*icall);
87 interrupt_context_t *ctx;
88
89 ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
90 if (ctx != NULL && ctx->handler != NULL)
91 (*ctx->handler)(ctx->dev, iid, icall);
92}
93
94static interrupt_context_t *create_interrupt_context(void)
95{
96 interrupt_context_t *ctx;
97
98 ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
99 if (ctx != NULL)
100 memset(ctx, 0, sizeof(interrupt_context_t));
101
102 return ctx;
103}
104
105static void delete_interrupt_context(interrupt_context_t *ctx)
106{
107 if (ctx != NULL)
108 free(ctx);
109}
110
111static void init_interrupt_context_list(interrupt_context_list_t *list)
112{
113 memset(list, 0, sizeof(interrupt_context_list_t));
114 fibril_mutex_initialize(&list->mutex);
115 list_initialize(&list->contexts);
116}
117
118static void add_interrupt_context(interrupt_context_list_t *list,
119 interrupt_context_t *ctx)
120{
121 fibril_mutex_lock(&list->mutex);
122 ctx->id = list->curr_id++;
123 list_append(&ctx->link, &list->contexts);
124 fibril_mutex_unlock(&list->mutex);
125}
126
127static void remove_interrupt_context(interrupt_context_list_t *list,
128 interrupt_context_t *ctx)
129{
130 fibril_mutex_lock(&list->mutex);
131 list_remove(&ctx->link);
132 fibril_mutex_unlock(&list->mutex);
133}
134
135static interrupt_context_t *find_interrupt_context_by_id(
136 interrupt_context_list_t *list, int id)
137{
138 fibril_mutex_lock(&list->mutex);
139
140 list_foreach(list->contexts, link, interrupt_context_t, ctx) {
141 if (ctx->id == id) {
142 fibril_mutex_unlock(&list->mutex);
143 return ctx;
144 }
145 }
146
147 fibril_mutex_unlock(&list->mutex);
148 return NULL;
149}
150
151static interrupt_context_t *find_interrupt_context(
152 interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
153{
154 fibril_mutex_lock(&list->mutex);
155
156 list_foreach(list->contexts, link, interrupt_context_t, ctx) {
157 if (ctx->irq == irq && ctx->dev == dev) {
158 fibril_mutex_unlock(&list->mutex);
159 return ctx;
160 }
161 }
162
163 fibril_mutex_unlock(&list->mutex);
164 return NULL;
165}
166
167
168int register_interrupt_handler(ddf_dev_t *dev, int irq,
169 interrupt_handler_t *handler, const irq_code_t *pseudocode)
170{
171 interrupt_context_t *ctx = create_interrupt_context();
172
173 ctx->dev = dev;
174 ctx->irq = irq;
175 ctx->handler = handler;
176
177 add_interrupt_context(&interrupt_contexts, ctx);
178
179 if (pseudocode == NULL)
180 pseudocode = &default_pseudocode;
181
182 int res = irq_register(irq, dev->handle, ctx->id, pseudocode);
183 if (res != EOK) {
184 remove_interrupt_context(&interrupt_contexts, ctx);
185 delete_interrupt_context(ctx);
186 }
187
188 return res;
189}
190
191int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
192{
193 interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
194 dev, irq);
195 int res = irq_unregister(irq, dev->handle);
196
197 if (ctx != NULL) {
198 remove_interrupt_context(&interrupt_contexts, ctx);
199 delete_interrupt_context(ctx);
200 }
201
202 return res;
203}
204
205/**
206 * @}
207 */
Note: See TracBrowser for help on using the repository browser.