Files
sibo-playground/code/SIBOSDK/ldd/atimdvr.asm
T

447 lines
14 KiB
NASM
Raw Normal View History

2026-07-06 18:01:36 +01:00
title ATIMDVR -- Attached timer device driver example
subttl Copyright (c) Psion PLC 1991
name ATIMDVR
;
; VER DATE BY DESCRIPTION
; ----- -------- ---- -----------
; 1.00A 01/02/92 JH Alpha release
;
TURBOC equ 1
;
include epocdef.inc
include epocmac.inc
include epocpan.inc
include epoclib.inc
include epocser.inc
HandlerDisable equ 000h ; the hnadler should not be called
HandlerEnable equ 001h ; the handler should be called
;
TimerEnt struc
TimerIo ChanEnt <> ; I/O device driver hdr
ReadRq RqEnt <> ; read request info
ReadStat dw ? ; read completion status
InStrategy dw ? ; internal control
WaitHandler dw ? ; wait handler handle
TimerChan dw ? ; open timer channel handle
Timeout dd ? ; read timout
TimerStat dw ? ; timer completion status
TimerEnt ends
CodeSeg
ProcBegin@ AttachedTimerLDD
; =================
; The externally loadable Attached timer device table
dw LDDSignature
db 'ATM',0,0,0,0,0
dw (VectorEnd-Vector)/2
Vector:
dw AttachedTimerInstall
dw AttachedTimerRemove
dw AttachedTimerHold
dw AttachedTimerResume
dw AttachedTimerReset
dw AttachedTimerUnits
dw AttachedTimerOpen
dw AttachedTimerStrategy
VectorHandler:
dw AttachedTimerHandler
VectorEnd:
ProcEnd noret
ProcBegin@ AttachedTimerInstall,far
; =====================
; Called on device installation by the operating system
;
clc ; installed OK
ret
ProcEnd noret
ProcBegin@ AttachedTimerRemove,far
; ====================
; Always allow to be removed.
;
clc ; removed ok.
ret
ProcEnd noret
ProcBegin@ AttachedTimerHold,far
; ==================
; This does not need to do anything.
;
ret
ProcEnd noret
ProcBegin@ AttachedTimerResume,far
; ====================
; This does not need to do anything.
;
ret
ProcEnd noret
ProcBegin@ AttachedTimerReset,far
; ===================
; This will never be called since we dont request it to be called.
; The lower level driver and timer driver will handle the process
; terminating abnormally.
;
ProcEnd noret
ProcBegin@ AttachedTimerUnits,far
; ===================
; Called by device query units operating system service
;
mov ax, -1 ; supports many open requests
ret
ProcEnd noret
ProcBegin@ AttachedTimerOpen,far
; ==================
; Called by the IoOpen system service
;
; In:
; DX - device handle
; SI - ptr to OpenEnt struct
; Out:
; Carry clear
; BX - open channel handle
; DX - device handle as passed
; Carry set
; AL - error number
; DX - device handle as passed
;
cld
mov cx, (size TimerEnt)
HeapAllocateCell
jc endOpen ; return that error
mov bx, ax
; Initialise the allocated cell to zero.
mov di, ax
shr cx, 1 ; alloc cells should be even no of bytes.
xor ax, ax
rep stosw ; initialize all struct to zero
; Add the waithandler function
mov al, (VectorHandler-Vector)/2
IoAddHandler
jc freeCellExit ; report the add handler error
mov [bx].WaitHandler, ax ; handler handle
; Open a timer channel
push bx ; save the alloc cell handle
mov cx, sp ; save SP for now
xor ax, ax
push ax
mov ax, ':' shl 8 + 'M'
push ax
mov ax, 'I' shl 8 + 'T'
push ax
mov bx, sp ; BX is pointer to name to 'TIM:'
IoOpen ; CX and DX are irrelvant for a timer
mov sp, cx
pop bx
jc freeHandlerExit ; report the timer open error.
mov [bx].TimerChan, ax
; Set up the channel header
mov [bx].ChanSignature, IoChanSignature
mov [bx].ChanLibHandle, dx
mov [bx].ChanNext, bx ; were a root driver for now
; Attach this driver to the currently open driver Hierarchy
mov cx, bx ; channel were attaching
mov al, IoFuncAttach
mov bx, [si].OpenChan ; driver to attach to
IoWithWait
clc ; return BX (ie what attached to)
; Finished the open request
endOpen:
ret
; An error has occured, free the handler then cell in BX and return an error
freeHandlerExit:
push ax
push bx
mov bx, [bx].WaitHandler
IoRemoveHandler
pop bx
pop ax
; An error has occured, free the cell in BX and return an error
freeCellExit:
push ax
HeapFreeCell
pop ax ; AL has the error code
stc
ret
ProcEnd noret
ProcBegin@ StrategyVectorTable
; ===================
; The strategy vector jump table
;
dw StrategyDefault ; IoFuncPanic
dw StrategyRead ; IoFuncRead
dw StrategyDefault ; IoFuncWrite
dw StrategyClose ; IoFuncClose
dw StrategyCancel ; IoFuncCancel
dw StrategyDefault ; IoFuncAttach
dw StrategyDefault ; IoFuncDetach
dw StrategySet ; IoFuncSet
dw StrategySense ; IoFuncSense
StrategyVectorEnd:
ProcEnd noret
ProcBegin@ CancelTimer
; ===========
; Cancel the outstanding timer request
; In:
; BX = TimerEnt ptr
; Out:
; NONE
;
push bx
mov bx, [bx].TimerChan
mov al, IoFuncCancel ; cancel the queued timer
IoWithWait
pop bx
lea di, [bx].TimerStat
IoWaitForStatus ; use up completion signal
ret
ProcEnd noret
ProcBegin@ CancelRead
; ==========
; Cancel the outstanding read request on the lower driver
; In:
; BX = TimerEnt ptr
; Out:
; NONE
;
mov al, IoFuncCancel ; cancel the queued read
IoWithWait
lea di, [bx].ReadStat
IoWaitForStatus ; use up completion signal
ret
ProcEnd noret
ProcBegin@ SignalReadAX
; ============
; Complete the orignal read request with the completion status in AX
; In:
; AX = completion status to report
; BX = control block ptr as allocated by open
; Out:
; NONE
;
xor di, di ; complete the original read request
xchg di, [bx].ReadRq.RqStatusPtr
mov word ptr [di], ax
IoSignal
ret
ProcEnd noret
ProcBegin@ CancelAnyRequests
; =================
; Cancel any outstanding attached driver and timer requests.
; In:
; BX = control block ptr as allocated by open
; Out:
; NONE
;
cmp [bx].ReadRq.RqStatusPtr, 0
je noRequestsQueued
call CancelRead
call CancelTimer
push bx
mov bx, [bx].WaitHandler
mov cl, HandlerDisable
IoEnableHandler
pop bx
mov ax, CancelErr
call SignalReadAX
noRequestsQueued:
ret
ProcEnd noret
ProcBegin@ AttachedTimerStrategy,far
; =====================
; Called by the applications I/O services.
; In:
; BX = control block ptr as allocated by open
; SI = RqEnt pointer
; Out:
; Carry clear
; The request was sucessfully queued, (may have completed)
; Carry set
; The request failed to start
;
cld
mov [bx].InStrategy, 1 ; anti nesting
mov di, [si].RqStatusPtr
mov word ptr [di], PendingErr ; request now pending
mov ax, di ; pre-load AX
mov di, [si].RqFunction
cmp di, (StrategyVectorEnd-StrategyVectorTable)/2
ja StrategyDefault
mov cx, [si].RqA1Ptr ; pre-load CX and DX
mov dx, [si].RqA2Ptr
shl di, 1 ; vector table entry
jmp word ptr cs:StrategyVectorTable[di]
; This device driver does not handle this function, pass it up the driver
; hierarchy to a driver that may support this function.
StrategyDefault:
mov [bx].InStrategy, 0
IoSuper ; pass request to next dvr
ret
StrategyRead:
cmp [bx].ReadRq.RqStatusPtr, 0
jne panicPending ; already a read queued
mov [bx].ReadRq.RqStatusPtr, ax
mov [bx].ReadRq.RqA1Ptr, cx
mov [bx].ReadRq.RqA2Ptr, dx
lea di, [bx].ReadStat ; Q an attached dvr read
mov al, IoFuncRead
IoAsynchronousNoError ; Queue a read on lower dvr
lea di, [bx].TimerStat
lea cx, [bx].Timeout
push bx
push [bx].WaitHandler
mov bx, [bx].TimerChan
mov al, IoFuncRead
IoAsynchronousNoError ; Queue a read on the timer channel
; now let the wait handler be callable
pop bx
mov cl, HandlerEnable
IoEnableHandler
pop bx
and [bx].InStrategy, 0
clc
ret
; The process is making a 2nd call of a function that is already outstanding.
panicPending:
mov al, PanicIoPending
ProcPanic ; stop calling process.
StrategyCancel:
call CancelAnyRequests
and [bx].InStrategy, 0
jmp short completeRequestOk
; This driver defines the IoFuncSet function to set the read timout.
StrategySet:
mov di, cx ; RqA1Ptr is a pointer to a long
mov ax, [di]
mov word ptr [bx].Timeout, ax
mov ax, [di+2]
mov word ptr [bx+2].Timeout, ax
and [bx].InStrategy, 0
jmp short completeRequestOk
; This driver defines the IoFuncSense function to sense the read timout.
StrategySense:
mov di, cx ; RqA1Ptr is a pointer to a long
mov ax, word ptr [bx].Timeout
mov word ptr [di], ax
mov ax, word ptr [bx+2].Timeout
mov word ptr [di+2], ax
completeRequestOk:
mov di, [si].RqStatusPtr
and word ptr [di], 0 ; complete request OK.
IoSignal
and [bx].InStrategy, 0
clc
ret
StrategyClose:
call CancelAnyRequests
push bx
push [bx].WaitHandler
mov bx, [bx].TimerChan
IoClose ; close the timer
pop bx
IoRemoveHandler ; remove the waithandler
pop bx
mov al, IoFuncDetach ; detach from lower driver
IoWithWait
HeapFreeCell ; alloc cell freed !!!
mov di, [si].RqStatusPtr
and word ptr [di], 0 ; complete request OK.
IoSignal
clc
ret
ProcEnd noret
ProcBegin@ AttachedTimerHandler,far
; ====================
; Called by the operating system when the applications I/O semaphore has
; been signalled. See if its one of our requests that have been completed.
; The operating system will automatically stop any nesting if it called this
; handler, however we will get called if we are in the strategy vector and
; use synchronous I/O requests. The driver has set itself up such that this
; will only ever be called if there is an outstanding request by only
; enabling the handler when a read request is received.
;
; In:
; BX = as passed to IoAddHandler
; Out:
; Carry clear
; The signal was not for us.
; Carry set
; AL = 0 - we used signal, allow handler to be disabled.
; AL = 1 - we used signal, keep the handler enabled.
;
cmp [bx].InStrategy, 1
jne notInAttachedTimerStrategy
signalNotForThisDriver:
clc ; get out as fast as possible
ret ; as event definatly not for us.
notInAttachedTimerStrategy:
cmp [bx].ReadStat, PendingErr
je readRequestNotComplete
; The read request has completed.
call CancelTimer
mov ax, [bx].ReadStat ; read completion result
jmp short signalAXdisableHandler
readRequestNotComplete:
cmp [bx].TimerStat, PendingErr
je signalNotForThisDriver
; The timer request has completed.
call CancelRead
mov ax, InActivityErr ; read inactivity on timeout
signalAXdisableHandler:
call SignalReadAX
xor al, al ; we used signal
stc ; handler now disabled.
ret
ProcEnd noret
EndCodeSeg
;
stack segment stack para 'data'
;
stack ends
;
end AttachedTimerLDD