鼠標控制與32位模式切換

Day8 鼠標控制與32位模式切換
對HariMain中的數據進行修改

enable_mouse();
    mouse_phase = 0; /* 進入到等待鼠標的0xfa的狀態 */

    for (;;) {
        io_cli();
        if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {
            io_stihlt();
        } else {
            if (fifo8_status(&keyfifo) != 0) {
                i = fifo8_get(&keyfifo);
                io_sti();
                sprintf(s, "%02X", i);
                boxfill8(binfo->vram, binfo->scrnx, COL8_008484,  0, 16, 15, 31);
                putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
            } else if (fifo8_status(&mousefifo) != 0) {
                i = fifo8_get(&mousefifo);
                io_sti();
                if (mouse_phase == 0) {
                    /* 等待鼠標0xfa的狀態*/
                    if (i == 0xfa) {
                        mouse_phase = 1;
                    }
                } else if (mouse_phase == 1) {
                    /*等待鼠標第一字節*/
                    mouse_dbuf[0] = i;
                    mouse_phase = 2;
                } else if (mouse_phase == 2) {
                    /*等待鼠標第二字節*/
                    mouse_dbuf[1] = i;
                    mouse_phase = 3;
                } else if (mouse_phase == 3) {
                    /*等待鼠標0xfa第三字節*/
                    mouse_dbuf[2] = i;
                    mouse_phase = 1;
                    /* 鼠標的三個字節都齊了,顯示出來 */
                    sprintf(s, "%02X %02X %02X", mouse_dbuf[0], mouse_dbuf[1], mouse_dbuf[2]);
                    boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 8 * 8 - 1, 31);
                    putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
                }
            }
        }
    }

2.稍事整理

    struct MOUSE_DEC {
    unsigned char buf[3], phase;
};

用一個結構體把鼠標所需要的變量都放在這裏。另外將鼠標的解讀處理放到了mouse_decode函數中。

3.鼠標解讀(2)

int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{
    if (mdec->phase == 0) {
        /* 等待鼠標的0xfa階段*/
        if (dat == 0xfa) {
            mdec->phase = 1;
        }
        return 0;
    }
    if (mdec->phase == 1) {
        /*等待鼠標的第一字節階段 */
        if ((dat & 0xc8) == 0x08) {
            /* 正しい1バイト目だった */
            mdec->buf[0] = dat;
            mdec->phase = 2;
        }
        return 0;
    }
    if (mdec->phase == 2) {
        /*等待鼠標的第二字節階段*/
        mdec->buf[1] = dat;
        mdec->phase = 3;
        return 0;
    }
    if (mdec->phase == 3) {
        /*等待鼠標的第三字節階段*/
        mdec->buf[2] = dat;
        mdec->phase = 1;
        mdec->btn = mdec->buf[0] & 0x07;
//取出低三位,作爲鼠標鍵的狀態
        mdec->x = mdec->buf[1];
        mdec->y = mdec->buf[2];
        if ((mdec->buf[0] & 0x10) != 0) {
            mdec->x |= 0xffffff00;
        }
        if ((mdec->buf[0] & 0x20) != 0) {
            mdec->y |= 0xffffff00;
        }
        mdec->y = - mdec->y; /* 鼠標y方向與畫面符號方向相反 */
        return 1;
    }
    return -1; /*應該不會到這兒來 */
}


else if (fifo8_status(&mousefifo) != 0) {
                i = fifo8_get(&mousefifo);
                io_sti();
                if (mouse_decode(&mdec, i) != 0) {
                    /* 數據的三個字節都齊了,顯示出來 */
                    sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
                    if ((mdec.btn & 0x01) != 0) {
                        s[1] = 'L';
                    }
                    if ((mdec.btn & 0x02) != 0) {
                        s[3] = 'R';
                    }
                    if ((mdec.btn & 0x04) != 0) {
                        s[2] = 'C';
                    }
//鼠標鍵被按下的時候大寫,否則小寫
                    boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
                    putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);

4.移動鼠標指針

else if (fifo8_status(&mousefifo) != 0) {
                i = fifo8_get(&mousefifo);
                io_sti();
                if (mouse_decode(&mdec, i) != 0) {
                    /* 數據的三個字節都齊了*/
                    sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
                    if ((mdec.btn & 0x01) != 0) {
                        s[1] = 'L';
                    }
                    if ((mdec.btn & 0x02) != 0) {
                        s[3] = 'R';
                    }
                    if ((mdec.btn & 0x04) != 0) {
                        s[2] = 'C';
                    }
                    boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
                    putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
                    /* 鼠標指針的移動 */
                    boxfill8(binfo->vram, binfo->scrnx, COL8_008484, mx, my, mx + 15, my + 15); /* 隱藏鼠標 */
                    mx += mdec.x;
                    my += mdec.y;
                    if (mx < 0) {
                        mx = 0;
                    }
                    if (my < 0) {
                        my = 0;
                    }
                    if (mx > binfo->scrnx - 16) {
                        mx = binfo->scrnx - 16;
                    }
                    if (my > binfo->scrny - 16) {
                        my = binfo->scrny - 16;
                    }
                    sprintf(s, "(%3d, %3d)", mx, my);
                    boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 0, 79, 15); /* 隱藏座標*/
                    putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s); /* 顯示座標*/
                    putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16); /* 描畫鼠標 */
                }

5.通往32位模式之路

; PIC關閉一切中斷
;根據AT兼容機的規則,如果要初始化PIC必須在CLI之前執行。否則有時會掛起。
;隨後進行PIC的初始化

        MOV     AL,0xff
        OUT     0x21,AL
        NOP                     ; 如果連續執行OUT指令,有些機種會無法執行
        OUT     0xa1,AL

        CLI                     ; 禁止CPU級別的中斷

這段程序用來禁止中斷

;爲了讓CPU能夠訪問1MB以上的內存空間,設定A20GATE

    CALL     waitkbdout
    MOV     AL,0xd1
    OUT     0x64,AL
    CALL    waitkbdout
    MOV     AL,0xdf         ; enable A20
    OUT     0x60,AL
    CALL    waitkbdout

;切換到保護模式

[INSTRSET "i486p"]              ;想要使用484指令的敘述

        LGDT    [GDTR0]         ; 設定臨時GDT
        MOV     EAX,CR0
        AND     EAX,0x7fffffff  ; 設bit31爲0(爲了禁止)
        OR      EAX,0x00000001  ;設bit0爲1(爲了切換到保護模式)
        MOV     CR0,EAX
        JMP     pipelineflush
pipelineflush:
        MOV     AX,1*8          ; 可讀寫的段32bit
        MOV     DS,AX
        MOV     ES,AX
        MOV     FS,AX
        MOV     GS,AX
        MOV     SS,AX
; bootpack的轉送

        MOV     ESI,bootpack    ; 轉送元
        MOV     EDI,BOTPAK      ; 轉送目的地
        MOV     ECX,512*1024/4
        CALL    memcpy

; 磁盤數據最終轉送到他本來的位置去

; 首先從啓動盤開始

        MOV     ESI,0x7c00      ; 轉送元
        MOV     EDI,DSKCAC      ; 轉送元

        MOV     ECX,512/4
        CALL    memcpy

; 所有剩下的

        MOV     ESI,DSKCAC0+512 ; 轉送元

        MOV     EDI,DSKCAC+512  ; 轉送元
        MOV     ECX,0
        MOV     CL,BYTE [CYLS]
        IMUL    ECX,512*18*2/4  ; 從柱面數變換爲字節數/4
        SUB     ECX,512/4       ; 減去IPL
        CALL    memcpy

//以上15行函數只是在調用memset函數。
memset(轉送源地址,轉送目的地址,轉送數據大小)

;必須由asmhead完成的工作完畢,之後就有bootpack完成

;   bootpack的啓動

        MOV     EBX,BOTPAK
        MOV     ECX,[EBX+16]
        ADD     ECX,3           ; ECX += 3;
        SHR     ECX,2           ; ECX /= 4;
        JZ      skip            ; 轉送元
        MOV     ESI,[EBX+20]    ; 轉送元
        ADD     ESI,EBX
        MOV     EDI,[EBX+12]    ; 轉送元
        CALL    memcpy
skip:
        MOV     ESP,[EBX+12]    ; 棧初始值
        JMP     DWORD 2*8:0x0000001b
waitkbdout:
        IN       AL,0x64          
        AND      AL,0x02             ;空讀
        JNZ     waitkbdout      ; AND的結果如果不是0就跳轉到waitkbdout
        RET
memcpy:
        MOV     EAX,[ESI]
        ADD     ESI,4
        MOV     [EDI],EAX
        ADD     EDI,4
        SUB     ECX,1
        JNZ     memcpy          ; 減法運算的結果如果不是0就跳轉到memcpy
        RET

        ALIGNB  16
GDT0:
        RESB    8               ; null  selector
        DW      0xffff,0x0000,0x9200,0x00cf ;可以讀寫的段32位
        DW      0xffff,0x0000,0x9a28,0x0047 ; 可以執行的段32位

        DW      0
GDTR0:
        DW      8*3-1
        DD      GDT0

        ALIGNB  16

bootpack:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章