Rev 1260 | Rev 1342 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1260 | Rev 1281 | ||
---|---|---|---|
Line 42... | Line 42... | ||
42 | #include <debug.h> |
42 | #include <debug.h> |
43 | 43 | ||
44 | #include <print.h> |
44 | #include <print.h> |
45 | #include <proc/thread.h> |
45 | #include <proc/thread.h> |
46 | #include <arch/interrupt.h> |
46 | #include <arch/interrupt.h> |
- | 47 | #include <ipc/irq.h> |
|
47 | 48 | ||
48 | /* Open channel that is assigned automatically to new tasks */ |
49 | /* Open channel that is assigned automatically to new tasks */ |
49 | answerbox_t *ipc_phone_0 = NULL; |
50 | answerbox_t *ipc_phone_0 = NULL; |
50 | 51 | ||
51 | static slab_cache_t *ipc_call_slab; |
52 | static slab_cache_t *ipc_call_slab; |
52 | 53 | ||
53 | typedef struct { |
- | |
54 | SPINLOCK_DECLARE(lock); |
- | |
55 | answerbox_t *box; |
- | |
56 | } ipc_irq_t; |
- | |
57 | - | ||
58 | static ipc_irq_t *irq_conns = NULL; |
- | |
59 | static int irq_conns_size; |
- | |
60 | - | ||
61 | /* Initialize new call */ |
54 | /* Initialize new call */ |
62 | static void _ipc_call_init(call_t *call) |
55 | static void _ipc_call_init(call_t *call) |
63 | { |
56 | { |
64 | memsetb((__address)call, sizeof(*call), 0); |
57 | memsetb((__address)call, sizeof(*call), 0); |
65 | call->callerbox = &TASK->answerbox; |
58 | call->callerbox = &TASK->answerbox; |
Line 326... | Line 319... | ||
326 | spinlock_lock(&box->lock); |
319 | spinlock_lock(&box->lock); |
327 | if (!list_empty(&box->irq_notifs)) { |
320 | if (!list_empty(&box->irq_notifs)) { |
328 | ipl = interrupts_disable(); |
321 | ipl = interrupts_disable(); |
329 | spinlock_lock(&box->irq_lock); |
322 | spinlock_lock(&box->irq_lock); |
330 | 323 | ||
331 | request = list_get_instance(box->answers.next, call_t, list); |
324 | request = list_get_instance(box->irq_notifs.next, call_t, list); |
332 | list_remove(&request->list); |
325 | list_remove(&request->list); |
333 | 326 | ||
334 | spinlock_unlock(&box->irq_lock); |
327 | spinlock_unlock(&box->irq_lock); |
335 | interrupts_restore(ipl); |
328 | interrupts_restore(ipl); |
336 | } else if (!list_empty(&box->answers)) { |
329 | } else if (!list_empty(&box->answers)) { |
Line 368... | Line 361... | ||
368 | IPC_SET_RETVAL(call->data, EHANGUP); |
361 | IPC_SET_RETVAL(call->data, EHANGUP); |
369 | _ipc_answer_free_call(call); |
362 | _ipc_answer_free_call(call); |
370 | } |
363 | } |
371 | } |
364 | } |
372 | 365 | ||
373 | /** Disconnect all irq's notifications |
- | |
374 | * |
- | |
375 | * TODO: It may be better to do some linked list, so that |
- | |
376 | * we wouldn't need to go through whole array every cleanup |
- | |
377 | */ |
- | |
378 | static void ipc_irq_cleanup(answerbox_t *box) |
- | |
379 | { |
- | |
380 | int i; |
- | |
381 | ipl_t ipl; |
- | |
382 | - | ||
383 | for (i=0; i < irq_conns_size; i++) { |
- | |
384 | ipl = interrupts_disable(); |
- | |
385 | spinlock_lock(&irq_conns[i].lock); |
- | |
386 | if (irq_conns[i].box == box) |
- | |
387 | irq_conns[i].box = NULL; |
- | |
388 | spinlock_unlock(&irq_conns[i].lock); |
- | |
389 | interrupts_restore(ipl); |
- | |
390 | } |
- | |
391 | } |
- | |
392 | - | ||
393 | /** Cleans up all IPC communication of the given task |
366 | /** Cleans up all IPC communication of the given task |
394 | * |
367 | * |
395 | * |
368 | * |
396 | */ |
369 | */ |
397 | void ipc_cleanup(task_t *task) |
370 | void ipc_cleanup(task_t *task) |
Line 441... | Line 414... | ||
441 | atomic_dec(&task->active_calls); |
414 | atomic_dec(&task->active_calls); |
442 | ipc_call_free(call); |
415 | ipc_call_free(call); |
443 | } |
416 | } |
444 | } |
417 | } |
445 | 418 | ||
446 | /** Initialize table of interrupt handlers */ |
- | |
447 | static void ipc_irq_make_table(int irqcount) |
- | |
448 | { |
- | |
449 | int i; |
- | |
450 | - | ||
451 | irq_conns_size = irqcount; |
- | |
452 | irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0); |
- | |
453 | for (i=0; i < irqcount; i++) { |
- | |
454 | spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock"); |
- | |
455 | irq_conns[i].box = NULL; |
- | |
456 | } |
- | |
457 | } |
- | |
458 | - | ||
459 | void ipc_irq_unregister(answerbox_t *box, int irq) |
- | |
460 | { |
- | |
461 | ipl_t ipl; |
- | |
462 | - | ||
463 | ipl = interrupts_disable(); |
- | |
464 | spinlock_lock(&irq_conns[irq].lock); |
- | |
465 | if (irq_conns[irq].box == box) |
- | |
466 | irq_conns[irq].box = NULL; |
- | |
467 | - | ||
468 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
469 | interrupts_restore(ipl); |
- | |
470 | } |
- | |
471 | - | ||
472 | /** Register an answerbox as a receiving end of interrupts notifications */ |
- | |
473 | int ipc_irq_register(answerbox_t *box, int irq) |
- | |
474 | { |
- | |
475 | ipl_t ipl; |
- | |
476 | - | ||
477 | ASSERT(irq_conns); |
- | |
478 | - | ||
479 | ipl = interrupts_disable(); |
- | |
480 | spinlock_lock(&irq_conns[irq].lock); |
- | |
481 | - | ||
482 | if (irq_conns[irq].box) { |
- | |
483 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
484 | interrupts_restore(ipl); |
- | |
485 | return EEXISTS; |
- | |
486 | } |
- | |
487 | irq_conns[irq].box = box; |
- | |
488 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
489 | interrupts_restore(ipl); |
- | |
490 | - | ||
491 | return 0; |
- | |
492 | } |
- | |
493 | - | ||
494 | /** Notify process that an irq had happend |
- | |
495 | * |
- | |
496 | * We expect interrupts to be disabled |
- | |
497 | */ |
- | |
498 | void ipc_irq_send_notif(int irq) |
- | |
499 | { |
- | |
500 | call_t *call; |
- | |
501 | - | ||
502 | ASSERT(irq_conns); |
- | |
503 | spinlock_lock(&irq_conns[irq].lock); |
- | |
504 | - | ||
505 | if (irq_conns[irq].box) { |
- | |
506 | call = ipc_call_alloc(FRAME_ATOMIC); |
- | |
507 | call->flags |= IPC_CALL_NOTIF; |
- | |
508 | IPC_SET_METHOD(call->data, IPC_M_INTERRUPT); |
- | |
509 | IPC_SET_ARG1(call->data, irq); |
- | |
510 | - | ||
511 | spinlock_lock(&irq_conns[irq].box->irq_lock); |
- | |
512 | list_append(&call->list, &irq_conns[irq].box->irq_notifs); |
- | |
513 | spinlock_unlock(&irq_conns[irq].box->irq_lock); |
- | |
514 | - | ||
515 | waitq_wakeup(&irq_conns[irq].box->wq, 0); |
- | |
516 | } |
- | |
517 | - | ||
518 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
519 | } |
- | |
520 | 419 | ||
521 | /** Initilize ipc subsystem */ |
420 | /** Initilize ipc subsystem */ |
522 | void ipc_init(void) |
421 | void ipc_init(void) |
523 | { |
422 | { |
524 | ipc_call_slab = slab_cache_create("ipc_call", |
423 | ipc_call_slab = slab_cache_create("ipc_call", |