babyos2(7)——键盘中断、时钟中断、实时钟

来源:互联网 发布:拍照最好的手机 知乎 编辑:程序博客网 时间:2024/06/05 22:58

babyos2暂时还是使用8259a作为中断控制器,后续可能会尝试使用APIC。

/* * guzhoudiaoke@126.com * 2017-11-7 */#ifndef _I8259A_H_#define _I8259A_H_#include "types.h"#define IRQ_0               (0x20)#define IRQ_NUM             (0x10)#define IRQ_TIMER           (0x0)#define IRQ_KEYBOARD        (0x1)#define IRQ_HARDDISK        (0xe)#define IRQ_SYSCALL         (0x80)class i8259a_t {public:    i8259a_t();    ~i8259a_t();    void init();    void enable_irq(uint32 irq);};#endif/* * guzhoudiaoke@126.com * 2017-11-7 */#include "i8259a.h"#include "x86.h"i8259a_t::i8259a_t(){}i8259a_t::~i8259a_t(){}void i8259a_t::init(){    //console()->kprintf(WHITE, "i8259a_t::init()\n");    /* ICW1:0x11, 表示边沿触发、多片级联、需要发送ICW4 */    outb(0x20, 0x11);    outb(0xa0, 0x11);    /* ICW2:     * 重新映射 IRQ0~IRQ7 到 0x20~0x27,重新映射 IRQ8~IRQ15 到 0x28~0x2F */    outb(0x21, 0x20);    outb(0xa1, 0x28);    /* ICW3:     *       A0 D7  D6  D5  D4  D3  D2  D1  D0     * master 1 S7  S6  S5  S4  S3  S2  S1  S0     * slave  1 0   0   0   0   0   ID2 ID1 ID0     * master: 0x04,表示主芯片的IR2引脚连接一个从芯片     * slave: 0x02,表示从片连接到主片的IR2 引脚 */    outb(0x21, 0x04);    outb(0xa1, 0x02);    /* 从片连接到主片的 IRQ2 */    /* ICW4:0x01,表示8259A芯片被设置成普通嵌套、非中断方式、     * 用于8086 及其兼容模式 */    outb(0x21, 0x01);    outb(0xa1, 0x01);    /* disable all interrupts */    outb(0x21, 0xff);    outb(0xa1, 0xff);}void i8259a_t::enable_irq(uint32 irq){    uint8 mask;    if (irq < 8)    {        mask = inb(0x21) & (0xff ^ (1 << irq));        outb(0x21, mask);    }    else if (irq < 16)    {        mask = inb(0x21) & 0xfb;        outb(0x21, mask);        mask = inb(0xa1) & (0xff ^ (1 << (irq-8)));        outb(0xa1, mask);    }}

8259a的初始化及开启特定中断代码如上所示。关于8259a编程可以找特定的文档,在此不多做描述。

/* * guzhoudiaoke@126.com * 2017-10-27 */#ifndef _KEYBOARD_H_#define _KEYBOARD_H_#include "types.h"#include "queue.h"#define NR_SCAN_CODES       0x80        /* 扫描码个数 */#define NR_CODE_COL         0x03        /* 扫描码列数 *//* 简单起见暂时先把键盘上所有键分为7类,分类来给每个键一个唯一标号(一个类号,一个标识号): * 可打印的字符、特殊字符、功能键、转换键、锁定键、小键盘上的键、APIC键 */#define KT_ASCII            0           /* 可打印字符键 */#define KT_SPECIAL          1           /* 特殊字符键 */#define KT_FUNCTION         2           /* 功能键 */#define KT_SHIFT            3           /* 转换键 */#define KT_LOCK             4           /* 锁定键 */#define KT_CONTROL          5           /* 中间方向键等控制键盘 */#define KT_PAD              6           /* 小键盘 */#define KT_APIC             7           /* APIC键 *//* KEY用来构造一个唯一标号 * KEY_TYPE用来获得键的类型 * KEY_VALUE用来得到键的值 */#define KEY(type, value)    (((type) << 8) | (value))#define KEY_TYPE(x)         ((x) >> 8)#define KEY_VALUE(x)        ((x) &  0xff)/* 功能键 */#define K_F0                KEY(KT_FUNCTION, 0)#define K_F1                KEY(KT_FUNCTION, 1)#define K_F2                KEY(KT_FUNCTION, 2)#define K_F3                KEY(KT_FUNCTION, 3)#define K_F4                KEY(KT_FUNCTION, 4)#define K_F5                KEY(KT_FUNCTION, 5)#define K_F6                KEY(KT_FUNCTION, 6)#define K_F7                KEY(KT_FUNCTION, 7)#define K_F8                KEY(KT_FUNCTION, 8)#define K_F9                KEY(KT_FUNCTION, 9)#define K_F10               KEY(KT_FUNCTION, 10)#define K_F11               KEY(KT_FUNCTION, 11)#define K_F12               KEY(KT_FUNCTION, 12)/* 特殊字符键 */#define K_ESC               KEY(KT_SPECIAL, 0)#define K_BACKSPACE         KEY(KT_SPECIAL, 1)#define K_TAB               KEY(KT_SPECIAL, 2)#define K_ENTER             KEY(KT_SPECIAL, 3)#define K_GUI_L             KEY(KT_SPECIAL, 4)#define K_GUI_R             KEY(KT_SPECIAL, 5)#define K_APPS              KEY(KT_SPECIAL, 6)/* 转换键 */#define K_SHIFT_L           KEY(KT_SHIFT, 0)#define K_SHIFT_R           KEY(KT_SHIFT, 1)#define K_CTRL_L            KEY(KT_SHIFT, 2)#define K_CTRL_R            KEY(KT_SHIFT, 3)#define K_ALT_L             KEY(KT_SHIFT, 4)#define K_ALT_R             KEY(KT_SHIFT, 5)/* 锁定键 */#define K_CAPS_LOCK         KEY(KT_LOCK, 0)#define K_NUM_LOCK          KEY(KT_LOCK, 1)#define K_SCROLL_LOCK       KEY(KT_LOCK, 2)/* 控制键 */#define K_PRINTSCREEN       KEY(KT_CONTROL, 0)      /* Print Screen */#define K_PAUSEBREAK        KEY(KT_CONTROL, 1)      /* Pause/Break  */#define K_INSERT            KEY(KT_CONTROL, 2)      /* Insert   */#define K_DELETE            KEY(KT_CONTROL, 3)      /* Delete   */#define K_HOME              KEY(KT_CONTROL, 4)      /* Home     */#define K_END               KEY(KT_CONTROL, 5)      /* End      */#define K_PAGEUP            KEY(KT_CONTROL, 6)      /* Page Up  */#define K_PAGEDOWN          KEY(KT_CONTROL, 7)      /* Page Down*/#define K_UP                KEY(KT_CONTROL, 8)      /* Up       */#define K_DOWN              KEY(KT_CONTROL, 9)      /* Down     */#define K_LEFT              KEY(KT_CONTROL, 10)     /* Left     */#define K_RIGHT             KEY(KT_CONTROL, 11)     /* Right    *//* ACPI 键 */#define K_POWER             KEY(KT_APIC, 0)         /* Power    */#define K_SLEEP             KEY(KT_APIC, 1)         /* Sleep    */#define K_WAKE              KEY(KT_APIC, 2)         /* Wake Up  *//* Num Pad */#define K_PAD_0             KEY(KT_PAD, 0)          #define K_PAD_1             KEY(KT_PAD, 1)          #define K_PAD_2             KEY(KT_PAD, 2)          #define K_PAD_3             KEY(KT_PAD, 3)          #define K_PAD_4             KEY(KT_PAD, 4)          #define K_PAD_5             KEY(KT_PAD, 5)              #define K_PAD_6             KEY(KT_PAD, 6)              #define K_PAD_7             KEY(KT_PAD, 7)          #define K_PAD_8             KEY(KT_PAD, 8)          #define K_PAD_9             KEY(KT_PAD, 9)          #define K_PAD_SLASH         KEY(KT_PAD, 10)         /* /        */#define K_PAD_STAR          KEY(KT_PAD, 11)         /* *        */#define K_PAD_MINUS         KEY(KT_PAD, 12)         /* -        */#define K_PAD_PLUS          KEY(KT_PAD, 13)         /* +        */#define K_PAD_ENTER         KEY(KT_PAD, 14)         /* Enter    */#define K_PAD_DOT           KEY(KT_PAD, 15)         /* .        */#define K_PAD_UP            K_PAD_8                 /* Up       */#define K_PAD_DOWN          K_PAD_2                 /* Down     */#define K_PAD_LEFT          K_PAD_4                 /* Left     */#define K_PAD_RIGHT         K_PAD_6                 /* Right    */#define K_PAD_HOME          K_PAD_7                 /* Home     */#define K_PAD_END           K_PAD_1                 /* End      */#define K_PAD_PAGEUP        K_PAD_9                 /* Page Up  */#define K_PAD_PAGEDOWN      K_PAD_3                 /* Page Down*/#define K_PAD_INS           K_PAD_0                 /* Ins      */#define K_PAD_MID           K_PAD_5                 /* Middle key*/#define K_PAD_DEL           K_PAD_DOT                   /* Del      *//* 将0x80个扫描码一一映射成上面的标识号 */static const uint32 keymap[NR_SCAN_CODES][NR_CODE_COL] = {    /* scancode !shift              shift           0xE0 0x??   */    /* -------------------------------------------------------- */    /* 0x00 */  { 0,                0,              0 },    /* 0x01 */  { K_ESC,            K_ESC,          0 },    /* 0x02 */  { '1',              '!',            0 },    /* 0x03 */  { '2',              '@',            0 },    /* 0x04 */  { '3',              '#',            0 },    /* 0x05 */  { '4',              '$',           0 },    /* 0x06 */  { '5',              '%',            0 },    /* 0x07 */  { '6',              '^',            0 },    /* 0x08 */  { '7',              '&',            0 },    /* 0x09 */  { '8',              '*',            0 },    /* 0x0A */  { '9',              '(',            0 },    /* 0x0B */  { '0',              ')',            0 },    /* 0x0C */  { '-',              '_',            0 },    /* 0x0D */  { '=',              '+',            0 },    /* 0x0E */  { K_BACKSPACE,      K_BACKSPACE,    0 },    /* 0x0F */  { K_TAB,            K_TAB,          0 },    /* 0x10 */  { 'q',              'Q',            0 },    /* 0x11 */  { 'w',              'W',            0 },    /* 0x12 */  { 'e',              'E',            0 },    /* 0x13 */  { 'r',              'R',            0 },    /* 0x14 */  { 't',              'T',            0 },    /* 0x15 */  { 'y',              'Y',            0 },    /* 0x16 */  { 'u',              'U',            0 },    /* 0x17 */  { 'i',              'I',            0 },    /* 0x18 */  { 'o',              'O',            0 },    /* 0x19 */  { 'p',              'P',            0 },    /* 0x1A */  { '[',              '{',            0 },    /* 0x1B */  { ']',              '}',            0 },    /* 0x1C */  { K_ENTER,          K_ENTER,        K_PAD_ENTER },    /* 0x1D */  { K_CTRL_L,         K_CTRL_L,       K_CTRL_R },    /* 0x1E */  { 'a',              'A',            0 },    /* 0x1F */  { 's',              'S',            0 },    /* 0x20 */  { 'd',              'D',            0 },    /* 0x21 */  { 'f',              'F',            0 },    /* 0x22 */  { 'g',              'G',            0 },    /* 0x23 */  { 'h',              'H',            0 },    /* 0x24 */  { 'j',              'J',            0 },    /* 0x25 */  { 'k',              'K',            0 },    /* 0x26 */  { 'l',              'L',            0 },    /* 0x27 */  { ';',              ':',            0 },    /* 0x28 */  { '\'',             '"',            0 },    /* 0x29 */  { '`',              '~',           0 },    /* 0x2A */  { K_SHIFT_L,        K_SHIFT_L,      0 },    /* 0x2B */  { '\\',             '|',            0 },    /* 0x2C */  { 'z',              'Z',            0 },    /* 0x2D */  { 'x',              'X',            0 },    /* 0x2E */  { 'c',              'C',            0 },    /* 0x2F */  { 'v',              'V',            0 },    /* 0x30 */  { 'b',              'B',            0 },    /* 0x31 */  { 'n',              'N',            0 },    /* 0x32 */  { 'm',              'M',            0 },    /* 0x33 */  { ',',              '<',            0 },    /* 0x34 */  { '.',              '>',            0 },    /* 0x35 */  { '/',              '?',            K_PAD_SLASH },    /* 0x36 */  { K_SHIFT_R,        K_SHIFT_R,      0 },    /* 0x37 */  { '*',              '*',            0 },    /* 0x38 */  { K_ALT_L,          K_ALT_L,        K_ALT_R },    /* 0x39 */  { ' ',              ' ',            0 },    /* 0x3A */  { K_CAPS_LOCK,      K_CAPS_LOCK,    0 },    /* 0x3B */  { K_F1,             K_F1,           0 },    /* 0x3C */  { K_F2,             K_F2,           0 },    /* 0x3D */  { K_F3,             K_F3,           0 },    /* 0x3E */  { K_F4,             K_F4,           0 },    /* 0x3F */  { K_F5,             K_F5,           0 },    /* 0x40 */  { K_F6,             K_F6,           0 },    /* 0x41 */  { K_F7,             K_F7,           0 },    /* 0x42 */  { K_F8,             K_F8,           0 },    /* 0x43 */  { K_F9,             K_F9,           0 },    /* 0x44 */  { K_F10,            K_F10,          0 },    /* 0x45 */  { K_NUM_LOCK,       K_NUM_LOCK,     0 },    /* 0x46 */  { K_SCROLL_LOCK,    K_SCROLL_LOCK,  0 },    /* 0x47 */  { K_PAD_HOME,       '7',            K_HOME },    /* 0x48 */  { K_PAD_UP,         '8',            K_UP },    /* 0x49 */  { K_PAD_PAGEUP,     '9',            K_PAGEUP },    /* 0x4A */  { K_PAD_MINUS,      '-',            0 },    /* 0x4B */  { K_PAD_LEFT,       '4',            K_LEFT },    /* 0x4C */  { K_PAD_MID,        '5',            0 },    /* 0x4D */  { K_PAD_RIGHT,      '6',            K_RIGHT },    /* 0x4E */  { K_PAD_PLUS,       '+',            0 },    /* 0x4F */  { K_PAD_END,        '1',            K_END },    /* 0x50 */  { K_PAD_DOWN,       '2',            K_DOWN },    /* 0x51 */  { K_PAD_PAGEDOWN,   '3',            K_PAGEDOWN },    /* 0x52 */  { K_PAD_INS,        '0',            K_INSERT },    /* 0x53 */  { K_PAD_DOT,        '.',            K_DELETE },    /* 0x54 */  { 0,                0,              0 },    /* 0x55 */  { 0,                0,              0 },    /* 0x56 */  { 0,                0,              0 },    /* 0x57 */  { K_F11,            K_F11,          0 },        /* 0x58 */  { K_F12,            K_F12,          0 },        /* 0x59 */  { 0,                0,              0 },        /* 0x5A */  { 0,                0,              0 },        /* 0x5B */  { 0,                0,              K_GUI_L },      /* 0x5C */  { 0,                0,              K_GUI_R },      /* 0x5D */  { 0,                0,              K_APPS },       /* 0x5E */  { 0,                0,              0 },        /* 0x5F */  { 0,                0,              0 },    /* 0x60 */  { 0,                0,              0 },    /* 0x61 */  { 0,                0,              0 },        /* 0x62 */  { 0,                0,              0 },        /* 0x63 */  { 0,                0,              0 },        /* 0x64 */  { 0,                0,              0 },        /* 0x65 */  { 0,                0,              0 },        /* 0x66 */  { 0,                0,              0 },        /* 0x67 */  { 0,                0,              0 },        /* 0x68 */  { 0,                0,              0 },        /* 0x69 */  { 0,                0,              0 },        /* 0x6A */  { 0,                0,              0 },        /* 0x6B */  { 0,                0,              0 },        /* 0x6C */  { 0,                0,              0 },        /* 0x6D */  { 0,                0,              0 },        /* 0x6E */  { 0,                0,              0 },        /* 0x6F */  { 0,                0,              0 },        /* 0x70 */  { 0,                0,              0 },        /* 0x71 */  { 0,                0,              0 },        /* 0x72 */  { 0,                0,              0 },        /* 0x73 */  { 0,                0,              0 },        /* 0x74 */  { 0,                0,              0 },        /* 0x75 */  { 0,                0,              0 },        /* 0x76 */  { 0,                0,              0 },        /* 0x77 */  { 0,                0,              0 },        /* 0x78 */  { 0,                0,              0 },        /* 0x78 */  { 0,                0,              0 },        /* 0x7A */  { 0,                0,              0 },            /* 0x7B */  { 0,                0,              0 },        /* 0x7C */  { 0,                0,              0 },        /* 0x7D */  { 0,                0,              0 },        /* 0x7E */  { 0,                0,              0 },    /* 0x7F */  { 0,                0,              0 },};class keyboard_t {public:    keyboard_t();    ~keyboard_t();    void init();    void do_irq();    int32 read();private:    queue_t m_queue;    uint8 m_shift_l;    uint8 m_shift_r;    uint8 m_leading_e0;};#endif

上面代码主要参考了linux,是简化版,主要功能是实现对扫描码的分类及到相应字符的对应。

/* * guzhoudiaoke@126.com * 2017-10-27 */#include "babyos.h"#include "keyboard.h"#include "x86.h"#include "arch.h"keyboard_t::keyboard_t(){}keyboard_t::~keyboard_t(){}void keyboard_t::do_irq(){    uint8 scan_code = inb(0x60);                        /* read scan code */    if (!m_queue.full())    {        m_queue.en_queue(scan_code);        }    outb(0x20, 0x20);}void keyboard_t::init(){    //console()->kprintf(WHITE, "keyboard_t::init()\n");    os()->get_arch()->get_8259a()->enable_irq(IRQ_KEYBOARD);        /* enable keyboard interrupt */    m_queue.init();    m_shift_l = 0;    m_shift_r = 0;    m_leading_e0 = 0;}int32 keyboard_t::read(){    uint8 scan_code = 0, shift = 0;    uint32 col = 0, key = 0;    if (!m_queue.empty())    {        m_queue.de_queue(&scan_code);        /* set m_leading_e0 */        if (scan_code == 0xe0)        {            m_leading_e0 = 1;            return 0;        }        /* key up */        if (scan_code & 0x80)        {            key = keymap[scan_code & 0x7f][col];            if (key == K_SHIFT_L) {                m_shift_l = 0;            }            if (key == K_SHIFT_R) {                m_shift_r = 0;            }            return 0;        }        shift = m_shift_l || m_shift_r;        col = shift ? 1 : 0;        if (m_leading_e0)        {            col = 2;            m_leading_e0 = 0;        }        key = keymap[scan_code & 0x7f][col];        if (key == K_SHIFT_L) {            m_shift_l = 1;        }        if (key == K_SHIFT_R) {            m_shift_r = 1;        }        shift = m_shift_l || m_shift_r;        if (key == K_ENTER) {            key = '\n';        }        else if (key == K_TAB) {            key = '\t';        }        else if (key == K_BACKSPACE) {            key = '\b';        }        else if (KEY_TYPE(key) != KT_ASCII) {            return 0;        }        return key;    }    return 0;}

do_irq通过端口0x60读取一个扫描码,然后加入到队列中去。之后当有需要读取按键内容时,调用read从队列读取,并分析按键。
目前的处理比较简单,只是返回了对应的字符。

        case IRQ_0 + IRQ_KEYBOARD:            os()->get_arch()->get_keyboard()->do_irq();            ch = os()->get_arch()->get_keyboard()->read();            if (ch != 0) {                console()->kprintf(WHITE, "%c", ch);            }            break;

然后简单的打印下相应的字符。
这里写图片描述
如上图所示,hello babyos这段代码是通过键盘中断敲上去的。

/* * guzhoudiaoke@126.com * 2017-10-28 */#ifndef _TIMER_H_#define _TIMER_H_#include "types.h"#define HZ              (100)#define CLOCK_TICK_RATE (1193180)class timer_t {public:    timer_t();    ~timer_t();    void init();    void do_irq();    uint64 get_tick();private:    uint64 m_tick;};/* * guzhoudiaoke@126.com * 2017-10-28 */#include "timer.h"#include "babyos.h"#include "arch.h"#include "x86.h"timer_t::timer_t(){}timer_t::~timer_t(){}void timer_t::init(){    m_tick = 0;    uint32 val = CLOCK_TICK_RATE / HZ;    /* control */    outb(0x43, 0x36);    /* clock 0 */    outb(0x40, uint8(val & 0xff));    outb(0x40, uint8(val >> 8));    os()->get_arch()->get_8259a()->enable_irq(IRQ_TIMER);       /* enable keyboard interrupt */}void timer_t::do_irq(){    m_tick++;    /* EOI */    outb(0x20, 0x20);}uint64 timer_t::get_tick(){    return m_tick;}

时钟中断比较简单,初始化时计算怎样让时钟中断频率为100HZ,即1s中断100次。do_irq时只是增加tick计数,并发送EOI。

class rtc_t {public:    rtc_t();    ~rtc_t();    void init();    void update();    uint32 year() { return m_year; }    uint32 month() { return m_month; }    uint32 day() { return m_day; }    uint32 hour() { return m_hour; }    uint32 minute() { return m_minute; }    uint32 second() { return m_second; }private:    void get_time();    uint8 bcd_to_binary(uint8 bcd);private:    uint8 m_year;    uint8 m_month;    uint8 m_day;    uint8 m_hour;    uint8 m_minute;    uint8 m_second;    uint32 m_tick_to_update;};void rtc_t::init(){    m_tick_to_update = HZ;    get_time();}void rtc_t::update(){    if (--m_tick_to_update != 0) {        return;    }    m_tick_to_update = HZ;    m_second++;    /* every 1 minute, re-read rtc from cmos */    if (m_second == 60) {        get_time();    }}void rtc_t::get_time(){    m_year  = bcd_to_binary(cmos_read(9));    m_month = bcd_to_binary(cmos_read(8));    m_day   = bcd_to_binary(cmos_read(7));    m_hour  = bcd_to_binary(cmos_read(4));    m_minute= bcd_to_binary(cmos_read(2));    m_second= bcd_to_binary(cmos_read(0));}uint8 rtc_t::bcd_to_binary(uint8 bcd){    return (bcd >> 4) * 10 + (bcd & 0xf);}

实时钟通过读取CMOS获取当前时间。
这里写图片描述

原创粉丝点击