; Async Module. IDEAL MODEL large EOI equ 020h ; 8259 end-of-interupt Ctrl8259_0 equ 020h ; 8259 port Ctrl8259_1 equ 021h ; 8259 port (Masks) BufSize equ 8196 ; Buffer Size DATASEG ; Various things to be set upon AsyncInit() VectorNum db ? ; Vector Number EnableIRQ db ? ; Mask to enable 8259 IRQ DisableIRQ db ? ; Mask to disable 8259 IRQ VectorSeg dw ? ; Old Vector Segment VectorOfs dw ? ; Old Vector Offset ; Register Addresses for the 8250 UART Port dw ? ; Port Base Address LABEL RegStart word THR dw ? ; Transmitter Holding Register RDR dw ? ; Reciever Data Register BRDL dw ? ; Baud Rate Divisor, Low byte BRDH dw ? ; Baud Rate Divisor, High Byte IER dw ? ; Interupt Enable Register IIR dw ? ; Interupt Identification Register LCR dw ? ; Line Control Register MCR dw ? ; Modem Control Register LSR dw ? ; Line Status Register MSR dw ? ; Modem Status Register ; Buffer Data RecBuffer db BufSize DUP (?) ; Recieve Buffer RecHead dw ? ; Buffer Head Pointer RecTail dw ? ; Buffer Tail Pointer TransBuffer db BufSize DUP (?) ; Transmit Buffer TransHead dw ? ; Buffer Head Pointer TransTail dw ? ; Buffer Tail Pointer ; Register Offsets for the UART RegOffsets dw 0, 0, 0, 1, 1, 2, 3, 4, 5, 6 CODESEG PUBLIC _AsyncInit, _AsyncClear, _AsyncStop PUBLIC _AsyncIn, _AsyncOut, _AsyncSet PUBLIC _AsyncHand, _AsyncStat, _AsyncInStat PUBLIC _AsyncOutStat ;----------------------------------------------------------------------------- ; AsyncClear Empty the recieve buffer ;----------------------------------------------------------------------------- ; void AsyncClear( void); ; ; ;----------------------------------------------------------------------------- PROC _AsyncClear cli push ax mov ax, offset RecBuffer mov [RecHead], ax mov [RecTail], ax mov ax, offset TransBuffer mov [TransHead], ax mov [TransTail], ax pop ax sti ret ENDP _AsyncClear ;----------------------------------------------------------------------------- ; AsyncInit Initalize Serial Port and install ISR ;----------------------------------------------------------------------------- ; void AsyncInit( int port) ; ; Where Port is ; 0 = COM1 ; 1 = COM2 ; 2 = COM3 ; 3 = COM4 ; ;----------------------------------------------------------------------------- PROC _AsyncInit ARG CommPort:word push bp mov bp, sp ;---- Set various things according to com port number mov ax, [CommPort] ;----- COM1 cmp ax, 0 jne @@1 mov [Port], 03F8h mov [VectorNum], 0Ch mov [EnableIRQ], 0EFh mov [DisableIRQ], 10h jmp @@Done @@1: ;----- COM2 cmp ax, 1 jne @@2 mov [Port], 02F8h mov [VectorNum], 0Bh mov [EnableIRQ], 0F7h mov [DisableIRQ], 08h jmp @@Done @@2: ;----- COM3 cmp ax, 2 ; 2 jne @@3 mov [Port], 03E8h ; 03E8 mov [VectorNum], 0Ch ; 0C mov [EnableIRQ], 0EFh ; EF mov [DisableIRQ], 10h ; 10 jmp @@Done @@3: ;----- COM4 mov [Port], 02E8h ; 02E8 mov [VectorNum], 0Bh ; 0B mov [EnableIRQ], 0F7h ; F7 mov [DisableIRQ], 08h ; 08 @@Done: ;---- Compute Register locations mov cx, 10 mov bx, offset RegOffsets push di mov di, offset RegStart @@4: mov ax, [bx] add ax, [Port] mov [di], ax add bx, 2 add di, 2 loop @@4 pop di ;----- Initalize Buffer call _AsyncClear ;--- Save and reassign interrupt vector push ds ; Save Old Vector mov al,[VectorNum] mov ah,35h int 21h mov [VectorSeg], es mov [VectorOfs], bx mov al, [VectorNum] push cs ; Set New Vector pop ds mov dx, offset AsyncISR mov ah, 25h int 21h pop ds ;----- Enable 8259 interrupt (IRQ) line for this async adapter in al, Ctrl8259_1 and al, [EnableIRQ] out Ctrl8259_1, al ;----- Enable 8250 Interrupt-on-data-ready mov dx, [LCR] ; Read Line control register and clear in al, dx ; bit 7, the Divisor Latch Address and al, 07Fh out dx, al mov dx, [IER] mov al, 0 ;we're gonna test the UART first out dx, al in al, dx ;if this isn't 0, there's no UART cmp al, 0 jnz @@222 mov al, 3 out dx, al ;----- Clear 8250 Status and data registers @@10: mov dx, [RDR] ; Clear RDR by reading port in al, dx mov dx, [LSR] ; Clear LSR in al, dx mov dx, [MSR] ; Clear MSR in al, dx mov dx, [IIR] ; Clear IIR in al, dx test al, 1 jz @@10 ;----- Set Bit 3 of MCR -- Enable interupts mov dx, [MCR] in al, dx or al, 08h out dx, al ;----- Clear Buffer Just in case call _AsyncClear ;----- Return xor ax, ax @@222: pop bp ret ENDP _AsyncInit ;----------------------------------------------------------------------------- ; AsyncStop Uninstall ISR ;----------------------------------------------------------------------------- ; void AsyncStop( void) ;----------------------------------------------------------------------------- PROC _AsyncStop push bp mov bp, sp ;----- Mask (disable) 8259 IRQ Interrupt in al, Ctrl8259_1 or al, [DisableIRQ] out Ctrl8259_1, al ;----- Disable 8250 interrupt mov dx, [LCR] in al, dx and al, 07Fh out dx, al mov dx, [IER] xor al, al out dx, al ;----- Set bit 3 in MCR to 0 mov dx, [MCR] in al, dx and al, 0F7h out dx, al ;----- Interrupts are disables. Restore saved interrupt vector. push ds mov al, [VectorNum] mov ah, 25h mov dx, [VectorOfs] mov ds, [VectorSeg] int 21h pop ds ;----- Return pop bp ret ENDP _AsyncStop ;----------------------------------------------------------------------------- ; AsyncISR Async Interrupt Service Routine ;----------------------------------------------------------------------------- ; To be called only as an interrupt. ;----------------------------------------------------------------------------- PROC AsyncISR push ax ; Save Registers push bx push ds push dx mov ax, @data ; Address local data with ds mov ds, ax mov dx, [IIR] ; Check if data actually recieved in al, dx and al, 06h cmp al, 04h je @@recieve cmp al, 02h jne @@end ;----- Transmit A byte @@transmit: mov bx, [TransTail] cmp bx, [TransHead] jne @@1 mov dx, [IER] ; Buffer empty mov al, 1 out dx, al ; Disable THR empty interrupt jmp @@end @@1: mov al, [byte ptr bx] ; Get Byte inc [TransTail] ; Update buffer pointer cmp [word ptr TransTail], offset TransBuffer + BufSize jb @@2 mov [TransTail], offset TransBuffer @@2: mov dx, [THR] out dx, al jmp @@end ;----- Recieve a byte @@recieve: mov dx, [RDR] ; Get Byte in al, dx mov bx, [RecHead] ; Store Byte in buffer mov [byte ptr bx], al inc bx ; Update RecHead cmp bx, offset RecBuffer + BufSize jb @@10 mov bx, offset RecBuffer @@10: cmp bx, [RecTail] jne @@20 mov bx, [RecHead] ; Cancel Pointer advance on overflow @@20: mov [RecHead], bx ; Store new pointer @@end: mov al, EOI ; Signal end ot interrupt out Ctrl8259_0, al ; Disable and re-enable interrupts so that there ; is an interrupt edge. mov dx,[IER] ; Point to Interrupt Enable Register. in al,dx ; Read the current value. push ax ; Save it. mov al,0 ; Disable the interrupts. out dx,al pop ax ; Restore original mask. out dx,al ; Re-enable interrupts. pop dx ; Restore saved registers. pop ds pop bx pop ax iret ENDP AsyncISR ;----------------------------------------------------------------------------- ; AsyncIn Gets a byte from the input buffer ;----------------------------------------------------------------------------- ; int AsyncIn( void) ;----------------------------------------------------------------------------- PROC _AsyncIn push bp mov bp, sp xor ax, ax ; Pre-Set result to 0 mov bx, [RecTail] cmp bx, [RecHead] je @@return mov al, [byte ptr bx] inc [RecTail] cmp [word ptr RecTail], offset RecBuffer + BufSize jb @@return mov [RecTail], offset RecBuffer @@return: pop bp ret ENDP _AsyncIn ;----------------------------------------------------------------------------- ; AsyncOut Output a byte ;----------------------------------------------------------------------------- ; void AsyncOut( int c) ;----------------------------------------------------------------------------- PROC _AsyncOut ARG CharOut:word push bp mov bp, sp mov ax, [CharOut] mov bx, [TransHead] mov cx, bx inc cx ; Compute NEW buffer position cmp cx, offset TransBuffer + BufSize jb @@1 mov cx, offset TransBuffer @@1: cmp cx, [TransTail] ; Wait for space in buffer je @@1 mov [byte ptr bx], al ; Add byte to buffer mov [TransHead], cx ; Update pointer mov dx, [IER] ; Enable THR empty interrupt mov al, 3 out dx, al pop bp ret ENDP _AsyncOut ;----------------------------------------------------------------------------- ; AsyncSet Set communication paramaters ;----------------------------------------------------------------------------- ; void AsyncSet( int Baud, int Control) ; ; Baud = 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 28800, 38400, 57600 ; Control = The valure to place in the LCR ;----------------------------------------------------------------------------- PROC _AsyncSet ARG Baud:word, Control:word push bp mov bp, sp mov bx, [Baud] cmp bx, 0 je @@abort mov ax, 0C200h ; Baud rate divisor = 115200 / Baud mov dx, 0001h ; 115200 = 0001C200h div bx mov cx, ax cli mov dx, [LCR] ; Set Port Toggle to BRDL/BRDH registers mov al, 0ffh out dx, al mov dx, [BRDL] ; Set Baud Rate mov al, cl out dx, al mov dx, [BRDH] mov al, ch out dx, al mov dx, [LCR] ; Set LCR and Port Toggle mov ax, [Control] and al, 07Fh out dx, al sti @@abort: pop bp ret ENDP _AsyncSet ;----------------------------------------------------------------------------- ; AsyncInStat Returns the # of characters in buffer ;----------------------------------------------------------------------------- ; int AsyncInStat( void) ;----------------------------------------------------------------------------- PROC _AsyncInStat push bp mov bp, sp mov ax,[RecHead] sub ax, [RecTail] jge @@10 add ax, BufSize @@10: pop bp ret ENDP _AsyncInStat ;----------------------------------------------------------------------------- ; AsyncOutStat Returns the # of characters in buffer ;----------------------------------------------------------------------------- ; int AsyncOutStat( void) ;----------------------------------------------------------------------------- PROC _AsyncOutStat push bp mov bp, sp mov ax,[TransHead] sub ax, [TransTail] jge @@10 add ax, BufSize @@10: pop bp ret ENDP _AsyncOutStat ;----------------------------------------------------------------------------- ; AsyncHand Sets various handshaking lines ;----------------------------------------------------------------------------- ; void AsyncHand( int Hand) ;----------------------------------------------------------------------------- PROC _AsyncHand ARG Hand:word push bp mov bp, sp mov dx, [MCR] mov ax, [Hand] or al, 08h ; Keep interrupt enable ON out dx, al pop bp ret ENDP _AsyncHand ;----------------------------------------------------------------------------- ; AsyncStat Returns Async/Modem status ;----------------------------------------------------------------------------- ; unsigned AsyncStat( void) ; ; MSR is returned in the high byte, LSR in the low byte ;----------------------------------------------------------------------------- PROC _AsyncStat push bp mov bp, sp mov dx, [MSR] in al, dx mov cl, al mov dx, [LSR] in al, dx ; LSR in low byte mov ah, cl ; MSR in high byte pop bp ret ENDP _AsyncStat END