; ASYNC.SAL Driver for RS232 fra Turbo Pascal V4 ; Version 2.0 ; Date: 87-11-19, 20:10 saljmp short salcmp unsigned salmac := mov &-,&+ include pascal.mac buffers struc PortNr dw ? IntNr dw ? oldModemCntrReg db ? oldLevel db ? oldVector dd ? Inx dw ? R_Buf2 dw ? OutX dw ? SizeX dw ? LimitX dw ? InT dw ? OutT dw ? T_Buf2 dw ? SizeT dw ? Send_T dw ? Show_X dw ? Show_X2 dw ? Toggle_Xoff dd ? RLS_user dd ? MODEM_user dd ? Ctrl_P db ? UseTInt db ? HostX db ? Bfull db ? AutoX db ? AltX db ? Xoff1C db ? Xoff2C db ? Xon1C db ? Xon2C db ? Line_Status db ? MODEM_Status db ? WaitTX db ? Int_Mask db ? buffers ends DXofs MACRO ofs mif ofs ife ofs - 1 inc dx else ife ofs + 1 dec dx else add dx,ofs endif endif endif ENDM InPort MACRO ofs dx := [bx.PortNr] DXofs in al,dx ENDM OutPort MACRO ofs dx := [bx.PortNr] DXofs out dx,al ENDM InPOfs MACRO ofs DXofs in al,dx ENDM OutPOfs MACRO ofs DXofs out dx,al ENDM LineContrReg = 3 ; (* to specify format of transmitted data *) LowBaudRateDiv = 0 ; (* lower byte of divisor to select baud rate *) HighBaudRateDiv = 1 ; (* higher byte of divisor *) LineStatusReg = 5 ; (* holds status info on the data transfer *) ReceiverReg = 0 ; (* received CHAR is in this register *) TransmitReg = 0 ; (* CHAR to send is to put in this reg *) IntEnableReg = 1 ; (* to enable the selected interrupt *) IntIdentReg = 2 ; (* to identify the interrupt *) ModemContrReg = 4 ; (* controls the interface to a modem *) ModemStatusReg = 6 ; (* holds status of line (BREAK etc.) *) Icntrlw2 = 20h ;Interrupt controller SEOI1 = 64h ;EOI for COM1 SEOI2 = 63h ;EOI for COM2 FALSE = 0 TRUE = 1 RLSint = 6 RDRint = 4 THREint = 2 MODEMint = 0 DATA SEGMENT WORD PUBLIC ASSUME DS:DATA EXTRN RS_BufPtr:WORD EXTRN RS_TimeOut:WORD DATA ENDS CODE SEGMENT BYTE PUBLIC ASSUME CS:CODE public Rs_Com4int Rs_Com4int proc far push ax push bx mov bx,offset DATA:rs_bufptr[12] jmp short comcont public rs_com3int rs_com3int proc far push ax push bx mov bx,offset DATA:rs_bufptr[8] jmp short comcont public rs_com2int rs_com2int proc far push ax push bx mov bx,offset DATA:rs_bufptr[4] jmp short comcont public rs_com1int rs_com1int proc far push ax push bx mov bx,offset DATA:rs_bufptr[0] comcont: push ds mov ax, DATA mov ds,ax ASSUME DS:DATA mov bx,[bx] ; Reset Video TimeOut Count rs_timeout := 0 ; STI ;Enable int's push cx push dx push di push si push es repeat_int: CLI InPort IntIdentReg ;Hvorfor er jeg her? if al = RDRint then call ReadInt jmp repeat_int endif if al = THREint then ;TX int call SendNext ;Restart jmp repeat_int endif if al = RLSint then InPOfs and al,1Eh ;Keep OE(2),PE(4),FE(8) and BI(10) or [bx.Line_Status],al jmp repeat_int endif if al = MODEMint then InPOfs ;Restart async chip or [bx.MODEM_Status],al if word ptr [bx].MODEM_user <> 0 then push bx push ds call dword ptr [bx+MODEM_user] pop ds pop bx endif jmp repeat_int endif InPOfs ;Restart async chip or [bx.MODEM_Status],al jmp $+2 InPOfs and al,1Eh ;Keep OE(2),PE(4),FE(8) and BI(10) or [bx.Line_Status],al pop es pop si pop di pop dx pop cx pop ds pop bx ; Enable HW int's CLI al := 20h out Icntrlw2,al pop ax iret rs_com1int endp rs_com2int endp rs_com3int endp rs_com4int endp ReadInt Proc near InPOfs ;Get received char ; Test if room in buffer les si,dword ptr [bx.InX] ;Get buffer Address lea di,[si+1] if di >= [bx.SizeX] then xor di,di if di <> [bx.OutX] then ;Buffer not full es:[si] := al [bx.InX] := di else or [bx.Line_Status],20h ;Overrun Error! endif STI if [bx.AutoX] = FALSE then ret ; Test if XOFF or XON ah := al ; Test if XOFF or XON and ah,7fh ; Use 7 low bits! if [bx.Ctrl_P] < 1 then if [bx.HostX] = FALSE then cmp ah,[BX.Xoff1C] je TurnOff if [bx.AltX] = TRUE then cmp ah,[bx.Xoff2C] je TurnOff endif endif cmp ah,[BX.Xon1C] je TurnOn cmp [bx.AltX],TRUE jne nochange cmp ah,[bx.Xon2C] je TurnOn jmp short nochange endif if = then ; if [bx.Ctrl_P] = 1 then if ah = 10h then [bx.Ctrl_P] := 2 jmp short nochange endif cmp [bx.HostX],TRUE je TurnOn cmp ah,[bx.Xoff1C] je TurnOff jmp short nochange endif if [bx.Ctrl_P] = 2 then [bx.Ctrl_P] := 3 jmp short nochange endif [bx.Ctrl_P] := 1 jmp short nochange TurnOn: [bx.HostX] := FALSE ; Save new value call StartSender al := ' ' jmp short updateX TurnOff: [bx.HostX] := TRUE al := 'X' UpdateX: if [bx.Show_X2] <> 0 then les di,dword ptr [bx.Show_X] es:[di] := al endif NoChange: ; Test if buffer almost full dx := [bx.OutX] di := [bx.InX] inc di sub dx,di ;InX if carry then add dx,[bx.SizeX] ; dx = Free space in buffer cmp dx,[bx.LimitX] jbe almost_full ret ;Buffer not full, early exit Almost_Full: test [bx.Bfull],1 ;Is our bit set? jnz Second_Limit ;Yes, check if past second limit or [bx.Bfull],1 ;Set our bit Stop_Rec: if [bx.UseTint] = TRUE then al := [bx.Xoff1C] ah := TRUE [bx.Send_T] := ax ;Send before all others call StartSender ret ;Exit after XOFF sent endif call WaitTHRE al := [bx.Xoff1C] out dx,al ret Second_Limit: shl dx,1 cmp dx,[bx.LimitX] jbe Stop_Rec ret ReadInt endp WaitTHRE proc near mov dx,[bx].PortNr DXofs LineStatusReg repeat in al,dx ah := al and ah,1Eh or [bx.Line_Status],ah until al AND 20h true DXofs ret WaitTHRE endp SendByte proc near ; Sending WO TX-int ; INPUT al : byte to send ; OUTPUT ah : status ; REG'S dx push ax call WaitTHRE pop ax ah := FALSE; if [bx.HostX] = FALSE then out dx,al ah := TRUE endif ret SendByte EndP SendInt Proc near ; Use buffered sending ; INPUT al : byte to send ; OUTPUT ah : status ; REG'S dx,si,di,es, si := [bx.InT] lea di,[si+1] if di >= [bx.SizeT] then xor di,di ah := FALSE if di <> [bx.OutT] then es := [bx.T_Buf2] es:[si] := al [bx.InT] := di ;Update input pointer ah := TRUE endif call StartSender ;Restart if neccessary ret SendInt endp StartSender proc near push ax call SendNext ;Turn on TX int's again! InPort IntEnableReg or al,2 out dx,al pop ax ret StartSender endp SendNoMore: ; Turn off TX int's when no more data InPort IntEnableReg and al,NOT 2 out dx,al ret SendNext Proc near ;SI ; INPUT ; OUTPUT ; REG'S dx,ax,si,es if [bx.WaitTX] = FALSE then InPort LineStatusReg ah := al and ah,1Eh or [bx.Line_Status],ah if al AND 20h true then DXofs xor ax,ax xchg ax,[bx.Send_T] if ah <> FALSE then out dx,al elseif [bx.HostX] = FALSE then les si, dword ptr [bx.OutT] if si = [bx.InT] then jmp SendNoMore cld lods byte ptr es:[si] if si >= [bx.SizeT] then xor si,si [bx.OutT] := si out dx,al endif endif endif STI ret SendNext endp avail proc near ; INPUT ; OUTPUT cx : bytes in input buffer ; REG'S cx cx := [bx.InX] sub cx,[bx.OutX] if carry then add cx,[bx.sizeX] ret avail endp checkempty proc near ;Local proc for read and readblock ; INPUT ; OUTPUT ; REG'S cx,ax if [bx.Bfull] and 1 true then call avail if cx <= [bx.LimitX] then and [bx.Bfull],254 if zero then [bx.WaitTX] := TRUE ;Allocate TX call WaitTHRE al := [bx.Xon1C] out dx,al [bx.WaitTX] := FALSE endif endif endif ret checkempty endp intro MACRO com bx := [bp+com] shl bx,1 shl bx,1 bx := rs_bufptr[bx-4] ENDM PasProc rs_readblock FAR ; REG'S dx,cx,si,di,es,bx,ax intro com xor dx,dx ;zero bytes read call avail if cx > [bp].max then cx := [bp].max ;max bytes jcxz skipblock mov si,[bx.OutX] ;output index les di,[bp].buf ;buffer address cld ;les forover! dx := [bx.SizeX] ;Copy of size push ds ds := [bx.R_buf2] ;Segment of buffer push bx xor bx,bx ;bytes read repeat lodsb if si >= dx then xor si,si ah := al inc ah and ah,7fh if ah <= ' ' then if bx <> 0 then if si = 0 then si := dx dec si leave endif stosb inc bx leave endif stosb inc bx until loop dx := bx ;Save bytes read pop bx pop ds [bx.OutX] := si skipblock: les di,[bp].byt es:[di] := dx ;bytes read in block call checkempty PasRet PasProc rs_busyread FAR intro com si := [bx.OutX] ax := FALSE if si <> [bx.InX] then es := [bx.R_Buf2] cld lods byte ptr es:[si] if si >= [bx.SizeX] then xor si,si [bx.OutX] := si les di,[bp+chr] ;ch stosb call checkempty al := TRUE endif les di,[bp.done] stosb PasRet PasProc rs_getchar FAR intro com si := [bx.OutX] xor ax,ax ; Return value if si <> [bx.InX] then es := [bx.R_Buf2] cld lods byte ptr es:[si] xor dx,dx ah := al inc ah and ah,7fh if ah > ' ' then if si >= [bx.SizeX] then xor si,si [bx.OutX] := si les di,[bp+chr] ;ch stosb call checkempty dl := TRUE endif ax := dx endif PasRet PasProc rs_write FAR intro com al := [bp+chr] if [bx.UseTInt] = TRUE then call SendInt else call SendByte endif les di,[bp.done] es:[di] := ah PasRet PasProc rs_writeblock FAR intro com cld ;Forward if [bx.UseTint] = FALSE then les si,[bp+buf] ;buf cx := [bp+len] ;len dx := cx ;bytes sent jcxz skipwr push dx repeat lods byte ptr es:[si] call SendByte if ah = FALSE then leave until loop pop dx sub dx,cx skipwr: ax := dx ;Bytes sent else ;Use TX int's ; Compute free room in TX buffer cx := [bx.OutT] di := [bx.InT] lea si,[di+1] ax := [bx.SizeT] sub cx,si ; OutT - (InT+1) if carry then add cx,ax if cx > [bp+len] then cx := [bp+len] ;Min(room,len) push cx ;Bytes sent jcxz skipwblock ;Request to send zero bytes! es := [bx.T_Buf2] ; di := [bx.InT] ; OK from start push ds mov ds,[bp+bufs] ;******************* Her peker DS p bufferet, ikke p RS_Buffer! mov si,[bp+buf] ;buf sub ax,di ;Size - InT if ax < cx then ;Room on top of buffer? sub cx,ax ;Overflow part xchg cx,ax ;Room on top rep movsb ;First block xor di,di ;Continue from start of TX buffer cx := ax ;last part endif rep movsb ;Second block pop ds ;******************** N er DS:BX ok igjen! if di >= [bx.SizeT] then xor di,di [bx.InT] := di skipwblock: pop ax ; # of bytes sent endif les di,[bp+done] stosw call StartSender PasRet PasProc rs_avail FAR intro com call avail ax := cx PasRet PasProc rs_room FAR ;Room in output buffer intro com ax := [bx.OutT] dx := [bx.InT] inc dx sub ax,dx if carry then add ax,[bx].SizeT PasRet PasProc rs_enable FAR intro com [bx.HostX] := FALSE mov al,0 OutPort IntEnableReg al := [bx].Int_Mask out dx,al al := TRUE xchg al,[bx.WaitTX] if al = FALSE then call StartSender [bx.WaitTX] := FALSE endif PasRet PasProc rs_writefirst FAR intro com [bx.WaitTX] := TRUE ;Allocate transmitter! call WaitTHRE al := [bp+chr] ;ch to send first out dx,al [bx.WaitTX] := FALSE PasRet CODE ENDS END