PS2 Library

Dependents:   Pong Brickbreaker

Files at this revision

API Documentation at this revision

Comitter:
wjohnsto
Date:
Sun Feb 27 23:34:31 2011 +0000
Commit message:

Changed in this revision

PS2.h Show annotated file Show diff for this revision Revisions of this file
PS2KB.cpp Show annotated file Show diff for this revision Revisions of this file
PS2KB.h Show annotated file Show diff for this revision Revisions of this file
PS2KB_INIT.cpp Show annotated file Show diff for this revision Revisions of this file
PS2KB_INIT.h Show annotated file Show diff for this revision Revisions of this file
PS2Keyboard.cpp Show annotated file Show diff for this revision Revisions of this file
PS2Keyboard.h Show annotated file Show diff for this revision Revisions of this file
PS2MS.cpp Show annotated file Show diff for this revision Revisions of this file
PS2MS.h Show annotated file Show diff for this revision Revisions of this file
PS2MS_INIT.cpp Show annotated file Show diff for this revision Revisions of this file
PS2MS_INIT.h Show annotated file Show diff for this revision Revisions of this file
PS2Mouse.cpp Show annotated file Show diff for this revision Revisions of this file
PS2Mouse.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2.h	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,46 @@
+/**
+ * PS/2 interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+
+#ifndef _PS2_H_
+#define _PS2_H_
+
+#include "mbed.h"
+
+/**
+ * PS/2 interface control class.
+ */
+class PS2 {
+public:
+    /**
+     * Create.
+     *
+     * @param clk_pin Clock pin.
+     * @param dat_pin Data pin.
+     */
+    PS2(PinName clk_pin, PinName dat_pin);
+
+    /**
+     * Destory.
+     */
+    virtual ~PS2();
+
+    /**
+     * Get a data from a PS/2 device.
+     *
+     * @return A data from a PS/2 device.
+     */
+    virtual int getc(void) = 0;
+
+    /**
+     * Set timeout.
+     *
+     * @param ms Timeout ms.
+     */
+    virtual void setTimeout(int ms) = 0;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2KB.cpp	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,140 @@
+/**
+ * PS/2 keyboard interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+
+#include "PS2KB.h"
+
+/**
+ * Create.
+ *
+ * @param clk_pin Clock pin.
+ * @param dat_pin Data pin.
+ */
+PS2KB::PS2KB(PinName clk_pin, PinName dat_pin)
+        : clk(clk_pin), dat(dat_pin) {
+    init_work();
+    clk.fall(this, &PS2KB::func_fall);
+    timeout = 1;
+}
+
+/**
+ * Destory.
+ */
+PS2KB::~PS2KB() {
+    wdt.detach();
+}
+
+/**
+ * Get a data from a PS/2 device.
+ *
+ * @return A data from a PS/2 device.
+ */
+int PS2KB::getc() {
+    tot.reset();
+    tot.start();
+    while (work.cStart == work.cEnd) {
+        wait_ms(1);
+        if ((timeout > 0) && (tot.read_ms() > timeout)) {
+            // printf("Timeout occured.\n");
+            return EOF;
+        }
+    }
+    tot.stop();
+
+    char c = work.buffer[work.cStart++];
+    work.cStart =  work.cStart % RINGBUFSIZ;
+
+    return c;
+}
+
+/**
+ * Set timeout.
+ *
+ * @param ms Timeout ms.
+ */
+void PS2KB::setTimeout(int ms) {
+    timeout = ms;
+}
+
+void PS2KB::func_timeout(void) {
+    work.bitcnt = 0;
+}
+
+void PS2KB::func_fall(void) {
+    int oddpar = 0;
+    /*
+     */
+    switch (work.bitcnt) {
+        case 0:
+            /*
+             * Start bit.
+             */
+            if (dat.read() != 0) {
+                // printf("Illegal start bit condition.\n");
+            }
+            work.bitcnt++;
+            break;
+        case 9:
+            /*
+             * Parity bit.
+             */
+            for (int i = 0; i < 8; i++) {
+                if ((work.buffer[work.cEnd] & (1 << i)) != 0) {
+                    oddpar++;
+                }
+            }
+            if (dat.read() == 1) {
+                oddpar++;
+            }
+            if ((oddpar % 2) != 1) {
+                // printf("Data parity error.\n");
+            }
+            work.bitcnt++;
+            break;
+        case 10:
+            /*
+             * Stop bit.
+             */
+            if (dat.read() != 1) {
+                // printf("Illegal stop bit condition.\n");
+            }
+            if (work.cStart != ((work.cEnd + 1) % RINGBUFSIZ)) {
+                work.cEnd++;
+                work.cEnd = work.cEnd % RINGBUFSIZ;
+                work.bitcnt = 0;
+            } else {
+                // printf("Buffer overrun.\n");
+            }
+            break;
+        default:
+            if ((1 <= work.bitcnt) && (work.bitcnt <= 8)) {
+                /*
+                 * data bit.
+                 */
+                if (dat.read() == 1) {
+                    work.buffer[work.cEnd] |= (1 << (work.bitcnt - 1));
+                } else {
+                    work.buffer[work.cEnd] &= ~(1 << (work.bitcnt - 1));
+                }
+                work.bitcnt++;
+            } else {
+                /*
+                 * Illegal internal state.
+                 */
+                // printf("Illegal internal state found.\n");
+                init_work();
+            }
+            break;
+    }
+    wdt.detach();
+    wdt.attach_us(this, &PS2KB::func_timeout, 250);
+}
+
+void PS2KB::init_work(void) {
+    work.bitcnt = 0;
+    work.cStart = 0;
+    work.cEnd = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2KB.h	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,67 @@
+/**
+ * PS/2 keyboard interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+
+#ifndef _PS2KB_H_
+#define _PS2KB_H_
+
+#include "mbed.h"
+
+/**
+ * PS/2 keyboard interface control class.
+ */
+class PS2KB {
+public:
+    /**
+     * Create.
+     *
+     * @param clk_pin Clock pin.
+     * @param dat_pin Data pin.
+     */
+    PS2KB(PinName clk_pin, PinName dat_pin);
+
+    /**
+     * Destory.
+     */
+    virtual ~PS2KB();
+
+    /**
+     * Get a data from a PS/2 device.
+     *
+     * @return A data from a PS/2 device.
+     */
+    virtual int getc(void);
+
+    /**
+     * Set timeout.
+     *
+     * @param ms Timeout ms.
+     */
+    virtual void setTimeout(int ms);
+
+private:
+    static const int RINGBUFSIZ = 256;
+    InterruptIn clk;    /**< Interrupt input for CLK. */
+    DigitalIn dat;      /**< Digital input for DAT. */
+    Timeout wdt;    /**< Watch dog timer. */
+    Timer tot;      /**< Timeout timer. */
+    int timeout;    /**< Timeout[ms] for getc(). */
+
+    typedef struct {
+        int bitcnt;
+        int cStart;
+        int cEnd;
+        uint8_t buffer[RINGBUFSIZ];
+    } work_t;
+    work_t work;
+
+    void func_timeout(void);
+    void func_fall(void);
+
+    void init_work(void);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2KB_INIT.cpp	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,240 @@
+/**
+ * PS/2 keyboard interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#include "PS2KB_INIT.h"
+
+/**
+ * Create.
+ */
+PS2KB_INIT::PS2KB_INIT(PinName clk_pin, PinName dat_pin)
+        : clk(clk_pin), dat(dat_pin) {
+    clk.input();
+    dat.input();
+    clk.write(1);
+    dat.write(1);
+    
+    /*
+     * 0xFF: Reset.
+     * 0xED: Set/Reset status indicators.
+     * 0xF2: Read ID.
+     * 0xF3: Set typematic rate/delay.
+     * 0xF4: Enable.
+     */
+    char txdat[12] = "\xFF\xED\x07\xF2\xED\x00\xF3\x20\xF3\x00\xF4";
+    const int n = sizeof(txdat);
+    int txerrcnt = 0;
+    int rxerrcnt = 0;
+    for (int i = 0; i < n; i++) {
+        if (send(txdat[i]) != 0) {
+            txerrcnt++;
+        }
+        if (recv() < 0) {
+            rxerrcnt++;
+        }
+        if (txdat[i] == 0xF2) {
+            if (recv() < 0) {
+                rxerrcnt++;
+            }
+        }
+    }
+    
+    if (txerrcnt > 0) {
+        // printf("TX %d errors occured.\n", txerrcnt);
+    }
+    if (rxerrcnt > 0) {
+        // printf("RX %d errors occured.\n", rxerrcnt);
+    }
+}
+
+/**
+ * Destroy.
+ */
+PS2KB_INIT::~PS2KB_INIT() {
+}
+
+/**
+ * Send a byte data.
+ *
+ * @param c a character.
+ *
+ * @return Negative value is a error number.
+ */
+int PS2KB_INIT::send(uint8_t c) {
+    clk.output();
+    dat.output();
+
+    clk.write(0);
+    wait_us(200);
+
+    dat.write(0);
+    wait_us(10);
+    clk.write(1);
+    wait_us(10);
+
+    clk.input();
+    int parcnt = 0;
+    for (int i = 0; i < 10; i++) {
+        if (!waitClockDownEdge()) {
+            return -1;
+        }
+        if ((0 <= i) && (i <= 7)) {
+            /*
+             * Data bit.
+             */
+            if ((c & (1 << i)) == 0) {
+                dat.write(0);
+            } else {
+                dat.write(1);
+                parcnt++;
+            }
+        }
+        if (i == 8) {
+            /*
+             * Parity bit.
+             */
+            if ((parcnt % 2) == 0) {
+                dat.write(1);
+            } else {
+                dat.write(0);
+            }
+        }
+        if (i == 9) {
+            /*
+             * Stop bit.
+             */
+            dat.write(1);
+        }
+    }
+    dat.input();
+
+    /*
+     * Check a ACK.
+     */
+    if (!waitClockDownEdge()) {
+        return -2;
+    }
+    if (dat.read() != 0) {
+        return -3;
+    }
+
+    if (!waitClockUpLevel()) {
+        return -4;
+    }
+
+    return 0;
+}
+
+/**
+ * Receive a byte data.
+ *
+ * @return return a data. Negative value is a error number.
+ */
+int PS2KB_INIT::recv(void) {
+    uint8_t c = 0;
+    clk.input();
+    dat.input();
+    int parcnt = 0;
+    for (int i = 0; i < 11; i++) {
+        if (!waitClockDownEdge()) {
+            return -1;
+        }
+        if (i == 0) {
+            /*
+             * Start bit.
+             */
+            if (dat.read() != 0) {
+                return -2;
+            }
+        }
+        if ((1 <= i) && (i <= 8)) {
+            /*
+             * Data bit.
+             */
+            if (dat.read() == 0) {
+                c &= ~(1 << (i - 1));
+            } else {
+                c |= (1 << (i - 1));
+                parcnt++;
+            }
+        }
+        if (i == 9) {
+            /*
+             * Parity bit.
+             */
+            if (dat.read() == 0) {
+                if ((parcnt % 2) != 1) {
+                    return -3;
+                }
+            } else {
+                if ((parcnt % 2) != 0) {
+                    return -4;
+                }
+            }
+        }
+        if (i == 10) {
+            /*
+             * Stop bit.
+             */
+            if (dat.read() != 1) {
+                return -5;
+            }
+        }
+    }
+    return (int)c;
+}
+
+/**
+ * Wait a clock down edge.
+ *
+ * @return true if wait done.
+ */
+bool PS2KB_INIT::waitClockDownEdge(void) {
+    int cnt;
+    /*
+     * Wait until clock is low.
+     */
+    cnt = 0;
+    while (clk.read() == 0) {
+        cnt++;
+        if (MAX_RETRY < cnt) {
+            return false;
+        }
+        wait_us(1);
+    }
+    /*
+     * Wait until clock is high.
+     */
+    cnt = 0;
+    while (clk.read() == 1) {
+        cnt++;
+        if (MAX_RETRY < cnt) {
+            return false;
+        }
+        wait_us(1);
+    }
+    return true;
+}
+
+/**
+ * Wait a clock up level.
+ *
+ * @return true if wait done.
+ */
+bool PS2KB_INIT::waitClockUpLevel(void) {
+    int cnt;
+    /*
+     * Wait until clock is low.
+     */
+    cnt = 0;
+    while (clk.read() == 0) {
+        cnt++;
+        if (MAX_RETRY < cnt) {
+            return false;
+        }
+        wait_us(1);
+    }
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2KB_INIT.h	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,64 @@
+/**
+ * PS/2 keyboard interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#ifndef _PS2KB_INIT_H_
+#define _PS2KB_INIT_H_
+
+#include "mbed.h"
+
+/**
+ * PS2 keyboard initializer.
+ */
+class PS2KB_INIT {
+public:
+
+    /**
+     * Create.
+     */
+    PS2KB_INIT(PinName clk_pin, PinName dat_pin);
+
+    /**
+     * Destroy.
+     */
+    ~PS2KB_INIT();
+private:
+    DigitalInOut clk;
+    DigitalInOut dat;
+
+    static const int MAX_RETRY = 1000000;
+
+    /**
+     * Send a byte data.
+     *
+     * @param c a character.
+     *
+     * @return Negative value is a error number.
+     */
+    int send(uint8_t c);
+
+    /**
+     * Receive a byte data.
+     *
+     * @return return a data. Negative value is a error number.
+     */
+    int recv(void);
+
+    /**
+     * Wait a clock down edge.
+     *
+     * @return true if wait done.
+     */
+    bool waitClockDownEdge(void);
+
+    /**
+     * Wait a clock up level.
+     *
+     * @return true if wait done.
+     */
+    bool waitClockUpLevel(void);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2Keyboard.cpp	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,117 @@
+/**
+ * PS/2 keyboard interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#include "PS2Keyboard.h"
+
+PS2Keyboard::PS2Keyboard(PinName clk_pin, PinName dat_pin)
+        : ps2kb_init(clk_pin, dat_pin), ps2kb(clk_pin, dat_pin) {
+}
+
+PS2Keyboard::~PS2Keyboard() {
+}
+
+bool PS2Keyboard::processing(keyboard_event_t *p) {
+    bool emit = false;
+    const int c = ps2kb.getc();
+    if (0 <= c) {
+        scancode[count++] = c;
+        switch (count) {
+            case 1:
+                if ((scancode[0] != 0xE0)
+                        && (scancode[0] != 0xE1)
+                        && (scancode[0] != 0xF0)) {
+                    p->type = KeyMake;
+                    p->length = count;
+                    memcpy(p->scancode, scancode, sizeof(p->scancode));
+                    emit = true;
+                    count = 0;
+                }
+                break;
+            case 2:
+                if (scancode[0] == 0xF0) {
+                    p->type = KeyBreak;
+                    p->length = count;
+                    memcpy(p->scancode, scancode, sizeof(p->scancode));
+                    emit = true;
+                    count = 0;
+                }
+                if ((scancode[0] == 0xE0)
+                        && (scancode[1] != 0xF0)
+                        && (scancode[1] != 0x12)) {
+                    p->type = KeyMake;
+                    p->length = count;
+                    memcpy(p->scancode, scancode, sizeof(p->scancode));
+                    emit = true;
+                    count = 0;
+                }
+                break;
+            case 3:
+                if ((scancode[0] == 0xE0)
+                        && (scancode[1] == 0xF0)
+                        && (scancode[2] != 0x7C)) {
+                    p->type = KeyBreak;
+                    p->length = count;
+                    memcpy(p->scancode, scancode, sizeof(p->scancode));
+                    emit = true;
+                    count = 0;
+                }
+                break;
+            case 4:
+                if ((scancode[0] == 0xE0)
+                        && (scancode[1] == 0x12)
+                        && (scancode[2] == 0xE0)
+                        && (scancode[3] == 0x7C)) {
+                    p->type = KeyMake;
+                    p->length = count;
+                    memcpy(p->scancode, scancode, sizeof(p->scancode));
+                    emit = true;
+                    count = 0;
+                }
+                break;
+            case 5:
+                // Do nothing.
+                break;
+            case 6:
+                if ((scancode[0] == 0xE0)
+                        && (scancode[1] == 0xF0)
+                        && (scancode[2] == 0x7C)
+                        && (scancode[3] == 0xE0)
+                        && (scancode[4] == 0xF0)
+                        && (scancode[5] == 0x12)) {
+                    p->type = KeyBreak;
+                    p->length = count;
+                    memcpy(p->scancode, scancode, sizeof(p->scancode));
+                    emit = true;
+                    count = 0;
+                }
+                break;
+            case 7:
+                // Do nothing.
+                break;
+            case 8:
+                if ((scancode[0] == 0xE1)
+                        && (scancode[1] == 0x14)
+                        && (scancode[2] == 0x77)
+                        && (scancode[3] == 0xE1)
+                        && (scancode[4] == 0xF0)
+                        && (scancode[5] == 0x14)
+                        && (scancode[6] == 0xF0)
+                        && (scancode[7] == 0x77)) {
+                    p->type = KeyMake;
+                    p->length = count;
+                    memcpy(p->scancode, scancode, sizeof(p->scancode));
+                    emit = true;
+                    count = 0;
+                }
+                break;
+            default:
+                count = 0;
+                break;
+        }
+        count = count % sizeof(scancode);
+    }
+    return emit;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2Keyboard.h	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,34 @@
+/**
+ * PS/2 keyboard interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#ifndef _PS2_KEYBOARD_H_
+#define _PS2_KEYBOARD_H_
+
+#include "PS2KB_INIT.h"
+#include "PS2KB.h"
+
+class PS2Keyboard {
+public:
+    PS2Keyboard(PinName clk_pin, PinName dat_pin);
+    ~PS2Keyboard();
+    typedef enum {
+        KeyMake,
+        KeyBreak
+    } Type;
+    typedef struct {
+        Type type;
+        int length;
+        char scancode[8];
+    } keyboard_event_t;
+    bool processing(keyboard_event_t *p);
+private:
+    PS2KB_INIT ps2kb_init;
+    PS2KB ps2kb;
+    int count;
+    char scancode[8];
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2MS.cpp	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,135 @@
+/**
+ * PS/2 mouse interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+
+#include "PS2MS.h"
+
+/**
+ * Create.
+ *
+ * @param clk_pin Clock pin.
+ * @param dat_pin Data pin.
+ */
+PS2MS::PS2MS(PinName clk_pin, PinName dat_pin)
+        : clk(clk_pin), dat(dat_pin) {
+    init_work();
+    clk.fall(this, &PS2MS::func_fall);
+    timeout = 1;
+}
+
+/**
+ * Destory.
+ */
+PS2MS::~PS2MS() {
+    wdt.detach();
+}
+
+int PS2MS::getc() {
+    tot.reset();
+    tot.start();
+    while (work.cStart == work.cEnd) {
+        wait_ms(1);
+        if ((timeout > 0) && (tot.read_ms() > timeout)) {
+            // printf("Timeout occured.\n");
+            return EOF;
+        }
+    }
+    tot.stop();
+
+    char c = work.buffer[work.cStart++];
+    work.cStart =  work.cStart % RINGBUFSIZ;
+
+    return c;
+}
+
+/**
+ * Set timeout.
+ *
+ * @param ms Timeout ms.
+ */
+void PS2MS::setTimeout(int ms) {
+    timeout = ms;
+}
+
+void PS2MS::func_timeout(void) {
+    work.bitcnt = 0;
+}
+
+void PS2MS::func_fall(void) {
+    int oddpar = 0;
+    /*
+     */
+    switch (work.bitcnt) {
+        case 0:
+            /*
+             * Start bit.
+             */
+            if (dat.read() != 0) {
+                // printf("Illegal start bit condition.\n");
+            }
+            work.bitcnt++;
+            break;
+        case 9:
+            /*
+             * Parity bit.
+             */
+            for (int i = 0; i < 8; i++) {
+                if ((work.buffer[work.cEnd] & (1 << i)) != 0) {
+                    oddpar++;
+                }
+            }
+            if (dat.read() == 1) {
+                oddpar++;
+            }
+            if ((oddpar % 2) != 1) {
+                // printf("Data parity error.\n");
+            }
+            work.bitcnt++;
+            break;
+        case 10:
+            /*
+             * Stop bit.
+             */
+            if (dat.read() != 1) {
+                // printf("Illegal stop bit condition.\n");
+            }
+            if (work.cStart != ((work.cEnd + 1) % RINGBUFSIZ)) {
+                work.cEnd++;
+                work.cEnd = work.cEnd % RINGBUFSIZ;
+                work.bitcnt = 0;
+            } else {
+                // printf("Buffer overrun.\n");
+            }
+            break;
+        default:
+            if ((1 <= work.bitcnt) && (work.bitcnt <= 8)) {
+                /*
+                 * data bit.
+                 */
+                if (dat.read() == 1) {
+                    work.buffer[work.cEnd] |= (1 << (work.bitcnt - 1));
+                } else {
+                    work.buffer[work.cEnd] &= ~(1 << (work.bitcnt - 1));
+                }
+                work.bitcnt++;
+            } else {
+                /*
+                 * Illegal internal state.
+                 */
+                // printf("Illegal internal state found.\n");
+                init_work();
+            }
+            break;
+    }
+    wdt.detach();
+    wdt.attach_us(this, &PS2MS::func_timeout, 250);
+}
+
+void PS2MS::init_work(void) {
+    work.bitcnt = 0;
+    work.cStart = 0;
+    work.cEnd = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2MS.h	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,67 @@
+/**
+ * PS/2 mouse interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+
+#ifndef _PS2MS_H_
+#define _PS2MS_H_
+
+#include "mbed.h"
+
+/**
+ * PS/2 mouse interface control class.
+ */
+class PS2MS {
+public:
+    /**
+     * Create.
+     *
+     * @param clk_pin Clock pin.
+     * @param dat_pin Data pin.
+     */
+    PS2MS(PinName clk_pin, PinName dat_pin);
+
+    /**
+     * Destory.
+     */
+    virtual ~PS2MS();
+
+    /**
+     * Get a data from a PS/2 device.
+     *
+     * @return A data from a PS/2 device.
+     */
+    virtual int getc(void);
+
+    /**
+     * Set timeout.
+     *
+     * @param ms Timeout ms.
+     */
+    virtual void setTimeout(int ms);
+
+private:
+    static const int RINGBUFSIZ = 1024;
+    InterruptIn clk;    /**< Interrupt input for CLK. */
+    DigitalIn dat;      /**< Digital input for DAT. */
+    Timeout wdt;    /**< Watch dog timer. */
+    Timer tot;      /**< Timeout timer. */
+    int timeout;    /**< Timeout[ms] for getc(). */
+
+    typedef struct {
+        int bitcnt;
+        int cStart;
+        int cEnd;
+        uint8_t buffer[RINGBUFSIZ];
+    } work_t;
+    work_t work;
+
+    void func_timeout(void);
+    void func_fall(void);
+
+    void init_work(void);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2MS_INIT.cpp	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,249 @@
+/**
+ * PS/2 mouse interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#include "PS2MS_INIT.h"
+
+/**
+ * Create.
+ */
+PS2MS_INIT::PS2MS_INIT(PinName clk_pin, PinName dat_pin)
+        : clk(clk_pin), dat(dat_pin) {
+    clk.input();
+    dat.input();
+    clk.write(1);
+    dat.write(1);
+
+    /*
+     * 0xFF: Reset command.
+     * 0xF3: Set sample rate.
+     * 0xF2: Read device type.
+     * 0xE8: Set resolution.
+     * 0xE6: Set scaling.
+     * 0xF4: Enable device.
+     */
+    char txdat[17] = "\xFF\xFF\xFF\xF3\xC8\xF3\x64\xF3\x50\xF2\xE8\x03\xE6\xF3\x28\xF4";
+    const int n = sizeof(txdat);
+    int txerrcnt = 0;
+    int rxerrcnt = 0;
+    for (int i = 0; i < n; i++) {
+        if (send(txdat[i]) != 0) {
+            txerrcnt++;
+        }
+        if (recv() < 0) {
+            rxerrcnt++;
+        }
+        if (txdat[i] == 0xF2) {
+            if (recv() < 0) {
+                rxerrcnt++;
+            }
+        }
+        if (txdat[i] == 0xFF) {
+            if (recv() < 0) {
+                rxerrcnt++;
+            }
+            if (recv() < 0) {
+                rxerrcnt++;
+            }
+        }
+    }
+    
+    if (txerrcnt > 0) {
+        // printf("TX %d errors occured.\n", txerrcnt);
+    }
+    if (rxerrcnt > 0) {
+        // printf("RX %d errors occured.\n", rxerrcnt);
+    }
+}
+
+/**
+ * Destroy.
+ */
+PS2MS_INIT::~PS2MS_INIT() {
+}
+
+/**
+ * Send a byte data.
+ *
+ * @param c a character.
+ *
+ * @return Negative value is a error number.
+ */
+int PS2MS_INIT::send(uint8_t c) {
+    clk.output();
+    dat.output();
+
+    clk.write(0);
+    wait_us(200);
+
+    dat.write(0);
+    wait_us(10);
+    clk.write(1);
+    wait_us(10);
+
+    clk.input();
+    int parcnt = 0;
+    for (int i = 0; i < 10; i++) {
+        if (!waitClockDownEdge()) {
+            return -1;
+        }
+        if ((0 <= i) && (i <= 7)) {
+            /*
+             * Data bit.
+             */
+            if ((c & (1 << i)) == 0) {
+                dat.write(0);
+            } else {
+                dat.write(1);
+                parcnt++;
+            }
+        }
+        if (i == 8) {
+            /*
+             * Parity bit.
+             */
+            if ((parcnt % 2) == 0) {
+                dat.write(1);
+            } else {
+                dat.write(0);
+            }
+        }
+        if (i == 9) {
+            /*
+             * Stop bit.
+             */
+            dat.write(1);
+        }
+    }
+    dat.input();
+
+    /*
+     * Check a ACK.
+     */
+    if (!waitClockDownEdge()) {
+        return -2;
+    }
+    if (dat.read() != 0) {
+        return -3;
+    }
+
+    if (!waitClockUpLevel()) {
+        return -4;
+    }
+
+    return 0;
+}
+
+/**
+ * Receive a byte data.
+ *
+ * @return return a data. Negative value is a error number.
+ */
+int PS2MS_INIT::recv(void) {
+    uint8_t c = 0;
+    clk.input();
+    dat.input();
+    int parcnt = 0;
+    for (int i = 0; i < 11; i++) {
+        if (!waitClockDownEdge()) {
+            return -1;
+        }
+        if (i == 0) {
+            /*
+             * Start bit.
+             */
+            if (dat.read() != 0) {
+                return -2;
+            }
+        }
+        if ((1 <= i) && (i <= 8)) {
+            /*
+             * Data bit.
+             */
+            if (dat.read() == 0) {
+                c &= ~(1 << (i - 1));
+            } else {
+                c |= (1 << (i - 1));
+                parcnt++;
+            }
+        }
+        if (i == 9) {
+            /*
+             * Parity bit.
+             */
+            if (dat.read() == 0) {
+                if ((parcnt % 2) != 1) {
+                    return -3;
+                }
+            } else {
+                if ((parcnt % 2) != 0) {
+                    return -4;
+                }
+            }
+        }
+        if (i == 10) {
+            /*
+             * Stop bit.
+             */
+            if (dat.read() != 1) {
+                return -5;
+            }
+        }
+    }
+    return (int)c;
+}
+
+/**
+ * Wait a clock down edge.
+ *
+ * @return true if wait done.
+ */
+bool PS2MS_INIT::waitClockDownEdge(void) {
+    int cnt;
+    /*
+     * Wait until clock is low.
+     */
+    cnt = 0;
+    while (clk.read() == 0) {
+        cnt++;
+        if (MAX_RETRY < cnt) {
+            return false;
+        }
+        wait_us(1);
+    }
+    /*
+     * Wait until clock is high.
+     */
+    cnt = 0;
+    while (clk.read() == 1) {
+        cnt++;
+        if (MAX_RETRY < cnt) {
+            return false;
+        }
+        wait_us(1);
+    }
+    return true;
+}
+
+/**
+ * Wait a clock up level.
+ *
+ * @return true if wait done.
+ */
+bool PS2MS_INIT::waitClockUpLevel(void) {
+    int cnt;
+    /*
+     * Wait until clock is low.
+     */
+    cnt = 0;
+    while (clk.read() == 0) {
+        cnt++;
+        if (MAX_RETRY < cnt) {
+            return false;
+        }
+        wait_us(1);
+    }
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2MS_INIT.h	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,64 @@
+/**
+ * PS/2 mouse interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#ifndef _PS2MS_INIT_H_
+#define _PS2MS_INIT_H_
+
+#include "mbed.h"
+
+/**
+ * PS2 mouse initializer.
+ */
+class PS2MS_INIT {
+public:
+
+    /**
+     * Create.
+     */
+    PS2MS_INIT(PinName clk_pin, PinName dat_pin);
+
+    /**
+     * Destroy.
+     */
+    ~PS2MS_INIT();
+private:
+    DigitalInOut clk;
+    DigitalInOut dat;
+
+    static const int MAX_RETRY = 1000000;
+
+    /**
+     * Send a byte data.
+     *
+     * @param c a character.
+     *
+     * @return Negative value is a error number.
+     */
+    int send(uint8_t c);
+
+    /**
+     * Receive a byte data.
+     *
+     * @return return a data. Negative value is a error number.
+     */
+    int recv(void);
+
+    /**
+     * Wait a clock down edge.
+     *
+     * @return true if wait done.
+     */
+    bool waitClockDownEdge(void);
+
+    /**
+     * Wait a clock up level.
+     *
+     * @return true if wait done.
+     */
+    bool waitClockUpLevel(void);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2Mouse.cpp	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,58 @@
+/**
+ * PS/2 mouse interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#include "PS2Mouse.h"
+
+PS2Mouse::PS2Mouse(PinName clk_pin, PinName dat_pin)
+        : ps2ms_init(clk_pin, dat_pin), ps2ms(clk_pin, dat_pin) {
+    cnt = 0;
+}
+
+PS2Mouse::~PS2Mouse() {
+}
+
+bool PS2Mouse::processing(mouse_event_t *p) {
+    bool emit = false;
+    for (int i = 0; i < 4; i++) {
+        const int c = ps2ms.getc();
+        if (0 <= c) {
+            switch (cnt % 4) {
+                case 0:
+                    mi.byte1.byte = c;
+                    /*
+                     * Check and reset a buffer if state is wrong.
+                     */
+                    if (mi.byte1.bit.always1 == 0) {
+                        cnt = 0;
+                        while (0 <= ps2ms.getc()) {
+                        }
+                    }
+                    break;
+                case 1:
+                    mi.byte2.byte = c;
+                    break;
+                case 2:
+                    mi.byte3.byte = c;
+                    break;
+                case 3:
+                    mi.byte4.byte = c;
+                    /*
+                     * Store a event data.
+                     */
+                    p->left = mi.byte1.bit.btnLeft ? true : false;
+                    p->center = mi.byte1.bit.btnCenter ? true : false;
+                    p->right = mi.byte1.bit.btnRight ? true : false;
+                    p->x = mi.byte1.bit.signX ? (-256 + mi.byte2.byte) : mi.byte2.byte;
+                    p->y = mi.byte1.bit.signY ? (-256 + mi.byte3.byte) : mi.byte3.byte;
+                    p->z = mi.byte4.bit.signZ ? (-128 + mi.byte4.bit.value) : mi.byte4.bit.value;
+                    emit = true;
+                    break;
+            }
+            cnt++;
+        }
+    }
+    return emit;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PS2Mouse.h	Sun Feb 27 23:34:31 2011 +0000
@@ -0,0 +1,61 @@
+/**
+ * PS/2 mouse interface control class (Version 0.0.1)
+ *
+ * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
+ * http://shinta.main.jp/
+ */
+#ifndef _PS2_MOUSE_H_
+#define _PS2_MOUSE_H_
+
+#include "PS2MS_INIT.h"
+#include "PS2MS.h"
+
+class PS2Mouse {
+public:
+    PS2Mouse(PinName clk_pin, PinName dat_pin);
+    ~PS2Mouse();
+    typedef struct {
+        bool left;
+        bool center;
+        bool right;
+        int x;
+        int y;
+        int z;
+    } mouse_event_t;
+    bool processing(mouse_event_t *p);
+private:
+    PS2MS_INIT ps2ms_init;
+    PS2MS ps2ms;
+    typedef struct {
+        union {
+            uint8_t byte;
+            struct {
+                uint8_t btnLeft:1;
+                uint8_t btnRight:1;
+                uint8_t btnCenter:1;
+                uint8_t always1:1;
+                uint8_t signX:1;
+                uint8_t signY:1;
+                uint8_t overflowX:1;
+                uint8_t overflowY:1;
+            } bit;
+        } byte1;
+        union {
+            uint8_t byte;
+        } byte2;
+        union {
+            uint8_t byte;
+        } byte3;
+        union {
+            uint8_t byte;
+            struct {
+                uint8_t value:7;
+                uint8_t signZ:1;
+            } bit;
+        } byte4;
+    } mouse_info_t;
+    mouse_info_t mi;
+    int cnt;
+};
+
+#endif