00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
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
00284 call->private = atomic_preinc(&irq_conns[mq].counter);
00285
00286 IPC_SET_METHOD(call->data, irq);
00287
00288
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