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