日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

linux 0.11 内核学习 -- rs_io.s,串口汇编代码

發布時間:2025/3/15 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 0.11 内核学习 -- rs_io.s,串口汇编代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

/*

?* ?該文件實現rs232 串行通信中斷處理

?*/

/*

?* ?linux/kernel/rs_io.s

?*

?* ?(C) 1991 ?Linus Torvalds

?*/

/*

?* rs_io.s

?*

?* This module implements the rs232 io interrupts.

?*/

.text

.globl _rs1_interrupt,_rs2_interrupt

/* 讀寫隊列緩沖區的長度 */

size = 1024 /* must be power of two !

? and must match the value

? in tty_io.c!!! */

/* these are the offsets into the read/write buffer structures */

/* 讀寫緩沖結構中的偏移量tty_queue */

rs_addr = 0

head = 4

tail = 8

proc_list = 12

buf = 16

/* 當寫隊列里還剩256 個字符空間(WAKEUP_CHARS)時,我們就可以寫 */

startup = 256 /* chars left in write queue when we restart it */

/*

?* These are the actual interrupt routines. They look where

?* the interrupt is coming from, and take appropriate action.

?*/

.align 2

/* 串行端口1 中斷處理程序入口點 */

_rs1_interrupt:

// tty 表中對應串口1 的讀寫緩沖指針的地址入棧

pushl $_table_list+8 // table_list定義在文件tty_io.c文件中

jmp rs_int

/* 串行端口2 中斷處理程序入口點 */

.align 2

_rs2_interrupt:

pushl $_table_list+16 // 同上

rs_int:

pushl %edx

pushl %ecx

pushl %ebx

pushl %eax

push %es

push %ds /* as this is an interrupt, we cannot */

/* 讓ds、es 指向內核數據段 */

pushl $0x10 /* know that bs is ok. Load it */

pop %ds

pushl $0x10

pop %es

movl 24(%esp),%edx // 將緩沖隊列指針地址存入edx 寄存器

movl (%edx),%edx // 取讀隊列指針(地址)?-> edx

movl rs_addr(%edx),%edx // 取串口1 的端口號?-> edx

/* edx 指向中斷標識寄存器 */

addl $2,%edx /* interrupt ident. reg */

rep_int:

xorl %eax,%eax // eax = 0

inb %dx,%al // 取中斷標識字節,用以判斷中斷來源

testb $1,%al // 有無待處理的中斷?

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)

/* jmp_table在下面定義 */

call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */

popl %edx // 彈出中斷標識寄存器端口號0x3fa(或0x2fa)

jmp rep_int // 繼續處理

/* 向中斷控制器發送結束中斷指令EOI */

end: movb $0x20,%al

outb %al,$0x20 /* EOI */

pop %ds

pop %es

popl %eax

popl %ebx

popl %ecx

popl %edx

/* 丟棄緩沖隊列指針地址 */

addl $4,%esp # jump over _table_list entry

iret

/* 各中斷類型處理程序地址跳轉表 */

/* modem 狀態變化中斷,寫字符中斷,讀字符中斷,線路狀態有問題中斷 */

jmp_table:

.long modem_status,write_char,read_char,line_status

.align 2

/* 通過讀modem 狀態寄存器進行復位(0x3fe) */

modem_status:

addl $6,%edx /* clear intr by reading modem status reg */

inb %dx,%al

ret

.align 2

/* 通過讀線路狀態寄存器進行復位(0x3fd) */

line_status:

addl $5,%edx /* clear intr by reading line status reg. */

inb %dx,%al

ret

.align 2

/*

?* read_char實現的是從CPU讀取,將結果存儲到緩沖隊列中

?*/

read_char:

inb %dx,%al // 讀取字符?-> al

movl %ecx,%edx // 當前串口緩沖隊列指針地址?-> edx

subl $_table_list,%edx // 當前串口隊列指針地址?-> edx

shrl $3,%edx

movl (%ecx),%ecx # read-queue

// 取讀隊列中緩沖頭指針?-> ebx

movl head(%ecx),%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 // 將串口號壓入堆棧

call _do_tty_interrupt // 調用tty 中斷處理C 函數

addl $4,%esp // 丟棄入棧參數,并返回

ret

.align 2

/*

?* write_char函數是將收到的數據傳送給CPU

?*/

write_char:

// 取寫緩沖隊列結構地址?-> ecx

movl 4(%ecx),%ecx # write-queue

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) // 否則將進程置為可運行狀態(喚醒進程)

/*

?* 緩沖區的長度是1024,但是在緩沖區中含有256個字符時,就開始

?* 進行寫操作。下面的餓代碼首先將超過256的字節的后一個字節

?* 寫入端口中,然后該段代碼從尾部讀取一個字符,然后繼續rep_int

?* ,程序繼續判斷是那種的處理情況

?*

?* tail(low address) ---------------------> head(high address)

?*/

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 2

/*

?* 喚醒進程,改寫端口寄存器值

?*/

write_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 1f

/* disable transmit interrupt */

1: andb $0xd,%al

outb %al,%dx

ret

參考《linux內核完全注釋》和網上相關文章

轉載于:https://www.cnblogs.com/xuqiang/archive/2010/02/01/1953773.html

總結

以上是生活随笔為你收集整理的linux 0.11 内核学习 -- rs_io.s,串口汇编代码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。