www.pudn.com > tcpipstack.rar > CASYNCMS.ASM
;CASYNCMS.ASM - for Microsoft C ;Based on CASYNC.ASM by Curt Klinsing ;A set of C callable functions to support ;interrupt driven character I/O on the IBM PC. Input ;is buffered, output is polled. ;910609 rr minor cleanup ;930811 rr conversion for microsoft C ;931213 rr fix various bugs (I hope) ;940529 rr move to 9600 .286p .seq ; ----- Equates ----------------------------------------------------- BASE equ 03F8H ;BASE FOR SERIAL BOARD (COM1) IER equ BASE+1 ;Interrup Enable Register LCR equ BASE+3 ;Line control register MCR equ BASE+4 ;modem control register LSR equ BASE+5 ;line status register MSR equ BASE+6 ;modem status register ; Bits in IER ERBFI equ 01H ;enable 'data-ready' interrupt bit ; Bits in LSR THRE equ 20H ;8250 tbe flag IntCtlr equ 21H ;OCW 1 FOR 8259 CONTROLLER EnblIRQ4 equ 0EFH ;Enable COMMUNICATIONS (IRQ4) MaskIRQ4 equ 10H ;BIT TO DISABLE COMM INTERRUPT (IRQ4) RS8259 equ 20H ;OCW 3 FOR 8259 RSTINT equ 64H ;SPECIFIC EOI FOR COMM INTERRUPT DosCall equ 21h ;INTERRUPT NUMBER FOR DOS CALL BUFSIZ equ 512 ;Max NUMBER OF CHARS (was 512) SetIntVect equ 25H ;SET INTERRUPT VECTOR FUNCTION NUMBER ;divisor is 48 for 2400 baud, 12 for 9600 baud, ; 96 for 1200 baud BAUDRATEDIVISOR equ 12 ; ----- Data segment ------------------------------------------------ _DATA SEGMENT PARA PUBLIC 'DATA' circ_buf db BUFSIZ DUP(?) ;ALLOW MaxIMUM BUFFERED CHARACTERS buf_top equ $ - 1 ;KEEP TRACK OF THE TOP OF THE BUFFER circ_in dw offset circ_buf ;POINTER TO LAST CHAR. PLACED ;IN BUFFER circ_cur dw offset circ_buf ;POINTER TO NEXT CHAR. TO BE ;RETRIEVED FROM BUFFER circ_cnt dw 0 ;COUNT OF CHARACTERS USED IN BUFFER _DATA ENDS ; ----- Code segment ------------------------------------------------ _TEXT SEGMENT PARA PUBLIC 'CODE' ASSUME CS: _TEXT, DS: _DATA ;int far inp_status( void ) ;Returns the number of characters available in the input buffer. PUBLIC _inp_status _inp_status PROC FAR push ds mov ax,_DATA mov ds,ax mov ax,word ptr circ_cnt pop ds ret _inp_status ENDP ;void far inp_flush( void ) ;Flush the input buffer. PUBLIC _inp_flush _inp_flush PROC FAR push ds mov ax,_DATA mov ds,ax mov bx,offset circ_buf mov word ptr circ_in,bx mov word ptr circ_cur,bx xor ax,ax mov word ptr circ_cnt,ax pop ds ret _inp_flush ENDP ;--------- Init ----------------------------------- ;Program initialization: ;-- Set up vector for RS232 interrupt (0CH) ;-- Enbl IRQ4 ;-- Enbl RS232 interrupt on data ready ;--------------------------------------------------- ;void far init_comm( void ) PUBLIC _init_comm _init_comm PROC FAR push bp ;in case damaged by dos call cli ;disable interrupts ;---- Set up INT x'0C' for IRQ4 (COM1) push ds ;save DS mov ax,cs mov ds,ax ;put CS into DS mov dx,offset IntHdlr ;relative address of interrupt handler mov al,0CH ;interrupt number for comm. mov ah,SetIntVect ;function number for setting int vector int DosCall ;set interrupt in 8086 table pop ds ;restore DS ;---- Enbl IRQ4 on 8259 interrupt controller cli ;disable interrupts - again in al,IntCtlr ;get current masks and al,EnblIRQ4 ;Reset IRQ4 mask out IntCtlr,al ;And restore to IMR ;--- Set up 8250 port ;divisor is 48 for 2400 baud, 12 for 9600 baud, ; 96 for 1200 baud mov dx,LCR mov al,083h ;DLAB = 1 out dx,al ;to access baud rate divisors mov dx,BASE mov ax,BAUDRATEDIVISOR ;set baud rate divisor lsb out dx,al inc dx ;set baud rate divisor msb mov al,ah out dx,al mov dx,LCR mov al,03h ;8 bits, no parity, 1 stop out dx,al ;--- Enbl 8250 data ready interrupt mov dx,IER ;Interrupt Enbl Register mov al,ERBFI ;Enable 'data-ready' interrupt out dx,al ;--- Enbl OUT2 on 8250 mov dx,MCR ;modem control register mov al,0BH ;Enable OUT2, DCD and DTR out dx,al pop bp sti ;enable interrupts ret _init_comm ENDP ;void far uninit_comm( void ) ;Removes the interrupt structure ;installed by init_comm(). Must be ;done before passing control to the DOS, else chars received ;will be stored into the next program loaded! PUBLIC _uninit_comm _uninit_comm PROC FAR push bp ;--- Disable IRQ4 on 8259 cli in al,IntCtlr ;GET OCW1 FROM 8259 or al,MaskIRQ4 ;DISABLE COMMUNICATIONS INTERRUPT out IntCtlr,al ;--- Disable 8250 data ready interrupt mov dx,LCR ;DX ==> LCR in al,dx ;Reset DLAB for IER access and al,7FH out dx,al mov dx,IER ;Interrupt Enbl Register mov al,0 ;Disable all 8250 interrupts out dx,al ;--- Disable OUT2 on 8250 mov dx,MCR ;modem control register mov al,0 ;Disable OUT2 out dx,al sti ;reenable interrupts pop bp ret _uninit_comm ENDP ;int far inp_char( void ) ;Return a character from the input ;buffer. Assumes you have called ;inp_status() to see if theres any characters to get. PUBLIC _inp_char _inp_char PROC FAR push ds mov ax,_DATA mov ds,ax ;put _DATA in DS mov bx,word ptr circ_cur xor ax,ax mov al,[bx] ;get next char from circ_buf dec word ptr circ_cnt ;decrement circ_buf COUNT cmp bx,offset buf_top jz reset_cur ;JUMP IF SO inc bx ;ELSE, BUMP PTR jmp upd_cur reset_cur: mov bx,offset circ_buf ;RESET circ_cur TO BOTTOM OF BUF. upd_cur: mov word ptr circ_cur,bx ;SAVE NEW PTR pop ds ret _inp_char ENDP ;void far outp_char( int c ) ;Output the character to the ;char c;serial port. This is not buffered ;or interrupt driven. PUBLIC _outp_char _outp_char PROC FAR push bp mov bp,sp comout: mov dx,LSR in al,dx ;get 8250 status and al,THRE ;check for transmitter ready jz comout ;jump if not to wait mov al,[bp+6] ;get char to al mov dx,BASE ;data port out dx,al ;output char to 8250 pop bp ret _outp_char ENDP ; ----- RECEIVE INTERRUPT HANDLER ----------------------------------- PUBLIC IntHdlr IntHdlr PROC FAR cli ;disable interrupts push dx push bx push ax push ds mov ax,_DATA mov ds,ax mov bx,word ptr circ_in ;GET circ_buf IN PTR mov dx,BASE ;GET DATA PORT NUMBER in al,dx ;GET RECEIVED CHARACTER cmp word ptr circ_cnt,BUFSIZ ;SEE IF circ_buf ALREADY FULL jz clnup ;jump if so, discard char savch: mov [bx],al ;SAVE NEW CHARACTER IN circ_buf inc word ptr circ_cnt ;BUMP circ_buf COUNT cmp bx,offset buf_top ;ARE WE AT THE TOP OF THE circ_buf? jz reset_in ;JUMP IF SO inc bx ;ELSE, BUMP PTR jmp into_buf reset_in: mov bx,offset circ_buf ;RESET circ_in TO BOTTOM OF BUF. into_buf: mov word ptr circ_in,bx ;SAVE NEW PTR clnup: mov al,RSTINT out RS8259,al ;ISSUE SPECIFIC EOI FOR 8259 pop ds ;GET BACK ENTERING DS pop ax pop bx pop dx sti iret IntHdlr ENDP _TEXT ENDS END