瀏覽代碼

Merge pull request #1151 from enkiller/development

[bsp] Add keyboard and mouse driver for qemu-vexpress-a9
Bernard Xiong 7 年之前
父節點
當前提交
8a923193ab

+ 474 - 0
bsp/qemu-vexpress-a9/drivers/drv_keyboard.c

@@ -0,0 +1,474 @@
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include "board.h"
+#include "interrupt.h"
+#include "drv_keyboard.h"
+
+#define DBG_LEVEL DBG_LOG
+// #define DBG_ENABLE
+#define DBG_COLOR
+
+#include "rtdbg.h"
+
+#define KEYBOARD_ADDRESS    (0x10006000)
+#define KEYBOARD_IRQ_NUM    (IRQ_VEXPRESS_A9_KBD)
+
+#ifdef RT_USING_GUIENGINE
+
+#include <rtgui/event.h>
+#include <rtgui/rtgui_server.h>
+
+typedef rt_uint32_t virtual_addr_t;
+
+enum{
+    KEYBOARD_CR     = 0x00,
+    KEYBOARD_STAT   = 0x04,
+    KEYBOARD_DATA   = 0x08,
+    KEYBOARD_CLKDIV = 0x0c,
+    KEYBOARD_IIR    = 0x10,
+};
+
+struct keyboard_pl050_pdata_t
+{
+    virtual_addr_t virt;
+    int irq;
+};
+
+enum decode_state {
+    DECODE_STATE_MAKE_CODE,
+    DECODE_STATE_BREAK_CODE,
+    DECODE_STATE_LONG_MAKE_CODE,
+    DECODE_STATE_LONG_BREAK_CODE
+};
+
+struct keymap {
+    rt_uint8_t data;
+    rt_uint32_t key;
+    rt_uint32_t unicode;
+    char *normal_key;
+};
+
+enum key_value_t {
+    KEY_BUTTON_UP,
+    KEY_BUTTON_DOWN,
+};
+
+enum {
+    KBD_LEFT_SHIFT  = (0x1 << 0),
+    KBD_RIGHT_SHIFT = (0x1 << 1),
+    KBD_LEFT_CTRL   = (0x1 << 2),
+    KBD_RIGHT_CTRL  = (0x1 << 3),
+    KBD_CAPS_LOCK   = (0x1 << 6),
+    KBD_NUM_LOCK    = (0x1 << 7),
+    KBD_SCROLL_LOCK = (0x1 << 8),
+};
+
+static const struct keymap map[] = {
+    {0x1c,  RTGUIK_a, 0, "a",          },
+    {0x32,  RTGUIK_b, 0, "b",          },
+    {0x21,  RTGUIK_c, 0, "c",          },
+    {0x23,  RTGUIK_d, 0, "d",          },
+    {0x24,  RTGUIK_e, 0, "e",          },
+    {0x2b,  RTGUIK_f, 0, "f",          },
+    {0x34,  RTGUIK_g, 0, "g",          },
+    {0x33,  RTGUIK_h, 0, "h",          },
+    {0x43,  RTGUIK_i, 0, "i",          },
+    {0x3b,  RTGUIK_j, 0, "j",          },
+    {0x42,  RTGUIK_k, 0, "k",          },
+    {0x4b,  RTGUIK_l, 0, "l",          },
+    {0x3a,  RTGUIK_m, 0, "m",          },
+    {0x31,  RTGUIK_n, 0, "n",          },
+    {0x44,  RTGUIK_o, 0, "o",          },
+    {0x4d,  RTGUIK_p, 0, "p",          },
+    {0x15,  RTGUIK_q, 0, "q",          },
+    {0x2d,  RTGUIK_r, 0, "r",          },
+    {0x1b,  RTGUIK_s, 0, "s",          },
+    {0x2c,  RTGUIK_k, 0, "k",          },
+    {0x3c,  RTGUIK_u, 0, "u",          },
+    {0x2a,  RTGUIK_v, 0, "v",          },
+    {0x1d,  RTGUIK_w, 0, "w",          },
+    {0x22,  RTGUIK_x, 0, "x",          },
+    {0x35,  RTGUIK_y, 0, "y",          },
+    {0x1a,  RTGUIK_z, 0, "z",          },
+
+    {0x45,  RTGUIK_0, 0, "0",          },
+    {0x16,  RTGUIK_1, 0, "1",          },
+    {0x1e,  RTGUIK_2, 0, "2",          },
+    {0x26,  RTGUIK_3, 0, "3",          },
+    {0x25,  RTGUIK_4, 0, "4",          },
+    {0x2e,  RTGUIK_5, 0, "5",          },
+    {0x36,  RTGUIK_6, 0, "6",          },
+    {0x3d,  RTGUIK_7, 0, "7",          },
+    {0x3e,  RTGUIK_8, 0, "8",          },
+    {0x46,  RTGUIK_9, 0, "9",          },
+
+    {0x05,  RTGUIK_F1,  0, "F1",       },
+    {0x06,  RTGUIK_F2,  0, "F2",       },
+    {0x04,  RTGUIK_F3,  0, "F3",       },
+    {0x0c,  RTGUIK_F4,  0, "F4",       },
+    {0x03,  RTGUIK_F5,  0, "F5",       },
+    {0x0b,  RTGUIK_F6,  0, "F6",       },
+    {0x83,  RTGUIK_F7,  0, "F7",       },
+    {0x0a,  RTGUIK_F8,  0, "F8",       },
+    {0x01,  RTGUIK_F9,  0, "F9",       },
+    {0x09,  RTGUIK_F10, 0, "F10",      },
+    {0x78,  RTGUIK_F11, 0, "F11",      },
+    {0x07,  RTGUIK_F12, 0, "F12",      },
+
+    {0x29,  RTGUIK_SPACE,  0, "SPACE"  },
+    {0x71,  RTGUIK_DELETE, 0, "DELETE" },
+    {0x52,  RTGUIK_QUOTE,  0, "'"      },
+    {0x55,  RTGUIK_EQUALS, 0, "="      },
+    {0x41,  RTGUIK_COMMA,  0, ","      },
+    {0x4e,  RTGUIK_MINUS,  0, "-"      },
+    // {0x49,  RTGUIK_,    0, "."         },
+    {0x4a,  RTGUIK_SLASH,  0, "/"      },
+    {0x4c,  RTGUIK_SEMICOLON, 0, ";"   },
+    {0x54,  RTGUIK_LEFTBRACKET, 0, "[" },
+    {0x5d,  RTGUIK_BACKSLASH, 0, "\\"  },
+    {0x5b,  RTGUIK_RIGHTBRACKET, 0, "]"},
+    {0x75,  RTGUIK_UP,    0, "UP"      },
+    {0x72,  RTGUIK_DOWN,  0, "DOWN"    },
+    {0x6b,  RTGUIK_LEFT,  0, "LEFT"    },
+    {0x74,  RTGUIK_RIGHT, 0, "RIGHT"   },
+    {0x0d,  RTGUIK_TAB,   0, "TAB"     },
+    {0x76,  RTGUIK_ESCAPE, 0, "ESC"    },
+    {0x37,  RTGUIK_POWER,  0, "POWER"  }, 
+    {0x5a,  RTGUIK_KP_ENTER, 0, "ENTER"},
+    {0x66,  RTGUIK_BACKSPACE, 0, "BACKSPACE"},
+};
+
+rt_inline rt_uint8_t read8(uint32_t addr)
+{
+    return (*((volatile rt_uint8_t *)(addr)));
+}
+
+rt_inline void write8(uint32_t addr, rt_uint8_t value)
+{
+    *((volatile rt_uint8_t *)(addr)) = value;
+}
+
+rt_inline rt_uint32_t read32(uint32_t addr)
+{
+    return (*((volatile rt_uint32_t *)(addr)));
+}
+
+rt_inline void write32(uint32_t addr, rt_uint32_t value)
+{
+    *((volatile rt_uint32_t *)(addr)) = value;
+}
+
+rt_inline int kmi_write(struct keyboard_pl050_pdata_t * pdat, rt_uint8_t value)
+{
+    int timeout = 1000;
+
+    while((read8(pdat->virt + KEYBOARD_STAT) & (1 << 6)) == 0 && timeout--);
+
+    if(timeout)
+    {
+        write8(pdat->virt + KEYBOARD_DATA, value);
+        while((read8(pdat->virt + KEYBOARD_STAT) & (1 << 4)) == 0);
+
+        if(read8(pdat->virt + KEYBOARD_DATA) == 0xfa)
+            return RT_TRUE;
+    }
+    return RT_FALSE;
+}
+
+rt_inline int kmi_read(struct keyboard_pl050_pdata_t * pdat, rt_uint8_t * value)
+{
+    if((read8(pdat->virt + KEYBOARD_STAT) & (1 << 4)))
+    {
+        *value = read8(pdat->virt + KEYBOARD_DATA);
+        return RT_TRUE;
+    }
+    return RT_FALSE;
+}
+
+static void keyboard_report_event(void * device, rt_uint32_t flag, rt_uint8_t data, enum key_value_t press)
+{
+    struct rtgui_event_kbd key_event;
+    rt_uint16_t i = 0, mod = 0, find_key = 0;
+
+    for(i = 0; i < sizeof(map)/sizeof(map[0]); i++)
+    {
+        if (map[i].data == data)
+        {
+            dbg_log(DBG_LOG,"KEY info:\n");
+            if (flag & KBD_CAPS_LOCK)
+            {
+                dbg_log(DBG_LOG,"CAPS:LOCK\n");
+            }
+            else
+            {
+                dbg_log(DBG_LOG,"CAPS:UNLOCK\n");
+            }
+
+            if (flag & KBD_LEFT_SHIFT)
+            {
+                mod |= RTGUI_KMOD_LSHIFT;
+                dbg_log(DBG_LOG,"SHIFT:LEFT\n");
+            }
+            else if (flag & KBD_RIGHT_SHIFT)
+            {
+                mod |= RTGUI_KMOD_RSHIFT;
+                dbg_log(DBG_LOG,"SHIFT:RIGHT\n");
+            }
+            else
+            {
+                dbg_log(DBG_LOG,"SHIFT:NULL\n");
+            }
+
+            if (flag & KBD_LEFT_CTRL)
+            {
+                mod |= RTGUI_KMOD_LCTRL;
+                dbg_log(DBG_LOG,"CTRL:LEFT\n");
+            }
+            else if (flag & KBD_RIGHT_CTRL)
+            {
+                mod |= RTGUI_KMOD_RCTRL;
+                dbg_log(DBG_LOG,"CTRL:RIGHT\n");
+            }
+            else
+            {
+                dbg_log(DBG_LOG,"CTRL:NULL\n");
+            }
+
+            dbg_log(DBG_LOG,"flag:0x%08x value:0x%x key:%s status:%s\n", \
+                flag, data, map[i].normal_key, press ==0 ? "UP" : "DOWN");
+            find_key = 1;
+            break;
+        }
+    }
+    if (find_key == 0)
+    {
+        dbg_log(DBG_LOG,"flag:0x%08x value:0x%x key:%s status:%s\n", \
+            flag, data, "UNKNOWN", press ==0 ? "UP" : "DOWN");
+        return;
+    }
+
+    key_event.parent.sender = RT_NULL;
+    key_event.parent.type = RTGUI_EVENT_KBD;
+    key_event.type = (press == 0 ? RTGUI_KEYUP : RTGUI_KEYDOWN);
+    key_event.key = map[i].key;
+    key_event.mod = mod;
+    key_event.unicode = map[i].unicode;
+    rtgui_server_post_event(&key_event.parent, sizeof(key_event));
+}
+
+static void keyboard_pl050_interrupt(int irq, void *data)
+{
+    struct keyboard_pl050_pdata_t * pdat = (struct keyboard_pl050_pdata_t *)data;
+    static enum decode_state ds = DECODE_STATE_MAKE_CODE;
+    static rt_uint32_t kbd_flag = KBD_NUM_LOCK;
+    rt_uint8_t status, value;
+
+    status = read8(pdat->virt + KEYBOARD_IIR);
+
+    while(status & (1 << 0))
+    {
+        value = read8(pdat->virt + KEYBOARD_DATA);
+
+        switch(ds)
+        {
+        case DECODE_STATE_MAKE_CODE:
+            /* break code */
+            if(value == 0xf0)
+            {
+                ds = DECODE_STATE_BREAK_CODE;
+            }
+            /* long make code */
+            else if(value == 0xe0)
+            {
+                ds = DECODE_STATE_LONG_MAKE_CODE;
+            }
+            else
+            {
+                ds = DECODE_STATE_MAKE_CODE;
+
+                /* left shift */
+                if(value == 0x12)
+                {
+                    kbd_flag |= KBD_LEFT_SHIFT;
+                }
+                /* right shift */
+                else if(value == 0x59)
+                {
+                    kbd_flag |= KBD_RIGHT_SHIFT;
+                }
+                /* left ctrl */
+                else if(value == 0x14)
+                {
+                    kbd_flag |= KBD_LEFT_CTRL;
+                }
+                /* caps lock */
+                else if(value == 0x58)
+                {
+                    if(kbd_flag & KBD_CAPS_LOCK)
+                        kbd_flag &= ~KBD_CAPS_LOCK;
+                    else
+                        kbd_flag |= KBD_CAPS_LOCK;
+                }
+                /* scroll lock */
+                else if(value == 0x7e)
+                {
+                    if(kbd_flag & KBD_SCROLL_LOCK)
+                        kbd_flag &= ~KBD_SCROLL_LOCK;
+                    else
+                        kbd_flag |= KBD_SCROLL_LOCK;
+                }
+                /* num lock */
+                else if(value == 0x77)
+                {
+                    if(kbd_flag & KBD_NUM_LOCK)
+                        kbd_flag &= ~KBD_NUM_LOCK;
+                    else
+                        kbd_flag |= KBD_NUM_LOCK;
+                }
+                /* others */
+                else
+                {
+                    keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_DOWN);
+                }
+            }
+            break;
+
+        case DECODE_STATE_BREAK_CODE:
+            if( (value != 0xf0) && (value != 0xe0))
+            {
+                ds = DECODE_STATE_MAKE_CODE;
+
+                /* left shift */
+                if(value == 0x12)
+                {
+                    kbd_flag &= ~KBD_LEFT_SHIFT;
+                }
+                /* right shift */
+                else if(value == 0x59)
+                {
+                    kbd_flag &= ~KBD_RIGHT_SHIFT;
+                }
+                /* left ctrl */
+                else if(value == 0x14)
+                {
+                    kbd_flag &= ~KBD_LEFT_CTRL;
+                }
+                /* others */
+                else
+                {
+                    keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_UP);
+                }
+            }
+            else
+            {
+                ds = DECODE_STATE_BREAK_CODE;
+            }
+            break;
+
+        case DECODE_STATE_LONG_MAKE_CODE:
+            if( value != 0xf0 && value!= 0xe0)
+            {
+                ds = DECODE_STATE_MAKE_CODE;
+
+                /* left ctrl */
+                if(value == 0x14)
+                {
+                    kbd_flag |= KBD_RIGHT_CTRL;
+                }
+                /* others */
+                else
+                {
+                    keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_DOWN);
+                }
+            }
+            else
+            {
+                ds = DECODE_STATE_LONG_BREAK_CODE;
+            }
+            break;
+
+        case DECODE_STATE_LONG_BREAK_CODE:
+            if( (value != 0xf0) && (value != 0xe0))
+            {
+                ds = DECODE_STATE_MAKE_CODE;
+
+                /* left ctrl */
+                if(value == 0x14)
+                {
+                    kbd_flag &= ~KBD_RIGHT_CTRL;
+                }
+                /* others */
+                else
+                {
+                    keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_UP);
+                }
+            }
+            else
+            {
+                ds = DECODE_STATE_LONG_BREAK_CODE;
+            }
+            break;
+
+        default:
+            ds = DECODE_STATE_MAKE_CODE;
+            break;
+        }
+
+        status = read8(pdat->virt + KEYBOARD_IIR);
+    }
+}
+
+int rt_hw_keyboard_init(void)
+{
+    rt_uint8_t value;
+    rt_uint32_t id;
+    struct keyboard_pl050_pdata_t *pdat;
+    virtual_addr_t virt = (virtual_addr_t)KEYBOARD_ADDRESS;
+    int irq = KEYBOARD_IRQ_NUM;
+    
+    id = (((read32(virt + 0xfec) & 0xff) << 24) |
+                ((read32(virt + 0xfe8) & 0xff) << 16) |
+                ((read32(virt + 0xfe4) & 0xff) <<  8) |
+                ((read32(virt + 0xfe0) & 0xff) <<  0));
+    
+    if(((id >> 12) & 0xff) != 0x41 || (id & 0xfff) != 0x050)
+    {
+        dbg_log(DBG_ERROR, "read id fail id:0x%08x\n", id);
+        return RT_ERROR;
+    }
+
+    pdat = rt_malloc(sizeof(struct keyboard_pl050_pdata_t));
+    if(!pdat)
+    {
+        dbg_log(DBG_ERROR, "malloc memory\n", id);
+        return RT_ERROR;
+    }
+    rt_memset(pdat, 0, sizeof(struct keyboard_pl050_pdata_t));
+
+    pdat->virt = virt;
+    pdat->irq = irq;
+
+    write8(pdat->virt + KEYBOARD_CLKDIV, 0);
+    write8(pdat->virt + KEYBOARD_CR, (1 << 2));
+    kmi_read(pdat, &value);
+    kmi_write(pdat, 0xff);
+    kmi_read(pdat, &value);
+    kmi_write(pdat, 0xf3);
+    kmi_write(pdat, 0x2b);
+    kmi_write(pdat, 0xf0);
+    kmi_write(pdat, 0x02);
+    kmi_write(pdat, 0xfa);
+    kmi_write(pdat, 0xed);
+    kmi_write(pdat, 0x02);
+    write8(pdat->virt + KEYBOARD_CR, (1 << 2) | (1 << 4));
+
+    rt_hw_interrupt_install(irq, keyboard_pl050_interrupt, (void *)pdat, "keyboard");
+    rt_hw_interrupt_umask(irq);
+
+    return RT_EOK;
+}
+INIT_DEVICE_EXPORT(rt_hw_keyboard_init);
+
+#endif

+ 6 - 0
bsp/qemu-vexpress-a9/drivers/drv_keyboard.h

@@ -0,0 +1,6 @@
+#ifndef __DEV_KEYBOARD_H__
+#define __DEV_KEYBOARD_H__
+
+int rt_hw_keyboard_init(void);
+
+#endif

+ 298 - 0
bsp/qemu-vexpress-a9/drivers/drv_mouse.c

@@ -0,0 +1,298 @@
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include "board.h"
+#include "interrupt.h"
+#include "drv_mouse.h"
+
+#define DBG_LEVEL DBG_LOG
+// #define DBG_ENABLE
+#define DBG_COLOR
+
+#include "rtdbg.h"
+
+#define MOUSE_ADDRESS    (0x10007000)
+#define MOUSE_IRQ_NUM    (IRQ_VEXPRESS_A9_MOUSE)
+#define MOUSE_XMAX       (800)
+#define MOUSE_YMAX       (480)
+
+#define MOUSE_BUTTON_LEFT    (0x01)
+#define MOUSE_BUTTON_RIGHT   (0x02)
+#define MOUSE_BUTTON_MIDDLE  (0x04)
+#define MOUSE_BUTTON_DOWN    (0x10)
+#define MOUSE_BUTTON_UP      (0x20)
+#define MOUSE_BUTTON_MOVE    (0x40)
+#define MOUSE_BUTTON_WHELL   (0x80)
+
+#ifdef RT_USING_GUIENGINE
+
+#include <rtgui/event.h>
+#include <rtgui/rtgui_server.h>
+
+typedef rt_uint32_t virtual_addr_t;
+
+enum {
+    MOUSE_CR        = 0x00,
+    MOUSE_STAT      = 0x04,
+    MOUSE_DATA      = 0x08,
+    MOUSE_CLKDIV    = 0x0c,
+    MOUSE_IIR       = 0x10,
+};
+
+struct mouse_pl050_pdata_t {
+    virtual_addr_t virt;
+    int irq;
+    int xmax, ymax;
+    int xpos, ypos;
+    unsigned char packet[4];
+    int index;
+    int obtn;
+    int type;
+};
+
+rt_inline rt_uint8_t read8(uint32_t addr)
+{
+    return (*((volatile rt_uint8_t *)(addr)));
+}
+
+rt_inline void write8(uint32_t addr, rt_uint8_t value)
+{
+    *((volatile rt_uint8_t *)(addr)) = value;
+}
+
+rt_inline rt_uint32_t read32(uint32_t addr)
+{
+    return (*((volatile rt_uint32_t *)(addr)));
+}
+
+rt_inline void write32(uint32_t addr, rt_uint32_t value)
+{
+    *((volatile rt_uint32_t *)(addr)) = value;
+}
+
+rt_inline int kmi_write(struct mouse_pl050_pdata_t * pdat, rt_uint8_t value)
+{
+    int timeout = 1000;
+
+    while((read8(pdat->virt + MOUSE_STAT) & (1 << 6)) == 0 && timeout--);
+
+    if(timeout)
+    {
+        write8(pdat->virt + MOUSE_DATA, value);
+        while((read8(pdat->virt + MOUSE_STAT) & (1 << 4)) == 0);
+
+        if(read8(pdat->virt + MOUSE_DATA) == 0xfa)
+            return RT_TRUE;
+    }
+    return RT_FALSE;
+}
+
+rt_inline int kmi_read(struct mouse_pl050_pdata_t * pdat, rt_uint8_t * value)
+{
+    if((read8(pdat->virt + MOUSE_STAT) & (1 << 4)))
+    {
+        *value = read8(pdat->virt + MOUSE_DATA);
+        return RT_TRUE;
+    }
+    return RT_FALSE;
+}
+
+static rt_uint32_t emouse_id;
+
+void push_event_touch_move(int x, int y)
+{
+    struct rtgui_event_mouse emouse;
+
+    emouse.parent.sender = RT_NULL;
+    emouse.wid = RT_NULL;
+
+    emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN;
+    emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION;
+    emouse.x = x;
+    emouse.y = y;
+    emouse.ts = rt_tick_get();
+    emouse.id = emouse_id;
+
+    dbg_log(DBG_LOG, "[line]:%d motion event id:%d x:%d y:%d\n", __LINE__, emouse.id, x, y);
+    rtgui_server_post_event(&emouse.parent, sizeof(emouse));
+}
+
+void push_event_touch_begin(int x, int y)
+{
+    struct rtgui_event_mouse emouse;
+
+    emouse_id = rt_tick_get();
+
+    emouse.parent.sender = RT_NULL;
+    emouse.wid = RT_NULL;
+
+    emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
+    emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN;
+    emouse.x = x;
+    emouse.y = y;
+    emouse.ts = rt_tick_get();
+    emouse.id = emouse_id;
+    dbg_log(DBG_LOG, "[line]:%d down event id:%d x:%d y:%d\n", __LINE__, emouse.id, x, y);
+    rtgui_server_post_event(&emouse.parent, sizeof(emouse));
+}
+
+void push_event_touch_end(int x, int y)
+{
+    struct rtgui_event_mouse emouse;
+
+    emouse.parent.sender = RT_NULL;
+    emouse.wid = RT_NULL;
+
+    emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
+    emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP;
+    emouse.x = x;
+    emouse.y = y;
+    emouse.ts = rt_tick_get();
+    emouse.id = emouse_id;
+    
+    dbg_log(DBG_LOG, "[line]:%d up event id:%d x:%d y:%d\n", __LINE__, emouse.id, x, y);
+    rtgui_server_post_event(&emouse.parent, sizeof(emouse));
+}
+
+static void mouse_pl050_interrupt(int irq, void * data)
+{
+    struct mouse_pl050_pdata_t * pdat = (struct mouse_pl050_pdata_t *)data;
+    int x, y, relx, rely, delta;
+    int btndown, btnup, btn;
+    int status = 0;
+
+    status = read8(pdat->virt + MOUSE_IIR);
+    while(status & (1 << 0))
+    {
+        pdat->packet[pdat->index] = read8(pdat->virt + MOUSE_DATA);
+        pdat->index = (pdat->index + 1) & 0x3;
+
+        if(pdat->index == 0)
+        {
+            btn = pdat->packet[0] & 0x7;
+            btndown = (btn ^ pdat->obtn) & btn;
+            btnup = (btn ^ pdat->obtn) & pdat->obtn;
+            pdat->obtn = btn;
+
+            if(pdat->packet[0] & 0x10)
+                relx = 0xffffff00 | pdat->packet[1];
+            else
+                relx = pdat->packet[1];
+
+            if(pdat->packet[0] & 0x20)
+                rely = 0xffffff00 | pdat->packet[2];
+            else
+                rely = pdat->packet[2];
+            rely = -rely;
+
+            delta = pdat->packet[3] & 0xf;
+            if(delta == 0xf)
+                delta = -1;
+
+            if(relx != 0)
+            {
+                pdat->xpos = pdat->xpos + relx;
+                if(pdat->xpos < 0)
+                    pdat->xpos = 0;
+                if(pdat->xpos > pdat->xmax - 1)
+                    pdat->xpos = pdat->xmax - 1;
+            }
+            if(rely != 0)
+            {
+                pdat->ypos = pdat->ypos + rely;
+                if(pdat->ypos < 0)
+                    pdat->ypos = 0;
+                if(pdat->ypos > pdat->ymax - 1)
+                    pdat->ypos = pdat->ymax - 1;
+            }
+            x = pdat->xpos;
+            y = pdat->ypos;
+
+            if((btn & (0x01 << 0)) && ((relx != 0) || (rely != 0)))
+                push_event_touch_move(x, y);
+
+            if(btndown & (0x01 << 0))
+                push_event_touch_begin(x, y);
+
+            if(btnup & (0x01 << 0))
+                push_event_touch_end(x, y);
+        }
+
+        status = read8(pdat->virt + MOUSE_IIR);
+    }
+}
+
+int rt_hw_mouse_init(void)
+{
+    rt_uint8_t value;
+    rt_uint32_t id;
+    struct mouse_pl050_pdata_t *pdat;
+    virtual_addr_t virt = MOUSE_ADDRESS;
+    int irq = MOUSE_IRQ_NUM;
+
+    id = (((read32(virt + 0xfec) & 0xff) << 24) |
+                ((read32(virt + 0xfe8) & 0xff) << 16) |
+                ((read32(virt + 0xfe4) & 0xff) <<  8) |
+                ((read32(virt + 0xfe0) & 0xff) <<  0));
+    
+    if(((id >> 12) & 0xff) != 0x41 || (id & 0xfff) != 0x050)
+    {
+        dbg_log(DBG_ERROR, "read id fail id:0x%08x\n", id);
+        return RT_ERROR;
+    }
+
+    pdat = rt_malloc(sizeof(struct mouse_pl050_pdata_t));
+    if(!pdat)
+    {
+        dbg_log(DBG_ERROR, "malloc memory\n", id);
+        return RT_ERROR;
+    }
+    rt_memset(pdat, 0, sizeof(struct mouse_pl050_pdata_t));
+
+    pdat->virt = virt;
+    pdat->irq = irq;
+    pdat->xmax = MOUSE_XMAX;
+    pdat->ymax = MOUSE_YMAX;
+    pdat->xpos = pdat->xmax / 2;
+    pdat->ypos = pdat->ymax / 2;
+    pdat->packet[0] = 0;
+    pdat->packet[1] = 0;
+    pdat->packet[2] = 0;
+    pdat->packet[3] = 0;
+    pdat->index = 0;
+    pdat->obtn = 0;
+
+    write8(pdat->virt + MOUSE_CLKDIV, 0);
+    write8(pdat->virt + MOUSE_CR, (1 << 2));
+    kmi_write(pdat, 0xff);
+    kmi_read(pdat, &value);
+    kmi_write(pdat, 0xf3);
+    kmi_write(pdat, 200);
+    kmi_write(pdat, 0xf3);
+    kmi_write(pdat, 100);
+    kmi_write(pdat, 0xf3);
+    kmi_write(pdat, 80);
+    kmi_write(pdat, 0xf2);
+    kmi_read(pdat, &value);
+    kmi_read(pdat, &value);
+    kmi_write(pdat, 0xf3);
+    kmi_write(pdat, 100);
+    kmi_write(pdat, 0xe8);
+    kmi_write(pdat, 0x02);
+    kmi_write(pdat, 0xe6);
+    kmi_write(pdat, 0xf4);
+    kmi_read(pdat, &value);
+    kmi_read(pdat, &value);
+    kmi_read(pdat, &value);
+    kmi_read(pdat, &value);
+    write8(pdat->virt + MOUSE_CR, (1 << 2) | (1 << 4));
+
+    rt_hw_interrupt_install(pdat->irq, mouse_pl050_interrupt, (void *)pdat, "mouse");
+    rt_hw_interrupt_umask(pdat->irq);
+
+    return RT_EOK;
+}
+INIT_DEVICE_EXPORT(rt_hw_mouse_init);
+
+#endif

+ 6 - 0
bsp/qemu-vexpress-a9/drivers/drv_mouse.h

@@ -0,0 +1,6 @@
+#ifndef __DRV_MOUSE_H__
+#define __DRV_MOUSE_H__
+
+int rt_hw_mouse_init(void);
+
+#endif