1024 lines
36 KiB
NASM
1024 lines
36 KiB
NASM
title AS5PDD Epoc Serial physical device driver for the 16550
|
|
subttl Copyright Psion PLC 1993
|
|
name SYS$AS5
|
|
|
|
; VERSION DATE DESCRIPTION
|
|
; ------- -------- ---------------
|
|
; 1.0 08/12/94 Initial version
|
|
|
|
; Written by Jason December 1994
|
|
|
|
; Serial Driver for Epoc based around ASIC5
|
|
|
|
Sr5S3 = 0
|
|
Sr5S3a = 1
|
|
|
|
ifdef BUILDS3
|
|
Sr5S3 = 1
|
|
Sr5S3a = 0
|
|
BUILDHH equ 1
|
|
endif
|
|
|
|
if Sr5S3a
|
|
BUILDSB equ 1
|
|
endif
|
|
|
|
include ..\inc\epoc.inc
|
|
include ..\inc\epocser.inc
|
|
include ..\inc\epoclib.inc
|
|
include ..\inc\epocsibo.inc
|
|
include ..\srcs\ossibo.inc
|
|
include ..\srcs\ospack.inc
|
|
|
|
Sr5ChannelStruct struc
|
|
Sr5Open db ? ; Is the channel open
|
|
Sr5Ctrl db ? ; State of control lines
|
|
Sr5IntVector db ? ; The Vector number
|
|
Sr5Channel db ? ; Which channel are we
|
|
Sr5Mask db ? ; InterruptMask
|
|
Sr5Running db ? ; Are we running
|
|
Sr5IntRoutineVec dw ? ; Vector to Interrupt
|
|
Sr5Baud dw ? ; The baud rate
|
|
Sr5LddData dw ? ; Info from Ldd above
|
|
Sr5StatusInt dd ? ; Vectors in serial
|
|
Sr5RecvInt dd ? ; Above to be called
|
|
Sr5XmitInt dd ? ; On input/output
|
|
Sr5ClockEnable db ? ; Reason to stop
|
|
Sr5TheLines db ? ; State of the modem lines
|
|
Sr5ChannelStruct ends
|
|
|
|
A5Ent struc ; ASIC5 Read/Write
|
|
A5PortA db ? ; Port A R/W
|
|
A5PortB db ? ; Port B R/W
|
|
A5PortBMode db ? ; Inc/Mode
|
|
A5PortD db ? ; Port CD Write only
|
|
A5Swipe1 db ?
|
|
A5Swipe2 db ?
|
|
A5IntMask db ? ; Interrupt mask R/W
|
|
A5CtrlReg db ? ; IntType/Ctrl register
|
|
A5USR db ? ; UART Status/Ctrl
|
|
A5RHR db ? ; Receive/Transmit
|
|
A5BDLSB db ? ; Baud Rate write only
|
|
A5BDMSB db ? ; Baud Rate write only
|
|
A5MCR1Eoi db ? ; MCR shift register
|
|
A5MCRPresentEoi db ? ; Barcode data&ints
|
|
A5MCR2Eoi db ?
|
|
A5DUMMYF db ?
|
|
A5Ent ends
|
|
|
|
if Consumer
|
|
NumberOfChannels equ 1 ; S3 Single Channel
|
|
else
|
|
NumberOfChannels equ 3 ; HC,S3C Three Channel
|
|
endif
|
|
OsActivityMeter equ 158ch ; Activity Channel
|
|
StopTimeOut equ 1000 ; ~1s (1000ms) wait
|
|
|
|
S_RS232ON equ 00000001b ; RS232 on
|
|
S_RSTTLON equ 00000100b ; Line drivers on
|
|
S_CENTON equ 00010000b ; Line drivers enable
|
|
S_RXENB equ 00000001b ; Receive interrupt on
|
|
S_TXENB equ 00000010b ; Transmit interrupt on
|
|
S_TXEMPTY equ 00010000b ; transmit buffer empty
|
|
S_RXINT equ 00000001b ; Receive interrupt?
|
|
S_TXINT equ 00000010b ; transmit interrupt?
|
|
S_MDINT equ 00000100b ; Modem status interrupt
|
|
S_CTS equ 00000001b ; CTS
|
|
S_RTS equ 00000010b ; RTS
|
|
S_DCD equ 00000100b ; DCD
|
|
S_DSR equ 00000010b ; DCR
|
|
S_DTR equ 00000100b ; DTR
|
|
OVERRUN_ERROR equ 01000000b ; Character overrun
|
|
PARITY_ERROR equ 10000000b ; Parity error
|
|
S_PERIPHERALMODE equ 00000011b ; ASIC5 RS232 mode
|
|
S_UART_OFF equ 00000010b ; ASIC5 peripheral mode
|
|
|
|
dgroup group stack
|
|
assume ds:dgroup,es:dgroup,ss:dgroup
|
|
|
|
CodeSeg
|
|
|
|
ProcBegin@ OsAS5PDD
|
|
; ====================
|
|
|
|
dw PDDSignature
|
|
db 'TTY.SR5',0
|
|
dw (VectorEnd-Vector)/2
|
|
Vector:
|
|
dw OsAS5Install
|
|
dw OsAS5Remove
|
|
dw OsAS5Open
|
|
dw OsAS5Strategy
|
|
VectorEnd:
|
|
|
|
BaudRateTable dw -077fh,-04ffh,-0368h,-02cch,-027fh,-013fh
|
|
dw -009fh,-004fh,-0035h,-0030h,-0027h,-0019h
|
|
dw -0013h,-000ch,-0009h,-0004h
|
|
DataBitsTable db 0,2,4,6 ; 5,6,7,8 bits per char frame
|
|
ParityTable db 08h,18h,0h,0h ; Even,Odd,Mark,Space parity
|
|
|
|
Chan0 Sr5ChannelStruct <>
|
|
Chan1 Sr5ChannelStruct <>
|
|
Chan2 Sr5ChannelStruct <>
|
|
|
|
if Consumer
|
|
if Asic9
|
|
SetupTable dw offset AS5Int1
|
|
db HwIrq2Revector,mask A9MSlave
|
|
db SelectChannel5,(mask A9MClockEnable5 shr 8)
|
|
else
|
|
SetupTable dw offset AS5Int1
|
|
db HwIrq4Revector,mask Asic2Int
|
|
db SelectChannel7,(mask ClockEnable7 shr 8)
|
|
endif
|
|
else
|
|
if Asic9
|
|
SetupTable dw offset AS5Int1
|
|
db HwIrq4Revector,mask A9MExpIntA
|
|
db SelectChannel3,(mask A9MClockEnable3 shr 8)
|
|
dw offset AS5Int2
|
|
db HwIrq5Revector,mask A9MExpIntB
|
|
db SelectChannel4,(mask A9MClockEnable4 shr 8)
|
|
dw offset AS5Int3
|
|
db HwIrq2Revector,mask A9MSlave
|
|
db SelectChannel5,(mask A9MClockEnable5 shr 8)
|
|
else
|
|
SetupTable dw offset AS5Int1
|
|
db HwIrq3Revector,mask ExpIntLeftA
|
|
db ExpChannelLeftA,(mask ClockEnable6 shr 8)
|
|
dw offset AS5Int2
|
|
db HwIrq2Revector,mask ExpIntRightB
|
|
db ExpChannelRightB,(mask ClockEnable5 shr 8)
|
|
dw offset AS5Int3
|
|
db HwIrq4Revector,mask Asic2Int
|
|
db SelectChannel7,(mask ClockEnable7 shr 8)
|
|
endif
|
|
endif
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ OsAS5Install,far
|
|
; ============================
|
|
|
|
; Install the device driver
|
|
; Out: Carry clear -happy to install
|
|
|
|
cld ; Clear the channels
|
|
mov cx, NumberOfChannels ; and set up fixed
|
|
mov di, offset Chan0 ; parameters such
|
|
mov si, offset SetupTable ; as the interrupt
|
|
pushf ; vectors and masks
|
|
cli ; for each channel
|
|
push ds
|
|
mov ax, cs
|
|
mov ds, ax
|
|
ResetAllChannelsLoop:
|
|
mov [di].Sr5Open, 0 ; Channel not open
|
|
lodsw
|
|
mov [di].Sr5IntRoutineVec, ax ; Set the interrupt
|
|
lodsb ; handler to call
|
|
mov [di].Sr5IntVector, al ; Which Interrupt
|
|
lodsb
|
|
mov [di].Sr5Mask, al ; Mask for that
|
|
lodsb ; interrupt
|
|
mov [di].Sr5Channel, al ; Which Psion serial
|
|
lodsb ; channel
|
|
mov [di].Sr5ClockEnable, al ; Baud rate clocking
|
|
add di, size Sr5ChannelStruct ; enable
|
|
loop ResetAllChannelsLoop
|
|
pop ds
|
|
popf
|
|
AllChannelsOkay:
|
|
clc ; Returns with
|
|
ret ; Carry clear
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ OsAS5Remove,far
|
|
; ==========================
|
|
|
|
; Remove the device driver
|
|
; Out: Carry clear -happy to remove
|
|
; Carry set -we have an open channel and cant be removed.
|
|
|
|
xor ax, ax ; If we have a
|
|
or al, Chan0.Sr5Open ; channel Still open
|
|
or al, Chan1.Sr5Open ; then return a can't
|
|
or al, Chan2.Sr5Open ; do error else
|
|
jz AllChannelsOkay ; complete okay
|
|
mov ax, InUseErr
|
|
stc
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ OsAS5Open,far
|
|
; ========================
|
|
|
|
; Open a serial channel
|
|
; In: SS:SI is a pointer to the open Ent Structure
|
|
; Out: Carry clear, control block in BX
|
|
; Carry set, error in AX
|
|
|
|
cld
|
|
mov si, [si].OpenNamePtr ; Open the channel
|
|
mov al, [si+1] ; Get the channel
|
|
CharToFoldedChar ; Make Upper Case
|
|
cmp al, 'A' ; Indicator which is
|
|
jb ErrorInOpen ; Part of the name
|
|
sub al, 'A' ; Should be A,B,C
|
|
cmp al, NumberOfChannels
|
|
jae ErrorInOpen
|
|
xor ah, ah
|
|
mov bx, offset Chan0 ; What Channel are
|
|
cmp al, 1 ; We Openning
|
|
jb GotChan ; Pointer to Control
|
|
mov bx, offset Chan2 ; Block in bx
|
|
ja GotChan
|
|
mov bx, offset Chan1
|
|
GotChan:
|
|
mov al, 1
|
|
xchg al, cs:[bx].Sr5Open
|
|
cmp al, 0 ; Now try to Open
|
|
je OkayToOpen ; That channel
|
|
CantOpen:
|
|
mov ax, InUseErr
|
|
CantOpenDiffErr:
|
|
stc
|
|
ret
|
|
ErrorInOpen:
|
|
mov ax, NameErr
|
|
stc
|
|
ret
|
|
OkayToOpen:
|
|
xor al, al
|
|
mov cs:[bx].Sr5Running, al
|
|
mov cs:[bx].Sr5TheLines, al
|
|
mov cs:[bx].Sr5Ctrl, al
|
|
mov al, cs:[bx].Sr5Mask
|
|
HwGetChannel
|
|
jc CantOpenSoClose ; Check that we have
|
|
call CheckHardwarePresent ; The right Hardware
|
|
jnc OpenedOkay
|
|
mov al, cs:[bx].Sr5Mask
|
|
HwFreeChannel
|
|
CantOpenSoClose:
|
|
mov cs:[bx].Sr5Open, 0
|
|
mov ax, DeviceErr
|
|
jmp short CantOpenDiffErr ; Return with the
|
|
OpenedOkay: ; Offset of our
|
|
xor ax, ax ; Control Block
|
|
ret ; In bx
|
|
ProcEnd noret
|
|
|
|
AS5StrategyJumpTable label word
|
|
dw offset AS5Open ; Load Handler offsets
|
|
dw offset AS5Close ; Close the channel
|
|
dw offset AS5Start ; Start the channel
|
|
dw offset AS5Stop ; Stop the channel
|
|
dw offset AS5Set ; Does nothing
|
|
dw offset AS5Sense ; Returns chan status
|
|
dw offset AS5Control ; Drive the lines
|
|
dw offset AS5Enquire ; Returns baud rate
|
|
dw offset AS5Enable ; Begin Output
|
|
dw offset AS5SetHandlerCS ; Get Handler segments
|
|
|
|
ProcBegin@ OsAS5Strategy,far
|
|
; =============================
|
|
|
|
; Strategy functions entry point
|
|
; Warning! This can be called from within Interrupt
|
|
; In: vector number in AX + various data in other registers
|
|
; DS is OsDataGroup (and MUST be preserved)
|
|
; Out: DI is pointer to control block
|
|
; Old channel and flags on stack
|
|
|
|
cld
|
|
mov bx, sp
|
|
mov bx, ss:[bx+4]
|
|
mov bl, cs:[bx].Sr5Channel ; Select the correct
|
|
xchg bx, ax ; Output channel
|
|
pushf ; Then Call the right
|
|
cli ; Function to deal
|
|
HwSelectChannel ; With the strategy
|
|
mov ah, bh ; request
|
|
xor bh, bh
|
|
push ax ; Interrupts off
|
|
mov ax, di ; and flags are on
|
|
mov di, sp ; the stack
|
|
mov di, ss:[di+8]
|
|
jmp AS5StrategyJumpTable[bx]
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Open,far
|
|
; ======================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
|
|
mov cs:[di].Sr5LddData, cx ; Load the offsets of
|
|
mov word ptr cs:[di].Sr5StatusInt, ax ; the data send and
|
|
mov word ptr cs:[di].Sr5RecvInt, si ; recieve routines in
|
|
mov word ptr cs:[di].Sr5XmitInt, dx ; the Ldd above us
|
|
xor dx, dx ; DX=0 -We don't support
|
|
pop ax ; power management
|
|
HwSelectChannel ; Return the old
|
|
popf ; channel
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Close,far
|
|
; =======================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
|
|
and cs:[di].Sr5Open, 0 ; Close the Channel
|
|
mov al, cs:[di].Sr5Mask ; Free up our channel
|
|
HwFreeChannel ; And the Hardware
|
|
pop ax ; Channel
|
|
HwSelectChannel ; Return the old
|
|
popf ; channel
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Start,far
|
|
; =======================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
|
|
call CheckHardwareFromStart
|
|
mov dx, 0
|
|
jc CantStartSomethingWhichIsntThere
|
|
|
|
if Asic9
|
|
in ax, A9WControlExtraRW ; Start the S3s clock
|
|
or ah, cs:[di].Sr5ClockEnable ; Generator
|
|
out A9WControlExtraRW, ax
|
|
else
|
|
mov al, cs:[di].Sr5ClockEnable
|
|
HwSetA2Control2Bits
|
|
endif
|
|
|
|
mov al, SerialWriteSingle or A5USR ; Set the baud rate
|
|
SBUSY ; and other
|
|
SCONTOUT ; characteristics
|
|
mov al, cs:[di].Sr5Ctrl
|
|
SBUSY
|
|
SDATAOUT
|
|
mov al, SerialWriteSingle or A5BDLSB
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, byte ptr cs:[di].Sr5Baud
|
|
SBUSY
|
|
SDATAOUT
|
|
mov al, SerialWriteSingle or A5BDMSB
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, byte ptr cs:[di+1].Sr5Baud
|
|
SBUSY
|
|
SDATAOUT
|
|
|
|
call GetTheInterrupt ; Get the interrupt
|
|
xor cx, cx ; and clear down
|
|
call DriveRts ; the RTS line (DTR
|
|
; stays at the state
|
|
mov al, SerialWriteSingle or A5CtrlReg ; it was set)
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, (S_CENTON or S_RS232ON or S_RSTTLON)
|
|
SBUSY
|
|
SDATAOUT ; Switch on the line
|
|
mov cx, 8 ; 8 ms ; drivers and wait
|
|
pop dx ; for them to power up
|
|
call WaitTimer
|
|
push dx
|
|
mov ah, (S_RXENB or S_TXENB or S_MDINT) ; Start all interrupts
|
|
call EnableTheInterrupt
|
|
mov cs:[di].Sr5Running, 1
|
|
mov bx, Asic5SerialCurrent
|
|
HwSetPCurrent
|
|
call Status
|
|
CantStartSomethingWhichIsntThere:
|
|
pop ax ; Return the old
|
|
HwSelectChannel ; channel
|
|
popf
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Stop,far
|
|
; =======================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
|
|
|
|
xor cx, cx ; Clear the state of
|
|
call DriveRts ; the modem lines
|
|
mov al, SerialReadSingle or A5IntMask ; Stop all of the
|
|
SBUSY ; interrupts
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
and al, not (S_TXENB or S_RXENB or S_MDINT)
|
|
mov ah, al
|
|
mov al, SerialWriteSingle or A5IntMask
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, ah
|
|
SBUSY
|
|
SDATAOUT
|
|
pop dx
|
|
cmp dh, DevHoldPowerFail
|
|
je DontStopHardware
|
|
cmp cs:[di].Sr5Running, 1
|
|
jne DontWait
|
|
mov cx, StopTimeOut
|
|
jmp short CompareNow
|
|
WaitForEmpty:
|
|
call TickTimer
|
|
CompareNow:
|
|
mov al, SerialReadSingle or A5USR
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
test al, S_TXEMPTY
|
|
loopne WaitForEmpty
|
|
DontWait:
|
|
cmp bh,DevHoldNormal
|
|
je DontStopHardware
|
|
|
|
if Asic9
|
|
mov cl, cs:[di].Sr5ClockEnable ; Turn off baud rate
|
|
not cl ; clocking from the
|
|
in ax, A9WControlExtraRW ; S3/3a
|
|
and ah, cl
|
|
out A9WControlExtraRW, ax
|
|
else
|
|
mov al, cs:[di].Sr5ClockEnable
|
|
HwClearA2Control2Bits
|
|
endif
|
|
mov al, SerialWriteSingle or A5CtrlReg ; Stop the drivers
|
|
SBUSY ; and stuff
|
|
SCONTOUT
|
|
sub al, al ; clear S_CENTON,
|
|
SBUSY ; S_RS232ON, S_RSTTLON
|
|
SDATAOUT
|
|
DontStopHardware:
|
|
mov al, dl ; Return the old
|
|
HwSelectChannel ; channel
|
|
popf
|
|
xor bx, bx
|
|
HwSetPCurrent
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Set,far
|
|
; =====================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
; In: Information required is on the stack
|
|
|
|
pop ax ; Return the old
|
|
HwSelectChannel ; channel
|
|
popf
|
|
mov ah, ss:[si].SerialCharTbaud ; Set the Recieve,
|
|
cmp ah, ss:[si].SerialCharRbaud ; Transmit characteristics
|
|
jnz ErrorInSet ; First set the Baud
|
|
cmp ah, P_BAUD_50 ; Rate
|
|
jb ErrorInSet
|
|
cmp ah, P_BAUD_19200
|
|
ja ErrorInSet
|
|
GotTheSpecialBaud:
|
|
dec ah
|
|
mov cl, ss:[si].SerialCharFrame ; Then the number of
|
|
mov al, ss:[si].SerialCharParity ; Stop bits
|
|
dec al
|
|
xor ch, ch
|
|
push bx
|
|
test cl, P_TWOSTOP
|
|
jz OnlyOneStopBit
|
|
or ch, 020h
|
|
OnlyOneStopBit:
|
|
test cl, P_PARITY ; The Parity
|
|
jz NoParity
|
|
mov bx, offset ParityTable
|
|
xlat cs:[ParityTable]
|
|
or ch, al
|
|
NoParity:
|
|
mov bx, offset DataBitsTable ; And finally the
|
|
and cl, P_DATA_FRM ; Number of data bits
|
|
mov al, cl ; Per frame
|
|
xlat cs:[DataBitsTable]
|
|
or ch, al
|
|
mov bx, offset BaudRateTable
|
|
mov al, ah
|
|
xor ah, ah
|
|
shl ax, 1
|
|
add bx, ax
|
|
mov ax, cs:[bx]
|
|
pop bx
|
|
mov cs:[di].Sr5Ctrl, ch
|
|
mov cs:[di].Sr5Baud, ax
|
|
xor al, al
|
|
ret
|
|
ErrorInSet:
|
|
mov al, NotSupportedErr
|
|
stc
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Sense,far
|
|
; =======================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
; Out: The state of the DCD,CTS,DSR lines returned in DX
|
|
|
|
call Status
|
|
pop ax ; Return the old
|
|
HwSelectChannel ; channel
|
|
popf
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ Status
|
|
; =================
|
|
|
|
; Out: State of modem lines in DX
|
|
|
|
mov al, SerialReadSingle or A5USR ; Get the current
|
|
SBUSY ; Modem status
|
|
SCONTOUT ; Lines and return
|
|
XNOP ; With the result
|
|
SBUSY ; In dx
|
|
SDATAIN
|
|
and al, (S_CTS or S_DSR or S_DCD) ; Get the lines we want
|
|
xor al, (S_CTS or S_DSR or S_DCD) ; Invert signals
|
|
xor ah, ah
|
|
mov dx, ax
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Control,far
|
|
; =========================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
; In: Lines to drive and state to drive them in DX
|
|
|
|
mov cl, dl ; Set the state of one
|
|
test dh, P_SRCTRL_DTR ; of the modem Lines
|
|
jz DriveRtsNow ; DH is the line to
|
|
call DriveDtr ; Drive and DL is the
|
|
pop ax ; State to drive it to
|
|
HwSelectChannel ; Return the old
|
|
popf ; channel
|
|
ret
|
|
DriveRtsNow:
|
|
call DriveRts
|
|
pop ax ; Return the old
|
|
HwSelectChannel ; channel
|
|
popf
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ DriveDtr
|
|
; ===================
|
|
|
|
mov ah, S_DTR ; Set/Reset the DTR
|
|
jmp short DriveTheLine ; Line
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ DriveRts
|
|
; ===================
|
|
|
|
mov ah, S_RTS ; Set/Reset RTS
|
|
DriveTheLine:
|
|
mov al, SerialWriteSingle or A5PortD ; Common code to set
|
|
SBUSY ; and reset either
|
|
SCONTOUT ; line while
|
|
mov al, cs:[di].Sr5TheLines ; preserving the
|
|
test cl, cl ; states of the other
|
|
jz ClearLine ; lines
|
|
or al, ah
|
|
jmp DoTheOutput
|
|
ClearLine:
|
|
not ah
|
|
and al, ah
|
|
DoTheOutput:
|
|
mov cs:[di].Sr5TheLines, al
|
|
SBUSY
|
|
SDATAOUT
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Enquire,far
|
|
; =========================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
; Out: DX,AX are the supported baud rates AX for 50 to 19200 DX for above
|
|
; CX says what data bits, parity, etc we support
|
|
|
|
pop ax ; Return the old
|
|
HwSelectChannel ; channel
|
|
popf
|
|
if Asic9
|
|
mov ax, -1
|
|
else
|
|
mov ax, 07fffh
|
|
endif
|
|
xor dx, dx
|
|
mov cx, (0ffffh AND (NOT (P_SRINQ_SPLIT OR P_SRINQ_PARSPACE OR P_SRINQ_PARMARK)))
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Enable,far
|
|
; ========================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
|
|
mov ah, S_TXENB ; Begin Output by
|
|
call EnableTheInterrupt ; enabling transmit
|
|
pop ax ; interrupts
|
|
HwSelectChannel ; Return the old
|
|
popf ; channel
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5SetHandlerCS,far
|
|
; ==============================
|
|
|
|
; Old channel and flags on the stack, interrupts off
|
|
; CX is CS of above LDD
|
|
|
|
mov word ptr cs:[di].(Sr5StatusInt+2), cx ; Load the Segment
|
|
mov word ptr cs:[di].(Sr5RecvInt+2), cx ; Within which the
|
|
mov word ptr cs:[di].(Sr5XmitInt+2), cx ; The Ldd above us
|
|
pop ax ; Return the old
|
|
HwSelectChannel ; channel
|
|
popf ; Resides
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Int3,far
|
|
; ======================
|
|
|
|
mov di, offset Chan2 ; Channel 3 interrupt
|
|
mov ax, PortCActive ; vector
|
|
jmp ComInt ; Jumps to Comint
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Int2,far
|
|
; ======================
|
|
|
|
mov di, offset Chan1 ; Channel 2 interrupt
|
|
mov ax, PortBActive ; vector
|
|
jmp ComInt ; Jumps to Comint
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ AS5Int1,far
|
|
; ======================
|
|
|
|
mov di,offset Chan0 ; Channel 1 interrupt
|
|
mov ax,PortAActive ; vector
|
|
; FALL THROUGH ; Falls through
|
|
ProcEnd noret ; to Comint
|
|
|
|
ProcBegin@ ComInt,far
|
|
; =====================
|
|
|
|
; The common interrupt handler
|
|
; DS points to OS data space
|
|
; DI is our control block
|
|
; AX is the Active channel
|
|
|
|
if S3b or S3c
|
|
or ds:[OsActivityMeter], ax ; Set active state
|
|
endif
|
|
mov al, cs:[di].Sr5Channel ; Select our
|
|
HwSelectChannel ; channel
|
|
push ax
|
|
mov bx, cs:[di].Sr5LddData ; Data for LDD above
|
|
TheInterruptLoop: ; in bx
|
|
mov al, SerialReadSingle or A5CtrlReg ; Find out what
|
|
SBUSY ; caused the
|
|
SCONTOUT ; interrupt
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
test al, al
|
|
je NothingToDo
|
|
HaveWeGotAModemStatusLineInterrupt:
|
|
test al, S_MDINT
|
|
jz HaveWeGotARecieveInterrupt
|
|
mov al, SerialReadSingle or A5USR
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
test al, (OVERRUN_ERROR or PARITY_ERROR)
|
|
jz ModemStatusInterruptOnly
|
|
push ax ; Something has been
|
|
mov ah, SERPARITY_ERR ; recieved in error
|
|
test al, PARITY_ERROR
|
|
jnz IsAParityError ; Establish the error
|
|
mov ah, SEROVERRUN_ERR
|
|
IsAParityError:
|
|
mov al, SerialReadSingle or A5RHR ; Get the character
|
|
SBUSY ; in question
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
push di
|
|
call dword ptr cs:[di].Sr5RecvInt
|
|
pop di
|
|
pop ax
|
|
ModemStatusInterruptOnly:
|
|
and ax, (S_CTS or S_DSR or S_DCD)
|
|
xor al, (S_CTS or S_DSR or S_DCD) ; invert signals
|
|
mov dx, ax
|
|
push di
|
|
call dword ptr cs:[di].Sr5StatusInt
|
|
pop di
|
|
jmp short TheInterruptLoop
|
|
HaveWeGotARecieveInterrupt:
|
|
test al, S_RXINT
|
|
jz HaveWeGotATransmitInterrupt
|
|
mov al, SerialReadSingle or A5RHR
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
xor ah, ah ; AX has character received
|
|
push di
|
|
call dword ptr cs:[di].Sr5RecvInt
|
|
pop di
|
|
jmp short TheInterruptLoop
|
|
HaveWeGotATransmitInterrupt:
|
|
test al, S_TXINT
|
|
jz NothingToDo
|
|
push di
|
|
call dword ptr cs:[di].Sr5XmitInt
|
|
pop di
|
|
test ax, ax ; -1 if disable
|
|
js DisableTransmitInts
|
|
mov ah, al
|
|
mov al, SerialWriteSingle or A5RHR
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, ah
|
|
SBUSY
|
|
SDATAOUT
|
|
jmp TheInterruptLoop
|
|
NothingToDo:
|
|
if Asic9
|
|
out A9BNonSpecificEoiW,al
|
|
else
|
|
out A1NonSpecificEoi, al
|
|
endif
|
|
pop ax
|
|
HwSelectChannel
|
|
clc ; Resced if neccessary
|
|
ret
|
|
DisableTransmitInts: ; disable TX interrupts
|
|
mov al, SerialReadSingle or A5IntMask
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
and al, not S_TXENB
|
|
mov ah, al
|
|
mov al, SerialWriteSingle or A5IntMask
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, ah
|
|
SBUSY
|
|
SDATAOUT
|
|
jmp TheInterruptLoop
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ GetTheInterrupt
|
|
; ==========================
|
|
|
|
mov al, cs:[di].Sr5IntVector ; Load the address of
|
|
mov cx, cs ; the appropriate
|
|
mov bx, cs:[di].Sr5IntRoutineVec ; interrupt routine
|
|
GenSetRevector ; into the correct
|
|
ret ; vector
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ EnableTheInterrupt
|
|
; =============================
|
|
|
|
mov al, SerialReadSingle or A5IntMask
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
or ah, al
|
|
mov al, SerialWriteSingle or A5IntMask
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, ah
|
|
SBUSY
|
|
SDATAOUT
|
|
if Asic9
|
|
in al,A9BInterruptMaskRW ; Set the mask
|
|
or al, cs:[di].Sr5Mask ; to enable Interrupts
|
|
out A9BInterruptMaskRW,al
|
|
else
|
|
in al, A1InterruptMask
|
|
or al, cs:[di].Sr5Mask
|
|
out A1InterruptMask, al
|
|
endif
|
|
ret
|
|
ProcEnd noret
|
|
|
|
|
|
ProcBegin@ StopInterrupts
|
|
; =========================
|
|
|
|
mov al, SerialReadSingle or A5IntMask ; Stop interrupts
|
|
SBUSY ; from Asic5
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
and al, not (S_RXENB or S_TXENB or S_MDINT)
|
|
mov ah, al
|
|
mov al, SerialWriteSingle or A5IntMask
|
|
SBUSY
|
|
SCONTOUT
|
|
mov al, ah
|
|
SBUSY
|
|
SDATAOUT
|
|
|
|
mov ah, cs:[di].Sr5Mask
|
|
not ah
|
|
if Asic9
|
|
in al,A9BInterruptMaskRW ; Stop Interrupts
|
|
and al,ah ; By clearing the
|
|
out A9BInterruptMaskRW,al ; Mask and resetting
|
|
else ; The Vector
|
|
in al, A1InterruptMask
|
|
and al,ah
|
|
out A1InterruptMask, al
|
|
endif
|
|
|
|
mov al, cs:[di].Sr5IntVector
|
|
GenResetRevector
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ CheckHardwarePresent
|
|
; ===============================
|
|
|
|
pushf
|
|
cli
|
|
mov al, cs:[bx].Sr5Channel ; Check that the
|
|
HwSelectChannel ; Harware is there
|
|
HwNullFrame ; And that it is what
|
|
mov al,(SerialSelect or Asic5NormalId) ; It should be
|
|
SBUSY ; First look for An
|
|
SCONTOUT ; ASIC4 at the other
|
|
XNOP ; End of the link
|
|
SBUSY
|
|
SDATAIN
|
|
test al,al
|
|
je ConnectionFailed
|
|
GotConnection:
|
|
popf
|
|
clc
|
|
ret
|
|
ConnectionFailed:
|
|
mov al, SerialSelect or Asic4Id ; Asic4 Id
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
test al, al
|
|
jne ConnectionFailedExit
|
|
mov al, SerialSelect or Asic8Id ; Modem chip Id
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
test al, al
|
|
jne ConnectionFailedExit
|
|
mov al, SerialSelect or Asic5PackId ; Asic5pack Id
|
|
SBUSY
|
|
SCONTOUT
|
|
XNOP
|
|
SBUSY
|
|
SDATAIN
|
|
ConnectionFailedExit:
|
|
popf
|
|
stc
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ CheckHardwareFromStart
|
|
; =================================
|
|
|
|
pushf
|
|
HwNullFrame ; Check that the
|
|
mov al,(SerialSelect or Asic5NormalId) ; Harware is there
|
|
SBUSY ; First look for An
|
|
SCONTOUT ; ASIC5 at the other
|
|
XNOP ; End of the link
|
|
SBUSY
|
|
SDATAIN
|
|
test al,al
|
|
je ConnectionFailed ; If not a 3link or
|
|
test al, mask A5MultiDrop ; if in multidrop
|
|
jne ConnectionFailedExit ; mode then we are
|
|
popf ; in trouble
|
|
mov al, SerialWriteSingle or A5PortBMode
|
|
SBUSY
|
|
SCONTOUT ; Put the 3Link in
|
|
mov al, S_PERIPHERALMODE ; peripheral mode
|
|
SBUSY
|
|
SDATAOUT
|
|
clc
|
|
ret
|
|
ProcEnd noret
|
|
|
|
ProcBegin@ WaitTimer
|
|
; ====================
|
|
|
|
; In: CX number of ms to wait for
|
|
; Channel store in DL
|
|
; Out: Channel store in DL
|
|
|
|
inc cx ; Wait for a given
|
|
WaitTickLoop: ; Number of ms
|
|
call TickTimer ; Plus one to guarantee
|
|
loop WaitTickLoop ; That at least cx ms
|
|
ret ; Go by
|
|
ProcEnd
|
|
;
|
|
ProcBegin@ TickTimer
|
|
; ====================
|
|
|
|
; Uses writes down our channel to simulate tick timer waits
|
|
; Must allow interrupts so other things can run -we will be here
|
|
; for 1/1000 of a second and may be called many times
|
|
; ChannelStore in/out in DL
|
|
|
|
mov al, dl ; Return the old
|
|
HwSelectChannel ; channel
|
|
mov ah, al
|
|
pushf
|
|
sti
|
|
push cx
|
|
mov cx, 12 ; 1ms
|
|
WaiterLoop: ; 128 frames =1ms
|
|
pushf ; about 12 times
|
|
cli ; round the loop
|
|
out ResetWatchDog,al
|
|
mov al, ah
|
|
HwSelectChannel
|
|
mov dl, al ; Get Correct channel
|
|
mov al, (SerialWriteSingle or 0) ; Do a write to
|
|
SBUSY ; nowhere and
|
|
SCONTOUT ; waste some time
|
|
SBUSY
|
|
SCONTOUT ; Do it eight times
|
|
SBUSY
|
|
SCONTOUT
|
|
SBUSY
|
|
SCONTOUT
|
|
SBUSY
|
|
SCONTOUT
|
|
SBUSY
|
|
SCONTOUT
|
|
SBUSY
|
|
SCONTOUT
|
|
SBUSY
|
|
SCONTOUT
|
|
SBUSY
|
|
mov al, dl ; Return the old
|
|
HwSelectChannel ; channel
|
|
mov ah, al
|
|
popf
|
|
loop WaiterLoop
|
|
pop cx
|
|
popf
|
|
mov al, ah
|
|
HwSelectChannel
|
|
mov dl, al
|
|
ret
|
|
ProcEnd
|
|
|
|
EndCodeSeg
|
|
|
|
stack segment stack para 'data'
|
|
stack ends
|
|
|
|
end OsAS5PDD
|
|
|
|
|