|
|
page,132 ;---------------------------Module-Header-------------------------------; ; Module Name: IBMCOM.ASM ; ; !!! ; ; Created: Fri 06-Feb-1987 10:45:12 ; Author: Walt Moore [waltm] ; ; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved. ; ; General Description: ; ; History: ; ; *************************************************************** ; Tue Dec 19 1989 09:32:15 -by- Amit Chatterjee [amitc] ; --------------------------------------------------------------- ; Modified the 'InitAPort' routine called from 'ReactivateOpenCommPort'. ; If the out queue for a port has characters to send out then we must ; restart the trasmission process by faking a comm interrupt on that ; port. ; *************************************************************** ; Tue Nov 21 1989 09:46:50 -by- Amit Chatterjee [amitc] ; --------------------------------------------------------------- ; The base port addresses in the COMM1,COMM2,COMM3,COMM4 structures ; are being zeroed out when the corresponding comm port is closed. ; This is because the 'ReactivateOpenCommPort' function looks at it ; and if the port address is not zero decides that comm ports are ; open. ; *************************************************************** ; Tue Nov 14 1989 18:42:00 ADDED TWO EXPORTED FUNCTIONS ; --------------------------------------------------------------- ; Added two exported functions 'SuspendOpenCommPorts' and ; 'ReactivateOpenCommPorts' for 286 winoldap support. The first one simply ; releases the comm int vects and installs the originall one, the second one ; hooks back the comm driver comm vectors and then reads the receive buffer, ; the status and the IIR registers of all the available comm ports to ; remove pending interrupts. It also reprograms the PIC to enable interrupts ; on all open comm channels. ; --------------------------------------------------------------- ; -by- Amit Chatterjee [amitc] ; *************************************************************** ; Tue Aug 30 198? 12:52:00 MAJOR FIX TO HANDLE 8250B ; --------------------------------------------------------------- ; ; 8250B has the following peculiar charactersistic ; . The very first time (after reset) the Tx Holding Empty ; interrupt is enabled, an immediate interrupt is generated ; ; . After the first time, switching the Tx Holding Empty ; interrupt enable bit from disabled to enabled will NOT ; generate an immediate interrupt (unlike in 8250) ; Because of this the KICKTX routine fails to set the transmit cycle ; on if the machine has a 8250B ; ; This has been taken care as follows: ; . For the very first byte that is being transmitted, KICKTX ; is used to generate the first Tx Holding Empty interrupt ; . Subsequently, whenever we find that the transmit buffer ; is empty, we use a SOFTWARE INT (either INT 0Bh, or INT 0Ch) ; to force the first character out, once this is done the ; Tx Holding Empty interrupt will be generated once the buffer ; really is empty ; . Now we no longer disable the Tx Holding Empty interrupt ; in the Xmit ISR to ensure that even m/cs with 8250, use ; the software int to kick the tx interrupt on after the ; first time. ; . The software interrupt is also forced whenever an X-ON ; character is received. ; ; The code that implements the above logic is marked out with a line ; asterixes. ; ------------------------------------------------------------------ ; -by- Amit Chatterjee [amitc] ; ****************************************************************** ; ; 062587 HSFlag and Evtmask in DoLPT. These fields do not exist ; for LPT type devices. The code which manipulated them ; was removed ; ; KickTx from $SndCom - interrupts were not disabled when ; calling KickTx. ; ; $SetCom - added CLD at the start ; ; $SetQue - movsw ==> stosw ; ; 111285 Changed the Timeout from 7 to 30 seconds. ; ; 110885 Forgot to set EV_RxChar event when a character ; was received. ; ; 102985 INS8250, INS8250B bug with enabling interrupts. ; Setting ACE_ETBEI in the Interrupt Enable Register ; will cause an immediate interrupt regardless of ; whether the transmitter register is empty or not. ; The first interrupt MAY also be missed. ; ; The first case is not a problem since we only enable ; interrupts if the transmitter register is empty. The ; second problem was showing up on Microsoft System Cards ; in PC-XTs. The first interrupt was missed after a cold ; boot. National claims the fix is to write the register ; twice, which SEEMS to work... ; ; Added timeout code to $TRMCOM. If the number of ; characters in the output queue doesn't decrease ; in "Timeout" seconds, then the port will be closed ; anyway. Also flushed the input queue and added a ; discard-input flag for the data available interrupt ; code to discard any input received while terminating ; a port. $TRMCOM will return an error code if it ; discarded any output data. ; ; Removed infinite timeout test in MSRWait routine. ; Still bad, but it will timeout around 65 seconds ; instead of never. ; ; 102785 LPT initialization code was jumping to InitCom90, ; which was setting EFlags[si] to null. Well, LPTs ; don't have an EFlags field, so the null was getting ; stuffed over the LSB of BIOSPortLoc of the next LPT ; device. ; ; 101185 Save interrupt vector when opening a comm port ; and restore it when closing. Would you believe ; there are actually programs that assume the ; vector points to a non-specific 8259 ACK and ; an IRET! ; ; 100985 Added MS-NET support to gain exclusive control ; of an LPT port if DOS 3.x and not running in as ; a server, receiver, or messenger. Required to ; keep another application, such as command.com ; from closing the stream or mixing their output ; with ours. ; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping ; FCLI/FSTI macros ;-----------------------------------------------------------------------;
title IBMCom - IBM PC, PC-XT, PC-AT, PS/2 Communications Interface
.xlist include cmacros.inc include comdev.inc include ins8250.inc include ibmcom.inc include vint.inc .list
externNP GetDEB externNP DoLPT externNP StringToLPT externNP FindCOMPort externNP StealPort
sBegin Data
externB $MachineID
sEnd Data
sBegin Code assumes cs,Code assumes ds,Data
page
;----------------------------Public Routine-----------------------------; ; ; $RECCOM - Receive Characters From Device ; ; Read Byte From RS232 Input Queue If Data Is Ready ; ; LPT ports will return with an indication that no characters are ; available. ; ; Entry: ; AH = Device ID ; Returns: ; 'Z' clear if data available ; AL = byte ; Error Returns: ; 'Z' Set if error or no data ; AX = error code ; AX = 0 if no data ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $RECCOM $RECCOM proc near
push si ;Once again, save some registers push di call GetDEB ;Get DEB pointer in SI jc RecCom10 ;Invalid Port [rkh] ... jns RecCom20 ;COM port jmp RecCom95 ;LPT port, return no characters
RecCom10: jmp RecCom100 ; Invalid Port
; Before removing any charcters from the input queue, check to see ; if XON needs to be issued. If it needs to be issued, set the ; flag that will force it and arm transmit interrupts.
RecCom20: test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack? jz RecCom32 ; No test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped? jnz RecCom21 ; No Enq recvd & no lines dropped jmp RecCom60 ; No Enq recvd & no lines dropped RecCom21: jmp short RecCom34
RecCom32: test HSFlag[si],HSSent ;Handshake sent? jnz RecCom33 ; No XOFF sent & no lines dropped jmp RecCom60 ; No XOFF sent & no lines dropped RecCom33:
RecCom34: mov ax,QInCount[si] ;Get current count of input chars cmp ax,[si.DCB_XonLim] ;See if at XOn limit ja RecCom60 ;Not at XOn limit yet
; If any hardware lines are down, then raise them. Then see ; about sending XON.
mov dx,Port[si] ;Get the port mov ah,HHSLines[si] ;Get hardware lines mask call DOCLI ;Handle this as a critical section mov cl,HSFlag[si] ;Get handshaking flags or ah,ah ;Any hardware lines to play with? jz RecCom40 ; No add dl,ACE_MCR ;--> Modem control register in al,dx or al,ah ;Turn on the hardware bits iodelay out dx,al and cl,NOT HHSDropped ;Show hardware lines back up
RecCom40: test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack? jz RecCom47 ; No test cl,EnqReceived ;Did we receive Enq? jz RecCom55 ; No and cl,NOT EnqReceived jmp short RecCom50
RecCom47: test cl,XOffSent ;Did we send XOFF? jz RecCom55 ; No and cl,NOT XOffSent ;Remove XOFF sent flag
RecCom50: or cl,XOnPending ;Show XON or ACK must be sent call KickTx ;Kick xmit if needed
RecCom55: mov HSFlag[si],cl ;Store handshake flag call DOSTI ;Can allow interrupts now
; Now we can get down to the business at hand, and remove a character ; from the receive queue. If a communications error exists, we return ; that, and nothing else.
RecCom60: xor ax,ax or ax,ComErr[si] ;Any Errors? jnz RecCom100 ; Yes, return the error code or ax,QInCount[si] ;Get current input char count jz RecCom90 ;No characters in the queue les di,QInAddr[si] ;Get queue pointer assumes es,nothing
mov bx,QInGet[si] ;Also get the index to head mov al,es:[bx][di] ;Finally, get byte from queue inc bx ;Update queue index cmp bx,QInSize[si] ;See if time for wrap-around jc RecCom70 ;Jump if no wrap xor bx,bx ;wrap by zeroing the index
RecCom70: mov QInGet[si],bx ;Save new head pointer dec QInCount[si] ;Dec # of bytes in queue
mov cx, [si.QinCount] cmp cx, [si.RecvTrigger] ;Q: have we read below trigger? jae RecCom80 ; N: and [si.NotifyFlagsHI], NOT CN_RECEIVE ; allow timeout notify again RecCom80: or sp,sp ;Reset PSW.Z pop di pop si ret
; No characters in the input queue. Check to see if EOF ; was received, and return it if it was. Otherwise show ; no characters.
RecCom90: test [si.DCB_Flags],fBinary ;Are we doing binary stuff? jnz RecCom95 ; Yes, show no characters mov al,[si.DCB_EofChar] ;Assume EOF test EFlags[si],fEOF ;Has end of file char been received? jnz RecCom80 ; Yes, show end of file
RecCom95: xor ax,ax ;Show no more characters
; Return with 'Z' to show error or no characters
RecCom100: xor cx,cx ;Set PSW.Z pop di pop si ret
$RECCOM endp page
;----------------------------Public Routine-----------------------------; ; ; $RECSTR - Receive Characters From Device ; ; Read Byte From RS232 Input Queue If Data Is Ready ; ; LPT ports will return with an indication that no characters are ; available. ; ; Entry: ; AH = Device ID ; ES:DI -> receive buffer ; CX max bytes to read ; Returns: ; 'Z' clear if data available ; AX = # of bytes read ; Error Returns: ; 'Z' Set if error or no data ; AX = error code ; AX = 0 if no data ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $RECSTR $RECSTR proc near
push si ;Once again, save some registers push di call GetDEB ;Get DEB pointer in SI jc RecStr10 ;Invalid Port [rkh] ... jns RecStr20 ;COM port jmp RecStr95 ;LPT port, return no characters
RecStr10: jmp RecStr100 ; Invalid Port RecStr15: jmp RecStr90
RecStr20: xor ax,ax or ax,ComErr[si] ;Any Errors? jnz RecStr10 ; Yes, return the error code or ax,QInCount[si] ;Get current input char count jz RecStr15 ;No characters in the queue
cmp cx, ax ;Q: more chars available than can read? jbe short RecStr30 ; N: mov cx, ax ; Y: adjust # of chars to read RecStr30: push cx mov dx, QInSize[si] mov ax, QInGet[si] sub dx, ax ; dx = # of bytes before end of buf cmp dx, cx ;Q: more avail than can read? jbe short RecStr40 ; N: mov dx, cx ; Y: adjust avail count RecStr40: xchg cx, dx ; cx = # of bytes for 1st copy sub dx, cx ; dx = # of bytes for 2nd copy
push ds push si lds bx, QInAddr[si] mov si, bx add si, ax ; ds:si -> first char in buffer cld rep movsb ; do first copy mov cx, dx jcxz short RecStr50 ; jump if no 2nd copy needed mov si, bx ; ds:si -> start of buffer rep movsb ; do 2nd copy RecStr50: sub si, bx ; si = new QInGet mov bx, si pop si pop ds pop cx call DOCLI mov QInGet[si], bx ; update QInGet sub QInCount[si], cx ; update count mov ax, QInCount[si] call DOSTI
cmp ax, [si.RecvTrigger] ;Q: have we read below trigger? jae @F ; N: and [si.NotifyFlagsHI], NOT CN_RECEIVE ; allow timeout notify again @@:
; Check to see if XON needs to be issued. If it needs to be issued, set the ; flag that will force it and arm transmit interrupts.
test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack? jz @F ; No test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped? jnz RecStr58 ; No Enq recvd & no lines dropped jmp RecStr80 ; No Enq recvd & no lines dropped RecStr58: jmp short RecStr60
@@: test HSFlag[si],HSSent ;Handshake sent? jnz RecStr59 ; No XOFF sent & no lines dropped jmp RecStr80 ; No XOFF sent & no lines dropped RecStr59:
RecStr60: ;ax = current count of input chars cmp ax,[si.DCB_XonLim] ;See if at XOn limit ja RecStr80 ;Not at XOn limit yet
;; int 1 ; If any hardware lines are down, then raise them. Then see ; about sending XON.
mov dx,Port[si] ;Get the port mov ah,HHSLines[si] ;Get hardware lines mask push cx call DOCLI ;Handle this as a critical section mov cl,HSFlag[si] ;Get handshaking flags or ah,ah ;Any hardware lines to play with? jz @F ; No add dl,ACE_MCR ;--> Modem control register in al,dx or al,ah ;Turn on the hardware bits iodelay out dx,al and cl,NOT HHSDropped ;Show hardware lines back up
@@: test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack? jz @F ; No test cl,EnqReceived ;Did we receive Enq? jz RecStr70 ; No and cl,NOT EnqReceived jmp short RecStr65
@@: test cl,XOffSent ;Did we send XOFF? jz RecStr70 ; No and cl,NOT XOffSent ;Remove XOFF sent flag
RecStr65: or cl,XOnPending ;Show XON or ACK must be sent call KickTx ;Kick xmit if needed
RecStr70: mov HSFlag[si],cl ;Store handshake flag call DOSTI ;Can allow interrupts now pop cx
RecStr80: mov ax, cx or sp,sp ;Reset PSW.Z pop di pop si ret
; No characters in the input queue. Check to see if EOF ; was received, and return it if it was. Otherwise show ; no characters.
RecStr90: test [si.DCB_Flags],fBinary ;Are we doing binary stuff? jnz RecStr95 ; Yes, show no characters mov al,[si.DCB_EofChar] ;Assume EOF test EFlags[si],fEOF ;Has end of file char been received? jnz RecStr80 ; Yes, show end of file
RecStr95: xor ax,ax ;Show no more characters
; Return with 'Z' to show error or no characters
RecStr100: xor cx,cx ;Set PSW.Z pop di pop si ret
$RECSTR endp page
;----------------------------Public Routine-----------------------------; ; ; $SNDIMM - Send A Character Immediately ; ; This routine either sends a character to the port immediately, ; or places the character in a special location which is used by ; the next transmit interrupt to transmit the character prior to ; those in the normal transmit queue. ; ; For LPT ports, the character is always sent immediately. ; ; Entry: ; AH = Device ID ; AL = Character ; Returns: ; AX = 0 ; Error Returns: ; AX = 8000H if Bad ID ; AX = 4000H if couldn't send because another character ; transmitted "immediately" is waiting to be sent ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $SNDIMM $SNDIMM proc near
push si call GetDEB ;Get pointer to the DEB jc SendImm20 ;Bad ID, return an error jns SendImm10 ;Its a COM port
; For LPT ports, call DoLPT to do the dirty work. If DoLPT ; returns an error code, map it to 4000h.
xor ch,ch ;Show xmit character call DoLPT ;Do the work here or ax,ax ;Error occur? jz SendImm20 ; No, show all is OK mov ax,4000h ; Yes, return 4000h jmp short SendImm20
SendImm10: mov dl, al mov ax,4000h ;In case we cannot send test EFlags[si],fTxImmed ;Another char waiting "immediately"? jnz SendImm20 ; Yes, return error mov ah,dl ;Set char for TXI call DOCLI ;TXI is critical section code call TXI ;Set character to tx immediately call DOSTI xor ax,ax ;Show all is OK
SendImm20: pop si ret
$SNDIMM endp page
;----------------------------Public Routine-----------------------------; ; ; $SNDCOM - Send Byte To Port ; ; The given byte is sent to the passed port if possible. ; If the output queue is full, an error will be returned. ; ; Entry: ; AH = Device ID ; AL = Character ; Returns: ; AX = 0 ; Error Returns: ; AX = error code ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $SNDCOM $SNDCOM proc near
push si push di call GetDEB ;--> DEB jc SendCom40 ;Invalid ID jns SendCom20 ;Its a COM port
; Handle the transmission of a LPT character. The ROM BIOS int 17 ; call will be made to do the transmission. The port address will ; be restored during the call, then zeroed out upon return.
SendCom10: xor ch,ch ;Show xmit character call DoLPT ;Do the work here jmp short SendCom40 ;Return the status to caller
; Send a character to a COM port. Return an error if control ; line timeout occurs or there is no room in the output queue.
SendCom20: push ax ;Save character
call MSRWait ;See if lines are correct for output pop ax ;Restore char jnz SendCom60 ;Timeout occured, return error mov cx,QOutSize[si] ;See if queue is full cmp cx,QOutCount[si] jle SendCom50 ;There is no room in the queue les di,QOutAddr[si] ;--> output queue assumes es,nothing
mov bx,QOutPut[si] ;Get index into queue mov es:[bx][di],al ;Store the byte inc bx ;Update index cmp bx,cx ;Wrap time? jc SendCom30 ; No xor bx,bx ;Wrap-around is a new zero pointer
SendCom30:
call DOCLI mov QOutPut[si],bx ;Store updated pointer mov ax,QOutCount[si] ; get the count inc ax ; have the updated value in AX for test later mov QOutCount[si],ax ;Update queue population call KickTx ;Make sure xmit interrupt is armed call DOSTI
xor ax,ax ;Show no error (that we know of)
;****************************************************************************
SendCom40: pop di pop si ret
SendCom50: or by ComErr+1[si],HIGH CE_TXFULL .errnz LOW CE_TXFULL
SendCom60: mov ax,ComErr[si] ;Return error code to caller jmp short SendCom40
$SNDCOM endp page
;----------------------------Public Routine-----------------------------; ; ; $SNDCOMSTR - Send buffer To Port ; ; The given buffer is sent to the passed port if possible. ; Once the output queue is detected as being full, a CE_TXFULL error ; will be indicated and AX will be returned as the # of chars actually ; queued. ; ; Entry: ; DS:SI --> DEB ; ES:DI --> buffer ; Returns: ; AX = # of bytes queued ; Registers Destroyed: ; AX,BX,CX,DX,DI,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $SNDCOMSTR $SNDCOMSTR proc near
push cx ; save count call GetDEB jc cws_error ; jump if id invalid jns cws_comm ; jump if COM port
call StringToLPT pop cx ; discard saved count, ax = # transfered jmp short cws_exit
cws_error: pop ax sub ax, cx ; ax = # transfered cws_exit: ret
cws_comm: call MSRWait ;See if lines are correct for output pop cx push cx jnz cws_error ;Timeout occured, return error
mov dx, QOutSize[si] ;See if queue is full sub dx, QOutCount[si] ; dx = # of chars free in queue jg scs_loop jmp scs_full ;There is no room in the queue
scs_loop: push cx ; save count left to send cmp cx, dx ;Q: room for buffer in queue? jbe @f ; Y: mov cx, dx ; N: adjust size to send @@: push cx ; save # of chars which will be copied push si push ds push di push es les bx,QOutAddr[si] ;--> output queue assumes es,nothing
mov dx, QOutSize[si] mov di, QOutPut[si] ;Get index into queue sub dx, di ; dx = # of free chars before end of queue cmp dx, cx jbe @f mov dx, cx @@: xchg cx, dx ; cx = # of chars for 1st copy sub dx, cx ; dx = # of chars for 2nd copy pop ds pop si ; ds:si -> src buffer assumes ds,nothing add di, bx ; es:di -> current pos in queue cld rep movsb ; copy first section mov cx, dx jcxz @F mov di, bx ; circle back to start of queue rep movsb ; copy 2nd section @@: sub di, bx ; di last index into queue mov dx, di mov di, si ; last location in src buffer mov si, ds mov es, si ; es:di -> last loc in src buf pop ds pop si ; ds:si -> ComDEB assumes ds,data pop bx ; # of chars copied call DOCLI mov QOutPut[si], dx ;new index into queue add QOutCount[si], bx call KickTx call DOSTI pop cx sub cx, bx ; # of chars left to send jnz scs_full_2 ; jump if none scs_exit: pop ax sub ax, cx ; ax = # transfered ret
scs_full: call DOCLI call KickTx call DOSTI scs_full_2: or by ComErr+1[si],HIGH CE_TXFULL .errnz LOW CE_TXFULL jmp scs_exit
$SNDCOMSTR endp page
;----------------------------Public Routine-----------------------------; ; ; $FLUSH - Flush The Input and Output Queues ; ; This is a hard initialization of the transmit and receive queue's, ; which immediately empties the given queue. ; ; LPT ports will just return the device error word ; ; Entry: ; AH = Device ID ; BH = Queue # to clear (0=Tx, 1=Rx) ; Returns: ; AX = Device Error Word. (Not reset) ; Error Returns: ; AX = error code ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $FLUSH $FLUSH proc near
push si push di call GetDEB ;si --> DEB jc Flush40 ;Invalid ID js Flush30 ;LPT port, return any error
mov cx,QOutCount-QInCount ;# of bytes to zero lea di,QInCount[si] ;--> receive queue data or bh,bh ;Transmit queue? jnz Flush10 ; No, input queue add di,cx ; Yes, --> xmit queue data
Flush10: cld push ds pop es assumes es,nothing
xor al,al call DOCLI ;Time to worry about critical sections rep stosb call DOSTI .errnz QInGet-QInCount-2 .errnz QInPut-QInGet-2 .errnz QOutCount-QInPut-2 .errnz QOutGet-QOutCount-2 .errnz QOutPut-QOutGet-2
or bh,bh ;Rx queue? jz Flush30 ; No, xmit queue
; If the queue to be cleared is the receive queue, any ; hardware handshake must be cleared to prevent a possible ; deadlock situation. Since we just zeroed the queue count, ; a quick call to $RecCom should do wonders to clear any ; receive handshake (i.e. send XON if needed).
Flush20: call $RECCOM ;Take care of handshakes here
Flush30: mov ax,ComErr[si] ;And return the error word.
Flush40: pop di pop si ret
$FLUSH endp page
;----------------------------Private-Routine----------------------------; ; ; TXI - Transmit A Character Immediately ; ; Set up a character to be transmitted "immediately". ; by placing the character in a location that guarantees ; it to be the next character transmitted. ; ; The check to see if the immediate character can be placed has ; already been made prior to entry. ; ; Interrupts must be disabled before entering this code ; ; Entry: ; AH = Character ; DS:SI --> DEB ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; BX,CX,SI,DI,DS,ES ; Registers Destroyed: ; L,DX,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public TXI ;Public for debugging TXI proc near
; call DOCLI ;Must be done by caller! or EFlags[si],fTxImmed ;Show char to xmit mov ImmedChar[si],ah ;Set character to transmit next ; jmp short KickTx ;Kick Xmit just in case errn$ KickTx
TXI endp page
;----------------------------Private-Routine----------------------------; ; ; KickTx - Kick Transmitter ; ; "Kick" the transmitter interrupt routine into operation. ; If the Transmitter Holding Register isn't empty, then ; nothing needs to be done. If it is empty, then the xmit ; interrupt needs to enabled in the IER. ; ; Entry: ; DS:SI --> DEB ; INTERRUPTS DISABLED! ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; BX,CX,SI,DI,DS,ES ; Registers Destroyed: ; AX,DX,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public KickTx ;Public for debugging KickTx proc near
; call DOCLI ;Done by caller test [si.VCDflags], 1 ;Q: we still own port? jnz can_we_steal ; N:
enable_int: mov dx,Port[si] ;Get device I/O address add dl,ACE_IER ;--> Interrupt enable register in al,dx ;Get current IER state test al,ACE_ETBEI ;Interrupt already enabled? jnz KickTx10 ; Yes, don't reenable it or al,ACE_ETBEI ; No, enable it out dx,al iodelay ;8250, 8250-B bug requires out dx,al ; writting register twice
KickTx10: ; call DOSTI ;Done by caller ret
can_we_steal: call StealPort ; call VCD to see if we can steal ; the port back jnc short enable_int ; jump, if we got it ; ; flush out queue ; xor ax, ax mov [si.QOutCount], ax mov [si.QOutMod], ax mov ax, [si.QOutGet] mov [si.QOutPut], ax jmp short KickTx10 ; N:
KickTx endp page
;----------------------------Private-Routine----------------------------; ; ; MSRWait - Modem Status Register Wait ; ; This routine checks the modem status register for CTS, DSR, ; and/or RLSD signals. If a timeout occurs while checking, ; the appropriate error code will be returned. ; ; This routine will not check for any signal with a corresponding ; time out value of 0 (ignore line). ; ; Entry: ; SI --> DEB ; Returns: ; AL = error code ; ComErr[si] updated ; 'Z' set if no timeout ; Error Returns: ; None ; Registers Destroyed: ; AX,CX,DX,FLAGS ; History: ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public MSRWait ;Public for debugging
MSRWait proc near
push di
MSRRestart: xor di,di ;Init Timer
MSRWait10: mov cx,11 ;Init Delay counter (used on non-ATs)
MSRWait20: xor dh,dh ;Init error accumulator mov al,MSRShadow[si] ;Get Modem Status and al,MSRMask[si] ;Only leave bits of interest xor al,MSRMask[si] ;0 = line high jz MSRWait90 ;All lines of interest are high mov ah,al ;ah has 1 bits for down lines
shl ah,1 ;Line Signal Detect low? jnc MSRWait30 ; No, it's high .errnz ACE_RLSD-10000000b cmp di,[si.DCB_RlsTimeout] ;RLSD timeout yet? jb MSRWait30 ; No or dh,CE_RLSDTO ;Show modem status timeout
MSRWait30: shl ah,1 ;Data Set Ready low? shl ah,1 .errnz ACE_DSR-00100000b jnc MSRWait40 ; No, it's high cmp di,[si.DCB_DsrTimeout] ;DSR timeout yet? jb MSRWait40 ; No or dh,CE_DSRTO ;Show data set ready timeout
MSRWait40: shl ah,1 ;CTS low? jnc MSRWait50 ; No, it's high .errnz ACE_CTS-00010000b cmp di,[si.DCB_CtsTimeout] ;CTS timeout yet? jb MSRWait50 ; No or dh,CE_CTSTO ;Show clear to send timeout
MSRWait50: or dh,dh ;Any timeout occur? jnz MSRWait80 ; Yes
cmp [$MachineID],0FCh ;Is this a PC-AT? [rkh debug for PS/2] je MSRWait60 ; Yes, use ROM function loop MSRWait20 ; No, continue until timeout jmp short MSRWait70 ;Should have taken about a millisecond
MSRWait60: push bx ;Special SALMON ROM routine to delay push di xor cx,cx ;Number of Microseconds to delay mov dx,1000 ; in CX:DX mov ah,86h int 15h ;Wait 1 millisecond pop di pop bx
MSRWait70: inc di ;Timer +1 jmp short MSRWait10 ;Until Timeout or Good status
MSRWait80: xor ah,ah mov al,dh or by ComErr[si],al ;Return updated status .errnz HIGH CE_CTSTO .errnz HIGH CE_DSRTO .errnz HIGH CE_RLSDTO
MSRWait90: or al,al ;Set 'Z' if no timeout pop di ret
MSRWait endp page
;----------------------------Public Routine-----------------------------; ; ; $EVT - Set Event Mask ; ; Set up event word and mask. Returns a pointer to a word in which ; certain bits, as enabled by the mask, will be set when certain ; events occur. ; ; Entry: ; AH = Device ID ; BX = Event enable mask ; Returns: ; DX:AX --> event word. ; Error Returns: ; AX = 0 if error ; Registers Preserved: ; BX,CX,SI,DI,DS,ES ; Registers Destroyed: ; AX,DX,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $EVT $EVT proc near
push si xor dx,dx ;In case of error call GetDEB ;Get pointer to DEB mov ax,dx ;Finish setting error return value jc Evt10 ;Illegal id, return error js Evt10 ;LPTx, return error mov EvtMask[si],bx ;Save the new event mask lea ax,EvtWord[si] ;Get address of event word mov dx,ds ; into dx:ax
Evt10: pop si ret
$EVT endp page
;----------------------------Public Routine-----------------------------; ; ; $EVTGET - Get Event Word ; ; Return and clear fields in the event word. This routine MUST be used ; by applications to read the event word, as it is the ONLY way they ; can be assured that an event is not lost between reading the flags ; and resetting some. ; ; Entry: ; AH = Device ID ; BX = Event clear mask ; Returns: ; AX = event word ; Error Returns: ; None ; Registers Preserved: ; AX,CX,SI,DI,DS,ES ; Registers Destroyed: ; BX,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $EVTGET $EVTGET proc near
push si call GetDEB mov ah,0 ;In case of error (AL already 0) jc EvtGet10 ;Illegal ID js EvtGet10 ;Illegal ID call DOCLI ;No interrupts allowed mov ax,EvtWord[si] ;Get the current event word not bx ;Convert mask for our purposes and bx,ax ;Clear events that user wants us to mov EvtWord[si],bx ;And save those results call DOSTI ;Magic over
EvtGet10: pop si ret
$EVTGET endp page
;----------------------------Public Routine-----------------------------; ; ; $STACOM - Return Status Information ; ; Returns the number of bytes in both queues. ; ; LPT ports will show both queues empty. ; and resetting some. ; ; Entry: ; AH = Device ID ; ES:BX = Pointer to status structure to be updated. ; = Null if not to update ; Returns: ; AX = comm error word ; Status Structure Updated. ; Error Returns: ; AX = error code ; Registers Preserved: ; SI,DI,DS,ES ; Registers Destroyed: ; AX,BX,CX,DX,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $STACOM $STACOM proc near
push si call GetDEB ;Get DEB pointer in SI jc StaCom30 ;Invalid ID mov cx,es ;Is the pointer NULL? or cx,bx jz StaCom25 ; Yes, just return error code xor cx,cx xor dx,dx or ah,ah ;Set 'S' if LPT port mov ax,cx ;For LPTs, everything is zero js StaCom20 ;LPT port
; Need to get the status for a com port. Since not all the ; status is contained within EFlags, it has to be assembled. ; Also note that currently there is no way to specify RLSD ; as a handshaking line, so fRLSDHold is always returned false.
mov al,MSRShadow[si] ;Get state of hardware lines and al,OutHHSLines[si] ;Mask off required bits xor al,OutHHSLines[si] ;1 = line low mov cl,4 ;Align bits shr al,cl ;al = fCTSHold + fDSRHold .errnz ACE_CTS-00010000b .errnz ACE_DSR-00100000b .errnz fCTSHold-00000001b .errnz fDSRHold-00000010b
mov ah,HSFlag[si] ;Get fXOffHold+fXOffSent and ah,XOffReceived+XOffSent or al,ah
.errnz XOffReceived-fXOFFHold .errnz XOffSent-fXOFFSent
mov ah,EFlags[si] ;Get fEOF+fTxImmed and ah,fEOF+fTxImmed or al,ah
mov cx,QInCount[si] ;Get input queue count mov dx,QOutCount[si] ;Get tx queue count
StaCom20: mov es:[bx.COMS_BitMask1],al mov es:[bx.COMS_cbInQue],cx mov es:[bx.COMS_cbOutQue],dx
StaCom25: xor ax,ax ;Return old com error xchg ax,ComErr[si] ; and clear it out
StaCom30: pop si ret
$STACOM endp page
;----------------------------Public Routine-----------------------------; ; ; $SetBrk - Set Break ; ; Clamp the Tx data line low. Does not wait for the ; transmitter holding register and shift registers to empty. ; ; LPT ports will just return the comm error word ; ; Entry: ; AH = Device ID ; Returns: ; AX = comm error word ; Error Returns: ; AX = error code ; Registers Preserved: ; SI,DI,DS,ES ; Registers Destroyed: ; AX,BX,CX,DX,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $SETBRK $SETBRK proc near
mov cx,0FF00h+ACE_SB ;Will be setting break jmp short ClrBrk10 .errnz BreakSet-ACE_SB ;Must be same bits
$SETBRK endp page
;----------------------------Public Routine-----------------------------; ; ; $CLRBRK - Clear Break ; ; Release any BREAK clamp on the Tx data line. ; ; LPT ports will just return the comm error word ; ; Entry: ; AH = Device ID ; Returns: ; AX = comm error word ; Error Returns: ; AX = error code ; Registers Preserved: ; SI,DI,DS,ES ; Registers Destroyed: ; AX,BX,CX,DX,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public $CLRBRK $CLRBRK proc near
mov cx,(NOT ACE_SB) SHL 8 .errnz BreakSet-ACE_SB ;Must be same bits
ClrBrk10: push si call GetDEB ;Get DEB address jc ClrBrk30 ;Invalid ID js ClrBrk20 ;Ignored for LPT ports call DOCLI and HSFlag[si],ch ;Set or clear the BreakSet bit or HSFlag[si],cl
; ch = mask to remove bits in the Line Control Register ; cl = mask to turn bits on in the Line Control Register
mov dx,Port[si] ;Get comm device base I/O port add dl,ACE_LCR ;Point at the Line Control Regieter in al,dx ;Get old line control value and al,ch ;Turn off desired bits or al,cl ;Turn on desired bits iodelay out dx,al ;Output New LCR. call DOSTI
ClrBrk20: mov ax,ComErr[si] ;Return Status Word
ClrBrk30: pop si ret
$CLRBRK endp
page
;----------------------------Public Routine-----------------------------; ; ; $EXTCOM - Extended Comm Functions ; ; A number of extended functions are routed through this entry point. ; ; Functions currently implemented: ; ; 0: Ignored ; 1: SETXOFF - Exactly as if X-OFF character has been received. ; 2: SETXON - Exactly as if X-ON character has been received. ; 3: SETRTS - Set the RTS signal ; 4: CLRRTS - Clear the RTS signal ; 5: SETDTR - Set the DTR signal ; 6: CLRDTR - Clear the DTR signal ; 7: RESET - Yank on reset line if available (LPT devices) ; ; Entry: ; AH = Device ID ; BL = Function Code ; (0-127 are MS-defined, 128-255 are OEM defined) ; Returns: ; AX = comm error word ; Error Returns: ; AX = error code ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
; Dispatch table for the extended functions
ExtTab dw ExtComDummy ;Function 0: Never Mind dw ExtCom_FN1 ;1: Set X-Off dw ExtCom_FN2 ;2: Clear X-Off dw ExtCom_FN3 ;3: Set RTS dw ExtCom_FN4 ;4: Clear RTS dw ExtCom_FN5 ;5: Set DSR dw ExtCom_FN6 ;6: Clear DSR dw ExtCom_FN7 ;7: Reset printer dw ExtCom_FN8 ;8: Get Max LPT Port dw ExtCom_FN9 ;9: Get Max COM Port dw ExtCom_FN10 ;10: Get COM Port Base & IRQ dw ExtCom_FN10 ;11: Get COM Port Base & IRQ %OUT fix this for bld 32 -- GetBaseIRQ is now 10
assumes ds,Data assumes es,nothing
public $EXTCOM $EXTCOM proc near
push si push di call GetDEB ;Get DEB pointer jc ExtCom40 ;Invalid ID, return error mov dx,Port[si] ; get port address jns ExtCom10 ;Its a COM port cmp bl,7 ;RESET extended function? jne ExtCom30 ; No, return error word jmp short ExtCom20 ; Yes, invoke the function
ExtCom10: cmp bl,11 ;Last fcn supported ja ExtCom30 ;Not an implemented function.
ExtCom20: xor bh,bh add bx,bx ;Shift for the call call DOCLI ;Consider as critical sections call ExtTab[bx] ; and perform the function call DOSTI jc ExtCom40 ; jump if sub returns data in DX:AX
ExtCom30: mov ax,ComErr[si] ;Return standard error word xor dx, dx
ExtCom40: pop di pop si
ret
$EXTCOM endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN1 - Extended Function Set X-Off ; ; Analagous to receiving an X-OFF character. Bufferred transmision of ; characters is halted until an X-ON character is received, or until ; we fake that with a Clear X-Off call. ; ; Entry: ; interrupts disabled ; dx = port base address ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN1 ExtCom_FN1 proc near
or HSFlag[si],XOffReceived ExtComDummy: clc ret
ExtCom_FN1 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN2 - Extended Function Clear X-Off ; ; Analagous to receiving an X-ON character. Buffered ; transmission of characters is restarted. ; ; Entry: ; interrupts disabled ; dx = port base address ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN2 ExtCom_FN2 proc near
and HSFlag[si],NOT XOffReceived call KickTx ;Kick transmitter interrupts on clc ret
ExtCom_FN2 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN3 - Extended Function Set RTS ; ; Set the RTS signal active. ; ; Entry: ; interrupts disabled ; dx = port base address ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN3 ExtCom_FN3 proc near
add dl,ACE_MCR ;Point at Modem Control Register in al,dx ;Get current settings or al,ACE_RTS ;Set RTS iodelay out dx,al ;And update clc ret
ExtCom_FN3 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN4 - Extended Function Clear RTS ; ; Set the RTS signal inactive. ; ; Entry: ; interrupts disabled ; dx = port base address ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN4 ExtCom_FN4 proc near
add dl,ACE_MCR ;Point at Modem Control Register in al,dx ;Get current settings and al,NOT ACE_RTS ;Clear RTS iodelay out dx,al ;And update clc ret
ExtCom_FN4 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN5 - Extended Function Set DTR ; ; Set the DTR signal active. ; ; Entry: ; interrupts disabled ; dx = port base address ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN5 ExtCom_FN5 proc near
add dl,ACE_MCR ;Point at Modem Control Register in al,dx ;Get current settings or al,ACE_DTR ;Set DTR iodelay out dx,al ;And update clc ret
ExtCom_FN5 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN6 - Extended Function Clear DTR ; ; Set the DTR signal inactive. ; ; Entry: ; interrupts disabled ; dx = port base address ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN6 ExtCom_FN6 proc near
add dl,ACE_MCR ;Point at Modem Control Register in al,dx ;Get current settings and al,NOT ACE_DTR ;Clear DTR iodelay out dx,al ;And update clc ret
ExtCom_FN6 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN7 - Extended Function Reset Printer ; ; Assert the RESET line on an LPT port ; ; Entry: ; interrupts disabled ; dx = port base address ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN7 ExtCom_FN7 proc near
call DOSTI ;Not called at interrupt time mov ch,1 ;ROM BIOS Reset Port call DoLPT ;Perform the function clc ret
ExtCom_FN7 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN8 - Get Num Ports ; ; Entry: ; Returns: ; AX = Max LPT port id ; DX = 0 ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN8 ExtCom_FN8 proc near
mov ax, MAXLPT + LPTx xor dx, dx stc ret
ExtCom_FN8 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN9 - Get Max COM Port ; ; Entry: ; Returns: ; AX = Max COM port id ; DX = 0 ; Error Returns: ; None ; Registers Preserved: ; SI,DI,DS ; Registers Destroyed: ; AX,BX,CX,DX,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN9 ExtCom_FN9 proc near
mov ax, MAXCOM xor dx, dx stc ret
ExtCom_FN9 endp page
;----------------------------Private-Routine----------------------------; ; ; ExtCom_FN10 - Get COM Port Bas & IRQ ; ; Entry: ; AH = com id ; DS:SI -> DEB ; Returns: ; AX = base ; DX = irq ; Error Returns: ; None ; Registers Preserved: ; DS ; Registers Destroyed: ; AX,BX,CX,DX,DI,ES,FLAGS ; History: ;-----------------------------------------------------------------------;
;------------------------------Pseudo-Code------------------------------; ; { ; } ;-----------------------------------------------------------------------;
assumes ds,Data assumes es,nothing
public ExtCom_FN10 ExtCom_FN10 proc near
call FindCOMPort stc ret
ExtCom_FN10 endp page
ifdef DEBUG public RecCom40, RecCom50, RecCom60, RecCom70, RecCom80 public RecCom90, RecCom95, RecCom100 public SendImm10, SendImm20, public SendCom10, SendCom20, SendCom30, SendCom40, SendCom50, SendCom60 public Flush10, Flush20, Flush30, Flush40 public KickTx10 public Evt10 public EvtGet10 public StaCom20, StaCom25, StaCom30 public ClrBrk10, ClrBrk20, ClrBrk30 public ExtCom10, ExtCom20, ExtCom30, ExtCom40, ExtComDummy public MSRRestart, MSRWait10, MSRWait20, MSRWait30, MSRWait40 public MSRWait50, MSRWait60, MSRWait70, MSRWait80, MSRWait90 endif
DOSTI proc near FSTI ret DOSTI endp
DOCLI proc near FCLI ret DOCLI endp
sEnd code End
|