diff --git a/arch/x86_64/Cargo.toml b/arch/x86_64/Cargo.toml
index 65a644a3d0f1b1944857c183d29d7a7623102e47..567b412ce781d6b0ce379af82657c726bd703d60 100644
--- a/arch/x86_64/Cargo.toml
+++ b/arch/x86_64/Cargo.toml
@@ -4,7 +4,8 @@ version = "0.1.0"
 
 [dependencies]
 bitflags = "*"
-hole_list_allocator = { path = "../../alloc/hole_list_allocator"}
+hole_list_allocator = { path = "../../alloc/hole_list_allocator" }
+io = { path = "../../drivers/io" }
 ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" }
 spin = "*"
 
diff --git a/arch/x86_64/src/device/mod.rs b/arch/x86_64/src/device/mod.rs
index 02fe70dd11e69d00b70628e0b56fd8c866a2aec9..c8032646e51d355f792a25b3b5f4da2b6f1ccc63 100644
--- a/arch/x86_64/src/device/mod.rs
+++ b/arch/x86_64/src/device/mod.rs
@@ -1,11 +1,9 @@
 use paging::ActivePageTable;
 
 pub mod display;
-pub mod ps2;
 pub mod serial;
 
 pub unsafe fn init(active_table: &mut ActivePageTable){
     serial::init();
     display::init(active_table);
-    ps2::init();
 }
diff --git a/arch/x86_64/src/io/mod.rs b/arch/x86_64/src/io/mod.rs
deleted file mode 100644
index 86a1c34f42c2c4e612000fbbd6adfdc830887efb..0000000000000000000000000000000000000000
--- a/arch/x86_64/src/io/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-/// I/O functions
-
-pub use self::io::*;
-pub use self::mmio::*;
-pub use self::pio::*;
-
-mod io;
-mod mmio;
-mod pio;
diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs
index 21d4ceb353343f9b9bd3dd3b95fb2f35d9860d4b..c7e5f877df0f841b6aa9b656c7cb81cd10299a89 100644
--- a/arch/x86_64/src/lib.rs
+++ b/arch/x86_64/src/lib.rs
@@ -15,6 +15,7 @@ extern crate hole_list_allocator as allocator;
 
 #[macro_use]
 extern crate bitflags;
+extern crate io;
 extern crate ransid;
 extern crate spin;
 pub extern crate x86;
@@ -198,9 +199,6 @@ pub mod gdt;
 /// Interrupt descriptor table
 pub mod idt;
 
-/// IO Handling
-pub mod io;
-
 /// Interrupt instructions
 pub mod interrupt;
 
diff --git a/drivers/io/Cargo.toml b/drivers/io/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b0ee40b297428b67e55088d62657e3efc2e6123e
--- /dev/null
+++ b/drivers/io/Cargo.toml
@@ -0,0 +1,3 @@
+[package]
+name = "io"
+version = "0.1.0"
diff --git a/arch/x86_64/src/io/io.rs b/drivers/io/src/io.rs
similarity index 100%
rename from arch/x86_64/src/io/io.rs
rename to drivers/io/src/io.rs
diff --git a/drivers/io/src/lib.rs b/drivers/io/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..22f8eb72c0ba52ae3bd36795116a98f1fc1cee31
--- /dev/null
+++ b/drivers/io/src/lib.rs
@@ -0,0 +1,14 @@
+//! I/O functions
+
+#![feature(asm)]
+#![feature(const_fn)]
+#![feature(core_intrinsics)]
+#![no_std]
+
+pub use self::io::*;
+pub use self::mmio::*;
+pub use self::pio::*;
+
+mod io;
+mod mmio;
+mod pio;
diff --git a/arch/x86_64/src/io/mmio.rs b/drivers/io/src/mmio.rs
similarity index 100%
rename from arch/x86_64/src/io/mmio.rs
rename to drivers/io/src/mmio.rs
diff --git a/arch/x86_64/src/io/pio.rs b/drivers/io/src/pio.rs
similarity index 53%
rename from arch/x86_64/src/io/pio.rs
rename to drivers/io/src/pio.rs
index 562c1c1e13e3000d9f5a9adb648f36b67d49b5c1..91ae310b624a06029cd872905ea2f97abdc42e9a 100644
--- a/arch/x86_64/src/io/pio.rs
+++ b/drivers/io/src/pio.rs
@@ -1,5 +1,4 @@
 use core::marker::PhantomData;
-use x86::io;
 
 use super::io::Io;
 
@@ -27,13 +26,19 @@ impl Io for Pio<u8> {
     /// Read
     #[inline(always)]
     fn read(&self) -> u8 {
-        unsafe { io::inb(self.port) }
+        let value: u8;
+        unsafe {
+            asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
+        }
+        value
     }
 
     /// Write
     #[inline(always)]
     fn write(&mut self, value: u8) {
-        unsafe { io::outb(self.port, value) }
+        unsafe {
+            asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
+        }
     }
 }
 
@@ -44,13 +49,19 @@ impl Io for Pio<u16> {
     /// Read
     #[inline(always)]
     fn read(&self) -> u16 {
-        unsafe { io::inw(self.port) }
+        let value: u16;
+        unsafe {
+            asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
+        }
+        value
     }
 
     /// Write
     #[inline(always)]
     fn write(&mut self, value: u16) {
-        unsafe { io::outw(self.port, value) }
+        unsafe {
+            asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
+        }
     }
 }
 
@@ -61,12 +72,18 @@ impl Io for Pio<u32> {
     /// Read
     #[inline(always)]
     fn read(&self) -> u32 {
-        unsafe { io::inl(self.port) }
+        let value: u32;
+        unsafe {
+            asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
+        }
+        value
     }
 
     /// Write
     #[inline(always)]
     fn write(&mut self, value: u32) {
-        unsafe { io::outl(self.port, value) }
+        unsafe {
+            asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
+        }
     }
 }
diff --git a/drivers/ps2d/Cargo.toml b/drivers/ps2d/Cargo.toml
index f49dee131349c9f1e94ec6fc3bf6a4c0eb253b61..665e3c19c89c0898c0fd97330cf3843b86519453 100644
--- a/drivers/ps2d/Cargo.toml
+++ b/drivers/ps2d/Cargo.toml
@@ -2,5 +2,8 @@
 name = "ps2d"
 version = "0.1.0"
 
-[dependencies.syscall]
-path = "../../syscall/"
+[dependencies]
+bitflags = "*"
+io = { path = "../io/" }
+spin = "*"
+syscall = { path = "../../syscall/" }
diff --git a/arch/x86_64/src/device/ps2.rs b/drivers/ps2d/src/controller.rs
similarity index 66%
rename from arch/x86_64/src/device/ps2.rs
rename to drivers/ps2d/src/controller.rs
index 8b29f0310c2d5b2aa7bda404d295381a745f7632..8355dba7bc8e59de22c22298b2f8e56e6986c0e8 100644
--- a/arch/x86_64/src/device/ps2.rs
+++ b/drivers/ps2d/src/controller.rs
@@ -1,5 +1,3 @@
-use core::cmp;
-
 use io::{Io, Pio, ReadOnly, WriteOnly};
 
 pub unsafe fn init() {
@@ -79,86 +77,6 @@ enum MouseCommandData {
     SetSampleRate = 0xF3,
 }
 
-bitflags! {
-    flags MousePacketFlags: u8 {
-        const LEFT_BUTTON = 1,
-        const RIGHT_BUTTON = 1 << 1,
-        const MIDDLE_BUTTON = 1 << 2,
-        const ALWAYS_ON = 1 << 3,
-        const X_SIGN = 1 << 4,
-        const Y_SIGN = 1 << 5,
-        const X_OVERFLOW = 1 << 6,
-        const Y_OVERFLOW = 1 << 7
-    }
-}
-
-pub struct Ps2Mouse {
-    data: ReadOnly<Pio<u8>>,
-    mouse: [u8; 4],
-    mouse_i: usize,
-    mouse_extra: bool,
-    mouse_x: usize,
-    mouse_y: usize
-}
-
-impl Ps2Mouse {
-    fn new(mouse_extra: bool) -> Self {
-        Ps2Mouse {
-            data: ReadOnly::new(Pio::new(0x60)),
-            mouse: [0; 4],
-            mouse_i: 0,
-            mouse_extra: mouse_extra,
-            mouse_x: 0,
-            mouse_y: 0
-        }
-    }
-
-    pub fn on_irq(&mut self) {
-        self.mouse[self.mouse_i] = self.data.read();
-        self.mouse_i += 1;
-
-        let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]);
-        if ! flags.contains(ALWAYS_ON) {
-            println!("MOUSE MISALIGN {:X}", self.mouse[0]);
-
-            self.mouse = [0; 4];
-            self.mouse_i = 0;
-        } else if self.mouse_i >= self.mouse.len() || (!self.mouse_extra && self.mouse_i >= 3) {
-            if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
-                let mut dx = self.mouse[1] as isize;
-                if flags.contains(X_SIGN) {
-                    dx -= 0x100;
-                }
-
-                let mut dy = self.mouse[2] as isize;
-                if flags.contains(Y_SIGN) {
-                    dy -= 0x100;
-                }
-
-                let _extra = if self.mouse_extra {
-                    self.mouse[3]
-                } else {
-                    0
-                };
-
-                //print!("MOUSE {:?}, {}, {}, {}\n", flags, dx, dy, extra);
-
-                if let Some(ref mut display) = *super::display::DISPLAY.lock() {
-                    self.mouse_x = cmp::max(0, cmp::min(display.width as isize - 1, self.mouse_x as isize + dx)) as usize;
-                    self.mouse_y = cmp::max(0, cmp::min(display.height as isize - 1, self.mouse_y as isize - dy)) as usize;
-                    let offset = self.mouse_y * display.width + self.mouse_x;
-                    display.onscreen[offset as usize] = 0xFF0000;
-                }
-            } else {
-                println!("MOUSE OVERFLOW {:X} {:X} {:X} {:X}", self.mouse[0], self.mouse[1], self.mouse[2], self.mouse[3]);
-            }
-
-            self.mouse = [0; 4];
-            self.mouse_i = 0;
-        }
-    }
-}
-
 pub struct Ps2 {
     data: Pio<u8>,
     status: ReadOnly<Pio<u8>>,
@@ -166,7 +84,7 @@ pub struct Ps2 {
 }
 
 impl Ps2 {
-    const fn new() -> Self {
+    pub fn new() -> Self {
         Ps2 {
             data: Pio::new(0x60),
             status: ReadOnly::new(Pio::new(0x64)),
@@ -244,7 +162,7 @@ impl Ps2 {
         self.read()
     }
 
-    fn init(&mut self) {
+    pub fn init(&mut self) -> bool {
         // Disable devices
         self.command(Command::DisableFirst);
         self.command(Command::DisableSecond);
@@ -294,18 +212,6 @@ impl Ps2 {
         let mouse_id = self.read();
         let mouse_extra = mouse_id == 3;
 
-        // Enable extra buttons, TODO
-        /*
-        if self.mouse_extra {
-            print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
-            print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
-            print!("SAMPLE 80 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 80));
-            print!("GET ID {:X}\n", self.mouse_command(MouseCommand::GetDeviceId));
-            let mouse_id = self.read();
-            print!("MOUSE ID: {:X} == 0x04\n", mouse_id);
-        }
-        */
-
         // Set sample rate to maximum
         assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);
 
@@ -325,5 +231,7 @@ impl Ps2 {
         }
 
         self.flush_read();
+
+        mouse_extra
     }
 }
diff --git a/drivers/ps2d/src/keyboard.rs b/drivers/ps2d/src/keyboard.rs
new file mode 100644
index 0000000000000000000000000000000000000000..109819a7256343587c0e7df0ab21c6c308098cdb
--- /dev/null
+++ b/drivers/ps2d/src/keyboard.rs
@@ -0,0 +1,34 @@
+use std::fs::File;
+use std::io::{Read, Write};
+use std::mem;
+use std::thread;
+
+use keymap;
+
+pub fn keyboard() {
+    let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1");
+
+    loop {
+        let mut irqs = [0; 8];
+        if file.read(&mut irqs).expect("ps2d: failed to read irq:1") >= mem::size_of::<usize>() {
+            let data: u8;
+            unsafe {
+                asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile");
+            }
+
+            let (scancode, pressed) = if data >= 0x80 {
+                (data - 0x80, false)
+            } else {
+                (data, true)
+            };
+
+            if pressed {
+                print!("{}", keymap::get_char(scancode));
+            }
+
+            file.write(&irqs).expect("ps2d: failed to write irq:1");
+        } else {
+            thread::yield_now();
+        }
+    }
+}
diff --git a/drivers/ps2d/src/main.rs b/drivers/ps2d/src/main.rs
index f5818a6b7ae9e84ae5e637d6061c9a60884e7340..4a3888eab85c5b1c96d952598079a9a4b29c19ad 100644
--- a/drivers/ps2d/src/main.rs
+++ b/drivers/ps2d/src/main.rs
@@ -1,77 +1,42 @@
 #![feature(asm)]
 
+#[macro_use]
+extern crate bitflags;
+extern crate io;
 extern crate syscall;
 
-use std::fs::File;
-use std::io::{Read, Write};
-use std::mem;
 use std::thread;
 
 use syscall::iopl;
 
+mod controller;
+mod keyboard;
 mod keymap;
+mod mouse;
 
-fn keyboard() {
-    let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1");
-
-    loop {
-        let mut irqs = [0; 8];
-        if file.read(&mut irqs).expect("pskbd: failed to read irq:1") >= mem::size_of::<usize>() {
-            let data: u8;
-            unsafe {
-                asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile");
-            }
-
-            let (scancode, pressed) = if data >= 0x80 {
-                (data - 0x80, false)
-            } else {
-                (data, true)
-            };
-            println!("pskbd: IRQ {}: {:X}: {:X}: {}: {}", unsafe { *(irqs.as_ptr() as *const usize) }, data, scancode, keymap::get_char(scancode), pressed);
-
-            file.write(&irqs).expect("pskbd: failed to write irq:1");
-        } else {
-            thread::yield_now();
-        }
+fn main() {
+    unsafe {
+        iopl(3).expect("ps2d: failed to get I/O permission");
+        asm!("cli" :::: "intel", "volatile");
     }
-}
-
-fn mouse() {
-    let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12");
 
-    loop {
-        let mut irqs = [0; 8];
-        if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::<usize>() {
-            let data: u8;
-            unsafe {
-                asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile");
-            }
+    let extra_packet = controller::Ps2::new().init();
 
-            println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data);
-
-            file.write(&irqs).expect("psmsd: failed to write irq:12");
-        } else {
-            thread::yield_now();
-        }
-    }
-}
-
-fn main() {
     thread::spawn(|| {
         unsafe {
-            iopl(3).expect("pskbd: failed to get I/O permission");
+            iopl(3).expect("ps2d: failed to get I/O permission");
             asm!("cli" :::: "intel", "volatile");
         }
 
-        keyboard();
+        keyboard::keyboard();
     });
 
-    thread::spawn(|| {
+    thread::spawn(move || {
         unsafe {
-            iopl(3).expect("psmsd: failed to get I/O permission");
+            iopl(3).expect("ps2d: failed to get I/O permission");
             asm!("cli" :::: "intel", "volatile");
         }
 
-        mouse();
+        mouse::mouse(extra_packet);
     });
 }
diff --git a/drivers/ps2d/src/mouse.rs b/drivers/ps2d/src/mouse.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f273de9670ce2612284141ca0d9f32638c9188cd
--- /dev/null
+++ b/drivers/ps2d/src/mouse.rs
@@ -0,0 +1,73 @@
+use std::fs::File;
+use std::io::{Read, Write};
+use std::mem;
+use std::thread;
+
+bitflags! {
+    flags MousePacketFlags: u8 {
+        const LEFT_BUTTON = 1,
+        const RIGHT_BUTTON = 1 << 1,
+        const MIDDLE_BUTTON = 1 << 2,
+        const ALWAYS_ON = 1 << 3,
+        const X_SIGN = 1 << 4,
+        const Y_SIGN = 1 << 5,
+        const X_OVERFLOW = 1 << 6,
+        const Y_OVERFLOW = 1 << 7
+    }
+}
+
+pub fn mouse(extra_packet: bool) {
+    let mut file = File::open("irq:12").expect("ps2d: failed to open irq:12");
+
+    let mut packets = [0; 4];
+    let mut packet_i = 0;
+    loop {
+        let mut irqs = [0; 8];
+        if file.read(&mut irqs).expect("ps2d: failed to read irq:12") >= mem::size_of::<usize>() {
+            let data: u8;
+            unsafe {
+                asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile");
+            }
+
+            packets[packet_i] = data;
+            packet_i += 1;
+
+            let flags = MousePacketFlags::from_bits_truncate(packets[0]);
+            if ! flags.contains(ALWAYS_ON) {
+                println!("MOUSE MISALIGN {:X}", packets[0]);
+
+                packets = [0; 4];
+                packet_i = 0;
+            } else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) {
+                if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
+                    let mut dx = packets[1] as isize;
+                    if flags.contains(X_SIGN) {
+                        dx -= 0x100;
+                    }
+
+                    let mut dy = packets[2] as isize;
+                    if flags.contains(Y_SIGN) {
+                        dy -= 0x100;
+                    }
+
+                    let extra = if extra_packet {
+                        packets[3]
+                    } else {
+                        0
+                    };
+
+                    print!("ps2d: IRQ {:?}, {}, {}, {}\n", flags, dx, dy, extra);
+                } else {
+                    println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]);
+                }
+
+                packets = [0; 4];
+                packet_i = 0;
+            }
+
+            file.write(&irqs).expect("ps2d: failed to write irq:12");
+        } else {
+            thread::yield_now();
+        }
+    }
+}