irq.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Ondrej Palkovsky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00051 #include <arch.h>
00052 #include <mm/slab.h>
00053 #include <errno.h>
00054 #include <ipc/ipc.h>
00055 #include <ipc/irq.h>
00056 #include <atomic.h>
00057 #include <syscall/copy.h>
00058 #include <console/console.h>
00059 
00060 typedef struct {
00061         SPINLOCK_DECLARE(lock);
00062         answerbox_t *box;
00063         irq_code_t *code;
00064         atomic_t counter;
00065 } ipc_irq_t;
00066 
00067 
00068 static ipc_irq_t *irq_conns = NULL;
00069 static int irq_conns_size;
00070 
00071 #include <print.h>
00072 /* Execute code associated with IRQ notification */
00073 static void code_execute(call_t *call, irq_code_t *code)
00074 {
00075         int i;
00076         __native dstval = 0;
00077         
00078         if (!code)
00079                 return;
00080         
00081         for (i=0; i < code->cmdcount;i++) {
00082                 switch (code->cmds[i].cmd) {
00083                 case CMD_MEM_READ_1:
00084                         dstval = *((__u8 *)code->cmds[i].addr);
00085                         break;
00086                 case CMD_MEM_READ_2:
00087                         dstval = *((__u16 *)code->cmds[i].addr);
00088                         break;
00089                 case CMD_MEM_READ_4:
00090                         dstval = *((__u32 *)code->cmds[i].addr);
00091                         break;
00092                 case CMD_MEM_READ_8:
00093                         dstval = *((__u64 *)code->cmds[i].addr);
00094                         break;
00095                 case CMD_MEM_WRITE_1:
00096                         *((__u8 *)code->cmds[i].addr) = code->cmds[i].value;
00097                         break;
00098                 case CMD_MEM_WRITE_2:
00099                         *((__u16 *)code->cmds[i].addr) = code->cmds[i].value;
00100                         break;
00101                 case CMD_MEM_WRITE_4:
00102                         *((__u32 *)code->cmds[i].addr) = code->cmds[i].value;
00103                         break;
00104                 case CMD_MEM_WRITE_8:
00105                         *((__u64 *)code->cmds[i].addr) = code->cmds[i].value;
00106                         break;
00107 #if defined(ia32) || defined(amd64)
00108                 case CMD_PORT_READ_1:
00109                         dstval = inb((long)code->cmds[i].addr);
00110                         break;
00111                 case CMD_PORT_WRITE_1:
00112                         outb((long)code->cmds[i].addr, code->cmds[i].value);
00113                         break;
00114 #endif
00115 #if defined(ia64) 
00116                 case CMD_IA64_GETCHAR:
00117                         dstval = _getc(&ski_uconsole);
00118                         break;
00119 #endif
00120 #if defined(ppc32)
00121                 case CMD_PPC32_GETCHAR:
00122                         dstval = cuda_get_scancode();
00123                         break;
00124 #endif
00125                 default:
00126                         break;
00127                 }
00128                 if (code->cmds[i].dstarg && code->cmds[i].dstarg < 4) {
00129                         call->data.args[code->cmds[i].dstarg] = dstval;
00130                 }
00131         }
00132 }
00133 
00134 static void code_free(irq_code_t *code)
00135 {
00136         if (code) {
00137                 free(code->cmds);
00138                 free(code);
00139         }
00140 }
00141 
00142 static irq_code_t * code_from_uspace(irq_code_t *ucode)
00143 {
00144         irq_code_t *code;
00145         irq_cmd_t *ucmds;
00146         int rc;
00147 
00148         code = malloc(sizeof(*code), 0);
00149         rc = copy_from_uspace(code, ucode, sizeof(*code));
00150         if (rc != 0) {
00151                 free(code);
00152                 return NULL;
00153         }
00154         
00155         if (code->cmdcount > IRQ_MAX_PROG_SIZE) {
00156                 free(code);
00157                 return NULL;
00158         }
00159         ucmds = code->cmds;
00160         code->cmds = malloc(sizeof(code->cmds[0]) * (code->cmdcount), 0);
00161         rc = copy_from_uspace(code->cmds, ucmds, sizeof(code->cmds[0]) * (code->cmdcount));
00162         if (rc != 0) {
00163                 free(code->cmds);
00164                 free(code);
00165                 return NULL;
00166         }
00167 
00168         return code;
00169 }
00170 
00172 void ipc_irq_unregister(answerbox_t *box, int irq)
00173 {
00174         ipl_t ipl;
00175         int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
00176 
00177         ipl = interrupts_disable();
00178         spinlock_lock(&irq_conns[mq].lock);
00179         if (irq_conns[mq].box == box) {
00180                 irq_conns[mq].box = NULL;
00181                 code_free(irq_conns[mq].code);
00182                 irq_conns[mq].code = NULL;
00183         }
00184 
00185         spinlock_unlock(&irq_conns[mq].lock);
00186         interrupts_restore(ipl);
00187 }
00188 
00190 int ipc_irq_register(answerbox_t *box, int irq, irq_code_t *ucode)
00191 {
00192         ipl_t ipl;
00193         irq_code_t *code;
00194         int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
00195 
00196         ASSERT(irq_conns);
00197 
00198         if (ucode) {
00199                 code = code_from_uspace(ucode);
00200                 if (!code)
00201                         return EBADMEM;
00202         } else
00203                 code = NULL;
00204 
00205         ipl = interrupts_disable();
00206         spinlock_lock(&irq_conns[mq].lock);
00207 
00208         if (irq_conns[mq].box) {
00209                 spinlock_unlock(&irq_conns[mq].lock);
00210                 interrupts_restore(ipl);
00211                 code_free(code);
00212                 return EEXISTS;
00213         }
00214         irq_conns[mq].box = box;
00215         irq_conns[mq].code = code;
00216         atomic_set(&irq_conns[mq].counter, 0);
00217         spinlock_unlock(&irq_conns[mq].lock);
00218         interrupts_restore(ipl);
00219 
00220         return 0;
00221 }
00222 
00226 static void send_call(int mq, call_t *call)
00227 {
00228         spinlock_lock(&irq_conns[mq].box->irq_lock);
00229         list_append(&call->link, &irq_conns[mq].box->irq_notifs);
00230         spinlock_unlock(&irq_conns[mq].box->irq_lock);
00231                 
00232         waitq_wakeup(&irq_conns[mq].box->wq, 0);
00233 }
00234 
00238 void ipc_irq_send_msg(int irq, __native a1, __native a2, __native a3)
00239 {
00240         call_t *call;
00241         int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
00242 
00243         spinlock_lock(&irq_conns[mq].lock);
00244 
00245         if (irq_conns[mq].box) {
00246                 call = ipc_call_alloc(FRAME_ATOMIC);
00247                 if (!call) {
00248                         spinlock_unlock(&irq_conns[mq].lock);
00249                         return;
00250                 }
00251                 call->flags |= IPC_CALL_NOTIF;
00252                 IPC_SET_METHOD(call->data, irq);
00253                 IPC_SET_ARG1(call->data, a1);
00254                 IPC_SET_ARG2(call->data, a2);
00255                 IPC_SET_ARG3(call->data, a3);
00256                 /* Put a counter to the message */
00257                 call->private = atomic_preinc(&irq_conns[mq].counter);
00258                 
00259                 send_call(mq, call);
00260         }
00261         spinlock_unlock(&irq_conns[mq].lock);
00262 }
00263 
00268 void ipc_irq_send_notif(int irq)
00269 {
00270         call_t *call;
00271         int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
00272 
00273         ASSERT(irq_conns);
00274         spinlock_lock(&irq_conns[mq].lock);
00275 
00276         if (irq_conns[mq].box) {
00277                 call = ipc_call_alloc(FRAME_ATOMIC);
00278                 if (!call) {
00279                         spinlock_unlock(&irq_conns[mq].lock);
00280                         return;
00281                 }
00282                 call->flags |= IPC_CALL_NOTIF;
00283                 /* Put a counter to the message */
00284                 call->private = atomic_preinc(&irq_conns[mq].counter);
00285                 /* Set up args */
00286                 IPC_SET_METHOD(call->data, irq);
00287 
00288                 /* Execute code to handle irq */
00289                 code_execute(call, irq_conns[mq].code);
00290                 
00291                 send_call(mq, call);
00292         }
00293                 
00294         spinlock_unlock(&irq_conns[mq].lock);
00295 }
00296 
00297 
00302 void ipc_irq_make_table(int irqcount)
00303 {
00304         int i;
00305 
00306         irqcount +=  IPC_IRQ_RESERVED_VIRTUAL;
00307 
00308         irq_conns_size = irqcount;
00309         irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0);
00310         for (i=0; i < irqcount; i++) {
00311                 spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock");
00312                 irq_conns[i].box = NULL;
00313                 irq_conns[i].code = NULL;
00314         }
00315 }
00316 
00322 void ipc_irq_cleanup(answerbox_t *box)
00323 {
00324         int i;
00325         ipl_t ipl;
00326         
00327         for (i=0; i < irq_conns_size; i++) {
00328                 ipl = interrupts_disable();
00329                 spinlock_lock(&irq_conns[i].lock);
00330                 if (irq_conns[i].box == box)
00331                         irq_conns[i].box = NULL;
00332                 spinlock_unlock(&irq_conns[i].lock);
00333                 interrupts_restore(ipl);
00334         }
00335 }
00336 

Generated on Sun Jun 18 17:28:03 2006 for HelenOS Kernel (ppc64) by  doxygen 1.4.6