63.html
来自「linux 0.11中文版 有注释」· HTML 代码 · 共 186 行
HTML
186 行
<html>
<head>
<title>kernel/chr_drv/rs_io.s</title>
<meta name='robots' content='noindex,nofollow'>
<meta name='generator' content='GLOBAL-5.4.1'>
</head>
<body text='#191970' bgcolor='#f5f5dc' vlink='gray'>
<a name='TOP'><h2><a href='../mains.html'>root</a>/<a href='../files/104.html'>kernel</a>/<a href='../files/106.html'>chr_drv</a>/rs_io.s</h2>
<i><font color='green'>/* [<][>][^][v][top]<a href='#BOTTOM'>[bottom]</a><a href='../mains.html'>[index]</a><a href='../help.html'>[help]</a> */</font></i>
<hr>
<pre>
<a name='L1'><i><font color='green'>/*</font></i>
<a name='L2'><i><font color='green'>* linux/kernel/rs_io.s</font></i>
<a name='L3'><i><font color='green'>*</font></i>
<a name='L4'><i><font color='green'>* (C) 1991 Linus Torvalds</font></i>
<a name='L5'><i><font color='green'>*/</font></i>
<a name='L6'>
<a name='L7'><i><font color='green'>/*</font></i>
<a name='L8'><i><font color='green'>* rs_io.s</font></i>
<a name='L9'><i><font color='green'>*</font></i>
<a name='L10'><i><font color='green'>* This module implements the rs232 io interrupts.</font></i>
<a name='L11'><i><font color='green'>*/</font></i>
<a name='L12'><i><font color='green'>/*</font></i>
<a name='L13'><i><font color='green'>* 该程序模块实现rs232 输入输出中断处理程序。</font></i>
<a name='L14'><i><font color='green'>*/</font></i>
<a name='L15'>
<a name='L16'>.text
<a name='L17'>.globl _rs1_interrupt,_rs2_interrupt
<a name='L18'>
<a name='L19'><i><font color='green'>// size 是读写队列缓冲区的字节长度。</font></i>
<a name='L20'>size = 1024 <i><font color='green'>/* must be power of two ! 必须是2 的次方并且需</font></i>
<a name='L21'><i><font color='green'>and must match the value 与tty_io.c 中的值匹配!</font></i>
<a name='L22'><i><font color='green'>in tty_io.c!!! */</font></i>
<a name='L23'>
<a name='L24'><i><font color='green'>/* these are the offsets into the read/write buffer structures */</font></i>
<a name='L25'><i><font color='green'>/* 以下这些是读写缓冲结构中的偏移量 */</font></i>
<a name='L26'><i><font color='green'>// 对应定义在include/linux/tty.h 文件中tty_queue 结构中各变量的偏移量。</font></i>
<a name='L27'>rs_addr = 0 <i><font color='green'>// 串行端口号字段偏移(端口号是0x3f8 或0x2f8)。</font></i>
<a name='L28'>head = 4 <i><font color='green'>// 缓冲区中头指针字段偏移。</font></i>
<a name='L29'>tail = 8 <i><font color='green'>// 缓冲区中尾指针字段偏移。</font></i>
<a name='L30'>proc_list = 12 <i><font color='green'>// 等待该缓冲的进程字段偏移。</font></i>
<a name='L31'>buf = 16 <i><font color='green'>// 缓冲区字段偏移。</font></i>
<a name='L32'>
<a name='L33'>startup = 256 <i><font color='green'>/* chars left in write queue when we restart it */</font></i>
<a name='L34'><i><font color='green'>/* 当写队列里还剩256 个字符空间(WAKEUP_CHARS)时,我们就可以写 */</font></i>
<a name='L35'>
<a name='L36'><i><font color='green'>/*</font></i>
<a name='L37'><i><font color='green'>* These are the actual interrupt routines. They look where</font></i>
<a name='L38'><i><font color='green'>* the interrupt is coming from, and take appropriate action.</font></i>
<a name='L39'><i><font color='green'>*/</font></i>
<a name='L40'><i><font color='green'>/*</font></i>
<a name='L41'><i><font color='green'>* 这些是实际的中断程序。程序首先检查中断的来源,然后执行相应</font></i>
<a name='L42'><i><font color='green'>* 的处理。</font></i>
<a name='L43'><i><font color='green'>*/</font></i>
<a name='L44'>.align 2
<a name='L45'><i><font color='green'>//// 串行端口1 中断处理程序入口点。</font></i>
<a name='L46'>_rs1_interrupt:
<a name='L47'>pushl $_table_list+8 <i><font color='green'>// tty 表中对应串口1 的读写缓冲指针的地址入栈(tty_io.c,99)。</font></i>
<a name='L48'>jmp rs_int
<a name='L49'>.align 2
<a name='L50'><i><font color='green'>//// 串行端口2 中断处理程序入口点。</font></i>
<a name='L51'>_rs2_interrupt:
<a name='L52'>pushl $_table_list+16 <i><font color='green'>// tty 表中对应串口2 的读写缓冲队列指针的地址入栈。</font></i>
<a name='L53'>rs_int:
<a name='L54'>pushl %edx
<a name='L55'>pushl %ecx
<a name='L56'>pushl %ebx
<a name='L57'>pushl %eax
<a name='L58'>push %es
<a name='L59'>push %ds <i><font color='green'>/* as this is an interrupt, we cannot */</font></i>
<a name='L60'>pushl $0x10 <i><font color='green'>/* know that bs is ok. Load it */</font></i>
<a name='L61'>pop %ds <i><font color='green'>/* 由于这是一个中断程序,我们不知道ds 是否正确,*/</font></i>
<a name='L62'>pushl $0x10 <i><font color='green'>/* 所以加载它们(让ds、es 指向内核数据段 */</font></i>
<a name='L63'>pop %es
<a name='L64'>movl 24(%esp),%edx <i><font color='green'>// 将缓冲队列指针地址存入edx 寄存器,</font></i>
<a name='L65'><i><font color='green'>// 也即35 或39 行上最先压入堆栈的地址。</font></i>
<a name='L66'>movl (%edx),%edx <i><font color='green'>// 取读队列指针(地址)??edx。</font></i>
<a name='L67'>movl rs_addr(%edx),%edx <i><font color='green'>// 取串口1 的端口号??edx。</font></i>
<a name='L68'>addl $2,%edx <i><font color='green'>/* interrupt ident. reg */</font></i> <i><font color='green'>/* edx 指向中断标识寄存器 */</font></i>
<a name='L69'>rep_int: <i><font color='green'>// 中断标识寄存器端口是0x3fa(0x2fa),参见上节列表后信息。</font></i>
<a name='L70'>xorl %eax,%eax <i><font color='green'>// eax 清零。</font></i>
<a name='L71'>inb %dx,%al <i><font color='green'>// 取中断标识字节,用以判断中断来源(有4 种中断情况)。</font></i>
<a name='L72'>testb $1,%al <i><font color='green'>// 首先判断有无待处理的中断(位0=1 无中断;=0 有中断)。</font></i>
<a name='L73'>jne end <i><font color='green'>// 若无待处理中断,则跳转至退出处理处end。</font></i>
<a name='L74'>cmpb $6,%al <i><font color='green'>/* this shouldn't happen, but ... */</font></i> <i><font color='green'>/* 这不会发生,但是…*/</font></i>
<a name='L75'>ja end <i><font color='green'>// al 值>6? 是则跳转至end(没有这种状态)。</font></i>
<a name='L76'>movl 24(%esp),%ecx <i><font color='green'>// 再取缓冲队列指针地址??ecx。</font></i>
<a name='L77'>pushl %edx <i><font color='green'>// 将端口号0x3fa(0x2fa)入栈。</font></i>
<a name='L78'>subl $2,%edx <i><font color='green'>// 0x3f8(0x2f8)。</font></i>
<a name='L79'>call jmp_table(,%eax,2) <i><font color='green'>/* NOTE! not *4, bit0 is 0 already */</font></i> <i><font color='green'>/* 不乘4,位0 已是0*/</font></i>
<a name='L80'><i><font color='green'>// 上面语句是指,当有待处理中断时,al 中位0=0,位2-1 是中断类型,因此相当于已经将中断类型</font></i>
<a name='L81'><i><font color='green'>// 乘了2,这里再乘2,得到跳转表对应各中断类型地址,并跳转到那里去作相应处理。</font></i>
<a name='L82'>popl %edx <i><font color='green'>// 弹出中断标识寄存器端口号0x3fa(或0x2fa)。</font></i>
<a name='L83'>jmp rep_int <i><font color='green'>// 跳转,继续判断有无待处理中断并继续处理。</font></i>
<a name='L84'>end: movb $0x20,%al <i><font color='green'>// 向中断控制器发送结束中断指令EOI。</font></i>
<a name='L85'>outb %al,$0x20 <i><font color='green'>/* EOI */</font></i>
<a name='L86'>pop %ds
<a name='L87'>pop %es
<a name='L88'>popl %eax
<a name='L89'>popl %ebx
<a name='L90'>popl %ecx
<a name='L91'>popl %edx
<a name='L92'>addl $4,%esp # jump over _table_list entry # 丢弃缓冲队列指针地址。
<a name='L93'>iret
<a name='L94'>
<a name='L95'><i><font color='green'>// 各中断类型处理程序地址跳转表,共有4 种中断来源:</font></i>
<a name='L96'><i><font color='green'>// modem 状态变化中断,写字符中断,读字符中断,线路状态有问题中断。</font></i>
<a name='L97'>jmp_table:
<a name='L98'>.long modem_status,write_char,read_char,line_status
<a name='L99'>
<a name='L100'>.align 2
<a name='L101'>modem_status:
<a name='L102'>addl $6,%edx <i><font color='green'>/* clear intr by reading modem status reg */</font></i>
<a name='L103'>inb %dx,%al <i><font color='green'>/* 通过读modem 状态寄存器进行复位(0x3fe) */</font></i>
<a name='L104'>ret
<a name='L105'>
<a name='L106'>.align 2
<a name='L107'>line_status:
<a name='L108'>addl $5,%edx <i><font color='green'>/* clear intr by reading line status reg. */</font></i>
<a name='L109'>inb %dx,%al <i><font color='green'>/* 通过读线路状态寄存器进行复位(0x3fd) */</font></i>
<a name='L110'>ret
<a name='L111'>
<a name='L112'>.align 2
<a name='L113'>read_char:
<a name='L114'>inb %dx,%al <i><font color='green'>/* 读取字符??al。</font></i>
<a name='L115'><i><font color='green'>movl %ecx,%edx /* 当前串口缓冲队列指针地址??edx。</font></i>
<a name='L116'><i><font color='green'>subl $_table_list,%edx // 缓冲队列指针表首址 - 当前串口队列指针地址??edx,</font></i>
<a name='L117'><i><font color='green'>shrl $3,%edx // 差值/8。对于串口1 是1,对于串口2 是2。</font></i>
<a name='L118'><i><font color='green'>movl (%ecx),%ecx # read-queue # 取读缓冲队列结构地址??ecx。</font></i>
<a name='L119'><i><font color='green'>movl head(%ecx),%ebx // 取读队列中缓冲头指针??ebx。</font></i>
<a name='L120'><i><font color='green'>movb %al,buf(%ecx,%ebx) // 将字符放在缓冲区中头指针所指的位置。</font></i>
<a name='L121'><i><font color='green'>incl %ebx // 将头指针前移一字节。</font></i>
<a name='L122'><i><font color='green'>andl $size-1,%ebx // 用缓冲区大小对头指针进行模操作。指针不能超过缓冲区大小。</font></i>
<a name='L123'><i><font color='green'>cmpl tail(%ecx),%ebx // 缓冲区头指针与尾指针比较。</font></i>
<a name='L124'><i><font color='green'>je 1f // 若相等,表示缓冲区满,跳转到标号1 处。</font></i>
<a name='L125'><i><font color='green'>movl %ebx,head(%ecx) // 保存修改过的头指针。</font></i>
<a name='L126'><i><font color='green'>1: pushl %edx // 将串口号压入堆栈(1- 串口1,2 - 串口2),作为参数,</font></i>
<a name='L127'><i><font color='green'>call _do_tty_interrupt // 调用tty 中断处理C 函数(。</font></i>
<a name='L128'><i><font color='green'>addl $4,%esp // 丢弃入栈参数,并返回。</font></i>
<a name='L129'><i><font color='green'>ret</font></i>
<a name='L130'><i><font color='green'></font></i>
<a name='L131'><i><font color='green'>.align 2</font></i>
<a name='L132'><i><font color='green'>write_char:</font></i>
<a name='L133'><i><font color='green'>movl 4(%ecx),%ecx # write-queue # 取写缓冲队列结构地址??ecx。</font></i>
<a name='L134'><i><font color='green'>movl head(%ecx),%ebx // 取写队列头指针??ebx。</font></i>
<a name='L135'><i><font color='green'>subl tail(%ecx),%ebx // 头指针 - 尾指针 = 队列中字符数。</font></i>
<a name='L136'><i><font color='green'>andl $size-1,%ebx # nr chars in queue # 对指针取模运算。</font></i>
<a name='L137'><i><font color='green'>je write_buffer_empty // 如果头指针 = 尾指针,说明写队列无字符,跳转处理。</font></i>
<a name='L138'><i><font color='green'>cmpl $startup,%ebx // 队列中字符数超过256 个?</font></i>
<a name='L139'><i><font color='green'>ja 1f // 超过,则跳转处理。</font></i>
<a name='L140'><i><font color='green'>movl proc_list(%ecx),%ebx # wake up sleeping process # 唤醒等待的进程。</font></i>
<a name='L141'><i><font color='green'>// 取等待该队列的进程的指针,并判断是否为空。</font></i>
<a name='L142'><i><font color='green'>testl %ebx,%ebx # is there any? # 有等待的进程吗?</font></i>
<a name='L143'><i><font color='green'>je 1f // 是空的,则向前跳转到标号1 处。</font></i>
<a name='L144'><i><font color='green'>movl $0,(%ebx) // 否则将进程置为可运行状态(唤醒进程)。。</font></i>
<a name='L145'><i><font color='green'>1: movl tail(%ecx),%ebx // 取尾指针。</font></i>
<a name='L146'><i><font color='green'>movb buf(%ecx,%ebx),%al // 从缓冲中尾指针处取一字符??al。</font></i>
<a name='L147'><i><font color='green'>outb %al,%dx // 向端口0x3f8(0x2f8)送出到保持寄存器中。</font></i>
<a name='L148'><i><font color='green'>incl %ebx // 尾指针前移。</font></i>
<a name='L149'><i><font color='green'>andl $size-1,%ebx // 尾指针若到缓冲区末端,则折回。</font></i>
<a name='L150'><i><font color='green'>movl %ebx,tail(%ecx) // 保存已修改过的尾指针。</font></i>
<a name='L151'><i><font color='green'>cmpl head(%ecx),%ebx // 尾指针与头指针比较,</font></i>
<a name='L152'><i><font color='green'>je write_buffer_empty // 若相等,表示队列已空,则跳转。</font></i>
<a name='L153'><i><font color='green'>ret</font></i>
<a name='L154'><i><font color='green'>.align 2</font></i>
<a name='L155'><i><font color='green'>write_buffer_empty:</font></i>
<a name='L156'><i><font color='green'>movl proc_list(%ecx),%ebx # wake up sleeping process # 唤醒等待的进程。</font></i>
<a name='L157'><i><font color='green'>// 取等待该队列的进程的指针,并判断是否为空。</font></i>
<a name='L158'><i><font color='green'>testl %ebx,%ebx # is there any? # 有等待的进程吗?</font></i>
<a name='L159'><i><font color='green'>je 1f # 无,则向前跳转到标号1 处。</font></i>
<a name='L160'><i><font color='green'>movl $0,(%ebx) # 否则将进程置为可运行状态(唤醒进程)。</font></i>
<a name='L161'><i><font color='green'>1: incl %edx # 指向端口0x3f9(0x2f9)。</font></i>
<a name='L162'><i><font color='green'>inb %dx,%al # 读取中断允许寄存器。</font></i>
<a name='L163'><i><font color='green'>jmp 1f # 稍作延迟。</font></i>
<a name='L164'><i><font color='green'>1: jmp 1f</font></i>
<a name='L165'><i><font color='green'>1: andb $0xd,%al /* disable transmit interrupt */</font></i>
<a name='L166'><i><font color='green'>/* 屏蔽发送保持寄存器空中断(位1) */</font></i>
<a name='L167'>outb %al,%dx <i><font color='green'>// 写入0x3f9(0x2f9)。</font></i>
<a name='L168'>ret
</pre>
<hr>
<a name='BOTTOM'>
<i><font color='green'>/* [<][>][^][v]<a href='#TOP'>[top]</a>[bottom]<a href='../mains.html'>[index]</a><a href='../help.html'>[help]</a> */</font></i>
</body>
</html>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?