?? rs_io.s
字號:
/** linux/kernel/rs_io.s** (C) 1991 Linus Torvalds*//** rs_io.s** This module implements the rs232 io interrupts.*//** 該程序模塊實現rs232 輸入輸出中斷處理程序。*/.text.globl _rs1_interrupt,_rs2_interrupt// size 是讀寫隊列緩沖區的字節長度。size = 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 *//* 以下這些是讀寫緩沖結構中的偏移量 */// 對應定義在include/linux/tty.h 文件中tty_queue 結構中各變量的偏移量。rs_addr = 0 // 串行端口號字段偏移(端口號是0x3f8 或0x2f8)。head = 4 // 緩沖區中頭指針字段偏移。tail = 8 // 緩沖區中尾指針字段偏移。proc_list = 12 // 等待該緩沖的進程字段偏移。buf = 16 // 緩沖區字段偏移。startup = 256 /* chars left in write queue when we restart it *//* 當寫隊列里還剩256 個字符空間(WAKEUP_CHARS)時,我們就可以寫 *//** These are the actual interrupt routines. They look where* the interrupt is coming from, and take appropriate action.*//** 這些是實際的中斷程序。程序首先檢查中斷的來源,然后執行相應* 的處理。*/.align 2//// 串行端口1 中斷處理程序入口點。_rs1_interrupt:pushl $_table_list+8 // tty 表中對應串口1 的讀寫緩沖指針的地址入棧(tty_io.c,99)。jmp rs_int.align 2//// 串行端口2 中斷處理程序入口點。_rs2_interrupt:pushl $_table_list+16 // tty 表中對應串口2 的讀寫緩沖隊列指針的地址入棧。rs_int:pushl %edxpushl %ecxpushl %ebxpushl %eaxpush %espush %ds /* as this is an interrupt, we cannot */pushl $0x10 /* know that bs is ok. Load it */pop %ds /* 由于這是一個中斷程序,我們不知道ds 是否正確,*/pushl $0x10 /* 所以加載它們(讓ds、es 指向內核數據段 */pop %esmovl 24(%esp),%edx // 將緩沖隊列指針地址存入edx 寄存器,// 也即35 或39 行上最先壓入堆棧的地址。movl (%edx),%edx // 取讀隊列指針(地址)??edx。movl rs_addr(%edx),%edx // 取串口1 的端口號??edx。addl $2,%edx /* interrupt ident. reg */ /* edx 指向中斷標識寄存器 */rep_int: // 中斷標識寄存器端口是0x3fa(0x2fa),參見上節列表后信息。xorl %eax,%eax // eax 清零。inb %dx,%al // 取中斷標識字節,用以判斷中斷來源(有4 種中斷情況)。testb $1,%al // 首先判斷有無待處理的中斷(位0=1 無中斷;=0 有中斷)。jne end // 若無待處理中斷,則跳轉至退出處理處end。cmpb $6,%al /* this shouldn't happen, but ... */ /* 這不會發生,但是…*/ja end // al 值>6? 是則跳轉至end(沒有這種狀態)。movl 24(%esp),%ecx // 再取緩沖隊列指針地址??ecx。pushl %edx // 將端口號0x3fa(0x2fa)入棧。subl $2,%edx // 0x3f8(0x2f8)。call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */ /* 不乘4,位0 已是0*/// 上面語句是指,當有待處理中斷時,al 中位0=0,位2-1 是中斷類型,因此相當于已經將中斷類型// 乘了2,這里再乘2,得到跳轉表對應各中斷類型地址,并跳轉到那里去作相應處理。popl %edx // 彈出中斷標識寄存器端口號0x3fa(或0x2fa)。jmp rep_int // 跳轉,繼續判斷有無待處理中斷并繼續處理。end: movb $0x20,%al // 向中斷控制器發送結束中斷指令EOI。outb %al,$0x20 /* EOI */pop %dspop %espopl %eaxpopl %ebxpopl %ecxpopl %edxaddl $4,%esp # jump over _table_list entry # 丟棄緩沖隊列指針地址。iret// 各中斷類型處理程序地址跳轉表,共有4 種中斷來源:// modem 狀態變化中斷,寫字符中斷,讀字符中斷,線路狀態有問題中斷。jmp_table:.long modem_status,write_char,read_char,line_status.align 2modem_status:addl $6,%edx /* clear intr by reading modem status reg */inb %dx,%al /* 通過讀modem 狀態寄存器進行復位(0x3fe) */ret.align 2line_status:addl $5,%edx /* clear intr by reading line status reg. */inb %dx,%al /* 通過讀線路狀態寄存器進行復位(0x3fd) */ret.align 2read_char:inb %dx,%al /* 讀取字符??al。movl %ecx,%edx /* 當前串口緩沖隊列指針地址??edx。subl $_table_list,%edx // 緩沖隊列指針表首址 - 當前串口隊列指針地址??edx,shrl $3,%edx // 差值/8。對于串口1 是1,對于串口2 是2。movl (%ecx),%ecx # read-queue # 取讀緩沖隊列結構地址??ecx。movl head(%ecx),%ebx // 取讀隊列中緩沖頭指針??ebx。movb %al,buf(%ecx,%ebx) // 將字符放在緩沖區中頭指針所指的位置。incl %ebx // 將頭指針前移一字節。andl $size-1,%ebx // 用緩沖區大小對頭指針進行模操作。指針不能超過緩沖區大小。cmpl tail(%ecx),%ebx // 緩沖區頭指針與尾指針比較。je 1f // 若相等,表示緩沖區滿,跳轉到標號1 處。movl %ebx,head(%ecx) // 保存修改過的頭指針。1: pushl %edx // 將串口號壓入堆棧(1- 串口1,2 - 串口2),作為參數,call _do_tty_interrupt // 調用tty 中斷處理C 函數(。addl $4,%esp // 丟棄入棧參數,并返回。ret.align 2write_char:movl 4(%ecx),%ecx # write-queue # 取寫緩沖隊列結構地址??ecx。movl head(%ecx),%ebx // 取寫隊列頭指針??ebx。subl tail(%ecx),%ebx // 頭指針 - 尾指針 = 隊列中字符數。andl $size-1,%ebx # nr chars in queue # 對指針取模運算。je write_buffer_empty // 如果頭指針 = 尾指針,說明寫隊列無字符,跳轉處理。cmpl $startup,%ebx // 隊列中字符數超過256 個?ja 1f // 超過,則跳轉處理。movl proc_list(%ecx),%ebx # wake up sleeping process # 喚醒等待的進程。// 取等待該隊列的進程的指針,并判斷是否為空。testl %ebx,%ebx # is there any? # 有等待的進程嗎?je 1f // 是空的,則向前跳轉到標號1 處。movl $0,(%ebx) // 否則將進程置為可運行狀態(喚醒進程)。。1: movl tail(%ecx),%ebx // 取尾指針。movb buf(%ecx,%ebx),%al // 從緩沖中尾指針處取一字符??al。outb %al,%dx // 向端口0x3f8(0x2f8)送出到保持寄存器中。incl %ebx // 尾指針前移。andl $size-1,%ebx // 尾指針若到緩沖區末端,則折回。movl %ebx,tail(%ecx) // 保存已修改過的尾指針。cmpl head(%ecx),%ebx // 尾指針與頭指針比較,je write_buffer_empty // 若相等,表示隊列已空,則跳轉。ret.align 2write_buffer_empty:movl proc_list(%ecx),%ebx # wake up sleeping process # 喚醒等待的進程。// 取等待該隊列的進程的指針,并判斷是否為空。testl %ebx,%ebx # is there any? # 有等待的進程嗎?je 1f # 無,則向前跳轉到標號1 處。movl $0,(%ebx) # 否則將進程置為可運行狀態(喚醒進程)。1: incl %edx # 指向端口0x3f9(0x2f9)。inb %dx,%al # 讀取中斷允許寄存器。jmp 1f # 稍作延遲。1: jmp 1f1: andb $0xd,%al /* disable transmit interrupt *//* 屏蔽發送保持寄存器空中斷(位1) */outb %al,%dx // 寫入0x3f9(0x2f9)。ret
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -