                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Module: Command_Driver 0
;>
;>      This module controls the way in which commands received by
;>      the Host are executed. It's main responsibility is to determine
;>      whether a command string is protected by a check byte ( the
;>      original Profile commands are not ) and then decode the command
;>      and pass control over to the correct driver routine to
;>      execute the command. All exception handling at this level is
;>      controlled by the individual command routines.
;>
;>      PORCEDURE Read_ID
;>      PROCEDURE Read_SprTbl
;>      PROCEDURE Pro_Write
;>      FUNCTION Wr_Common : BOOLEAN
;>      PROCEDURE Pro_WrVer
;>      FUNCTION WrVer_Common : BOOLEAN
;>
;>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Read_ID
;>
;>      This procedure is responsible for letting the host system
;>      know what type of device it is talking to.
;>
;>      Inputs: { none }
;>
;>      Output: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       ClrNormStat
;>       Zero_RdBuf
;>       ID.DeviceName := DeviceName
;>       ID.DeviceNumber := DeviceNumber
;>       ID.Revision := RevisionNumber
;>       ID.Capacity := Capacity
;>       ID.BlockSize := BlockSize
;>       Move4( StatusArray, Status )
;>       Goto Rd_Leave
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN
                
D_Read_ID:
                Call    ClrNormStat
                 Ld     Wrk_Io+$A,#D_R_ID_Response
                Call    Ack_Read

Read_ID:         Ld     !r2,#.HIBYTE. Zero_RdBuf
                 Ld     !r3,#.LOWBYTE. Zero_RdBuf
                Call    Bank_Call
                
                Ld      !rC,#.HIBYTE. RBuffer1
                Ld      !rD,#.LOWBYTE. RBuffer1
                Ld      !rE,#.HIBYTE. DeviceParams
                Ld      !rF,#.LOWBYTE. DeviceParams
                Ld      !r1,#Dev_Parm_Length
                
Read_ID_Lp:     Ldc     !r0,@!!rE
                Lde     @!!rC,!r0
                Incw    !!rC
                Incw    !!rE
                Djnz    !r1,Read_ID_Lp
                
                Clr     !r0
                Clr     !r1
                
                 Ld     !rE,#.HIBYTE. SprCount
                 Ld     !rF,#.LOWBYTE. SprCount
                 Lde    !r2,@!!rE ;get SpareCount
                Call    MoveI_3
                
                 Incw   !!rE ;point to BadBlock count
                 Lde    !r2,@!!rE
                Call    MoveI_3
                
                 Ld     !r2,#.HIBYTE. FmtOffset
                 Ld     !r3,#.LOWBYTE. FmtOffset
                 Ld     !rE,!rC
                 Ld     !rF,!rD
                Call    Move4_B0
                
                Jp      Rd_Leave
                
MoveI_3:        Ld      !r3,#3 ;move 3 bytes
                Ld      !r4,Rp
MoveI_3_Lp:     Ldei    @!!rC,@!r4
                Djnz    !r3,MoveI_3_Lp
                Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Read_SprTbl
;>
;>      This procedure is responsible for passing the spare
;>      table on to the host. Note that this information is
;>      sent in it's raw form and that it is up to the host
;>      to correctly interpret it.
;>
;>      Inputs: { none }
;>
;>      Output: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       RBuffer1 := SpareArray
;>       Move4( StatusArray, Status )
;>       Clr_Bsy( StatusArray )
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN
                
D_Read_SprTbl:
                Call    ClrNormStat
                Ld      Wrk_Io+$A,#D_R_Spr_Response
                Call    Ack_Read

Read_SprTbl:     Ld     !r2,#.HIBYTE. Spr_To_RBuf
                 Ld     !r3,#.LOWBYTE. Spr_To_RBuf
                Call    Bank_Call
                
                Jp      Rd_Leave
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Pro_Write
;>
;>      This procedure emulates the ProFile Write command
;>
;>      Inputs: { none }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       ClrNormStat
;>       LoadLogicalBlock( Pro_Log_Offset )
;>       Get_Type( Widget ) { check logical block bounds }
;>       Seek_Type := Access_Offset
;>       OverLap( User_Type, Write_Op, Write_Response, BlockNumber, 0 )
;>       IF ( BlkStat.SprCode = BadBlock )
;>        THEN
;>              BlockMove( Buf2Array, WBuffer1-1 )
;>              Data_Ex_Handler( SpareBlock )
;>        ELSE
;>         IF NOT( Wr_Common )
;>          THEN Data_Ex_Handler( Wr_Common.ErrorCode )
;>       Rd_Leave
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Pro_Write:
                 Ld     Wrk_Io+$A,#Wr_Response
                Call    Pro_Wr_SetUp
                
                Tm      BlkStat,#B_Block ;IF BadBlock
                Jr      Z,ProWr_1
                
Pro_Wr_BB:      Call    Wr_BBlock
                Jr      Wr_Leave
                
ProWr_1:        Call    Wr_Common
Pro_Wr_Exit:    Jr      Nz,Wr_Leave
                
                Call    Data_Ex_Handler
                
Wr_Leave:       Jp      Rd_Leave
                
                .Page
                
Pro_Wr_SetUp:   Call    ClrNormStat
                
                Call    Get_Wr_Data
                
                 Ld     !r0,#Pro_Log_Offset
                Call    Ld_LgclBlk ;LogicalBlockNumber := ...
                
                 Ld     !r8,#Widget
                 Ld     !r2,#.HIBYTE. Get_Type
                 Ld     !r3,#.LOWBYTE. Get_Type
                Call    Bank_Call ;check block bounds
                
                Ld      Seek_Type,#Access_Offset
                Ld      Data_Type,#User_Type
                Or      DiskStat,#Wr_Op
                
                 Ld     !r2,#.HIBYTE. OverLap
                 Ld     !r3,#.LOWBYTE. OverLap
                Call    Bank_Call
                
                Tm      DiskStat,#Offset_On
                Jr      Nz,P_W_S_End
                
                Call    ReSeek
                
P_W_S_End:      Ret

;*********************************

Wr_BBlock:       Ld     !r2,#.HIBYTE. WrBuf_To_Buf2
                 Ld     !r3,#.LOWBYTE. WrBuf_To_Buf2
                Call    Bank_Call
                 
                 Ld     !r0,#Error+Ex_SprBlock
                Call    Data_Ex_Handler
                Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Function: Wr_Common
;>
;>      This function handles all of the write specific details
;>      for all of Widget's write commands.
;>
;>      Inputs: { none }
;>
;>      Outputs:
;>              Wr_Common : BOOLEAN { zero flag is set if data exception }
;>              ErrorCode.Error : BOOLEAN { !r0/Bit 7 }
;>              ErrorCode.Type : 7 BITS { !r0/Bits 6:0 }
;>
;>      Local Variables:
;>              Retry        : BYTE { !r5 }
;>              ErrorCode    : BYTE { !r4 }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       ErrorCode.Error := False
;>       IF NOT( WriteBlock )
;>        THEN
;>         ErrorCode.Error := True
;>         ErrorCode.Type := Undetermined
;>         IF Recovery
;>            THEN
;>                IF ServoError OR NoHeaderFound
;>                 THEN
;>                   ErrorCode.Error := False
;>                   Retry := 4
;>                   REPEAT
;>                     THEN
;>                           ServoRecovery
;>                           Retry := Retry - 1
;>                   UNTIL NOT( Retry = 0 ) OR WriteBlock
;>                  IF NOT( WriteBlock )
;>                   THEN
;>                       ErrorCode.Error := True
;>                       ErrorCode.Type := Undetermined
;>                  IF ServoError
;>                   THEN
;>                        SetStatus( Byte0, Status_ServoError )
;>                        Abort
;>                  IF NoHeaderFound
;>                   THEN 
;>                       MoveBlock( Buffer2, WriteBuffer )
;>                       ErrorCode.Type := SpareBlock
;>       Write_Common := NOT( ErrorCode.Error )
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Wr_Common:
                 Ld     ScrReg2,#.HIBYTE. WBlkFence ;check for host overflow
                 Ld     ScrReg3,#.LOWBYTE. WBlkFence
                 Ld     !r2,#.HIBYTE. Chk_PassWord
                 Ld     !r3,#.LOWBYTE. Chk_PassWord
                Call    Bank_Call
                Jr      Nz,Wr_Cmn_Ok
                
                 Ld     !r0,#0 ;byte zero
                 Ld     !r1,#WrBuf_OR ;buffer over run
                Call    SetStatus
                Call    Abort
                
Wr_Cmn_Ok:      Push    !r4

                Or      DiskStat,#Wr_Op
                Clr     !r4
                Call    WriteBlock
                Jr      Nz,Wr_Cmn_End
                
                 Ld     !r2,#.HIBYTE. WrBuf_To_Buf2
                 Ld     !r3,#.LOWBYTE. WrBuf_To_Buf2
                Call    Bank_Call
                
                Ld      !r4,#Error ;ErrorCode := Error, Undetermined
                
                Tm      Excpt_Stat,#Recovery ;IF Recovery THEN ...
                Jr      Z,Wr_Cmn_End
                
                Ld      !r5,#4  ;Retry := 4
                
Wr_Cmn_Lp:       Ld     !r2,#.HIBYTE. SrvoRcvry
                 Ld     !r3,#.LOWBYTE. SrvoRcvry
                Call    Bank_Call
                
                 Ld     !r2,#.HIBYTE. Buf2_To_WrBuf
                 Ld     !r3,#.LOWBYTE. Buf2_To_WrBuf
                Call    Bank_Call
                
                Call    WriteBlock
                Clr     !r4
                Jr      Nz,Wr_Cmn_End
                
                Djnz    !r5,Wr_Cmn_Lp
                Ld      !r4,#Error
                
Wr_Cmn_Servo:   Tm      WrStat,#WrSrvoErr
                Jr      Z,Wr_Cmn_Hdr
                
                 Clr    !r0 ;Byte 0
                 Ld     !r1,#Stat_Srvo
                Call    SetStatus
                Call    Abort
                
Wr_Cmn_Hdr:     Tm      WrStat,#WrNoHdrFnd
                Jr      Z,Wr_Cmn_End
                
                Ld      !r4,#Error+Ex_HdrSpr
                
Wr_Cmn_End:     Ld      !r0,!r4
                Pop     !r4             ;retrieve register from stack
                Tcm     !r0,#WrError
                Jp      Bank_Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Pro_WrVer
;>
;>      This procedure emulates the ProFile Write/Verify
;>      command.
;>
;>      Inputs: { none }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       ClrNormStat
;>       LoadLogicalBlock( Pro_Log_Offset )
;>       Get_Type( Widget ) { check logical block bounds }
;>       Seek_Type := Access_Offset
;>       OverLap( User_Type, Write_Op, WrVer_Response, BlockNumber, 0 )
;>       IF ( BlkStat.SprCode = BadBlock )
;>        THEN
;>              BlockMove( Buf2Array, WBuffer1-1 )
;>              Data_Ex_Handler( SpareBlock )
;>        ELSE
;>         IF NOT( WrVer_Common )
;>          THEN Data_Ex_Handler( WrVer_Common.ErrorCode )
;>       Rd_Leave
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Sys_WrV:
                 Ld     Wrk_Io+$A,#Sys_WrVer_Resp
                Jr      Pro_WrVer_2

Pro_WrVer:
                 Ld     Wrk_Io+$A,#WrVer_Response
Pro_WrV_2:      Call    Pro_Wr_SetUp

                 Ld     !r2,#.HIBYTE. WrBuf_To_Buf2
                 Ld     !r3,#.LOWBYTE. WrBuf_To_Buf2
                Call    Bank_Call

                Tm      BlkStat,#B_Block ;IF BadBlock
                Jr      Z,ProWrV_1
                
                Call    Wr_BBlock
                Jr      WrVer_Leave
                
ProWrV_1:       Call    WrVer_Common
                Jr      Nz,WrVer_Leave
                
                Call    Data_Ex_Handler
                
WrVer_Leave:    Jp      Rd_Leave

                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Function: WrVer_Common
;>
;>      This function has the responsibility of making certain ( within
;>      reasonable limits ) that when a block is written to the disk that
;>      it can also be read back. WriteVerify comes in two flavors:
;>      Conservative and NotConservative. The attempt here is to make
;>      the WriteVerify routine attractive to end users as well as provide
;>      a means for the controller to have a high degree of confidence
;>      in writing some of it's more important blocks.
;>
;>      Inputs: { none }
;>
;>      Outputs:
;>              WrVer_Common : BOOLEAN { zero flag set if operation failed }
;>
;>      Algorithm:
;>
;>      BEGIN
;>        IF Wr_Common
;>         THEN
;>              DiskStat.Wr_Op := False
;>              Rd_Common
;>              IF ( Rd_Common.ErrorType = Ex_HdrBad )
;>               THEN Rd_Common.ErrorType := Ex_HdrSpr
;>               ELSE
;>                IF ( Rd_Common.ErrorType = Ex_BadBlock )
;>                 THEN Rd_Common.ErrorType := Ex_SprBlock
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

WrVer_Common:
                Call    ExtPush_Vector
                
                Or      DiskStat,#Wr_Op
                Call    Wr_Common
                Jr      Z,WrVer_Ret
                
                And     DiskStat,#$FF-Wr_Op
                Call    Read_Common
                Jr      Nz,WrVer_Ret
                
                Ld      !r1,!r0
                And     !r1,#$7F ;mask off error bit
                
                Cp      !r1,#Ex_HdrBad
                Ld      !r2,#Error+Ex_HdrSpr
                Jr      Z,WrV_ChgEx
                
                Cp      !r1,#Ex_BadBlock
                Ld      !r2,#Error+Ex_SprBlock
                Jr      Nz,WrVer_Ret
                
WrV_Chg_Ex:     Ld      !r0,!r2
                
WrVer_Ret:      Push    !r0
                Call    ExtPop_Vector
                Pop     !r0
                Tcm     !r0,#Error ;set error condition
                Jp      Bank_Ret
                
                .LSTOFF


