?? rs_io.s
字號:
;/* passed;* linux/kernel/rs_io.s;*;* (C) 1991 Linus Torvalds;*/.386p
.model flat
;/*;* rs_io.s;*;* This module implements the rs232 io interrupts.;*/;/*;* 該程序模塊實現(xiàn)rs232 輸入輸出中斷處理程序。;*/;// size 是讀寫隊列緩沖區(qū)的字節(jié)長度。bsize = 1024 ;/* must be power of two ! 必須是2 的次方并且需 ; and must match the value 與tty_io.c 中的值匹配! ; in tty_io.c!!! */;/* these are the offsets into the read/write buffer structures */;/* 以下這些是讀寫緩沖結(jié)構(gòu)中的偏移量 */;// 對應(yīng)定義在include/linux/tty.h 文件中tty_queue 結(jié)構(gòu)中各變量的偏移量。rs_addr = 0 ;// 串行端口號字段偏移(端口號是0x3f8 或0x2f8)。head = 4 ;// 緩沖區(qū)中頭指針字段偏移。tail = 8 ;// 緩沖區(qū)中尾指針字段偏移。proc_list = 12 ;// 等待該緩沖的進程字段偏移。buf = 16 ;// 緩沖區(qū)字段偏移。startup = 256 ;/* chars left in write queue when we restart it */;/* 當(dāng)寫隊列里還剩256 個字符空間(WAKEUP_CHARS)時,我們就可以寫 */;/*;* These are the actual interrupt routines. They look where;* the interrupt is coming from, and take appropriate action.;*/;/*;* 這些是實際的中斷程序。程序首先檢查中斷的來源,然后執(zhí)行相應(yīng);* 的處理。;*/
extrn _table_list:dword, _do_tty_interrupt:proc
public _rs1_interrupt,_rs2_interrupt
.code
align 4;// 串行端口1 中斷處理程序入口點。_rs1_interrupt: push _table_list+8 ;// tty 表中對應(yīng)串口1 的讀寫緩沖指針的地址入棧(tty_io.c,99)。 jmp rs_intalign 4;// 串行端口2 中斷處理程序入口點。_rs2_interrupt: push _table_list+16 ;// tty 表中對應(yīng)串口2 的讀寫緩沖隊列指針的地址入棧。rs_int: push edx push ecx push ebx push eax push es push ds ;/* as this is an interrupt, we cannot */ push 10h ;/* know that bs is ok. Load it */ pop ds ;/* 由于這是一個中斷程序,我們不知道ds 是否正確,*/ push 10h ;/* 所以加載它們(讓ds、es 指向內(nèi)核數(shù)據(jù)段 */ pop es mov edx,24[esp] ;// 將緩沖隊列指針地址存入edx 寄存器,;// 也即35 或39 行上最先壓入堆棧的地址。 mov edx,[edx] ;// 取讀隊列指針(地址)->edx。 mov edx,rs_addr[edx] ;// 取串口1 的端口號??edx。 add edx,2 ;/* interrupt ident. reg */ /* edx 指向中斷標(biāo)識寄存器 */rep_int: ;// 中斷標(biāo)識寄存器端口是0x3fa(0x2fa),參見上節(jié)列表后信息。 xor eax,eax ;// eax 清零。 in al,dx ;// 取中斷標(biāo)識字節(jié),用以判斷中斷來源(有4 種中斷情況)。 test al,1 ;// 首先判斷有無待處理的中斷(位0=1 無中斷;=0 有中斷)。 jne end1 ;// 若無待處理中斷,則跳轉(zhuǎn)至退出處理處end。 cmp al,6 ;/* this shouldn't happen, but ... */ /* 這不會發(fā)生,但是…*/ ja end1 ;// al 值>6? 是則跳轉(zhuǎn)至end(沒有這種狀態(tài))。 mov ecx,24[esp] ;// 再取緩沖隊列指針地址??ecx。 push edx ;// 將端口號0x3fa(0x2fa)入棧。 sub edx,2 ;// 0x3f8(0x2f8)。 call jmp_table[eax*2] ;/* NOTE! not ;*4, bit0 is 0 already */ /* 不乘4,位0 已是0*/;// 上面語句是指,當(dāng)有待處理中斷時,al 中位0=0,位2-1 是中斷類型,因此相當(dāng)于已經(jīng)將中斷類型;// 乘了2,這里再乘2,得到跳轉(zhuǎn)表對應(yīng)各中斷類型地址,并跳轉(zhuǎn)到那里去作相應(yīng)處理。 pop edx ;// 彈出中斷標(biāo)識寄存器端口號0x3fa(或0x2fa)。 jmp rep_int ;// 跳轉(zhuǎn),繼續(xù)判斷有無待處理中斷并繼續(xù)處理。end1:
mov al,20h ;// 向中斷控制器發(fā)送結(jié)束中斷指令EOI。 out 20h,al ;/* EOI */ pop ds pop es pop eax pop ebx pop ecx pop edx add esp,4 ;// jump over _table_list entry # 丟棄緩沖隊列指針地址。 iretd;// 各中斷類型處理程序地址跳轉(zhuǎn)表,共有4 種中斷來源:;// modem 狀態(tài)變化中斷,寫字符中斷,讀字符中斷,線路狀態(tài)有問題中斷。jmp_table: dd modem_status,write_char,read_char,line_statusalign 4modem_status: add edx,6 ;/* clear intr by reading modem status reg */ in al,dx ;/* 通過讀modem 狀態(tài)寄存器進行復(fù)位(0x3fe) */ retalign 4line_status: add edx,5 ;/* clear intr by reading line status reg. */ in al,dx ;/* 通過讀線路狀態(tài)寄存器進行復(fù)位(0x3fd) */ retalign 4read_char: in al,dx ;// 讀取字符->al。 mov edx,ecx ;// 當(dāng)前串口緩沖隊列指針地址??edx。 sub edx,_table_list ;// 緩沖隊列指針表首址 - 當(dāng)前串口隊列指針地址??edx, shr edx,3 ;// 差值/8。對于串口1 是1,對于串口2 是2。 mov ecx,[ecx] ;// read-queue # 取讀緩沖隊列結(jié)構(gòu)地址??ecx。 mov ebx,head[ecx] ;// 取讀隊列中緩沖頭指針??ebx。 mov buf[ebx+ecx],al ;// 將字符放在緩沖區(qū)中頭指針?biāo)傅奈恢谩?/span> inc ebx ;// 將頭指針前移一字節(jié)。 and ebx,bsize-1 ;// 用緩沖區(qū)大小對頭指針進行模操作。指針不能超過緩沖區(qū)大小。 cmp ebx,tail[ecx] ;// 緩沖區(qū)頭指針與尾指針比較。 je l1 ;// 若相等,表示緩沖區(qū)滿,跳轉(zhuǎn)到標(biāo)號1 處。 mov head[ecx],ebx ;// 保存修改過的頭指針。l1: push edx ;// 將串口號壓入堆棧(1- 串口1,2 - 串口2),作為參數(shù), call _do_tty_interrupt ;// 調(diào)用tty 中斷處理C 函數(shù)(。 add esp,4 ;// 丟棄入棧參數(shù),并返回。 retalign 4write_char: mov ecx,[4+ecx] ;// write-queue # 取寫緩沖隊列結(jié)構(gòu)地址??ecx。 mov ebx,head[ecx] ;// 取寫隊列頭指針??ebx。 sub ebx,tail[ecx] ;// 頭指針 - 尾指針 = 隊列中字符數(shù)。 and ebx,bsize-1 ;// nr chars in queue # 對指針取模運算。 je write_buffer_empty ;// 如果頭指針 = 尾指針,說明寫隊列無字符,跳轉(zhuǎn)處理。 cmp ebx,startup ;// 隊列中字符數(shù)超過256 個? ja l2 ;// 超過,則跳轉(zhuǎn)處理。 mov ebx,proc_list[ecx] ;// wake up sleeping process # 喚醒等待的進程。;// 取等待該隊列的進程的指針,并判斷是否為空。 test ebx,ebx ;// is there any? # 有等待的進程嗎? je l2 ;// 是空的,則向前跳轉(zhuǎn)到標(biāo)號1 處。 mov dword ptr [ebx],0 ;// 否則將進程置為可運行狀態(tài)(喚醒進程)。。l2: mov ebx,tail[ecx] ;// 取尾指針。 mov al,buf[ebx+ecx] ;// 從緩沖中尾指針處取一字符??al。 out dx,al ;// 向端口0x3f8(0x2f8)送出到保持寄存器中。 inc ebx ;// 尾指針前移。 and ebx,bsize-1 ;// 尾指針若到緩沖區(qū)末端,則折回。 mov tail[ecx],ebx ;// 保存已修改過的尾指針。 cmp ebx,head[ecx] ;// 尾指針與頭指針比較, je write_buffer_empty ;// 若相等,表示隊列已空,則跳轉(zhuǎn)。 retalign 4write_buffer_empty: mov ebx,proc_list[ecx] ;// wake up sleeping process # 喚醒等待的進程。;// 取等待該隊列的進程的指針,并判斷是否為空。 test ebx,ebx ;// is there any? # 有等待的進程嗎? je l3 ;// 無,則向前跳轉(zhuǎn)到標(biāo)號1 處。 mov dword ptr [ebx],0 ;// 否則將進程置為可運行狀態(tài)(喚醒進程)。l3: inc edx ;// 指向端口0x3f9(0x2f9)。 in al,dx ;// 讀取中斷允許寄存器。 jmp l4 ;// 稍作延遲。l4: jmp l5l5: and al,0dh ;/* disable transmit interrupt */;/* 屏蔽發(fā)送保持寄存器空中斷(位1) */ out dx,al ;// 寫入0x3f9(0x2f9)。 retend
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -