; ; Low level ASYNC serial I/O driver for ; use with DDS MICRO-C compiler on IBM/PC. ; ; Copyright 1990-2000 Dave Dunfield ; All rights reserved. ; ; Misc constants. ?BUFMSK EQU $00FF ;Buffer size mask ?WINDOW EQU 256-30 ;Flow control assertion window ?RXRDY EQU %00000001 ;Uart Receiver ready flag ?TXRDY EQU %00100000 ;Uart Transmitter ready flag ?8259 EQU $0020 ;8259 interrupt controller ; Bits in driver control flags ?RFLOW EQU %10000000 ;Received flow control ?TFLOW EQU %01000000 ;Transmit flow control ?TXOFF EQU %00100000 ;Transmit XOFF pending ?TXON EQU %00010000 ;Transmit XON pending ?XPAREN EQU %00001000 ;Transparency enabled ; $SE:1 ; ; Initialized variables & tables ; Cflags DB 0 ;Control flags ?comvec DW 0 ;Comm interrupt vector ; $DD:?rdptr 2 ;Buffer read pointer $DD:?wrptr 2 ;Buffer write pointer $DD:?comadr 2 ;Com port address $DD:?oldoff 2 ;Saved old interrupt offset $DD:?oldseg 2 ;Saved old interrupt segment $DD:?buffer 256 ;Receive buffer ; $SE:0 ; ; Open the com port: Copen(int port, int speed, char mode, char modem) ; Copen PUSH BP ;Save callers stack MOV BP,SP ;Address parameters CALL Cclose ;Insure its closed MOV AX,10[BP] ;Get com port MOV DX,#$03FD ;Comm 1 address MOV BX,#$0030 ;Comm 1 interrupt vector MOV CL,#$0EF ;Comm 1 interrupt mask DEC AX ;Is it com1? JZ ?2 ;Yes, it is MOV DX,#$02FD ;Comm 2 address MOV BX,#$002C ;Comm 2 interrupt vector MOV CL,#$0F7 ;Comm 2 interrupt mask DEC AX ;Is it com2? JZ ?2 ;Yes it is ; Report failure to open port ?1 STI ;Insure interrupts enabled MOV AX,#-1 ;Indicate failure POP BP ;Restore caller RET ; Proceed with opening the comm port ?2 MOV ?comadr,DX ;Save address CLI ;Inhibit interrupts ; Setup the uart DEC DX ;Backup ... DEC DX ;to line control register (FB) IN AL,DX ;Read current value OR AL,#$80 ;Enable baud rate register OUT DX,AL ;Write it MOV AX,8[BP] ;Get baud rate SUB DX,#3 ;Point to baud rate LSB (F8) OUT DX,AL ;Write it INC DX ;Advance to MSB (F9) MOV AL,AH ;Get MSB OUT DX,AL ;Write it DEC DX ;Backup to LSB (F8) IN AL,DX ;Re-read LSB MOV AH,AL ;Copy for later INC DX ;Back to MSB (F9) IN AL,DX ;Re-read MSB XCHG AH,AL ;Swap for multi CMP AX,8[BP] ;Does it match JNZ ?1 ;No, its dosn't MOV AL,6[BP] ;Get mode AND AL,#$7F ;Insure no baud rate INC DX ;Advance... INC DX ;to line control register (FB) OUT DX,AL ;Write it MOV AL,#$01 ;Receive interrupt only DEC DX ;Backup ... DEC DX ;to Interrupt enable register (F9) OUT DX,AL ;Write it MOV AL,4[BP] ;Get modem control ADD DX,#3 ;Point to modem control register (FC) OUT DX,AL ;Write it ; Setup the interrupt vector MOV ?comvec,BX ;Save interrupt vector MOV CS:?dsval,DS ;Save data segment for int handler XOR AX,AX ;Get a zero MOV ?rdptr,AX ;Zero read pointer MOV ?wrptr,AX ;Zero write pointer MOV AX,ES:[BX] ;Get old offset MOV ?oldoff,AX ;Save old offset MOV AX,ES:2[BX] ;Get old segmemt MOV ?oldseg,AX ;Save segment MOV AX,#?COMINT ;Point to routine MOV ES:[BX],AX ;Write new offset MOV ES:2[BX],CS ;Write new segment ; Clear out any pending characters SUB DX,#4 ;Point to data register (F8) IN AL,DX ;Read to clear interrupt IN AL,DX ;Read to clear interrupt ; Setup the interrupt controller IN AL,?8259+1 ;Read interrupt mask AND AL,CL ;Enable serial port OUT ?8259+1,AL ;Write interrupt controller STI ;Re-enable interrupts XOR AX,AX ;Indicate success POP BP ;Restore caller RET ; ; Close the comm port: Cclose() ; Cclose XOR AX,AX ;Get zero MOV ES,AX ;Point to interrupt vectors MOV BX,?comvec ;Get old vector AND BX,BX ;Is it set? JZ ?3 ;No, its not MOV ?comvec,AX ;Indicate not set CLI ;Disable interrupts ; Restore the old comm interrupt vector MOV DX,?oldoff ;Get old offset MOV ES:[BX],DX ;Restore old offset MOV DX,?oldseg ;Get old segment MOV ES:2[BX],DX ;Restore old segment ; Disable interrupts on the uart MOV DX,?comadr ;Get uart address SUB DX,#4 ;Point to interrupt enable register OUT DX,AL ;Write zero IN AL,?8259+1 ;Read interrupt mask OR AL,#$18 ;Disable comm interrupts OUT ?8259+1,AL ;Write interrupt mask STI ;Re-enable interrupts ?3 RET ; ; Test for char from com port: int Ctestc() ; Ctestc MOV BX,?rdptr ;Get read pointer CMP BX,?wrptr ;Test for data in buffer JNZ ?4 ;Yes, we have some MOV AX,#-1 ;Report no data available RET ; ; Read a character from the comport: int Cgetc() ; Cgetc MOV BX,?rdptr ;Get read pointer CMP BX,?wrptr ;Test for data in buffer JZ Cgetc ;No characters, wait for them ; Read character from com port ?4 MOV DI,#?buffer ;Get I/O buffer address MOV AL,[BX+DI] ;Get character from buffer XOR AH,AH ;Zero high INC BX ;Advance read pointer AND BX,#?BUFMSK ;Mask for buffer wrap MOV ?rdptr,BX ;Resave read pointer CMP BX,?wrptr ;Did we just empty buffer? JNZ ?3 ;No, its ok PUSH AX ;Save for later ; Buffer is empty, send XON if necessary MOV DX,?comadr ;Point to com port CLI ;No interrupts MOV AH,Cflags ;Get control flags TEST AH,#?TFLOW ;Flow controlled? JZ ?7 ;No, its not AND AH,#~(?TFLOW|?TXOFF|?TXON) ;Clear flags IN AL,DX ;Get status TEST AL,#?TXRDY ;Ok to send? JZ ?5 ;No, set pending SUB DX,#5 ;Backup to data port MOV AL,#'Q'-$40 ;Get XON character OUT DX,AL ;Send the XON JMP <?6 ;And continue ; Cannot send not, set pending flag ?5 OR AH,#?TXON ;Set XON pending flag ?6 MOV Cflags,AH ;Resave the flags ?7 STI ;Re-enable interrupts POP AX ;Restore character RET ; ; Write a character to the com port: Cputc(char c) ; Cputc PUSH BP ;Save callers stack frame MOV BP,SP ;Address parameters ?8 MOV DX,?comadr ;Get address of uart IN AL,DX ;Read uart status TEST AL,#?TXRDY ;Ok to transmit JZ ?8 ;No, wait for it SUB DX,#5 ;Position to data address CLI ;Disallow interrupts MOV AH,Cflags ;Get control flags ; Test for pending XOFF to send TEST AH,#?TXOFF ;Transmit XOFF? JZ ?9 ;No, try next MOV AL,#'S'-$40 ;Get XOFF AND AH,#~?TXOFF ;Clear the bit JMP <?10 ;Write to comm port ; Test for pending XON to send ?9 TEST AH,#?TXON ;Transmit XON? JZ ?11 ;No, output character MOV AL,#'Q'-$40 ;Get XON AND AH,#~?TXON ;Clear the bit ; Resave the control flags & proceed ?10 MOV Cflags,AH ;Re-save control flags STI ;Re-enable interrupts OUT DX,AL ;Write character JMP <?8 ;And proceed ; No pending flow control, output data ?11 STI ;Re-enable interrupts TEST AH,#?RFLOW ;Output inhibited? JNZ ?8 ;Yes, wait for it MOV AL,4[BP] ;Get character OUT DX,AL ;Write to comm port POP BP ;Restore caller RET ; ; Read the com port signals: int Csignals() ; Csignals MOV DX,?comadr ;Get the com port address INC DX ;Advance to modem status register IN AL,DX ;Read modem status XOR AH,AH ;Zero high bits RET ; ; Comms Interrupt handler ; ?COMINT PUSH AX ;Save AX PUSH BX ;Save BX PUSH DX ;Save DX PUSH DI ;Save DI PUSH DS ;Save DS MOV DS,CS:?dsval ;Get data segment MOV DX,?comadr ;Get com port I/O address IN AL,DX ;Read uart status register TEST AL,#?RXRDY ;Receiver ready? JZ ?15 ;No, Spurious interrupt SUB DX,#5 ;Backup to data port MOV AH,Cflags ;Get comm flags IN AL,DX ;Read data character TEST AH,#?XPAREN ;Are we transparent? JNZ ?13 ;Yes, do not interpret flow control ; Test for XOFF, inhibit output CMP AL,#'S'-$40 ;Is it XOFF? JNZ ?12 ;No, try next OR AH,#?RFLOW ;Set flow control bit JMP <?14 ;and continue ; Test for XON, enable output ?12 CMP AL,#'Q'-$40 ;Is it XON JNZ ?13 ;No, its not AND AH,#~?RFLOW ;Reset flow control bit JMP <?14 ;and continue ; Normal character, stuff in buffer ?13 MOV DI,#?buffer ;Get I/O buffer address MOV BX,?wrptr ;Get write pointer MOV [BX+DI],AL ;Write into buffer INC BX ;Advance AND BX,#?BUFMSK ;Mask for buffer wrap MOV ?wrptr,BX ;Resave pointer ; Test for nearing end of buffer SUB BX,?rdptr ;Calculate size of buffer AND BX,#?BUFMSK ;Mask for buffer wrap CMP BX,#?WINDOW ;Are we nearing end JB ?15 ;No, its ok TEST AH,#?XPAREN ;Are we transparent? JNZ ?15 ;Don't send flow ctrl ; Send XOFF, flow control dest OR AH,(?TFLOW|?TXOFF) ;Indicate flow control asserted AND AH,#~?TXON ;Insure no XON pending ADD DX,#5 ;Offset to status register IN AL,DX ;Read status TEST AL,#?TXRDY ;Test for transmitter ready JZ ?14 ;Not ready SUB DX,#5 ;Backup to data port MOV AL,#'S'-$40 ;Get XOFF character OUT DX,AL ;Write to port AND AH,#~?TXOFF ;No pending XOFF needed ; Resave status flags to record ;changes ?14 MOV Cflags,AH ;Resave flags ; Reset 8259, Restore registers ;& return from interrupt ?15 MOV AL,#$20 ;End of Interrupt command OUT ?8259,AL ;Write to interrupt controller POP DS ;Restore DS POP DI ;Restore DI POP DX ;Restore DX POP BX ;Restore BX POP AX ;Restore AX IRET ; Saved data segment incase we are running in small model ?dsval DW 0 ;Stored code segment value D
file: /Techref/com/dunfield/ftp/embedpc/comm_asm.htm, 28KB, , updated: 2000/5/5 09:49, local time: 2024/11/19 17:17,
18.118.33.35:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/Techref/com/dunfield/ftp/embedpc/comm_asm.htm"> Comm.asm </A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to massmind.org! |
.