/* * 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 */ rs_addr = 0 head = 4 tail = 8 proc_list = 12 buf = 16 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 4 rs1_interrupt: pushl $table_list+8 jmp rs_int .align 4 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 */ pushl $0x10 /* know that bs is ok. Load it */ pop %ds pushl $0x10 pop %es movl 24(%esp),%edx movl (%edx),%edx movl rs_addr(%edx),%edx addl $2,%edx /* interrupt ident. reg */ rep_int: xorl %eax,%eax inb %dx,%al testb $1,%al jne end cmpb $6,%al /* this shouldn't happen, but ... */ ja end movl 24(%esp),%ecx pushl %edx subl $2,%edx call jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */ popl %edx jmp rep_int 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 jmp_table: .long modem_status,write_char,read_char,line_status .align 4 modem_status: addl $6,%edx /* clear intr by reading modem status reg */ inb %dx,%al ret .align 4 line_status: addl $5,%edx /* clear intr by reading line status reg. */ inb %dx,%al ret .align 4 read_char: inb %dx,%al movl %ecx,%edx subl $table_list,%edx shrl $3,%edx movl (%ecx),%ecx # read-queue movl head(%ecx),%ebx movb %al,buf(%ecx,%ebx) incl %ebx andl $size-1,%ebx cmpl tail(%ecx),%ebx je 1f movl %ebx,head(%ecx) 1: pushl %edx call do_tty_interrupt addl $4,%esp ret .align 4 write_char: movl 4(%ecx),%ecx # write-queue movl head(%ecx),%ebx subl tail(%ecx),%ebx andl $size-1,%ebx # nr chars in queue je write_buffer_empty cmpl $startup,%ebx ja 1f movl proc_list(%ecx),%ebx # wake up sleeping process testl %ebx,%ebx # is there any? je 1f movl $0,(%ebx) 1: movl tail(%ecx),%ebx movb buf(%ecx,%ebx),%al outb %al,%dx incl %ebx andl $size-1,%ebx movl %ebx,tail(%ecx) cmpl head(%ecx),%ebx je write_buffer_empty ret .align 4 write_buffer_empty: movl proc_list(%ecx),%ebx # wake up sleeping process testl %ebx,%ebx # is there any? je 1f movl $0,(%ebx) 1: incl %edx inb %dx,%al jmp 1f 1: jmp 1f 1: andb $0xd,%al /* disable transmit interrupt */ outb %al,%dx ret