;; -----------------------------------------------------------------------
;;
;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
;; Boston MA 02111-1307, USA; either version 2 of the License, or
;; (at your option) any later version; incorporated herein by reference.
;;
;; -----------------------------------------------------------------------
;;
;; serirq.inc
;;
;; Serial port IRQ code
;;
;; We don't know what IRQ, if any, we have, so map all of them...
;;
section .text16
bits 16
align 8
section .bss16
alignb 8
%assign n 0
%rep 16
section .text16
serstub_irq %+ n :
push dword [cs:oldirq %+ n]
jmp short irq_common
section .bss16
oldirq %+ n resd 1
%assign n n+1
%endrep
section .text16
irq_common:
pushf
push ax
push dx
mov dx,[cs:SerialPort]
add dx,5 ; DX -> LSR
in al,dx
test al,1 ; Received data
jnz .data
.done:
pop dx
pop ax
popf
retf ; Chain to next handler
.data:
push es
push di
mov ax,aux_seg + (aux.serial >> 4)
mov es,ax
mov di,[cs:SerialHead]
.loop:
mov dx,[cs:SerialPort] ; DX -> RDR
in al,dx
stosb
mov ah,[cs:FlowIgnore]
add dx,5 ; DX -> LSR
in al,dx
push ax
and al,ah
cmp al,ah
jne .drop
and di,serial_buf_size-1 ; Wrap around if necessary
cmp di,[cs:SerialTail] ; Would this cause overflow?
je .drop ; If so, just drop the data
mov [cs:SerialHead],di
.drop:
pop ax
test al,1 ; More data?
jnz .loop
.full:
pop di
pop es
jmp .done
section .bss16
;
; SerialIRQPort will generally track SerialPort, but will be 0 when an
; IRQ service is not installed.
;
SerialIRQPort resw 1 ; Serial port w IRQ service
SerialHead resw 1 ; Head of serial port rx buffer
SerialTail resw 1 ; Tail of serial port rx buffer
section .bss16
IRQMask resw 1 ; PIC IRQ mask status
section .text16
sirq_install:
pushad
call sirq_cleanup
; Save the old interrupt vectors
mov si,4*08h
mov di,oldirq0
mov cx,8
rep movsd
mov si,4*70h
mov cx,8
rep movsd
; Install new interrupt vectors
mov di,4*08h
mov cx,8
mov eax,serstub_irq0
.pic0:
stosd
add ax,serstub_irq1 - serstub_irq0
loop .pic0
mov di,4*70h
mov cx,8
.pic1:
stosd
add ax,serstub_irq1 - serstub_irq0
loop .pic1
mov bx,[SerialPort]
mov [SerialIRQPort],bx
lea dx,[bx+5] ; DX -> LCR
mov al,03h ; Clear DLAB (should already be...)
slow_out dx,al
lea dx,[bx+1] ; DX -> IER
mov al,1 ; Enable receive interrupt
slow_out dx,al
;
; Enable all ther interupt lines at the PIC. Some BIOSes
; only enable the timer interrupts and other interrupts
; actively in use by the BIOS.
;
in al,0xA1 ; Secondary PIC mask register
mov ah,al
in al,0x21 ; Primary PIC mask register
mov [IRQMask],ax
io_delay
xor ax,ax ; Remove all interrupt masks
out 0x21,al
out 0xA1,al
popad
ret
sirq_cleanup_nowipe:
pushad
push ds
push es
xor ax,ax
mov ds,ax
mov es,ax
mov bx,[SerialIRQPort]
and bx,bx
jz .done
lea dx,[bx+5] ; DX -> LCR
mov al,03h ; Clear DLAB (should already be...)
slow_out dx,al
lea dx,[bx+1] ; DX -> IER
xor ax,ax
slow_out dx,al ; Clear IER
; Restore PIC masks
mov ax,[IRQMask]
out 0x21,al
mov al,ah
out 0xA1,al
; Restore the original interrupt vectors
mov si,oldirq0
mov di,4*08h
mov cx,8
rep movsd
mov di,4*70h
mov cx,8
rep movsd
xor ax,ax
mov [SerialIRQPort],ax ; No active interrupt system
.done:
pop es
pop ds
popad
ret
sirq_cleanup:
call sirq_cleanup_nowipe
pushad
push es
; Just in case it might contain a password, erase the
; serial port receive buffer...
mov ax,aux_seg + (aux.serial >> 4)
mov es,ax
xor eax,eax
mov [cs:SerialHead],eax
mov cx,serial_buf_size >> 2
xor di,di
rep stosd
pop es
popad
ret
section .text16