Files
sibo-playground/code/HDK/TMPA4LDD.ASM
T

809 lines
21 KiB
NASM
Raw Normal View History

2026-07-06 18:28:16 +01:00
title NAME.LDD device driver for S3/S3a/S3c/S3../HC
subttl Copyright PSION PLC November 1995
name NAME
; VERSION DATE DESCRIPTION
; ------- -------- ---------------
; 1.0 12/01/95 Template Asic4/5 LDD
; Written by Jason Robinson January 1995
BUILDSB equ 1
Asic4Type =0
Asic5Type =0
NeedTheInterrupt =0
NeedClocking =0
StartChannelInOpen =0
include ..\inc\epoc.inc
include ..\inc\epocser.inc
include ..\inc\epoclib.inc
include ..\inc\epocsibo.inc
include ..\srcs\ossibo.inc
include ..\srcs\ospack.inc
WeSupportS3Only equ Lcd240X80
WeSupportS3aOnly equ Lcd480X160
WeSupportS3cOnly equ Lcd240X100
WeSupportHCOnly equ Lcd160X80
if Consumer
NumberOfChannels equ 1
if Asic9
TheMachineWeSupport equ WeSupportS3aOnly
else
TheMachineWeSupport equ WeSupportS3Only
endif
else
NumberOfChannels equ 3
if Asic9
TheMachineWeSupport equ WeSupportS3cOnly
else
TheMachineWeSupport equ WeSupportHCOnly
endif
endif
A4PERIPH_MASK equ 0f0h
TheInfoByteThatWeWant equ 1
TmpltEnt struc
TmpltEntOpen db ? ; Channel open flag
TmpltChannelStarted db ? ; Channel should be running
TmpltHwChannel dw ? ; The harware we want
TmpltStructPtr dw ? ; Ptr to CB in Apps DS
TmpltTckHandle dw ? ; Tick Handle
TmpltChannelRunning db ? ; Can channel really run
TmpltInterruptMask db ? ; InterruptMask
TmpltChannel db ? ; Channel
if NeedTheInterrupt
TmpltInterruptNumber db ? ; Interrupt Number
TmpltInterruptVector dw ? ; Were to Jump To
if Asic5Type and NeedClocking
TmpltA5Clocking db ? ; Asic5 baud rate clocking
TmpltSpare db ?
endif
else
TmpltSpare db ?
endif
TmpltEnt ends
TmpltStruct struc
Tmpltblk ChanEnt <> ; I/O control block
TmpltEntPtr dw ? ; Ptr to our CS CB
TmpltStruct ends
dgroup group stack
assume ds:dgroup,es:dgroup,ss:dgroup
CodeSeg
ProcBegin@ TmpltLDD
; ===================
dw LDDSignature
db 'HSB',0,0,0,0,0
dw (TableEnd-TableStart)/2
TableStart:
dw TmpltInstall
dw TmpltRemove
dw TmpltHold
dw TmpltResume
dw TmpltReset
dw TmpltUnits
dw TmpltOpen
dw TmpltStrategy
MonitorVector:
dw MonitorInt
TableEnd:
if Consumer
if Asic9
SetupTable db mask A9MSlave,SelectChannel5
db (mask A9MClockEnable5 shr 8),HwIrq2Revector
if NeedTheInterrupt
dw offset Interrupt0
endif
else
SetupTable db mask Asic2Int,SelectChannel7
db (mask ClockEnable7 shr 8),HwIrq4Revector
if NeedTheInterrupt
dw offset Interrupt0
endif
endif
else
if Asic9
SetupTable db mask A9MExpIntA,SelectChannel3
db (mask A9MClockEnable3 shr 8),HwIrq4Revector
if NeedTheInterrupt
dw offset Interrupt0
endif
db mask A9MExpIntB,SelectChannel4
db (mask A9MClockEnable4 shr 8),HwIrq5Revector
if NeedTheInterrupt
dw offset Interrupt1
endif
db mask A9MSlave,SelectChannel5
db (mask A9MClockEnable5 shr 8),HwIrq2Revector
if NeedTheInterrupt
dw offset Interrupt2
endif
else
SetupTable db mask ExpIntLeftA,ExpChannelLeftA
db (mask ClockEnable6 shr 8),HwIrq3Revector
if NeedTheInterrupt
dw offset Interrupt0
endif
db mask ExpIntRightB,ExpChannelRightB
db (mask ClockEnable5 shr 8),HwIrq2Revector
if NeedTheInterrupt
dw offset Interrupt1
endif
db mask Asic2Int,SelectChannel7
db (mask ClockEnable7 shr 8),HwIrq4Revector
if NeedTheInterrupt
dw offset Interrupt2
endif
endif
endif
CsHeldFlag db 0 ; Ldd under a hold?
MachineType db 0
if Consumer
Channel0 TmpltEnt <>
else
Channel0 TmpltEnt <>
Channel1 TmpltEnt <>
Channel2 TmpltEnt <>
endif
ProcEnd noret
ProcBegin@ TmpltInstall,far
; ===========================
; Install the driver
; Exit with carry clear for okay
GenLcdType ; Do we only run on
mov MachineType,al ; particular machines?
cmp al,TheMachineWeSupport
jne CannotInstallOnThisMachine
pushf
cli
push ds
mov ax, cs
mov ds, ax
mov CsHeldFlag, 0 ; Initialise all
mov cx, NumberOfChannels ; the variables
mov di, offset Channel0
mov si, offset SetupTable
ResetAllChannelsLoop:
mov [di].TmpltEntOpen, 0
lodsb
mov [di].TmpltInterruptMask, al
lodsb
mov [di].TmpltChannel, al
lodsb
if NeedClocking
mov [di].TmpltA5Clocking, al
endif
lodsb
if NeedTheInterrupt
mov [di].TmpltInterruptNumber, al
lodsw
mov [di].TmpltInterruptVector, ax
endif
add di,size TmpltEnt
loop ResetAllChannelsLoop
pop ds
popf
FinishedOkay:
clc
ret
CannotInstallOnThisMachine:
mov ax,NotSupportedErr
stc
ret
ProcEnd noret
ProcBegin@ TmpltRemove,far
; ==========================
; Remove the driver
; Exit with carry clear for okay
; Exit with carry set if channel still open
mov cx,NumberOfChannels
mov di,offset Channel0
xor ax,ax
CheckAllChannelsClosedLoop:
cmp cs:[di].TmpltEntOpen,al
jne WeHaveAnOpenChannelSoFail
add di,size TmpltEnt
loop CheckAllChannelsClosedLoop
jmp FinishedOkay
WeHaveAnOpenChannelSoFail:
mov ax,InUseErr
stc
ret
ProcEnd noret
ProcBegin@ TmpltUnits,far
; =========================
; Return the Number of channels that can be opened in AX
mov ax,NumberOfChannels ; We have ? channels
ret
ProcEnd noret
ProcBegin@ TmpltReset,far
; =========================
; Reset the open channel
mov di,cx
cmp cs:[di].TmpltEntOpen,0 ; Somethings gone
je NotOpenToReset ; wrong with the
mov ah,DevHoldPowerDown ; application that
call StopTheChannel ; opened us.
call FreeHardware ; Stop interupts and
mov cs:[di].TmpltEntOpen,0 ; free the channel
NotOpenToReset:
ret
ProcEnd noret
ProcBegin@ TmpltHold,far
; ========================
; Hold the channels
; Hold reason in AH
mov cx,1
xchg cl,CsHeldFlag ; Stop any interrupts
cmp cl,0 ; Mark channel as
jne AlreadyHeld ; under a normal hold
DoHold:
mov cx,NumberOfChannels
mov di,offset Channel0
HoldAllTheChannelsLoop:
cmp cs:[di].TmpltEntOpen,0
je DontHoldBecauseNotOpen
cmp cs:[di].TmpltChannelStarted,0
je DontHoldBecauseNotOpen
push ax
push cx
call StopTheChannel
pop cx
pop ax
DontHoldBecauseNotOpen:
add di,size TmpltEnt
loop HoldAllTheChannelsLoop
AlreadyHeld:
ret
ProcEnd noret
ProcBegin@ TmpltResume,far
; ==========================
; Resume the channel
xor cx,cx ; Be warned during an
xchg cl,CsHeldFlag ; on/off the power to
cmp cl,0 ; ASIC4 is not restored
je AlreadyResumed ; until after this
GenDataSegment ; A resume is pointless
HwGetSsdData ; if there is still no
mov bx,ax ; power to the port
cmp es:[bx].SsdDoorStatus,DoorOpen ; Leave the resume
je DoorsAreOpen ; to the tick
DoResume:
mov cx,NumberOfChannels
mov di,offset Channel0 ; Right hardware?
ResumeAllTheChannelsLoop: ; Else restart
cmp cs:[di].TmpltEntOpen,0 ; interrupts
je DontResumeBecauseNotOpen
cmp cs:[di].TmpltChannelStarted,0
je DontResumeBecauseNotOpen
push cx
call StartTheChannel
pop cx
DontResumeBecauseNotOpen:
add di,size TmpltEnt
loop ResumeAllTheChannelsLoop
AlreadyResumed:
ret
DoorsAreOpen:
mov CsHeldFlag,2
ret
ProcEnd noret
ProcBegin@ TmpltOpen,far
; ========================
; Open the channel
; DS,ES,SS Applications data space
; Handle in DX
cld
pushf
cli
call FindFreeChannel
jnc GotFreeChannel
popf
LockedError:
mov ax,LockedErr
stc
ret
AllErrorsExitHere:
push ax
HeapFreeCell
pop ax
FreeTckAndChannel:
push ax
call FreeHardware
pop ax
FreeTckAndExit:
push ax
mov bx,cs:[di].TmpltTckHandle
IoClose
pop ax
CloseThenFree:
mov cs:[di].TmpltEntOpen,0
stc
ret
GotFreeChannel:
mov cs:[di].TmpltEntOpen,1
mov cs:[di].TmpltChannelStarted,0
mov cs:[di].TmpltChannelRunning,0
popf
xor ax,ax
push ax
mov ax,((':' shl 8)+'K')
push ax
mov ax,(('C' shl 8)+'T')
push ax
mov bx,sp
IoOpen
jnc GotATickChannel
add sp,6
mov ax,LockedErr
jmp CloseThenFree
GotATickChannel:
add sp,6
mov cs:[di].TmpltTckHandle,ax
push dx
mov bx,ax
mov ax,IoFuncStart
mov cx,1
push cx ; Frequency 1 tick
push di ; Data is our CS CB
push dx ; Our device handle
mov cx,(MonitorVector-TableStart)/2 ; Vector to call
push cx
mov cx,sp
IoWithWait
add sp,8
pop dx
call GetHardware
jc FreeTckAndExit
mov cx,(size TmpltStruct) ; Get ourselfs a CB
HeapAllocateCell ; In the applications
jc FreeTckAndChannel ; Data space
mov bx,ax
mov [bx].Tmpltblk.ChanNext,bx
mov [bx].Tmpltblk.ChanSignature,IoChanSignature
mov [bx].Tmpltblk.ChanLibHandle,dx
mov [bx].TmpltEntPtr,di
push bx
mov bx,dx
mov cx,di
IoRequestReset
pop bx
if StartChannelInOpen
call StartChannelFromOpen
endif
xor ax,ax
ret
ProcEnd noret
StrategyVectorTable label word
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset TmpltClose
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
dw offset StrategyDefault
ProcBegin@ TmpltStrategy,far
; ============================
; BX is our control block
; SI points to the parameters
; DS,ES Applications data space
mov ax,[si].RqFunction
mov dx,[si].RqA1Ptr
cmp ax,IoFuncSuperFrame
ja StrategyDefault
shl ax,1
mov di,ax
push StrategyVectorTable[di]
mov di,[bx].TmpltEntPtr
retn
StrategyDefault:
IoRoot
ret
ExitStrategyOkay:
xor ax,ax
ExitStrategy:
mov di,[si].RqStatusPtr
mov word ptr [di],ax
cmp ax,PendingErr
je JustExit
IoSignal
JustExit:
xor ax,ax
ret
ProcEnd noret
ProcBegin@ TmpltClose,far
; =========================
; Close a channel
; DI CS control block
; BX DS control block
; SI points to aurguments on stack
; DX Argument one pointer
mov ah,DevHoldPowerDown
call StopTheChannel
call FreeHardware
mov cs:[di].TmpltChannelStarted,0
push bx
mov bx,[bx].Tmpltblk.ChanLibHandle
mov cx,di
IoRequestResetCancel
pop bx
HeapFreeCell
mov bx,cs:[di].TmpltTckHandle
IoClose
mov cs:[di].TmpltEntOpen,0
jmp short ExitStrategyOkay
ProcEnd noret
ProcBegin@ StartTheChannel
; ==========================
; Start the Channel Running
; Assume channel set up and interrupts off
cmp cs:[di].TmpltChannelRunning,0
jne ChannelAlreadyRunning
if Asic5Type and NeedClocking
if Asic9
in ax, A9WControlExtraRW ; Start the S3s clock
or ah, [bx].TmpltA5Clocking ; Generator
out A9WControlExtraRW, ax
else
mov al, [bx].TmpltA5Clocking
HwSetA2Control2Bits
endif
endif
if NeedTheInterrupt
mov al, cs:[di].TmpltInterruptNumber ; Load the address of
mov cx, cs ; the appropriate
mov bx, cs:[di].TmpltInterruptVector ; interrupt routine
GenSetRevector ; into the correct vector
if Asic9
in al,A9BInterruptMaskRW ; Set the mask
or al,cs:[di].TmpltInterruptMask ; to enable Interrupts
out A9BInterruptMaskRW,al
else
in al, A1InterruptMask
or al,cs:[di].TmpltInterruptMask
out A1InterruptMask, al
endif
endif
mov cs:[di].TmpltChannelRunning,1
ChannelAlreadyRunning:
ret
ProcEnd noret
ProcBegin@ StopTheChannel
; =========================
; Stop the Channel Running
; Assume channel set up and interrupts off
; Stop reason in AH
cmp byte ptr cs:[di].TmpltChannelRunning,0
je ChannelAlreadyStopped
if NeedTheInterrupt
mov ah,cs:[di].TmpltInterruptMask
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].TmpltInterruptNumber
GenResetRevector
endif
if Asic5Type and NeedClocking
if Asic9
mov cl, [bx].TmpltA5Clocking ; Turn off baud rate
not cl ; clocking from the
in ax, A9WControlExtraRW ; S3/3a
and ah, cl
out A9WControlExtraRW, ax
else
mov al, [bx].TmpltA5Clocking
HwClearA2Control2Bits
endif
endif
mov cs:[di].TmpltChannelRunning,0
ChannelAlreadyStopped:
ret
ProcEnd noret
if StartChannelInOpen
ProcBegin@ StartChannelFromOpen
; ===============================
pushf
cli
mov cs:[di].TmpltChannelStarted,1
mov al,cs:[di].TmpltChannel
HwSelectChannel
push ax
call StartTheChannel
pop ax
HwSelectChannel
popf
ret
ProcEnd noret
endif
ProcBegin@ GetHardware
; ======================
mov al, cs:[di].TmpltInterruptMask
HwGetChannel
jc ChannelNotAvailable
pushf
cli
mov al,cs:[di].TmpltChannel
HwSelectChannel
push ax
call CheckForHardware
pop ax
jc NoHardwareFreeTheChannel
HwSelectChannel
popf
clc
ret
NoHardwareFreeTheChannel:
HwSelectChannel
popf
mov al, cs:[di].TmpltInterruptMask
HwFreeChannel
ChannelNotAvailable:
stc
ret
ProcEnd noret
ProcBegin@ FreeHardware
; =======================
mov al, cs:[di].TmpltInterruptMask
HwFreeChannel
ret
ProcEnd noret
ProcBegin@ FindFreeChannel
; ==========================
mov si,[si].OpenNamePtr
mov al,[si+1]
CharToFoldedChar
cmp al,'A'
jb CantGetThatChannel
sub al,'A'
cmp al,NumberOfChannels
jae CantGetThatChannel
xor ah,ah
push dx
mov dx,size TmpltEnt
mul dx
pop dx
mov di,ax
add di,offset Channel0
cmp cs:[di].TmpltEntOpen,0
je FoundAFreeChannel
CantGetThatChannel:
stc
ret
FoundAFreeChannel:
clc
ret
ProcEnd noret
ProcBegin@ CheckForHardware
; ===========================
; Assume Interrupts are off
; Correct channel should be selected
; Out: clc - got correct hardware
; stc - wrong or no hardware
if Asic5Type
HwNullFrame ; Check that the
mov al,(SerialSelect or Asic5NormalId) ; Harware is there
SBUSY ; And that it is what
SCONTOUT ; It should be
XNOP ; First look for An
SBUSY ; ASIC5 at the other
SDATAIN ; End of the link
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
else
HwNullFrame
mov al,(SerialSelect or Asic4Id)
SBUSY ; First look for An
SCONTOUT ; ASIC4 at the other
XNOP ; End of the link
SBUSY
SDATAIN
test al, al
je ConnectionFailed
mov al,SerialReadSingle or A4InfoR ; Now see if we have
SBUSY ; The right card
SCONTOUT
XNOP ; Allows the busy signal to come through for the wait
SBUSY
SDATAIN
and al,A4PERIPH_MASK
cmp al,TheInfoByteThatWeWant
jne ConnectionFailedExit
clc
ret
ConnectionFailed:
mov al,(SerialSelect or Asic5NormalId) ; Select as an
SBUSY ; Asic5 peripheral
SCONTOUT
XNOP
SDATAIN
test al,al
jne ConnectionFailedExit
endif
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:
stc
ret
ProcEnd noret
ProcBegin@ MonitorInt,far
; =========================
; Called on every tick
; Issues pack door hold and resumes
; In: Door state in SI
cmp si,DoorOpen
je TheDoorIsOpenSoCantDoAnything
cmp CsHeldFlag,2
je NeedToDoTheResume
ret
NeedToDoTheResume:
mov CsHeldFlag,0
jmp DoResume
TheDoorIsOpenSoCantDoAnything:
cmp CsHeldFlag,0
jne DontNeedToHold
mov CsHeldFlag,2
mov ah,DevHoldPowerFail
jmp DoHold
DontNeedToHold:
ret
ProcEnd noret
if NeedTheInterrupt
ife Consumer
ProcBegin@ Interrupt2,far
; =========================
mov di,offset Channel2
mov ax,PortCActive
jmp ComInt
ProcEnd noret
ProcBegin@ Interrupt1,far
; =========================
mov di,offset Channel1
mov ax,PortBActive
jmp ComInt
ProcEnd noret
endif
ProcBegin@ Interrupt0,far
; =========================
mov di,offset Channel0
mov ax,PortAActive
; FALLTHROUGH to ComInt
ProcEnd noret
ProcBegin@ ComInt,far
; =====================
if Asic9
out A9BNonSpecificEoiW,al
else
out A1NonSpecificEoi, al
endif
clc
ret
ProcEnd noret
endif
EndCodeSeg
stack segment stack para 'data'
stack ends
end TmpltLDD