home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
ddkx86v5.zip
/
DDKX86
/
SRC
/
DEV
/
ATCOM
/
ATCOM.ASM
next >
Wrap
Assembly Source File
|
1995-04-14
|
97KB
|
2,670 lines
;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT Copyright (C) 1995 IBM Corporation
;
; The following IBM OS/2 WARP source code is provided to you solely for
; the purpose of assisting you in your development of OS/2 WARP device
; drivers. You may use this code in accordance with the IBM License
; Agreement provided in the IBM Device Driver Source Kit for OS/2. This
; Copyright statement may not be removed.;
;*****************************************************************************/
; SCCSID = @(#)atcom.asm 6.14 92/03/18
; ***************************************************************************
; *
; *
; *
; ***************************************************************************
PAGE 80,132
.286p
TITLE com01.sys - Asynchronous Communication Device Driver
NAME com01
; Bryan Diehl
; David Gilman
;*** atcom.asm
;
; This file contains the strategy routine for the com01.sys
; device driver. This is the asynch device driver for the AT.
; The device driver handles up to four com ports.
; The asynch device driver is an installable driver. It is
; installed via the 'device=' command in config.sys. It has no
; command line arguments, therefore installation amounts to
; the command:
;
; device=com01.sys
;
; being present in config.sys.
; Com01.sys must use low memory for its I/O buffers. Therefore
; it is advisable not to install the driver unless it is needed.
; Modification History
;
; DJG 01/06/87 Re-written to conform to MS standard for
; style, clarity and efficiency.
; JGT 05/10/88 Add enhanced baud rate support (p587-cpd12)
; JGT 07/25/88 Disable to read MsCount in ComClose - p1355
; YN 05/25/89 MVDM Support @VDM
; ACW 04/16/91 @PVW Added perfview counters/timers
; YN 08/13/91 CP20D1390 - Bulletin Board Support
; YN 10/30/91 CP20PB729004 - Shutdown Support (Reset FIFO)
; MF 02/21/92 PB732220 - Procomm Plus host mode fix (@0001)
; JAG 07/29/93 72032 Fix detection of FIFO buffer for PCMCIA
; JAG 09/14/93 73679 change IDC_handler to behave correctly
; (Cy set on error; more parm checking)
; RAC 12/7/93 Add define statements to conditionally
; assemble PERFVIEW and TRACE code
; RDW 03/17/94 77701 same as defect 76009 (add getlid to ABIOS)
; RDW 03/30/94 81245 SMC SIO chip cause hang enabling FIFO UART
; JAG 07/11/94 85558 Update 40:X for PCMCIA card inst/deinst.
; JAG 08/26/94 95202 Check ABIOS rc for NOT_VALID; ThinkPad 720
; JAG 09/26/94 99428 Resource manager fixes
; JAG 09/29/94 100764 High speed pcmcia modems busted.
; PMS 11/16/94 103070 -1 ComClose does not CLI before ProcBlockNI
; Found ComWFlushSub / ComRFlushSub were trashing
; ES:DI registers (ReqPacket).
; PMS 11/16/94 103070 -2 PERFVIEW addition removed JMPs from
; ComRead and ComWrite code
COM_ATTRIB EQU DEV_CHAR_DEV OR DEV_30 OR DEVLEV_3 OR DEV_GIOCTL OR DEV_SHARE OR DEV_IDC
.xlist
include devhlp.inc
include devsym.inc
include realmac.inc
include basemaca.inc
include error.inc
include filemode.inc
include infoseg.inc
include aberror.inc
.list
include atcom.inc
include gas.inc
include ateisa.inc
EXTRN Com1:WORD
EXTRN Com2:WORD
EXTRN Com3:WORD
EXTRN Com4:WORD
EXTRN Com1P:WORD
EXTRN Com2P:WORD
EXTRN Com3P:WORD
EXTRN Com4P:WORD
EXTRN Kernel_Type:WORD
EXTRN ComInit:FAR
EXTRN ComIoctl:NEAR
EXTRN DevHlp:DWORD
EXTRN Ticker:NEAR
extrn CheckLCR:near
extrn CheckTX:near
extrn Get_OCI_Sem:near
extrn LinkRP:near
extrn ProcBlock:near
extrn ProcBlockNI:near
extrn ProcRun:near
extrn ReadQueue:near
extrn StartNextRRP:near
extrn StartNextWRP:near
extrn UnLinkHeadRP:near
extrn UnLinkRP:near
extrn WriteQueue:near
extrn EnqComInfo:near
extrn DeqComInfo:near
extrn SetUpGDT:near
extrn endswapcode:byte
extrn ENDSWAPDATA:word
extrn MxInt:near
extrn EnableRemoteTX:near
extrn ComputeAPO:near
extrn ComputeHHS:near
extrn ComputeRTO:near
extrn ComputeWTO:near
extrn SetLineC:near
extrn SetBaud:near
extrn CheckLCR:near
EXTRN ComInit:FAR
EXTRN ComInt1:FAR
EXTRN ComInt2:FAR
EXTRN ComInt3:FAR
EXTRN ComInt4:FAR
EXTRN SComInt1:FAR
EXTRN SComInt2:FAR
EXTRN SComInt3:FAR
EXTRN SComInt4:FAR
EXTRN ShrdIRQ1:BYTE
EXTRN _RMHELP_CreateLDev:FAR
EXTRN _RMHELP_DestroyLDev:FAR
EXTRN _RMHELP_FindPCMCIANode:FAR
HSEG SEGMENT
; Com1Dev and Com2Dev are the headers for the asynch
; device drivers.
; WARNING : If Com1Dev is the first header in the device
; driver chain, the DOS expects to find it at the beginning
; of the device driver's data segment.
SDev macro baselabel, devnext, devattr, devstrat, devintr, devname, devpCS, devpDS, devrCS, devrDS, devcap
?SDev macro field, size, value
.errnz ($ - baselabel - offset field)
size value
endm
baselabel label byte
?SDev SDevNext dd <devnext>
?SDev SDevAtt dw <devattr>
?SDev SDevStrat dw <devstrat>
?SDev SDevInt dw <devintr>
?SDev SDevName db <devname>
?SDev SDevProtCS dw <devpCS>
?SDev SDevProtDS dw <devpDS>
?SDev SDevRealCS dw <devrCS>
?SDev SDevRealDS dw <devrDS>
?SDev SDevCaps dd <devcap OR 0000000000000001b>
.errnz ($ - baselabel - size SysDev3)
endm
;IFDEF COMDEBUG
;SDev Com1Dev -1, COM_ATTRIB, Com1Strat, 0, 'COM1 '
;ELSE
SDev Com1Dev <offset Com2Dev>,COM_ATTRIB,Com1Strat,COM1_IDC_Entry,'COM1 ',0,0,0,0,DEV_16MB
SDev Com2Dev <offset Com3Dev>,COM_ATTRIB,Com2Strat,COM2_IDC_Entry,'COM2 ',0,0,0,0,DEV_16MB
SDev Com3Dev <offset Com4Dev>,COM_ATTRIB,Com3Strat,COM3_IDC_Entry,'COM3 ',0,0,0,0,DEV_16MB
SDev Com4Dev -1, COM_ATTRIB,Com4Strat,COM4_IDC_Entry,'COM4 ',0,0,0,0,DEV_16MB
;ENDIF
.ERRNZ OFFSET HSEG:Com1Dev ; enforce the above warning
HSEG ENDS
DSEG SEGMENT
public startswapdata
startswapdata label byte
; There are 13 (out of a possible 21) commands that can be
; made of a character device driver. Communication with a
; device driver is performed through packets. Within this
; packet is the command code. We use this value to drive the
; strategy routine of com01.sys. This is accomplished via the
; following jump table.
EVEN ; force word alignment
ComStratTab LABEL WORD
DW 0 ;0: Init (not used in this table)
DW OFFSET CSEG:CmxUnknown ;1: Media Check (Block Devices Only)
DW OFFSET CSEG:CmxUnknown ;2: Build BPB (Block Devices Only)
DW OFFSET CSEG:CmxUnknown ;3: Reserved (used to be Ioctl Input)
DW OFFSET CSEG:ComRead ;4: Input (Read)
DW OFFSET CSEG:ComNDRead ;5: Non-Destructive Input, no wait.
DW OFFSET CSEG:ComRStat ;6: Input Status
DW OFFSET CSEG:ComRFlush ;7: Input Flush
DW OFFSET CSEG:ComWrite ;8: Output (Write)
DW OFFSET CSEG:ComWrite ;9: Output (Write) with verify
DW OFFSET CSEG:ComWStat ;10: Output Status
DW OFFSET CSEG:ComWFlush ;11: Output Flush
DW OFFSET CSEG:CmxUnknown ;12: Reserved (used to be Ioctl Output)
DW OFFSET CSEG:ComOpen ;13: Device Open
DW OFFSET CSEG:ComClose ;14: Device Close
DW OFFSET CSEG:CmxUnknown ;15: Removable Media
DW OFFSET CSEG:ComIoctl ;16: Generic Ioctl
DW OFFSET CSEG:CmxUnknown ;17: Reset Media
DW OFFSET CSEG:CmxUnknown ;18: Get Logical Drive Map
DW OFFSET CSEG:CmxUnknown ;19: Set Logical Drive Map
DW OFFSET CSEG:CmxUnknown ;20: DeInstall
MAXCMD = (($ - ComStratTab)/2) - 1
TimerHook DB 0 ; timer hook count
; actually a count of the number of ports that are open.
; incremented on a first open, decremented on a last close for any port.
PUBLIC VCOMAddress ; @VDM
VCOMAddress df 0 ; @VDM
; VCOM interrupt handler entry point @VDM
PUBLIC ClkIntrvl
ClkIntrvl DW 0 ; System clock interval in 10000s of a second
SysInfoSeg DW 0 ; for getting running MsCount for close timeout
PUBLIC Flags
Flags DB 0 ; flags for driver shut down
PUBLIC ComLHead, ComGAS
ComLHead LOGHEAD <,GasSize-$-2,SNAGENALERT,,,,,,,> ; SNA ALERT log entry header
PSIDS <> ; product set ID SV
ComGAS GAS <,,,GAS_PERM_LOSS,GAS_ADC_DEVCOMERROR,0> ; alert Sub Vector
ComPCS GAS_PCS <,,GAS_PCD_COMSTARTSTOP> ; prob cause SV
ComFCS GAS_FCS <,,,,GAS_FCC_DEVOUT,,,GAS_RAC_READY_DEVICE> ; fail cause SV
GasSize LABEL WORD
codelockhandle db lhlen dup(0)
datalockhandle db lhlen dup(0)
public IntRoutines
IntRoutines DW OFFSET RSEG:ComInt1 ; Int. routine for COM1
DW OFFSET RSEG:ComInt2 ; Int. routine for COM2
DW OFFSET RSEG:ComInt3 ; Int. routine for COM3
DW OFFSET RSEG:ComInt4 ; Int. routine for COM4
DSEG ENDS
CSEG SEGMENT
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
public startswapcode
startswapcode label byte
;** ComStrat - strategy entry point for COM
;
; Com1Strat and Com2Strat are the entry points for the strategy
; routine for the asynch device driver. The strategy routine is
; called by the DOS in order to handle device requests. This is
; the combined portion of the strategy code. This portion is
; swappable until the first open completes.
;
; ENTRY (es:bx) -> request packet
; (ds) DSEG segment for com01.sys
;
; EXIT result of operation set in request
; packet status field (PktStatus)
;
; USES di
Procedure ComStrat,FAR
mov di,bx ; (es:di) -> request packet
IFDEF RPSTRICT
or es:[di].PktStatus,SIGNATURE
ENDIF
SaveReg <es,di> ; save pointer to request packet
SaveReg <ds,si> ; save pointer to ComInfo structure
mov bp,sp ; allocate NULL stack frame
; cmp es:[di].PktCmd,01BH
cmp es:[di].PktCmd,CMDInit
jne cst10 ; init command, call directly
call ComInit ; do init
jmp bx ; do end processing
cst10:
cmp es:[di].PktCmd,CMDShutdown
jne cst20 ; init command, call directly
call ComShutdown
jmp CmxDone
cst20:
or si,si
jz CmxNotReady ; device not installed
xor bx,bx
mov bl,es:[di].PktCmd
cmp bl,MAXCMD
ja CmxUnknown ; command is invalid
IFDEF COMDEBUG
; int 3
ENDIF
shl bx,1 ; (bx) = word index to ComStratTab
; On entry to each of the command handlers:
;
; (ds:si) -> device info structure for COM1 or COM2.
; (es:di) -> request packet
; ax = device minor number
jmp ComStratTab[bx] ; go execute command
; Following are the six exit points for the driver. Request
; handlers all jump to one of these labels to have their exit
; condition set. The stack is permitted to be in an inconsistent
; state here because we are going to deallocate the stack frame.
Entry CmxDone,,,nocheck ; no error
mov ax,STDON
jmp SHORT cmx
Entry CmxUnknown,,,nocheck ; error - unknown command
mov ax,STDON OR STERR OR ERROR_I24_BAD_COMMAND
jmp SHORT cmx
Entry CmxNotReady,,,nocheck ; error - device not ready
mov ax,STDON OR STERR OR ERROR_I24_NOT_READY
jmp SHORT cmx
Entry CmxBusy,,,nocheck ; no error, device busy
mov ax,STDON OR STBUI
jmp SHORT cmx
Entry CmxMonitor,,,nocheck ; error - monitors not supported
mov ax,STDON OR STERR OR ERROR_I24_NO_MONITOR_SUPPORT
jmp SHORT cmx
Entry CmxInterrupted,,,nocheck ; error - interrupted ProcBlock
mov ax,STDON OR STERR OR ERROR_I24_CHAR_CALL_INTERRUPTED
jmp SHORT cmx
Entry CmxInvalidParameter,,,nocheck ; error - invalid parameter
mov ax,STDON OR STERR OR ERROR_I24_INVALID_PARAMETER
jmp SHORT cmx
Entry CmxBadLock,,,nocheck ; error, Lock failed
Entry CmxGenFail,,,nocheck ; error, general failure
mov ax,STDON OR STERR OR ERROR_I24_GEN_FAILURE
jmp SHORT cmx
Entry CmxInUse,,,nocheck ; error, device in use
mov ax,STDON OR STERR OR ERROR_I24_DEVICE_IN_USE
; Common exit point.
cmx: sti ; just in case someone left them off
mov sp,bp ; deallocate NULL stack frame
RestoreReg <si,ds> ; (ds:si) -> ComInfo structure
RestoreReg <di,es> ; (es:di) -> request packet
ASSUME ds:DSEG,es:NOTHING
;BUGBUG internal error if es:di not a req packet
;can't call ChkRPPtr because already poped stack frame.
mov es:[di].PktStatus,ax ; update status field
or si,si
jz cmret ; port is not installed or ShtuDown
test Flags,F_SHUT_DOWN
jnz cmret ; driver is shut down
;** Logging Facility support:
;
; if ci_flagGA != 0 ; is there an alert condition active?
; if SIS_SysLog != 0 ; yes, is the system logging active?
; ax = 8 ; yes, so set cx = max flag bit value
; GASLoop: if ci_flagGA[cx] != 0 ; is the bit on?
; es:bx --> ci_GAS ; yes, set up pointer to alert struc
; CALL DevHlp_LogEntry ; send the alert struc to sys log
; end_GASLoop; ; no....
; if ci_flagGA == 0 ; any other bits on?
; or ax == 0
; jump to postGAS ; no, so quit
; ax = ax - 1 ; test next bit in ci_flagGA
; ci_flagGA = ci_flagGA/2 ; shift right, lose low order bit
; jump to GASLoop ; and iterate
; postGAS: ci_flagGA = 0
;
mov cx,[si].ci_flagGA ; do we have an alert condition?
or cx,cx
jz cmx_oci ; no, so skip to check OCI Sem
mov ax,SysInfoSeg ; get SysInfoSeg pointer
push ds
mov ds,ax
mov ax,ds:SIS_SysLog ; get SysLog word from SysInfoSeg
test ax,LF_LOGENABLE ; is system logging enabled?
pop ds
jz postGAS ; no, reset GAS flag & continue on
; from here, check and service each bit in ci_flagGA that is set
mov ax,GAS_FLAG_MAX ; start with highest valid GAS bit
GASloop:
test cx,ax ; is this bit on?
jz end_GASLoop ; no, so check next bit
; now we know we have a specific alert condition (index = ax)
SaveReg <es,cx> ; preserve RP address
mov cx,LOGERROR ; function is LOGERROR
mov WORD PTR DS:ComGAS.GAS_ALERTID,ax ; IBMHACK use this for now
mov WORD PTR DS:ComGAS.GAS_ALERTID+2,0 ; IBMHACK
push ds ; es needs to point to COM data seg
pop es
lea bx,ComLHead ; (es:bx) --> ComLHead struc
mov dl,DevHlp_LogEntry ; log this generic alert
DevHelp ; via the DevHlp
RestoreReg <cx,es> ; restore RP pointer
end_GASLoop:
shr ax,1 ; bump test bit over one
jnz GASloop ; else try next bit
postGAS:
mov [si].ci_flagGA,0 ; reset all flags for next request
;** If this request is the owner of the oci_sem semaphore, clear it.
; We do this here, rather than in the respective ComXXX routines,
; because of the many places in which these routines can 'exit'.
;BUGBUG internal error if ds:si not a ComInfo
;can't call ChkComInfoPtr because already poped stack frame.
cmx_oci:
mov ax,es ; (ax) = es
cmp ax,[si].ci_oci_sem_own._hi
jne cmret ; not oci_sem owner
cmp di,[si].ci_oci_sem_own._lo
jne cmret ; not oci_sem owner
; this request owns the semaphore so clear it
mov ax,ds
lea bx,[si].ci_oci_sem ; (ax:bx) -> semaphore
mov dl,DevHlp_SemClear
DevHelp
mov [si].ci_oci_sem_own._hi,0 ; zap owner high (segment)
cmret: ret
EndProc ComStrat
;** IDC_Handler - IDC strategy entry point for COM
;
; IDC_Handler is the entry point for the IDC strategy
; routine for the asynch device driver. The strategy routine is
; called by the PCMCIA drivers.
;
; ENTRY (es:bx) -> request packet
; (ds) DSEG segment for com01.sys
;
; EXIT result of operation set in request
; packet status field (Return_Code)
;
; USES di
Procedure IDC_Handler,FAR
push es
push ds
pusha
setDS DSEG
mov di,bx ; (es:di) -> request packet
mov dx,es:[di].Command_Flag ;Check Command Flag
cmp dx,INSTALL_CMD ; Is it for Install COM port?
je idc10 ; Yes
cmp dx,DEINSTALL_CMD ; Is it for Deinstall COM port?
lje idc_deinstall ; Yes
mov cx,ERROR_INVALID_FUNCTION ; Otherwise, invalid Command
jmp idc88 ; Set Return Code and end
; Process Install COM port command
idc10: ;
mov ax,es:[di].Com_Port_Num ; Check for Port Number conflict
cmp ax,MAXCOMPORTS ; Com port > 4?
ljg port_num_conflict ; yes
dec ax ;
shl ax,1 ;
push bx
lea bx,Com1 ; Check 40:X for conflict
add bx,ax ;
mov bx,DS:[bx] ;
cmp bx,0 ;
pop bx
ljne port_num_conflict ;
; COM port address verification ;
no_40x_conflict:
mov dx,es:[bx].Com_Port_Addr
cmp dx,0 ;
lje port_addr_conflict
mov si,Com1 ;
cmp si,0 ;
je addr_check2 ;
mov dx,ds:[si].ci_port ;
cmp es:[bx].Com_Port_Addr,dx ;
jne addr_check2 ;
jmp port_addr_conflict ;
addr_check2: ;
mov si,Com2 ;
cmp si,0 ;
je addr_check3 ;
mov dx,ds:[si].ci_port ;
cmp es:[bx].Com_Port_Addr,dx ;
jne addr_check3 ;
jmp port_addr_conflict ;
addr_check3: ;
mov si,Com3 ;
cmp si,0 ;
je addr_check4 ;
mov dx,ds:[si].ci_port ;
cmp es:[bx].Com_Port_Addr,dx ;
jne addr_check4 ;
jmp port_addr_conflict ;
addr_check4: ;
mov si,Com4 ;
cmp si,0 ;
je irq_check ;
mov dx,ds:[si].ci_port ;
cmp es:[bx].Com_Port_Addr,dx ;
jne irq_check ;
jmp port_addr_conflict ;
; IRQ verification
public irq_check
irq_check: ;
mov dx,es:[di].Com_Port_IRQ ; Copy port IRQ from IDC packet
cmp dx,0
lje port_irq_conflict
mov ax,es:[di].Com_Port_Num ;
dec ax ;
shl ax,1 ;
lea bx,Com1P ; Copy ComNP to ComN
add bx,ax ; to install COM port
mov dx,DS:[bx] ;
mov si,dx ;
mov dx,es:[di].Com_Port_IRQ ; Copy port IRQ from IDC packet
lea bx,Com1 ;
add bx,ax ;
mov DS:[bx],si ;
shr ax,1
no_irq_conflict: ;
; SetUp ComInfo Structure!
mov ds:[si].ci_port_number,al ;
mov ds:[si].ci_irq,dl ; to ComInfo structure
mov dx,es:[di].Com_Port_Addr ; Copy port addr from IDC packet
mov ds:[si].ci_port,dx ; to ComInfo structure
mov [si].ci_flagx,0 ; chip type = ? @72032
mov [si].ci_dcb_writeto, WRITE_TO_INIT ; write timeout
mov [si].ci_dcb_readto, READ_TO_INIT ; read timeout
mov [si].ci_dcb_flags1, F1_INIT ; first flags byte
mov [si].ci_dcb_flags2, F2_INIT ; second flags byte
mov [si].ci_dcb_flags3, F3_INIT ; third flags byte
mov [si].ci_dcb_XonChar, xonequ ; XON character
mov [si].ci_dcb_XoffChar, xoffequ ; XOFF character
mov [si].ci_signature, SIGNATURE ; signature ID word
mov [si].ci_baud, DEFAULT_BAUD ; baud rate
mov [si].ci_bytesize, DEFAULT_BYTESIZE ; TX/RX byte size
mov [si].ci_parity, DEFAULT_PARITY ; parity
mov [si].ci_stopbits, DEFAULT_STOPBITS ; stop bits
mov [si].ci_cmask, DEFAULT_CHAR_MASK ; received character mask
mov [si].ci_depth, D_NONE ; interrupt depth
mov [si].ci_r_rpl.rpl_signature, SIGNATURE
mov [si].ci_w_rpl.rpl_signature, SIGNATURE
mov [si].ci_int_sharing, 0 ; int. sharing
mov [si].ci_mult_COMs_IRQ, 0 ; no other COM ports
; on this IRQ line
or [si].ci_dcb_flags2,F2_BRK_CHAR ;break replace active
or [si].ci_vdm_flag,VDM_Flag_notify_the_VCOM_TX ;@VDM
or [si].ci_vdm_flag,VDM_Flag_notify_the_VCOM_RX ;@VDM
or [si].ci_vdm_flag,VDM_Flag_InOut_Handshake_Init
mov [si].ci_vdm_Rx_State,1 ;@VDM set to Rx state 1
mov [si].ci_vdm_Tx_State,1 ;@VDM set to Tx state 1
mov [si].ci_vdm_Rx_Count,0 ;@VDM
mov [si].ci_vdm_Tx_Count,0 ;@VDM
mov [si].ci_vdm_LastMSR,0 ;@VDM
or [si].ci_flagx1, FX1_PCMCIA_MODEM ; Leave pcmcia bit
push es
push ax
push dx
push DSEG
push si
call _RMHELP_FindPCMCIANode
add sp,4
push DSEG
push si
call _RMHELP_CreateLDev
add sp,4
pop dx
pop ax
pop es
public idc_40_0
idc_40_0:
; update 40:0 area ; 85558
mov bx,ax ; port num
shl bx,1 ; com minor
mov ax,COM_SEG ; 40: tiled selector to ROM data
push es ; save es
mov es,ax ; (es:bx) -> 40:X
mov es:[bx],dx ; (dx) -> port addr
pop es ; restore es
public idc_uart
idc_uart:
; check for 16550A (FIFO)
add dx,R_FIFOC ; (dx) -> FIFO control register
mov al,FF_CLEAR_RX OR FF_CLEAR_TX
mout dx,al ; try to turn off the 16550A FIFOs
mov al,FF_ENABLE
mout dx,al ; try to turn on the 16550A FIFOs
min al,dx ; (al) = interrupt id
and al,II_16550A
test [si].ci_flagx,FX_16550A ; chip type = 16550A?
jnz idc20
cmp al,II_16550A
jne idc21 ; NO 16550A FIFO; go check for 16450
idc20:
or [si].ci_flagx,FX_16550A ; chip type = 16550A
or [si].ci_dcb_flags3,F3_FIFO_APO ; FIFO auto priority override
xor al,al
mout dx,al ; disable the 16550 FIFOs
jmp short idc23
idc21: ; check for 16450 (or 16550) by looking for the scratch register
; that is only on the 16450, 16550 and 16550A (not on 8250x).
MAGIC EQU 10101100b
xor al,al
mout dx,al ; disable the 16550 FIFOs
add dx,R_SCRATCH-R_FIFOC ; (dx) -> scratch register
mov al,MAGIC
mout dx,al ; (scratch) = MAGIC
min al,dx ; (al) = (scratch)
cmp al,MAGIC
jne idc23 ; NO scratch register; must be 8250
or [si].ci_flagx,FX_16450 ; set type flag to 16450
idc23:
cmp Kernel_Type, ABIOS_COM ;
jne idc30 ;
cli
call InitSharedIRQ
sti
mov [si].ci_int_sharing, INT_SHARING ; sharing com irq
mov [si].ci_mult_COMs_IRQ, INT_SHARING ;
cli
call OptimizeSharedIRQs
sti
idc30:
mov dx,[si].ci_port ; get port address
add dx,R_MODMC ; (dx) -> modem control reg.
xor al,al ; (al) = 0
mout dx,al ; lower all modem control lines
add dx,R_LINEC-R_MODMC ; (dx) -> line control reg.
min al,dx ; (al) = line control register
and al,NOT LC_BREAK ; turn off break
mout dx,al ; send to port
; save interrupt handler offset
; To make multiple COM ports easier to handle, this code is now
; table driven.
idc40:
mov bx,es:[di].Com_Port_Num
dec bx ; (bx) = minor number
shl bx,1 ; (es:bx) -> 40:X
mov dx, IntRoutines[bx] ; bx = com_minor*2
add bx, OFFSET DSEG:Com1 ; adjust to com. data struc.
idc45:
setDS DSEG
mov [si].ci_isr,dx ; save in cominfo
mov [bx],si ; init ComInfo ptr.
call InitQueues ; initialize input and output queues
xor cx,cx ; NO_ERROR return code
jmp SHORT idc89 ; CY cleared by XOR
; Process Deinstall COM port command
public idc_deinstall
idc_deinstall:
mov ax,es:[di].Com_Port_Num
dec ax
shl ax,1
lea bx,Com1
add bx,ax
mov ax,ds:[bx]
mov si,ax
cmp ax,0
je port_not_exist
xor ax,ax
mov ds:[bx],ax
; 85558
mov bx,es:[di].Com_Port_Num ; Update 40:X BIOS data area
dec bx ; Zero based
shl bx,1 ; Offset into 40:0
mov ax,COM_SEG ; 40: tiled selector to ROM data
push es ; save es
mov es,ax ; (es:bx) -> 40:X
xor ax,ax ; clear ax
mov es:[bx],ax ; (dx) -> port addr
push DSEG
push si
call _RMHELP_DestroyLDev
add sp,4
pop es ; restore es
cli
call OptimizeSharedIRQs ; Clean up SharedIRQ structure
sti
xor cx,cx ; NO_ERROR return code
jmp SHORT idc89 ; CY cleared by XOR
port_not_exist: ;
mov cx,ERROR_DEV_NOT_EXIST ;
jmp SHORT idc88 ;
port_irq_conflict: ;
mov cx,ERROR_INTERRUPT ;
jmp SHORT idc88 ;
port_addr_conflict: ;
mov cx,487 ; ERROR_INVALID_ADDRESS
jmp SHORT idc88 ;
port_num_conflict: ;
mov cx,ERROR_DEVICE_IN_USE ;
idc88: stc ; CY set for ERROR
idc89: ;
mov es:[di].Return_Code,cx ;
idc90: ;
popa
pop ds
pop es
ret ;
EndProc IDC_Handler
;** ComOpen - open request handler
;
; Most of the work performed by ComOpen occurs if the device
; is being opened for the first time. If it isn't all we have
; to do is increment the count of the number of opens (this is
; needed for close processing). If it is the first open then we
; have to initialize the device and the driver. Specifically, we
; have to;
; - hook the appropriate IRQ
; - hook the timer ticks
; - initialize the clock interval value (done once per boot)
; - flush the I/O queues
; - initialize the DCB structure, line control register,
; hardware registers and hardware handshake status
; - enable the modem control signals which in turn enables
; the remote transmitter
;
; ENTRY (ds:si) -> ComInfo
; (es:di) -> request packet
;
; EXIT hardware and driver initialized, open count incremented
;
; USES ax bx cx dx di
Procedure ComOpen,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
ChkRPPtr
mov [si].ci_vdm_OpenError ,1 ;@VDM set up for general failure
test es:[di].PktStatus,open_monitor
jz cop01
test [si].ci_vdm_flag,VDM_Flag_InUse ; FIX ---------------
ljz CmxMonitor ; no monitor support
jmp CmxGenFail ; if vdm, it is a failure
; We need to insure mutual exclusion between opens, closes and ioctls.
cop01:
call Get_OCI_Sem ; will not return if error
ChkComInfoPtr
cmp [si].ci_nopens,0
je cop05 ; not first open
;@VDM Begin
; check for VDM-Protectmode conflict
; IF (OpenCount != 0) AND (ComInfo.vdm_flag.InUse = TRUE)
test [si].ci_vdm_flag,VDM_Flag_InUse ;CP20D1390 ---------------
jz vdm_sup001 ; |
push es ; |
push ax
mov al,LocINFOseg ;Set VAR index for Local InfoSeg.
mov dl,DevHlp_GetDOSVar ;Set DevHlp function.
xor dh,dh
call [DevHlp] ;Go get variable address.
mov es,ax ;Make ES:BX point to InfoSeg address variable.
mov ax,es:[bx]+2
mov bx,es:[bx]
mov es,ax ;Make ES:BX point to InfoSeg address variable.
mov ax,es:[bx].LIS_CurScrnGrp ;Get Screen Group ID = Session ID
cmp [si].ci_sid,ax ;
pop ax ; |
pop es ; |
je UsedOpen ;CP20D1390
; THEN
jmp CmxInUse
UsedOpen: ; CP20D1390
inc [si].ci_nvdmopens ; Increment the counter for special VDM open
vdm_sup001: ; not in use by VDM
; ENDIF
;@VDM End
jmp cop80
; When the device is opened for the first time there are a number of
; initializations that need to be performed.
cop05:
test [si].ci_vdm_flag,VDM_Flag_No_IRQ_Open
ljnz cop90
test [si].ci_vdm_flag,VDM_Flag_InOut_Handshake_Init
jz cop0505
and [si].ci_vdm_flag,NOT VDM_Flag_InOut_Handshake_Init
push ax
push es ; |
mov al,LocINFOseg ;Set VAR index for Local InfoSeg.
mov dl,DevHlp_GetDOSVar ;Set DevHlp function.
xor dh,dh
call [DevHlp] ;Go get variable address.
mov es,ax ;Make ES:BX point to InfoSeg address variable.
mov ax,es:[bx]+2
mov bx,es:[bx]
mov es,ax ;Make ES:BX point to InfoSeg address variable.
cmp es:[bx].LIS_ProcType,LIS_PT_REALMODE ;If VDM session
jne cop0504
mov al,[si].ci_dcb_flags1
and al,NOT F1_IN_DSR_SENSE ; IDSR=OFF
and al,NOT F1_OUT_DSR_FLOW ; ODSR=OFF
and al,NOT F1_OUT_CTS_FLOW ; OCTS=OFF
mov [si].ci_dcb_flags1,al
; mov al,[si].ci_dcb_flags3
; test al,F3_FIFO_ON ; Is FIFO enabled?
; jz cop0504 ; no
; ; yes
; and al,NOT F3_FIFO_ON ; then,
; or al,F3_FIFO_OFF ; disable FIFO
;
; and al,NOT F3_RX_MASK ; set Receive Triger Level to 1 char
; and al,NOT F3_TX_16 ; set Transmit Triger Level to 1 char
; mov [si].ci_dcb_flags3,al
cop0504:
pop es ; |
pop ax ; |
; Rules for locking code and data segments:
; if (port is only one open)
; lock non-resident code and data segments;
cop0505:
.386p
cmp TimerHook,0 ; has any port been opened?
ljne codelocked ; at least one opened so already locked
push si
; lock driver's non-resident code segment
; do a virttolin DevHelp (linear address)
mov ax,CSEG
lea esi,startswapcode
mov dl,DevHlp_VirtToLin
DevHelp
mov edi,eax
; do a virttolin DevHelp (lockhandle)
mov ax,DSEG
mov esi,OFFSET codelockhandle
mov dl,DevHlp_VirtToLin
DevHelp
; do a VMLock DevHelp
mov esi,eax ; get offset to lock handle
mov eax,16 ; long term lock
mov ebx,edi ; get offset to area to lock
mov edi,-1 ; set to no page list
lea ecx,endswapcode ; size to lock
sub ecx,OFFSET startswapcode ; size to lock
mov dl,DevHlp_VMLock
DevHelp
ljc CmxBadLock
; Lock driver's non-resident data segment.
; If ANY enhanced ports were initialized, then this segment must
; be both physically contiguous and writable. This segment contains
; all ComInfos, and ComInfos contain the port's in/out queues.
; An enhanced port may do DMA operations to/from these queues, so
; the segment must be contiguous and writable. Since this lock is
; done when the FIRST port is opened, the lock must be "DMA aware"
; (subsequent enhanced port opens may need this).
mov ax,DSEG
lea esi,startswapdata
mov dl,DevHlp_VirtToLin
DevHelp
mov edi,eax
; do a virttolin DevHelp (lockhandle)
mov ax,DSEG
mov esi,OFFSET datalockhandle
mov dl,DevHlp_VirtToLin
DevHelp
; do a VMLock DevHelp
mov esi,eax ; get offset to lock handle
mov ebx,edi ; get offset to area to lock
mov edi,-1 ; set to no page list
movzx ecx,endswapdata ; size to lock
sub ecx,OFFSET startswapdata ; size to lock
LOCK_CONTIGUOUS EQU 0000010b
LOCK_WRITE EQU 0001000b
LOCK_LONG_TERM EQU 0010000b
mov eax,LOCK_LONG_TERM
test Flags,F_LOCK_CONTIGUOUS
jz no_dma
or eax,LOCK_CONTIGUOUS OR LOCK_WRITE
no_dma: mov dl,DevHlp_VMLock
DevHelp
pop si
jnc codelocked
; unlock code
push si
; do a virttolin DevHelp (lockhandle)
mov ax,DSEG
mov esi,OFFSET codelockhandle
mov dl,DevHlp_VirtToLin
DevHelp
; do a VMUnlock DevHelp using previously saved lock handle
mov esi,eax ; get offset to lock handle
mov dl,DevHlp_VMUnlock
DevHelp
pop si
jmp CmxBadLock
codelocked:
.286p
SetDS DSEG
;;==================== Enable LID again RAY Change Team 11\30\93 =====
; defect 77701 rdw BUGBUG The following code was removed because of problems
; wtih Resource Manager on Thinkpad with PCMCIA. There could
; still be a problem if resource manger is not fixed.
;
cmp Kernel_Type, ABIOS_COM
jne cop06c
mov al,DEVICE_ID ; set device ID value
mov bl, [si].ci_port_number ; get port number
inc bl
mov dl,DevHlp_GetLIDEntry
xor dh, dh
call [DevHlp] ; go for it!
jnc cop06d
mov [si].ci_LID,0 ;clear @95202
cmp ax, ERROR_LID_DOES_NOT_EXIST ;PCMCIA? @95202
je cop06c ;no LID @95202
jmp CmxInUse ;
cop06d:
mov [si].ci_LID, ax ; remember it for Close LID!
;;==========================================================================
cop06c:
test [si].ci_mult_COMs_IRQ, INT_SHARING ; sharing the IRQ with
jnz cop069 ; other COM ports?
cop06z:
mov ax,[si].ci_isr ; (ds:ax) -> handler
mov bl,[si].ci_irq ; (bx) = interrupt to be set
cop07:
xor bh,bh
mov dh,[si].ci_int_sharing ; 0 on ISA, var. on EISA
mov dl,DevHlp_SetIRQ ; devhlp request code
; Grab the interrupt vector.
; The interrupt handler will ignore interrupts (disable 16450 chip interrupts
; and EOI) if ci_nopens is zero, so interrupts can remain enabled until
; the interrupt enable register is to be set.
push es
push ds
pop es
setDS HSEG ; DS = driver's res. data seg
call es:[DevHlp]
pop es
setDS DSEG
jnc cop06 ; error, couldn't get IRQ
copFreeLID:
mov ax,[si].ci_LID ; set device ID value
mov bl, [si].ci_port_number ; get port number
inc bl
mov dl,DevHlp_FreeLIDEntry ; Free LID
xor dh,dh
call [DevHlp]
jmp CmxGenFail
cop069:
pushf ; Y: save interrupt flag
cli ; while updating linked list
call EnqComInfo ; add to queue
jnc cop053 ; no errors, so continue
call DeqComInfo ; add to queue
popf ; restore interrupt flag
jmp CmxGenFail ; error, couldn't get IRQ
cop053:
popf ; restore interrupt flag
; We hook the timer once for the driver, not for each port.
cop06:
cmp TimerHook,0
ljne cop40 ; timer already hooked
; The system clock interval is retrieved once, the very first time we
; get a first open.
cmp ClkIntrvl,0
jne cop30 ; ClkIntrvl already known
mov al,1
mov dl,DevHlp_GetDOSVar
DevHelp ; (ax:bx) -> SysInfoSeg
jnc cop10
ComErr <ComOpen : DOSvars unavailable>
cop10: mov es,ax
mov es,es:[bx] ; (es:0) -> InfoSeg
mov SysInfoSeg,es ; save SysInfoSeg pointer for close
mov ax,es:SIS_ClkIntrvl ; (ax) = clock interval in 0.0001 secs.
; BUGBUG 11-29-88 bryand - min clock interval = 100/10000 sec
; The test below insures that we can divide the caller's timeout values
; by the system clock interval and still store the results in a word.
cmp ax,100
jae cop20 ; safe timeout value
ComErr <ComOpen : system timeout value too small>
cop20: mov ClkIntrvl,ax ; save the value
; Hook the timer
cop30: mov dl,DevHlp_SetTimer
mov ax,OFFSET Ticker
setES DSEG ; ES = seg where DevHlp is
setDS HSEG ; DS = driver's res. data seg
call es:[DevHlp]
setDS DSEG
jnc cop40 ; sucessfully got timer
; could not hook timer - unset IRQ and fail the open
test [si].ci_mult_COMs_IRQ, INT_SHARING ; sharing the IRQ with
; other COM ports?
jz cop35 ; N: unset normally
pushf ; Y: save interrupt flag
cli ; while updating linked list
call DeqComInfo ; remove from queue
popf ; restore interrupt flag
jmp CmxGenFail ; then continue
cop35:
xor bh,bh
mov bl,[si].ci_irq
mov dl,DevHlp_UnSetIRQ
setES DSEG ; ES = seg where DevHlp is
setDS HSEG ; DS = driver's res. data seg
call es:[DevHlp]
setDS DSEG
jmp CmxGenFail
cop40: inc TimerHook ; got timer - inc count
FlushQueue ci_qin ; Flush the I/O queues.
FlushQueue ci_qout
; Initialize dcb values and internal flags needed on a first open.
mov [si].ci_dcb_XonChar,xonequ
mov [si].ci_dcb_XoffChar,xoffequ
mov [si].ci_dcb_writeto,WRITE_TO_INIT
mov [si].ci_dcb_readto,READ_TO_INIT
xor ax,ax ; (AX) = 0
mov [si].ci_dcb_ErrChar,al
mov [si].ci_dcb_BrkChar,al
and [si].ci_dcb_flags2,NOT (F2_ERR_CHAR OR F2_NULL_STRIP OR F2_BRK_CHAR)
and [si].ci_dcb_flags3,NOT F3_READ_TO_MASK
or [si].ci_dcb_flags3,F3_READ_TO_NORM
mov [si].ci_event,ax
mov [si].ci_comerr,ax
mov [si].ci_hsflag,al
mov al,[si].ci_bytesize
mov ah,[si].ci_parity
mov ch,[si].ci_stopbits
;
; reset VDM stuff for this port
;
; IF (ComInfo.vdm_flag.InUse = TRUE)
test [si].ci_vdm_flag,VDM_Flag_InUse ;@VDM
jz vdm_sup010 ;@VDM
; THEN
or [si].ci_dcb_flags2,F2_BRK_CHAR ;break replace active
or [si].ci_vdm_flag,VDM_Flag_notify_the_VCOM_TX ;@VDM
or [si].ci_vdm_flag,VDM_Flag_notify_the_VCOM_RX ;@VDM
mov [si].ci_vdm_Rx_State,1 ;@VDM set to Rx state 1
mov [si].ci_vdm_Tx_State,1 ;@VDM set to Tx state 1
mov [si].ci_vdm_Rx_Count,0 ;@VDM
mov [si].ci_vdm_Tx_Count,0 ;@VDM
mov [si].ci_vdm_LastMSR,0 ;@VDM
vdm_sup010: ; not in use by VDM
call CheckLCR ; set up line control reg.
jnc cop50
ComErr <ComOpen : invalid line control>
cop50:
call SetLineC ; set LCR
;
; vdm NO FIFO
;
; test [si].ci_vdm_flag,VDM_Flag_InUse
; jnz cop55
; ComputeAPO MUST be called before SetBaud so SetBaud can set
; the timeouts based on the baud rate.
call ComputeAPO ; compute FIFO modes
cop55:
mov ax,[si].ci_baud
call SetBaud ; set baud rate and timeouts
jnc short cop70
ComErr <SetBaud : invalid baud rate>
; Standard port: initialize UART registers.
cop70: mov dx,[si].ci_port
; WARNING: From here to the end of ComOpen (dx) is used to address a number
; of different ports. These port addresses are computed relative to the
; address currently in (dx). Any changes to this code should be sensitive
; to the order in which things occur.
; rdw 81245 - The following code has been added to handle on SMC UART's
; per the recommendation from from SMC Engineering.
; jag 102436 - Make sure interrupts are turned off at chip before prodding.
; check for 16550A (FIFO)
public smcuart1
smcuart1:
test [si].ci_flagx1, FX1_PCMCIA_MODEM
jnz rlines
xor ax,ax ; clear ax - disable all ints
add dx,R_INTEN ; (dx) -> interrupt enable reg
mout dx,al ; turn off ints
add dx, R_FIFOC-R_INTEN ; 81245 (dx) -> FIFO Control Register
mov al, FF_CLEAR_RX OR FF_CLEAR_TX ; 81245
mout dx, al ; 81245 try to turn of the 16550a FIFOs
add dx, R_MODMC-R_FIFOC ; 81245 (dx) -> MCR
min al, dx ; 81245 Get current value of MCR
or al, MC_LOOP ; 81245 Set loopback ON to clear THR
mout dx, al ; 81245
add dx, R_DATA-R_MODMC ; 81245 (dx) -> RBR
min al, dx ; 81245 Clear the 1 byte RBR
; 81245 At this point, we don't have to worry about clearing the loop back
; in the MCR as we will do this later when we clear MCR.
rlines:
add dx,R_LINES ; (dx) -> line status reg
min al,dx ; (al) = line status (clear it)
mov [si].ci_lsrshadow,al ; shadow the contents of the LSR
add dx,R_DATA-R_LINES ; (dx) -> data reg
min al,dx ; clear RX buffer
add dx,R_FIFOC-R_DATA ; (dx) -> fifo control reg
test [si].ci_dcb_flags3,F3_FIFO_HW_ON
jz cop75 ; FIFO HW off
mov al,[si].ci_dcb_flags3 ; (al) = flags3
and al,F3_RX_MASK ; (al) = RX trigger level
shl al,1 ; (al) = RX trigger level bits for FIFO
or al,FF_ENABLE OR FF_CLEAR_RX OR FF_CLEAR_TX
mout dx,al ; clear RX and TX FIFOs
cop75: .errnz R_INTID-R_FIFOC
; add dx,R_INTID-R_FIFOC ; (dx) -> int id reg.
min al,dx ; clear int id
mov [si].ci_msrshadow,0 ; zero previous msrshadow
add dx,R_MODMS-R_INTID ; (dx) -> modem status reg.
min al,dx ; clear modem status
call MxInt ; update msrshadow
xor bx,bx ; show 0 for previous flags1 and flags2
call ComputeHHS ; set up handshake state and
; initialize the MCR
call EnableRemoteTX ; we're all set up, tell the remote TXer
cli ; disable processor interrupts before
; enabling 16450 chip interrupts
; Enable Receive Data and nModem Status interrupts.
; TX Holding Register interrupt will be enabled by CheckTx.
mov dx,[si].ci_port ; (dx) -> port
public smcuart2
smcuart2:
mov al,IE_RX OR IE_MX ; (al) = interrupts to enable
add dx,R_INTEN ; (dx) -> interrupt enable reg
mout dx,al
cop80:
inc [si].ci_nopens ; count the open calls
cop90:
push es ;CP20D1390 Store the Session ID
push ax
mov al,LocINFOseg ;Set VAR index for Local InfoSeg.
mov dl,DevHlp_GetDOSVar ;Set DevHlp function.
xor dh,dh
call [DevHlp] ;Go get variable address.
mov es,ax ;Make ES:BX point to InfoSeg address variable.
mov ax,es:[bx]+2
mov bx,es:[bx]
mov es,ax ;Make ES:BX point to InfoSeg address variable.
mov ax,es:[bx].LIS_CurScrnGrp ;Get Screen Group ID = Session ID
mov [si].ci_sid,ax ;Save the Session ID
pop ax
pop es
cop100:
sti ; enable processor interrupts now that
; UART/ESP interrupts are enabled and the
; open count has been incremented.
jmp CmxDone ; done, no error
EndProc ComOpen
;** ComClose - close request handler
;
; ComClose performs most of its functions if it the close request
; leaves no pending opens on the device. If there are pending opens
; then ComClose does nothing. In the case where the close request
; will close the device, the following major functions are performed:
;
; - I/O queues are flushed
; - XON is sent if a previous XOFF was sent
; - async interrupts are disabled
; - the TX hardware is flushed
; - the timer hook and IRQ are released
;
; ENTRY (ds:si) -> ComInfo
;
; EXIT open count decremented, device may be closed
;
; USES ax bx cx dx di
Procedure ComClose,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
; Need to insure mutual exclusion between opens, closes and ioctls.
call Get_OCI_Sem ; will not return if error
ChkComInfoPtr
ChkRPPtr
ChkRPType CMDClose
cmp [si].ci_nopens,0
jne ccl1 ; device is open
jmp CmxDone ; done, no opens
ccl1: cmp [si].ci_nopens,1
ljne ccl99 ; not the last close, port is still open
; Set the last close flag so that the RX interrupt service routine
; will not enqueue any more data.
test [si].ci_vdm_flag,VDM_Flag_No_IRQ_Open
ljnz ccl99
or [si].ci_flagx,FX_LAST_CLOSE ; flag last close in progress
mov [si].ci_sid,0 ; Clear the Session ID (@0001)
SaveReg <es,di> ; 103070-1 Keep our Req. Packet PTR
call ComWFlushSub ; flush all outstanding write requests
call ComRFlushSub ; flush all outstanding read requests
RestoreReg <di,es> ; 103070-1 Restore our Req. Packet PTR
mov al,[si].ci_linec ; (al) = line control value
and al,NOT LC_BREAK ; turn off break
and [si].ci_hsflag, NOT HS_BREAK_SET
; break no longer set
call SetLineC
; Standard port:
ccl13: call EnableRemoteTX ; send an XON if XOFF previously sent
mov dx,[si].ci_port
add dx,R_INTEN ; (dx) -> interruprt enable reg
xor al,al
mout dx,al ; disable all com interrupts
test [si].ci_mult_COMs_IRQ, INT_SHARING ; sharing the IRQ with
; other COM ports?
jz ccl12 ; N: unset normally
pushf ; Y: save interrupt flag
cli ; while updating linked list
call DeqComInfo ; remove from queue
popf ; restore interrupt flag
jmp short ccl15 ; then continue
ccl12:
ccl14:
xor bh,bh
mov bl,[si].ci_irq
mov dl,DevHlp_UnSetIRQ
push es
push ds
pop es
setDS HSEG
call es:[DevHlp] ; release the IRQ
pop es
setDS DSEG
jnc ccl15
ComErr <ComClose : could not release the IRQ>
; BUGBUG Should we compute wait time based on byte size too?
; if either DTR or RTS is ON, we need to wait:
; for data to get out of TX hardware (THRE & TSRE)
; up to 2 character times (.5 char time at a time up to 1 second)
; for data to be received by remote
; 10 character times up to a 1 second maximum
; before turning OFF DTR and RTS.
ccl15: mov dx,[si].ci_port
add dx,R_MODMC ; (dx) -> modem control reg
min al,dx ; al = modem output signals
test al,MC_DTR OR MC_RTS
ljz ccl60 ; lines are already down, don't wait
; wait for data to get out of TX hardware (THRE & TSRE)
; 6000 (bits*ms/sec) = 12 bits * .5 chars * 1000 (ms/sec)
; ms = 6000 (bits*ms/sec) / baud (bits/sec)
xor dx,dx
mov ax,6000d ; dx:ax = 6000d
; trap 0 problem: ci_baud MUST be > 0 for the div to work
; the result MUST fit into ax for the div to work
; (dx = 0 so the above is true)
cmp [si].ci_baud,0
je ccl151
div [si].ci_baud ; ax = ms for 6 bits
jmp short ccl152
ccl151:
mov ax,998d ; set AX value for ci_baud = 0
ccl152:
inc ax ; round up
mov cx,ax ; (0:cx) = timeout
cmp cx,1000d
jb ccl20 ; cx < 1 second timeout
mov cx,1000d ; cx = 1 second timeout
ccl20: ; don't have to use ReadLSR because IRQ is already disabled
mov dx,[si].ci_port
add dx,R_LINES ; (dx) -> LSR
min al,dx ; (al) = LSR
and al,LS_THRE OR LS_TSRE
cmp al,LS_THRE OR LS_TSRE
je ccl30 ; transmit hardware already empty
xor dx,dx ; (dx:cx) = timeout value
cli ; 103070-1 must cli before block
call ProcBlockNI ; wait for data to get out of hardware
jmp SHORT ccl20 ; go check if done
; wait 10 char times for data to be received by remote (1 sec max)
; 120000 (bits*ms/sec) = 12 bits * 10 chars * 1000 (ms/sec)
; ms = 120000 (bits*ms/sec) / baud (bits/sec)
; NOTE: baud must be >= 2 or div will overflow
;
; timeout = (120000/baud)+1
; if (timeout > 1000)
; timeout = 1000
; endtime = MsCount + timeout
; do {
; block(timeout)
; timeout = endtime - MsCount
; } while (timeout > 0);
ccl30: mov dx,1
mov ax,0d4c0h ; (dx:ax) = 120000
cmp [si].ci_baud,2 ; remove trap 0
jb ccl301
div [si].ci_baud ; ax = ms for 12 bits
jmp short ccl302
ccl301:
mov ax,998d
ccl302:
inc ax ; round up
mov cx,ax
xor dx,dx ; (dx:cx) = timeout value
cmp cx,1000d
jb ccl40 ; cx < 1 second timeout
mov cx,1000d ; cx = 1 second timeout
ccl40: ; get current time (running MS count from sysinfoseg)
SaveReg <ds>
mov ax,SysInfoSeg ; get SysInfoSeg pointer for close
mov ds,ax
cli ;JGT disable to read MsCount
mov ax,ds:SIS_MsCount._hi
mov bx,ds:SIS_MsCount._lo ; (ax:bx) = running MS count
sti ;JGT and reenable
RestoreReg <ds>
add bx,cx
adc ax,0 ; (ax:bx) = completion MS count
ccl50: SaveReg <ax,bx> ; save completion MS count
cli ; 103070-1 must cli before block
call ProcBlockNI ; wait for remote to get data
; blocks NON-INTERRUPTABLY for up to 1 second
; if the block times out, then the full time was waited;
; else spurious ProcRun, we have to make sure enough time elapsed
RestoreReg <bx,ax> ; (ax:bx) = completion MS count
jc ccl60 ; block timed out, were done
SaveReg <ds>
mov cx,SysInfoSeg
mov ds,cx ; (ds:0) -> SysInfoSeg
mov cx,bx
mov dx,ax ; (dx:cx) = completion MS count
cli ;JGT disable to read MsCount
sub cx,ds:SIS_MsCount._lo
sbb dx,ds:SIS_MsCount._hi ; (dx:cx) = MS remaining
sti ;JGT and reenable
RestoreReg <ds>
js ccl60 ; remaining is neg, done
jnz ccl50 ; remaining is NZ, not done
or cx,cx
jnz ccl50 ; remaining is NZ, not done
ccl60: mov dx,[si].ci_port
add dx,R_MODMC ; (dx) -> modem control reg
xor al,al
mout dx,al ; turn off all MCR signals
ccl70:
.386p
; Unhook timer if all devices closed
dec TimerHook
jnz ccl90 ; one of the ports still has
; outstanding opens
mov dl,DevHlp_ResetTimer
mov ax,OFFSET Ticker
setES DSEG
setDS HSEG
call es:[DevHlp]
setDS DSEG
; unlock code
push si
; do a virttolin DevHelp (lockhandle)
mov ax,ds
mov esi,OFFSET codelockhandle
mov dl,DevHlp_VirtToLin
DevHelp
; do a VMUnlock DevHelp using previously saved lock handle
mov esi,eax ; get offset to lock handle
mov dl,DevHlp_VMUnlock
DevHelp
pop si
; unlock common data
push si
; do a virttolin DevHelp (lockhandle)
mov ax,ds
mov esi,OFFSET datalockhandle
mov dl,DevHlp_VirtToLin
DevHelp
; do a VMUnlock DevHelp using previously saved lock handle
mov esi,eax ; get offset to lock handle
mov dl,DevHlp_VMUnlock
DevHelp
pop si
.286p
jnc ccl90
ComErr <ComClose : could not reset timer>
ccl90: and [si].ci_flagx,NOT FX_LAST_CLOSE ; clear last close flag
cmp Kernel_Type, ABIOS_COM
jne ccl99
mov ax, [si].ci_LID ; retrieve the LID for him
mov dl, DevHlp_FreeLIDEntry
call [DevHlp]
ccl99: dec [si].ci_nopens ; one less open
cmp [si].ci_nvdmopens,0 ; CP20D1390 If special VDM open was done
jle ccl100 ; then
dec [si].ci_nvdmopens ; decrement the counter
ccl100:
jmp CmxDone
EndProc ComClose
;** ComDeInstall - deinstall request handler
;
; Deinstallation is not supported.
;
; ENTRY
;
; EXIT
;
; USES
;Procedure ComDeInstall,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
; Since we are not supporting deinstallation, we optimize the handling
; of this request by making its table entry CmxUnknown.
;EndProc ComDeInstall
;** ComRead - read request handler
;
; ComRead handles read requests for the driver. If there are no
; outstanding requests, we will attempt to satisfy the current
; one immediately. If we can't then we will block the thread
; until we can satisfy it or we time out. Once the thread wakes
; up from the block it will attempt to satisfy its request.
;
; ENTRY (ds:si) -> ComInfo
; (es:di) -> request packet
;
; EXIT
;
; USES al cx dx si
Procedure ComRead,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
ChkRPPtr
ChkRPType CMDINPUT
ifdef PERFVIEW
pvw_Read START ;@PVW start timer
endif
cli
cmp [si].ci_r_rp._hi,0
jne crr30 ; current request active, queue this one
; test [si].ci_vdm_flag,VDM_Flag_InUse ;CP20D1390 -- Fix CP20PB726384
; jz crr_normal_req ; If the port is opened by special
; cmp [si].ci_nvdmopens,0 ; VDM access, Read is not allowed.
; ljg CmxInUse ;+yn Device in Use
crr_normal_req:
; If there are no outstanding read requests we attempt to satisfy the
; one we just got.
sti
mov cx,es:[di].IOcount ; (cx) = requested bytes
or cx,cx
ifdef PERFVIEW
ljz crrx ; request is for 0 bytes, done;@PVW
else
ljz CmxDone
endif
mov [si].ci_r_to_move,cx ; initialize number of bytes to move
; set up GDT selector which we allocated at init time
;; PhysToGDTSel (ComInfo[si].GDTSelRead, physical @, length)
;; move ComInfo[si].GDTSelRead to Physical @. _hi
;; move 0 to Physical @. _lo
push si
mov si,[si].ci_GDTSelRead
; es:di -> request packet
call SetUpGDT
pop si
cmp [si].ci_qin.ioq_count,0
je crr00 ; no data in queue
call ReadQueue ; returns (cx) = bytes not dequeued
; updates ci_r_to_move
; The current request may be satisfied if any of the following are true
; - all the data requested was moved (ci_r_to_move == cx == 0)
; - read mode is no wait
; - read mode is wait for something and something was moved
; (ci_r_to_move != IOcount)
; If the request cannot be completed now, it is either normal timeout
; mode or 'wait for something' mode and nothing received yet.
; If it is normal timeout mode, the request will be run when there is
; enough data in the RXQ to satisfy the request (RxInt) or when the
; request times out (ReadTick).
; If it is 'wait for something' mode, the request will be run when there
; is ANY data in the RXQ (RxInt) or when the request times out (ReadTick).
jcxz crr10 ; all the data was moved (done)
crr00: mov al,[si].ci_dcb_flags3
and al,F3_READ_TO_MASK ; al = read timeout mode
cmp al,F3_READ_TO_NW
je crr10 ; read mode is no wait (done)
cmp al,F3_READ_TO_NORM
je crr20 ; read mode normal (block)
cmp cx,es:[di].IOcount
je crr20 ; nothing moved and wait for something
crr10: sub es:[di].IOcount,cx ; update number of bytes read
ifdef PERFVIEW
jmp crrx ; request is done ;@PVW
else
jmp CmxDone
endif
; If we get here we couldn't satisfy the request. This means
; that we couldn't completely satisfy a normal request or there
; was nothing to move for a wait for something request.
crr20: cli
mov [si].ci_r_rp._hi,es ; save request packet pointer
mov [si].ci_r_rp._lo,di
mov cx,[si].ci_r_to_start ; initialize request time out value
mov [si].ci_r_to,cx
jmp SHORT crr40 ; go block
crr30:
; We get here when there is already a current request, so this request
; must be added to the read request packet list and processed later.
SaveReg <si>
lea si,[si].ci_r_rpl ; (ds:si) -> read request packet list
call LinkRP ; add RP to list of reads
; outstanding requests
RestoreReg <si> ; (ds:si) -> ComInfo
crr40:
; Block until the request:
; completes - normal wait mode - ProcRun'ed - carry clear
; enough data in qin to finish request
;
; completes - no wait mode - ProcRun'ed - carry clear
; may be some data in qin (could be 0)
; may be enough data in qin to finish request (could be 0)
;
; completes - wait for something - ProcRun'ed - carry clear
; some data in qin (could be 1)
; may be enough data in qin to finish request (could be 1)
;
; times out - ProcRun'ed - carry clear
; may not be enough data in qin to finish request
;
; is flushed - ProcRun'ed - carry clear
; request packet shows zero bytes requested
;
; block is interrupted (usually for a signal to the thread).
; may be enough data in qin to finish request (could be 0)
ifdef PERFVIEW
pvw_Read STOP ;@PVW Stop perfview timer
endif
mov cx,-1 ; (dx:cx) = infinite time out
mov dx,cx
call ProcBlock
ChkRPType CMDINPUT
ifdef PERFVIEW
pushf ;@PVW save flags
pvw_Read START ;@PVW start timer again
popf ;@PVW restore flags
endif
cli
jc crr50 ; interrupted ProcBlock
test es:[di].PktStatus,STDON
jz crr40 ; spurious ProcRun go ProcBlock again
; We were run, lets finish the request.
jmp SHORT crr60
; Interrupted ProcBlock.
crr50: cmp di,[si].ci_r_rp._lo
jne crr80 ; not the current request
mov ax,es
cmp ax,[si].ci_r_rp._hi
jne crr80 ; not the current request
; As the current request we were either run or interrupted.
; Either way, we will finish the request know.
crr60: mov cx,es:[di].IOcount
jcxz crr70 ; request is satisfied (zero length)
; could have been forced to zero
; because it was flushed
mov cx,[si].ci_r_to_move ; (cx) = number of bytes to transfer
jcxz crr70 ; already done
cmp [si].ci_qin.ioq_count,0
je crr70 ; there is nothing to transfer
sti
call ReadQueue ; returns (cx) = bytes not dequeued
; updates ci_r_to_move
cli
crr70: sub es:[di].IOcount,cx ; update number of bytes transfered
mov [si].ci_r_rp._hi,0 ; no longer current
call StartNextRRP ; start the next read request
ifdef PERFVIEW
jmp SHORT crrx ; this request is done
else
jmp CmxDone
endif
; The ProcBlock was interrupted but we are not the current request.
; So we have to pull ourselves out of the read request list.
crr80: cmp [si].ci_r_rpl._hi,0 ; 103070-1 See if RPL exists
je crr81 ; 103070-1 No, must be ci_r_rp._hi=0
lea si,[si].ci_r_rpl ; (ds:si) -> read request packet list
call UnLinkRP ; unlink the specific interrupted RP
crr81: ; 103070-1 Clear IO count and return
mov es:[di].IOcount,0 ; interrupted, therefore 0 bytes moved
ifdef PERFVIEW
crrx:
pvw_Read STOP,DOCOUNTERS ;@PVW stop timer, inc num_reads,
;@PVW update bytes read
jmp CmxDone
else
jmp CmxDone ; 103070-2 no Perfview enabled
endif
EndProc ComRead
;** ComWrite - write request handler
;
; ComWrite handles write requests for the driver. When we get a write
; request we check to see if there are any others active. If there
; aren't we transfer as much data into the queue as we can. Either
; way we then block the process until we send the data out the hardware.
; When we wake up from the block we adjust the number of bytes moved
; and return. If we are interrupted and are not the current request
; we pull ourselves out of the queue and set the number of bytes
; transferred to zero.
;
; ENTRY (ds:si) -> ComInfo
; (es:di) -> request packet
;
; EXIT
;
;
; USES ax bx cx
Procedure ComWrite,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
ChkRPPtr
IFDEF RPTSTRICT
mov es:[di].PktCmd,CMDOUTPUT ; write with verity => write
ENDIF
ifdef PERFVIEW
pvw_Write START ;@PVW start timer
endif
cli
; test [si].ci_vdm_flag,VDM_Flag_InUse ;CP20D1390 -- Fix CP20PB726384
; jz cwr_normal_req ; If the port is opened with special
; cmp [si].ci_nvdmopens,0 ; vdm access, Write is not allowed
; ljg CmxInUse ;+yn error General Failure
cwr_normal_req:
cmp [si].ci_w_rp._hi,0
jne cwr1 ; no current request
; If there are no outstanding write requests we move as much data
; as we can into the output queue.
sti
mov cx,es:[di].IOcount
or cx,cx
ifdef PERFVIEW
ljz cwrx ; request is for 0 bytes, done;@PVW
else
ljz CmxDone
endif
; set up GDT selector which we allocated at init time
;; PhysToGDTSel (ComInfo[si].GDTSelWrite, physical @, length)
;; move ComInfo[si].GDTSelWrite to Physical @. _hi
;; move 0 to Physical @. _lo
push si
mov si,[si].ci_GDTSelWrite
; es:di -> request packet
call SetUpGDT
pop si
call WriteQueue ; returns (cx) = bytes not enqueued
; updates ci_w_to_move
cli
mov [si].ci_w_rp._hi,es ; save request packet pointer
mov [si].ci_w_rp._lo,di
mov cx,[si].ci_w_to_start ; initialize request time out value
mov [si].ci_w_to,cx
SaveReg <di> ; save request pkt ptr
call CheckTX ; adjust TX empty interrupt
RestoreReg <di> ; restore request pkt ptr
jmp SHORT cwr2
; Whether or not we are the current request we have to block until
; the data moves out of the hardware.
cwr1: SaveReg <si>
lea si,[si].ci_w_rpl ; (ds:si) -> write request packet list
call LinkRP ; add RP to list of writes
RestoreReg <si> ; (ds:si) -> ComInfo
; Now that we have linked the request we want to block it
; until we are able to satisfy it.
cwr2:
ifdef PERFVIEW
pvw_Write STOP ;@PVW stop timer
endif
mov cx,-1 ; (dx:cx) = no ProcBlock time out
mov dx,cx
call ProcBlock
ChkRPType CMDOUTPUT
ifdef PERFVIEW
pushf ;@PVW save flags
pvw_Write START ;@PVW start timer again
popf ;@PVW restore flags
endif
cli
jc cwr3 ; interrupted ProcBlock
test es:[di].PktStatus,STDON
jz cwr2 ; spurious ProcRun go ProcBlock again
;;MF jmp cwrx ; valid ProcRun, request done ;@PVW
jmp cwr3_5 ;;MF ; valid ProcRun, run next request
; Interrupted ProcBlock.
cwr3: test es:[di].PktStatus,STDON
;;MF jnz cwrx ; request already complete
jnz cwr3_5 ; request complete, run next request
cmp di,[si].ci_w_rp._lo
jne cwr4 ; not the current request
mov ax,es
cmp ax,[si].ci_w_rp._hi
jne cwr4 ; not the current request
; Current request was interrupted.
mov [si].ci_w_rp._hi,0 ; no longer a current request
mov ax,[si].ci_w_to_move
add ax,[si].ci_qout.ioq_count
sub es:[di].IOcount,ax ; number of bytes sent to HW
FlushQueue ci_qout
sti
cwr3_5: ;;MF
call StartNextWRP ; start the next write request
ifdef PERFVIEW
jmp SHORT cwrx ; this request is done
else
jmp CmxDone
endif
; The ProcBlock was interrupted but we were not the current request.
cwr4: cmp [si].ci_w_rpl._hi,0 ; 103070-1 Check to see that RPL exists
je cwr4_5 ; 103070-1 No, must be ci_w_rp._hi=0
lea si,[si].ci_w_rpl ; (ds:si) -> write request packet list
call UnLinkRP ; unlink the specific interrupted RP
cwr4_5: ; 103070-1 Clear IO Count and return
mov es:[di].IOcount,0 ; interrupted therefore 0 bytes written
ifdef PERFVIEW
cwrx:
pvw_Write STOP,DOCOUNTERS ;@PVW stop timer, inc num_writes,
;@PVW update bytes written
jmp CmxDone
else
jmp CmxDone ; 103070-2 no PERVIEW enabled
endif
EndProc ComWrite
;** ComNDRead - Non-destructive read request handler
;
; ComNDRead will return the first character in the input queue
; if there is one. Otherwise it returns an error. The read is
; non-destructive in that the character is not removed from the
; queue.
;
; ENTRY (ds:si) -> ComInfo
; (es:di) -> request packet
;
; EXIT
;
; USES bx
Procedure ComNDRead,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
ChkRPPtr
; test [si].ci_vdm_flag,VDM_Flag_InUse ;CP20D1390 -- Fix CP20PB726384
; jz cndr_normal_req ; If the port is opened with special
; cmp [si].ci_nvdmopens,0 ; vdm access, none distructive Read is not allowed.
; ljg CmxInUse ;+yn error General Failure
cndr_normal_req:
cmp [si].ci_qin.ioq_count,0
lje CmxBusy ; no data in queue, device busy
mov bx,[si].ci_qin.ioq_out ; Get the first char
mov bl,[bx]
mov es:[di].NDRbyte,bl
jmp CmxDone ; Return w/ "Done, no error."
EndProc ComNDRead
;** ComRStat - input status request handler
;
; We return busy if the input queue is empty or
; if there is an outstanding read request.
; Otherwise we return done.
;
; ENTRY (ds:si) -> ComInfo
;
; EXIT
;
; USES NONE
Procedure ComRStat,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
cmp [si].ci_qin.ioq_count,0
lje CmxBusy ; queue is empty
cmp [si].ci_r_rp._hi,0
ljne CmxBusy ; request outstanding
jmp CmxDone ; we're not busy
EndProc ComRStat
;** ComWStat - output status request handler
;
; We return busy if there is an outstanding write request
; or we are unable to transmit.
; Otherwise we return done.
;
; ENTRY (ds:si) -> ComInfo
;
; EXIT
;
; USES al
Procedure ComWStat,NEAR
ChkComInfoPtr
cmp [si].ci_w_rp._hi,0
ljne CmxBusy ; request outstanding
; If a BREAK is set or an XOFF was sent or recieved, we can not transmit.
test [si].ci_hsflag,HS_BREAK_SET OR HS_XOFF_RECEIVED OR HS_XOFF_SENT
ljnz CmxBusy
mov al,[si].ci_msrshadow ; (al) = msr_shadow
and al,[si].ci_outhhslines ; mask bits of interest
cmp al,[si].ci_outhhslines
ljne CmxBusy ; modem lines down
jmp CmxDone ; we're not busy
EndProc ComWStat
;** ComRFlush - read flush request handler
;** ComWFlush - write flush request handler
;
; ENTRY (ds:si) -> ComInfo
;
; EXIT
;
; USES
Procedure ComRFlush,NEAR
; -- Fix CP20PB726384
; test [si].ci_vdm_flag,VDM_Flag_InUse ;CP20D1390 If the port is opened
; jz crf_normal_req ; with special vdm access,
; cmp [si].ci_nvdmopens,0 ; Read Buffer Flush is not allowed.
; ljg CmxInUse ;+yn error General Failure
crf_normal_req:
call ComRFlushSub
cr10: call EnableRemoteTX ; send an XON if XOFF previously sent
jmp CmxDone
Entry ComWFlush,,,nocheck
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
call ComWFlushSub
jmp CmxDone
EndProc ComRFlush
Procedure ComRFlushSub,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
; -- Fix CP20PB726384
; test [si].ci_vdm_flag,VDM_Flag_InUse ;CP20D1390 If the port is opened
; jz cwf_normal_req ; with special vdm access,
; cmp [si].ci_nvdmopens,0 ; Write Buffer Flush is not allowed.
; ljg CmxInUse ;+yn error General Failure
cwf_normal_req:
cli
or [si].ci_Flagx1,FX1_FLUSH_RX_IP ;;MF
FlushQueue ci_qin
cmp [si].ci_r_rp._hi,0
je crf1 ; no current request
les di,[si].ci_r_rp ; (es:di) -> current read request
ChkRPPtr
ChkRPType CMDINPUT
mov es:[di].IOcount,0 ; update number of bytes transfered
mov es:[di].PktStatus,STDON ;mw mark request done
mov [si].ci_r_rp._hi,0 ; no more read requests
sti
call ProcRun
crf1: push si
lea si,[si].ci_r_rpl ; (ds:si) -> read request packet list
jmp SHORT cmf1
Entry ComWFlushSub,,,nocheck
cli
or [si].ci_Flagx1,FX1_FLUSH_TX_IP ;;MF
mov dx,[si].ci_port
add dx,R_INTEN ; (dx) -> interrupt enable reg
in al,dx
and al,NOT IE_TX ; disable TX interrupts first
out dx,al
ChkComInfoPtr
mov cx,[si].ci_qout.ioq_count
FlushQueue ci_qout
cmp [si].ci_w_rp._hi,0
je cwf1 ; no current requests
les di,[si].ci_w_rp ; (es:di) -> current write request
ChkRPPtr
ChkRPType CMDOUTPUT
add cx,[si].ci_w_to_move
sub es:[di].IOcount,cx ; update number of bytes transfered
mov es:[di].PktStatus,STDON ;mw mark request done
mov [si].ci_w_rp._hi,0 ; no more write requests
mov [si].ci_w_to_move,0 ;;MF reset the # of bytes left to move
sti
call ProcRun
cwf1: push si
lea si,[si].ci_w_rpl ; (ds:si) -> write request packet list
; We enter here, after the current requests are flushed, in
; order to flush all outstanding requests.
cmf1: sti
;BUGBUG must remove all requests from the list BEFORE enabling interrupts.
;unless ci_r_rp is always checked before trying to use ci_r_rpl
ChkRPLPtr
call UnLinkHeadRP ; (es:di) -> runnable request packet
jc cmfx ; no more to run
ChkRPPtr
mov es:[di].IOcount,0 ; update number of bytes transfered
call ProcRun
jmp SHORT cmf1 ; try to run another
cmfx: pop si
and [si].ci_Flagx1, not (FX1_FLUSH_TX_IP+FX1_FLUSH_RX_IP) ;;MF
ret
EndProc ComRFlushSub
;** ComShutdown - Shutdown Handler
;
; ComShutdown turns off the FIFO enabling bit of the given COM port.
; ComShutdown also turns off the loop back bit of MCR.
;
;
; ENTRY (ds:si) -> ComInfo
; (es:di) -> request packet
;
; EXIT
;
; USES bx
Procedure ComShutdown,NEAR
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
ChkRPPtr
cmp si,0
je End_Shutdown
test [si].ci_dcb_flags3,F3_FIFO_ON
jz End_Shutdown
mov dx,[si].ci_port
add dx,R_FIFOC
; 81245 mov al,FF_ENABLE
; 81245 mout dx,al
min al,dx
and al,NOT FF_RX_MASK
mout dx,al
mov al,NOT FF_ENABLE
mout dx,al
and [si].ci_dcb_flags3,NOT F3_FIFO_ON
mov dx,[si].ci_port
add dx,R_MODMC
min al,dx
and al,NOT MC_LOOP
mout dx,al
End_Shutdown:
ret
EndProc ComShutdown
;------- !WARNING! Keep InitQueues at the bottom or risk assmembly errors!
;** InitQueues - initialize the qin and qout IO_Queues
;
; InitQueues merely sets up the input and output queues
; to there initial state. That is,
;
; base = in = out = start of queue
; end = start of queue + size of queue
; count = 0
;
; ENTRY (ds:si) -> ComInfo structure
;
; EXIT ioq structures initialized
;
; USES ax
Procedure InitQueues,HYBRID
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
ChkComInfoPtr
lea ax,WORD PTR [si].ci_qin_q ; (ax) -> input queue
; Initialize input queue.
mov [si].ci_qin.ioq_base,ax
mov [si].ci_qin.ioq_in,ax
mov [si].ci_qin.ioq_out,ax
add ax,QI_SIZE
mov [si].ci_qin.ioq_end,ax
mov [si].ci_qin.ioq_count,0
lea ax,WORD PTR [si].ci_qout_q ; (ax) -> output queue
; Initialize output queue.
mov [si].ci_qout.ioq_base,ax
mov [si].ci_qout.ioq_in,ax
mov [si].ci_qout.ioq_out,ax
add ax,QO_SIZE
mov [si].ci_qout.ioq_end,ax
mov [si].ci_qout.ioq_count,0
ret
EndProc InitQueues
;** InitSharedIRQ - initialize the ShrdIRQData structure
;
; InitSharedIRQ - sets up the ShrdIRQData structure for
; a shared interrupt line. This data structure is used
; as the "head" pointer for the linked list of ComInfo structures
; that share an IRQ line. There is a two-way link used
; to connect the data structures (NOTE: this picture is of the
; FIRST ComInfo structure in the chain - the variable si_firstCOM
; is the "head" pointer to the start of the chain.)
;
; ShrdIRQData ComInfo
; structure structure
;
; +----------------+
; +->| ci_dcb_writeto |
; | +----------------+
; +-------------+ | .
; | si_irq | <--+ | .
; +-------------+ | | +----------------+
; | si_opens | +----| ci_int_data |
; +-------------+ | +----------------+
; | si_firstCOM |------+ | ci_nextCOM |--->next ComInfo
; +-------------+ +----------------+ in the chain
;
; This way, when the COM port is opened, the ci_int_data field in
; ComInfo can be used to determine
; which of the ShrdIRQData structures the COM port is associated with.
; The chain can then be walked to determine where the COM port
; should be placed (based on highest baud rate first).
;
;
; The responsiblity of this routine is to initialize ci_int_data
; and, if necessary, si_irq.
;
; ENTRY (ds:si) -> ComInfo structure
;
; EXIT ComInfo and ShrdIRQData structures initialized
;
; USES flags
Procedure InitSharedIRQ,HYBRID
ASSUME cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
pusha
push ds
push es
setDS DSEG ; DSEG selector
xor bx,bx ; init. index
mov al, [si].ci_irq ; IRQ number to search for
mov cx, MAXCOMPORTS ; max. COM ports = max. IRQ lines
sinit5:
cmp ShrdIRQ1[bx].si_irq, al ; IRQ line matches?
je sinit40 ; Y: update data structures
add bx, size SharedIntData ; N: increment index to next IRQ struc.
loop sinit5 ; and try again
; No ShrdIRQ structure has been setup yet for this IRQ line,
; so find the first empty ShrdIRQ structure and use it.
xor bx, bx ; re-init.
mov cx, MAXCOMPORTS ; re-init.
sinit10:
cmp ShrdIRQ1[bx].si_irq, 0 ; this entry is empty?
je sinit20 ; Y: initialize this entry
add bx, size SharedIntData ; N: increment index to next IRQ struc.
loop sinit10 ; and try again
mov byte ptr [si].int_sharing, 0 ; don't support int. sharing
jmp short sinit50
sinit20:
mov ShrdIRQ1[bx].si_irq, al ; store the IRQ line
mov ShrdIRQ1[bx].si_count, 0 ; initialize the total count value
sinit40:
inc ShrdIRQ1[bx].si_count ; total number of COMs on this IRQ line
mov [si].ci_int_data, bx ; save offset for use at open time
sinit50:
pop es
pop ds
popa
ret
EndProc InitSharedIRQ
;** OptimizeSharedIRQs - check the ShrdIRQData structures for
; unnecessary entries.
; OptimizeSharedIRQs - examines the ShrdIRQData structures that are in
; use. If the total COM port count for an IRQ line is equal to 1,
; then there is no reason to use the "shared" entry point in to
; the interrupt service routine. The "shared" entry points have
; a small amount of extra overhead for handling multiple COM ports
; on the same IRQ line. If, however, a COM port is not sharing
; its IRQ line with one or more other COM ports (instead, it is
; being shared with some other peripheral in the system), then
; there is no reason to use the "shared" entry point. The regular
; entry point for the COM port can be called directly, which
; saves on that small amount of overhead. When this routine finds a
; ShrdIRQData structure that has a value of 1, it sets the
; ci_mult_COMs_IRQ flag for that COM port to zero, so that at
; DosOpen time the regular interrupt entry point will be registered
; via DevHlp_SetIRQ.
;
; ENTRY none
;
; EXIT ComInfo structures updated if needed
;
; USES flags
Procedure OptimizeSharedIRQs,HYBRID
ASSUME cs:CSEG,ds:NOTHING,es:NOTHING,ss:NOTHING
pusha
push ds
setDS DSEG ; DSEG selector
xor bx,bx ; init. index
mov cx, MAXCOMPORTS ; examine all COM ports
optz5:
cmp word ptr Com1[bx], 0 ; Valid COM port?
je optz40 ; N: try the next one
mov si, word ptr Com1[bx] ; Y: load the offset
cmp [si].ci_mult_COMs_IRQ, INT_SHARING ; possibly sharing with
; another COM port?
jne optz40 ; N: go to next COM port
mov di, [si].ci_int_data ; Y: get offset of shared IRQ data
cmp ShrdIRQ1[di].si_count, 1 ; Only 1 COM port on this IRQ line?
jne optz40 ; N: No changes needed, go to next COM
mov [si].ci_mult_COMs_IRQ, 0 ; Y: indicate only 1 COM on this IRQ
optz40:
inc bx
inc bx ; next ComInfo offset in the array
loop optz5 ; and try again
optz50:
pop ds
popa
ret
EndProc OptimizeSharedIRQs
CSEG ENDS
RSEG SEGMENT
ASSUME cs:RSEG
;** Com1Strat - strategy entry point for COM1
;** Com2Strat - strategy entry point for COM2
;
; Com1Strat and Com2Strat are the entry points for the strategy
; routine for the asynch device driver. The strategy routine is
; called by the OS to handle device requests.
;
; ENTRY (es:bx) -> request packet
; (ds) HSEG segment for com01.sys
;
; EXIT none (doesn't come through here on exit)
;
; USES ax si
Procedure Com1Strat,FAR
ASSUME cs:RSEG,ds:HSEG,es:NOTHING,ss:NOTHING
IFDEF COMDEBUG
int 3
ENDIF
setDS DSEG
mov si,Com1 ; (ds:si) -> COM1 info
mov ax,Com1Minor
jmp ComStrat
Entry Com2Strat,,,nocheck
ASSUME cs:RSEG,ds:HSEG,es:NOTHING,ss:NOTHING
IFDEF COMDEBUG
int 3
ENDIF
setDS DSEG
mov si,Com2 ; (ds:si) -> COM2 info
mov ax,Com2Minor
jmp ComStrat
Entry Com3Strat,,,nocheck
IFDEF COMDEBUG
int 3
ENDIF
setDS DSEG
mov si,Com3 ; (ds:si) -> COM3 info
mov ax,Com3Minor
jmp ComStrat
Entry Com4Strat,,,nocheck
IFDEF COMDEBUG
int 3
ENDIF
setDS DSEG
mov si,Com4 ; (ds:si) -> COM4 info
mov ax,Com4Minor
jmp ComStrat
EndProc Com1Strat
;********************************************************************
;*
;* FUNCTION NAME : HIDC_Entry
;*
;* DESCRIPTION : Hardware DD IDC entry point.
;*
;* Route all IDC function requests.
;*
;* ENTRY POINT : COM1_IDC_Entry LINKAGE: CALL FAR
;*
;* INPUT : ES:BX = Segemrnt:Offset of IDC packet
;*
;* RETURN-NORMAL : Function performed, carry clear
;*
;* RETURN-ERROR : Function rejected, carry set.
;*
;* EFFECTS : Stack is clean on return. AX, CX, DX, SI, and DI
;* registers are changed.
;*
;* INTERNAL REFERENCES:
;* ROUTINES: Query_Config, Read_Enable, Read_Disable,
;* Enable_Device, Disable_Device
;*
;* EXTERNAL REFERENCES:
;* ROUTINES: NONE.
;* DevHlps: None.
;*
;********************************************************************
Procedure COM1_IDC_Entry,FAR
ASSUME cs:RSEG,ds:HSEG,es:NOTHING,ss:NOTHING
jmp IDC_Handler
Entry COM2_IDC_Entry,,,nocheck
jmp IDC_Handler
Entry COM3_IDC_Entry,,,nocheck
jmp IDC_Handler
Entry COM4_IDC_Entry,,,nocheck
jmp IDC_Handler
EndProc COM1_IDC_Entry
RSEG ENDS
END