Changes in uspace/lib/drv/generic/interrupt.c [7edfde9:56fd7cf] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/interrupt.c
r7edfde9 r56fd7cf 39 39 #include <errno.h> 40 40 #include <sys/types.h> 41 #include <macros.h>42 41 43 42 #include "ddf/interrupt.h" 44 43 #include "private/driver.h" 45 44 45 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall); 46 static interrupt_context_t *create_interrupt_context(void); 47 static void delete_interrupt_context(interrupt_context_t *ctx); 48 static void init_interrupt_context_list(interrupt_context_list_t *list); 49 static void add_interrupt_context(interrupt_context_list_t *list, 50 interrupt_context_t *ctx); 51 static void remove_interrupt_context(interrupt_context_list_t *list, 52 interrupt_context_t *ctx); 53 static interrupt_context_t *find_interrupt_context_by_id( 54 interrupt_context_list_t *list, int id); 55 static interrupt_context_t *find_interrupt_context( 56 interrupt_context_list_t *list, ddf_dev_t *dev, int irq); 46 57 int 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); 59 int unregister_interrupt_handler(ddf_dev_t *dev, int irq); 60 61 /** Interrupts */ 62 static interrupt_context_list_t interrupt_contexts; 63 64 static irq_cmd_t default_cmds[] = { 65 { 66 .cmd = CMD_ACCEPT 67 } 68 }; 69 70 static irq_code_t default_pseudocode = { 71 0, 72 NULL, 73 sizeof(default_cmds) / sizeof(irq_cmd_t), 74 default_cmds 75 }; 76 77 void 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 86 static 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 96 static 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 107 static void delete_interrupt_context(interrupt_context_t *ctx) 108 { 109 if (ctx != NULL) 110 free(ctx); 111 } 112 113 static 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 120 static 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 129 static 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 137 static 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 156 static 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 176 int 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; 51 197 } 52 198 53 199 int unregister_interrupt_handler(ddf_dev_t *dev, int irq) 54 200 { 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; 56 211 } 57 212
Note:
See TracChangeset
for help on using the changeset viewer.