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