00001
00009
00010
00011
00012
00013
00014 #include <l4/sys/types.h>
00015 #include <l4/sys/ipc.h>
00016 #include <l4/sys/kdebug.h>
00017 #include <l4/omega0/client.h>
00018 #include <l4/util/util.h>
00019 #include <l4/util/l4_macros.h>
00020 #include <l4/log/l4log.h>
00021 #include <stdlib.h>
00022 #include <omega0_proto.h>
00023
00024 #include "globals.h"
00025 #include "server.h"
00026 #include "irq_threads.h"
00027
00036 static int
00037 attach(l4_threadid_t client, omega0_irqdesc_t desc)
00038 {
00039 int num;
00040 client_chain*c;
00041 l4util_wq_lock_queue_elem_t wqe;
00042
00043 desc.s.num--;
00044 if (desc.s.num > IRQ_NUMS)
00045 return -1;
00046 if (!irqs[desc.s.num].available)
00047 return -1;
00048
00049
00050
00051
00052 for (num=0;num<IRQ_NUMS; num++)
00053 {
00054 for (c = irqs[num].clients;c;c=c->next){
00055 if (l4_thread_equal(client, c->client))
00056 return -1;
00057 }
00058 }
00059
00060
00061
00062
00063 if (irqs[desc.s.num].clients &&
00064 (!desc.s.shared || !irqs[desc.s.num].shared))
00065 return -1;
00066
00067
00068 c = malloc(sizeof(client_chain));
00069 if(!c)
00070 {
00071 LOGl("error getting %ld bytes of memory", (unsigned long)sizeof(client_chain));
00072 if(ENTER_KDEBUG_ON_ERRORS)
00073 enter_kdebug("!");
00074 return -1;
00075 }
00076
00077 c->client = client;
00078 c->masked = 0;
00079 c->waiting = 0;
00080 c->in_service = 0;
00081 aquire_mutex(&irqs[desc.s.num].mutex, &wqe);
00082 c->last_irq_num = irqs[desc.s.num].counter;
00083 c->next = irqs[desc.s.num].clients;
00084 irqs[desc.s.num].clients = c;
00085 irqs[desc.s.num].shared = desc.s.shared;
00086 irqs[desc.s.num].masked++;
00087 irqs[desc.s.num].clients_registered++;
00088 c->masked = 1;
00089 release_mutex(&irqs[desc.s.num].mutex, &wqe);
00090
00091 LOGdl(OMEGA0_DEBUG_REQUESTS,
00092 "client [%x.%x] registered to irq 0x%lx, registered_clients=%d\n",
00093 client.id.task, client.id.lthread,
00094 (unsigned long)desc.s.num,
00095 (unsigned)irqs[desc.s.num].clients_registered);
00096
00097 return irqs[desc.s.num].lthread;
00098 }
00099
00100
00102 static int
00103 detach(l4_threadid_t client, int irq, int cmp_task)
00104 {
00105 client_chain *c, *b;
00106 l4util_wq_lock_queue_elem_t wqe;
00107
00108 aquire_mutex(&irqs[irq].mutex, &wqe);
00109
00110 b = NULL;
00111 for (c=irqs[irq].clients; c; c=c->next)
00112 {
00113 if (( cmp_task && l4_tasknum_equal(client, c->client)) ||
00114 (!cmp_task && l4_thread_equal(client, c->client)))
00115 break;
00116 b = c;
00117 }
00118 if (!c)
00119 {
00120 release_mutex(&irqs[irq].mutex, &wqe);
00121 return -1;
00122 }
00123
00124 if(OMEGA0_STRATEGY_AUTO_CONSUME)
00125 {
00126 check_auto_consume(irq, c);
00127 irqs[irq].clients_registered--;
00128 }
00129
00130 if (b)
00131 b->next = c->next;
00132 else
00133 irqs[irq].clients = c->next;
00134 release_mutex(&irqs[irq].mutex, &wqe);
00135
00136 free(c);
00137 return 0;
00138 }
00139
00141 static int
00142 detach_all(int task)
00143 {
00144 int irq;
00145 l4_threadid_t client;
00146
00147 client.id.task = task;
00148
00149 for (irq=0; irq<IRQ_NUMS; irq++)
00150 detach(client, irq, 1);
00151
00152 return 0;
00153 }
00154
00159 static int
00160 pass(l4_threadid_t client, omega0_irqdesc_t desc, l4_threadid_t new_client)
00161 {
00162 if (detach(client, desc.s.num-1, 0)==0)
00163 return attach(new_client, desc);
00164 else
00165 return -1;
00166 }
00167
00169 static int
00170 first(void)
00171 {
00172 int i;
00173
00174 for (i=0;i<IRQ_NUMS;i++)
00175 if (irqs[i].available)
00176 return i+1;
00177
00178 return 0;
00179 }
00180
00182 static int
00183 next(int irq)
00184 {
00185 for (;irq<IRQ_NUMS;irq++)
00186 if (irqs[irq].available)
00187 return irq+1;
00188 return 0;
00189 }
00190
00195 void
00196 server(void)
00197 {
00198 l4_threadid_t client;
00199 extern l4_threadid_t events_thread_id;
00200 l4_umword_t dw0, dw1;
00201 l4_msgdope_t result;
00202 int error, ret;
00203 struct
00204 {
00205 l4_fpage_t rcv_fpage;
00206 l4_msgdope_t size;
00207 l4_msgdope_t snd;
00208 l4_umword_t dw0, dw1;
00209 l4_threadid_t thread;
00210 } msg;
00211
00212 msg.size = L4_IPC_DOPE(4,0);
00213 error = l4_ipc_wait(&client, &msg, &dw0, &dw1, L4_IPC_NEVER, &result);
00214 while (1)
00215 {
00216 if (error)
00217 {
00218 LOGl("IPC error %#x", error);
00219 msg.size = L4_IPC_DOPE(4,0);
00220 error = l4_ipc_wait(&client, &msg, &dw0, &dw1,
00221 L4_IPC_NEVER, &result);
00222 continue;
00223 }
00224
00225 switch(dw0)
00226 {
00227 case OMEGA0_ATTACH:
00228 ret = attach(client, (omega0_irqdesc_t)dw1);
00229 break;
00230 case OMEGA0_DETACH:
00231 ret = detach(client, ((omega0_irqdesc_t)dw1).s.num-1, 0);
00232 break;
00233 case OMEGA0_DETACH_ALL:
00234 if (l4_thread_equal(client, events_thread_id))
00235 ret = detach_all(dw1);
00236 else
00237 {
00238 LOGl("Ignoring detach_all request from "l4util_idfmt,
00239 l4util_idstr(client));
00240 ret = -1;
00241 }
00242 break;
00243 case OMEGA0_PASS:
00244 ret = pass(client, (omega0_irqdesc_t)dw1, msg.thread);
00245 break;
00246 case OMEGA0_FIRST:
00247 ret = first();
00248 break;
00249 case OMEGA0_NEXT:
00250 ret = next(dw1);
00251 break;
00252 default:
00253 ret = -1;
00254 break;
00255 }
00256 msg.size = L4_IPC_DOPE(4,0);
00257 error = l4_ipc_reply_and_wait(client, L4_IPC_SHORT_MSG, ret, 0,
00258 &client, &msg, &dw0, &dw1,
00259 L4_IPC_SEND_TIMEOUT_0, &result);
00260 }
00261 }