自制操作系統day7(獲取按鍵編碼、FIFO緩沖區、鼠標、鍵盤控制器(Keyboard Controller, KBC)、PS/2協議)

day7


獲取按鍵編碼(hiarib04a)


void inthandler21(int *esp)
{struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;  // 獲取系統啟動信息結構體指針unsigned char data, s[4];                                   // data: 鍵盤數據緩存,s: 格式化字符串緩存io_out8(PIC0_OCW2, 0x61);     // 發送EOI命令(0x61)通知PIC中斷處理完成// 具體說明:
// 1. PIC0_OCW2 是主PIC的操作命令字寄存器(端口地址0x20)
// 2. 0x61 的二進制形式是 01100001,其中:
//    - 高三位 011 表示「指定IRQ級別的EOI命令」
//    - 低五位 00001 表示IRQ1(鍵盤中斷)
// 3. 該操作完成兩個功能:
//    a. 清除PIC的中斷服務寄存器(ISR)對應位
//    b. 允許PIC繼續接收新的中斷請求data = io_in8(PORT_KEYDAT);                                 // 從鍵盤數據端口讀取掃描碼sprintf(s, "%02X", data);                                   // 將掃描碼轉為16進制字符串boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31); // 清空顯示區域(青灰色背景)putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s); // 顯示白色文本的掃描碼return;
}

這句話用來通知PIC“已經知道發生了IRQ1中斷哦”。如果是IRQ3,則寫成0x63。也就是說,將“0x60+IRQ號碼”輸出給OCW2就可以。執行這句話之后,PIC繼續時刻監視IRQ1中斷是否發生。

如果忘記了執行這句話,PIC就不再監視IRQ1中斷,不管下次由鍵盤輸入什么信息,系統都感知不到了。

從編號為0x0060的設備輸入的8位信息是按鍵編碼。編號為0x0060的設備就是鍵盤。


加快中斷處理(hiarib04b


struct KEYBUF {unsigned char data, flag;
};
#define PORT_KEYDAT		0x0060struct KEYBUF keybuf;
void inthandler21(int *esp)
{unsigned char data;io_out8(PIC0_OCW2, 0x61);	data = io_in8(PORT_KEYDAT);if (keybuf.flag == 0) {keybuf.data = data;keybuf.flag = 1;}return;
}
for (;;) {io_cli();//如果flag是0,
//表示緩沖區為空;如果flag是1,就表示緩沖區中存有數據if (keybuf.flag == 0) {io_stihlt();} else {i = keybuf.data;keybuf.flag = 0;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);}}

io_sti();io_hlt();不等于io_stihlt();

如果io_sti()之后產生了中斷,keybuf里就會存入數據,這時候讓CPU進入HLT狀態,keybuf里存入的數據就不會被覺察到。根據CPU的規范,機器語言的STI指令之后,如果緊跟著HLT指令,那么就暫不受理這兩條指令之間的中斷,而要等到HLT指令之后才受理,

緩沖區建立優點:

  1. 異步處理機制:鍵盤中斷(IRQ1)發生時需要立即響應,但此時系統可能正在處理其他任務。緩沖區作為數據的中轉站,允許中斷處理程序快速保存數據后立即返回
  2. 防止數據丟失:當用戶快速連續按鍵時,中斷可能連續觸發。緩沖區可以存儲多個按鍵數據(雖然當前實現是單緩沖區,后續可以擴展為隊列)
  3. 線程安全:通過flag標志位(keybuf.flag)實現簡單的同步機制,避免主程序讀取數據時與中斷程序發生競爭
  4. 解耦硬件操作:將底層硬件讀取(io_in8)與上層邏輯處理分離,提高代碼的可維護性

自此中斷處理和調用流程

  1. 中斷向量表初始化?(在?int.c?的 PIC 初始化中)
int.
// PIC初始化時設置中斷向量號
io_out8(PIC0_ICW2, 0x20);  // IRQ0-7對應INT 0x20-0x27
io_out8(PIC1_ICW2, 0x28);  // IRQ8-15對應INT 0x28-0x2f
  1. 匯編層中斷門處理?(在?naskfunc.nas?中實現)
naskfunc.nas
_asm_inthandler21: ; 對應鍵盤中斷(IRQ1)PUSH    ESPUSH    DSPUSHADMOV     EAX,ESPPUSH    EAXMOV     AX,SSMOV     DS,AXMOV     ES,AXCALL    _inthandler21 ; 調用C語言處理函數POP     EAXPOPADPOP     DSPOP     ESIRETD
  1. C語言中斷服務程序?(在?int.c?中實現)
int.c
// 鍵盤中斷處理程序
void inthandler21(int *esp) {unsigned char data;io_out8(PIC0_OCW2, 0x61); // 通知PIC中斷處理完成data = io_in8(PORT_KEYDAT); // 讀取鍵盤數據// ... 緩沖區處理 ...
}

完整的中斷調用流程:

  1. 硬件中斷觸發 → 2. CPU查IDT表 → 3. 跳轉至_asm_inthandlerXX → 4. 保存上下文 → 5. 調用C處理函數 → 6. 恢復上下文 → 7. IRETD返回

制作FIFO緩沖區(hiarib04c


就是將緩沖區的數據部分弄成鏈表,但這里是靜態數組,到下面整理緩沖區就是動態分配內存了

struct KEYBUF {unsigned char data[32];int next;
};
void inthandler21(int *esp)
{unsigned char data;io_out8(PIC0_OCW2, 0x61);data = io_in8(PORT_KEYDAT);if (keybuf.next < 32) {keybuf.data[keybuf.next] = data;keybuf.next++;}return;
}
for (;;) {io_cli();if (keybuf.next == 0) {io_stihlt();} else {i = keybuf.data[0];keybuf.next--;for (j = 0; j < keybuf.next; j++) {keybuf.data[j] = keybuf.data[j + 1];}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);}}

但這個程序,中斷處理的時候涉及數據移送操作,如果在數據移送前中斷的話,數據就會亂

所以下面就改善一下


改善FIFO緩沖區(hiarib04d


其實就是一個雙指針,一個讀數據指針,一個寫數據指針

寫的時候直接覆蓋寫,到了len最大容量就歸0


整理FIFO緩沖區(hiarib04e


struct FIFO8 {unsigned char *buf;int p, q, size, free, flags;
};
/*可變緩沖區,size存入緩沖區的總字節數,變量free保存緩沖區里美歐數據的字節數,
buf存緩沖區的地址,p代表下一個數據寫入地址(next_w),q代表下一個數據讀出地址
(next_r)。
*/
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
/* 初始化FIFO緩沖區 */
{
fifo->size = size;
fifo->buf = buf;
fifo->free = size; /* 緩沖區的大小 */
fifo->flags = 0;
fifo->p = 0; /* 下一個數據寫入位置 */
fifo->q = 0; /* 下一個數據讀出位置 */
return;
}
#define FLAGS_OVERRUN 0x0001
int fifo8_put(struct FIFO8 *fifo, unsigned char data)
/* 向FIFO傳送數據并保存 */
{
if (fifo->free == 0) {
/* 空余沒有了,溢出 */
fifo->flags |= FLAGS_OVERRUN;
return -1;
}
fifo->buf[fifo->p] = data;
fifo->p++;
if (fifo->p == fifo->size) {
fifo->p = 0;
}
fifo->free--;
return 0;
}
int fifo8_get(struct FIFO8 *fifo)
/* 從FIFO取得一個數據 */
{
int data;
if (fifo->free == fifo->size) {
/* 如果緩沖區為空,則返回 -1 */
return -1;
}
data = fifo->buf[fifo->q];
fifo->q++;
if (fifo->q == fifo->size) {
fifo->q = 0;
}
fifo->free++;
return data;
}
int fifo8_status(struct FIFO8 *fifo)
/* 報告一下到底積攢了多少數據 */
{
return fifo->size - fifo->free;
}

鼠標(harib04f


#define PORT_KEYDAT 0x0060
#define PORT_KEYSTA 0x0064
#define PORT_KEYCMD 0x0064
#define KEYSTA_SEND_NOTREADY 0x02
#define KEYCMD_WRITE_MODE 0x60
#define KBC_MODE 0x47
void wait_KBC_sendready(void)
{
/* 等待鍵盤控制電路準備完畢 */
for (;;) {
if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
break;
}
}
return;
//鍵盤控制電路(keyboard controller, KBC)做好準備動作,等待控制指令的到來。
//因為雖然CPU的電路很快,但鍵盤控制電路卻沒有那么快。
//如果鍵盤控制電路可以接受CPU指令了,CPU從設備號碼0x0064處所讀
//取的數據的倒數第二位(從低位開始數的第二位)應該是0。在確認到這一位是0之前,程序一直通過for語句循環查詢。
}
void init_keyboard(void)
{
/* 初始化鍵盤控制電路 
一邊確認可否往鍵盤
控制電路傳送信息,一邊發送模式設定指令,指令中包含著要設定為何種模式。模
式設定的指令是0x60,利用鼠標模式的模式號碼是0x47,*/
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}

鍵盤控制器(Keyboard Controller, KBC)

i8042 鍵盤控制器-------詳細介紹 - LinKArftc - 博客園 (cnblogs.com)

在x86架構中,鍵盤控制器(Keyboard Controller, KBC)通過特定端口與CPU通信。以下是代碼中涉及的端口地址、宏定義和函數的詳細解釋:


一、端口地址定義

宏定義端口地址功能描述
PORT_KEYDAT0x0060鍵盤數據端口:用于讀取鍵盤掃描碼或發送鍵盤配置參數。
PORT_KEYSTA0x0064鍵盤狀態端口:讀取鍵盤控制器的狀態(如是否準備好接收命令)。
PORT_KEYCMD0x0064鍵盤命令端口:向鍵盤控制器發送控制命令(與狀態端口共享地址,操作區分方向)。

二、關鍵宏定義

宏定義功能描述
KEYSTA_SEND_NOTREADY0x02狀態寄存器中的“發送未就緒”標志位:若該位為1,表示控制器忙,不能接收新命令。
KEYCMD_WRITE_MODE0x60鍵盤控制器的命令:寫入操作模式到配置字節。
KBC_MODE0x47鍵盤控制器的工作模式參數:啟用鍵盤和鼠標接口,并設置掃描碼轉換模式。

三、函數解析

1. wait_KBC_sendready()

void wait_KBC_sendready(void) {for (;;) {if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {break;}}return;
}
  • 功能:等待鍵盤控制器準備好接收命令。
  • 實現
    1. 循環讀取狀態端口(0x0064)。
    2. 檢查狀態寄存器的第1位(KEYSTA_SEND_NOTREADY):
      • 若為0,表示控制器就緒,退出循環。
      • 若為1,繼續等待。

2. init_keyboard()

void init_keyboard(void) {wait_KBC_sendready();io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);  // 發送模式設置命令wait_KBC_sendready();io_out8(PORT_KEYDAT, KBC_MODE);           // 寫入模式參數return;
}
  • 功能:初始化鍵盤控制器的工作模式。
  • 流程
    1. 等待控制器就緒。
    2. 向命令端口(0x0064)發送命令 0x60KEYCMD_WRITE_MODE),表示要寫入配置字節。
    3. 再次等待控制器就緒。
    4. 向數據端口(0x0060)寫入模式參數 0x47KBC_MODE),配置控制器行為。

四、配置字節?0x47?的位定義

名稱功能
7Reserved保留位,必須設為0。
6Translation Mode1=啟用掃描碼轉換(將XT鍵盤掃描碼集1轉換為AT鍵盤掃描碼集2)。
5Second Port Clock0=啟用鼠標接口(PS/2 Port 2)。
4First Port Clock0=啟用鍵盤接口(PS/2 Port 1)。
3Ignore Lock Keys0=正常處理鎖定鍵(如Caps Lock)。
2System Flag由BIOS設置的系統標志(通常設為0)。
1Second Port IRQ1=啟用鼠標中斷(IRQ12)。
0First Port IRQ1=啟用鍵盤中斷(IRQ1)。

0x47(二進制?01000111)的具體配置

作用
70保留位為0,符合規范。
61啟用掃描碼轉換(將XT掃描碼轉換為AT掃描碼,增強兼容性)。
50啟用鼠標接口(允許鼠標數據傳輸)。
40啟用鍵盤接口(允許鍵盤數據傳輸)。
30正常處理Caps Lock等鎖定鍵。
20系統標志為0(通常由BIOS設置)。
11啟用鼠標中斷(IRQ12),允許鼠標事件觸發中斷。
01啟用鍵盤中斷(IRQ1),允許鍵盤事件觸發中斷。

五、硬件交互原理

  1. 端口I/O操作
    • io_in8(port):從指定端口讀取1字節數據。
    • io_out8(port, data):向指定端口寫入1字節數據。
    • 在x86中,端口地址空間獨立于內存地址空間,需通過IN/OUT指令訪問。
  2. 鍵盤控制器流程
    • 發送命令:向PORT_KEYCMD0x0064)寫入命令字節。
    • 寫入參數:向PORT_KEYDAT0x0060)寫入命令參數(如模式字節)。
    • 狀態檢查:從PORT_KEYSTA0x0064)讀取狀態,確保操作安全。

六、代碼的意義

這段代碼的目標是配置鍵盤控制器以支持鍵盤和鼠標輸入,具體作用包括:

  1. 啟用鍵盤接口(允許接收按鍵掃描碼)。
  2. 啟用鼠標接口(為后續鼠標驅動做準備)。
  3. 設置掃描碼轉換模式,確保兼容性。

七、實際應用場景

  • 操作系統啟動初期:在初始化輸入設備時調用init_keyboard(),確保鍵盤可用。
  • 外設驅動開發:理解端口通信是編寫鍵盤/鼠標驅動的基礎。

總結

這段代碼通過操作鍵盤控制器的端口,配置其工作模式,為后續處理鍵盤和鼠標輸入奠定基礎。理解端口地址、狀態標志和配置字節的細節,是開發操作系統輸入子系統的關鍵一步。

發送鼠標激活指令

#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
void enable_mouse(void)
{
/* 激活鼠標 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
return; /* 順利的話,鍵盤控制其會返送回ACK(0xfa)*/
}

在x86架構中,PS/2鍵盤控制器(KBC)負責管理鍵盤和鼠標的通信。以下是代碼的逐層解析:


一、關鍵宏定義

宏定義功能描述
KEYCMD_SENDTO_MOUSE0xD4鍵盤控制器命令:指示下一個寫入數據端口的字節將發送到鼠標(而非鍵盤)。
MOUSECMD_ENABLE0xF4鼠標命令:啟用鼠標數據報告模式(開始發送移動/按鍵事件)。

二、代碼流程分析

函數 enable_mouse()

void enable_mouse(void) {wait_KBC_sendready();            // 等待KBC就緒io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);  // 發送命令0xD4到命令端口(0x64)wait_KBC_sendready();            // 再次等待KBC就緒io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);      // 發送命令0xF4到數據端口(0x60)return;  // 正常情況下,KBC會返回ACK(0xFA)
}

三、分步詳解

1. wait_KBC_sendready()

  • 作用:確保鍵盤控制器(KBC)可接收新命令。
  • 實現:循環讀取狀態端口(0x64),直到狀態寄存器的“發送未就緒”位(KEYSTA_SEND_NOTREADY=0x02)為0。

2. 發送命令 0xD4 到命令端口(0x64

  • 目的:通知KBC,下一個寫入數據端口(0x60)的字節是發送給鼠標的指令(而非鍵盤)。
  • PS/2協議:鍵盤和鼠標共享同一控制器,通過此命令區分目標設備。

3. 發送命令 0xF4 到數據端口(0x60

  • 作用:向鼠標發送“啟用數據報告”指令。此后,鼠標將開始發送移動和按鍵事件數據包。
  • 響應:鼠標應返回0xFA(ACK確認),表示指令已接收。

四、硬件交互邏輯

  1. KBC與設備的通信鏈

    CPU → KBC命令端口(0x64) → 發送命令0xD4 → KBC → 轉發到鼠標
    CPU → KBC數據端口(0x60) → 發送數據0xF4 → KBC → 轉發到鼠標
  2. ACK確認機制

    • 鼠標收到有效指令后,會通過KBC返回0xFA(需通過中斷或輪詢讀取數據端口獲取)。
    • 此代碼未處理ACK,可能依賴后續中斷服務程序(ISR)處理。

五、技術細節

1. 鍵盤控制器狀態寄存器(PORT_KEYSTA=0x64)

名稱說明
0Output Buffer Full1=數據端口(0x60)有數據待讀取。
1Input Buffer Full1=控制器忙,不能接收命令(代碼檢查此位)。
2-7保留

2. 鼠標命令 0xF4 的作用

  • 啟用數據報告模式:鼠標持續發送數據包,格式為3字節:

    Byte 1: Y溢出 | X溢出 | Y符號位 | X符號位 | 保留 | 中鍵 | 右鍵 | 左鍵
    Byte 2: X軸移動量(補碼)
    Byte 3: Y軸移動量(補碼)

六、實際應用場景

  • 操作系統初始化階段:在鍵盤初始化后調用此函數,激活鼠標輸入。
  • 驅動程序開發:理解PS/2協議是處理傳統輸入設備的基礎。

七、注意事項

  • ACK處理:需在中斷處理中捕獲0xFA,否則可能錯過鼠標數據。
  • 兼容性:現代硬件可能使用USB替代PS/2,需額外判斷設備存在性。
  • 錯誤處理:未收到ACK時需重試或報錯。

總結

此代碼通過鍵盤控制器向鼠標發送啟用指令,使其進入數據報告模式。核心步驟為:

  1. 等待控制器就緒 → 2. 聲明目標為鼠標 → 3. 發送啟用命令。
    理解PS/2協議和端口I/O操作是開發輸入設備驅動的關鍵。

PS/2協議解釋

PS/2協議是早期計算機用于連接鍵盤和鼠標的通信標準,盡管逐漸被USB取代,但在許多傳統系統和嵌入式設備中仍有應用。以下是其核心機制和關鍵細節的詳解:


一、物理接口與電氣特性

  1. 接口定義
    • PS/2接口為6針Mini-DIN,實際使用4針:

      引腳功能
      1數據線(DATA)
      3地線(GND)
      4VCC(+5V)
      5時鐘線(CLK)
  2. 通信方式
    • 同步串行傳輸:設備(鍵盤/鼠標)與主機(鍵盤控制器)通過CLK同步,DATA線傳輸數據。
    • 主從模式:默認設備控制CLK,主機可接管時鐘(如發送命令時)。

二、數據幀格式

每幀數據包含?11位,按順序如下:

名稱說明
1起始位0標志數據開始
8數據位0/1LSB(最低位)優先發送
1奇偶校驗位0/1奇校驗(數據位+校驗位的1個數為奇)
1停止位1標志數據結束

示例:鍵盤發送按鍵按下碼?0x1C(字母’A’的掃描碼)的幀結構:

0?0011100?1?1?→ 起始位 + 數據(二進制0011100,LSB優先為0011100) + 奇偶位 + 停止位。


三、通信方向與流程

1. 設備到主機(如按鍵事件)

  1. 設備檢測到動作(如按鍵按下),生成中斷(IRQ1鍵盤/IRQ12鼠標)。
  2. 設備拉低CLK并發送數據幀。
  3. 主機讀取DATA線,在CLK下降沿采樣數據位。

2. 主機到設備(如發送命令)

  1. 主機拉低CLK至少100μs,通知設備準備接收命令。
  2. 主機控制CLK,逐位發送命令幀。
  3. 設備在接收到命令后,返回ACK(0xFA)或錯誤碼。

四、關鍵命令與響應

1. 鍵盤常用命令

命令功能響應
重置0xFF復位鍵盤0xFA?+?0xAA
啟用掃描0xF4開始發送按鍵事件0xFA
設置LED0xED控制Num/Caps/Scroll燈0xFA

2. 鼠標常用命令

命令功能響應
重置0xFF復位鼠標0xFA?+?0xAA
啟用報告0xF4開始發送移動/按鍵數據0xFA
設置分辨率0xE8調整移動靈敏度0xFA

五、數據包格式

1. 鍵盤數據包

  • 單字節:傳輸按鍵的掃描碼(按下或釋放)。
    • 例如:0x1C(A鍵按下),0x9C(A鍵釋放,前綴0xF0表示釋放)。

2. 鼠標數據包

  • 標準3字節格式(兼容模式):

    字節位7-0
    Byte1Y溢出
    Byte2X軸移動量(8位補碼,-128~127)
    Byte3Y軸移動量(8位補碼,-128~127)

六、錯誤處理與重試

  1. 奇偶校驗錯誤:主機檢測到校驗錯誤時,可發送重傳命令(0xFE)。
  2. 超時:若設備未響應,主機可復位設備或記錄錯誤。
  3. ACK缺失:未收到0xFA時,主機應重發命令或初始化設備。

七、PS/2與USB的對比

特性PS/2USB
熱插拔不支持(可能損壞設備)支持
中斷機制專用IRQ(低延遲)輪詢或中斷傳輸
協議復雜度簡單(固定數據包)復雜(多種傳輸類型、描述符)
應用場景傳統設備、嵌入式系統現代外設、即插即用

八、操作系統中的實現

  1. 初始化流程
    • 啟用鍵盤/鼠標接口 → 發送重置命令 → 配置掃描碼模式。
  2. 中斷處理程序
    • 讀取數據端口(0x60) → 解析掃描碼或鼠標包 → 傳遞事件到上層。
  3. 緩沖區管理
    • 維護循環隊列存儲輸入事件,避免數據丟失。

總結

PS/2協議通過同步串行通信實現低延遲輸入,其核心在于時鐘同步、數據幀格式和命令響應機制。

從鼠標接受數據(harib04g


struct FIFO8 mousefifo;
void inthandler2c(int *esp)
/* 來自PS/2鼠標的中斷 */
{
unsigned char data;
io_out8(PIC1_OCW2, 0x64); /* 通知PIC1 IRQ-12的受理已經完成 */
io_out8(PIC0_OCW2, 0x62); /* 通知PIC0 IRQ-02的受理已經完成 */
data = io_in8(PORT_KEYDAT);
fifo8_put(&mousefifo, data);
return;
}

在x86系統中,處理來自PS/2鼠標的中斷(IRQ12)時,需要與可編程中斷控制器(PIC)交互以確認中斷處理完成。以下是代碼的詳細解釋:


一、代碼功能概述

這段代碼是處理PS/2鼠標中斷的中斷服務程序(ISR),主要完成以下操作:

  1. 通知PIC中斷處理完成:通過向主PIC和從PIC發送EOI(End of Interrupt)命令。
  2. 讀取鼠標數據:從鍵盤控制器數據端口獲取鼠標事件數據。
  3. 存儲數據到緩沖區:將數據存入FIFO隊列供后續處理。

二、關鍵代碼解析

1. 中斷處理流程

void inthandler2c(int *esp) {unsigned char data;// 通知PIC中斷處理完成io_out8(PIC1_OCW2, 0x64);  // 從PIC(IRQ12)的EOIio_out8(PIC0_OCW2, 0x62);  // 主PIC(IRQ2)的EOI// 讀取鼠標數據data = io_in8(PORT_KEYDAT);// 存入FIFO隊列fifo8_put(&mousefifo, data);return;
}

2. PIC的端口與命令

  • PIC1_OCW2:從PIC(PIC1)的操作命令字端口,地址為0xA0
  • PIC0_OCW2:主PIC(PIC0)的操作命令字端口,地址為0x20
  • EOI命令值0x640x62是特殊EOI命令,通知PIC中斷已處理。

三、PIC的EOI通知機制

1. 主從PIC的級聯

  • 主PIC(PIC0):處理IRQ0-IRQ7。
  • 從PIC(PIC1):處理IRQ8-IRQ15,其輸出連接到主PIC的IRQ2。
  • 中斷傳遞:當從PIC的IRQ12(鼠標中斷)觸發時,主PIC的IRQ2也會被激活。

2. 發送EOI命令的必要性

  • 目的:告訴PIC中斷處理已完成,允許其繼續響應新中斷。
  • 級聯場景:處理從PIC的中斷(如IRQ12)時,需向主從PIC均發送EOI。

3. 特殊EOI命令詳解

  • OCW2格式

    7 ?6 (SL)5 (EOI)4-0 (L3-L0)
    011中斷級別
  • 從PIC(IRQ12)的EOI命令0x64

    • 二進制:01100100
    • SL=1, EOI=1:表示發送特殊EOI命令。
    • L3-L0=0100:指定從PIC的中斷級別4(對應IRQ12 = IRQ8 + 4)。
  • 主PIC(IRQ2)的EOI命令0x62

    • 二進制:01100010
    • SL=1, EOI=1:特殊EOI命令。
    • L3-L0=0010:指定主PIC的中斷級別2(IRQ2)。

四、代碼執行步驟

  1. 發送EOI到從PIC

    io_out8(0xA0, 0x64); // 通知從PIC,IRQ4(即IRQ12)已處理
    • 從PIC收到命令后,清除IRQ4的中斷狀態。
  2. 發送EOI到主PIC

    io_out8(0x20, 0x62); // 通知主PIC,IRQ2(級聯中斷)已處理
    • 主PIC收到命令后,清除IRQ2的中斷狀態。
  3. 讀取鼠標數據

    data = io_in8(0x60); // 從鍵盤控制器數據端口讀取鼠標數據包
    • 數據端口0x60用于傳輸鍵盤和鼠標的輸入數據。
  4. 存儲數據到緩沖區

    fifo8_put(&mousefifo, data); // 將數據存入隊列供后續解析
    • 使用FIFO隊列避免中斷處理過程中數據丟失。

五、關聯硬件行為

  • 中斷觸發:鼠標移動或點擊時,鍵盤控制器通過IRQ12通知CPU。
  • PIC級聯:從PIC通過主PIC的IRQ2向CPU傳遞中斷。
  • 數據包格式:PS/2鼠標數據為3字節,需在后續代碼中解析。

六、常見問題

1. 為何需要同時通知主從PIC?

  • 從PIC的中斷通過主PIC的IRQ2級聯,需兩者均確認中斷完成,否則后續中斷會被阻塞。

2. 0x640x62如何計算?

  • 特殊EOI命令公式:OCW2 = 0x60 | (IRQ_LEVEL & 0x07)
    • 從PIC IRQ4:0x60 | 4 = 0x64
    • 主PIC IRQ2:0x60 | 2 = 0x62

3. 是否必須使用特殊EOI?

  • 常規EOI(0x20)僅適用于非特殊模式,級聯中斷需特殊EOI明確指定中斷級別。

總結

這段代碼通過向主從PIC發送特殊EOI命令,確保中斷處理正確完成,并讀取鼠標數據存入緩沖區。理解PIC的級聯機制和OCW2命令格式,是編寫可靠中斷處理程序的關鍵。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/81258.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/81258.shtml
英文地址,請注明出處:http://en.pswp.cn/web/81258.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Javase 基礎加強 —— 09 IO流第二彈

本系列為筆者學習Javase的課堂筆記&#xff0c;視頻資源為B站黑馬程序員出品的《黑馬程序員JavaAI智能輔助編程全套視頻教程&#xff0c;java零基礎入門到大牛一套通關》&#xff0c;章節分布參考視頻教程&#xff0c;為同樣學習Javase系列課程的同學們提供參考。 01 緩沖字節…

服務器操作系統調優內核參數(方便查詢)

fs.aio-max-nr1048576 #此參數限制并發未完成的異步請求數目&#xff0c;應該設置避免I/O子系統故障 fs.file-max1048575 #該參數決定了系統中所允許的文件句柄最大數目&#xff0c;文件句柄設置代表linux系統中可以打開的文件的數量 fs.inotify.max_user_watches8192000 #表…

[Windows] 格式工廠 FormatFactory v5.20.便攜版 ——多功能媒體文件轉換工具

想要輕松搞定各類媒體文件格式轉換&#xff1f;這款 Windows 平臺的格式工廠 FormatFactory v5.20 便攜版 正是你的不二之選&#xff01;無需安裝&#xff0c;即開即用&#xff0c;為你帶來高效便捷的文件處理體驗。 全能格式轉換&#xff0c;滿足多元需求 軟件功能覆蓋視頻、…

[AI]主流大模型、ChatGPTDeepseek、國內免費大模型API服務推薦(支持LangChain.js集成)

主流大模型特色對比表 模型核心優勢適用場景局限性DeepSeek- 數學/代碼能力卓越&#xff08;GSM8K準確率82.3%&#xff09;1- 開源生態完善&#xff08;支持醫療/金融領域&#xff09;7- 成本極低&#xff08;API價格僅為ChatGPT的2%-3%&#xff09;5科研輔助、代碼開發、數據…

國際薦酒師(香港)協會亮相新西蘭葡萄酒巡展深度參與趙鳳儀大師班

國際薦酒師&#xff08;香港&#xff09;協會率團亮相2025新西蘭葡萄酒巡展 深度參與趙鳳儀MW“百年百碧祺”大師班 廣州/上海/青島&#xff0c;2025年5月12-16日——國際薦酒師&#xff08;香港&#xff09;協會&#xff08;IRWA&#xff09;近日率專業代表團出席“純凈獨特&…

Node.js Express 項目現代化打包部署全指南

Node.js Express 項目現代化打包部署全指南 一、項目準備階段 1.1 依賴管理優化 # 生產依賴安裝&#xff08;示例&#xff09; npm install express mongoose dotenv compression helmet# 開發依賴安裝 npm install nodemon eslint types/node --save-dev1.2 環境變量配置 /…

java基礎知識回顧3(可用于Java基礎速通)考前,面試前均可用!

目錄 一、基本算數運算符 二、自增自減運算符 三、賦值運算符 四、關系運算符 五、邏輯運算符 六、三元運算符 七、 運算符的優先級 八、小案例&#xff1a;在程序中接收用戶通過鍵盤輸入的數據 聲明&#xff1a;本文章根據黑馬程序員b站教學視頻做的筆記&#xff0c;可…

隨機密碼生成器:原理、實現與應用(多語言實現)

在當今數字化的時代&#xff0c;信息安全至關重要。而密碼作為保護個人和敏感信息的第一道防線&#xff0c;其安全性直接關系到我們的隱私和數據安全。然而&#xff0c;許多人在設置密碼時往往使用簡單、易猜的組合&#xff0c;如生日、電話號碼或常見的單詞&#xff0c;這使得…

TypeScript 泛型講解

如果說 TypeScript 是一門對類型進行編程的語言&#xff0c;那么泛型就是這門語言里的&#xff08;函數&#xff09;參數。本章&#xff0c;我將會從多角度講解 TypeScript 中無處不在的泛型&#xff0c;以及它在類型別名、對象類型、函數與 Class 中的使用方式。 一、泛型的核…

SQL 每日一題(6)

繼續做題&#xff01; 原始表&#xff1a;employee_resignations表 employee_idresignation_date10012022-03-1510022022-11-2010032023-01-0510042023-07-1210052024-02-28 第一題&#xff1a; 查詢累計到每個年度的離職人數 結果輸出&#xff1a;年度、當年離職人數、累計…

工業RTOS生態重構:從PLC到“端 - 邊 - 云”協同調度

一、引言 在當今數字化浪潮席卷全球的背景下&#xff0c;工業領域正經歷著深刻變革。工業自動化作為制造業發展的基石&#xff0c;其技術架構的演進直接關系到生產效率、產品質量以及企業的市場競爭力。傳統的PLC&#xff08;可編程邏輯控制器&#xff09;架構雖然在工業控制領…

從版本控制到協同開發:深度解析 Git、SVN 及現代工具鏈

前言&#xff1a;在當今軟件開發的浪潮中&#xff0c;版本控制與協同開發無疑扮演著舉足輕重的角色。從最初的單兵作戰到如今大規模團隊的高效協作&#xff0c;一套成熟且得力的版本控制系統以及圍繞其構建的現代工具鏈&#xff0c;已然成為推動軟件項目穩步前行的關鍵引擎。今…

Visual Studio Code插件離線安裝指南:從市場獲取并手動部署

Visual Studio Code插件離線安裝指南&#xff1a;從市場獲取并手動部署 一、場景背景二、操作步驟詳解步驟1&#xff1a;訪問官方插件市場步驟2&#xff1a;定位目標版本步驟3&#xff1a;提取關鍵參數步驟4&#xff1a;構造下載鏈接步驟5&#xff1a;下載與安裝 三、注意事項 …

用HTML5實現實時ASCII藝術攝像頭

用HTML5實現實時ASCII藝術攝像頭 項目簡介 這是一個將攝像頭畫面實時轉換為ASCII字符藝術的Web應用&#xff0c;基于HTML5和原生JavaScript實現。通過本項目可以學習到&#xff1a; 瀏覽器攝像頭API的使用Canvas圖像處理技術實時視頻流處理復雜DOM操作性能優化技巧 功能亮點…

論文審稿之我對SCI寫作的思考

有幸被邀請審過二區、三區、四區期刊的論文&#xff0c;近期審稿10余篇&#xff0c;分享一下我從一個審稿人的角度出發&#xff0c;如何提升自己寫作的質量。 作圖高清和好看&#xff0c;永遠是排第一位。圖中的字要清晰&#xff0c;有的放大200%還看不清字&#xff1b;每幅圖的…

MLA:Transformer的智能變形金剛——解密多頭潛在注意力的進化密碼

第一章 MLA的進化之路&#xff1a;從MHA到智能變形 1.1 變形金剛的誕生背景 當LLM模型規模突破萬億參數量級時&#xff0c;傳統Transformer的注意力機制開始顯現"成長的煩惱"&#xff1a;訓練階段計算密集、推理階段內存吃緊。DeepSeek團隊的MLA如同給注意力模塊裝…

電子電路:電學都有哪些核心概念?

電子是基本粒子,帶負電荷。電荷是物質的一種屬性,電子帶有負電荷,而質子帶有正電荷。電荷的單位是庫侖。 電流呢,應該是指電荷的流動,單位是安培,也就是庫侖每秒。所以電流其實就是電荷在導體中的移動形成的。比如,當電子在導線中流動時,就形成了電流。不過要注意,傳…

第三次中醫知識問答模型微調

本次參數 llamafactory-cli train \ --stage sft \ --do_train True \ --model_name_or_path /home/qhyz/zxy/LLaMA-Factory/model \ --preprocessing_num_workers 16 \ --finetuning_type lora \ --template deepseek3 \ --flash_attn fa2 \ --dataset_dir data \ --dataset …

leetcode2081. k 鏡像數字的和-hard

1 題目&#xff1a;k 鏡像數字的和 官方標定難度&#xff1a;難 一個 k 鏡像數字 指的是一個在十進制和 k 進制下從前往后讀和從后往前讀都一樣的 沒有前導 0 的 正 整數。 比方說&#xff0c;9 是一個 2 鏡像數字。9 在十進制下為 9 &#xff0c;二進制下為 1001 &#xff…

計算機網絡學習(七)——IP

一、IP 在計算機網絡中&#xff0c;IP&#xff08;Internet Protocol&#xff0c;網際協議&#xff09;是網絡層的核心協議&#xff0c;用于實現跨越不同網絡的數據包傳輸。IP 是 TCP/IP 協議族的核心部分&#xff0c;屬于網絡層協議&#xff0c;也是 Internet 賴以運作的基礎…