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 ifdef NEC_98 externFP MSR_READ_Call ;[QN] ;(ins 92.09.27) externFP AOBA_MSR_READ_Call ;AOBA-bug ins 94.11.19 KBNES externFP Set8251modeFar ;(ins 94.04.18) externFP SetFIFOmodeFar ;(ins 94.04.18) endif ; NEC_98 sBegin Data externB $MachineID ifdef NEC_98 ;-------------------------------------------------------;[QN] (ins 92.08.xx) ; MSR's_DELAY local buffer ;[QN] (ins 92.08.xx) ;-------------------------------------------------------;[QN] (ins 92.08.xx) _BIOS_FLAG1_ DB 0 ;[0:458H] ;[QN] (ins 92.08.xx) _BIOS_FLAG2_ DB 0 ;[0:480H] ;[QN] (ins 92.08.xx) _BIOS_FLAG3_ DB 0 ;[0:45BH] ;[QN] (ins 93.03.09) _CPU_ DW 0 ;loop count ;[QN] (ins 92.08.xx) _TIME_ DW 0 ;target time ;[QN] (ins 92.08.xx) _MUKASI_ DW 0 ;previous time ;[QN] (ins 92.08.xx) endif ; NEC_98 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? ifdef NEC_98 jnz RecCom34 ; No XOFF sent & no lines dropped jmp RecCom60 ; No XOFF sent & no lines dropped else ; NEC_98 jnz RecCom33 ; No XOFF sent & no lines dropped jmp RecCom60 ; No XOFF sent & no lines dropped RecCom33: endif ; NEC_98 RecCom34: mov ax,QInCount[si] ;Get current count of input chars cmp ax,[si.DCB_XonLim] ;See if at XOn limit ifdef NEC_98 jbe Dummy00 ;(95.1.25) jmp RecCom60 ;Not at XOn limit yet Dummy00: else ; NEC_98 ja RecCom60 ;Not at XOn limit yet endif ; NEC_98 ; If any hardware lines are down, then raise them. Then see ; about sending XON. ifdef NEC_98 mov dx,CommandPort[si] ;Get the port ;[QN] (ins 92.08.xx) else ; NEC_98 mov dx,Port[si] ;Get the port endif ; NEC_98 mov ah,HHSLines[si] ;Get hardware lines mask ifndef NEC_98 call DOCLI ;Handle this as a critical section endif ; NEC_98 mov cl,HSFlag[si] ;Get handshaking flags or ah,ah ;Any hardware lines to play with? jz RecCom40 ; No ifdef NEC_98 mov al,CommandShadow[si] ;8251 Command get (ins 92.08.xx)| test ah,ACE_DTR ;DTR handshake Enable ? (ins 92.08.xx)| jz RecCom31 ; No (ins 92.08.xx)| or al,DTR ;Set 8251's DTR Active ! (ins 92.08.xx)| RecCom31: ; (ins 92.08.xx)| test ah,ACE_RTS ;RTS handshake Enable ? (ins 92.08.xx)| jz RecCom33 ; No (ins 92.08.xx)| or al,RTS ;Set 8251's RTS Active ! (ins 92.08.xx)| RecCom33: ; (ins 92.08.xx)| push dx ; (ins 94.05.18)| mov dh,CommandShadow[si] ; (ins 94.05.18)| mov dl,al ; (ins 94.05.18)| and dx,2222h ; (ins 94.05.18)| cmp dh,dl ; (ins 94.05.18)| pop dx ; (ins 94.05.18)| je @f ; (ins 94.05.18)| FCLI ; (ins 94.05.18)| test [si.AOBA_flag],fFIFO_Mode ; (ins 94.05.18)| jz RecCom35 ;Now, 8251 mode (ins 94.05.18)| call Set8251modeFar ;Change to 8251 mode (ins 94.05.18)| RecCom35: ; (ins 94.05.18)| out dx,al ; (ins 92.08.xx)| test [si.AOBA_flag],fFIFO_Mode ; (ins 94.05.18)| jz @F ;Now, 8251 mode (ins 94.05.18)| call SetFIFOmodeFar ;Change to FIFO mode (ins 94.05.18)| @@: ; (ins 94.05.18)| mov CommandShadow[si],al ;Get Back 8251 Command (ins 92.08.xx)| else ; NEC_98 add dl,ACE_MCR ;--> Modem control register in al,dx or al,ah ;Turn on the hardware bits iodelay out dx,al endif ; NEC_98 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 ifdef NEC_98 mov HSFlag[si],cl ;Store handshake flag ;[QN](ins 92.08.xx /92.10.21) endif ; NEC_98 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 ifdef NEC_98 jbe Dummy10 ;(95.1.25) jmp RecStr80 ;Not at XOn limit yet Dummy10: else ; NEC_98 ja RecStr80 ;Not at XOn limit yet endif ; NEC_98 ;; int 1 ; If any hardware lines are down, then raise them. Then see ; about sending XON. ifdef NEC_98 push cx ; (ins 92.09.xx)| mov dx,CommandPort[si] ;Get the port (92.08.xx)| mov ah,HHSLines[si] ;Get hardware lines mask (92.08.xx)| mov cl,HSFlag[si] ;Get handshaking flags (92.08.xx)| or ah,ah ;Any H/W lines to play with?(92.08.xx)| jz RecStr64 ; No (Goto Xmit Xon Char) (92.08.xx)| mov al,CommandShadow[si] ;8151 Command get (92.08.xx)| test ah,ACE_DTR ;DTR handshake Enable ? (92.08.xx)| jz RecStr61 ; No (92.08.xx)| or al,DTR ;Set 8251's DTR Active ! (92.08.xx)| RecStr61: ; (92.08.xx)| test ah,ACE_RTS ;RTS handshake Enable ? (92.08.xx)| jz RecStr63 ; No (92.08.xx)| or al,RTS ;Set 8251's RTS Active ! (92.08.xx)| RecStr63: ; (92.08.xx)| push dx ; (ins 94.05.18)| mov dh,CommandShadow[si] ; (ins 94.05.18)| mov dl,al ; (ins 94.05.18)| and dx,2222h ; (ins 94.05.18)| cmp dh,dl ; (ins 94.05.18)| pop dx ; (ins 94.05.18)| je @f ; (ins 94.05.18)| FCLI ; (ins 94.05.18)| test [si.AOBA_flag],fFIFO_Mode ; (ins 94.05.18)| jz RecStr63_1 ;Now, 8251 mode (ins 94.05.18)| call Set8251modeFar ;Change to 8251 mode (ins 94.05.18)| RecStr63_1: ; (ins 94.05.18)| out dx,al ; (92.08.xx)| test [si.AOBA_flag],fFIFO_Mode ; (ins 94.05.18)| jz @F ;Now, 8251 mode (ins 94.05.18)| call SetFIFOmodeFar ;Change to FIFO mode (ins 94.05.18)| @@: ; (ins 94.05.18)| mov CommandShadow[si],al ;Get Back 8251 Command Byte (92.08.xx)| and cl,NOT HHSDropped ;Show hardware lines back up(92.08.xx)| RecStr64: ; (92.08.xx)| else ; NEC_98 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 @@: endif ; NEC_98 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 ifdef NEC_98 mov HSFlag[si],cl ;Store handshake flg ;[QN](ins92.10.19) endif ; NEC_98 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 ifdef NEC_98 push cx ; ;[QN] (ins 92.09.24) endif ; NEC_98 test [si.VCDflags], 1 ;Q: we still own port? jnz can_we_steal ; N: enable_int: ifdef NEC_98 cmp [si.DCB_id],ID_Com1 ;Is This Com1 ID ? (ins 92.08.xx)| jne KickTx5 ;No, go to KickTx5 (ins 92.08.xx)| mov dx,MaskFFPort[si] ;F/F Port Mask Bit (ins 92.08.xx)| in al,dx ; (ins 92.08.xx)| mov MaskFFShadow[si],al ;Save the Old Mask bit (ins 92.08.xx)| ; (ins 92.08.xx)| KickTx5: ; (ins 92.08.xx)| mov al,MaskFFShadow[si] ;mask data(port C) save (ins 92.08.xx)| test al,MSK_TXR ; (ins 93.06.18)| jnz KickTx10 ; Enable (ins 92.08.xx)| KickTx9: or al,MSK_TXR+MSK_RXR ; (ins 93.06.18)| mov dx,MaskFFPort[si] ;Port address (Port C) (ins 92.08.xx)| mov MaskFFShadow[si],al ;Masking data save (ins 92.08.xx)| out dx,al ;Masking set (ins 92.08.xx)| pop cx ; (ins 92.09.24)| ret ; (ins 92.08.xx)| KickTx10: ; (ins 92.08.xx)| and al,NOT(MSK_TXR+MSK_RXR) ; (ins 93.06.18) mov dx,MaskFFPort[si] ;Port address (Port C) (ins 93.03.22) out dx,al ;Masking set (ins 93.03.22) NEWIODELAY 1 ; (ins 93.03.22) jmp short KickTx9 ; (ins 93.03.22) else ; NEC_98 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 endif ; NEC_98 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: ifdef NEC_98 test [si.AOBA_flag],fFIFO_Mode ; (ins 94.04.18)| jnz @F ;Now, fifo mode (ins 94.04.18)| call MSR_READ_Call ; (ins 92.08.xx)| @@: ; (ins 94.04.18)| endif ; NEC_98 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 ifndef NEC_98 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 endif ; NEC_98 MSRWait60: ifdef NEC_98 mov cx,1 ;(ins 92.08.xx)| call MSR_DELAY ;(ins 92.08.xx)| else ; NEC_98 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 endif ; NEC_98 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 ifdef NEC_98 test [si.AOBA_flag],fFIFO_Mode ; (ins 94.04.16)| jnz @F ;Now, fifo mode (ins 94.04.16)| call MSR_READ_Call ; (ins 92.08.xx)| jmp short MSR_READ_END ;AOBA-bug ins 94.11.19 KBNES @@: ; (ins 94.04.16)| call AOBA_MSR_READ_Call ;AOBA-bug ins 94.11.19 KBNES MSR_READ_END: ;AOBA-bug ins 94.11.19 KBNES endif ; NEC_98 ; 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 ifdef NEC_98 push bx ;(ins 92.08.xx) mov bh,SEND_BREAK ;Save the Break commands bit(ins 92.08.xx) endif ; NEC_98 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 ifdef NEC_98 push bx ;(ins 92.08.xx) mov bh,not SEND_BREAK ;Save the Break Reset command(ins 92.08.xx) endif ; NEC_98 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 ifdef NEC_98 test [si.AOBA_flag],fFIFO_Mode ; (ins 94.04.16)| jz @F ;Now, 8251 mode (ins 94.04.16)| call Set8251modeFar ;Change to 8251 mode (ins 94.04.16)| @@: ; (ins 94.04.16)| mov dx,CommandPort[si] ;8251 Command Address (ins 92.08.xx)| mov al,CommandShadow[si] ;8251 Active CMD Byte (ins 92.08.xx)| cmp bh,SEND_BREAK ;Send Break ? (ins 92.08.xx)| jne ClrBrk15 ; No, Clear bit (ins 92.08.xx)| or al,bh ;Send break bit "set" (ins 92.08.xx)| jmp short ClrBrk17 ; (ins 92.08.xx)| ClrBrk15: ; (ins 92.08.xx)| and al,bh ;Send break bit "reset" (ins 92.08.xx)| ClrBrk17: ; (ins 92.08.xx)| out dx,al ;New command out (ins 92.08.xx)| test [si.AOBA_flag],fFIFO_Mode ; (ins 94.04.16)| jz @F ;Now, 8251 mode (ins 94.04.16)| call SetFIFOmodeFar ;Change to FIFO mode (ins 94.04.16)| @@: ; (ins 94.04.16)| FSTI ; (ins 92.08.xx)| ; (ins 92.08.xx)| ClrBrk20: ; (ins 92.08.xx)| mov ax,ComErr[si] ;Return Status Word (ins 92.08.xx)| ; (ins 92.08.xx)| ClrBrk30: ; (ins 92.08.xx)| pop si ; (ins 92.08.xx)| pop bx ; (ins 92.08.xx)| ret ; (ins 92.08.xx)| else ; NEC_98 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 endif ; NEC_98 $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 ifdef NEC_98 mov dx,CommandPort[si] ;Command registor (ins 92.08.xx) else ; NEC_98 mov dx,Port[si] ; get port address endif ; NEC_98 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 ifdef NEC_98 mov al,CommandShadow[si] ;Old command byte load (ins 92.08.22)| or al,RTS ;=00100000B RTS bit "On"(ins 92.08.22)| mov dx,CommandPort[si] ;Command registor (ins 92.08.22)| call GoNakasu ;RTS set (ins 92.08.22)| mov CommandShadow[si],al ;New command byte save (ins 92.08.22)| else ; NEC_98 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 endif ;NEC_98 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 ifdef NEC_98 mov al,CommandShadow[si] ;Old command byte load (ins 92.08.22)| and al,not RTS ;=11011111B RTS bit"Off"(ins 92.08.22)| mov dx,CommandPort[si] ;Command registor (ins 92.08.22)| call GoNakasu ;Clear rts (ins 92.08.22)| mov CommandShadow[si],AL ;New command byte save (ins 92.08.22)| else ; NEC_98 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 endif ; NEC_98 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 ifdef NEC_98 mov al,CommandShadow[si] ;Old command byte load (ins 92.08.xx)| or al,DTR ;=00000010B DTR bit "On"(ins 92.08.xx)| mov dx,CommandPort[si] ;Command registor (ins 92.08.xx)| call GoNakasu ;set dtr (ins 92.08.xx)| mov CommandShadow[si],al ;New command byte save (ins 92.08.xx)| else ; NEC_98 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 endif ; NEC_98 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 ifdef NEC_98 mov al,CommandShadow[si] ;Old command byte load (ins 92.08.xx)| and al,not DTR ;=11111101B DTR bit"Off"(ins 92.08.xx)| mov dx,CommandPort[si] ;Command registor (ins 92.08.xx)| call GoNakasu ;set DTR (ins 92.08.xx)| mov CommandShadow[si],al ;New command byte save (ins 92.08.xx)| else ; NEC_98 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 endif ; NEC_98 clc ret ExtCom_FN6 endp ifdef NEC_98 GoNakasu proc near ; (ins 94.05.19)| push dx ; (ins 94.05.19)| mov dh,CommandShadow[si] ; (ins 94.05.19)| mov dl,al ; (ins 94.05.19)| and dx,2222h ; (ins 94.05.19)| cmp dh,dl ; (ins 94.05.19)| pop dx ; (ins 94.05.19)| je @f ; (ins 94.05.19)| test [si.AOBA_flag],fFIFO_Mode ; (ins 94.05.19)| jz HakataNoYatai ;Now, 8251 mode (ins 94.05.19)| call Set8251modeFar ;Change to 8251 mode (ins 94.05.19)| HakataNoYatai: ; (ins 94.05.19)| out dx,al ; (ins 94.05.19)| test [si.AOBA_flag],fFIFO_Mode ; (ins 94.05.19)| jz @F ;Now, 8251 mode (ins 94.05.19)| call SetFIFOmodeFar ;Change to FIFO mode (ins 94.05.19)| @@: ; (ins 94.05.19)| ret ; (ins 94.05.19)| GoNakasu endp ; (ins 94.05.19)| endif ; NEC_98 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 NEC_98 include delay.asm ; (ins 92.08.xx) TOMOE_PAT DB 16 DUP('PATCH !!') ;PATCH AREA (ins 92.11.11) endif ; NEC_98 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