From 65e8abb449e8caec8d7358f29e6340814e07a050 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Fri, 14 Feb 2020 18:43:48 +0100
Subject: [PATCH] Allow multiple processes to share IRQs.

I haven't been able to receive xhc interrupt anyway.
---
 src/scheme/irq.rs | 57 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 44 insertions(+), 13 deletions(-)

diff --git a/src/scheme/irq.rs b/src/scheme/irq.rs
index 60bcdd2c..a238698c 100644
--- a/src/scheme/irq.rs
+++ b/src/scheme/irq.rs
@@ -1,6 +1,8 @@
 use core::{mem, str};
-use core::sync::atomic::Ordering;
-use spin::Mutex;
+use core::sync::atomic::{AtomicUsize, Ordering};
+use spin::{Mutex, RwLock};
+
+use alloc::collections::BTreeMap;
 
 use crate::event;
 use crate::interrupt::irq::acknowledge;
@@ -12,22 +14,42 @@ use crate::syscall::scheme::Scheme;
 pub static IRQ_SCHEME_ID: AtomicSchemeId = AtomicSchemeId::default();
 
 /// IRQ queues
-static ACKS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
 static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
+static HANDLES: RwLock<Option<BTreeMap<usize, Handle>>> = RwLock::new(None);
 
 /// Add to the input queue
 #[no_mangle]
 pub extern fn irq_trigger(irq: u8) {
     COUNTS.lock()[irq as usize] += 1;
-    event::trigger(IRQ_SCHEME_ID.load(Ordering::SeqCst), irq as usize, EVENT_READ);
+
+    let guard = HANDLES.read();
+    if let Some(handles) = guard.as_ref() {
+        for (fd, _) in handles.iter().filter(|(_, handle)| handle.irq == irq) {
+            event::trigger(IRQ_SCHEME_ID.load(Ordering::SeqCst), *fd, EVENT_READ);
+        }
+    } else {
+        println!("Calling IRQ without triggering");
+    }
 }
 
-pub struct IrqScheme;
+struct Handle {
+    ack: AtomicUsize,
+    irq: u8,
+}
+
+pub struct IrqScheme {
+    next_fd: AtomicUsize,
+}
 
 impl IrqScheme {
     pub fn new(scheme_id: SchemeId) -> IrqScheme {
         IRQ_SCHEME_ID.store(scheme_id, Ordering::SeqCst);
-        IrqScheme
+
+        *HANDLES.write() = Some(BTreeMap::new());
+
+        IrqScheme {
+            next_fd: AtomicUsize::new(0),
+        }
     }
 }
 
@@ -39,7 +61,9 @@ impl Scheme for IrqScheme {
             let id = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
 
             if id < COUNTS.lock().len() {
-                Ok(id)
+                let fd = self.next_fd.fetch_add(1, Ordering::Relaxed);
+                HANDLES.write().as_mut().unwrap().insert(fd, Handle { ack: AtomicUsize::new(0), irq: id as u8 });
+                Ok(fd)
             } else {
                 Err(Error::new(ENOENT))
             }
@@ -51,9 +75,11 @@ impl Scheme for IrqScheme {
     fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize> {
         // Ensures that the length of the buffer is larger than the size of a usize
         if buffer.len() >= mem::size_of::<usize>() {
-            let ack = ACKS.lock()[file];
-            let current = COUNTS.lock()[file];
-            if ack != current {
+            let handles_guard = HANDLES.read();
+            let handle = &handles_guard.as_ref().unwrap().get(&file).ok_or(Error::new(EBADF))?;
+
+            let current = COUNTS.lock()[handle.irq as usize];
+            if handle.ack.load(Ordering::SeqCst) != current {
                 // Safe if the length of the buffer is larger than the size of a usize
                 assert!(buffer.len() >= mem::size_of::<usize>());
                 unsafe { *(buffer.as_mut_ptr() as *mut usize) = current; }
@@ -69,11 +95,16 @@ impl Scheme for IrqScheme {
     fn write(&self, file: usize, buffer: &[u8]) -> Result<usize> {
         if buffer.len() >= mem::size_of::<usize>() {
             assert!(buffer.len() >= mem::size_of::<usize>());
+
+            let handles_guard = HANDLES.read();
+            let handle = &handles_guard.as_ref().unwrap().get(&file).ok_or(Error::new(EBADF))?;
+
             let ack = unsafe { *(buffer.as_ptr() as *const usize) };
-            let current = COUNTS.lock()[file];
+            let current = COUNTS.lock()[handle.irq as usize];
+
             if ack == current {
-                ACKS.lock()[file] = ack;
-                unsafe { acknowledge(file); }
+                handle.ack.store(ack, Ordering::SeqCst);
+                unsafe { acknowledge(handle.irq as usize); }
                 Ok(mem::size_of::<usize>())
             } else {
                 Ok(0)
-- 
GitLab