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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 85a4350 was 77ad86c, checked in by Martin Decky <martin@…>, 13 years ago

cstyle (no change in functionality)

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