Archival snapshot of the Virtual World Entertainment Tesla cockpit software, 1994-1996: MUNGA engine and L4 pod layer source (Borland C++ 5.0), BT/RP game code, and game content (models, audio, maps, gauges, Division renderer data). Includes third-party libraries: Division dVS/DPL graphics, HMI SOS audio, WATTCP networking. Files are preserved byte-for-byte (.gitattributes disables all line-ending conversion). README.md documents the layout, target hardware, and toolchain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2045 lines
62 KiB
NASM
2045 lines
62 KiB
NASM
;===========================================================================
|
|
; File: PCSPAK.asm
|
|
; Project: MUNGA
|
|
; Contents: PC serial packet driver
|
|
;---------------------------------------------------------------------------
|
|
; Date Who Modification
|
|
; -------- --- -----------------------------------------------------------
|
|
; 01/16/95 CPB Initial coding
|
|
;---------------------------------------------------------------------------
|
|
; Copyright (C) 1994, Virtual World Entertainment, Inc.
|
|
; All Rights reserved worldwide
|
|
; This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
|
|
;===========================================================================
|
|
|
|
include l4asm.inc
|
|
include pcserial.inc
|
|
include pcpic.inc
|
|
include pcdpmi.inc
|
|
|
|
;===========================================================================
|
|
;; Diagnostics flags
|
|
;===========================================================================
|
|
KEEP_HISTORY equ 0
|
|
DIE_ON_ERROR equ 1
|
|
DIE_ON_OVERFLOW equ 1
|
|
WATCH_IRQ equ 1
|
|
|
|
THE_WAY_IT_WAS equ 0
|
|
|
|
;===========================================================================
|
|
; Equates
|
|
;===========================================================================
|
|
if DIE_ON_ERROR
|
|
|
|
DISABLE_AND_DIE MACRO val ;debugging macro: crash to debugger
|
|
;--------------------------------------------------------------
|
|
; Disable UART interrupt
|
|
;--------------------------------------------------------------
|
|
mov dx,global_serial_port
|
|
RETRACT_MCR UART_MCR_IRQ+UART_MCR_RTS
|
|
; NOTE: from this point on, interrupts CANNOT occur from the UART.
|
|
;--------------------------------------------------------------
|
|
; Send non-specific EOI just in case we're in IRQ routine
|
|
;--------------------------------------------------------------
|
|
PIC_RESET_MASTER
|
|
;--------------------------------------------------------------
|
|
; Okay, NOW die.
|
|
;--------------------------------------------------------------
|
|
push eax ;save ax
|
|
push edx ;save dx
|
|
mov edx,0FFFFFFFFh ;crash loudly
|
|
mov eax,val
|
|
mov [edx],eax
|
|
ENDM
|
|
|
|
else
|
|
DISABLE_AND_DIE MACRO val
|
|
ENDM
|
|
|
|
endif
|
|
|
|
|
|
if WATCH_IRQ
|
|
|
|
IRQ_WATCH MACRO val
|
|
mov iThinkIRQIsOn,val
|
|
ENDM
|
|
|
|
IRQ_WATCH_ENTRY MACRO
|
|
push iThinkIRQIsOn
|
|
mov iThinkIRQIsOn,0
|
|
ENDM
|
|
|
|
IRQ_WATCH_EXIT MACRO
|
|
pop iThinkIRQIsOn
|
|
ENDM
|
|
|
|
else
|
|
|
|
IRQ_WATCH MACRO val
|
|
ENDM
|
|
|
|
IRQ_WATCH_ENTRY MACRO
|
|
ENDM
|
|
|
|
IRQ_WATCH_EXIT MACRO
|
|
ENDM
|
|
|
|
endif
|
|
|
|
TICK MACRO ;debugging macro: ticks the speaker
|
|
|
|
push dx
|
|
push ax
|
|
|
|
mov dx,061h
|
|
in al,dx
|
|
|
|
xor al,002h
|
|
out dx,al
|
|
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
xor al,002h
|
|
out dx,al
|
|
|
|
pop ax
|
|
pop dx
|
|
ENDM
|
|
|
|
SPKR_SET MACRO ;debugging macro
|
|
|
|
push dx
|
|
push ax
|
|
|
|
mov dx,061h
|
|
in al,dx
|
|
|
|
or al,002h
|
|
out dx,al
|
|
|
|
pop ax
|
|
pop dx
|
|
ENDM
|
|
|
|
SPKR_RESET MACRO ;debugging macro
|
|
|
|
push dx
|
|
push ax
|
|
|
|
mov dx,061h
|
|
in al,dx
|
|
|
|
and al,(NOT 002h)
|
|
out dx,al
|
|
|
|
pop ax
|
|
pop dx
|
|
ENDM
|
|
|
|
SPKR_TOGGLE MACRO ;debugging macro
|
|
|
|
push dx
|
|
push ax
|
|
|
|
mov dx,061h
|
|
in al,dx
|
|
|
|
xor al,002h
|
|
out dx,al
|
|
|
|
pop ax
|
|
pop dx
|
|
ENDM
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Command buffer equates
|
|
;
|
|
; WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING
|
|
; Any modifications to this structure MUST be
|
|
; reflected in L4PCSPAK.hpp!!
|
|
;
|
|
; BE ESPECIALLY CAREFUL IF 'BUFSIZE' IS CHANGED!
|
|
;
|
|
; WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING
|
|
;-------------------------------------------------------------------------
|
|
COMBUFSIZE EQU 512 ;;;1024 ;buffer size (must be power of 2)
|
|
;; was 256 before 7-13-95 cpb
|
|
COMBUF STRUC
|
|
head dw 0
|
|
tail dw 0
|
|
tempHead dw 0
|
|
tempTail dw 0
|
|
|
|
count dw 0
|
|
tempIn dw 0
|
|
tempOut dw 0
|
|
|
|
data db COMBUFSIZE dup (?)
|
|
COMBUF ENDS
|
|
|
|
;------------------------------------------------
|
|
; COM_INIT macro
|
|
; Initializes COMBUF structure
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; (none)
|
|
;------------------------------------------------
|
|
COM_INIT MACRO name ;enter with object pointer in esi
|
|
|
|
add esi,name ;;build COMBUF pointer in esi
|
|
|
|
mov head[esi],0
|
|
mov tempHead[esi],0
|
|
mov tempTail[esi],0
|
|
mov tail[esi],0
|
|
|
|
mov count[esi],0
|
|
mov tempIn[esi],0
|
|
mov tempOut[esi],0
|
|
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_PUT_AL macro
|
|
; 'Temporarily' puts character in AL into COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; ebx modified
|
|
;------------------------------------------------
|
|
COM_PUT_AL MACRO name
|
|
LOCAL label1
|
|
LOCAL label2
|
|
|
|
add esi,name ;;build COMBUF pointer in esi
|
|
|
|
cmp tempIn[esi],COMBUFSIZE
|
|
|
|
if DIE_ON_OVERFLOW
|
|
jb label1
|
|
DISABLE_AND_DIE 8
|
|
endif
|
|
jge label2
|
|
label1:
|
|
|
|
inc tempIn[esi] ;;increment 'tempIn' count
|
|
|
|
xor ebx,ebx ;;get 'tempHead' offset in ebx
|
|
mov bx,tempHead[esi]
|
|
add esi,ebx ;;add to base
|
|
mov data[esi],al ;;write the data
|
|
sub esi,ebx ;;restore COMBUF pointer
|
|
|
|
inc bx ;;bump 'tempHead'
|
|
and bx,COMBUFSIZE-1 ;;limit it
|
|
mov tempHead[esi],bx ;;save the new 'tempHead' offset
|
|
label2:
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_RESTORE_IN macro
|
|
; Discards characters 'temporarily' placed in COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; bx modified
|
|
;------------------------------------------------
|
|
COM_RESTORE_IN MACRO name
|
|
|
|
add esi,name ;;build COMBUF pointer in ecx
|
|
|
|
mov tempIn[esi],0 ;;clear the 'tempIn' count
|
|
|
|
mov bx,head[esi] ;;restore 'tempHead' index
|
|
mov tempHead[esi],bx
|
|
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_ACCEPT_IN macro
|
|
; Accepts characters 'temporarily' placed in COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; bx modified
|
|
;------------------------------------------------
|
|
COM_ACCEPT_IN MACRO name
|
|
|
|
add esi,name ;;build COMBUF pointer in ecx
|
|
|
|
xor bx,bx ;;prepare for exchange
|
|
xchg bx,tempIn[esi] ;;get, clear 'tempIn' count
|
|
add count[esi],bx ;;add to current count
|
|
|
|
mov bx,tempHead[esi] ;;set the new head offset
|
|
mov head[esi],bx
|
|
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_GET_AL macro
|
|
; 'Temporarily' gets character into AL from COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; ebx modified
|
|
;------------------------------------------------
|
|
COM_GET_AL MACRO name
|
|
|
|
add esi,name ;;build COMBUF pointer in ecx
|
|
|
|
inc tempOut[esi] ;;inc 'tempOut' count
|
|
|
|
xor ebx,ebx ;;get 'tempTail' offset in ebx
|
|
mov bx,tempTail[esi]
|
|
|
|
add esi,ebx ;;add to base
|
|
mov al,data[esi] ;;read the data
|
|
sub esi,ebx ;;restore COMBUF pointer
|
|
|
|
inc bx ;;bump 'tempTail'
|
|
and bx,COMBUFSIZE-1 ;;limit it
|
|
mov tempTail[esi],bx ;;save the new 'tempTail' offset
|
|
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_RESTORE_OUT macro
|
|
; Restores characters 'temporarily' removed from COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; bx modified
|
|
;------------------------------------------------
|
|
COM_RESTORE_OUT MACRO name
|
|
|
|
add esi,name ;;build COMBUF pointer in ecx
|
|
|
|
mov tempOut[esi],0 ;;clear the 'tempOut' count
|
|
|
|
mov bx,tail[esi] ;;restore 'tempTail' index
|
|
mov tempTail[esi],bx
|
|
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_ACCEPT_OUT macro
|
|
; Discards characters 'temporarily' removed from COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; bx modified
|
|
;------------------------------------------------
|
|
COM_ACCEPT_OUT MACRO name
|
|
|
|
add esi,name ;;build COMBUF pointer in ecx
|
|
|
|
xor ax,ax ;;prepare for exchange
|
|
xchg ax,tempOut[esi] ;;get, clear 'tempOut' count
|
|
sub count[esi],ax ;;subtract from current count
|
|
|
|
mov ax,tempTail[esi] ;;set the new tail offset
|
|
mov tail[esi],ax
|
|
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_EAT_PACKET macro
|
|
; Discards entire buffer item from COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; ebx = pointer to command length table
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; ax modified
|
|
;------------------------------------------------
|
|
COM_EAT_PACKET MACRO name
|
|
|
|
add esi,name ;;build COMBUF pointer in esi
|
|
|
|
push ebx
|
|
xor ebx,ebx ;;get 'tail' offset in ebx
|
|
mov bx,tail[esi]
|
|
add esi,ebx ;;add to base
|
|
mov al,data[esi] ;;read the packet command byte
|
|
sub esi,ebx ;;restore COMBUF pointer
|
|
pop ebx
|
|
|
|
and al,07fh ;;remove the MSB
|
|
xlatb ;;convert packet command to length
|
|
xor ah,ah ;;convert packet length to unsigned word
|
|
inc ax ;;include the command byte
|
|
sub count[esi],ax ;;subtract from count
|
|
|
|
add ax,tail[esi] ;;move the tail
|
|
and ax,COMBUFSIZE-1 ;;limit it
|
|
mov tail[esi],ax ;;save it
|
|
mov tempTail[esi],ax ;;set the new tempTail index
|
|
|
|
mov tempOut[esi],0 ;;clear the 'tempOut' count also
|
|
|
|
sub esi,name ;;restore esi
|
|
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_SPACE_IN macro
|
|
; Returns input bytes available in COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
; reg = register to use
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; ax contains number of bytes available
|
|
;------------------------------------------------
|
|
COM_SPACE_IN MACRO name,reg
|
|
|
|
add esi,name ;;build COMBUF pointer in ecx
|
|
mov reg,COMBUFSIZE
|
|
sub reg,count[esi]
|
|
sub reg,tempIn[esi]
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;------------------------------------------------
|
|
; COM_SPACE_OUT macro
|
|
; Returns output bytes available in COMBUF
|
|
;------------------------------------------------
|
|
; Enter:
|
|
; esi = pointer to object containing COMBUF
|
|
; name = offset to COMBUF within object
|
|
;------------------------------------------------
|
|
; Side effects:
|
|
; ax contains number of bytes available
|
|
;------------------------------------------------
|
|
COM_SPACE_OUT MACRO name
|
|
|
|
add esi,name ;;build COMBUF pointer in ecx
|
|
mov ax,count[esi]
|
|
sub ax,tempOut[esi]
|
|
sub esi,name ;;restore esi
|
|
ENDM
|
|
|
|
;-------------------------------------------------------------------------
|
|
; IRQ data equates
|
|
;-------------------------------------------------------------------------
|
|
|
|
IRQDATA STRUC
|
|
irqHandler dd ?
|
|
irqThis dd ?
|
|
|
|
irqOldOffset dd ? ;THE ORDER OF THESE TWO IS CRITICAL.
|
|
irqOldSelector dw ? ;See the interrupt handlers near the end.
|
|
|
|
irqPort dw ?
|
|
|
|
irqNum db ?
|
|
irqPICbit db ?
|
|
irqOldPICbits db ?
|
|
irqPadByte db ?
|
|
IRQDATA ENDS
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAK object equates
|
|
;
|
|
; WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING
|
|
; Any modifications to this structure MUST be
|
|
; reflected in PCSPAK.hh!!
|
|
; WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING
|
|
;-------------------------------------------------------------------------
|
|
|
|
TX_IDLE_STATE EQU 0
|
|
TX_RESTART_STATE EQU 1
|
|
TX_BODY_STATE EQU 2
|
|
TX_WAIT_STATE EQU 3
|
|
|
|
RX_IDLE_STATE EQU 0
|
|
RX_ACTIVE_STATE EQU 1
|
|
|
|
;
|
|
; Lower eight bits reserved for UART status
|
|
;
|
|
ERR_INIT EQU 0000000100000000b
|
|
TX_EARLY_ERR EQU 0000001000000000b
|
|
TX_ABANDON EQU 0000010000000000b
|
|
TX_RESTART EQU 0000100000000000b
|
|
TX_NAK EQU 0001000000000000b
|
|
RX_SEQ_ERR EQU 0010000000000000b
|
|
RX_BAD_CHECKSUM EQU 0100000000000000b
|
|
RX_COM_ERR EQU 1000000000000000b
|
|
|
|
TXMAXRESET EQU 3
|
|
TXMAXERROR EQU 3
|
|
TXMAXIDLE EQU 4
|
|
|
|
; 080h...0FBh ;command codes
|
|
MAX_COMMAND_CHAR EQU 0FBh ;largest command code allowed
|
|
ACK_CHAR EQU 0FCh
|
|
NAK_CHAR EQU 0FDh
|
|
RESTART_CHAR EQU 0FEh
|
|
IDLE_CHAR EQU 0FFh
|
|
|
|
RX_ACK_BIT EQU 00000001b
|
|
RX_NAK_BIT EQU 00000010b
|
|
|
|
PCSPAK STRUC
|
|
portBase dw ? ;base port address
|
|
ErrorValue dw ?
|
|
|
|
enabled db ? ;set if rx/tx enabled
|
|
txHoldOff db ?
|
|
txReply db ?
|
|
txState db ?
|
|
txCount db ?
|
|
txResetCount db ?
|
|
txErrorCount db ?
|
|
txIdleCount db ?
|
|
txChecksum db ?
|
|
txMaximum db ?
|
|
|
|
rxFlags db ?
|
|
rxState db ?
|
|
rxCount db ?
|
|
rxChecksum db ?
|
|
rxMaximum db ?
|
|
|
|
txTablePtr dd ?
|
|
rxTablePtr dd ?
|
|
|
|
intDataPtr dd ? ;pointer to IRQDATA structure
|
|
|
|
txBuf COMBUF <>
|
|
rxBuf COMBUF <>
|
|
PCSPAK ENDS
|
|
|
|
HISTORYSIZE equ 256
|
|
|
|
IRQ_EVENT equ 0
|
|
IRQ_EVENT_RX equ 1
|
|
IRQ_EVENT_TX equ 2
|
|
IRQ_EVENT_MSR equ 3
|
|
IRQ_EVENT_LSR equ 4
|
|
IRQ_EVENT_BOGUS equ 5
|
|
|
|
TX_EVENT_RESTART equ 10
|
|
TX_EVENT_ABANDON equ 11
|
|
TX_EVENT_DONE equ 12
|
|
TX_EVENT_ACK equ 13
|
|
TX_EVENT_NAK equ 14
|
|
TX_EVENT_EARLY equ 15
|
|
TX_EVENT_EMPTY equ 16
|
|
TX_EVENT_KICK equ 17
|
|
|
|
RX_EVENT_FULL equ 20
|
|
RX_EVENT_NOT_CMD equ 21
|
|
RX_EVENT_FULLBODY equ 22
|
|
RX_EVENT_NAK equ 23
|
|
RX_EVENT_CKSMERR equ 24
|
|
RX_EVENT_OK equ 25
|
|
|
|
if KEEP_HISTORY
|
|
|
|
SAVE_TX MACRO
|
|
LOCAL skip
|
|
|
|
push ax
|
|
push ebx
|
|
|
|
mov ebx,historyIndex
|
|
cmp ebx,HISTORYSIZE
|
|
jge skip
|
|
|
|
mov ah,01h
|
|
mov history[ebx],ax
|
|
add ebx,2
|
|
mov historyIndex,ebx
|
|
|
|
inc pcspakCharactersSent ;;keep a running count
|
|
skip:
|
|
pop ebx
|
|
pop ax
|
|
ENDM
|
|
|
|
SAVE_RX MACRO
|
|
LOCAL skip
|
|
|
|
push ax
|
|
push ebx
|
|
|
|
mov ebx,historyIndex
|
|
cmp ebx,HISTORYSIZE
|
|
jge skip
|
|
|
|
mov ah,02h
|
|
mov history[ebx],ax
|
|
add ebx,2
|
|
mov historyIndex,ebx
|
|
|
|
skip:
|
|
pop ebx
|
|
pop ax
|
|
ENDM
|
|
|
|
SAVE_EVENT MACRO marker
|
|
LOCAL skip
|
|
|
|
push ax
|
|
push ebx
|
|
|
|
mov ebx,historyIndex
|
|
cmp ebx,HISTORYSIZE
|
|
jge skip
|
|
|
|
mov ah,03h
|
|
mov al,marker
|
|
mov history[ebx],ax
|
|
add ebx,2
|
|
mov historyIndex,ebx
|
|
|
|
skip:
|
|
pop ebx
|
|
pop ax
|
|
ENDM
|
|
else
|
|
SAVE_TX MACRO
|
|
inc pcspakCharactersSent ;;keep a running count
|
|
ENDM
|
|
|
|
SAVE_RX MACRO
|
|
ENDM
|
|
|
|
SAVE_EVENT MACRO marker
|
|
ENDM
|
|
endif
|
|
|
|
;===========================================================================
|
|
; Data segment
|
|
;===========================================================================
|
|
BEGIN_DATA
|
|
|
|
data_selector dw ?
|
|
irq_com1 IRQDATA <IntCom1, 0,0,0,0,0,0,0,0>
|
|
irq_com2 IRQDATA <IntCom2, 0,0,0,0,0,0,0,0>
|
|
irq_com3 IRQDATA <IntCom3, 0,0,0,0,0,0,0,0>
|
|
irq_com4 IRQDATA <IntCom4, 0,0,0,0,0,0,0,0>
|
|
|
|
public historyIndex
|
|
historyIndex dd 0
|
|
|
|
public history
|
|
if KEEP_HISTORY
|
|
history dw HISTORYSIZE dup(0)
|
|
else
|
|
history dw 0
|
|
endif
|
|
|
|
public iThinkIRQIsOn
|
|
iThinkIRQIsOn dd 0
|
|
|
|
public pcspakCharactersSent
|
|
pcspakCharactersSent dd 0
|
|
|
|
public previousIMR,previousISR,previousIRR
|
|
previousIMR db 0
|
|
previousISR db 0
|
|
previousIRR db 0
|
|
|
|
public middleIMR,middleISR,middleIRR
|
|
middleIMR db 0
|
|
middleISR db 0
|
|
middleIRR db 0
|
|
|
|
public postIMR,postISR,postIRR
|
|
postIMR db 0
|
|
postISR db 0
|
|
postIRR db 0
|
|
|
|
public pcspakLSR,pcspakIER,pcspakIIR
|
|
pcspakLSR db 0
|
|
pcspakIER db 0
|
|
pcspakIIR db 0
|
|
|
|
|
|
|
|
global_serial_port dw 0
|
|
|
|
END_DATA
|
|
;===========================================================================
|
|
; Code segment
|
|
;===========================================================================
|
|
BEGIN_CODE
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKInit()
|
|
; Constructor for serial packet driver interface
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; init_this = pointer to object
|
|
; init_port = address of serial port
|
|
; init_irq_num = interrupt number
|
|
; init_rx_len = pointer to (byte) receive length table
|
|
; init_tx_len = pointer to (byte) transmit length table
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; 1 if ok,
|
|
; -1 if IRQ's all used,
|
|
; -2 if DPMI error,
|
|
; -3 if really weird bogus error,
|
|
; else IIR value
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKInit <ebx,ecx,edx,esi,edi,es>
|
|
|
|
ARG_DPTR init_this
|
|
ARG_WORD init_rate
|
|
ARG_WORD init_port
|
|
ARG_WORD init_irq_num
|
|
ARG_DPTR init_rx_len
|
|
ARG_WORD init_rx_count
|
|
ARG_DPTR init_tx_len
|
|
ARG_WORD init_tx_count
|
|
|
|
LOCAL_DWORD return_status
|
|
|
|
BUILD_STACK_FRAME
|
|
|
|
mov return_status,0 ;everything's OK
|
|
;--------------------------------------------------------------
|
|
; Save off the data selector so we can get it back later.
|
|
;--------------------------------------------------------------
|
|
; ...In flat mode, CS and DS overlap, but CS is write-protected
|
|
; and DS isn't. Therefore we can write DS to [data_selector]
|
|
; and read it back from CS later.
|
|
;--------------------------------------------------------------
|
|
mov [data_selector],ds
|
|
;--------------------------------------------------------------
|
|
; Disable interrupts
|
|
;--------------------------------------------------------------
|
|
DPMI_DISABLE_SAVE_INT ;pushes ax!
|
|
IRQ_WATCH 0
|
|
;--------------------------------------------------------------
|
|
; Point ESI at object data
|
|
;--------------------------------------------------------------
|
|
mov esi,init_this
|
|
;--------------------------------------------------------------
|
|
; Clear the data buffers
|
|
;--------------------------------------------------------------
|
|
COM_INIT rxBuf ;assumes esi points to object
|
|
COM_INIT txBuf ;assumes esi points to object
|
|
;--------------------------------------------------------------
|
|
; Initialize values
|
|
;--------------------------------------------------------------
|
|
xor eax,eax
|
|
mov enabled[esi],al ;clear 'enabled' flag
|
|
|
|
mov txHoldOff[esi],al ;flag as not held off
|
|
mov txReply[esi],al ;clear 'reply' char
|
|
mov rxFlags[esi],al ;clear receive flags (ack/nak)
|
|
mov ErrorValue[esi],ax ;clear errors
|
|
mov intDataPtr[esi],eax ;(flag as not allocated)
|
|
|
|
mov historyIndex,eax
|
|
|
|
mov al,TX_IDLE_STATE ;initialize to idle state
|
|
mov txState[esi],al
|
|
|
|
mov al,RX_IDLE_STATE ;initialize to idle state
|
|
mov rxState[esi],al
|
|
|
|
mov ax,init_port ;get the port address
|
|
mov portBase[esi],ax ;save it
|
|
|
|
mov eax,init_tx_len ;set dialect transmit table pointer
|
|
mov txTablePtr[esi],eax
|
|
|
|
mov ax,init_tx_count ;set maximum dialect transmit index
|
|
mov txMaximum[esi],al
|
|
|
|
mov eax,init_rx_len ;set dialect receive table pointer
|
|
mov rxTablePtr[esi],eax
|
|
|
|
mov ax,init_rx_count ;set maximum dialect receive index
|
|
mov rxMaximum[esi],al
|
|
;--------------------------------------------------------------
|
|
; Find unused IRQDATA structure
|
|
;--------------------------------------------------------------
|
|
mov ecx,4
|
|
mov edi,OFFSET irq_com1
|
|
searchLoop:
|
|
mov ax,irqPort[edi] ;is irqPort equal to zero?
|
|
je short searchDone ;yes, use this structure
|
|
add edi,SIZE IRQDATA ;no, move to next one
|
|
loop searchLoop
|
|
|
|
mov ErrorValue[esi],ERR_INIT ;allocation failed, set errors!
|
|
mov return_status,-1 ;return an error code
|
|
jmp allocFailed
|
|
|
|
searchDone:
|
|
mov ax,init_port ;save port address
|
|
mov irqPort[edi],ax
|
|
mov global_serial_port,ax ;save in case of crash
|
|
|
|
mov ax,init_irq_num ;save interrupt number
|
|
mov irqNum[edi],al
|
|
;--------------------------------------------------------------
|
|
; Save init_this in irq structure, irqPtr in "this" structure
|
|
;--------------------------------------------------------------
|
|
mov irqThis[edi],esi
|
|
mov intDataPtr[esi],edi
|
|
;--------------------------------------------------------------
|
|
; Save the old PROTECTED MODE interrupt vector
|
|
;--------------------------------------------------------------
|
|
mov bl,irqNum[edi] ;bl has interrupt number
|
|
DPMI_GET_PROT_VECTOR ;returns cx:edx
|
|
mov irqOldSelector[edi],cx
|
|
mov irqOldOffset[edi],edx
|
|
;--------------------------------------------------------------
|
|
; Set the new PROTECTED MODE interrupt vector
|
|
;--------------------------------------------------------------
|
|
mov bx,init_irq_num ;bl has interrupt number
|
|
mov cx,cs ;cx:edx has selector:offset
|
|
mov edx,irqHandler[edi]
|
|
DPMI_SET_PROT_VECTOR
|
|
jnc short allocOk ;carry clear, allocation succeeded
|
|
|
|
mov ErrorValue[esi],ERR_INIT ;allocation failed, set errors!
|
|
mov return_status,-2 ;return an error code
|
|
jmp allocFailed
|
|
allocOk:
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
; Diagnostics values
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
PIC_IMR_TO_AL
|
|
mov previousIMR,al
|
|
PIC_ISR_TO_AL
|
|
mov previousISR,al
|
|
PIC_IRR_TO_AL
|
|
mov previousIRR,al
|
|
;--------------------------------------------------------------
|
|
; Initialize PIC
|
|
;--------------------------------------------------------------
|
|
;-----------------------------
|
|
; Get master PIC data:
|
|
; enable bit in bl,
|
|
; interrupt number in bh
|
|
;-----------------------------
|
|
mov ax,init_irq_num ;get interrupt number
|
|
cmp ax,0000Ch ;COM1?
|
|
jnz short mustBeCom2 ;no, must be COM2
|
|
|
|
mov bl,PIC_COM1COM3 ;yes, get COM1, COM3 enable...
|
|
mov bh,OCW2_SPEC_EOI+4 ;...and PIC specific EOI
|
|
jmp short hasPicBits
|
|
|
|
mustBeCom2:
|
|
mov bl,PIC_COM2COM4 ;get COM2, COM4 enable...
|
|
mov bh,OCW2_SPEC_EOI+3 ;...and PIC specific EOI
|
|
hasPicBits:
|
|
mov irqPICbit[edi],bl ;save for termination
|
|
;-----------------------------
|
|
; Enable interrupts in PIC
|
|
;-----------------------------
|
|
ASSERT_PIC_REG bl
|
|
;-----------------------------
|
|
; Make sure PIC interrupt
|
|
; request is cleared
|
|
;-----------------------------
|
|
mov al,bh ;output the specific EOI
|
|
out PIC_MASTER_0,al
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
; Diagnostics values
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
PIC_IMR_TO_AL
|
|
mov middleIMR,al
|
|
PIC_ISR_TO_AL
|
|
mov middleISR,al
|
|
PIC_IRR_TO_AL
|
|
mov middleIRR,al
|
|
;--------------------------------------------------------------
|
|
; Initialize UART
|
|
;--------------------------------------------------------------
|
|
mov dx,init_port ;get port address from stack
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
; Diagnostics values
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
add dx,UART_IIR
|
|
in al,dx
|
|
mov pcspakIIR,al
|
|
sub dx,UART_IIR
|
|
;-----------------------------
|
|
; Disable UART interrupts
|
|
;-----------------------------
|
|
RETRACT_MCR UART_MCR_IRQ ;This clears irq into PIC
|
|
;-----------------------------
|
|
; Disable all UART interrupt
|
|
; sources. Not mandatory,
|
|
; but a safe practice.
|
|
;-----------------------------
|
|
RETRACT_IER UART_IER_ALL
|
|
;-----------------------------
|
|
; Set baud rate
|
|
; Side effect: the divisor
|
|
; latch access bit is cleared
|
|
;-----------------------------
|
|
mov cx,init_rate ;set data rate
|
|
SETBAUD_CX ;macro from PCSERIAL.INC
|
|
;-----------------------------
|
|
; Set data format:
|
|
; 8 data bits,
|
|
; 1 stop bit,
|
|
; no parity
|
|
; Side effect: the divisor
|
|
; latch access bit is cleared
|
|
;-----------------------------
|
|
mov al,UART_LCR_8+UART_LCR_S1+UART_LCR_NP
|
|
SETFORMAT_AL
|
|
|
|
|
|
;-----------------------------
|
|
; Enable UART interrupt sources
|
|
;-----------------------------
|
|
ASSERT_IER UART_IER_ALL
|
|
;-----------------------------
|
|
; Enable UART interrupts, RTS
|
|
;-----------------------------
|
|
ASSERT_MCR UART_MCR_IRQ+UART_MCR_RTS
|
|
;-----------------------------
|
|
; Clear UART interrupt sources
|
|
;-----------------------------
|
|
in al,dx ;clear receiver interrupt (read inputs)
|
|
in al,dx
|
|
|
|
;; mov al,IDLE_CHAR ; clear transmit interrupt
|
|
;; out dx,al
|
|
;; out dx,al
|
|
|
|
add dx,UART_MSR ;read modem status reg to clear IRQ
|
|
in al,dx ;discard the result
|
|
sub dx,UART_MSR
|
|
|
|
add dx,UART_LSR ;read line status reg to clear IRQ
|
|
in al,dx ;read value
|
|
mov pcspakLSR,al ;(save for diagnostics)
|
|
sub dx,UART_LSR
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
; Diagnostics values
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
add dx,UART_IER
|
|
in al,dx
|
|
mov pcspakIER,al
|
|
sub dx,UART_IER
|
|
|
|
PIC_IMR_TO_AL
|
|
mov postIMR,al
|
|
PIC_ISR_TO_AL
|
|
mov postISR,al
|
|
PIC_IRR_TO_AL
|
|
mov postIRR,al
|
|
;--------------------------------------------------------------
|
|
; Mark as 'enabled'
|
|
;--------------------------------------------------------------
|
|
mov enabled[esi],1
|
|
|
|
allocFailed:
|
|
;--------------------------------------------------------------
|
|
; Reenable the old interrupt state and return
|
|
;--------------------------------------------------------------
|
|
DPMI_RESTORE_PREV_INT ;pops ax!
|
|
IRQ_WATCH 1
|
|
|
|
mov eax,return_status
|
|
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKTerm()
|
|
; Destructor for serial packet interface
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; (this) = pointer to object
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; (nothing)
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKTerm <eax,ebx,ecx,edx,esi,edi>
|
|
|
|
ARG_DPTR term_this
|
|
BUILD_STACK_FRAME
|
|
|
|
;--------------------------------------------------------------
|
|
; Disable interrupts
|
|
;--------------------------------------------------------------
|
|
DPMI_DISABLE_SAVE_INT ;pushes ax!
|
|
IRQ_WATCH 0
|
|
;--------------------------------------------------------------
|
|
; Get "this" pointer
|
|
;--------------------------------------------------------------
|
|
mov esi,term_this
|
|
mov eax,esi ;is it NULL?
|
|
or eax,eax
|
|
jz short skipRestore ;OHMIGOSH!! EXIT!!!
|
|
;--------------------------------------------------------------
|
|
; Turn off RTS and interrupts
|
|
;--------------------------------------------------------------
|
|
mov dx,portBase[esi]
|
|
RETRACT_MCR UART_MCR_IRQ+UART_MCR_RTS
|
|
|
|
; NOTE: from this point on, interrupts CANNOT occur from the UART.
|
|
|
|
;--------------------------------------------------------------
|
|
; If improperly allocated, skip 'release'
|
|
;--------------------------------------------------------------
|
|
mov eax,intDataPtr[esi] ;get pointer to IRQ data
|
|
or eax,eax
|
|
jz short skipRestore ;null pointer, skip release
|
|
|
|
mov edi,eax ;place pointer in edi
|
|
;--------------------------------------------------------------
|
|
; Mark IRQDATA record as unused
|
|
;--------------------------------------------------------------
|
|
mov irqPort[edi],0
|
|
;--------------------------------------------------------------
|
|
; Restore the old PROTECTED MODE interrupt vector
|
|
;--------------------------------------------------------------
|
|
mov bl,irqNum[edi] ;bl has interrupt number
|
|
mov cx,irqOldSelector[edi] ;cx:edx has selector:offset
|
|
mov edx,irqOldOffset[edi]
|
|
DPMI_SET_PROT_VECTOR
|
|
;--------------------------------------------------------------
|
|
; Disable PIC channel
|
|
;--------------------------------------------------------------
|
|
mov bl,irqPICbit[edi] ;get our PIC bit
|
|
RETRACT_PIC bl ;no, turn it off
|
|
skipRestore:
|
|
;--------------------------------------------------------------
|
|
; Reenable the old interrupt state and return
|
|
;--------------------------------------------------------------
|
|
DPMI_RESTORE_PREV_INT ;pops ax!
|
|
IRQ_WATCH 1
|
|
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKReceive()
|
|
; Returns packet if available
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; rp_this = pointer to object
|
|
; Byte *destPtr = pointer to 128-byte destination buffer
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int packetSize (or zero if no packet available)
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKReceive <ebx,ecx,edx,esi,edi>
|
|
|
|
ARG_DPTR rp_this
|
|
ARG_DPTR rp_dest
|
|
BUILD_STACK_FRAME
|
|
|
|
;--------------------------------------------------------------
|
|
; Get "this" pointer
|
|
;--------------------------------------------------------------
|
|
mov esi,rp_this
|
|
mov eax,esi ;is it NULL?
|
|
or eax,eax
|
|
jz spr_done ;OHMIGOSH!! EXIT!!!
|
|
;--------------------------------------------------------------
|
|
; Skip if disabled
|
|
;--------------------------------------------------------------
|
|
mov al,enabled[esi] ;if disabled, don't even try
|
|
or al,al
|
|
jnz short recvOK
|
|
|
|
xor eax,eax
|
|
jmp spr_done
|
|
recvOK:
|
|
;--------------------------------------------------------------
|
|
; Check character count: non-zero indicates entire packet
|
|
;--------------------------------------------------------------
|
|
xor eax,eax ;clear top of eax
|
|
mov ax,rxBuf.count[esi] ;get # of characters in ax
|
|
or ax,ax ;empty?
|
|
jz spr_done ;yes, return zero
|
|
;;; ;--------------------------------------------------------------
|
|
;;; ; Disable interrupts
|
|
;;; ;--------------------------------------------------------------
|
|
;;; DPMI_DISABLE_INT
|
|
;;; IRQ_WATCH 0
|
|
;--------------------------------------------------------------
|
|
; Get buffer length
|
|
;--------------------------------------------------------------
|
|
mov edi,rp_dest ;get pointer to destination
|
|
cld ;make sure direction is ok
|
|
|
|
xor eax,eax ;clear top of ax
|
|
COM_GET_AL rxBuf ;get character into al
|
|
;--------------------------------------------------------------
|
|
; Verify first char is a valid command character
|
|
;--------------------------------------------------------------
|
|
test al,080h ;1st character = command (high bit set)?
|
|
jnz short sprOk
|
|
|
|
DISABLE_AND_DIE 9
|
|
xor eax,eax
|
|
jmp short spr_done
|
|
sprOk:
|
|
stosb ;save it
|
|
and al,07Fh ;remove MSB
|
|
mov ebx,rxTablePtr[esi] ;point bx at length table
|
|
xlatb ;translate into length
|
|
xor ecx,ecx ;set ecx from al
|
|
mov cl,al
|
|
mov edx,ecx ;save in edx
|
|
inc edx ;return at least one character
|
|
;--------------------------------------------------------------
|
|
; Transfer data from buffer
|
|
;--------------------------------------------------------------
|
|
or cx,cx ;if no additional characters, skip
|
|
jz short spr_skip
|
|
spr_loop:
|
|
COM_GET_AL rxBuf ;get character into al
|
|
stosb ;save in buffer
|
|
loop spr_loop
|
|
spr_skip:
|
|
COM_ACCEPT_OUT rxBuf ;accept all 'taken' characters
|
|
;;; ;--------------------------------------------------------------
|
|
;;; ; Reenable the old interrupt state
|
|
;;; ;--------------------------------------------------------------
|
|
;;; DPMI_RESTORE_PREV_INT ;pops ax!
|
|
;;; IRQ_WATCH 1
|
|
|
|
mov eax,edx ;place count in eax
|
|
;--------------------------------------------------------------
|
|
; Return count in eax
|
|
;--------------------------------------------------------------
|
|
spr_done:
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKSend()
|
|
; Transmits packet
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; sp_this = pointer to object
|
|
; Byte *sp_src = pointer to (up to) 128-byte source buffer
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; void
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKSend <eax,ebx,ecx,edx,esi,edi>
|
|
|
|
ARG_DPTR sp_this
|
|
ARG_DPTR sp_src
|
|
|
|
BUILD_STACK_FRAME
|
|
;--------------------------------------------------------------
|
|
; Get "this" pointer
|
|
;--------------------------------------------------------------
|
|
mov esi,sp_this
|
|
mov eax,esi ;is it NULL?
|
|
or eax,eax
|
|
jz sendSkip ;OHMIGOSH!! EXIT!!!
|
|
;--------------------------------------------------------------
|
|
; Wait for sufficient room
|
|
;--------------------------------------------------------------
|
|
mov al,enabled[esi] ;if disabled, don't even try
|
|
or al,al
|
|
jz sendSkip
|
|
|
|
;;; SET_LPT 5
|
|
|
|
mov edi,sp_src ;get pointer to source
|
|
mov al,[edi] ;get the command byte
|
|
and al,07Fh ;remove MSB
|
|
mov ebx,txTablePtr[esi] ;set ebx to point to length table
|
|
xlatb ;get the length in al
|
|
xor ecx,ecx ;move al to ecx
|
|
mov cl,al
|
|
inc cx ;add one for command byte
|
|
spt_wait:
|
|
COM_SPACE_IN txBuf,ax ;get buffer 'in' space
|
|
cmp ax,cx ;enough room?
|
|
jae spt_space ;yes, continue
|
|
|
|
DISABLE_AND_DIE 0
|
|
jmp short spt_wait
|
|
|
|
spt_space:
|
|
;--------------------------------------------------------------
|
|
; Disable interrupts
|
|
;--------------------------------------------------------------
|
|
DPMI_DISABLE_SAVE_INT ;pushes ax!
|
|
IRQ_WATCH 0
|
|
;--------------------------------------------------------------
|
|
; Copy data into tx buffer
|
|
;--------------------------------------------------------------
|
|
spt_loop:
|
|
mov al,[edi] ;get the byte
|
|
inc edi ;increment the source pointer
|
|
COM_PUT_AL txBuf ;place it in the buffer
|
|
loop spt_loop
|
|
|
|
COM_ACCEPT_IN txBuf ;accept all 'placed' characters
|
|
mov dx,portBase[esi] ;set dx to port base address
|
|
call StartSending ;attempt to start tx interrupt
|
|
;--------------------------------------------------------------
|
|
; Reenable the old interrupt state
|
|
;--------------------------------------------------------------
|
|
DPMI_RESTORE_PREV_INT ;pops ax!
|
|
IRQ_WATCH 1
|
|
|
|
;;; CLEAR_LPT 5
|
|
|
|
sendSkip:
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKActive()
|
|
; Returns transmitter 'active' state (=0 when all transmission is done).
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; pa_this = pointer to object
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int errors
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKActive <ebx,ecx,edx,esi>
|
|
|
|
ARG_DPTR pa_this
|
|
BUILD_STACK_FRAME
|
|
;--------------------------------------------------------------
|
|
; Get "this" pointer
|
|
;--------------------------------------------------------------
|
|
mov esi,pa_this
|
|
mov eax,esi ;is it NULL?
|
|
or eax,eax
|
|
jz short actNULL ;OHMIGOSH!! EXIT!!!
|
|
;--------------------------------------------------------------
|
|
; Get 'active' status
|
|
;
|
|
; The LSR register has two bits reflecting the
|
|
; transmitter state:
|
|
; THR = transmit holding register (1=empty)
|
|
; TSR = transmit serial register (1=empty)
|
|
;
|
|
; The transmission is completely finished when both of these
|
|
; bits are high.
|
|
;--------------------------------------------------------------
|
|
xor eax,eax ;clear top of eax
|
|
|
|
mov dx,portBase[esi] ;get the port base
|
|
add dx,UART_LSR ;get LSR
|
|
in al,dx
|
|
;;sub dx,UART_LSR ;we usually subtract, no need here
|
|
|
|
and al,UART_LSR_THR+UART_LSR_TSR ; remove all but THR,TSR
|
|
xor al,UART_LSR_THR+UART_LSR_TSR ; invert the bits
|
|
actNULL:
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKErrors()
|
|
; Returns error bits: zero indicates no errors.
|
|
; The error code is cleared by this call as well.
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; pe_this = pointer to object
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int errors
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKErrors <ebx,ecx,edx,esi>
|
|
|
|
ARG_DPTR pe_this
|
|
BUILD_STACK_FRAME
|
|
;--------------------------------------------------------------
|
|
; Get "this" pointer
|
|
;--------------------------------------------------------------
|
|
mov esi,pe_this
|
|
mov eax,esi ;is it NULL?
|
|
or eax,eax
|
|
jz short errNULL ;OHMIGOSH!! EXIT!!!
|
|
;--------------------------------------------------------------
|
|
; Get, clear error word
|
|
;--------------------------------------------------------------
|
|
mov ax,ErrorValue[esi] ;init error?
|
|
and ax,ERR_INIT
|
|
jnz short haveInitError ;yes, don't clear it
|
|
|
|
xor ax,ax ;no, go ahead and clear it
|
|
xchg ax,ErrorValue[esi]
|
|
haveInitError:
|
|
and eax,0FFFFh ;make sure top of eax is clear
|
|
errNULL:
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKIRQState()
|
|
; Returns IRQ state
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; (void)
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int state
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKIRQState <ebx,ecx,edx,esi>
|
|
|
|
BUILD_STACK_FRAME
|
|
|
|
DPMI_INT_STATE
|
|
and eax,0FFh ;make sure top of eax is clear
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKTestInstance()
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; (this) = pointer to object
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int True
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKTestInstance
|
|
mov eax,1
|
|
ret
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKIsSignatureBad()
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; (this) = pointer to object
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int False
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKIsSignatureBad
|
|
mov eax,0
|
|
ret
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKReceiveCount()
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; (this) = pointer to object
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int number of items in receive queue
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKReceiveCount <esi>
|
|
|
|
ARG_DPTR prc_this
|
|
BUILD_STACK_FRAME
|
|
|
|
mov esi,prc_this
|
|
xor eax,eax
|
|
mov ax,rxBuf.count[esi]
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKTransmitCount()
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; (this) = pointer to object
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int number of items in transmit queue
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKTransmitCount <esi>
|
|
|
|
ARG_DPTR ptc_this
|
|
BUILD_STACK_FRAME
|
|
|
|
mov esi,ptc_this
|
|
xor eax,eax
|
|
mov ax,txBuf.count[esi]
|
|
END_C_PROC
|
|
|
|
|
|
;-------------------------------------------------------------------------
|
|
; PCSPAKSetDTR()
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; (this) = pointer to object
|
|
; on = zero to retract DTR, non-zero to assert DTR
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; int number of items in transmit queue
|
|
;-------------------------------------------------------------------------
|
|
BEGIN_C_PROC PCSPAKSetDTR <esi>
|
|
|
|
ARG_DPTR sdtr_this
|
|
ARG_DWORD sdtr_on
|
|
BUILD_STACK_FRAME
|
|
;--------------------------------------------------------------
|
|
; Get "this" pointer
|
|
;--------------------------------------------------------------
|
|
mov esi,sdtr_this
|
|
mov eax,esi ;is it NULL?
|
|
or eax,eax
|
|
jz short sdtrExit ;OHMIGOSH!! EXIT!!!
|
|
|
|
mov dx,portBase[esi] ;get the port base
|
|
;--------------------------------------------------------------
|
|
; Get "on"
|
|
;--------------------------------------------------------------
|
|
cmp sdtr_on,0
|
|
je sdtrOff
|
|
;--------------------------------------------------------------
|
|
; Assert DTR
|
|
;--------------------------------------------------------------
|
|
ASSERT_MCR UART_MCR_DTR
|
|
jmp short sdtrExit
|
|
;--------------------------------------------------------------
|
|
; Retract DTR
|
|
;--------------------------------------------------------------
|
|
sdtrOff:
|
|
RETRACT_MCR UART_MCR_DTR
|
|
sdtrExit:
|
|
|
|
END_C_PROC
|
|
|
|
;-------------------------------------------------------------------------
|
|
; StartSending - attempt to start transmitter (if allowed)
|
|
; ...called from the receive interrupt routine and PCSPAK::sendPacket.
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; ESI = pointer to PCSPAK structure
|
|
; DX = UART base address
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; (void)
|
|
;-------------------------------------------------------------------------
|
|
; Side effects:
|
|
; Modifies register AL
|
|
;-------------------------------------------------------------------------
|
|
StartSending PROC NOLANGUAGE NEAR
|
|
|
|
add dx,UART_LSR ;get THR bit from LSR
|
|
in al,dx
|
|
sub dx,UART_LSR
|
|
|
|
test al,UART_LSR_THR ;is there anything in the holding reg?
|
|
jz sptNoKick ;yes, interrupt will occur later
|
|
|
|
SAVE_EVENT TX_EVENT_KICK
|
|
call SendChar ;restart transmitter
|
|
sptNoKick:
|
|
ret
|
|
StartSending ENDP
|
|
|
|
;-------------------------------------------------------------------------
|
|
; SendChar - send character through UART
|
|
; ...called from the interrupt routine and PCSPAK::sendCommand.
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; ESI = pointer to PCSPAK structure
|
|
; DX = UART base address
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; (void)
|
|
;-------------------------------------------------------------------------
|
|
; Side effects:
|
|
; registers EAX, EBX, ECX modified
|
|
;-------------------------------------------------------------------------
|
|
SendChar PROC NOLANGUAGE NEAR
|
|
;;; SET_LPT 6
|
|
|
|
;--------------------------------------------------------------
|
|
; Send reply character if one is waiting
|
|
;--------------------------------------------------------------
|
|
cmp txReply[esi],0 ;"reply" character waiting?
|
|
je noReply ;no, continue
|
|
|
|
xor al,al ;prepare for exchange
|
|
xchg al,txReply[esi] ;get and clear the "reply" character
|
|
out dx,al ;yes, send the reply character
|
|
SAVE_TX
|
|
jmp sendDone ;done for now.
|
|
noReply:
|
|
;--------------------------------------------------------------
|
|
; Enter the appropriate state handler
|
|
;--------------------------------------------------------------
|
|
mov al,txState[esi] ;get the transmit state
|
|
|
|
cmp al,TX_IDLE_STATE ;idle state?
|
|
je short txIdleState ;yes, go to it
|
|
|
|
cmp al,TX_BODY_STATE ;"body" state?
|
|
je txBodyState ;yes, go to it
|
|
|
|
cmp al,TX_WAIT_STATE ;"wait" state?
|
|
je txWaitState ;yes, go to it
|
|
|
|
cmp al,TX_RESTART_STATE ;restart state?
|
|
je short txRestartState ;yes, go to it
|
|
|
|
DISABLE_AND_DIE 1
|
|
jmp txWaitState ;must be "wait" state
|
|
;--------------------------------------------------------------
|
|
; Transmitter idle state
|
|
;--------------------------------------------------------------
|
|
txIdleState:
|
|
cmp txHoldOff[esi],0 ;If transmitter 'held off', do nothing
|
|
jne short txIsIdle
|
|
|
|
cmp txBuf.count[esi],0 ;input buffer available?
|
|
jne short txIdleAvail ;yes, send something
|
|
txIsIdle:
|
|
SAVE_EVENT TX_EVENT_EMPTY ;nothing to send, just return
|
|
jmp sendDone
|
|
|
|
txIdleAvail:
|
|
;---------------------------
|
|
; Buffer ready, start
|
|
;---------------------------
|
|
mov txResetCount[esi],TXMAXRESET ;set the 'reset' counter
|
|
mov txErrorCount[esi],TXMAXERROR ;set the 'error' counter
|
|
|
|
;...deliberately fall through into 'txRestartState'
|
|
|
|
;--------------------------------------------------------------
|
|
; Transmitter restart state
|
|
;--------------------------------------------------------------
|
|
txRestartState:
|
|
COM_GET_AL txBuf ;assumes esi points to object
|
|
|
|
cmp al,07Fh ;is it a command?
|
|
jbe short txRestartBad ;no, discard it
|
|
|
|
mov ah,al ;transfer to ah
|
|
and ah,07Fh ;remove MSB
|
|
cmp ah,txMaximum[esi] ;legitimate command?
|
|
jb short txRestartOk ;yes
|
|
|
|
txRestartBad:
|
|
DISABLE_AND_DIE 2
|
|
COM_ACCEPT_OUT txBuf ;eat the character
|
|
mov txState[esi],TX_IDLE_STATE ;move to the "idle" state
|
|
jmp sendDone
|
|
|
|
txRestartOk:
|
|
out dx,al ;transmit the command character
|
|
mov txChecksum[esi],al ;begin a new checksum count
|
|
SAVE_TX
|
|
|
|
mov al,ah ;move AND'ed value back to al
|
|
mov ebx,txTablePtr[esi] ;get length table pointer into ebx
|
|
xlatb ;look up length
|
|
inc al ;include the command byte
|
|
mov txCount[esi],al ;save the length
|
|
|
|
mov txState[esi],TX_BODY_STATE ;move to the "body" state
|
|
jmp sendDone
|
|
|
|
;--------------------------------------------------------------
|
|
; Transmitter "body" state
|
|
; Send message body, then checksum (unless interrupted by ACK/NAK)
|
|
;--------------------------------------------------------------
|
|
txBodyState:
|
|
;---------------------------
|
|
; Interrupted by ACK/NAK?
|
|
;---------------------------
|
|
cmp rxFlags[esi],0 ;flag set?
|
|
je txBodySend ;no, send normal body
|
|
|
|
COM_RESTORE_OUT txBuf ;interrupted, reset 'out' pointer
|
|
|
|
mov al,rxFlags[esi] ;get flags
|
|
mov rxFlags[esi],0 ;clear them
|
|
|
|
test al,RX_ACK_BIT ;was it an ACK?
|
|
jne short txBodyNak ;no
|
|
or ErrorValue[esi],TX_EARLY_ERR ;yes, set error flag
|
|
txBodyNak:
|
|
SAVE_EVENT TX_EVENT_EARLY
|
|
;---------------------------
|
|
; Restart or die
|
|
;---------------------------
|
|
dec txResetCount[esi] ;check the restart count
|
|
jl short txBodyGiveUp ;if too many errors, give up
|
|
;---------------------------
|
|
; Attempt restart
|
|
;---------------------------
|
|
mov al,RESTART_CHAR ;no, send restart character
|
|
out dx,al
|
|
SAVE_TX
|
|
|
|
mov txState[esi],TX_RESTART_STATE ;move to the "restart" state
|
|
jmp sendDone
|
|
;---------------------------
|
|
; Too many errors, die!
|
|
;---------------------------
|
|
txBodyGiveUp:
|
|
SAVE_EVENT TX_EVENT_ABANDON
|
|
or ErrorValue[esi],TX_ABANDON ;set error flag
|
|
mov ebx,txTablePtr[esi] ;get pointer to length table
|
|
COM_EAT_PACKET txBuf ;discard current packet
|
|
jmp txIdleState ;start another packet
|
|
;---------------------------
|
|
; Send body or checksum
|
|
;---------------------------
|
|
txBodySend:
|
|
dec txCount[esi] ;is buffer done?
|
|
jle txBodyCheck ;yes, send checksum
|
|
;---------------------------
|
|
; Send a body character
|
|
;---------------------------
|
|
COM_GET_AL txBuf ;get a character from the buffer
|
|
|
|
cmp al,07Fh ;legitimate body char?
|
|
jbe txBodyOk ;yes, continue
|
|
DISABLE_AND_DIE 3
|
|
and al,07Fh ;prevent bad data from becoming command
|
|
txBodyOk:
|
|
out dx,al ;send it
|
|
add txChecksum[esi],al ;add to the checksum
|
|
SAVE_TX
|
|
jmp sendDone
|
|
;---------------------------
|
|
; End of body, send checksum
|
|
;---------------------------
|
|
txBodyCheck:
|
|
mov al,txChecksum[esi] ;get the checksum
|
|
and al,07Fh ;limit it
|
|
out dx,al ;send it
|
|
SAVE_TX
|
|
SAVE_EVENT TX_EVENT_DONE
|
|
;---------------------------
|
|
; prepare for "wait" state
|
|
;---------------------------
|
|
mov txIdleCount[esi],TXMAXIDLE ;set the idle counter
|
|
mov txState[esi],TX_WAIT_STATE ;move to the "wait" state
|
|
jmp sendDone
|
|
|
|
;--------------------------------------------------------------
|
|
; Transmitter "wait" state
|
|
; Waits for reply from other end
|
|
;--------------------------------------------------------------
|
|
txWaitState:
|
|
xor al,al ;prepare to exchange flags
|
|
xchg al,rxFlags[esi] ;get flags, also clear them
|
|
or al,al ;flags clear?
|
|
jz txWaitMore ;yes, keep waiting
|
|
|
|
test al,RX_ACK_BIT ;ACK?
|
|
jz short txWaitNak ;no, process NAK
|
|
;---------------------------
|
|
; ACK, buffer received OK
|
|
;---------------------------
|
|
SAVE_EVENT TX_EVENT_ACK
|
|
COM_ACCEPT_OUT txBuf ;yes, good transmission. Discard packet.
|
|
mov txState[esi],TX_IDLE_STATE ;move to the "idle" state
|
|
jmp txIdleState ;start another buffer
|
|
;---------------------------
|
|
; NAK!
|
|
;---------------------------
|
|
txWaitNak:
|
|
SAVE_EVENT TX_EVENT_ACK
|
|
or ErrorValue[esi],TX_NAK ;set error flag
|
|
COM_RESTORE_OUT txBuf ;restore output pointers
|
|
|
|
dec txErrorCount[esi] ;check the error count
|
|
jl txWaitGiveUp ;if too many errors, give up
|
|
jmp txRestartState ;no, resend it
|
|
;---------------------------
|
|
; Keep waiting
|
|
;---------------------------
|
|
txWaitMore:
|
|
dec txIdleCount[esi] ;have we waited too long?
|
|
jl short txWaitDone ;yes, attempt to restart
|
|
|
|
mov al,IDLE_CHAR ;no, send idle character
|
|
out dx,al
|
|
SAVE_TX
|
|
jmp sendDone
|
|
;---------------------------
|
|
; Attempt restart
|
|
;---------------------------
|
|
txWaitDone:
|
|
SAVE_EVENT TX_EVENT_RESTART
|
|
or ErrorValue[esi],TX_RESTART ;set error flag
|
|
COM_RESTORE_OUT txBuf ;restore output pointers
|
|
|
|
dec txResetCount[esi] ;too many restarts?
|
|
jl short txWaitGiveUp ;yes, abandon buffer
|
|
|
|
mov al,RESTART_CHAR ;no, send restart character
|
|
out dx,al
|
|
SAVE_TX
|
|
|
|
mov txIdleCount[esi],TXMAXIDLE ;reset the idle counter
|
|
mov txState[esi],TX_RESTART_STATE ;move to the "idle" state
|
|
jmp short sendDone
|
|
;---------------------------
|
|
; Give up
|
|
;---------------------------
|
|
txWaitGiveUp:
|
|
SAVE_EVENT TX_EVENT_ABANDON
|
|
or ErrorValue[esi],TX_ABANDON ;set error flag
|
|
mov ebx,txTablePtr[esi] ;get pointer to length table
|
|
COM_EAT_PACKET txBuf ;discard the packet
|
|
mov txState[esi],TX_IDLE_STATE ;move to the "idle" state
|
|
jmp txIdleState ;start another packet
|
|
|
|
sendDone:
|
|
;;; CLEAR_LPT 6
|
|
|
|
ret
|
|
|
|
SendChar ENDP
|
|
|
|
;-------------------------------------------------------------------------
|
|
; RecvChar - receive character from UART
|
|
;-------------------------------------------------------------------------
|
|
; Enter:
|
|
; ESI = pointer to PCSPAK structure
|
|
; DX = UART base address
|
|
; AL = character
|
|
;-------------------------------------------------------------------------
|
|
; Returns:
|
|
; (void)
|
|
;-------------------------------------------------------------------------
|
|
; Side effects:
|
|
; registers EAX, EBX, ECX modified
|
|
;-------------------------------------------------------------------------
|
|
RecvChar PROC NOLANGUAGE NEAR
|
|
SAVE_RX
|
|
;--------------------------------------------------------------
|
|
; Process universal special characters: ACK, NAK, IDLE
|
|
;--------------------------------------------------------------
|
|
test al,080h ;MSB set?
|
|
jz short rcNotSpecial ;no, can't be special character
|
|
;------------------------------
|
|
; IDLE
|
|
;------------------------------
|
|
cmp al,IDLE_CHAR ;IDLE character?
|
|
jne short rcNotIdle ;no
|
|
jmp recvDone ;yes, ignore it
|
|
rcNotIdle:
|
|
;------------------------------
|
|
; ACK
|
|
;------------------------------
|
|
cmp al,ACK_CHAR ;ACK character?
|
|
jne short rcNotAck ;no
|
|
or rxFlags[esi],RX_ACK_BIT ;yes, flag for transmitter
|
|
jmp recvDone
|
|
rcNotAck:
|
|
;------------------------------
|
|
; NAK
|
|
;------------------------------
|
|
cmp al,NAK_CHAR ;NAK character?
|
|
jne short rcNotNak ;no
|
|
or rxFlags[esi],RX_NAK_BIT ;yes, flag for transmitter
|
|
jmp recvDone
|
|
rcNotNak:
|
|
rcNotSpecial:
|
|
;--------------------------------------------------------------
|
|
; Process state-dependent characters
|
|
;--------------------------------------------------------------
|
|
cmp rxState[esi],0 ;test the state
|
|
jne rxActive ;non-zero, so active
|
|
;--------------------------------------------------------------
|
|
; Receiver "idle" state
|
|
; Wait for command character
|
|
;--------------------------------------------------------------
|
|
test al,080h ;is it a control character?
|
|
jnz short rxIdleSpecial ;yes, process it
|
|
|
|
or ErrorValue[esi],RX_SEQ_ERR ;Not expecting data, so error.
|
|
jmp recvDone
|
|
|
|
rxIdleSpecial:
|
|
cmp al,RESTART_CHAR ;restart?
|
|
je recvDone ;yes, discard it
|
|
|
|
COM_SPACE_IN rxBuf,bx ;get remaining space
|
|
or bx,bx ;zero?
|
|
jnz short rxIdleSpace ;no, continue
|
|
|
|
SAVE_EVENT RX_EVENT_FULL
|
|
DISABLE_AND_DIE 4
|
|
or ErrorValue[esi],RX_COM_ERR ;error. Set flag.
|
|
jmp recvDone
|
|
|
|
rxIdleSpace:
|
|
mov ah,al ;move to ah for testing
|
|
and ah,07Fh ;remove MSB
|
|
cmp ah,rxMaximum[esi] ;legitimate command?
|
|
jb short rxIdleOk ;yes, continue
|
|
|
|
SAVE_EVENT RX_EVENT_NOT_CMD
|
|
DISABLE_AND_DIE 5
|
|
or ErrorValue[esi],RX_COM_ERR ;no.
|
|
jmp recvDone
|
|
rxIdleOk:
|
|
COM_PUT_AL rxBuf ;save command character in buffer
|
|
mov rxChecksum[esi],al ;start a new receive checksum
|
|
|
|
mov al,ah ;put ah back into al
|
|
mov ebx,rxTablePtr[esi] ;get length table pointer into ebx
|
|
xlatb ;look up length
|
|
inc al ;include the command byte
|
|
mov rxCount[esi],al ;save the length
|
|
|
|
mov rxState[esi],RX_ACTIVE_STATE ;change to "active" state
|
|
jmp recvDone
|
|
|
|
;--------------------------------------------------------------
|
|
; Receiver "active" state
|
|
; Place N characters into buffer, test checksum, and reply
|
|
;--------------------------------------------------------------
|
|
rxActive:
|
|
test al,080h ;control character?
|
|
jz short rxActiveData ;no, therefore data
|
|
|
|
or ErrorValue[esi],RX_SEQ_ERR ;yes, error. Set error flag
|
|
COM_RESTORE_IN rxBuf ;Discard received data
|
|
;------------------------------
|
|
; Process control char
|
|
;------------------------------
|
|
cmp al,RESTART_CHAR ;restart character?
|
|
je rxActiveAbandon ;yes, abandon received data
|
|
|
|
SAVE_EVENT RX_EVENT_NAK
|
|
mov al,NAK_CHAR ;error, tell transmitter to send NAK
|
|
jmp rxActiveReply
|
|
;------------------------------
|
|
; Process data
|
|
;------------------------------
|
|
rxActiveData:
|
|
dec rxCount[esi] ;check the receive count
|
|
jle rxActiveCheck ;if end of message, process checksum
|
|
;------------------------------
|
|
; Enough space in buffer?
|
|
;------------------------------
|
|
COM_SPACE_IN rxBuf,bx ;get remaining space
|
|
|
|
or bx,bx ;zero?
|
|
jnz short rxActiveSpace ;no, continue
|
|
|
|
SAVE_EVENT RX_EVENT_FULLBODY
|
|
DISABLE_AND_DIE 6 ;crash hard (if enabled)
|
|
or ErrorValue[esi],RX_COM_ERR ;error. Set flag.
|
|
COM_RESTORE_IN rxBuf ;Discard received data
|
|
jmp rxActiveAbandon ;give up on packet
|
|
|
|
rxActiveSpace:
|
|
;------------------------------
|
|
; Save data in buffer
|
|
;------------------------------
|
|
add rxChecksum[esi],al ;update the checksum
|
|
COM_PUT_AL rxBuf ;save the character
|
|
jmp recvDone
|
|
;------------------------------
|
|
; Test checksum
|
|
;------------------------------
|
|
rxActiveCheck:
|
|
mov bl,rxChecksum[esi] ;get the checksum
|
|
and bl,07Fh ;remove MSB
|
|
cmp al,bl ;checksum OK?
|
|
je short rxActiveOk ;yes!
|
|
;------------------------------
|
|
; Buffer error
|
|
;------------------------------
|
|
SAVE_EVENT RX_EVENT_CKSMERR
|
|
or ErrorValue[esi],RX_BAD_CHECKSUM ;error. Set flag.
|
|
COM_RESTORE_IN rxBuf ;Discard received data
|
|
mov al,NAK_CHAR ;tell transmitter to send NAK
|
|
jmp short rxActiveReply
|
|
;------------------------------
|
|
; Buffer OK
|
|
;------------------------------
|
|
rxActiveOk:
|
|
SAVE_EVENT RX_EVENT_OK
|
|
COM_ACCEPT_IN rxBuf ;accept the received data
|
|
mov al,ACK_CHAR ;tell transmitter to send ACK
|
|
|
|
rxActiveReply:
|
|
mov txReply[esi],al
|
|
call StartSending ;restart transmitter if needed
|
|
;------------------------------
|
|
; Return to inactive state
|
|
;------------------------------
|
|
rxActiveAbandon:
|
|
mov rxState[esi],RX_IDLE_STATE
|
|
recvDone:
|
|
ret
|
|
RecvChar ENDP
|
|
|
|
;-------------------------------------------------------------------------
|
|
; Interrupt handlers
|
|
;-------------------------------------------------------------------------
|
|
IntHandler PROC NOLANGUAGE NEAR
|
|
ASSUME cs:_TEXT
|
|
|
|
IntCom1:
|
|
pushad
|
|
mov edi,OFFSET irq_com1 ;point EDI at IRQDATA structure
|
|
call IntMain
|
|
popad
|
|
iret
|
|
;jmp cs:fword ptr [irq_com1.irqOldOffset]
|
|
IntCom2:
|
|
pushad
|
|
mov edi,OFFSET irq_com2 ;point EDI at IRQDATA structure
|
|
call IntMain
|
|
popad
|
|
iret
|
|
;jmp cs:fword ptr [irq_com2.irqOldOffset]
|
|
IntCom3:
|
|
pushad
|
|
mov edi,OFFSET irq_com3 ;point EDI at IRQDATA structure
|
|
call IntMain
|
|
popad
|
|
iret
|
|
;jmp cs:fword ptr [irq_com3.irqOldOffset]
|
|
IntCom4:
|
|
pushad
|
|
mov edi,OFFSET irq_com4 ;point EDI at IRQDATA structure
|
|
call IntMain
|
|
popad
|
|
iret
|
|
;jmp cs:fword ptr [irq_com4.irqOldOffset]
|
|
|
|
;--------------------------------------------------------------
|
|
; Serial interrupt handler main body
|
|
;--------------------------------------------------------------
|
|
IntMain:
|
|
push ds ;save registers
|
|
push es
|
|
mov ds,cs:[data_selector] ;get our DS
|
|
ASSUME ds:_DATA
|
|
|
|
IRQ_WATCH_ENTRY
|
|
;;; SPKR_SET ;*********************************************
|
|
|
|
SAVE_EVENT IRQ_EVENT
|
|
;--------------------------------------------------------------
|
|
; Get pointer to PCSPAK structure, UART base address
|
|
;--------------------------------------------------------------
|
|
mov esi,irqThis[edi]
|
|
mov dx,irqPort[edi]
|
|
;--------------------------------------------------------------
|
|
; Get status in al
|
|
;--------------------------------------------------------------
|
|
procLoop:
|
|
add dx,UART_IIR ;point to interrupt ident reg
|
|
in al,dx ;get interrupt source ID
|
|
sub dx,UART_IIR ;restore dx
|
|
;--------------------------------------------------------------
|
|
; Receive character
|
|
;--------------------------------------------------------------
|
|
cmp al,UART_IIR_RDR ;receiver ready?
|
|
jne short procNoRx ;no, skip it
|
|
|
|
in al,dx ;get character
|
|
call RecvChar ;process it
|
|
jmp short procLoop
|
|
procNoRx:
|
|
;--------------------------------------------------------------
|
|
; Send character
|
|
;--------------------------------------------------------------
|
|
cmp al,UART_IIR_THR ;transmitter ready?
|
|
jne short procNoTx ;no, skip it
|
|
|
|
call SendChar ;send a character if available
|
|
jmp short procLoop
|
|
procNoTx:
|
|
;--------------------------------------------------------------
|
|
; Process modem status register change
|
|
;
|
|
; We currently ignore it. We could someday implement
|
|
; DTR/CTS/... flow control here if we desire.
|
|
;--------------------------------------------------------------
|
|
cmp al,UART_IIR_MSR ;MSR change?
|
|
jne short procNoMSR ;no, skip it
|
|
|
|
SAVE_EVENT IRQ_EVENT_MSR
|
|
add dx,UART_MSR ;read modem status reg to clear IRQ
|
|
in al,dx ;discard the result
|
|
sub dx,UART_MSR
|
|
jmp procLoop
|
|
procNoMSR:
|
|
;--------------------------------------------------------------
|
|
; Process line status register change (error or break)
|
|
;--------------------------------------------------------------
|
|
cmp al,UART_IIR_LSR ;LSR change?
|
|
jne short procNoLSR ;no, skip it
|
|
|
|
SAVE_EVENT IRQ_EVENT_LSR
|
|
add dx,UART_LSR ;read line status reg to clear IRQ
|
|
in al,dx ;read value
|
|
sub dx,UART_LSR
|
|
|
|
and ax,UART_LSR_ERRS ;remove non-error bits
|
|
or ErrorValue[esi],ax ;OR with current error state
|
|
jmp procLoop
|
|
procNoLSR:
|
|
;--------------------------------------------------------------
|
|
; Check for UART done
|
|
;--------------------------------------------------------------
|
|
cmp al,001h ;if LSB is set, no interrupt
|
|
je short procDone
|
|
SAVE_EVENT IRQ_EVENT_BOGUS
|
|
DISABLE_AND_DIE 7 ;weird state, flag error
|
|
procDone:
|
|
;--------------------------------------------------------------
|
|
; PIC port write
|
|
; (allows future interrupts to occur)
|
|
;--------------------------------------------------------------
|
|
PIC_RESET_MASTER
|
|
;--------------------------------------------------------------
|
|
; Restore registers, return from SUBROUTINE (not interrupt!)
|
|
;--------------------------------------------------------------
|
|
IRQ_WATCH_EXIT
|
|
;;; SPKR_RESET ;*********************************************
|
|
|
|
pop es
|
|
pop ds
|
|
ret
|
|
|
|
IntHandler ENDP
|
|
|
|
END_CODE
|
|
|
|
END
|