diff 3rdparty/drivers/burke/xtos9.src @ 91:c10820aa211b

Added
author boisy
date Wed, 03 Jul 2002 03:41:59 +0000
parents
children 892188818514
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/drivers/burke/xtos9.src	Wed Jul 03 03:41:59 2002 +0000
@@ -0,0 +1,953 @@
+*******************************************
+***                                     ***
+***     COPYRIGHT 1990 BURKE & BURKE    ***
+***     ALL RIGHTS RESERVED             ***
+***                                     ***
+***     COPYRIGHT 1992 BURKE & BURKE    ***
+***     ALL RIGHTS RESERVED             ***
+***                                     ***
+*******************************************
+
+*
+*  CoCo XT Hard Disk Driver  Version 2.0
+*
+*  For Western Digital WD1002-WX1 (or 27X) Controller.
+*
+*  The controller can only handle 512 bytes per sector,
+*  so these routines must synthesize 2 logical 256 byte
+*  sectors from each physical 512 byte sector.  This
+*  increases the time it takes to read or write a sector.
+*
+*  To counteract this, the 2nd half of each "even" sector
+*  is retained during a read.  If the next read accesses the
+*  "odd" half, the sector contents is read from the "verify"
+*  buffer instead of the hard disk.
+*
+*  This version can be optimized for a single ST-225 hard disk,
+*  via conditional assembly.  Several other parameters can also
+*  be controlled by conditional assembly.
+*
+*  Conditional assembly control:
+*
+*   Drives              ;Number of drives supported (1-2)
+*
+*   irqflg              ;non-zero to mask IRQ during disk access.
+*   fmtflg              ;non-zero if hard formatting supported
+*   fstflg              ;non-zero if fast transfers supported
+*   cchflg              ;non-zero if read cache supported
+*   vrfflg              ;non-zero if write verification supported
+*   tboflg              ;non-zero if jump to 2 MHz for block moves
+*   errflg              ;non-zero for good error messages
+*   icdflg              ;non-zero to ignore C/D status bit
+*   trsflg              ;non-zero if optimized for 32 SPT, 4 hd disks
+*   sysram              ;non-zero to use system RAM for verf buffer
+*   sizflg              ;non-zero if drives may be different sizes
+*
+*   XLEVEL              ;Special level 2 flag -- to use L1 assembler
+*
+*  Chris Burke  Schaumburg, IL  10/14/87
+*
+*   Modification History
+*   --------------------
+*
+*   Date        Who     Description
+*   --------    ---     -------------------------------------
+*   11/20/87    CJB     Fixed bug in PARK.
+*   12/23/87    CJB     Corrected table size and location
+*                       equates for L2 compatibility.  
+*                       Deleted support for Level 1, Version 
+*                       1.X OS9.
+*   12/27/87    CJB     Added code to grab parameters from
+*                       device descriptor if not obtained
+*                       by INIT.
+*   01/28/88    CJB     Added support for any slot.
+*   02/07/88    CJB     Changed FORMAT to reset drive parameters
+*                       Added speedy read cache algorithm.
+*                       Eliminated DIVA, DIVY, etc.
+*   02/23/88    CJB     Recoded for TRSFLG
+*   03/03/88    CJB     Changed module names to BBhdisk etc.
+*   04/17/88    cjb     Modified INIT to call WaitIdl before
+*                        shutting off controller interrupts & DMA
+*                       Fixed bugs in INIT which confused path
+*                        descriptor and device descriptor pointers
+*   04/21/88    cjb     Added code to disable I/O retries after
+*                        formatting hard drive.
+*   06/12/88    cjb     Changed to call WaitId2 instead of WaitIdl
+*   07/01/88    cjb     Changed revision from 2 to 3
+*   10/10/88    cjb     Modified for format error recovery
+*   05/18/90    cjb     Modified copyright
+*                       Added support for up to 4 drives
+*   07/07/91    cjb     Rev 2.5 (allow disabling of recalibration)
+*   04/15/92    cjb     Rev 2.6 (speed-ups, bug fix for DBLRDD)
+*
+
+ page
+*
+*  Equates
+*
+
+ ifp1
+        use     defsfile
+        use     wx2.equ
+ endc
+
+*  Index into device descriptor (using PD.XXX)
+
+DD.BASE equ M$DTYP-PD.OPT
+DD.HDSK equ $25              ;Start of extra hard disk stuff
+
+*  Multi-PAK Addresses
+MPAK equ $FF7F
+
+*
+*   Bogus equates for Level 2
+*
+
+D.DMARq2    equ     $008A       ;Bogus Level 2 D.DMAReq
+D.PROC2     equ     $0050       ;Bogus Level 2 D.PROC
+DRVMEM2     equ     $26         ;Level 2 drive table size
+DRVBEG2     equ     $0F         ;Level 2 start of drive tables
+
+*
+*   Bogus equates for Level 1
+*
+
+D.DMARq1    equ     $006A       ;Bogus Level 1 D.DMAReq
+D.PROC1     equ     $004B       ;Bogus Level 1 D.PROC
+DRVMEM1     equ     $18         ;Level 1 drive table size
+DRVBEG1     equ     $07         ;Level 1 start of drive tables
+
+    ifne    XLEVEL-1
+DMASEM  set     D.DMARq2        ;Level 2 DMA stuff (multi-pak)
+DPROC   set     D.PROC2         ;Level 2 process control stuff
+XDrvBeg set     DRVBEG2
+XDrvMen set     DRVMEM2
+
+    else
+DMASEM  set     D.DMARq1        ;Level 1 DMA stuff (multi-pak)
+DPROC   set     D.PROC1         ;Level 1 process control stuff
+XDrvBeg set     DRVBEG1
+XDrvMen set     DRVMEM1
+    endc
+
+ page
+*
+*   Module Header
+*
+verson  equ     2
+        mod     cchend,cchnam,drivr+objct,reent+verson,JmpTbl,endmem
+        fcb     DIR.+SHARE.+PEXEC.+PREAD.+PWRIT.+EXEC.+READ.+WRITE.
+
+*  Dynamic module name generation
+
+cchnam  equ     *
+
+    ifeq  testing
+        fcc     "BB"        ; (normal name)
+    else
+        fcc     "BK"        ; (special name)
+    endc
+
+    ifeq    (XLEVEL-1)      ;If level 1,
+        ifne    irqflg      ;If Level 1, Version 1 OS9
+            fcc /X/
+        else                ;If Level 1, Version 2 OS9
+            fcc /1/
+        endc
+    endc
+
+    ifne    fmtflg          ;If this driver can format hard disk,
+        fcc     /F/
+    endc
+
+    ifne    tboflg          ;If 2MHz transfers supported,
+        fcc     /T/
+    endc
+
+    ifne    trsflg          ;If "terse" version
+        fcs     /hd/        ;NOTE -- set MSB of last byte
+    else                    ;If "normal" version
+        fcs     /hdisk/     ;NOTE -- set MSB of last byte
+    endc
+
+        fcb     $06         ;revision - 2.6
+
+*   Copyright notice
+
+        fcc     /COPR. 1992 BURKE & BURKE/
+
+ page
+*
+*  Static Storage
+*
+
+    use     hdvars.src
+
+ page
+*
+*  Jump table
+*
+JmpTbl  lbra    INIT
+        lbra    READ
+        lbra    WRITE
+        lbra    GETSTA
+        lbra    SETSTA
+        lbra    TERM
+
+    ifne    sizflg              ;If drives may be different sizes,
+    page
+*
+*   Post-initialization for drives.
+*
+*   If we ever call a driver routine (other than INIT)
+*   with PARK LSN = 0, we know this drive has not been
+*   initialized.
+*
+*   Enter w/ Reg-Y = path descriptor pointer,
+*            Reg-U = static storage
+*
+*   Must save A and B:X as well as Y, U.
+*
+*   Returns carry set if error initializing drive
+*
+PostIni pshs    Y,X,D
+
+        ldb     PD.DRV,Y
+        lbsr    GOBPtr              ;Point Y to extra variables
+        clrb                        ;Force no carry (success)
+        ldb     (PRKLSN-OBSTART+0),Y
+        orb     (PRKLSN-OBSTART+1),Y
+         bne    PSTI0               ; (branch if OK)
+
+*   Perform drive info and controller intialization
+
+        ldy     4,S                 ;Get path pointer
+        ldy     PD.DEV,Y            ; get device table pointer
+        ldy     V$DESC,Y            ;  get device descriptor pointer
+        lbsr    CtlInit             ;Call routine to init. controller
+
+*   Done initiailizing this drive.
+
+PSTI0   puls  D,X,Y,PC
+
+    endc
+
+ page
+*
+*   Initialize driver routines
+*
+*   Reg-Y points to device descriptor
+*
+INIT    pshs    y
+
+*   This section calls routines that expect a *PATH* descriptor
+*   pointer in Reg-Y
+
+        leay    DD.BASE,Y   ;Make Y look like path descriptor to get slot
+
+        lbsr    Semfor      ;Wait, then select HD controller.
+        sta     >HDRSET     ;Reset controller
+        lbsr    WaitId2     ;Sleep -- wait for controller to reset
+*** Extra call to give WD1004 time to reset
+        lbsr    WaitId2     ;Sleep -- wait for controller to reset
+*** ENDK
+        ldy     ,S          ;Restore y -> device descriptor
+
+*   Set up controller for non-interrupt, non-DMA operation
+
+        clr     >HDMASK     ;Turn off controller interrupts and DMA
+
+*   Set # of drives we can handle
+
+        lda     #Drives
+        sta     V.NDRV,U
+
+*   Set up drive switching info
+
+    ifne    (Drives-1)
+        ldd     #$FFFF
+        std     prvdrv,u    ; (set PRVDRV unknown, DRVSEM for new drive)
+        std     actdrv,u    ;Pointer to active drive table
+    else
+        lda     #$FF
+        sta     DRVSEM,U
+    endc
+
+*   Enable hardware I/O retries.  These will be disabled by a FORMAT
+*   setstat, and will be re-enabled by an INIT call or a reboot.
+*   The main use of this is to disable retries during disk formatting.
+
+        clr     RetryEn,U   ;Enable hardware retries
+
+*   Program controller w/ drive parameters.  
+*   Y points to device descriptor.
+
+        bsr     CtlInit     ; (also clears BFRFLG,U and changes Y)
+         bcs    INIT9       ; (abort if error)
+
+*  Initialize the drive tables for all drives
+
+        ldd     #(-1)               ;Current track is unknown
+        stb     XDrvBeg+V.TRAK,U
+        std     XDrvBeg+DD.TOT,U    ;Set total sectors non-zero to allow LSN0
+    ifne    (Drives-1)
+        stb     XDrvBeg+XDrvMen*1+V.TRAK,U    ; (do all drives)
+        std     XDrvBeg+XDrvMen*1+DD.TOT,U
+      ifge  (Drives-3)
+        stb     XDrvBeg+XDrvMen*2+V.TRAK,U    ; (do all drives)
+        std     XDrvBeg+XDrvMen*2+DD.TOT,U
+      endc
+      ifge  (Drives-4)
+        stb     XDrvBeg+XDrvMen*3+V.TRAK,U    ; (do all drives)
+        std     XDrvBeg+XDrvMen*3+DD.TOT,U
+      endc
+    endc
+
+*   Reg-Y points to bogus path descriptor (courtesy of CtlInit).
+*   Wait for drive to be ready.  
+*
+*   Note that WaiDrv returns Reg-B=0 and carry clear to OK, 
+*   else reg-B = E$NotRdy and carry set.
+
+        bsr     WaiDrv          ;Note:  WaiDrv requires *PATH* descriptor
+
+*  Error hook
+INIT9   puls    Y               ;restore saved Y register (DD pointer)
+        bra     HDXIT
+
+*  Generic error-free exit
+OKXIT   clrb 
+
+*
+*  Generic exit.  Restore MULTI-PAK to
+*  slot #4 so floppy disk works, and release semaphore
+*
+*   Preserves CC and B
+*
+*   RELEASE also clears the V.WAKE flag.
+*
+HDXIT   lbsr    Release
+        rts 
+
+*
+*   Wait for drive ready
+*   Assumes reg-Y points to real or bogus path
+*   descriptor (for drive # and step rate)
+*
+WaiDrv  pshs    y,x,a,b
+
+        clr     ,-s                 ;Time out
+
+WaiDr2  lda     #WX$TST     ;Test drive ready
+
+    ifne    (Drives-1)              ;If more than 1 drive
+        ldb     PD.DRV,Y            ;get drive #
+    endc
+
+        lbsr    DrvCmd
+         bcc    WaiDr3              ; (branch if drive ready)
+
+        dec     ,s                  ;Decrement timeout
+         beq    WaiDr4              ; (branch if timeout)
+
+        lbsr    Snooze              ;Give drive some time
+        bra     WaiDr2              ; then retry.
+
+*   Timeout
+
+WaiDr4  comb
+        ldb     #E$NotRdy           ;Drive not ready
+        stb     1+1,S
+
+*   Carry clear if ready, else carry set
+
+WaiDr3  leas    1,S                 ;Discard counter
+        puls    a,b,x,y,pc
+
+*
+*   Get extra bytes from this drive's descriptor.
+*   Send them to the controller.  
+*
+*   Enter w/ 
+*   Reg-Y = Dev Desc pointer, and 
+*   Reg-U = static storage pointer.
+*
+*   Note that if there is a 2nd drive with different
+*   parameters, they must be obtained in a different
+*   manner.
+*
+*   Modifies Reg-Y to make it look like a bogus *PATH*
+*   descriptor
+*
+
+CtlInit equ     *
+
+    ifne    cchflg              ;If read cache,
+        clr     BFRFLG,U            ;Buffer contents invalid
+    endc
+
+        bsr     GetXtra             ;Call subroutine DDPTR in Y.
+
+*   Send drive parameters to controller.  Reg-Y points to device
+*   descriptor, but we adjust it to look like a path descriptor.
+
+        leay    DD.BASE,Y           ;Make Y look like path descriptor
+
+        lda     #WX$INI             ;Command to send drive parameters
+
+    ifne    (Drives-1)              ;If more than 1 drive
+        ldb     PD.DRV,Y            ;get drive #
+    endc
+
+        lbsr    DrvCmd              ;Set up drive parameters
+        rts
+
+    page
+*
+*   Copy precomp cylinder and park LSN from descriptor 
+*   (also gives max. tracks!)
+*
+
+GetXtra ldd     DD.HDSK+(PCCYL-OBSTART),Y       ;get prec, MSB of park LSN
+        ldx     DD.HDSK+(PRKLSN+1-OBSTART),Y    ;get rest of park LSN
+     ifne   (Drives-1)          ; If 2 drives,
+      ifne  sizflg              ;  of different sizes,
+        pshs    Y,X,D
+        ldb     DD.BASE+PD.DRV,Y    ;get drive #
+        lbsr    GOBPtr              ;get dest. pointer to Y
+        puls    D,X
+        std     (PCCYL-OBSTART),Y
+        stx     (PRKLSN+1-OBSTART),Y
+        puls    Y,PC                ;Recover DD ptr and exit
+      else                      ;  of same size,
+        std     PCCYL,U
+        stx     (PRKLSN+1),U        ;set up both tables at once
+        std     (PCCYL+OBSIZE),U
+        stx     (PRKLSN+1+OBSIZE),U
+        rts
+      endc
+     else                       ; If 1 drive,
+        std     PCCYL,U
+        stx     (PRKLSN+1),U
+        rts
+     endc
+
+    page
+*
+*   Terminate hard disk processing
+*
+TERM    lbsr    Semfor      ;Wait on semaphore, select controller
+        bra     OKXIT       ;Clear semaphore and successful exit
+
+*
+*  Dummy routine for GETSTA
+*
+GETSTA  comb                ;Set carry
+        ldb     #E$UnkSVC
+        rts 
+
+ page
+*
+*   Read a sector from disk
+*
+*   LSN in B:X.  If it is 1+OLDLSN,
+*   and the drive # is right, and the
+*   read cache is full, don't even bother
+*   doing address computations
+*
+*   There are always an even number of sectors
+*   per track, so if the new LSN is the old LSN
+*   with MSB set, we have a winner!  We always
+*   store the old LSN with MSB set.
+*
+
+READ    equ     *
+
+    ifne    cchflg      ;If read cache,
+
+        pshs    X,B         ;Save LSN
+        lbsr    SavSlt      ;Save old slot #, but don't change yet
+
+        tst     BFRFLG,U    ;Is buffer valid?
+         beq    READXX      ; (branch if no luck)
+     ifne   (Drives-1)
+        lda     PD.DRV,Y
+        cmpa    PRVDRV,U
+         bne    READXX      ; (branch if drive different)
+     endc
+        puls    B,X
+        cmpx    OLDLSN+1,U
+         bne    READXY
+        cmpb    OLDLSN+0,U
+         bne    READXY
+
+*   Use verify buffer for sector data -- no read necessary!
+*   The OLDLSN and PRVDRV variables are already set right.
+
+        pshs    u,y,x
+
+        ldb     #128
+        ldx     PD.BUF,Y        ;Get destination pointer
+        leay    vrfbuf,U        ;Get source pointer
+
+DR0     ldu     ,y++
+        stu     ,x++
+        decb
+         bne    DR0
+
+        puls    x,y,u
+        bra     OKXIT3          ;Successful exit
+
+*   Not a cache read.  Restore LSN
+
+READXX  puls    B,X
+
+*   Save LSN in case we can do a cache read next time.
+*   We always set the LSB of the saved LSN; the BFRFLG
+*   will be set only if the actual LSB is 0!
+
+READXY  clr     BFRFLG,U        ;Assume future cache read invalid
+        stb     OLDLSN+0,U      ;Save LSN for next time
+
+        pshs    B
+        tfr     X,D
+        bitb    #%00000001      ;If LSB is 0, cache read valid next time
+         bne    READXZ
+
+        com     BFRFLG,U        ; (cache read next time)
+
+READXZ  orb     #%00000001      ; (always set LSB in possible match)
+        std     OLDLSN+1,U
+        puls    B
+
+    endc
+
+*   Perform normal read -- LSN in B:X
+
+        lbsr    Semfor      ;Wait, select hard disk controller slot
+
+    ifne    sizflg      ;If drives can be different sizes,
+        lbsr    PostIni
+         bcs    HDXIT3
+    endc
+
+*   Check for LSN0
+
+        cmpx    #0          ;Check for LSN 0 -- SPECIAL
+         bne    NotLS0
+        tstb 
+         bne    NotLS0
+
+**   Wants to read LSN 0.
+**   See if LSN 0 has already been read once.
+**
+**   We must use PD.DTB,Y instead of ACTDRV,U because
+**   SELDRV has not been called yet.
+**
+**   Actually, we still read -- we just don't update
+**   the drive table
+*
+*        pshs    X,B         ;Save LSN
+*    ifne    (Drives-1)          ;If 2 drives,
+*        ldx     PD.DTB,Y    ;Point to drive table
+*    else
+*        leax    DRVTBL,U    ;Point to drive table
+*    endc
+*        ldd     DD.TOT,x    ;Get total sectors
+*        cmpd    #-1         ; -1 is a special value set by INIT routine
+*        puls    B,X         ;Restore LSN (always $000000)
+*         bne    NotLS0      ;If not -1, LSN 0 already read; no special stuff
+
+*   Special treatment for LSN0 -- refresh drive table when done
+
+        bsr     DoRead
+         bcs    HDXIT3
+
+        ldx     PD.BUF,y    ;Get buffer address
+        pshs    Y,X         ;Save old buffer and device descriptor ptrs
+
+*   Note that the SELDRV routine, called by DOREAD, sets up
+*   the drive table pointer in actdrv,U if there are 2 drives.
+
+    ifne    (Drives-1)          ;If 2 drives,
+        ldy     actdrv,u
+    else
+        leay    DRVTBL,U
+    endc
+
+        ldb     #DD.SIZ-1
+
+*  Update drive table from buffer
+
+RCPY1   lda     b,x
+        sta     b,y
+        decb 
+         bpl    RCPY1
+
+        puls    y,x
+        bra     OKXIT3
+
+*  Read (not LSN0)
+
+NotLS0  bsr     DoRead
+HDXIT3   lbcs   HDXIT
+
+OKXIT3  lbra    OKXIT
+
+ page
+*
+*  Utility to read a sector
+*
+DoRead  lbsr    SETUP
+         bcs    DORXIT
+
+*  Entry point for VERIFY
+VrfRdd  ldx     PD.BUF,Y    ;Get buffer address
+
+*  General read sector
+GetSec  lda     #WX$RDD        ;Create "READ SINGLE SECTOR" command
+        lbsr    CMEXEC
+DORXIT  rts 
+
+ page
+*
+*  Write a sector to disk.
+*
+*  This routine must pre-read the sector in order to
+*  pack 2 logical sectors into 1 physical sector.
+*  This invalidates any data that might have been pre-read
+*  into the verify buffer.
+*
+WRITE   lbsr    Semfor      ;Wait, then select HD controller
+
+    ifne    sizflg      ;If drives can be different sizes,
+        lbsr    PostIni
+         bcs    HDXIT3
+    endc
+
+*  Pre-read the "other" half of the sector to the verify buffer
+
+        pshs    X,B        ;Save LSN
+        lbsr    SETUP      ;Set up head, track, sector #'s
+        bsr     flphlf      ;flip LSB of SECNUM
+
+    ifne    cchflg      ;If read cache supported
+        clr     BFRFLG,u    ;2nd half of sector should not be saved
+    endc
+
+        leax    vrfbuf,U    ;Use verify buffer
+        bsr     GetSec      ; (re-use code)
+
+        puls    X,B
+         bcs    HDXIT3      ; branch to abort if pre-read fails
+
+        bsr     flphlf       ;fix up sector #
+
+*  Perform the write.  The "other" half of the physical sector
+*  has been pre-read into the verify buffer.
+
+        pshs    x,b       ;save LSN
+        bsr     DoWrit
+        puls    x,b
+         bcs    HDXIT3
+
+    ifne    vrfflg              ;If verify enabled,
+
+        tst     PD.VFY,Y   ;Verify writes?
+         bne    OKXIT3
+
+*  Verify the write
+        bsr     VERIFY
+         bcc    OKXIT3
+
+*  Verify failed; carry set
+        ldb     #E$Write
+        bra     HDXIT3
+
+    else
+
+        bra    OKXIT3
+
+    endc
+
+*
+*  Flip LSB of SECNUM.  This is used to pre-read the half of the sector
+*  that should not be changed by a write.
+*
+flphlf  lda     secnum,u
+        EORA    #1
+        sta     secnum,u
+        rts
+
+ page
+*
+*  Utility to write a sector
+*
+DoWRIT  lbsr    SETUP
+         bcs    DOWXIT
+
+        ldx     PD.BUF,Y        ;Get buffer pointer
+        lda     #WX$WRT         ;Create "WRITE SINGLE SECTOR" command
+        lbsr    CMEXEC
+
+DOWXIT  rts 
+
+    ifne    vrfflg          ;If verify supported,
+
+*
+*  Verify last sector written
+*
+*  Don't copy unused part of sector to verify buffer
+*
+VERIFY  pshs    x,b,a
+
+        ldx     PD.BUF,y    ;Save buffer pointer
+        pshs    x
+
+        leax    vrfbuf,U
+        stx     PD.BUF,y    ;Force dummy buffer pointer
+        ldx     4,s         ;Recover LSN
+
+        lbsr    setup
+         bcs    VF1
+
+    ifne    cchflg          ;If read cache supported,
+        clr     BFRFLG,u    ;Mark don't save 2nd half of sector
+    endc
+
+        lbsr    VrfRdd     ;Actual read done here
+
+VF1     puls    x
+        stx     PD.BUF,y    ;Restore buffer pointer
+         bcs    VRFXIT
+
+*  Look only at every 8th byte to speed up the verify
+        lda     #(256/8)    ;Iteration count
+        pshs    u,y,a
+
+        leay    vrfbuf,U    ;Point at sector buffer
+        tfr     x,u
+
+*  Compare the data read back to the data written
+VRF1    ldx     ,u
+        cmpx    ,y
+         bne    VRFERR
+
+        leau    8,u         ;next byte
+        leay    8,y
+        dec     ,s
+         bne    VRF1
+
+        bra     VRFOK
+
+*  Error exit
+VRFERR  orcc    #$01
+
+*  Deallocate temporaries
+VRFOK   puls    u,y,a
+
+*  Generic verify exit
+VRFXIT  puls    a,b,x,PC
+
+    endc
+
+ page
+*
+*   Set Status.
+*
+*   Reg-Y has path descriptor, and Reg-A has status code.
+*
+SETSTA  lbsr    Semfor      ;Wait, then select HD controller
+
+    ifne    sizflg      ;If drives can be different sizes,
+        lbsr    PostIni
+         lbcs   HDXIT
+    endc
+
+        lbsr    SELDRV
+
+        ldx     PD.RGS,y    ;Point at register stack
+        ldb     R$B,x       ;Recover service code
+
+        cmpb    #SS.Reset
+         bne    SS1
+
+        lbsr    SEEKT0
+        bra     SSXIT
+
+SS1     equ     *
+
+    ifne    fmtflg              ;If hard formatting supported,
+        cmpb    #SS.WTrk
+         bne    SS2
+
+        bsr     FmtTrk
+        bra     SSXIT
+    endc
+
+SS2     cmpb    #SS.SQD
+         bne    SS9
+
+        bsr     PwrDwn
+        bra     SSXIT
+
+*  Error - unrecognized SETSTA code
+
+SS9     comb 
+        ldb     #E$UnkSvc
+
+*  Generic exit.  Return error if carry set.
+
+SSXIT   lbcs    HDXIT
+        lbra    OKXIT
+
+ page
+*
+*  Power-down (park) disk
+*
+PwrDwn  equ     *
+
+*   Get park LSN to B:X
+
+    ifne    (Drives-1)      ;If 2 drives,
+        lbsr    GtPkLSN         ;Call routine to get park LSN to B:X
+    else
+        ldb     PRKLSN+0,U
+        ldx     PRKLSN+1,U
+    endc
+
+*   Seek to this LSN
+
+PwrDn2  lbsr    SETUP
+        lbsr    SEEK            ;Park head at last track
+        rts 
+
+    ifne    fmtflg          ;If hard format supported
+
+*
+*   Format a track.
+*
+*   Now we format one track at a time.
+*
+*   At entry Reg-X points to the register packet,
+*   and Reg-Y points to the path descriptor
+*
+FmtTrk  lda     #$80            ;Disable hardware retries
+        sta     RetryEn,U
+
+        ldd     R$U,x           ;Get track number -- must be zero.
+        cmpd    #0
+         bne    FMTXIT
+
+        ldd     R$Y,x           ;Check side/density -- MSB must be zero
+        cmpa    #0
+         beq    FMT1
+
+*  Ignore repeated calls, returning success
+FMTXIT  clrb 
+        rts 
+
+*  Perform the format if not write protected
+FMT1    pshs    u,y,x
+
+*  Proceed, disk not write protected
+FMT11   equ     *
+
+*   Set up reduced drive characteristics (only legal tracks)
+
+        lda     #WX$XIN     ;Bogus command to init. special parameters
+        lbsr    CmExec
+         bcs    FMTERR
+
+*  Initialize sector buffer
+
+        lda     #WX$WBF
+        lbsr    CmExec
+         bcs    FMTERR
+
+*   Begin formatting at track 0
+
+        ldd     #$C0FF          ;Set initial cylinder to (-1)
+        std     ERRHCYL,u
+
+*  Set up starting track for format
+
+FMT2    ldd     ERRHCYL,u       ;Use last good cylinder
+        anda    #%11000000
+        incb
+         bne    FMT3
+        adda    #%01000000
+FMT3    std     hicyl,U         ; (set track number, sector 0)
+
+*        clr     lowcyl,u        ;Clear LOWCYL
+*        clr     hicyl,u         ;Clear HICYL (and sector #)
+
+    ifne    (Drives-1)          ;If multiple drives,
+        lda     PD.DRV,Y        ;Set up drive #
+        ldb     #32
+        mul
+        stb     sdhreg,u        ;Select correct drive, clear head number
+    else
+        clr     sdhreg,u
+    endc
+
+        lda     PD.ILV,Y        ;Set interleave factor
+        lsra                    ; / 2 since physical sectors are 2X
+        sta     seccnt,u
+
+        lda     #WX$FMT         ;Command to FORMAT ENTIRE DRIVE
+*        lda     #WX$FTK         ;Command to FORMAT TRACK
+        lbsr    CmExec
+         bcs    FMT2            ;Try next track if error
+
+*   Return error code in B, C set or no error, C clear
+
+FMTERR  pshs    b,cc            ;Stack error status
+
+*   Set up correct drive characteristics (park track allowed)
+
+        lda     #WX$INI     ;Init. original parameters
+        lbsr    CmExec
+
+*   Get back error status
+
+        puls    cc,b
+
+*  End of format routine
+
+FMTEND  puls    x,y,u,PC
+
+    endc
+
+*
+*   End of main line of XTOS9.SRC.
+*   "USE" files follow.
+*
+
+ page
+*
+*   Include routines to issue command to controller
+*   and return completion status.
+*
+
+        use     hdcmd.src
+
+ page
+*
+*   Include routines to translate LSN & drive #
+*   to a controller task file.
+*
+
+        use     hdmath.src
+
+ page
+*
+*   Include utility routines.
+*
+
+        use     hdutil3.src
+
+ emod
+cchend equ *
+
+ end