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

1190 lines
49 KiB
NASM
Raw Normal View History

2026-07-06 18:28:16 +01:00
title A4EXIF -- Example ASIC4 Interface device driver
subttl Copyright (c) Psion PLC (1994)
name A4EXIF
;
; VER DATE BY DESCRIPTION
; ----------------------------------------
; 1.00F 26/1/95 Mal Working Version
;BUILDSB=1 ;S3a build environment (channels=1)
S3c=0 ;Need to specify no s3c
;BUILDSC=1 ;S3c build environment (channels=3)
BUILDCH=1 ;HC build environment (channels=3)
;BUILDHH=1 ;S3 build environment (channels=1)
include ..\inc\epoc.inc
include ..\inc\epoclib.inc
include ..\inc\epocsibo.inc
include ossibo.inc
include ospack.inc
; Example Logical Device Driver for prototype LED-ASIC4 Interface
; circuit for Corporate/S3C/Consumer serial port.
; Written by Mal Dec 1994/Jan 1995.
; A4EXIF CONSTANTS AND TYPES
; ==========================
; The following constants and type definitions
; are compiler directives used by the TCEP assembler
; when it is creating the LDD.
if Consumer
numberofchannels equ 1
else
if Corporate or S3c
numberofchannels equ 3
else
numberofchannels equ 2
endif
endif
;Channel StatusEnt block accessed through CS:DI
A4ExifStatusEnt struc
A4ExifCSProcessId dw ? ;Channel parent process id
A4ExifCSChannelOpen db ? ;Channel open flag
A4ExifCSChannelRunning db ? ;Channel hardware running flag
A4ExifCSChanReadCompleted db ? ;Channel request completed flag
A4ExifCSChannelIntMask db ? ;Channel interrupt mask
A4ExifCSChannelIntNum db ? ;Channel interrupt number
A4ExifCSChannelSelect db ? ;SIBO Channel select
A4ExifCSChannelIntVec dw ? ;Channel int vector number
A4ExifCSTickHandle dw ? ;TCK channel handle
A4ExifCSA1Value db ? ;Channel strategy A1 parameter
A4ExifCSA2Value db ? ;Channel strategy A2 parameter
A4ExifStatusEnt ends
;Open Channel Control block accessed through DS:BX
A4ExifEnt struc
A4ExifDSIo ChanEnt <> ;Open channel control block Ent
A4ExifDSHandlerPtr dw ? ;Cant touch when under
A4ExifDSStatusPtr dw ? ;Hold, Resume, Reset or
A4ExifDSA1Ptr dw ? ;interrupt routine
A4ExifDSA2Ptr dw ?
A4ExifDSStatusEntPtr dw ?
A4ExifEnt ends
A4PERIPH_MASK equ 0f0h ;11110000b
EXTENDED_INFO_BYTE equ 090h ;10010000b
U5_ENABLE_ON equ 080h ;Sets LBO for latch U5
U5_ENABLE_OFF equ 000h ;Deselects LBO for U5
;Latch addresses for reading/writing
U5OUTPUT_LATCH equ 00000000b ;Selects A0 for writing
U3INPUT_BUFFER equ 00000000b ;Selects A0 for reading
U4STATUS_BUFFER equ 00000001b ;Selects cs:[di].A4ExifCsA1Valuefor reading
INTERRUPT_LATCH equ 00000001b ;Selects A1 for writing
;Status byte masks
S2S3_ON equ 00000011b
S2S3_OFF equ 00000000b
S2_ONLY equ 00000001b
S3_ONLY equ 00000010b
INTERRUPT_STATUS_MASK equ 00000011b
;LED bytes
SOME_LEDS_ON equ 01010101b
SOME_LEDS_OFF equ 10101010b
TOP_LEDS_ON equ 11110000b
BOTTOM_LEDS_ON equ 00001111b
ZERO_BYTE equ 00h
dgroup group stack
assume ds:dgroup,es:dgroup,ss:dgroup
CodeSeg
; A4EXIF ENTRY TABLE
; ==================
ProcBegin@ A4ExifLDD
; =========
dw LDDSignature
db 'LED',0,0,0,0,0
dw (VectorEnd-Vector)/2
Vector:
dw A4ExifInstall
dw A4ExifRemove
dw A4ExifHold
dw A4ExifResume
dw A4ExifReset
dw A4ExifUnits
dw A4ExifOpen
dw A4ExifStrategy
VectorHandler:
dw A4ExifHandler
if Asic9
InterruptVectors:
dw A4ExifTickInt
endif
VectorEnd:
; A4EXIF INTERNAL DATA SPACE
; ==========================
; Device Driver global variables follow.
; These variables reside in the code segment
; and as such can always be accessed with
; the 'cs:' prefix.
if Asic9
if Consumer
Channel0 A4ExifStatusEnt<0,0,0,0,mask A9MSlave,HwIrq2Revector,SelectChannel5,IntVec0,0,0>
else
if Corporate or S3c
Channel0 A4ExifStatusEnt<0,0,0,0,mask A9MExpIntA,HwIrq4Revector,SelectChannel3,IntVec0,0,0>
Channel1 A4ExifStatusEnt<0,0,0,0,mask A9MExpIntB,HwIrq5Revector,SelectChannel4,IntVec1,0,0>
Channel2 A4ExifStatusEnt<0,0,0,0,mask A9MSlave,HwIrq2Revector,SelectChannel5,IntVec2,0,0>
else
Channel0 A4ExifStatusEnt<0,0,0,0,mask A9MExpIntA,HwIrq4Revector,SelectChannel3,IntVec0,0,0>
Channel1 A4ExifStatusEnt<0,0,0,0,mask A9MExpIntB,HwIrq5Revector,SelectChannel4,IntVec1,0,0>
endif
endif
else
if Consumer
Channel0 A4ExifStatusEnt<0,0,0,0,mask Asic2Int,HwIrq4Revector,SelectChannel7,IntVec0,0,0>
else
if Corporate
Channel0 A4ExifStatusEnt<0,0,0,0,mask ExpIntLeftA,HwIrq3Revector,ExpChannelLeftA,IntVec0,0,0>
Channel1 A4ExifStatusEnt<0,0,0,0,mask ExpIntRightB,HwIrq2Revector,ExpChannelRightB,IntVec1,0,0>
Channel2 A4ExifStatusEnt<0,0,0,0,mask Asic2Int,HwIrq4Revector,SelectChannel7,IntVec2,0,0>
else
Channel0 A4ExifStatusEnt<0,0,0,0,mask ExpIntLeftA,HwIrq3Revector,ExpChannelLeftA,IntVec0,0,0>
Channel1 A4ExifStatusEnt<0,0,0,0,mask ExpIntRightB,HwIrq2Revector,ExpChannelRightB,IntVec1,0,0>
endif
endif
endif
HoldFlag db 0 ;Hold/Resume flag
SwitchStatus db ? ;Holds the masked status byte from U4 after interrupt
ProcEnd noret
ProcBegin@ A4ExifInstall,far
; =============
; Installs the device driver.
; Invoked after a PLIB 'p_loadldd("A4EXIF.LDD")' call to load the LDD
; All of the fields inside the CS control blocks are preloaded
; with the correct values at install time. Install therefore does
; not do any work.
; IN:
; Nothing
; OUT:
; Carry Clear - driver successfully installed
;
clc ;The ChannelOpen fields are set to zero
ret ;in the relevant ChannelStatusEnt headers
ProcEnd noret
ProcBegin@ A4ExifRemove,far
; ============
; Removes the device driver.
; Invoked after a PLIB 'p_devdel("LED",E_LDD)'call to unload the
; device driver.
; A device driver cannot be removed if any of its channels
; are still open.
; IN:
; Nothing
; OUT:
; Carry clear - successfully removed
; Carry set - remove failed, error number in AL
;
mov cx, numberofchannels ;Check that each
mov di, offset Channel0 ;channel is closed
xor ax, ax
CheckAllChannelsClosedLoop:
cmp cs:[di].A4ExifCSChannelOpen, al ;Closed channels will
jne WeHaveAChannelOpenSoFail ;have the value 0 in
add di, (size A4ExifStatusEnt) ;their ChannelOpen
loop CheckAllChannelsClosedLoop ;flags
jmp FinishedOkay
WeHaveAChannelOpenSoFail:
mov al, InUseErr ;Fail if not all
stc ;closed
ret
FinishedOkay:
clc
ret
ProcEnd noret
ProcBegin@ A4ExifHold,far
; ==========
; Called by the operating system whenever the device driver is
; being moved or the machine is powering down.
; This will also be called by our pack door polling function when
; it sees that the doors have been opened and our peripheral has
; lost power.
; IN:
; Reason for the hold in AH
; OUT:
; Nothing
;
mov cx, 1 ;Hold can be called
xchg cl, HoldFlag ;when the driver is
cmp cl, 0 ;under a hold so
jne AlreadyHeld ;re-entrancy blocking
A4HoldFromTick: ;is required
mov cx, numberofchannels
mov di, offset Channel0 ;Loop because Hold
HoldAllTheChannelsLoop: ;must stop all the
cmp cs:[di].A4ExifCSChannelOpen, 0 ;channels
je DontHoldBecauseNotOpen ;Is the channel open?
push cx ;If it is then stop
call StopTheChannelRunning ;all interrupts
pop cx
DontHoldBecauseNotOpen:
add di, (size A4ExifStatusEnt)
loop HoldAllTheChannelsLoop
AlreadyHeld:
ret
ProcEnd noret
ProcBegin@ A4ExifResume,far
; ============
; Called by the operating system when it has finished moving the
; device driver in memory or when the machine is switching back on.
; Also called by our door polling routine when it sees that the doors
; have been closed and we can resume communication with our peripheral.
; IN:
; Nothing
; OUT:
; Nothing
;
xor cx, cx ;Block in case of re-entrancy
xchg cl, HoldFlag
cmp cl, 0
je AlreadyResumed
if Asic9
GenDataSegment ;Check to see if the pack
HwGetSsdData ;doors are still closed
mov bx, ax
cmp es:[bx].SsdDoorStatus, DoorOpen
je DoorsAreOpen
endif
A4ResumeFromTick:
mov cx, numberofchannels ;Loop because resume must
mov di, offset Channel0 ;restart each open channel
ResumeAllTheChannelsLoop:
cmp cs:[di].A4ExifCSChannelOpen, 0 ;Is the channel open?
je DontResumeBecauseNotOpen
push cx
call StartTheChannelRunning
pop cx
DontResumeBecauseNotOpen:
add di, (size A4ExifStatusEnt)
loop ResumeAllTheChannelsLoop
AlreadyResumed:
ret
DoorsAreOpen:
mov HoldFlag, 2
ret
ProcEnd noret
ProcBegin@ A4ExifReset,far
; ===========
; Called when an application which opened a channel terminates without
; closing the device driver.
; A device driver, for each open channel, has to request that the
; operating system calls this function when the application
; terminates abnormally (ie without closing an open channel).
; Reset can supply one piece of identifying data which will be
; passed in CX. This would usually be the channel's number or CS
; control block pointer.
; Reset just needs to clear interrupts, hardware reservations, and free
; the channel. Any allocated space will be cleaned up for you by the OS.
; IN:
; The device driver's handle in BX
; The address of the status struc identifying the channel in CX
; OUT:
; Nothing
;
mov di, cx
cmp cs:[di].A4ExifCSChannelOpen, 0
je NotOpenToReset
call StopTheChannelRunning ;Stop interrupts
mov al, cs:[di].A4ExifCSChannelIntMask ;Free the reserved
HwFreeChannel ;hardware
mov cs:[di].A4ExifCSChannelOpen, 0 ;The channel is now
NotOpenToReset: ;free
ret
ProcEnd noret
ProcBegin@ A4ExifUnits,far
; ===========
; Called to find how many open channels the driver will support
; In:
; Nothing
; Out:
; The total number of channels supported in AX
;
mov ax, numberofchannels
ret
ProcEnd noret
ProcBegin@ A4ExifOpen,far
; ==========
; Opens a device driver channel.
; Invoked after the PLIB call 'p_open(&appHandle,"LED:*",-1)'to open a
; channel to the device driver.
; In:
; OS device handle of the device driver in DX
; Pointer to the OpenEnt struc in SI
; Pointer to the IntEnt struc in BP
; DS,ES,SS point to the applications data space
; Out:
; Carry clear - BX holds the address of the open channel
; Carry set - AL holds the error number
;
cld ;Interrupts off to
pushf ;prevent multiple apps
cli ;calling open
mov si, [si].OpenNamePtr ;simultaneously
mov al, [si+1]
CharToFoldedChar ;Read the unit no.
cmp al, 'A' ;part of device name
jb OpenNameErr ;to find which channel
sub al, 'A' ;to open. eg "LED:A"
cmp al, numberofchannels
jae OpenNameErr
xor ah, ah
push dx ;Map the channel no.
mov dx, (size A4ExifStatusEnt) ;to a channel control
mul dx ;block in our CS
pop dx ;space
mov di, ax
add di, offset Channel0 ;Offset in DI
cmp cs:[di].A4ExifCSChannelOpen, 0
je GetATickChannel ;Check to see if
popf ;channel is already
mov ax, AlreadyOpenErr ;open
jmp ChannelAlreadyOpen
GetATickChannel:
mov cs:[di].A4ExifCSChannelOpen, 1 ;Obtain a TCK channel so
mov cs:[di].A4ExifCSChannelRunning,0 ;we can poll the door state
popf
ife Asic9
jmp GetHardwareChannel ;If HC, we don't need
else ;to set up the TCK
push ax ;routine
mov ax, ((':' shl 8)+'K')
push ax
mov ax, (('C' shl 8)+'T') ;Try to open "TCK:"
push ax ;channel with "TCK:"
mov bx, sp ;string on stack
IoOpen
jnc GotATickChannel ;TCK will call our
add sp, 6 ;door-polling function
mov ax, LockedErr ;32 times a second
jmp OpenFailed
GotATickChannel:
add sp, 6
mov cs:[di].A4ExifCSTickHandle, ax ;Start our
push dx ;door-polling function
mov bx, ax ;running by starting
mov ax, IoFuncStart ;the "TCK:" channel
mov cx, 1
push cx ;Frequency 1 tick
push cx ;Data irrelevant
push dx ;Handle to driver
mov cx, (InterruptVectors-Vector)/2 ;TCK function to call
push cx
mov cx, sp
IoWithWait
add sp, 8
pop dx
jmp GetHardwareChannel
endif
OpenNameErr:
popf
mov ax, NameErr
jmp ChannelAlreadyOpen
GetHardwareChannel: ;Check the hardware
mov al, cs:[di].A4ExifCSChannelIntMask ;is available then
HwGetChannel ;reserve it
jnc CheckHardwareNowThatSIBOChannelIsOpen ;Returns with carry
mov ax, InUseErr ;clear if OK
jmp FreeTckAndExit
FreeTckAndChannelHardware:
mov al, cs:[di].A4ExifCSChannelIntMask
HwFreeChannel
mov ax, DeviceErr
FreeTckAndExit:
if Asic9
push ax
mov bx, cs:[di].A4ExifCSTickHandle
IoClose
pop ax
endif
OpenFailed:
mov cs:[di].A4ExifCSChannelOpen, 0
ChannelAlreadyOpen:
stc
OpenExit:
ret
CheckHardwareNowThatSIBOChannelIsOpen:
ProcId ;Set up the calling
mov cs:[di].A4ExifCSProcessId, ax ;process ID
mov cs:[di].A4ExifCSChanReadCompleted, 0
call CheckHardwarePresent ;Returns with carry
jc FreeTckAndChannelHardware ;clear if successful
mov cx, (size A4ExifEnt) ;Allocate a control
HeapAllocateCell ;block in our app's
jc FreeTckAndChannelHardware ;data space
mov bx, ax
push bx ;IoAddHandler trashes BX
mov al, (VectorHandler-Vector)/2 ;Set up our wait handler
IoAddHandler ;Leaves the address of
pop bx ;handler in AX
jnc GotHandler
push ax ;If no handler, open fails
HeapFreeCell
pop ax
jmp FreeTckAndChannelHardware
GotHandler:
mov [bx].A4ExifDSStatusEntPtr, di
mov [bx].A4ExifDSHandlerPtr, ax
mov [bx].A4ExifDSStatusPtr, 0
mov [bx].A4ExifDSIo.ChanNext, bx
mov [bx].A4ExifDSIo.ChanSignature, IoChanSignature
mov [bx].A4ExifDSIo.ChanLibHandle, dx
mov cx, di ;IoRequestReset takes
xchg bx, dx ;the device handle in
IoRequestReset ;BX and the channel
xchg bx, dx ;handle in CX
xor ax, ax
call StartTheChannelRunning
ReturnCLC:
clc
ret
ProcEnd
if Asic9
ProcBegin@ A4ExifTickInt,far
; =============
; This function is called by the tick handler on every tick of
; the system clock. This happens 32 times a second.
; The operating system will call a device driver to hold when memory is
; being moved and when the machine is being powered down. It will not
; call the device driver when the pack doors are opened.
; Opening the pack doors will cause power to the peripheral to be cut,
; and therefore the driver needs to be held in the way it would be if
; the machine powered down. Only for Asic9 based machines.
; This function checks the state of the doors on every tick and calls
; Hold and resume when it sees the status of the doors change.
; IN:
; The state of the door in SI
; OUT:
; Nothing
;
cmp si, DoorOpen ;Is the door open
je TheDoorIsOpen ;or closed?
cmp HoldFlag, 2 ;Closed Door, HoldFlag=2
je NeedToDoTheResume ;means we do a resume
ret ;Closed Door, HoldFlag!=2
NeedToDoTheHold:
mov HoldFlag, 2
jmp A4HoldFromTick
NeedToDoTheResume:
mov HoldFlag, 0
jmp A4ResumeFromTick
TheDoorIsOpen:
xor ax, ax
cmp HoldFlag, al
je NeedToDoTheHold
ret
ProcEnd noret
endif
ProcBegin@ A4ExifHandler,far
; =============
; When an application is waiting within an iowait and a signal is
; generated then before passing that signal to the application the
; OS first runs any wait handlers belonging to the device driver
; channels that the application has open.
; The interrupt routine can generate a signal but cannot fill in any
; status words or pass values back to the application because the
; applications DS space is not available. The handler can consume a
; signal generated by an interrupt and then fill any status words
; before re-signalling the application. A handler always has access
; to the application's DS space. The wait handler can consume the
; signal which is then no longer passed back to the application.
; IN:
; Pointer to our control block in applications DS space in BX
; DS,ES,SS point at application's data space
; OUT:
; Carry clear - do not consume the signal, signal not for us
; Carry set - consume the signal, re-enable handler if AL
; non-zero else don't re-enable handler if AL=0.
;
cld
pushf
cli
mov di, [bx].A4ExifDSStatusEntPtr ;Is the signal for us?
cmp cs:[di].A4ExifCSChanReadCompleted, 1
jne ExitHandlerSignalNotForUs ;If it is, copy
mov cs:[di].A4ExifCSChanReadCompleted, 0 ;the values read in
mov al, cs:[di].A4ExifCSA1Value ;the interrupt
mov ah, cs:[di].A4ExifCSA2Value ;routine back to
mov di, [bx].A4ExifDSA1Ptr ;the application
mov [di], al ;Asynchronous read
mov di, [bx].A4ExifDSA2Ptr ;has been completed
mov [di], ah
xor di, di
xchg [bx].A4ExifDSStatusPtr, di ;Clear the status
mov word ptr [di], 0 ;word
popf
IoSignal
xor ax, ax
stc ;STC and AL!=0 =>
ret ;consume signal and
ExitHandlerSignalNotForUs: ;don't re-enable
popf ;handler
clc
ret
ProcEnd
StrategyVectorTable label word
dw offset A4ExifDefault ;StrategyPanic
dw offset A4ExifRead ;StrategyRead ie P_FREAD
dw offset A4ExifWrite ;StrategyWrite ie P_FWRITE
dw offset A4ExifClose ;StrategyClose ie P_FCLOSE
dw offset A4ExifCancel ;StrategyCancel ie P_FCANCEL
dw offset A4ExifDefault ;StrategyAttach
dw offset A4ExifDefault ;StrategyDetach
dw offset A4ExifSet ;StrategySet ie P_FSET
dw offset A4ExifSense ;StrategySense ie P_FSENSE
ProcBegin@ A4ExifStrategy,far
; ==============
; Called by the operating system when an I/O request is made on
; the device driver.
; Calls to this funcion from an owning application will usually take
; the form p_ioc(pcb,func,&Stat,&A1,&A2);
; The strategy function is called with a function number specifying
; the action which the driver is to take, a status word to fill when
; the action is complete, and two arguments A1 and A2.
; All strategy functions must complete with a signal to the application.
; Functions can be asynchronous and need not complete immediately.
; IN:
; Pointer to our control block in the applications DS in BX
; Device driver handle in DX
; Pointer to the RqEnt struct in SI
; Pointer to a IntEnt struct in BP
; DS,ES,SS point at the applications data space
; OUT:
; Returned value in AX
; Must call IoSignal somewhere to signal completion
; of the I/O request.
;
mov ax, [si].RqFunction ;Get the function number
mov dx, [si].RqA1Ptr ;DX holds the first argument
mov di, [si].RqStatusPtr ;for convenience
mov word ptr [di], PendingErr ;Status word holds
shl ax, 1 ;E_FILE_PENDING
mov di, ax
push StrategyVectorTable[di] ;Jump to required function
mov di, [bx].A4ExifDSStatusEntPtr ;with our CS control block
retn ;pointer in DI
A4ExifDefault:
IoRoot
ret
ExitWithCompletionStatusZero:
xor ax, ax ;Common exit points
ExitWithOtherCompletionStatus:
mov di, [si].RqStatusPtr
mov word ptr [di], ax
IoSignal
ExitStillPending:
xor ax, ax
clc
ret
ProcEnd noret
; STRATEGY VECTOR TABLE FUNCTIONS
; ===============================
;IN:
; DX holds the pointer to the first argument in 'p_iow(...)' call
; BX holds the address of the open channel control block
; CS:DI holds the address of status struc identifying the open channel
;
ProcBegin@ A4ExifRead,far
; ==========
; Strategy vector table function that handles asynchronous byte reads
; from the LEDs and switches.
; The corresponding PLIB call is p_ioc(pcb,P_FREAD,&Stat,&Arg1,&Arg2);
; The request is completed when the interrupt routine signals the
; handler which in turn signals the application passing back the values
; read at the time of the interrupt through the A1Ptr and A2Ptr.
; IN:
; Pointer to control block in applications data space in BX
; Pointer to control block in our CS space in DI
; A1 (pointer to Arg1) in DX
; OUT:
; Jumps to common exit point
; Panics if multiple requests
;
cmp [bx].A4ExifDSStatusPtr, 0 ;Panic if we already
jne PanicPending ;have an I/O read request
pushf ;pending on the channel
cli ;Disable interrupts
mov cs:[di].A4ExifCSChanReadCompleted, 2
mov ax, [si].RqA1Ptr
mov [bx].A4ExifDSA1Ptr, ax ;Store the locations to
mov ax, [si].RqA2Ptr ;put the data when we get it
mov [bx].A4ExifDSA2Ptr, ax
mov di, [si].RqStatusPtr
mov [bx].A4ExifDSStatusPtr, di ;DI holds the address
mov word ptr [di], PendingErr ;of status word and we
popf ;signal that we are waiting
mov bx, [bx].A4ExifDSHandlerPtr ;for completion of read
mov cl, 1
IoEnableHandler ;Enable Wait Handler
jmp short ExitStillPending ;No IoSignal because
PanicPending: ;we are still waiting
mov al, PanicIoPending
ProcPanic
ProcEnd noret
ProcBegin@ A4ExifWrite,far
; ===========
; This function sets the state of the LEDs.
; It completes immediately after setting the state as it has nothing
; to wait for.
; Write is the same as set.
; IN:
; Pointer to control block in applications data space in BX
; Pointer to control block in our CS space in DI
; A1 in DX
; OUT:
; Jumps to Set
;
jmp WriteAndSetAreTheSame
ProcEnd noret
ProcBegin@ A4ExifClose,far
; ===========
; Handles the request to close a channel.
; called by the PLIB call p_iow(pcb,P_FCLOSE) or p_close(pcb)
; IN:
; Pointer to control block in applications data space in BX
; Pointer to control block in our CS space in DI
; OUT:
; Jumps to common exit point
;
call StopTheChannelRunning ;Stop interrupts
if Asic9
push bx ;Close down the
mov bx, cs:[di].A4ExifCSTickHandle ;"TCK:" channel
IoClose
pop bx
endif
push bx
mov ax, [bx].A4ExifDSIo.ChanLibHandle ;Remove the wait
push ax ;handler
mov bx, [bx].A4ExifDSHandlerPtr
IoRemoveHandler
cmp cs:[di].A4ExifCSChanReadCompleted, 0 ;If the interrupt
je NoSignalToConsumeFromInterrupt ;has signalled the
IoWaitForSignal ;handler we need to
NoSignalToConsumeFromInterrupt: ;consume its signal
pop bx ;now the handler
mov cx, di ;has been removed
IoRequestResetCancel
pop bx ;No longer need reset
HeapFreeCell ;Free our control
mov al, cs:[di].A4ExifCSChannelIntMask ;block in app's DS
HwFreeChannel
mov cs:[di].A4ExifCSChannelOpen, 0
jmp ExitWithCompletionStatusZero ;To signal completion
ProcEnd noret ;of close request
ProcBegin@ A4ExifCancel,far
; ============
; Cancel any pending asynchronous read.
; Called by the PLIB function p_iow(pcb,P_FCANCEL);
; In:
; Pointer to control block in applications data space in BX
; Pointer to control block in our CS space in DI
; Out:
; Jumps to common exit point
;
pushf
cli
cmp [bx].A4ExifDSStatusPtr, 0 ;Check that there is
je NothingToCancel ;a request pending
push bx
mov bx, [bx].A4ExifDSHandlerPtr
sub cl, cl
IoEnableHandler ;Disable Wait Handler
pop bx
cmp cs:[di].A4ExifCSChanReadCompleted, 1
jne NoSignalFromInterrupt ;To consume any stray
IoWaitForSignal ;signal from the
NoSignalFromInterrupt: ;interrupt routine
mov cs:[di].A4ExifCSChanReadCompleted, 0
xor di, di ;To signal completion
xchg di, [bx].A4ExifDSStatusPtr ;of the outstanding
mov word ptr [di], CancelErr ;async read request
IoSignal ;Signal to p_waitstat
NothingToCancel:
popf
jmp ExitWithCompletionStatusZero ;To signal completion
ProcEnd noret ;of the cancel request
ProcBegin@ A4ExifSet,far
; =========
; Write a value to the LED latch.
; Can be called by the PLIB call p_iow(pcb,P_FSET,&Arg1); where A1
; is an unsigned byte.
; Write is the same as set.
; IN:
; Pointer to control block in applications data space in BX
; Pointer to control block in our CS space in DI
; A1 (pointer to Arg1) in DX
; OUT:
; Jumps to common exit point
;
WriteAndSetAreTheSame:
pushf
cli
mov al, cs:[di].A4ExifCSChannelSelect ;Select our SIBO
HwSelectChannel ;serial channel
push ax ;Store old channel
mov bx, dx
mov dl, U5OUTPUT_LATCH ;DX (now BX) points
mov al, [bx] ;to the value to
call OutputByte ;output to our
pop ax ;peripheral
HwSelectChannel ;Return old channel
popf
jmp ExitWithCompletionStatusZero ;To signal completion
ProcEnd noret ;of set request
ProcBegin@ A4ExifSense,far
; ===========
; Reads the state of the LEDS and Switches.
; Can be called from PLIB using p_iow(pcb,P_FSENSE,&Arg1,&Arg2)
; Where Arg1 and Arg2 are unsigned bytes.
; In:
; Pointer to control block in applications data space in BX
; Pointer to control block in our CS space in DI
; A1 (pointer to Arg1) in DX
; Out:
; Jumps to common exit point
;
pushf
cli ;Select our SIBO
mov al, cs:[di].A4ExifCSChannelSelect ;serial channel
HwSelectChannel ;Store old channel
push ax
mov bx, dx ;DX (now BX) points
mov dl, U4STATUS_BUFFER ;to the variable in
call InputByte ;which to place the
mov [bx], al ;value read from U4.
mov bx, [si].RqA2Ptr ;BX now points to
mov dl, U3INPUT_BUFFER ;the variable in
call InputByte ;which to place the
mov [bx], al ;value read from U3.
pop ax
HwSelectChannel ;Return old channel
popf
jmp ExitWithCompletionStatusZero ;To signal completion
ProcEnd noret ;of a sense request
; LOCAL DEVICE DRIVER FUNCTIONS
; =============================
ProcBegin@ InputByte
; =========
; Interrupts must be off prior to the call to this function.
; IN:
; DL has address to which Asic4 is to write
; AL holds the value to output
;
mov al, (SerialWriteSingle or A4Address)
SBUSY
SCONTOUT
mov al, dl
SBUSY
SDATAOUT
mov al, (SerialReadSingle or A4Data)
SBUSY
SCONTOUT
SBUSY
SDATAIN
ret
ProcEnd noret
ProcBegin@ OutputByte
; ==========
; Interrupts must be off prior to the call to this function.
; IN:
; DL has address to which Asic4 is to write
; AL has the value to output
;
push ax
mov al, (SerialWriteSingle or A4Address)
SBUSY
SCONTOUT
mov al, dl
SBUSY
SDATAOUT
mov al, (SerialWriteSingle or A4Data)
SBUSY
SCONTOUT
SBUSY
XNOP
pop ax
SDATAOUT
ret
ProcEnd noret
ProcBegin@ IntVec0,far
; ===========
; Interrupt on serial channel0
; Calls Comint with channel control block pointer in DI
;
mov di, offset Channel0
jmp ComInt
ProcEnd noret
if Corporate or S3c
ProcBegin@ IntVec1,far
; ===========
; Interrupt on serial channel1
; Calls Comint with channel control block pointer in DI
;
mov di, offset Channel1
jmp ComInt
ProcEnd noret
ProcBegin@ IntVec2,far
; ===========
; Interrupt on serial channel2
; Calls Comint with channel control block pointer in DI
;
mov di, offset Channel2
; FALL THROUGH
ProcEnd noret
endif
ProcBegin@ ComInt,far
; ==========
; The common interrupt service routine code.
; When an interrupt occurs, the first task is to read the status
; buffer of latch U4. The subsequent action is dependent on the
; postion of switches S1 and S2. For the purposes of this example,
; the four posibilities for the switch values correspond somewhat
; arbitrarily to four different byte values that are written to U5.
; in the 8086, interrupts cannot occur while in an interrupt routine.
; If an asynchronous read is pending then the handler is signalled.
; IN:
; Channel's CS based control block pointer in DI
;
cmp cs:[di].A4ExifCSChanReadCompleted, 2 ;Only if 2 do we have
jne NotAsynchronousRead ;asynch read completed
mov cs:[di].A4ExifCSChanReadCompleted, 1
mov bx, cs:[di].A4ExifCSProcessId ;Signals completion
IoSignalByPidNoReSched ;of read to OS so as
NotAsynchronousRead: ;to invoke handler
mov al, cs:[di].A4ExifCSChannelSelect
HwSelectChannel
push ax
mov dl, U3INPUT_BUFFER
call InputByte
mov cs:[di].A4ExifCSA2Value, al ;LED byte
mov dl, U4STATUS_BUFFER
call InputByte
mov cs:[di].A4ExifCSA1Value, al ;Status byte
and al, INTERRUPT_STATUS_MASK
xchg al, SwitchStatus
cmp SwitchStatus, S2S3_ON ;S2 and S3 on => turn
je AllLEDsOn ;on alternate LEDs
cmp SwitchStatus, S2S3_OFF ;S2 and S3 off => not
je AllLEDsOff ;the alternate LEDs
cmp SwitchStatus, S2_ONLY ;S2 on, S3 off => turn
je TopLEDsOn ;on top four LEDs
cmp SwitchStatus, S3_ONLY ;S3 on, S2 off => turn
je BottomLEDsOn ;on bottom four LEDs
ErrorInSwitchStatusByte:
jmp ClearInterruptAndReschedule
AllLEDsOn:
mov al, SOME_LEDS_ON
jmp OutputLEDByte
AllLEDsOff:
mov al, SOME_LEDS_OFF
jmp OutputLEDByte
TopLEDsOn:
mov al, TOP_LEDS_ON
jmp OutputLEDByte
BottomLEDsOn:
mov al, BOTTOM_LEDS_ON
OutputLEDByte:
mov dl, U5OUTPUT_LATCH
call OutputByte
ClearInterruptAndReschedule:
mov dl, INTERRUPT_LATCH
call OutputByte
if Asic9 ;A write to this location
out A9BNonSpecificEoiW, al ;informs the interrupt
else ;controller that the
out A1NonSpecificEoi, al ;installed interrupt
endif ;service routine has
pop ax ;finished
HwSelectChannel
clc ;Reschedule if necessary
ret
ProcEnd noret
ProcBegin@ StartInterrupts
; ===============
; Start interrupts assuming interrupts are
; off prior to call.
; The EPOC GenSetRevector service loads in
; a user-specified interrupt service routine
; located at the address given in cx:bx
; (segment cx, offset bx) for the interrupt
; vector number given in AL. Note that the
; variable A4ExifCSChannelIntVec holds the
; name of the appropriate required interrupt
; vector routine for the channel.
; IN:
; Our CS control block pointer in DI
; OUT:
; Nothing
;
mov al, cs:[di].A4ExifCSChannelIntNum ;Get the OS to call
mov cx, cs ;the function in
push bx ;CS:BX every time
mov bx, cs:[di].A4ExifCSChannelIntVec ;that the interrupt
GenSetRevector ;whose number is in
pop bx ;AL occurs
ife Asic9
in al, A1InterruptMask
or al, cs:[di].A4ExifCSChannelIntMask ;Set the mask
out A1InterruptMask, al ;location so as ;interrupt
else ;to enable that
in al, A9BInterruptMaskRW ;interrupt
or al, cs:[di].A4ExifCSChannelIntMask
out A9BInterruptMaskRW, al
endif
ret
ProcEnd noret
ProcBegin@ StopInterrupts
; ==============
; Stop interrupts assuming that interrupts are off
; The EPOC GenResetRevector OS service
; replaces the previously loaded user-specified
; interrupt service routine with the original
; routine and interrupt mask for the vector
; given in AL.
; IN:
; Our CS control block pointer in DI
; OUT:
; Nothing
;
ife Asic9
in al, A1InterruptMask ;Disable the
mov ah, cs:[di].A4ExifCSChannelIntMask ;interrupt
not ah
and al, ah
out A1InterruptMask, al
else
in al, A9BInterruptMaskRW
mov ah, cs:[di].A4ExifCSChannelIntMask
not ah
and al, ah
out A9BInterruptMaskRW, al
endif
mov al, cs:[di].A4ExifCSChannelIntNum ;Return the interrupt
GenResetRevector ;vector to the OS
ret ;default
ProcEnd noret
ProcBegin@ StartTheChannelRunning
; ======================
; Starts the hardware and interrupts going
; If the hardware is aready running then there is nothing to do
; Must check that the hardware has not vanished before restarting it
; IN:
; Our CS control block pointer in DI
; OUT:
; Nothing
;
pushf
cli
cmp byte ptr cs:[di].A4ExifCSChannelRunning, 0
jne ChannelAlreadyRunning
call CheckHardwarePresent
jc HardwareNotPresent
mov al, cs:[di].A4ExifCSChannelSelect
HwSelectChannel
push ax
mov al, (SerialWriteSingle or A4Control) ;Switch on the
SBUSY ;output latch U5
SCONTOUT ;by asserting
mov al, U5_ENABLE_ON ;the ASIC4 LBO line
SBUSY ;(LBO is inverted)
SDATAOUT
xor ax,ax
mov dl, INTERRUPT_LATCH ;Clear any pending
call OutputByte ;interrupt on the
mov dl, U5OUTPUT_LATCH ;peripheral
call OutputByte ;Preset the LEDs
pop ax ;to all off
HwSelectChannel
call StartInterrupts
mov cs:[di].A4ExifCSChannelRunning, 1
ChannelAlreadyRunning:
popf
clc
ret
HardwareNotPresent:
popf
stc
ret
ProcEnd noret
ProcBegin@ StopTheChannelRunning
; =====================
; Stops the hardware and interrupts
; Checks to see if the hardware is really running to start with
; IN:
; Our CS control block pointer in DI
; OUT:
; Nothing
;
pushf
cli
cmp byte ptr cs:[di].A4ExifCSChannelRunning, 0
je ChannelNotRunning
mov al, cs:[di].A4ExifCSChannelSelect
HwSelectChannel
push ax
mov al, (SerialWriteSingle or A4Control)
SBUSY
SCONTOUT
mov al, U5_ENABLE_OFF
SBUSY
SDATAOUT
xor ax, ax
mov dl, U5OUTPUT_LATCH
call OutputByte
pop ax
HwSelectChannel
call StopInterrupts
mov cs:[di].A4ExifCSChannelRunning, 0
ChannelNotRunning:
popf
ret
ProcEnd noret
ProcBegin@ CheckHardwarePresent
; ====================
; Used to determine whether the correct hardware is present
; on the successfully procured serial channel.
; IN:
; CS control block pointer in DI
; OUT:
; Carry clear - correct hardware is there
; Carry set - wrong or no hardware
;
pushf
cli ;Select the correct
mov al, cs:[di].A4ExifCSChannelSelect ;SIBO channel that
HwSelectChannel ;the peripheral is
push ax ;attached to
HwNullFrame
mov al,(SerialSelect or Asic4Id)
SBUSY ;First look for an
SCONTOUT ;ASIC4 at the other
XNOP ;end of the link
SBUSY
SDATAIN ;If the returned
test al,al ;value is non-zero
je ConnectionFailedA4NotPresent ;we have an ASIC4
mov al,(SerialReadSingle or A4InfoR)
SBUSY ;Now see if we have
SCONTOUT ;the right peripheral
XNOP ;XNOP allows the busy
SBUSY ;signal to come
SDATAIN ;through for the wait
and al, A4PERIPH_MASK
cmp al, EXTENDED_INFO_BYTE ;Mask out the bottom
jne ConnectionFailed ;four bits as the
pop ax ;upper four contain
HwSelectChannel ;the peripheral ID
popf
clc ;If it is our hardware
ret ;exit with carry clear
ConnectionFailedA4NotPresent:
mov al,(SerialSelect or Asic5NormalId) ;Its not an ASIC4
SBUSY ;peripheral
SCONTOUT ;By selecting a non
XNOP ;ASIC4 as an ASIC4,
SDATAIN ;we effectively
test al,al ;disable whatever is
jne ConnectionFailed ;out there so we do
mov al,(SerialSelect or Asic5PackId) ;a select for all
SBUSY ;possibilities so
SCONTOUT ;that we don't end
XNOP ;up disabling
SDATAIN ;anything that we
test al,al ;can't control.
jne ConnectionFailed
mov al,(SerialSelect or Asic8Id) ;Modem chip id
SBUSY
SCONTOUT
XNOP
SDATAIN
ConnectionFailed:
pop ax
HwSelectChannel
popf
stc
ret
ProcEnd noret
EndCodeSeg
stack segment stack para 'data'
stack ends
end A4ExifLDD