From 491f9d0d4a9367da00422a84a570e3c12a7d5ddf Mon Sep 17 00:00:00 2001
From: WangRunji <wangrunji0408@163.com>
Date: Tue, 17 Apr 2018 21:34:36 +0800
Subject: [PATCH] PIT working

---
 src/arch/x86_64/driver/mod.rs    |  2 ++
 src/arch/x86_64/driver/pit.rs    | 43 ++++++++++++++++++++++++++++++++
 src/arch/x86_64/interrupt/irq.rs | 10 +++++++-
 3 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 src/arch/x86_64/driver/pit.rs

diff --git a/src/arch/x86_64/driver/mod.rs b/src/arch/x86_64/driver/mod.rs
index f36812d..5535ab8 100644
--- a/src/arch/x86_64/driver/mod.rs
+++ b/src/arch/x86_64/driver/mod.rs
@@ -5,6 +5,7 @@ pub mod mp;
 pub mod serial;
 pub mod pic;
 pub mod keyboard;
+pub mod pit;
 
 pub fn init<F>(mut page_map: F)
     where F: FnMut(usize) {
@@ -31,6 +32,7 @@ pub fn init<F>(mut page_map: F)
     } else {
         pic::init();
     }
+    pit::init();
     serial::init();
     keyboard::init();
 }
\ No newline at end of file
diff --git a/src/arch/x86_64/driver/pit.rs b/src/arch/x86_64/driver/pit.rs
new file mode 100644
index 0000000..c151095
--- /dev/null
+++ b/src/arch/x86_64/driver/pit.rs
@@ -0,0 +1,43 @@
+use syscall::io::{Io, Pio};
+
+static mut PIT: Pit = Pit::new(0x40);
+
+pub fn init() {
+    assert_has_not_been_called!("pit::init must be called only once");
+    unsafe{ PIT.init(100); }
+    debug!("pit: init end");
+}
+
+struct Pit {
+    chan0: Pio<u8>,
+    chan1: Pio<u8>,
+    chan2: Pio<u8>,
+    command: Pio<u8>,
+}
+
+impl Pit {
+    const fn new(port: u16) -> Self {
+        Pit {
+            chan0: Pio::new(port),
+            chan1: Pio::new(port+1),
+            chan2: Pio::new(port+2),
+            command: Pio::new(port+3),
+        }
+    }
+    pub fn init(&mut self, freq: u32) {
+        self.command.write(TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+        let div = Pit::divisor(freq);
+        self.chan0.write((div & 0xFF) as u8);
+        self.chan0.write((div >> 8) as u8);
+    }
+    fn divisor(freq: u32) -> u16 {
+        let div = (TIMER_FREQ + freq / 2) / freq;
+        assert!(div < 0x10000);
+        div as u16
+    }
+}
+
+const TIMER_FREQ    : u32 = 1193182;
+const TIMER_SEL0    : u8 = 0x00;                    // select counter 0
+const TIMER_RATEGEN : u8 = 0x04;                    // mode 2, rate generator
+const TIMER_16BIT   : u8 = 0x30;                    // r/w counter 16 bits, LSB first
\ No newline at end of file
diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs
index 0780344..087e3d1 100644
--- a/src/arch/x86_64/interrupt/irq.rs
+++ b/src/arch/x86_64/interrupt/irq.rs
@@ -55,9 +55,17 @@ pub extern "x86-interrupt" fn com2_handler(
     ack(IRQ_COM2);
 }
 
+use spin::Mutex;
+static TICK: Mutex<usize> = Mutex::new(0);
+
 pub extern "x86-interrupt" fn timer_handler(
     stack_frame: &mut ExceptionStackFrame)
 {
-//    println!("\nInterupt: Timer \n{:#?}", stack_frame);
+    let mut tick = TICK.lock();
+    *tick += 1;
+    let tick = *tick;
+    if tick % 100 == 0 {
+        println!("\nInterupt: Timer\ntick = {}", tick);
+    }
     ack(IRQ_TIMER);    
 }
\ No newline at end of file