title AS5PDD Epoc Serial physical device driver for the 16550 subttl Copyright Psion PLC 1993 name SYS$AS5 ; VERSION DATE DESCRIPTION ; ------- -------- --------------- ; 1.0 08/12/94 Initial version ; Written by Jason December 1994 ; Serial Driver for Epoc based around ASIC5 Sr5S3 = 0 Sr5S3a = 1 ifdef BUILDS3 Sr5S3 = 1 Sr5S3a = 0 BUILDHH equ 1 endif if Sr5S3a BUILDSB equ 1 endif include ..\inc\epoc.inc include ..\inc\epocser.inc include ..\inc\epoclib.inc include ..\inc\epocsibo.inc include ..\srcs\ossibo.inc include ..\srcs\ospack.inc Sr5ChannelStruct struc Sr5Open db ? ; Is the channel open Sr5Ctrl db ? ; State of control lines Sr5IntVector db ? ; The Vector number Sr5Channel db ? ; Which channel are we Sr5Mask db ? ; InterruptMask Sr5Running db ? ; Are we running Sr5IntRoutineVec dw ? ; Vector to Interrupt Sr5Baud dw ? ; The baud rate Sr5LddData dw ? ; Info from Ldd above Sr5StatusInt dd ? ; Vectors in serial Sr5RecvInt dd ? ; Above to be called Sr5XmitInt dd ? ; On input/output Sr5ClockEnable db ? ; Reason to stop Sr5TheLines db ? ; State of the modem lines Sr5ChannelStruct ends A5Ent struc ; ASIC5 Read/Write A5PortA db ? ; Port A R/W A5PortB db ? ; Port B R/W A5PortBMode db ? ; Inc/Mode A5PortD db ? ; Port CD Write only A5Swipe1 db ? A5Swipe2 db ? A5IntMask db ? ; Interrupt mask R/W A5CtrlReg db ? ; IntType/Ctrl register A5USR db ? ; UART Status/Ctrl A5RHR db ? ; Receive/Transmit A5BDLSB db ? ; Baud Rate write only A5BDMSB db ? ; Baud Rate write only A5MCR1Eoi db ? ; MCR shift register A5MCRPresentEoi db ? ; Barcode data&ints A5MCR2Eoi db ? A5DUMMYF db ? A5Ent ends if Consumer NumberOfChannels equ 1 ; S3 Single Channel else NumberOfChannels equ 3 ; HC,S3C Three Channel endif OsActivityMeter equ 158ch ; Activity Channel StopTimeOut equ 1000 ; ~1s (1000ms) wait S_RS232ON equ 00000001b ; RS232 on S_RSTTLON equ 00000100b ; Line drivers on S_CENTON equ 00010000b ; Line drivers enable S_RXENB equ 00000001b ; Receive interrupt on S_TXENB equ 00000010b ; Transmit interrupt on S_TXEMPTY equ 00010000b ; transmit buffer empty S_RXINT equ 00000001b ; Receive interrupt? S_TXINT equ 00000010b ; transmit interrupt? S_MDINT equ 00000100b ; Modem status interrupt S_CTS equ 00000001b ; CTS S_RTS equ 00000010b ; RTS S_DCD equ 00000100b ; DCD S_DSR equ 00000010b ; DCR S_DTR equ 00000100b ; DTR OVERRUN_ERROR equ 01000000b ; Character overrun PARITY_ERROR equ 10000000b ; Parity error S_PERIPHERALMODE equ 00000011b ; ASIC5 RS232 mode S_UART_OFF equ 00000010b ; ASIC5 peripheral mode dgroup group stack assume ds:dgroup,es:dgroup,ss:dgroup CodeSeg ProcBegin@ OsAS5PDD ; ==================== dw PDDSignature db 'TTY.SR5',0 dw (VectorEnd-Vector)/2 Vector: dw OsAS5Install dw OsAS5Remove dw OsAS5Open dw OsAS5Strategy VectorEnd: BaudRateTable dw -077fh,-04ffh,-0368h,-02cch,-027fh,-013fh dw -009fh,-004fh,-0035h,-0030h,-0027h,-0019h dw -0013h,-000ch,-0009h,-0004h DataBitsTable db 0,2,4,6 ; 5,6,7,8 bits per char frame ParityTable db 08h,18h,0h,0h ; Even,Odd,Mark,Space parity Chan0 Sr5ChannelStruct <> Chan1 Sr5ChannelStruct <> Chan2 Sr5ChannelStruct <> if Consumer if Asic9 SetupTable dw offset AS5Int1 db HwIrq2Revector,mask A9MSlave db SelectChannel5,(mask A9MClockEnable5 shr 8) else SetupTable dw offset AS5Int1 db HwIrq4Revector,mask Asic2Int db SelectChannel7,(mask ClockEnable7 shr 8) endif else if Asic9 SetupTable dw offset AS5Int1 db HwIrq4Revector,mask A9MExpIntA db SelectChannel3,(mask A9MClockEnable3 shr 8) dw offset AS5Int2 db HwIrq5Revector,mask A9MExpIntB db SelectChannel4,(mask A9MClockEnable4 shr 8) dw offset AS5Int3 db HwIrq2Revector,mask A9MSlave db SelectChannel5,(mask A9MClockEnable5 shr 8) else SetupTable dw offset AS5Int1 db HwIrq3Revector,mask ExpIntLeftA db ExpChannelLeftA,(mask ClockEnable6 shr 8) dw offset AS5Int2 db HwIrq2Revector,mask ExpIntRightB db ExpChannelRightB,(mask ClockEnable5 shr 8) dw offset AS5Int3 db HwIrq4Revector,mask Asic2Int db SelectChannel7,(mask ClockEnable7 shr 8) endif endif ProcEnd noret ProcBegin@ OsAS5Install,far ; ============================ ; Install the device driver ; Out: Carry clear -happy to install cld ; Clear the channels mov cx, NumberOfChannels ; and set up fixed mov di, offset Chan0 ; parameters such mov si, offset SetupTable ; as the interrupt pushf ; vectors and masks cli ; for each channel push ds mov ax, cs mov ds, ax ResetAllChannelsLoop: mov [di].Sr5Open, 0 ; Channel not open lodsw mov [di].Sr5IntRoutineVec, ax ; Set the interrupt lodsb ; handler to call mov [di].Sr5IntVector, al ; Which Interrupt lodsb mov [di].Sr5Mask, al ; Mask for that lodsb ; interrupt mov [di].Sr5Channel, al ; Which Psion serial lodsb ; channel mov [di].Sr5ClockEnable, al ; Baud rate clocking add di, size Sr5ChannelStruct ; enable loop ResetAllChannelsLoop pop ds popf AllChannelsOkay: clc ; Returns with ret ; Carry clear ProcEnd noret ProcBegin@ OsAS5Remove,far ; ========================== ; Remove the device driver ; Out: Carry clear -happy to remove ; Carry set -we have an open channel and cant be removed. xor ax, ax ; If we have a or al, Chan0.Sr5Open ; channel Still open or al, Chan1.Sr5Open ; then return a can't or al, Chan2.Sr5Open ; do error else jz AllChannelsOkay ; complete okay mov ax, InUseErr stc ret ProcEnd noret ProcBegin@ OsAS5Open,far ; ======================== ; Open a serial channel ; In: SS:SI is a pointer to the open Ent Structure ; Out: Carry clear, control block in BX ; Carry set, error in AX cld mov si, [si].OpenNamePtr ; Open the channel mov al, [si+1] ; Get the channel CharToFoldedChar ; Make Upper Case cmp al, 'A' ; Indicator which is jb ErrorInOpen ; Part of the name sub al, 'A' ; Should be A,B,C cmp al, NumberOfChannels jae ErrorInOpen xor ah, ah mov bx, offset Chan0 ; What Channel are cmp al, 1 ; We Openning jb GotChan ; Pointer to Control mov bx, offset Chan2 ; Block in bx ja GotChan mov bx, offset Chan1 GotChan: mov al, 1 xchg al, cs:[bx].Sr5Open cmp al, 0 ; Now try to Open je OkayToOpen ; That channel CantOpen: mov ax, InUseErr CantOpenDiffErr: stc ret ErrorInOpen: mov ax, NameErr stc ret OkayToOpen: xor al, al mov cs:[bx].Sr5Running, al mov cs:[bx].Sr5TheLines, al mov cs:[bx].Sr5Ctrl, al mov al, cs:[bx].Sr5Mask HwGetChannel jc CantOpenSoClose ; Check that we have call CheckHardwarePresent ; The right Hardware jnc OpenedOkay mov al, cs:[bx].Sr5Mask HwFreeChannel CantOpenSoClose: mov cs:[bx].Sr5Open, 0 mov ax, DeviceErr jmp short CantOpenDiffErr ; Return with the OpenedOkay: ; Offset of our xor ax, ax ; Control Block ret ; In bx ProcEnd noret AS5StrategyJumpTable label word dw offset AS5Open ; Load Handler offsets dw offset AS5Close ; Close the channel dw offset AS5Start ; Start the channel dw offset AS5Stop ; Stop the channel dw offset AS5Set ; Does nothing dw offset AS5Sense ; Returns chan status dw offset AS5Control ; Drive the lines dw offset AS5Enquire ; Returns baud rate dw offset AS5Enable ; Begin Output dw offset AS5SetHandlerCS ; Get Handler segments ProcBegin@ OsAS5Strategy,far ; ============================= ; Strategy functions entry point ; Warning! This can be called from within Interrupt ; In: vector number in AX + various data in other registers ; DS is OsDataGroup (and MUST be preserved) ; Out: DI is pointer to control block ; Old channel and flags on stack cld mov bx, sp mov bx, ss:[bx+4] mov bl, cs:[bx].Sr5Channel ; Select the correct xchg bx, ax ; Output channel pushf ; Then Call the right cli ; Function to deal HwSelectChannel ; With the strategy mov ah, bh ; request xor bh, bh push ax ; Interrupts off mov ax, di ; and flags are on mov di, sp ; the stack mov di, ss:[di+8] jmp AS5StrategyJumpTable[bx] ProcEnd noret ProcBegin@ AS5Open,far ; ====================== ; Old channel and flags on the stack, interrupts off mov cs:[di].Sr5LddData, cx ; Load the offsets of mov word ptr cs:[di].Sr5StatusInt, ax ; the data send and mov word ptr cs:[di].Sr5RecvInt, si ; recieve routines in mov word ptr cs:[di].Sr5XmitInt, dx ; the Ldd above us xor dx, dx ; DX=0 -We don't support pop ax ; power management HwSelectChannel ; Return the old popf ; channel ret ProcEnd noret ProcBegin@ AS5Close,far ; ======================= ; Old channel and flags on the stack, interrupts off and cs:[di].Sr5Open, 0 ; Close the Channel mov al, cs:[di].Sr5Mask ; Free up our channel HwFreeChannel ; And the Hardware pop ax ; Channel HwSelectChannel ; Return the old popf ; channel ret ProcEnd noret ProcBegin@ AS5Start,far ; ======================= ; Old channel and flags on the stack, interrupts off call CheckHardwareFromStart mov dx, 0 jc CantStartSomethingWhichIsntThere if Asic9 in ax, A9WControlExtraRW ; Start the S3s clock or ah, cs:[di].Sr5ClockEnable ; Generator out A9WControlExtraRW, ax else mov al, cs:[di].Sr5ClockEnable HwSetA2Control2Bits endif mov al, SerialWriteSingle or A5USR ; Set the baud rate SBUSY ; and other SCONTOUT ; characteristics mov al, cs:[di].Sr5Ctrl SBUSY SDATAOUT mov al, SerialWriteSingle or A5BDLSB SBUSY SCONTOUT mov al, byte ptr cs:[di].Sr5Baud SBUSY SDATAOUT mov al, SerialWriteSingle or A5BDMSB SBUSY SCONTOUT mov al, byte ptr cs:[di+1].Sr5Baud SBUSY SDATAOUT call GetTheInterrupt ; Get the interrupt xor cx, cx ; and clear down call DriveRts ; the RTS line (DTR ; stays at the state mov al, SerialWriteSingle or A5CtrlReg ; it was set) SBUSY SCONTOUT mov al, (S_CENTON or S_RS232ON or S_RSTTLON) SBUSY SDATAOUT ; Switch on the line mov cx, 8 ; 8 ms ; drivers and wait pop dx ; for them to power up call WaitTimer push dx mov ah, (S_RXENB or S_TXENB or S_MDINT) ; Start all interrupts call EnableTheInterrupt mov cs:[di].Sr5Running, 1 mov bx, Asic5SerialCurrent HwSetPCurrent call Status CantStartSomethingWhichIsntThere: pop ax ; Return the old HwSelectChannel ; channel popf ret ProcEnd noret ProcBegin@ AS5Stop,far ; ======================= ; Old channel and flags on the stack, interrupts off xor cx, cx ; Clear the state of call DriveRts ; the modem lines mov al, SerialReadSingle or A5IntMask ; Stop all of the SBUSY ; interrupts SCONTOUT XNOP SBUSY SDATAIN and al, not (S_TXENB or S_RXENB or S_MDINT) mov ah, al mov al, SerialWriteSingle or A5IntMask SBUSY SCONTOUT mov al, ah SBUSY SDATAOUT pop dx cmp dh, DevHoldPowerFail je DontStopHardware cmp cs:[di].Sr5Running, 1 jne DontWait mov cx, StopTimeOut jmp short CompareNow WaitForEmpty: call TickTimer CompareNow: mov al, SerialReadSingle or A5USR SBUSY SCONTOUT XNOP SBUSY SDATAIN test al, S_TXEMPTY loopne WaitForEmpty DontWait: cmp bh,DevHoldNormal je DontStopHardware if Asic9 mov cl, cs:[di].Sr5ClockEnable ; Turn off baud rate not cl ; clocking from the in ax, A9WControlExtraRW ; S3/3a and ah, cl out A9WControlExtraRW, ax else mov al, cs:[di].Sr5ClockEnable HwClearA2Control2Bits endif mov al, SerialWriteSingle or A5CtrlReg ; Stop the drivers SBUSY ; and stuff SCONTOUT sub al, al ; clear S_CENTON, SBUSY ; S_RS232ON, S_RSTTLON SDATAOUT DontStopHardware: mov al, dl ; Return the old HwSelectChannel ; channel popf xor bx, bx HwSetPCurrent ret ProcEnd noret ProcBegin@ AS5Set,far ; ===================== ; Old channel and flags on the stack, interrupts off ; In: Information required is on the stack pop ax ; Return the old HwSelectChannel ; channel popf mov ah, ss:[si].SerialCharTbaud ; Set the Recieve, cmp ah, ss:[si].SerialCharRbaud ; Transmit characteristics jnz ErrorInSet ; First set the Baud cmp ah, P_BAUD_50 ; Rate jb ErrorInSet cmp ah, P_BAUD_19200 ja ErrorInSet GotTheSpecialBaud: dec ah mov cl, ss:[si].SerialCharFrame ; Then the number of mov al, ss:[si].SerialCharParity ; Stop bits dec al xor ch, ch push bx test cl, P_TWOSTOP jz OnlyOneStopBit or ch, 020h OnlyOneStopBit: test cl, P_PARITY ; The Parity jz NoParity mov bx, offset ParityTable xlat cs:[ParityTable] or ch, al NoParity: mov bx, offset DataBitsTable ; And finally the and cl, P_DATA_FRM ; Number of data bits mov al, cl ; Per frame xlat cs:[DataBitsTable] or ch, al mov bx, offset BaudRateTable mov al, ah xor ah, ah shl ax, 1 add bx, ax mov ax, cs:[bx] pop bx mov cs:[di].Sr5Ctrl, ch mov cs:[di].Sr5Baud, ax xor al, al ret ErrorInSet: mov al, NotSupportedErr stc ret ProcEnd noret ProcBegin@ AS5Sense,far ; ======================= ; Old channel and flags on the stack, interrupts off ; Out: The state of the DCD,CTS,DSR lines returned in DX call Status pop ax ; Return the old HwSelectChannel ; channel popf ret ProcEnd noret ProcBegin@ Status ; ================= ; Out: State of modem lines in DX mov al, SerialReadSingle or A5USR ; Get the current SBUSY ; Modem status SCONTOUT ; Lines and return XNOP ; With the result SBUSY ; In dx SDATAIN and al, (S_CTS or S_DSR or S_DCD) ; Get the lines we want xor al, (S_CTS or S_DSR or S_DCD) ; Invert signals xor ah, ah mov dx, ax ret ProcEnd noret ProcBegin@ AS5Control,far ; ========================= ; Old channel and flags on the stack, interrupts off ; In: Lines to drive and state to drive them in DX mov cl, dl ; Set the state of one test dh, P_SRCTRL_DTR ; of the modem Lines jz DriveRtsNow ; DH is the line to call DriveDtr ; Drive and DL is the pop ax ; State to drive it to HwSelectChannel ; Return the old popf ; channel ret DriveRtsNow: call DriveRts pop ax ; Return the old HwSelectChannel ; channel popf ret ProcEnd noret ProcBegin@ DriveDtr ; =================== mov ah, S_DTR ; Set/Reset the DTR jmp short DriveTheLine ; Line ProcEnd noret ProcBegin@ DriveRts ; =================== mov ah, S_RTS ; Set/Reset RTS DriveTheLine: mov al, SerialWriteSingle or A5PortD ; Common code to set SBUSY ; and reset either SCONTOUT ; line while mov al, cs:[di].Sr5TheLines ; preserving the test cl, cl ; states of the other jz ClearLine ; lines or al, ah jmp DoTheOutput ClearLine: not ah and al, ah DoTheOutput: mov cs:[di].Sr5TheLines, al SBUSY SDATAOUT ret ProcEnd noret ProcBegin@ AS5Enquire,far ; ========================= ; Old channel and flags on the stack, interrupts off ; Out: DX,AX are the supported baud rates AX for 50 to 19200 DX for above ; CX says what data bits, parity, etc we support pop ax ; Return the old HwSelectChannel ; channel popf if Asic9 mov ax, -1 else mov ax, 07fffh endif xor dx, dx mov cx, (0ffffh AND (NOT (P_SRINQ_SPLIT OR P_SRINQ_PARSPACE OR P_SRINQ_PARMARK))) ret ProcEnd noret ProcBegin@ AS5Enable,far ; ======================== ; Old channel and flags on the stack, interrupts off mov ah, S_TXENB ; Begin Output by call EnableTheInterrupt ; enabling transmit pop ax ; interrupts HwSelectChannel ; Return the old popf ; channel ret ProcEnd noret ProcBegin@ AS5SetHandlerCS,far ; ============================== ; Old channel and flags on the stack, interrupts off ; CX is CS of above LDD mov word ptr cs:[di].(Sr5StatusInt+2), cx ; Load the Segment mov word ptr cs:[di].(Sr5RecvInt+2), cx ; Within which the mov word ptr cs:[di].(Sr5XmitInt+2), cx ; The Ldd above us pop ax ; Return the old HwSelectChannel ; channel popf ; Resides ret ProcEnd noret ProcBegin@ AS5Int3,far ; ====================== mov di, offset Chan2 ; Channel 3 interrupt mov ax, PortCActive ; vector jmp ComInt ; Jumps to Comint ProcEnd noret ProcBegin@ AS5Int2,far ; ====================== mov di, offset Chan1 ; Channel 2 interrupt mov ax, PortBActive ; vector jmp ComInt ; Jumps to Comint ProcEnd noret ProcBegin@ AS5Int1,far ; ====================== mov di,offset Chan0 ; Channel 1 interrupt mov ax,PortAActive ; vector ; FALL THROUGH ; Falls through ProcEnd noret ; to Comint ProcBegin@ ComInt,far ; ===================== ; The common interrupt handler ; DS points to OS data space ; DI is our control block ; AX is the Active channel if S3b or S3c or ds:[OsActivityMeter], ax ; Set active state endif mov al, cs:[di].Sr5Channel ; Select our HwSelectChannel ; channel push ax mov bx, cs:[di].Sr5LddData ; Data for LDD above TheInterruptLoop: ; in bx mov al, SerialReadSingle or A5CtrlReg ; Find out what SBUSY ; caused the SCONTOUT ; interrupt XNOP SBUSY SDATAIN test al, al je NothingToDo HaveWeGotAModemStatusLineInterrupt: test al, S_MDINT jz HaveWeGotARecieveInterrupt mov al, SerialReadSingle or A5USR SBUSY SCONTOUT XNOP SBUSY SDATAIN test al, (OVERRUN_ERROR or PARITY_ERROR) jz ModemStatusInterruptOnly push ax ; Something has been mov ah, SERPARITY_ERR ; recieved in error test al, PARITY_ERROR jnz IsAParityError ; Establish the error mov ah, SEROVERRUN_ERR IsAParityError: mov al, SerialReadSingle or A5RHR ; Get the character SBUSY ; in question SCONTOUT XNOP SBUSY SDATAIN push di call dword ptr cs:[di].Sr5RecvInt pop di pop ax ModemStatusInterruptOnly: and ax, (S_CTS or S_DSR or S_DCD) xor al, (S_CTS or S_DSR or S_DCD) ; invert signals mov dx, ax push di call dword ptr cs:[di].Sr5StatusInt pop di jmp short TheInterruptLoop HaveWeGotARecieveInterrupt: test al, S_RXINT jz HaveWeGotATransmitInterrupt mov al, SerialReadSingle or A5RHR SBUSY SCONTOUT XNOP SBUSY SDATAIN xor ah, ah ; AX has character received push di call dword ptr cs:[di].Sr5RecvInt pop di jmp short TheInterruptLoop HaveWeGotATransmitInterrupt: test al, S_TXINT jz NothingToDo push di call dword ptr cs:[di].Sr5XmitInt pop di test ax, ax ; -1 if disable js DisableTransmitInts mov ah, al mov al, SerialWriteSingle or A5RHR SBUSY SCONTOUT mov al, ah SBUSY SDATAOUT jmp TheInterruptLoop NothingToDo: if Asic9 out A9BNonSpecificEoiW,al else out A1NonSpecificEoi, al endif pop ax HwSelectChannel clc ; Resced if neccessary ret DisableTransmitInts: ; disable TX interrupts mov al, SerialReadSingle or A5IntMask SBUSY SCONTOUT XNOP SBUSY SDATAIN and al, not S_TXENB mov ah, al mov al, SerialWriteSingle or A5IntMask SBUSY SCONTOUT mov al, ah SBUSY SDATAOUT jmp TheInterruptLoop ProcEnd noret ProcBegin@ GetTheInterrupt ; ========================== mov al, cs:[di].Sr5IntVector ; Load the address of mov cx, cs ; the appropriate mov bx, cs:[di].Sr5IntRoutineVec ; interrupt routine GenSetRevector ; into the correct ret ; vector ProcEnd noret ProcBegin@ EnableTheInterrupt ; ============================= mov al, SerialReadSingle or A5IntMask SBUSY SCONTOUT XNOP SBUSY SDATAIN or ah, al mov al, SerialWriteSingle or A5IntMask SBUSY SCONTOUT mov al, ah SBUSY SDATAOUT if Asic9 in al,A9BInterruptMaskRW ; Set the mask or al, cs:[di].Sr5Mask ; to enable Interrupts out A9BInterruptMaskRW,al else in al, A1InterruptMask or al, cs:[di].Sr5Mask out A1InterruptMask, al endif ret ProcEnd noret ProcBegin@ StopInterrupts ; ========================= mov al, SerialReadSingle or A5IntMask ; Stop interrupts SBUSY ; from Asic5 SCONTOUT XNOP SBUSY SDATAIN and al, not (S_RXENB or S_TXENB or S_MDINT) mov ah, al mov al, SerialWriteSingle or A5IntMask SBUSY SCONTOUT mov al, ah SBUSY SDATAOUT mov ah, cs:[di].Sr5Mask 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].Sr5IntVector GenResetRevector ret ProcEnd noret ProcBegin@ CheckHardwarePresent ; =============================== pushf cli mov al, cs:[bx].Sr5Channel ; Check that the HwSelectChannel ; Harware is there HwNullFrame ; And that it is what mov al,(SerialSelect or Asic5NormalId) ; It should be SBUSY ; First look for An SCONTOUT ; ASIC4 at the other XNOP ; End of the link SBUSY SDATAIN 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 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: popf stc ret ProcEnd noret ProcBegin@ CheckHardwareFromStart ; ================================= pushf HwNullFrame ; Check that the mov al,(SerialSelect or Asic5NormalId) ; Harware is there SBUSY ; First look for An SCONTOUT ; ASIC5 at the other XNOP ; End of the link SBUSY SDATAIN test al,al je ConnectionFailed ; If not a 3link or test al, mask A5MultiDrop ; if in multidrop jne ConnectionFailedExit ; mode then we are popf ; in trouble mov al, SerialWriteSingle or A5PortBMode SBUSY SCONTOUT ; Put the 3Link in mov al, S_PERIPHERALMODE ; peripheral mode SBUSY SDATAOUT clc ret ProcEnd noret ProcBegin@ WaitTimer ; ==================== ; In: CX number of ms to wait for ; Channel store in DL ; Out: Channel store in DL inc cx ; Wait for a given WaitTickLoop: ; Number of ms call TickTimer ; Plus one to guarantee loop WaitTickLoop ; That at least cx ms ret ; Go by ProcEnd ; ProcBegin@ TickTimer ; ==================== ; Uses writes down our channel to simulate tick timer waits ; Must allow interrupts so other things can run -we will be here ; for 1/1000 of a second and may be called many times ; ChannelStore in/out in DL mov al, dl ; Return the old HwSelectChannel ; channel mov ah, al pushf sti push cx mov cx, 12 ; 1ms WaiterLoop: ; 128 frames =1ms pushf ; about 12 times cli ; round the loop out ResetWatchDog,al mov al, ah HwSelectChannel mov dl, al ; Get Correct channel mov al, (SerialWriteSingle or 0) ; Do a write to SBUSY ; nowhere and SCONTOUT ; waste some time SBUSY SCONTOUT ; Do it eight times SBUSY SCONTOUT SBUSY SCONTOUT SBUSY SCONTOUT SBUSY SCONTOUT SBUSY SCONTOUT SBUSY SCONTOUT SBUSY mov al, dl ; Return the old HwSelectChannel ; channel mov ah, al popf loop WaiterLoop pop cx popf mov al, ah HwSelectChannel mov dl, al ret ProcEnd EndCodeSeg stack segment stack para 'data' stack ends end OsAS5PDD