home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d8xx / d803 / hackdisk.lha / Hackdisk / hackdisk.s < prev    next >
Text File  |  1993-01-24  |  69KB  |  3,011 lines

  1. ********************************************************************************
  2. * hackdisk.s -- my very own version of trackdisk.device
  3. * Copyright © 1992 by Dan Babcock
  4. *
  5. * Version history:
  6. * V1.00 04/25/92 First version. Supports 880K drives only.
  7. * V1.01 04/28/92 Optimized CopyMem
  8. * V1.02 04/30/92 More intelligent write algorithm fixes performance problem
  9. * V1.03 05/03/92 Sets IO_ACTUAL
  10. * V1.04 06/24/92 Fixes a couple bugs: RemChangeInt works now, and disk change
  11. *                errors are only reported when it makes sense.
  12. *                CrossDOSV5/CrossPC flushed out these bugs.
  13. * V1.10 07/04/92 Compatible with Kickstart 1.2 and higher.
  14. *                Fixed Seek (IO_OFFSET is in bytes, not tracks).
  15. *                Released on Fish 697!
  16. * V1.11 08/03/92 Fixed bug in readtrack routine - buffer not cleared if error
  17. *                in some cases (no sync).
  18. *                Fills TC_Userdata with bogus value to fool CrossDOS under Kick
  19. *                1.2/1.3.
  20. *                Puts -1 in IO_DEVICE on open error. Some (though not many)
  21. *                applications depend on this.
  22. *                Using a slightly more creative "invalid sync word" (was 0).
  23. *                This should fix many drive incompatibility problems.
  24. *                Glitch in disk check code fixed (only affected non-NoClick mode).
  25. * V1.12 08/16/92 CMD_STOP/CMD_START should work now.
  26. * V2.00 12/26/92 Supports Chinon/Commodore FB357A 150RPM HD floppy drives.
  27. *                Support added for 5.25 inch drives (NOT TESTED!!!)
  28. *                Added track number to verify error display (only under 2.0+).
  29. *                Added a tiny module at the end (see the comments for details).
  30. ********************************************************************************
  31.  
  32. ;This source was assembled with Macro68 release 3.
  33.  
  34.     exeobj
  35.     objfile    'devs:hackdisk.device'
  36.     MC68000
  37.     multipass
  38.  
  39. ;Standard register usage:
  40. ;A6            - ExecBase or $dff000
  41. ;A5 (A_DEVICE) - device ptr
  42. ;A4 (A_UNIT)   - unit ptr
  43. ;A3 (A_IO)     - IORequest
  44.  
  45.     IFND    SYS
  46. SYS    macro
  47.     jsr    _LVO\1(a6)
  48.     endm
  49.     ENDC
  50.  
  51.     IFND    _custom
  52. _custom    equ    $dff000
  53.     ENDC
  54.  
  55. ;Set INFO_LEVEL to 1 for full debugging output over the internal serial port.
  56. INFO_LEVEL    equ    0
  57.  
  58. A_DEVICE    equr    a5
  59. A_UNIT    equr    a4
  60. A_IO    equr    a3
  61.  
  62.  
  63. VERSION    equ    127
  64. REVISION    equ    0
  65. MYPRI    equ    0
  66.  
  67. MD_NUMUNITS    equ    4
  68. STACKSIZE    equ    4000
  69. TASKPRI    equ    5
  70.  
  71. RETRYCNT    equ    3
  72.  
  73. ;Put a message to the serial port.  Used like so:
  74. ;
  75. ;PUTDEBUG    <'Init: called'>
  76. ;
  77. ;Parameters can be printed out by pushing them on the stack and
  78. ;adding the appropriate C printf-style % formatting commands.
  79.  
  80. PUTDEBUG     macro    ;<msg>
  81.     ifne    INFO_LEVEL
  82.     movem.l    d0-d1/a0-a1,-(sp)
  83.     lea    .msg\@(pc),a0    ;Point to static format string
  84.     lea    16(sp),a1    ;Point to args
  85.     bsr    KPutFmt
  86.     movem.l    (sp)+,d0-d1/a0-a1
  87.     bra    .end\@
  88. .msg\@:
  89.     dc.b    \1,$a,0
  90.     even
  91. .end\@:
  92.     endc
  93.     endm
  94.  
  95. *--------------------------------------------------------------------
  96. *
  97. * Driver error defines
  98. *
  99. *--------------------------------------------------------------------
  100.  
  101. ;TDERR_NotSpecified    EQU    20    ; general catchall
  102. ;TDERR_NoSecHdr        EQU    21    ; couldn't even find a sector
  103. ;TDERR_BadSecPreamble    EQU    22    ; sector looked wrong
  104. ;TDERR_BadSecID        EQU    23    ; ditto
  105. ;TDERR_BadHdrSum        EQU    24    ; header had incorrect checksum
  106. ;TDERR_BadSecSum        EQU    25    ; data had incorrect checksum
  107. ;TDERR_TooFewSecs    EQU    26    ; couldn't find enough sectors
  108. ;TDERR_BadSecHdr        EQU    27    ; another "sector looked wrong"
  109. ;TDERR_WriteProt        EQU    28    ; can't write to a protected disk
  110. ;TDERR_DiskChanged    EQU    29    ; no disk in the drive
  111. ;TDERR_SeekError        EQU    30    ; couldn't find track 0
  112. ;TDERR_NoMem        EQU    31    ; ran out of memory
  113. ;TDERR_BadUnitNum    EQU    32    ; asked for a unit > NUMUNITS
  114. ;TDERR_BadDriveType    EQU    33    ; not a drive that trackdisk groks
  115. ;TDERR_DriveInUse    EQU    34    ; someone else allocated the drive
  116. ;TDERR_PostReset        EQU    35    ; user hit reset; awaiting doom
  117.  
  118. ; STRUCTURE TIMEVAL,0
  119. ;    ULONG    TV_SECS
  120. ;    ULONG    TV_MICRO
  121. ;    LABEL    TV_SIZE
  122.  
  123. ;Unit structure
  124.  
  125. *--------------------------------------------------------------------
  126. *
  127. * Public portion of unit structure
  128. *
  129. *--------------------------------------------------------------------
  130.  
  131. ;*------ UNIT_FLAG definitions:
  132.  
  133. ;These are bogus, but I won't re-define them.
  134. ;    BITDEF  UNIT,ACTIVE,0        ; driver is active
  135. ;    BITDEF  UNIT,INTASK,1        ; running in driver's task
  136.     BITDEF    UNIT,DiskInDrive,2
  137.     BITDEF    UNIT,WriteProtected,3
  138.  
  139. ; STRUCTURE TDU_PUBLICUNIT,UNIT_SIZE
  140. ;    UWORD    TDU_COMP01TRACK        ; track for first precomp
  141. ;    UWORD    TDU_COMP10TRACK        ; track for second precomp
  142. ;    UWORD    TDU_COMP11TRACK        ; track for third precomp
  143. ;    ULONG    TDU_STEPDELAY        ; time to wait after stepping
  144. ;    ULONG    TDU_SETTLEDELAY        ; time to wait after seeking
  145. ;    UBYTE    TDU_RETRYCNT        ; # of times to retry
  146. ;    UBYTE    TDU_PUBFLAGS        ; public flags, see below
  147. ;    UWORD    TDU_CURRTRK        ; track heads are over
  148.                     ;  (ONLY ACCESS WHILE UNIT IS STOPPED!)
  149. ;    ULONG    TDU_CALIBRATEDELAY    ; time to wait after stepping
  150.                     ; for recalibrate
  151. ;    ULONG    TDU_COUNTER        ; counter for disk changes
  152.                     ;  (ONLY ACCESS WHILE UNIT IS STOPPED!)
  153. ;    LABEL    TDU_PUBLICUNITSIZE
  154. ;*--------------------------------------------------------------------
  155.  
  156.     STRUCTURE    MyUnit,TDU_PUBLICUNITSIZE
  157.     STRUCT    Drive_LastCheck,TV_SIZE    ;last time diskchange was checked
  158.     STRUCT    ChangeIntList,MLH_SIZE    ;must be initialized!!!
  159.     LONG    TDRemoveInt
  160.     BYTE    UnitNum
  161.     BYTE    unit_pad1
  162.  
  163. ;The following will be InitStruct'ed in GetDriveType
  164.     LABEL    DriveParams
  165.     BYTE    DriveType
  166.     BYTE    NumTracks
  167.     LONG    BytesPerDisk
  168.     LONG    SectorMask
  169.     WORD    GapCount
  170.     LONG    SectorsPerTrack
  171.     LONG    RawBufSize
  172.     WORD    WriteDskLen
  173.     WORD    ReadDskLen
  174.     WORD    VerifyDskLen
  175.     WORD    MaxValidSec
  176.     WORD    FirstSector
  177.     LABEL    EndDriveParams
  178. ;MUST be word-aligned!!!
  179.     LABEL    MyUnit_Sizeof
  180.  
  181. DriveParams_Sizeof    equ    EndDriveParams-DriveParams
  182.  
  183.  
  184. ;*
  185. ;* Flags for TDU_PUBFLAGS:
  186. ;*
  187. ;    BITDEF    TDP,NOCLICK,0        ; set to enable noclickstart
  188.     BITDEF    TDP,VERIFY,1
  189.  
  190. ;Device global structure -- accessed as positive offsets from device base
  191. ;Note: The stuff in LIB_SIZE is *required*. Anything else is up to you...
  192.     STRUCTURE    DeviceGlobals,LIB_SIZE
  193.     STRUCT    TaskPort,MP_SIZE    ;MsgPort for task
  194.     STRUCT    Task,TC_SIZE
  195.     STRUCT    TaskStack,STACKSIZE
  196.     STRUCT    TempTimeVal,TV_SIZE
  197.     LONG    SegList    ;not used for ROM version
  198.     STRUCT    TimerIORequest,IOTV_SIZE
  199.     STRUCT    TimerPort,MP_SIZE
  200.     STRUCT    LastCheck,TV_SIZE    ;last time diskchange was checked
  201.     STRUCT    DiskResourceUnit,DRU_SIZE    ;must be initialized!!!
  202.     STRUCT    DiskResourcePort,MP_SIZE    ;must be initialized!!!
  203.  
  204. ;Allocated memory pointers
  205.     LONG    RawBuffer
  206.     LONG    DecodedBuffer
  207.     LONG    VerifyBuffer
  208.  
  209.     STRUCT    SectorLabels,22*16
  210.     STRUCT    Unit0,MyUnit_Sizeof
  211.     STRUCT    Unit1,MyUnit_Sizeof
  212.     STRUCT    Unit2,MyUnit_Sizeof
  213.     STRUCT    Unit3,MyUnit_Sizeof
  214.     LONG    GraphBase
  215.     LONG    IntBase
  216.     LONG    DiskResourceBase
  217.     LONG    CIABase
  218.     WORD    SyncCount
  219.     WORD    IndexDskLen
  220.     WORD    BlockIntDskLen
  221.     LONG    WriteMap
  222.  
  223.     LABEL    StartSigs
  224.     LONG    SyncSig
  225.     LONG    BlockSig
  226.     LABEL    EndSigs
  227.  
  228.     BYTE    BufferTrack
  229.     BYTE    BufferDrive
  230.     BYTE    DEV_FLAGS
  231.     BYTE    MotorState
  232.     BYTE    InquireBits
  233.     LABEL    MyDev_Sizeof
  234.  
  235. NumSigs    equ    (EndSigs-StartSigs)/4
  236.  
  237. ;Bit definitions for DEV_FLAGS:
  238.     BITDEF    DEV,Dirty,0    ;buffered track has been changed
  239.     BITDEF    DEV,Stopped,1    ;device is stopped
  240.     BITDEF    DEV,Verify,2    ;used by BlockInt for verify
  241.  
  242. ;A romtag structure.  After your driver is brought in from disk, the
  243. ;disk image will be scanned for this structure to discover magic constants
  244. ;about you (such as where to start running you from...).
  245.  
  246. RomTag:
  247.     dc.w    RTC_MATCHWORD    ;$4AFC ('illegal' opcode)
  248.     dc.l    RomTag
  249.     dc.l    EndCode    ;pointer to end of code
  250.     dc.b    RTF_AUTOINIT+RTF_COLDSTART    ;set things up automatically
  251.     dc.b    VERSION
  252.     dc.b    NT_DEVICE    ;module type (either device or library)
  253.     dc.b    MYPRI    ;usually not important
  254.     dc.l    Name    ;name used in OpenDevice
  255.     dc.l    IDString    ;optional
  256.     dc.l    Init    ;more init info
  257.  
  258. Name:    dc.b    'trackdisk.device',0
  259.     even
  260.  
  261. IDString:    dc.b    'Hackdisk V2.00 - Copyright © 1992 by Dan Babcock',$a,0
  262.     even
  263. DiskResourceName:
  264.     dc.b    'disk.resource',0
  265. TimerName:
  266.     dc.b    'timer.device',0
  267. GraphName:
  268.     dc.b    'graphics.library',0
  269. CIAName:    dc.b    'ciab.resource',0
  270. IntName:    dc.b    'intuition.library',0
  271.     even
  272.  
  273. ;The romtag specified that we were "RTF_AUTOINIT".  This means that the
  274. ;RT_INIT structure member points to one of these tables below.  If the
  275. ;AUTOINIT bit was not set then RT_INIT would point to a routine to run.
  276.  
  277. Init:    dc.l    MyDev_Sizeof    ;data space size (at least
  278.                 ;LIB_SIZE!!)
  279.     dc.l    FuncTable    ;pointer to function initializers
  280.     dc.l    DataTable    ;pointer to data initializers
  281.     dc.l    InitRoutine    ;routine to run
  282.  
  283. FuncTable:
  284.     dc.w    -1    ;this indicates that the following are offsets,
  285.             ;rather than absolute addresses
  286.     dc.w    Open-FuncTable    ;standard system routines
  287.     dc.w    _Close-FuncTable
  288.     dc.w    Expunge-FuncTable
  289.     dc.w    .Null-FuncTable    ;Reserved for future use!
  290.     dc.w    BeginIO-FuncTable    ;device definitions
  291.     dc.w    AbortIO-FuncTable
  292.     dc.w    -1    ;function table end marker
  293. .Null:    moveq    #0,d0
  294.     rts
  295.  
  296. ;The data table initializes static data structures. The format is
  297. ;specified in exec/InitStruct routine's manual pages.  The
  298. ;INITBYTE/INITWORD/INITLONG macros are in the file "exec/initializers.i".
  299. ;The first argument is the offset from the device base for this
  300. ;byte/word/long. The second argument is the value to put in that cell.
  301. ;The table is null terminated
  302.  
  303. DataTable:
  304.     INITBYTE    LN_TYPE,NT_DEVICE
  305.     INITLONG    LN_NAME,Name
  306.     INITBYTE    LIB_FLAGS,LIBF_SUMUSED+LIBF_CHANGED
  307.     INITWORD    LIB_VERSION,VERSION
  308.     INITWORD    LIB_REVISION,REVISION
  309.     INITLONG    LIB_IDSTRING,IDString
  310.     dc.w    0    ;terminate list (only one byte needed)
  311.  
  312. CmdTable:    dc.w    Invalid-CmdTable        ;0    CMD_INVALID
  313.     dc.w    Invalid-CmdTable        ;1    CMD_RESET
  314.     dc.w    Read-CmdTable        ;2    CMD_READ
  315.     dc.w    Write-CmdTable        ;3    CMD_WRITE / ETD_
  316.     dc.w    Update-CmdTable        ;4    CMD_UPDATE / ETD_
  317.     dc.w    Clear-CmdTable        ;5    CMD_CLEAR / ETD_
  318.     dc.w    MyStop-CmdTable        ;6    CMD_STOP / ETD_
  319.     dc.w    Start-CmdTable        ;7    CMD_START
  320.     dc.w    Invalid-CmdTable        ;8    CMD_FLUSH
  321.     dc.w    Motor-CmdTable        ;9    TD_MOTOR / ETD_
  322.     dc.w    TDSeek-CmdTable        ;10    TD_SEEK / ETD_
  323.     dc.w    Format-CmdTable        ;11    TD_FORMAT
  324.     dc.w    TDRemove-CmdTable        ;12    TD_REMOVE
  325.     dc.w    ChangeNum-CmdTable        ;13    TD_CHANGENUM
  326.     dc.w    ChangeState-CmdTable    ;14    TD_CHANGESTATE
  327.     dc.w    ProtStatus-CmdTable        ;15    TD_PROTSTATUS
  328.     dc.w    TDRawRead-CmdTable        ;16    TD_RAWREAD
  329.     dc.w    RawWrite-CmdTable        ;17    TD_RAWWRITE
  330.     dc.w    TDGetDriveType-CmdTable    ;18    TD_GETDRIVETYPE
  331.     dc.w    GetNumTracks-CmdTable    ;19    TD_GETNUMTRACKS
  332.     dc.w    AddChangeInt-CmdTable    ;20    TD_ADDCHANGEINT
  333.     dc.w    RemChangeInt-CmdTable    ;21    TD_REMCHANGEINT
  334.     dc.w    GetGeometry-CmdTable    ;22    TD_GETGEOMETRY
  335.     dc.w    Invalid-CmdTable        ;23    TD_EJECT
  336. EndCmdTable:
  337. HighestCommand    equ    ((EndCmdTable-CmdTable)/2)-1
  338. Invalid:    move.b    #IOERR_NOCMD,IO_ERROR(A_IO)
  339.     rts
  340.  
  341. InitRoutine:
  342. ;A0 - segment
  343. ;D0 - device ptr
  344.  
  345. ;Returns with the device ptr still in D0 if successful, otherwise zero.
  346.  
  347.     PUTDEBUG    <'InitRoutine: Entered'>
  348.     movem.l    d1-d7/a0-a6,-(sp)
  349.     move.l    d0,A_DEVICE
  350.     move.l    a0,SegList(A_DEVICE)
  351.     move.l    4,a6
  352.  
  353. ;Initialize ports
  354.     lea    TaskPort(A_DEVICE),a0
  355.     bsr    InitPort
  356.     lea    TimerPort(A_DEVICE),a0
  357.     bsr    InitPort
  358.  
  359. ;Invalidate track buffer
  360.     bsr    Clear
  361.  
  362. ;Open libraries/resources
  363.  
  364.     lea    DiskResourceName(pc),a1    ;'disk.resource'
  365.     SYS    OpenResource
  366.     move.l    d0,DiskResourceBase(A_DEVICE)
  367.     beq    .Failed
  368.     lea    CIAName(pc),a1    ;'ciab.resource'
  369.     SYS    OpenResource
  370.     move.l    d0,CIABase(A_DEVICE)
  371.     beq    .Failed
  372.  
  373.     lea    GraphName(pc),a1
  374.     SYS    OldOpenLibrary
  375.     move.l    d0,GraphBase(A_DEVICE)
  376.     beq    .Failed
  377.     lea    IntName(pc),a1
  378.     SYS    OldOpenLibrary
  379.     move.l    d0,IntBase(A_DEVICE)
  380.     beq    .Failed
  381.  
  382. ;Allocate buffer memory.
  383.     move.l    #DISK_RawBufSize*2,d0
  384.     move.l    #MEMF_CHIP,d1
  385.     SYS    AllocMem
  386.     move.l    d0,RawBuffer(A_DEVICE)
  387.     beq    .Failed
  388.  
  389.     move.l    #512*22,d0
  390.     move.l    #MEMF_CHIP,d1
  391.     SYS    AllocMem
  392.     move.l    d0,DecodedBuffer(A_DEVICE)
  393.     beq    .Failed
  394.  
  395.     move.l    #(1088*22)+2,d0
  396.     move.l    #MEMF_CHIP,d1
  397.     SYS    AllocMem
  398.     move.l    d0,VerifyBuffer(A_DEVICE)
  399.     beq    .Failed
  400.  
  401. ;Set up disk.resource structure.
  402.     lea    DiskResourcePort(A_DEVICE),a0
  403.     bsr    InitPort
  404.     move.l    a0,DiskResourceUnit+MN_REPLYPORT(A_DEVICE)
  405. ;    move.b    #PA_SIGNAL,MP_FLAGS(a0)    ;not needed (0)
  406.     lea    Name(pc),a0
  407.     move.l    a0,DiskResourceUnit+LN_NAME(A_DEVICE)
  408.  
  409.     move.l    A_DEVICE,DiskResourceUnit+DRU_DISCBLOCK+IS_DATA(A_DEVICE)
  410.     move.l    A_DEVICE,DiskResourceUnit+DRU_DISCSYNC+IS_DATA(A_DEVICE)
  411.     move.l    A_DEVICE,DiskResourceUnit+DRU_INDEX+IS_DATA(A_DEVICE)
  412.     lea    BlockInt(pc),a0
  413.     move.l    a0,DiskResourceUnit+DRU_DISCBLOCK+IS_CODE(A_DEVICE)
  414.     lea    SyncInt(pc),a0
  415.     move.l    a0,DiskResourceUnit+DRU_DISCSYNC+IS_CODE(A_DEVICE)
  416.     lea    IndexInt(pc),a0
  417.     move.l    a0,DiskResourceUnit+DRU_INDEX+IS_CODE(A_DEVICE)
  418.     moveq    #NT_INTERRUPT,d0
  419.     move.b    d0,DiskResourceUnit+DRU_DISCBLOCK+LN_TYPE(A_DEVICE)
  420.     move.b    d0,DiskResourceUnit+DRU_DISCSYNC+LN_TYPE(A_DEVICE)
  421.     move.b    d0,DiskResourceUnit+DRU_INDEX+LN_TYPE(A_DEVICE)
  422.  
  423. ;Initialize timer IORequest (except signal)
  424.     lea    TimerPort(A_DEVICE),a0
  425. ;    move.b    #PA_SIGNAL,MP_FLAGS(a0)    ;not needed (0)
  426.     move.l    a0,TimerIORequest+MN_REPLYPORT(A_DEVICE)
  427.     lea    TimerName(pc),a0
  428.     moveq    #UNIT_MICROHZ,d0
  429.     lea    TimerIORequest(A_DEVICE),a1
  430.     moveq    #0,d1
  431.     SYS    OpenDevice
  432.     tst.l    d0
  433.     bne    .Failed
  434.  
  435. ;*** Set up unit structures
  436.     moveq    #0,d2
  437.     lea    Unit0(A_DEVICE),A_UNIT
  438. .UnitLoop:
  439.     move.b    d2,UnitNum(A_UNIT)
  440.     lea    ChangeIntList(A_UNIT),a0
  441.     NEWLIST    a0
  442.     bset    #1,TDU_PUBFLAGS(A_UNIT)    ;verify ON!
  443.     move.b    #RETRYCNT,TDU_RETRYCNT(A_UNIT)
  444.     lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  445.     addq.b    #1,d2
  446.     cmp.b    #MD_NUMUNITS,d2
  447.     blo    .UnitLoop
  448.  
  449. ;Set up task
  450.     move.b    #PA_IGNORE,TaskPort+MP_FLAGS(A_DEVICE)
  451.     move.b    #NT_MSGPORT,TaskPort+LN_TYPE(A_DEVICE)
  452.     lea    Task(A_DEVICE),a1    ;Task Control Block
  453.  
  454. ;To make CrossDOS happy under 1.2/1.3
  455.     st    TC_Userdata(a1)
  456.  
  457.     lea    Name(pc),a0
  458.     move.l    a0,LN_NAME(a1)
  459.     move.b    #TASKPRI,LN_PRI(a1)
  460.     move.b    #NT_TASK,LN_TYPE(a1)
  461.     lea    TaskCode(pc),a2    ;initial PC
  462.     sub.l    a3,a3    ;final PC
  463.     lea    TaskStack(A_DEVICE),a0
  464.     move.l    a0,TC_SPLOWER(a1)
  465.     lea    STACKSIZE(a0),a0
  466.     move.l    a0,TC_SPUPPER(a1)
  467.  
  468.     move.l    A_DEVICE,-(a0)    ;pass device pointer to task
  469.     move.l    a0,TC_SPREG(a1)
  470.     move.l    a1,TaskPort+MP_SIGTASK(A_DEVICE)
  471.     SYS    AddTask
  472.  
  473.     move.l    A_DEVICE,d0
  474.     PUTDEBUG    <'InitRoutine: Done'>
  475. .End:    movem.l    (sp)+,d1-d7/a0-a6
  476.     rts
  477. .Failed:
  478.     PUTDEBUG    <'InitRoutine: Failed'>
  479. ;    bsr    CloseEverything
  480.     moveq    #0,d0
  481.     bra    .End
  482.  
  483. InitPort:
  484. ;Enter with pointer to port in A0. All registers preserved.
  485.     push    a0
  486.     lea    MP_MSGLIST(a0),a0
  487.     NEWLIST    a0
  488.     pop    a0
  489.     rts
  490.  
  491.     comment |
  492. CloseEverything:
  493. ;This routines cleans up device stuff. Enter with A_DEVICE.
  494.  
  495.     movem.l    d0-d1/a0-a1/a6,-(sp)
  496.     move.l    4,a6
  497. ;Close timer
  498.     tst.b    TimerIORequest+IO_ERROR(A_DEVICE)
  499.     beq    .SkipTimer
  500.     lea    TimerIORequest(A_DEVICE),a1
  501.     SYS    CloseDevice
  502. .SkipTimer:
  503.  
  504. ;Remove task
  505.     lea    Name(pc),a1
  506.     SYS    FindTask
  507.     tst.l    d0
  508.     beq    .SkipTask
  509.     move.l    d0,a1
  510.     SYS    RemTask
  511. .SkipTask:
  512.  
  513. ;Close libraries
  514.     move.l    GraphBase(A_DEVICE),d0
  515.     beq    .SkipGfx
  516.     move.l    d0,a1
  517.     SYS    CloseLibrary
  518. .SkipGfx:
  519.     move.l    IntBase(A_DEVICE),d0
  520.     beq    .SkipInt
  521.     move.l    d0,a1
  522.     SYS    CloseLibrary
  523. .SkipInt:
  524.  
  525. ;Free CHIP RAM. (Note: This will change when I support other drive types).
  526.     move.l    RawBuffer(A_DEVICE),d0
  527.     beq    .SkipRaw
  528.     move.l    d0,a1
  529.     move.l    #DISK_RawBufSize,d0
  530.     SYS    FreeMem
  531. .SkipRaw:
  532.     move.l    DecodedBuffer(A_DEVICE),d0
  533.     beq    .SkipDecoded
  534.     move.l    d0,a1
  535.     move.l    #512*11,d0
  536.     SYS    FreeMem
  537. .SkipDecoded:
  538.     move.l    VerifyBuffer(A_DEVICE),d0
  539.     beq    .SkipVerify
  540.     move.l    d0,a1
  541.     move.l    #(1088*11)+2,d0
  542.     SYS    FreeMem
  543. .SkipVerify:
  544. .End:    movem.l    (sp)+,d0-d1/a0-a1/a6
  545.     rts
  546. |
  547.  
  548. ;******************************* Task code ******************************
  549.  
  550. TaskCode:
  551.     PUTDEBUG    <'Task: Entered'>
  552.     move.l    4,a6
  553.  
  554. ;Grab the arguments passed down from our parent
  555.     move.l    4(sp),A_DEVICE    ;Device pointer
  556.  
  557. ;General initialization
  558.  
  559.     lea    StartSigs(A_DEVICE),a2
  560.     moveq    #NumSigs-1,d2    ;Number of signals to allocate-1
  561. .SigLoop:
  562.     moveq    #-1,d0    ;-1 is any signal at all
  563.     SYS    AllocSignal    ;Allocate signals for I/O interrupts
  564.     moveq    #0,d1    ;Convert bit number signal mask
  565.     bset    d0,d1
  566.     move.l    d1,(a2)+    ;Save in unit structure
  567.     dbra    d2,.SigLoop
  568.  
  569.     moveq    #-1,d0    ;-1 is any signal at all
  570.     SYS    AllocSignal    ;Allocate a signal
  571.     move.b    d0,TaskPort+MP_SIGBIT(A_DEVICE)
  572.     move.b    #PA_SIGNAL,TaskPort+MP_FLAGS(A_DEVICE)    ;Make message port "live"
  573.  
  574.     moveq    #-1,d0    ;-1 is any signal at all
  575.     SYS    AllocSignal    ;Allocate a signal
  576.     move.b    d0,TimerPort+MP_SIGBIT(A_DEVICE)
  577.     move.l    ThisTask(a6),TimerPort+MP_SIGTASK(A_DEVICE)
  578.  
  579.     moveq    #-1,d0    ;-1 is any signal at all
  580.     SYS    AllocSignal    ;Allocate a signal
  581.     move.b    d0,DiskResourcePort+MP_SIGBIT(A_DEVICE)
  582.     move.l    ThisTask(a6),DiskResourcePort+MP_SIGTASK(A_DEVICE)
  583.  
  584.     bsr    GetDrive
  585.     bsr    Inquire
  586.  
  587. ;Get drive types
  588.     moveq    #MD_NUMUNITS-1,d0
  589.     lea    Unit0(A_DEVICE),A_UNIT
  590. .TypeLoop:
  591.     bsr    GetDriveType
  592.     lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  593.     dbra    d0,.TypeLoop
  594.  
  595.     bsr    SeekZeroAll    ;Send all drives to track zero.
  596.     bsr    FreeDrive
  597.  
  598.     bra    .NextMessage
  599.  
  600. ;Main loop: Wait for a new message and handle disk changes.
  601.  
  602. .MainLoop:
  603.     moveq    #0,d0
  604.     move.b    MP_SIGBIT+TaskPort(A_DEVICE),d1
  605.     bset    d1,d0
  606.     move.l    #500000,d1
  607.     bsr    TimeOutWait
  608.     tst.l    d0
  609.     bne    .NextMessage
  610.  
  611. ;0.5 seconds have passed without receiving any work, so we check for disk
  612. ;changes, then drop into .NextMessage.
  613. ;Note: A6 undefined.
  614.  
  615. .CheckDiskChange:
  616.     moveq    #MD_NUMUNITS-1,d2
  617.     move.b    InquireBits(A_DEVICE),d3
  618.     lea    Unit0(A_DEVICE),A_UNIT
  619.     bsr    GetDrive
  620.     move.l    TimerIORequest+IO_DEVICE(A_DEVICE),a6
  621.  
  622. ;Algorithm (for each unit):
  623. ;Check hardware diskchange bit. If disk was ejected, seek to track zero,
  624. ;clear DiskInDrive bit. End.
  625. ;If no disk in drive, check NoClick bit. If set, immediately step toward
  626. ;track zero (using custom step routine). If clear, check the
  627. ;Drive_LastChecked time against the current time. If less than 2.5 seconds,
  628. ;End. If >2.5 seconds, step the head toward track zero, unless already on
  629. ;track zero. Check the hardware diskchange bit. If a disk is present in the
  630. ;drive set the DiskInDrive bit and check the hardware write protect status,
  631. ;setting WriteProtected as needed. End.
  632. ;Note: We also increment the diskchange counter in the public part of the
  633. ;unit structure, if a disk was inserted or removed.
  634.  
  635. .UnitLoop:
  636.     move.b    UnitNum(A_UNIT),d4
  637.     btst    d4,d3
  638.     beq    .NoCheck
  639.  
  640.     lea    TempTimeVal(A_DEVICE),a0
  641.     bsr    GetSysTime
  642.  
  643.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  644.     beq    .ThinkNoDisk
  645.     bsr    SelectDriveSameMotor
  646.     btst    #CIAB_DSKCHANGE,ciaapra
  647.     bne    .NoChange
  648. ;Disk was removed.
  649.     bclr    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  650.     bsr    SeekZero
  651.     bsr    MotorOff
  652.     bsr    Clear
  653.     bra    .Change
  654. .ThinkNoDisk:
  655.     btst    #TDPB_NOCLICK,TDU_PUBFLAGS(A_UNIT)
  656.     beq    .Click
  657.     bsr    SelectDriveSameMotor
  658.     bset    #CIAB_DSKDIREC,ciabprb    ;set to "out" (lower tracks)
  659.     bset    #CIAB_DSKSTEP,ciabprb
  660.     bclr    #CIAB_DSKSTEP,ciabprb    ;step head
  661.     bset    #CIAB_DSKSTEP,ciabprb
  662.     bsr    Deselect
  663.     move.l    TDU_SETTLEDELAY(A_UNIT),d0
  664.     bsr    delay
  665.     bsr    SelectDriveSameMotor
  666.     bra    .ChkChg
  667. .Click:
  668.     lea    Drive_LastCheck(A_UNIT),a1
  669.     SYS    SubTime
  670.     cmp.l    #2,TV_SECS(a0)
  671.     blo    .NoCheck
  672.     bhi    .SkipMicro
  673.     cmp.l    #500000,TV_MICRO(a0)
  674.     blo    .NoCheck
  675. .SkipMicro:
  676.     lea    Drive_LastCheck(A_UNIT),a0
  677.     bsr    GetSysTime
  678.     move.b    UnitNum(A_UNIT),d2    ;for Seek
  679.     move.w    TDU_CURRTRK(A_UNIT),d3
  680.     subq.w    #2,d3
  681.     bpl    .NotZero
  682.     moveq    #2,d3
  683. .NotZero:    bsr    SelectDriveSameMotor
  684.     bsr    SeekNoUpdate
  685. .ChkChg:    btst    #CIAB_DSKCHANGE,ciaapra
  686.     beq    .NoChange    ;no disk in drive
  687.     bsr    GetDriveType    ;reread drive type
  688.     bset    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  689.     bclr    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  690.     btst    #CIAB_DSKPROT,ciaapra
  691.     bne    .Change    ;not write protected
  692.     bset    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  693. .Change:
  694.     bsr    Deselect
  695.     addq.l    #1,TDU_COUNTER(A_UNIT)
  696.  
  697. ;This code notifies users of TD_REMOVE and TD_ADDCHANGEINT via Cause.
  698.  
  699.     push    a6
  700.     move.l    4,a6
  701.     SYS    Forbid
  702.     move.l    TDRemoveInt(A_UNIT),d0
  703.     beq    .NoRemoveInt
  704.     move.l    d0,a1
  705.     SYS    Cause
  706. .NoRemoveInt:
  707.     move.l    ChangeIntList+LH_HEAD(A_UNIT),a2
  708. .IntLoop:    move.l    (a2),d0
  709.     beq    .DoneInt
  710.     move.l    IO_DATA(a2),a1
  711.     move.l    d0,a2
  712.     SYS    Cause
  713.     bra    .IntLoop
  714. .DoneInt:    SYS    Permit
  715.     pop    a6
  716. .NoChange:
  717.     lea    LastCheck(A_DEVICE),a0
  718.     bsr    GetSysTime
  719. .NoCheck:
  720.     lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  721.     dbra    d2,.UnitLoop
  722.     move.l    4,a6
  723.     bsr    FreeDrive
  724.  
  725. .NextMessage:
  726.     btst    #DEVB_Stopped,DEV_FLAGS(A_DEVICE)    ;See if we are stopped
  727.     bne    .MainLoop    ;device is stopped, so ignore messages
  728.  
  729.     lea    TaskPort(A_DEVICE),a0
  730.     SYS    GetMsg    ;Get the next request
  731.     tst.l    d0
  732.     beq    .MainLoop    ;no message?
  733.     move.l    d0,A_IO    ;Do this request
  734.     move.l    IO_UNIT(A_IO),A_UNIT
  735.  
  736. ;Handle TDB_EXTCOM and dispatch command
  737.     move.w    IO_COMMAND(A_IO),d0
  738.  
  739.     IFNE    INFO_LEVEL
  740.     swap    d0
  741.     clr.w    d0
  742.     swap    d0
  743.     move.l    d0,-(sp)
  744.     PUTDEBUG    <'Command=%ld'>
  745.     addq.l    #4,sp
  746.     ENDC
  747.  
  748.     bclr    #TDB_EXTCOM,d0
  749.     beq    .NoExt
  750.     move.l    TDU_COUNTER(A_UNIT),d1
  751.     cmp.l    IOTD_COUNT(A_IO),d1
  752.     bls    .NoExt
  753. .ChgErr:    PUTDEBUG    <'Change error!'>
  754.     move.b    #TDERR_DiskChanged,IO_ERROR(A_IO)
  755.     bra    .Reply
  756. .NoExt:    move.l    #%000000111000111000011100,d1    ;specifies which commands should check for disk
  757.     btst    d0,d1
  758.     beq    .NoDiskNeeded
  759.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  760.     beq    .ChgErr
  761. .NoDiskNeeded:
  762.     bsr    GetDrive
  763.     lea    CmdTable(pc),a0
  764.     add.w    d0,d0
  765.     add.w    (a0,d0.w),a0
  766.     moveq    #0,d7    ;clear error flag
  767.     jsr    (a0)
  768.     bsr    FreeDrive
  769.     cmp.w    #TD_ADDCHANGEINT,IO_COMMAND(A_IO)
  770.     beq    .SkipReply
  771. .Reply:    move.l    A_IO,a1
  772.     SYS    ReplyMsg
  773. .SkipReply:
  774.  
  775. ;If at least 0.5 seconds has passed since last checking diskchange, do so
  776. ;now.
  777.     move.l    TimerIORequest+IO_DEVICE(A_DEVICE),a6
  778.     lea    TempTimeVal(A_DEVICE),a0
  779.     bsr    GetSysTime
  780.     lea    LastCheck(A_DEVICE),a1
  781.     SYS    SubTime
  782.     tst.l    TV_SECS(a0)
  783.     bne    .CheckDiskChange
  784.     cmp.l    #500000,TV_MICRO(a0)
  785.     bhs    .CheckDiskChange
  786.     lea    LastCheck(A_DEVICE),a0
  787.     bsr    GetSysTime
  788.     move.l    4,a6
  789.     bra    .NextMessage
  790.  
  791. GetSysTime:
  792.     cmp.w    #36,LIB_VERSION(a6)
  793.     bls    .OldKS
  794.     jmp    _LVOGetSysTime(a6)
  795. .OldKS:
  796. ;Compatibility routine for 1.2/1.3
  797.     movem.l    d0-d1/a0-a2/a6,-(sp)
  798.     move.l    a0,a2
  799.     lea    TimerIORequest(A_DEVICE),a1
  800.     move.l    4,a6
  801.     move.w    #TR_GETSYSTIME,IO_COMMAND(a1)
  802.     SYS    DoIO
  803.     lea    TimerIORequest(A_DEVICE),a1
  804.     move.l    IOTV_TIME+TV_SECS(a1),TV_SECS(a2)
  805.     move.l    IOTV_TIME+TV_MICRO(a1),TV_MICRO(a2)
  806.     movem.l    (sp)+,d0-d1/a0-a2/a6
  807.     rts
  808.  
  809. ;******************** External device routines ***********************
  810.  
  811. Open:
  812.  
  813. ;A6 - device ptr
  814. ;A1 - IORequest
  815. ;D0 - unit number
  816. ;D1 - flags (not used)
  817.  
  818. ;Important: On error, MUST put -1 in IO_DEVICE. This routine has no return
  819. ;value in d0 (return code is in IO_ERROR).
  820.  
  821.     PUTDEBUG    <'Open: Entered'>
  822.     moveq    #MD_NUMUNITS,d1
  823.     cmp.l    d1,d0
  824.     bhs    .Error
  825.     btst    d0,InquireBits(a6)
  826.     beq    .Error
  827.     lea    Unit0(a6),a0
  828.     mulu.w    #MyUnit_Sizeof,d0
  829.     add.l    d0,a0
  830.     move.l    a0,IO_UNIT(a1)
  831.     addq.w    #1,LIB_OPENCNT(a6)
  832.     clr.b    IO_ERROR(a1)    ;no error
  833.     move.b    #NT_REPLYMSG,LN_TYPE(a1)    ;Mark IORequest as "complete"
  834.     PUTDEBUG    <'Open: Done'>
  835.     rts
  836. .Error:
  837.     PUTDEBUG    <'Open: Failed'>
  838.  
  839. ;VirusX didn't like this.
  840. ;    move.b    #IOERR_OPENFAIL,IO_ERROR(a1)
  841.  
  842. ;NOTE: Trackdisk will return TDERR_BadDriveType if TDB_ALLOW_NON_3_5 flag set
  843. ;in "flags" and the drive is not present. (This is just trivia).
  844.  
  845.     move.b    #TDERR_BadUnitNum,IO_ERROR(a1)
  846.     moveq    #-1,d0
  847.     move.l    d0,IO_DEVICE(a1)
  848.     rts
  849.  
  850. _Close:
  851.  
  852. ;A6 - device ptr
  853. ;A1 - IORequest
  854.  
  855. ;Must return either 0 or, if the device wishes to be unloaded, the segment
  856. ;list.
  857.  
  858.     PUTDEBUG    <'Close: Called'>
  859.     moveq    #0,d0
  860.     rts
  861.  
  862. Expunge:
  863.  
  864. ;A6 - device ptr
  865.  
  866. ;Must return either 0 or SegList ptr in D0.
  867.  
  868.     moveq    #0,d0
  869.     rts
  870.  
  871. BeginIO:
  872. ;A1 - IORequest
  873. ;A6 - device ptr
  874.  
  875.     movem.l    d7/a3-a6,-(sp)
  876.     move.l    a1,A_IO
  877.     move.l    IO_UNIT(A_IO),A_UNIT
  878.     move.l    a6,A_DEVICE
  879.     move.l    4,a6
  880.  
  881.     clr.b    IO_ERROR(A_IO)
  882.     move.b    #NT_MESSAGE,LN_TYPE(A_IO)    ;So WaitIO() is guaranteed to work
  883.  
  884. ;Decide whether the command is immediate or queued
  885.     move.w    IO_COMMAND(A_IO),d1
  886.     bclr    #15,d1
  887.     cmp.w    #HighestCommand,d1
  888.     bhi    .BadCmd
  889.     move.l    #%111011001111000110000011,d0    ;specifies what commands are immediate
  890.     btst    d1,d0
  891.     beq    .Queue
  892.     add.w    d1,d1
  893.     lea    CmdTable(pc),a0
  894.     add.w    (a0,d1.w),a0
  895.     moveq    #0,d7    ;clear error flag
  896.     jsr    (a0)
  897. .Reply:    btst    #IOB_QUICK,IO_FLAGS(A_IO)
  898.     bne    .End
  899.     move.l    A_IO,a1
  900.     SYS    ReplyMsg
  901. .End:    movem.l    (sp)+,d7/a3-a6
  902.     rts
  903. .Queue:    bclr    #IOB_QUICK,IO_FLAGS(A_IO)    ;We did NOT complete this quickly
  904.     lea    TaskPort(A_DEVICE),a0
  905.     move.l    A_IO,a1
  906.     SYS    PutMsg
  907.     bra    .End
  908. .BadCmd:    move.b    #IOERR_NOCMD,IO_ERROR(a1)
  909.     bra    .Reply
  910.  
  911. AbortIO:
  912.  
  913. ;A6 - device ptr
  914. ;A1 - IORequest
  915.  
  916.     move.b    #IOERR_ABORTED,IO_ERROR(a1)    ;We always say we succeed(ed)
  917.     moveq    #0,d0    ;another success code
  918.     rts
  919.  
  920. ;**************** Device command (IO_COMMAND) routines *************************
  921.  
  922. ;Note: A6 = ExecBase upon entering a command routine.
  923. ;The low-level routines load $DFF000 into A6 when needed.
  924.  
  925. SaveRegs    setrl    d0-d3/d6-d7/a0-a2/a6
  926.  
  927. Read:
  928.     PUTDEBUG    <'Read: Called'>
  929.     movem.l    SaveRegs,-(sp)
  930.     bsr    RWSetup
  931.     tst.l    d7
  932.     bne    FinishRW
  933.  
  934.     bsr    DISK_Update    ;required because of complex write scheme
  935. ;Check for sector label nonsense
  936.     tst.b    IO_COMMAND(A_IO)
  937.     bpl    .NoLabel
  938.     move.l    IOTD_SECLABEL(A_IO),d2
  939.     bne    ReadSecLabel
  940. .NoLabel:
  941.  
  942.     bsr    DISK_Read
  943.     PUTDEBUG    <'Read: Done'>
  944.     bra    FinishRW
  945. Format:
  946. Write:    movem.l    SaveRegs,-(sp)
  947.     bsr    RWSetup
  948.     tst.l    d7
  949.     bne    FinishRW
  950.  
  951. ;Check for sector label nonsense
  952.     tst.b    IO_COMMAND(A_IO)
  953.     bpl    .NoLabel
  954.     move.l    IOTD_SECLABEL(A_IO),d2
  955.     bne    WriteSecLabel
  956. .NoLabel:
  957.  
  958.     bsr    DISK_Write
  959. FinishRW:    clr.l    IO_ACTUAL(A_IO)
  960.     move.b    d7,IO_ERROR(A_IO)
  961.     bne    .Skip
  962.     move.l    IO_LENGTH(A_IO),IO_ACTUAL(A_IO)
  963. .Skip:    movem.l    (sp)+,SaveRegs
  964.     rts
  965. RWSetup:
  966.     move.l    SectorsPerTrack(A_UNIT),d6
  967.     lsl.l    #8,d6
  968.     add.l    d6,d6    ;*512
  969.     move.l    #_custom,a6
  970.     move.l    IO_LENGTH(A_IO),d0
  971.     move.l    IO_OFFSET(A_IO),d1
  972.     move.l    IO_DATA(A_IO),a0
  973.     move.l    d1,d2    ;offset
  974.     add.l    d0,d2    ;length
  975.     cmp.l    BytesPerDisk(A_UNIT),d2
  976.     bhi    .Error
  977.     bsr    SelectDrive
  978.     bra    SelectSide
  979. .Error:    moveq    #DISK_BadParameter,d7
  980.     rts
  981.  
  982. ;Here are the routines for dealing with read/write requests that involve
  983. ;the sector label. Note that, unlike the usual read/write routines of my
  984. ;trackdisk, the normal parameter restrictions (e.g. IO_OFFSET and IO_LENGTH
  985. ;must be a multiple of 512) MUST be observed. And I don't check for illegal
  986. ;parameters, either. These routines are optimized for compactness rather
  987. ;than performance because they are rarely (if ever) used.
  988. ;Enter with:
  989. ;IO_LENGTH: D0
  990. ;IO_OFFSET: D1
  991. ;IO_DATA:   A0
  992.  
  993. ReadSecLabel:
  994.     PUTDEBUG    <'READSECLABEL!'>
  995.  
  996.     move.l    d2,a1
  997.     move.l    d0,d2
  998.     move.l    #512,d0
  999. .Read:    bsr    DISK_Read
  1000.     move.l    d1,d3
  1001.     add.l    d0,d1
  1002.     add.l    d0,a0
  1003.     divu.w    d6,d3    ;offset/tracksize
  1004.     swap    d3    ;remainder=sector# (in bytes)
  1005.     lsr.w    #5,d3    ;divide by 32 to get label offset
  1006.     lea    SectorLabels(A_DEVICE),a2
  1007.     lea    (a2,d3.w),a2    ;get pointer to label
  1008.     moveq    #3,d3
  1009. ..    move.l    (a2)+,(a1)+    ;copy label
  1010.     dbra    d3,..
  1011.     sub.l    d0,d2
  1012.     bne    .Read
  1013.     bra    FinishRW
  1014.  
  1015. WriteSecLabel:
  1016.     PUTDEBUG    <'WRITESECLABEL!'>
  1017.  
  1018.     move.l    d2,a1
  1019.     move.l    d0,d2
  1020. .Write:
  1021.     move.l    d1,d3
  1022.     divu.w    d6,d3    ;offset/tracksize
  1023.     swap    d3    ;remainder=sector# (in bytes)
  1024.     lsr.w    #5,d3    ;divide by 32 to get label offset
  1025.  
  1026. ;We check to see whether we can write a full track. (Somehow, I can't
  1027. ;ignore performance completely :-)).
  1028.     tst.w    d3
  1029.     bne    .Read
  1030.     cmp.l    d6,d0
  1031.     bhs    .FullTrack
  1032. .Read:    moveq    #0,d0
  1033.     bsr    DISK_Read    ;force a track read
  1034.     lea    SectorLabels(A_DEVICE),a2
  1035.     lea    (a2,d3.w),a2    ;get pointer to label
  1036.     moveq    #3,d3
  1037. ..    move.l    (a1)+,(a2)+    ;copy label
  1038.     dbra    d3,..
  1039.     move.l    #512,d0
  1040. .L1:    bsr    DISK_Write
  1041.     add.l    d0,d1
  1042.     add.l    d0,a0
  1043.     sub.l    d0,d2
  1044.     bne    .Write
  1045.     bra    FinishRW
  1046. .FullTrack:
  1047.     lea    SectorLabels(A_DEVICE),a2
  1048.     moveq    #((16*22)/4)-1,d3
  1049. ..    move.l    (a1)+,(a2)+    ;copy all sector labels
  1050.     dbra    d3,..
  1051.     move.l    d6,d0
  1052.     bra    .L1
  1053.  
  1054. Update:    move.l    d7,-(sp)
  1055.     moveq    #0,d7
  1056.     bsr    DISK_Update
  1057.     move.b    d7,IO_ERROR(A_IO)
  1058.     move.l    (sp)+,d7
  1059.     rts
  1060.  
  1061. Clear:
  1062. ;This routine marks the track buffer as invalid.
  1063.     st    BufferDrive(A_DEVICE)
  1064.     bclr    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  1065.     rts
  1066.  
  1067. Motor:
  1068. ;Controls the drive motor
  1069. ;If IO_LENGTH=1, motor on
  1070. ;   IO_LENGTH=0, motor off
  1071. ;Old motor state (0=off, anything else means on) stored in IO_ACTUAL.
  1072.  
  1073.     push    d2
  1074.     clr.l    IO_ACTUAL(A_IO)
  1075.     move.b    UnitNum(A_UNIT),d2
  1076.     btst    d2,MotorState(A_DEVICE)
  1077.     beq    .WasOff
  1078.     move.l    #1,IO_ACTUAL(A_IO)
  1079. .WasOff:    tst.l    IO_LENGTH(A_IO)
  1080.     beq    .Off
  1081. ;Turn motor on
  1082.     bsr    SelectDrive
  1083.     bra    .End
  1084. .Off:
  1085. ;Turn motor off
  1086.     bclr    d2,MotorState(A_DEVICE)
  1087.     bsr    Deselect
  1088.     bset    #CIAB_DSKMOTOR,ciabprb    ;motor off
  1089.     addq.b    #3,d2
  1090.     bclr    d2,ciabprb    ;select drive X
  1091. .End:    pop    d2
  1092.     rts
  1093.  
  1094. ChangeState:
  1095. ;Returns whether there is a disk currently in the drive
  1096. ;IO_ACTUAL=0 if disk in drive
  1097. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1098.  
  1099.     clr.l    IO_ACTUAL(A_IO)
  1100.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  1101.     bne    .End
  1102.     move.l    #1,IO_ACTUAL(A_IO)    ;no disk in drive
  1103. .End:    rts
  1104.  
  1105. ChangeNum:
  1106. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1107.     move.l    TDU_COUNTER(A_UNIT),IO_ACTUAL(A_IO)
  1108.     rts
  1109.  
  1110. ProtStatus:
  1111. ;IO_ACTUAL=0 if disk is not write protected
  1112. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1113.  
  1114. ;Very important for compatibility: we must return an error (disk changed)
  1115. ;if there's no disk in the drive.
  1116.     btst    #UNITB_DiskInDrive,UNIT_FLAGS(A_UNIT)
  1117.     bne    .OK
  1118.     move.b    #TDERR_DiskChanged,IO_ERROR(A_IO)
  1119.     rts
  1120.  
  1121. .OK:    clr.l    IO_ACTUAL(A_IO)
  1122.     btst    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  1123.     beq    .End    ;not write protected
  1124.     move.l    #1,IO_ACTUAL(A_IO)    ;no disk in drive
  1125. .End:    rts
  1126.  
  1127. TDGetDriveType:
  1128. ;Returns type of drive in IO_ACTUAL
  1129. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1130.     clr.l    IO_ACTUAL(A_IO)
  1131.     move.b    DriveType(A_UNIT),IO_ACTUAL+3(A_IO)
  1132.     rts
  1133.  
  1134. GetNumTracks:
  1135. ;Returns number of tracks (note: not cylinders) in IO_ACTUAL
  1136. ;* EXECUTED IMMEDIATELY, POSSIBILY WITHIN AN INTERRUPT *
  1137.  
  1138.     clr.l    IO_ACTUAL(A_IO)
  1139.     move.b    NumTracks(A_UNIT),IO_ACTUAL+3(A_IO)
  1140.     rts
  1141.  
  1142. GetGeometry:
  1143. ;Fills in DriveGeometry structure pointed to by IO_DATA
  1144.     movem.l    d0-d1/a0,-(sp)
  1145.     move.l    IO_DATA(A_IO),a0
  1146.     move.l    #512,dg_SectorSize(a0)    ;in bytes
  1147.     move.l    #2,dg_Heads(a0)    ;number of surfaces
  1148.     clr.l    dg_BufMemType(a0)    ;preferred buffer memory type
  1149.     clr.b    dg_DeviceType(a0)    ;codes as defined in the SCSI-2 spec
  1150.     move.b    #DGF_REMOVABLE,dg_Flags(a0)    ;flags, including removable
  1151.     clr.w    dg_Reserved(a0)
  1152.     move.l    SectorsPerTrack(A_UNIT),d0
  1153.     move.l    d0,dg_TrackSectors(a0)    ;number of sectors/track
  1154.     add.l    d0,d0
  1155.     move.l    d0,dg_CylSectors(a0)    ;number of sectors/cylinder
  1156.     moveq    #0,d1
  1157.     move.b    NumTracks(A_UNIT),d1
  1158.     lsr.l    #1,d1    ;convert tracks -> cylinders
  1159.     move.l    d1,dg_Cylinders(a0)    ;number of cylinders
  1160.     mulu.w    d0,d1
  1161.     move.l    d1,dg_TotalSectors(a0)    ;total # of sectors on drive
  1162.     movem.l    (sp)+,d0-d1/a0
  1163.     rts
  1164.  
  1165. MyStop:    bset    #DEVB_Stopped,DEV_FLAGS(A_DEVICE)
  1166.     bsr    Update
  1167.     bra    Clear
  1168. Start:    movem.l    d0-d1/a0-a1,-(sp)
  1169.     bclr    #DEVB_Stopped,DEV_FLAGS(A_DEVICE)
  1170.     moveq    #0,d0
  1171.     move.b    MP_SIGBIT+TaskPort(A_DEVICE),d1
  1172.     bset    d1,d0
  1173.     lea    Task(A_DEVICE),a1
  1174.     SYS    Signal
  1175.     movem.l    (sp)+,d0-d1/a0-a1
  1176.     rts
  1177.  
  1178. ;Note: This seek routine can't really be depended on by user programs,
  1179. ;because the disk.resource will corrupt the side select bit.
  1180. TDSeek:    movem.l    d0/d3,-(sp)
  1181.     bsr    SelectDriveSameMotor
  1182.     move.l    IO_OFFSET(A_IO),d3
  1183.     cmp.l    BytesPerDisk(A_UNIT),d3
  1184.     bhs    .Error
  1185.     move.l    SectorsPerTrack(A_UNIT),d0
  1186.     lsl.l    #8,d0
  1187.     add.l    d0,d0    ;*512 = bytes per track
  1188.     divu.w    d0,d3
  1189.     bsr    Seek
  1190. .End:    movem.l    (sp)+,d0/d3
  1191.     rts
  1192. .Error:    move.b    #TDERR_NotSpecified,IO_ERROR(A_IO)
  1193.     bra    .End
  1194.  
  1195. TDRawRead:
  1196.     movem.l    d0-d1/d3/a6,-(sp)
  1197.     move.l    #_custom,a6
  1198.     moveq    #0,d1
  1199.     bsr    DoRaw
  1200.     movem.l    (sp)+,d0-d1/d3/a6
  1201.     rts
  1202.  
  1203. RawWrite:
  1204.     movem.l    d0-d1/d3/a6,-(sp)
  1205.     move.l    #_custom,a6
  1206.     btst    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  1207.     bne    .WPErr
  1208.     move.w    #1<<14,d1
  1209.     bsr    DoRaw
  1210.     move.l    #3*1000,d0
  1211.     bsr    delay    ;post-write delay
  1212. .End:    movem.l    (sp)+,d0-d1/d3/a6
  1213.     rts
  1214. .WPErr:    move.b    #TDERR_WriteProt,IO_ERROR(A_IO)
  1215.     bra    .End
  1216.  
  1217. DoRaw:
  1218. ;Enter with bit 14 set in d1 according to read/write (for dsklen)
  1219. ;Uses d0-d1/d3 (not saved)
  1220. ;Assumes $dff000 in A6
  1221.  
  1222.     clr.l    IO_ACTUAL(A_IO)
  1223.     bsr    SelectDrive
  1224.     move.l    IO_OFFSET(A_IO),d3
  1225.     cmp.b    NumTracks(A_UNIT),d3
  1226.     bhs    .Error
  1227.     bsr    Seek
  1228.     tst.l    d7
  1229.     bne    .Error
  1230.  
  1231.     move.l    IO_DATA(A_IO),dskpt(a6)
  1232.     move.w    #ADKF_WORDSYNC,adkcon(a6)
  1233.     btst    #IOTDB_WORDSYNC,IO_FLAGS(A_IO)
  1234.     beq    .SkipSync
  1235.     move.w    #ADKF_SETCLR+ADKF_WORDSYNC,adkcon(a6)
  1236. .SkipSync:
  1237.     move.w    #ADKF_MSBSYNC,adkcon(a6)
  1238.     move.w    #ADKF_SETCLR+ADKF_FAST+ADKF_MFMPREC,adkcon(a6)
  1239.     bsr    PreComp
  1240.     move.w    #DMAF_SETCLR+DMAF_MASTER+DMAF_DISK,dmacon(a6)    ;enable disk DMA
  1241.     move.w    #$4489,dsksync(a6)    ;set magic sync word
  1242.     bsr    ClearSigs
  1243.     move.w    #INTF_SETCLR+INTF_DSKBLK,intena(a6)    ;enable int
  1244.     move.l    IO_LENGTH(A_IO),d0
  1245.  
  1246.     cmp.l    #32766,d0
  1247.     bhi    .Error
  1248.     lsr.l    #1,d0
  1249.     bset    #15,d0
  1250.     or.w    d1,d0
  1251.  
  1252.     btst    #IOTDB_INDEXSYNC,IO_FLAGS(A_IO)
  1253.     beq    .NoIndex
  1254.     move.w    d0,IndexDskLen(A_DEVICE)
  1255.     bsr    EnableIndex
  1256.     bra    .Wait
  1257. .NoIndex:
  1258.  
  1259.     move.w    d0,dsklen(a6)
  1260.     move.w    d0,dsklen(a6)
  1261. .Wait:    move.l    BlockSig(A_DEVICE),d0
  1262.     move.l    #900*1000*2,d1
  1263.     bsr    TimeOutWait
  1264.     beq    .NoSync
  1265.     move.w    #0,dsklen(a6)
  1266.     move.w    #INTF_DSKBLK,intena(a6)    ;disable int
  1267. .EndIO:    bsr    DisableIndex
  1268.     bsr    ClearSigs
  1269.     tst.b    IO_ERROR(A_IO)
  1270.     bne    .EndRTS
  1271.     move.l    IO_LENGTH(A_IO),IO_ACTUAL(A_IO)
  1272. .EndRTS:    rts
  1273. .Error:    move.b    #TDERR_NotSpecified,IO_ERROR(A_IO)
  1274.     rts
  1275. .NoSync:    bsr    StopDMA
  1276.     move.b    #TDERR_NoSecHdr,IO_ERROR(A_IO)
  1277.     bra    .EndIO
  1278.  
  1279.  
  1280. AddChangeInt:
  1281. ;This command uses the linkage fields of the IORequest to add a ChangeInt
  1282. ;request to a list maintained in the unit structure. This must NOT be
  1283. ;ReplyMsg'ed to avoid destroying the linkage fields - a special compare in
  1284. ;the task code handles this.
  1285.     movem.l    d0-d1/a0-a1,-(sp)
  1286.     move.l    A_IO,a1
  1287.     lea    ChangeIntList(A_UNIT),a0
  1288.     SYS    AddHead    ;could use any list add routine
  1289.     movem.l    (sp)+,d0-d1/a0-a1
  1290.     rts
  1291.  
  1292. RemChangeInt:
  1293. ;This command unlinks the AddChangeInt request from the task's port.
  1294. ;This is (and must be) an immediate command.
  1295. ;Note that because this command occurs asyncronously to the task code, the
  1296. ;task code that scans the ChangeInt list must be protected with a Forbid.
  1297.  
  1298.     movem.l    d0-d1/a0-a1,-(sp)
  1299.     SYS    Forbid
  1300.     move.l    A_IO,a1
  1301.     SYS    Remove
  1302.     SYS    Permit
  1303.     movem.l    (sp)+,d0-d1/a0-a1
  1304.     rts
  1305.  
  1306. TDRemove:
  1307. ;This command is obsolete, but is unfortuntely used by the ROM filesystem.
  1308. ;It accepts an Interrupt structure (for Cause) in IO_DATA. Only one user per
  1309. ;unit is permitted.
  1310.  
  1311.     tst.l    TDRemoveInt(A_UNIT)
  1312.     beq    .Ok
  1313.     move.b    #TDERR_DriveInUse,IO_ERROR(A_IO)
  1314.     rts
  1315. .Ok:    move.l    IO_DATA(A_IO),TDRemoveInt(A_UNIT)
  1316.     rts
  1317.  
  1318. GetDrive:
  1319. ;Obtain the use of this unit via disk.resource.
  1320.     movem.l    d0-d1/a0-a2/a6,-(sp)
  1321.     lea    DiskResourceUnit(A_DEVICE),a2
  1322. .GetUnit:    move.l    DiskResourceBase(A_DEVICE),a6
  1323.     move.l    a2,a1
  1324.     jsr    DR_GETUNIT(a6)
  1325.     tst.l    d0
  1326.     bne    .End
  1327.     lea    DiskResourcePort(A_DEVICE),a0
  1328.     move.l    4,a6
  1329.     SYS    WaitPort
  1330.     bra    .GetUnit
  1331. .End:    movem.l    (sp)+,d0-d1/a0-a2/a6
  1332.     rts
  1333.  
  1334. FreeDrive:
  1335. ;Release this unit to other users of disk.resource.
  1336.  
  1337.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1338.     move.l    DiskResourceBase(A_DEVICE),a6
  1339.     jsr    DR_GIVEUNIT(a6)
  1340.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1341.     rts
  1342.  
  1343. ;***************************** Low-level disk code **************************
  1344.  
  1345. ;Standard register usage:
  1346. ;A6            - $dff000
  1347. ;A5 (A_DEVICE) - device ptr
  1348. ;A4 (A_UNIT)   - unit ptr
  1349. ;A3 (A_IO)     - pointer to IO request
  1350.  
  1351. ;For reading/writing:
  1352. ;D0.L - length (bytes)
  1353. ;D1.L - offset (bytes)
  1354. ;A0.L - buffer
  1355.  
  1356. ;NOTE: Error code returned in D7.L - 0 if ok, else error
  1357.  
  1358. ;General errors
  1359. DISK_BadParameter    equ    TDERR_NotSpecified
  1360.  
  1361. ;Read errors
  1362. DISK_NoSync    equ    TDERR_NoSecHdr
  1363. DISK_BadHeader    equ    TDERR_BadHdrSum
  1364. DISK_BadData    equ    TDERR_BadSecSum
  1365.  
  1366. ;Write errors
  1367. DISK_WriteProtected    equ    TDERR_WriteProt
  1368. DISK_VerifyError    equ    TDERR_NotSpecified
  1369.  
  1370.     IFND    dskpt
  1371. dskpt    equ    dskpth
  1372.     ENDC
  1373.  
  1374. ;Note: This is a public value, but it is NOT meant to be changed!!!
  1375. DISK_RawBufSize    equ    13630
  1376.  
  1377. ciabprb    equ    $bfd100
  1378. ciaapra    equ    $bfe001
  1379. ciabddrb    equ    $bfd300
  1380. ciaaddra    equ    $bfe201
  1381.  
  1382. ***************************************************************
  1383. ;Important disk parameters, summary:
  1384.  
  1385. ;Step rate: 3ms. 4ms when looking for track zero.
  1386. ;Settle time: 15ms
  1387. ;Post-write delay: 3ms (officially 1.3ms)
  1388. ;Side select delay: 2ms (officially 1.3ms)
  1389. ***************************************************************
  1390.  
  1391. DISK_Read:
  1392.     movem.l    d0-d5/a0/a1,-(sp)
  1393.  
  1394.     move.l    a0,a1    ;destination ptr in A1
  1395.     move.l    d0,d5
  1396. .ReadLoop:
  1397.     move.l    d1,d3
  1398.     divu.w    d6,d3    ;d3.w is track #
  1399.     move.l    d3,d4
  1400.     clr.w    d4
  1401.     swap    d4    ;d4.l is byte offset into track
  1402.     bsr    MinSeek
  1403.     tst.l    d4    ;any offset?
  1404.     bne    .Complex    ;yes
  1405.     cmp.l    d6,d5    ;check remaining length
  1406.     blo    .Complex    ;if not a track, forget it
  1407.     move.l    a1,d0
  1408.     btst    #0,d0    ;word aligned?
  1409.     bne    .Complex    ;no, do it the long way
  1410.     move.l    a1,a0
  1411.     bsr    ReadTrackAndDecodeNoBuffer
  1412.     tst.l    d7
  1413.     bne    .End
  1414.     sub.l    d6,d5    ;update length
  1415.     beq    .End
  1416.     add.l    d6,a1    ;update destination pointer
  1417.     add.l    d6,d1    ;update offset
  1418.     bra    .ReadLoop
  1419.  
  1420. .Complex:
  1421.     move.l    DecodedBuffer(A_DEVICE),a0
  1422.     bsr    ReadTrackAndDecodeBuffered
  1423.     tst.l    d7
  1424.     bne    .End
  1425.     add.l    d4,a0
  1426.     sub.l    d6,d4
  1427.     neg.l    d4
  1428.     add.l    d4,d1    ;update offset
  1429.  
  1430. ;D4.L - number of bytes that could be transferred from this track
  1431. ;D5.L - number of bytes left in the entire Read request
  1432.  
  1433.     cmp.l    d5,d4
  1434.     bhs    .FinishUp
  1435.     sub.l    d4,d5    ;update length
  1436.     move.l    d4,d0
  1437.     bsr    CopyMem
  1438.     add.l    d0,a1    ;update destination pointer
  1439.     bra    .ReadLoop
  1440. .FinishUp:
  1441.     move.l    d5,d0
  1442.     bsr    CopyMem    ;use number of bytes left in entire request
  1443. .End:    movem.l    (sp)+,d0-d5/a0/a1
  1444.     rts
  1445.  
  1446. SelectDrive:
  1447. ;Selects drive AND turns on motor
  1448. ;Selects UnitNum(A_UNIT).
  1449.  
  1450.     movem.l    d0/d2,-(sp)
  1451.     move.b    UnitNum(A_UNIT),d2
  1452.     bsr    Deselect
  1453.     bclr    #CIAB_DSKMOTOR,ciabprb    ;motor on
  1454.     move.l    d2,d0
  1455.     addq.b    #3,d0
  1456.     bclr    d0,ciabprb    ;select drive X
  1457.     bset    d2,MotorState(A_DEVICE)
  1458.  
  1459.     moveq    #4,d2
  1460. .Wait:    btst    #CIAB_DSKRDY,ciaapra
  1461.     beq    .End
  1462.     move.l    #100*1000,d0
  1463.     bsr    delay
  1464.     dbra    d2,.Wait    
  1465.  
  1466. .End:    movem.l    (sp)+,d0/d2
  1467.     rts
  1468.  
  1469. Deselect:    or.b    #CIAF_DSKSEL0+CIAF_DSKSEL1+CIAF_DSKSEL2+CIAF_DSKSEL3,ciabprb    ;Deselect all drives
  1470.     rts
  1471.  
  1472. SelectDriveSameMotor:
  1473. ;Select a drive WITHOUT changing the current motor state
  1474. ;Selects UnitNum(A_UNIT).
  1475.  
  1476.     push    d2
  1477.     move.b    UnitNum(A_UNIT),d2
  1478.     bsr    Deselect
  1479.     bclr    #CIAB_DSKMOTOR,ciabprb    ;motor on
  1480.     btst    d2,MotorState(A_DEVICE)
  1481.     bne    .WasOn
  1482.     bset    #CIAB_DSKMOTOR,ciabprb    ;motor off
  1483. .WasOn:    addq.b    #3,d2
  1484.     bclr    d2,ciabprb    ;select drive X
  1485.     pop    d2
  1486. _RTS:    rts
  1487.  
  1488. DISK_Update:
  1489. ;Flush track buffer if "dirty"
  1490.  
  1491.     bclr    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  1492.     beq    _RTS
  1493.     movem.l    d0-d2/a0/a2/a6,-(sp)
  1494.     move.l    #_custom,a6
  1495.  
  1496. ;This is somewhat tricky, because the currently selected drive may not be
  1497. ;the drive that we want to write to!
  1498.     move.b    UnitNum(A_UNIT),d0
  1499.     move.w    TDU_CURRTRK(A_UNIT),d1
  1500.     move.b    BufferDrive(A_DEVICE),UnitNum(A_UNIT)    ;fake drive
  1501.     move.b    BufferTrack(A_DEVICE),TDU_CURRTRK+1(A_UNIT)    ;fake track
  1502.     bsr    SelectDrive
  1503.     bsr    SelectSide
  1504.  
  1505. ;The logic of this routine is complicated by the need to support the write
  1506. ;optimization scheme (see DISK_Write for details). What we need to do is
  1507. ;check the WriteMap to determine whether a ReadTrackAndDecode is required
  1508. ;before finally writing...
  1509.     move.l    WriteMap(A_DEVICE),d2
  1510.     and.l    SectorMask(A_UNIT),d2
  1511.     cmp.l    SectorMask(A_UNIT),d2
  1512.     beq    .SkipRead
  1513.     move.l    DecodedBuffer(A_DEVICE),a0
  1514.     bsr    ReadTrackAndDecode
  1515.     tst.l    d7
  1516.     bne    .End
  1517. .SkipRead:
  1518.     move.l    d7,WriteMap(A_DEVICE)
  1519.  
  1520.     move.l    DecodedBuffer(A_DEVICE),a2
  1521.     bsr    EncodeAndWriteTrack
  1522.     move.b    d0,UnitNum(A_UNIT)
  1523.     move.w    d1,TDU_CURRTRK(A_UNIT)
  1524.     bsr    SelectDrive
  1525. .End:    movem.l    (sp)+,d0-d2/a0/a2/a6
  1526.     rts
  1527.  
  1528. SelectSide:
  1529. ;Select the correct side based on current track. This routine MUST be
  1530. ;called by certain routines (e.g. Update, Write) because the side select is
  1531. ;lost after a GiveUnit!
  1532.     bclr    #CIAB_DSKSIDE,ciabprb    ;set to upper
  1533.     btst    #0,TDU_CURRTRK+1(A_UNIT)
  1534.     bne    .skip
  1535.     bset    #CIAB_DSKSIDE,ciabprb    ;set to lower
  1536. .skip:    push    d0
  1537.     move.l    #2*1000,d0
  1538.     bsr    delay
  1539.     pop    d0
  1540.     rts
  1541.  
  1542. ;Enter with destination track in d3.b
  1543.  
  1544. ;Note: This routine checks for valid track numbers -- if either the
  1545. ;current track number or the destination is invalid, PANIC.
  1546.  
  1547. SaveRegs    setrl    d0/d3-d4
  1548.  
  1549. SeekNoUpdate:
  1550. ;Perform a seek but don't call DISK_Update -- used by main routine when
  1551. ;checking for disk changes.
  1552.  
  1553.     movem.l    SaveRegs,-(sp)
  1554.     bra    SeekAfterUpdate
  1555.  
  1556. MinSeek:
  1557. ;Only call MinSeek if it is certain that the side select has not been
  1558. ;changed!
  1559.     cmp.b    TDU_CURRTRK+1(A_UNIT),d3
  1560.     bne    Seek
  1561.     move.w    d0,-(sp)
  1562.     move.b    BufferDrive(A_DEVICE),d0
  1563.     cmp.b    UnitNum(A_UNIT),d0
  1564.     bne    .Seek
  1565.     move.w    (sp)+,d0
  1566.     rts
  1567. .Seek:    move.w    (sp)+,d0
  1568.  
  1569. Seek:    movem.l    SaveRegs,-(sp)
  1570.  
  1571.     bsr    DISK_Update
  1572. SeekAfterUpdate:
  1573.     tst.l    d7
  1574.     bne    .End
  1575.  
  1576.     move.l    TDU_STEPDELAY(A_UNIT),d0
  1577.     cmp.b    NumTracks(A_UNIT),d3
  1578.     bhs    .Error
  1579.  
  1580. ;Set head
  1581.     bclr    #CIAB_DSKSIDE,ciabprb    ;set to upper
  1582.     btst    #0,d3
  1583.     bne    .skip
  1584.     bset    #CIAB_DSKSIDE,ciabprb    ;set to lower
  1585. .skip:
  1586.     move.w    TDU_CURRTRK(A_UNIT),d4
  1587.     lsr.b    #1,d4
  1588.     cmp.b    #80,d4
  1589.     bhs    .Error
  1590.     move.b    d3,TDU_CURRTRK+1(A_UNIT)
  1591.     lsr.b    #1,d3
  1592.     bset    #CIAB_DSKDIREC,ciabprb    ;set to "out" (lower tracks)
  1593.     sub.b    d3,d4
  1594.     beq    .SideSelectOnly
  1595.     bhi    .StepIn    ;Go if DISK_CurrentTrack > Destination
  1596.     bclr    #CIAB_DSKDIREC,ciabprb    ;set to "in" (higher tracks)
  1597.     neg.b    d4
  1598. .StepIn:
  1599.     bsr    SelectDriveSameMotor
  1600.     bset    #CIAB_DSKSTEP,ciabprb
  1601.     bclr    #CIAB_DSKSTEP,ciabprb    ;step head
  1602.     bset    #CIAB_DSKSTEP,ciabprb
  1603.     bsr    Deselect
  1604.     bsr    delay
  1605.     subq.b    #1,d4
  1606.     bne    .StepIn
  1607.     move.l    TDU_SETTLEDELAY(A_UNIT),d0
  1608.     bsr    delay
  1609.     bsr    SelectDriveSameMotor
  1610. .End:    movem.l    (sp)+,SaveRegs
  1611.     rts
  1612. .SideSelectOnly:
  1613.     move.l    #2*1000,d0
  1614.     bsr    delay
  1615.     bra    .End
  1616. .Error:
  1617. ;    move.w    #$f00,$dff180
  1618.     bra    .End
  1619.  
  1620. ;*************************** Delay code ****************************
  1621.  
  1622. delay:
  1623.  
  1624. ;Enter with microseconds in D0.L
  1625.  
  1626.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1627.     lea    TimerIORequest(A_DEVICE),a1
  1628.     move.w    #TR_ADDREQUEST,IO_COMMAND(a1)
  1629.     clr.l    TV_SECS+IO_SIZE(a1)
  1630.     move.l    d0,TV_MICRO+IO_SIZE(a1)
  1631.     move.l    4,a6
  1632.     SYS    DoIO
  1633.  
  1634. ;Clear signal bit (TimeOutWait depends on the signal bit being 'correct').
  1635.     lea    TimerIORequest(A_DEVICE),a1
  1636.     move.l    MN_REPLYPORT(a1),a0
  1637.     move.b    MP_SIGBIT(a0),d0
  1638.     moveq    #0,d1
  1639.     bset    d0,d1
  1640.     moveq    #0,d0
  1641.     SYS    SetSignal
  1642.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1643.     rts
  1644.  
  1645. TimeOutWait:
  1646.  
  1647. ;Wait for signal mask in D0, but include a time-out specified in D1 (usecs).
  1648. ;Returns wait mask in D0, or 0 if a time-out occured (Z flag will be set).
  1649.  
  1650.     movem.l    d1-d4/a0-a2/a6,-(sp)
  1651.     move.l    d0,d3
  1652.     move.l    4,a6
  1653.     lea    TimerIORequest(A_DEVICE),a1
  1654.     move.l    a1,a2
  1655.     move.w    #TR_ADDREQUEST,IO_COMMAND(a1)
  1656.     clr.l    TV_SECS+IO_SIZE(a1)
  1657.     move.l    d1,TV_MICRO+IO_SIZE(a1)
  1658.     move.l    MN_REPLYPORT(a1),a0
  1659.     moveq    #0,d2
  1660.     move.b    MP_SIGBIT(a0),d1
  1661.     bset    d1,d2
  1662.     SYS    SendIO
  1663.     move.l    d3,d0
  1664.     add.l    d2,d0    ;equivilent to OR in this case
  1665.     SYS    Wait
  1666.     and.l    d3,d0    ;exclude timer signal
  1667.     move.l    d0,d4
  1668.     beq    .TimeOut    ;if zero, timer signal was the only signal
  1669.     move.l    a2,a1
  1670.     SYS    AbortIO
  1671. .TimeOut:    move.l    a2,a1
  1672.     SYS    WaitIO
  1673.     moveq    #0,d0    ;value
  1674.     move.l    d2,d1    ;mask (timer sig)
  1675.     SYS    SetSignal    ;make SURE the timer signal is clear
  1676.     move.l    d4,d0
  1677.     movem.l    (sp)+,d1-d4/a0-a2/a6
  1678.     rts
  1679.  
  1680. ;*************************** Interrupt routines ************************
  1681.  
  1682. ;------------------------------------------
  1683. ;Register contents upon entering a handler:
  1684. ;D1 - (INTENAR) AND (INTREQR)
  1685. ;A0 - $dff000
  1686. ;A1 - data ptr (device ptr in this case)
  1687. ;A6 - ExecBase 
  1688.  
  1689. ;d0, d1, a0, a1, a5, and a6 are scratch.
  1690. ;-----------------------------------------
  1691.  
  1692. ;However, the disk.resource autodoc indicates the following arrangement for
  1693. ;interrupts installed by GetUnit:
  1694.  
  1695. ;D0/D1/A0/A1 are scratch
  1696. ;A1 points to IS_DATA (device pointer in this case).
  1697. ;Make no other assumptions!
  1698.  
  1699. SyncInt:    addq.w    #1,SyncCount(a1)
  1700.     move.l    SyncSig(a1),d0
  1701.     lea    Task(a1),a1
  1702.     push    a6
  1703.     move.l    4,a6
  1704.     SYS    Signal
  1705.     pop    a6
  1706.  
  1707. ;Delay approximately 63us to avoid two sync interrupts
  1708. ;This could be improved.
  1709.     moveq    #1,d0
  1710. .L1:    move.b    vhposr+_custom,d1
  1711. .L2:    cmp.b    vhposr+_custom,d1
  1712.     beq    .L2
  1713.     dbra    d0,.L1
  1714.     move.w    #INTF_DSKSYNC,intreq+_custom    ;clear sync
  1715.     rts    
  1716.  
  1717. BlockInt:
  1718.     push    a6
  1719.     move.l    #_custom,a6
  1720.     move.w    #INTF_DSKBLK,intreq(a6)
  1721.  
  1722. ;Test DEVB_Verify flag. If set, initiate a read into the verify buffer.
  1723.     bclr    #DEVB_Verify,DEV_FLAGS(a1)
  1724.     beq    .NoVerify
  1725.  
  1726.     move.w    #INTF_SETCLR+INTF_DSKSYNC,intena(a6)    ;enable sync int
  1727.     move.l    VerifyBuffer(a1),dskpt(a6)
  1728.     move.w    #ADKF_SETCLR+ADKF_WORDSYNC,adkcon(a6)
  1729.     move.w    #0,dsklen(a6)
  1730.     move.w    BlockIntDskLen(a1),dsklen(a6)
  1731.     move.w    BlockIntDskLen(a1),dsklen(a6)
  1732.     move.w    #$4489,dsksync(a6)    ;set magic sync word
  1733. ;Now the first sync interrupt we get will be known to be valid, because the
  1734. ;DMA read is fully started.
  1735.     bra    .End
  1736.  
  1737. .NoVerify:
  1738.     move.l    BlockSig(a1),d0
  1739.     lea    Task(a1),a1
  1740.     move.l    4,a6
  1741.     SYS    Signal
  1742. .End:    pop    a6
  1743.     rts
  1744.  
  1745. IndexInt:
  1746.     move.w    IndexDskLen(a1),d0
  1747.     beq    .End
  1748.     move.w    d0,dsklen+_custom
  1749.     move.w    d0,dsklen+_custom
  1750.     clr.w    IndexDskLen(a1)
  1751. .End:    rts
  1752.  
  1753. EnableIndex:
  1754.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1755.     move.l    CIABase(A_DEVICE),a6
  1756.     moveq    #16,d0
  1757.     SYS    SetICR    ;clear interrupt
  1758.     move.l    #16+128,d0
  1759.     SYS    AbleICR    ;enable interrupt
  1760.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1761.     rts
  1762. DisableIndex:
  1763.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1764.     move.l    CIABase(A_DEVICE),a6
  1765.     moveq    #16,d0
  1766.     SYS    AbleICR    ;disable interrupt
  1767.     moveq    #16,d0
  1768.     SYS    SetICR    ;clear interrupt
  1769.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1770.     rts
  1771.  
  1772. ;*********************** End interrupt routines ************************
  1773.  
  1774. ClearSigs:
  1775.     movem.l    d0-d1/a0-a1/a6,-(sp)
  1776.     move.w    #INTF_DSKBLK+INTF_DSKSYNC,intreq+_custom    ;clear sync+done
  1777.     clr.w    SyncCount(A_DEVICE)
  1778.     clr.w    IndexDskLen(A_DEVICE)
  1779.     move.l    4,a6
  1780.     moveq    #0,d0    ;value
  1781.     move.l    SyncSig(A_DEVICE),d1
  1782.     add.l    BlockSig(A_DEVICE),d1
  1783.     SYS    SetSignal
  1784.     movem.l    (sp)+,d0-d1/a0-a1/a6
  1785.     rts
  1786.  
  1787. SetRegs:
  1788. ;This routine enables the block interrupt, but leaves sync interrupts
  1789. ;disabled.
  1790.  
  1791.     move.l    RawBuffer(A_DEVICE),dskpt(a6)
  1792.     move.w    #ADKF_MSBSYNC+ADKF_PRECOMP0+ADKF_PRECOMP1,adkcon(a6)
  1793.     move.w    #ADKF_SETCLR+ADKF_FAST+ADKF_WORDSYNC+ADKF_MFMPREC,adkcon(a6)
  1794.     move.w    #DMAF_SETCLR+DMAF_MASTER+DMAF_DISK,dmacon(a6)    ;enable disk DMA
  1795.     bsr    ClearSigs
  1796.     move.w    #INTF_SETCLR+INTF_DSKBLK,intena(a6)    ;enable block int
  1797.     rts
  1798.  
  1799. PreComp:
  1800. ;Enter with $dff000 in A6
  1801.     movem.l    d0-d1,-(sp)
  1802.     move.w    #ADKF_PRECOMP0+ADKF_PRECOMP1,adkcon(a6)    ;no precomp
  1803.     move.w    TDU_CURRTRK(A_UNIT),d0
  1804.     cmp.w    TDU_COMP01TRACK(A_UNIT),d0
  1805.     bls    .End
  1806.     move.w    #ADKF_SETCLR+ADKF_PRECOMP0,d1
  1807.     cmp.w    TDU_COMP10TRACK(A_UNIT),d0
  1808.     bls    .Done
  1809.     move.w    #ADKF_SETCLR+ADKF_PRECOMP1,d1
  1810.     cmp.w    TDU_COMP11TRACK(A_UNIT),d0
  1811.     bls    .Done
  1812.     move.w    #ADKF_SETCLR+ADKF_PRECOMP0+ADKF_PRECOMP1,d1
  1813. .Done:    move.w    d1,adkcon(a6)
  1814. .End:    movem.l    (sp)+,d0-d1
  1815.     rts
  1816.  
  1817. ScanSync:
  1818. ;Scan for sync mark
  1819. ;A2 - pointer to raw data -- updated
  1820. ;Error code in D7
  1821.  
  1822.     bsr    WaitWordSync
  1823.     tst.l    d7
  1824.     bne    .End
  1825.  
  1826. ;This routine is trickier than it appears. The trick is that we must NOT
  1827. ;assume a $4489 at the beginning of our buffer. This phenomenon occurs when
  1828. ;the DMA starts in the middle of the first sync word. The second sync word
  1829. ;is thrown away by the hardware. It sounds exotic, but it actually happens
  1830. ;quite often!
  1831.  
  1832.     push    a0
  1833.     move.l    RawBuffer(A_DEVICE),a0
  1834.     cmp.l    a0,a2
  1835.     add.l    RawBufSize(A_UNIT),a0
  1836.     beq    .found    ;if start of buffer, don't scan for sync!!!
  1837.  
  1838. .Sync:    cmpi.w    #$4489,(a2)+
  1839.     beq    .found
  1840.     cmp.l    a2,a0
  1841.     bhi    .Sync
  1842. .Error:    pop    a0
  1843.     moveq    #DISK_NoSync,d7
  1844.     rts
  1845. .found:    cmpi.w    #$4489,(a2)
  1846.     bne    .ok
  1847.     addq.l    #2,a2
  1848.     cmp.l    a2,a0
  1849.     bhi    .found
  1850.     bra    .Error
  1851. .ok:    pop    a0
  1852. .End:    rts
  1853.  
  1854. StopDMA:    move.w    #0,dsklen(a6)
  1855.     move.w    #1<<15,dsklen(a6)
  1856.     move.w    #1<<15,dsklen(a6)    ;zero-length DMA transfer
  1857.     move.w    #INTF_DSKBLK+INTF_DSKSYNC,intena(a6)    ;disable ints
  1858.     bra    ClearSigs
  1859.  
  1860. WaitWordSync:
  1861. ;Wait for a sync mark or disk block done
  1862. ;Will return an error in 300ms if nothing happens.
  1863.  
  1864.     movem.l    d0-d1,-(sp)
  1865. .Wait:    tst.w    SyncCount(A_DEVICE)
  1866.     bne    .Sync
  1867.     move.l    SyncSig(A_DEVICE),d0
  1868.     add.l    BlockSig(A_DEVICE),d0
  1869.     move.l    #300*1000*2,d1    ;time-out (300ms)
  1870.     bsr    TimeOutWait
  1871.     beq    .Error
  1872.     and.l    BlockSig(A_DEVICE),d0
  1873.     bne    .Done
  1874.     bra    .Wait
  1875. .Sync:    subq.w    #1,SyncCount(A_DEVICE)
  1876. .End:    movem.l    (sp)+,d0-d1
  1877.     rts
  1878. .Done:    move.w    #$C000,SyncCount(A_DEVICE)    ;this is obscure - should change
  1879.     bra    .End
  1880. .Error:    moveq    #DISK_NoSync,d7
  1881.     bra    .End
  1882.  
  1883. ReadTrackAndDecodeBuffered:
  1884.     push    d0
  1885.     move.l    WriteMap(A_DEVICE),d0
  1886.     beq    .OK    ;no optimized writes to worry about
  1887.     and.l    SectorMask(A_UNIT),d0
  1888.     cmp.l    SectorMask(A_UNIT),d0
  1889.     beq    .End
  1890.     moveq    #-1,d0
  1891.     move.l    d0,WriteMap(A_DEVICE)    ;mark sectors as filled
  1892.     bra    .ReadTrack
  1893.  
  1894. .OK:    move.b    UnitNum(A_UNIT),d0
  1895.     cmp.b    BufferDrive(A_DEVICE),d0
  1896.     bne    .ReadTrack
  1897.     move.w    TDU_CURRTRK(A_UNIT),d0
  1898.     cmp.b    BufferTrack(A_DEVICE),d0
  1899.     bne    .ReadTrack
  1900. .End:    pop    d0
  1901.     rts
  1902. .ReadTrack:
  1903.     pop    d0
  1904.  
  1905. ReadTrackAndDecode:
  1906.  
  1907. ;Input: Buffer ptr in A0
  1908. ;Returns error code in D7
  1909.  
  1910.     move.b    UnitNum(A_UNIT),BufferDrive(A_DEVICE)
  1911.     move.b    TDU_CURRTRK+1(A_UNIT),BufferTrack(A_DEVICE)
  1912.  
  1913. ReadTrackAndDecodeNoBuffer:
  1914.     move.w    d0,-(sp)
  1915.     move.b    TDU_RETRYCNT(A_UNIT),d0
  1916. .Retry:    moveq    #0,d7
  1917.     bsr    ReadTrackAndDecodeNoRetry
  1918.     tst.l    d7
  1919.     beq    .End
  1920.     subq.b    #1,d0
  1921.     bpl    .Retry
  1922. ;Could not recover from error - clear the buffer
  1923.     bsr    Clear
  1924.  
  1925. .End:    move.w    (sp)+,d0
  1926.     rts
  1927.  
  1928. ReadTrackAndDecodeNoRetry:
  1929.     movem.l    d0-d6/a0-a2,-(sp)
  1930.  
  1931. ;Initiate a raw track read
  1932. ;Because we are using WORDSYNC interrupts, this code is VERY VERY tricky!!!!!
  1933.  
  1934.     bsr    SetRegs
  1935.     move.w    #$0123,dsksync(a6)    ;set invalid sync word
  1936. ;At this point sync interrupts will stop happenning, because $0000 will
  1937. ;never occur. So, we clear the interrupt and enable it.
  1938.     bsr    ClearSigs
  1939.     move.w    #INTF_SETCLR+INTF_DSKSYNC,intena(a6)    ;enable sync int
  1940.     move.w    #0,dsklen(a6)
  1941.     move.w    ReadDskLen(A_UNIT),dsklen(a6)
  1942.     move.w    ReadDskLen(A_UNIT),dsklen(a6)
  1943.     move.w    #$4489,dsksync(a6)    ;set magic sync word
  1944.  
  1945. ;Now the first sync interrupt we get will be known to be valid, because the
  1946. ;DMA read is fully started.
  1947.  
  1948. ;Decode track
  1949.     move.l    RawBuffer(A_DEVICE),a2
  1950.  
  1951.     move.l    SectorsPerTrack(A_UNIT),d3
  1952.     subq.l    #1,d3
  1953.     move.l    #$55555555,d2
  1954.  
  1955. ;Wait for first sync marks...
  1956.     bsr    WaitWordSync
  1957.     tst.l    d7
  1958.     bne    .End
  1959.  
  1960. .SecLoop:
  1961.     bsr    ScanSync
  1962.     tst.l    d7
  1963.     bne    .End
  1964.  
  1965.     bsr    DecodeLong    ;get header
  1966.     subq.l    #8,a2
  1967.  
  1968.     and.w    #$ff00,d0    ;mask off sector number
  1969.     move.l    d0,d1
  1970.     cmp.w    MaxValidSec(A_UNIT),d1
  1971.     bhi    .HeaderError
  1972.     add.w    d1,d1    ;convert to sector offset
  1973.     lsr.w    #4,d0    ;get sector label offset
  1974.     lea    SectorLabels(A_DEVICE),a1
  1975.     lea    (a1,d0.w),a1
  1976.  
  1977. ;This code supports the write optimization...
  1978.     lsr.w    #4,d0    ;sector number
  1979.     move.l    WriteMap(A_DEVICE),d4
  1980.     btst    d0,d4    ;should we avoid reading this sector?
  1981.     bne    .EndLoop    ;yes, skip to next sector
  1982.  
  1983.     move.l    d1,-(sp)
  1984.     moveq    #0,d5
  1985.     move.l    (a2)+,d0
  1986.     eor.l    d0,d5
  1987.     move.l    (a2)+,d0
  1988.     eor.l    d0,d5
  1989. ;Decode and checksum sector label
  1990.     moveq    #3,d6
  1991. .Label:    move.l    16(a2),d4
  1992.     eor.l    d4,d5
  1993.     and.l    d2,d4
  1994.     move.l    (a2)+,d1
  1995.     eor.l    d1,d5
  1996.     and.l    d2,d1
  1997.     add.l    d1,d1
  1998.     or.l    d1,d4
  1999.     move.l    d4,(a1)+
  2000.     dbra    d6,.Label
  2001.     and.l    d2,d5
  2002.     lea    16(a2),a2    ;point at header checksum
  2003.     move.l    (sp)+,d1
  2004.     bsr    DecodeLong    ;header checksum
  2005.     cmp.l    d0,d5
  2006.     bne    .HeaderError
  2007.  
  2008. ;Verify track position
  2009.     swap    d1
  2010.     cmp.b    TDU_CURRTRK+1(A_UNIT),d1
  2011.     bne    .WrongTrack
  2012.     swap    d1
  2013.  
  2014.     bsr    DecodeLong    ;data area checksum
  2015.     lea    (a0,d1.w),a1    ;compute destination
  2016.  
  2017. ;Decode and checksum data block
  2018.     moveq    #127,d6
  2019.     moveq    #0,d5
  2020. .L1:    move.l    512(a2),d4
  2021.     eor.l    d4,d5
  2022.     and.l    d2,d4
  2023.     move.l    (a2)+,d1
  2024.     eor.l    d1,d5
  2025.     and.l    d2,d1
  2026.     add.l    d1,d1
  2027.     or.l    d1,d4
  2028.     move.l    d4,(a1)+
  2029.     dbra    d6,.L1
  2030.     and.l    d2,d5
  2031.     lea    512(a2),a2
  2032.  
  2033.     cmp.l    d0,d5    ;check data area checksum
  2034.     bne    .DataError
  2035. .EndLoop:    dbra    d3,.SecLoop
  2036.  
  2037. .End:    bsr    StopDMA
  2038.     movem.l    (sp)+,d0-d6/a0-a2
  2039.     rts
  2040. .HeaderError:
  2041.     moveq    #DISK_BadHeader,d7
  2042.     bra    .End
  2043. .DataError:
  2044.     moveq    #DISK_BadData,d7
  2045.     bra    .End
  2046. .WrongTrack:
  2047.     moveq    #TDERR_SeekError,d7
  2048.     move.w    TDU_CURRTRK(A_UNIT),d3
  2049.     bsr    SeekZero
  2050.     bsr    SelectDrive
  2051.     bsr    SeekNoUpdate
  2052.     bra    .End
  2053.  
  2054. DecodeLong:
  2055. ;A2 - ptr to buffer -- updated
  2056. ;D2 - $55555555
  2057. ;D0 - result
  2058.  
  2059.     move.l    d1,-(sp)
  2060.     move.l    (a2)+,d0
  2061.     move.l    (a2)+,d1
  2062.     and.l    d2,d0
  2063.     and.l    d2,d1
  2064.     add.l    d0,d0    ;was lsl.l #1,d0
  2065.     or.l    d1,d0
  2066.     move.l    (sp)+,d1
  2067.     rts
  2068.  
  2069. EncodeLong:
  2070. ;Enter with data to be encoded in D0.L
  2071. ;and pointer to destination in A0 -- updated
  2072. ;Exit with checksum in D5
  2073.  
  2074.     movem.l    d0-d4,-(sp)
  2075.     moveq    #0,d5
  2076.     move.l    #$55555555,d4
  2077.     move.l    d0,d3
  2078.     lsr.l    #1,d0
  2079.     bsr    Encode
  2080.     move.l    d3,d0
  2081.     bsr    Encode
  2082.     and.l    #$55555555,d5
  2083.     movem.l    (sp)+,d0-d4
  2084.     rts
  2085.  
  2086. Encode:
  2087. ;Enter with longword to code in D0.L and #$55555555 in D4
  2088. ;uses d0,d1,d2,a0 -- not saved
  2089.  
  2090. ;Accumulates checksum in D5
  2091.  
  2092.     and.l    d4,d0
  2093.     move.l    d0,d2
  2094.     eor.l    d4,d2
  2095.     move.l    d2,d1
  2096.     add.l    d2,d2
  2097.     lsr.l    #1,d1
  2098.     bset    #31,d1
  2099.     and.l    d2,d1
  2100.     or.l    d1,d0
  2101.     btst    #0,-1(a0)
  2102.     beq    .ok
  2103.     bclr    #31,d0
  2104. .ok:    eor.l    d0,d5
  2105.     move.l    d0,(a0)+
  2106.     rts
  2107.  
  2108. EncodeBlock:
  2109. ;Destination is always chip RAM (RawBuffer).
  2110. ;Source could be in chip RAM or fast RAM (in A2).
  2111.  
  2112.     movem.l    d0-d1/a0-a1/a6,-(sp)
  2113.     move.l    4,a6
  2114.     move.l    a2,a1
  2115.     SYS    TypeOfMem
  2116.     and.l    #MEMF_CHIP,d0
  2117.     bne    .Chip
  2118.     movem.l    (sp)+,d0-d1/a0-a1/a6
  2119.     bra    EncodeBlockCPU
  2120. .Chip:    movem.l    (sp)+,d0-d1/a0-a1/a6
  2121.     bra    EncodeBlockBlit
  2122.  
  2123. EncodeBlockCPU:
  2124. ;Enter with pointer to source data in A2 -- updated
  2125. ;Enter with pointer to destination in A0 -- updated
  2126.  
  2127. ;Exit with checksum in D5
  2128.     move.l    d6,-(sp)
  2129.     moveq    #0,d5
  2130.     move.w    #(512/4)-1,d6
  2131.  
  2132. EncodeBlockSub:
  2133. ;Number of longwords to encode (minus one) in D6.w
  2134.     movem.l    d0-d4,-(sp)
  2135.  
  2136. ;Encode odd bits
  2137.     push    a2
  2138.     move.w    d6,d3
  2139.     move.l    #$55555555,d4
  2140. .L1:    move.l    (a2)+,d0
  2141.     lsr.l    #1,d0
  2142.     bsr    Encode
  2143.     dbra    d3,.L1
  2144.  
  2145. ;Encode even bits
  2146.     pop    a2
  2147.     move.w    d6,d3
  2148. .L2:    move.l    (a2)+,d0
  2149.     bsr    Encode
  2150.     dbra    d3,.L2
  2151.     and.l    #$55555555,d5
  2152.     movem.l    (sp)+,d0-d4
  2153.     move.l    (sp)+,d6
  2154.     rts
  2155.  
  2156. EncodeSectorLabels:
  2157. ;D5 (checksum) must be initialized by caller
  2158.     move.l    d6,-(sp)
  2159.     move.w    #(16/4)-1,d6
  2160.     bra    EncodeBlockSub
  2161.  
  2162. EncodeBlockBlit:
  2163. ;Enter with pointer to source data in A2 -- updated
  2164. ;Enter with pointer to destination in A0 -- updated
  2165.  
  2166. ;Exit with checksum in D5
  2167.  
  2168.     movem.l    d0-d2/a0-a1/a6,-(sp)
  2169.     push    a0
  2170.     move.l    GraphBase(A_DEVICE),a6
  2171.     SYS    OwnBlitter
  2172.     move.l    (sp),a0
  2173.     move.l    #_custom,a1
  2174.  
  2175.     move.w    #$808,d0    ;BLTSIZE
  2176.  
  2177.     SYS    WaitBlit
  2178.  
  2179.     move.w    #$ffff,bltafwm(a1)
  2180.     move.w    #$ffff,bltalwm(a1)
  2181.     clr.w    bltbmod(a1)
  2182.     clr.w    bltamod(a1)
  2183.     clr.w    bltdmod(a1)
  2184.     move.w    #$5555,bltcdat(a1)
  2185.  
  2186.     move.l    a2,bltbpt(a1)
  2187.     move.l    a2,bltapt(a1)
  2188.     move.l    a0,bltdpt(a1)
  2189.     move.w    #$1db1,bltcon0(a1)
  2190.     clr.w    bltcon1(a1)
  2191.     move.w    d0,bltsize(a1)
  2192.  
  2193.     SYS    WaitBlit
  2194.  
  2195.     move.l    a0,bltbpt(a1)
  2196.     move.l    a2,bltapt(a1)
  2197.     move.l    a0,bltdpt(a1)
  2198.     move.w    #$2d8c,bltcon0(a1)
  2199.     move.w    d0,bltsize(a1)
  2200.     movem.l    a0/a2,-(sp)
  2201.     lea    510(a2),a2    ;ptr to end of src
  2202.     lea    1022(a0),a0
  2203.  
  2204.     SYS    WaitBlit
  2205.  
  2206.     move.l    a2,bltbpt(a1)    ;src end
  2207.     move.l    a2,bltapt(a1)    ;src end
  2208.     move.l    a0,bltdpt(a1)    ;dst end
  2209.     move.w    #$0db1,bltcon0(a1)
  2210.     move.w    #$1002,bltcon1(a1)    ;decrement
  2211.     move.w    d0,bltsize(a1)
  2212.     movem.l    (sp)+,a0/a2
  2213.     lea    512(a0),a0
  2214.  
  2215.     SYS    WaitBlit
  2216.  
  2217.     move.l    a0,bltbpt(a1)
  2218.     move.l    a2,bltapt(a1)
  2219.     move.l    a0,bltdpt(a1)
  2220.     move.w    #$1d8c,bltcon0(a1)
  2221.     clr.w    bltcon1(a1)
  2222.     move.w    d0,bltsize(a1)
  2223.     pop    a0
  2224.  
  2225.     SYS    WaitBlit
  2226.  
  2227.     bsr    Correct
  2228.     lea    512(a0),a0
  2229.     bsr    Correct
  2230.     lea    -512(a0),a0
  2231.  
  2232.     move.w    #(1024/4)-1,d0
  2233.     move.l    #$55555555,d2
  2234.     moveq    #0,d5
  2235. ..    move.l    (a0)+,d1
  2236.     eor.l    d1,d5
  2237.     dbra    d0,..
  2238.     and.l    d2,d5
  2239.  
  2240.     SYS    DisownBlitter
  2241.     movem.l    (sp)+,d0-d2/a0-a1/a6
  2242.     lea    512(a2),a2    ;update source pointer
  2243.     lea    1024(a0),a0    ;update destination pointer
  2244.     rts
  2245.  
  2246. ;This routine corrects the high bit of the current byte based on the
  2247. ;low bit of the previous byte.
  2248.  
  2249. Correct:
  2250.     push    d0
  2251.     move.b    (a0),d0
  2252.     btst    #0,-1(a0)
  2253.     bne    .ResetClock
  2254.     btst    #6,d0
  2255.     bne    .end
  2256.     bset    #7,d0
  2257.     bra    .end1
  2258. .ResetClock:
  2259.     bclr    #7,d0
  2260. .end1:    move.b    d0,(a0)
  2261. .end:    pop    d0
  2262.     rts
  2263.  
  2264. DISK_Wait:
  2265. ;Assumes $dff000 in A6.
  2266.     movem.l    d0-d1,-(sp)
  2267.     tst.w    SyncCount(A_DEVICE)
  2268.     bmi    .OK    ;if WaitWordSync detected a BlockSig, don't wait!
  2269.     move.l    BlockSig(A_DEVICE),d0
  2270.     move.l    #300*1000*2,d1
  2271.     bsr    TimeOutWait
  2272.     bne    .OK
  2273.     moveq    #DISK_NoSync,d7
  2274. .OK:    move.w    #INTF_DSKBLK+INTF_DSKSYNC,intena(a6)    ;disable ints
  2275.     bsr    ClearSigs
  2276.     movem.l    (sp)+,d0-d1
  2277.     rts
  2278.  
  2279. EncodeAndWriteTrack:
  2280. ;Enter with pointer to source data in A2
  2281.  
  2282.     movem.l    d0-d6/a0-a2,-(sp)
  2283.  
  2284.     btst    #CIAB_DSKPROT,ciaapra    ;check write protect status
  2285.     beq    .Protected
  2286.  
  2287.     move.l    RawBuffer(A_DEVICE),a0
  2288.  
  2289. ;Gap = 1660 bytes - 2 bytes for hardware bug
  2290.     move.l    #$aaaaaaaa,d1    ;10101010...
  2291.     move.w    GapCount(A_UNIT),d0    ;414/829
  2292. ..    move.l    d1,(a0)+
  2293.     dbra    d0,..
  2294.     subq.l    #2,a0    ;leave room for 2 extra bytes at the very end
  2295.  
  2296.     move.l    SectorsPerTrack(A_UNIT),d1    ;number of sectors
  2297.     moveq    #0,d3    ;sector count
  2298. .SecLoop:
  2299.     move.l    #$aaaaaaaa,(a0)
  2300.     bsr    Correct
  2301.     addq.l    #4,a0
  2302.     move.l    #$44894489,(a0)+
  2303.     move.l    #$ff000000,d0
  2304.     moveq    #0,d6
  2305.     move.w    TDU_CURRTRK(A_UNIT),d6
  2306.     swap    d6
  2307.     or.l    d6,d0
  2308.     move.l    d3,d6
  2309.     lsl.l    #8,d6
  2310.     or.l    d6,d0
  2311.     or.l    d1,d0
  2312.     bsr    EncodeLong    ;header
  2313.  
  2314. ;Encode sector label
  2315.     push    a2
  2316.     lea    SectorLabels(A_DEVICE),a2
  2317.     move.l    d3,d0
  2318.     lsl.l    #4,d0    ;sector*16
  2319.     lea    (a2,d0.w),a2
  2320.     bsr    EncodeSectorLabels
  2321.     pop    a2
  2322.  
  2323.     move.l    d5,d0
  2324.     bsr    EncodeLong    ;header checksum
  2325.     move.l    a0,d2    ;save raw data pointer
  2326.     addq.l    #8,a0
  2327.     bsr    EncodeBlock    ;encode data block
  2328.     move.l    d5,d0
  2329.     exg    a0,d2
  2330.     bsr    EncodeLong    ;data block checksum
  2331.     bsr    Correct
  2332.     move.l    d2,a0
  2333.     addq.l    #1,d3
  2334.     subq.l    #1,d1
  2335.     bne    .SecLoop
  2336.  
  2337.     move.w    #$aaa8,(a0)
  2338.     bsr    Correct    ;extra word to avoid hardware bug
  2339.  
  2340. ;Physically write the data
  2341. .WriteAgain:
  2342.     bsr    SetRegs
  2343.     bsr    PreComp
  2344.     move.w    #ADKF_WORDSYNC,adkcon(a6)    ;turn OFF wordsync!!!
  2345.     move.w    #$0123,dsksync(a6)
  2346.     bsr    ClearSigs
  2347.     move.w    VerifyDskLen(A_UNIT),BlockIntDskLen(A_DEVICE)
  2348.  
  2349.     btst    #TDPB_VERIFY,TDU_PUBFLAGS(A_UNIT)
  2350.     beq    .SkipVerify
  2351.     bset    #DEVB_Verify,DEV_FLAGS(A_DEVICE)
  2352. .SkipVerify:
  2353.  
  2354.     move.l    VerifyBuffer(A_DEVICE),a0
  2355.     clr.l    (a0)+
  2356.     clr.l    (a0)
  2357.     move.w    #0,dsklen(a6)
  2358.     move.w    WriteDskLen(A_UNIT),dsklen(a6)
  2359.     move.w    WriteDskLen(A_UNIT),dsklen(a6)
  2360.  
  2361. ;This piece of code (commented out) tests the function of the rare
  2362. ;"interrupt delayed" requester. (I've never seen it appear in actual use).
  2363.     comment |
  2364. ;TEST
  2365.     push    a6
  2366.     move.l    4,a6
  2367.     SYS    Disable
  2368.     move.w    #5000,d0
  2369. .L1:    move.b    vhposr+_custom,d1
  2370. .L2:    cmp.b    vhposr+_custom,d1
  2371.     beq    .L2
  2372.     dbra    d0,.L1
  2373.     SYS    Enable
  2374.     pop    a6
  2375. |
  2376.  
  2377.     btst    #TDPB_VERIFY,TDU_PUBFLAGS(A_UNIT)
  2378.     beq    .NoVerify
  2379.  
  2380. ;VERIFY
  2381.  
  2382. ;We verify by comparing the raw MFM data in RawBuffer (what we just wrote)
  2383. ;and VerifyBuffer (what is coming in). Due to the ingenious method of
  2384. ;verifying (thanks to Sebastiano Vigna!) the data comes in sector-by-sector
  2385. ;in the same order that we wrote it.
  2386.  
  2387.     move.l    VerifyBuffer(A_DEVICE),a0
  2388.     move.l    RawBuffer(A_DEVICE),a2
  2389.     add.w    FirstSector(A_UNIT),a2    ;1666/3326 - first sector minus sync
  2390.     bsr    WaitWordSync
  2391.     tst.l    d7
  2392.     bne    .VerifyError
  2393.     bsr    WaitWordSync
  2394.     tst.l    d7
  2395.     bne    .VerifyError
  2396. ;Now we have our first sector in the verify buffer. Scan for a
  2397. ;sync mark. (There may be 1 or 2 sync marks).
  2398.     cmp.w    #$4489,(a0)+
  2399.     bne    .VerifyError
  2400.     cmp.w    #$4489,(a0)
  2401.     bne    .HaveSync
  2402.     addq.l    #2,a0
  2403. .HaveSync:
  2404.  
  2405. ;We go through a rather elaborate procedure here to make sure that we've
  2406. ;started reading with sector 0. (If not, display a requester informing the
  2407. ;user that something is locking out level-1 interrupts for a long period of
  2408. ;time).
  2409.     push    a2
  2410.     move.l    #$55555555,d2
  2411.     move.l    a0,a2
  2412.     bsr    DecodeLong
  2413.     pop    a2
  2414.     and.w    #$ff00,d0
  2415.     beq    .Sector0
  2416.     move.l    a0,a1
  2417.     moveq    #9,d0
  2418.     moveq    #0,d1
  2419. ..    move.l    (a1)+,d3
  2420.     eor.l    d3,d1
  2421.     dbra    d0,..
  2422.     and.l    d2,d1
  2423.     push    a2
  2424.     move.l    a1,a2
  2425.     bsr    DecodeLong
  2426.     pop    a2
  2427.     cmp.l    d0,d1
  2428.     bne    .VerifyError
  2429.  
  2430. ;Display an informational requester.
  2431.     bsr    StopDMA
  2432.     push    a6
  2433.     move.l    IntBase(A_DEVICE),a6
  2434.     cmp.w    #36,LIB_VERSION(a6)
  2435.     bhi    .KS20
  2436.  
  2437. ;Running under 1.3. Put up a DisplayAlert.
  2438.     moveq    #0,d0    ;alert type (recoverable)
  2439.     lea    .AlertLockOut(pc),a0
  2440.     moveq    #20,d1    ;height
  2441.     SYS    DisplayAlert
  2442.     pop    a6
  2443.     bra    .WriteAgain
  2444.  
  2445. ;Running under 2.0. Put up a EasyRequest.
  2446. .KS20:
  2447.     sub.l    a0,a0
  2448.     sub.l    a2,a2
  2449.     lea    .LockOut(pc),a1
  2450.     SYS    EasyRequestArgs
  2451.     pop    a6
  2452.     bra    .WriteAgain
  2453.  
  2454. ;Note: Probably should compare with the blitter, but this will be fairly
  2455. ;fast.
  2456.  
  2457. .Sector0:
  2458.     move.w    #270-1,d0
  2459. ..    cmp.l    (a0)+,(a2)+
  2460.     dbne    d0,..
  2461.     bne    .VerifyError
  2462.  
  2463. ;Now we are over the initial hump of the first sync mark. The rest of the
  2464. ;compare is even easier.
  2465.     move.l    SectorsPerTrack(A_UNIT),d1
  2466.     subq.l    #3,d1
  2467. .VLoop:    bsr    WaitWordSync
  2468.     tst.l    d7
  2469.     bne    .VerifyError
  2470.     move.w    #272-1,d0
  2471. ..    cmp.l    (a0)+,(a2)+
  2472.     dbne    d0,..
  2473.     bne    .VerifyError
  2474.     dbra    d1,.VLoop
  2475.  
  2476. ;We have one more sector to verify. This time we must wait for "Block
  2477. ;done", rather than another sync.
  2478.  
  2479.     bsr    DISK_Wait
  2480.     tst.l    d7
  2481.     bne    .VerifyError
  2482.     move.w    #272-1,d0
  2483. ..    cmp.l    (a0)+,(a2)+
  2484.     dbne    d0,..
  2485.     bne    .VerifyError
  2486.     bra    .End
  2487.  
  2488. .VerifyError:
  2489.     moveq    #0,d7    ;don't propagate the error to the app
  2490. ;We go here if an error is detected during the verify. We first shut down
  2491. ;the read operation that may be in progress, then put up a requester and let
  2492. ;the user choose whether to retry or abort.
  2493.  
  2494.     bsr    StopDMA    ;stop!!
  2495.     push    a6
  2496.     move.l    IntBase(A_DEVICE),a6
  2497.     cmp.w    #36,LIB_VERSION(a6)
  2498.     bhi    .DoKS20
  2499.  
  2500. ;Running under 1.3. Put up a DisplayAlert.
  2501.     moveq    #0,d0    ;alert type (recoverable)
  2502.     lea    .AlertVError(pc),a0
  2503.     moveq    #20,d1    ;height
  2504.     SYS    DisplayAlert
  2505. ;D0 is set to 'TRUE' if the LEFT button was pressed.
  2506.     pop    a6
  2507.     tst.l    d0
  2508.     bne    .WriteAgain    ;go if left button pressed
  2509.     bra    .End
  2510.  
  2511. ;Running under 2.0. Put up a EasyRequest.
  2512. .DoKS20:    sub.l    a0,a0
  2513.     sub.l    a2,a2
  2514.     lea    .VError(pc),a1
  2515.     push    a3
  2516.     move.w    TDU_CURRTRK(A_UNIT),-(sp)
  2517.     clr.w    -(sp)
  2518.     move.l    sp,a3
  2519.     SYS    EasyRequestArgs
  2520.     addq.l    #4,sp
  2521.     pop    a3
  2522.     pop    a6
  2523.     tst.l    d0
  2524.     bne    .WriteAgain    ;go if left gadget hit
  2525.     bra    .End
  2526. .NoVerify:
  2527.     bsr    DISK_Wait
  2528.     move.l    #4*1000,d0
  2529.     bsr    delay    ;post-write delay
  2530. .End:    movem.l    (sp)+,d0-d6/a0-a2
  2531.     rts
  2532. .Protected:
  2533.     moveq    #DISK_WriteProtected,d7
  2534.     bra    .End
  2535.  
  2536. .AlertVError:
  2537.     dc.w    10    ;x coordinate
  2538.     dc.b    10    ;y coordinate
  2539.     dc.b    '*** VERIFY ERROR !!! ***  Hit LEFT button to RETRY'
  2540.     dc.b    ', or RIGHT button to CANCEL.',0
  2541.     dc.b    0    ;continuation byte
  2542.     even
  2543.  
  2544. .AlertLockOut:
  2545.     dc.w    10    ;x coordinate
  2546.     dc.b    10    ;y coordinate
  2547.     dc.b    'Disk block interrupt delayed by >10ms.'
  2548.     dc.b    '  Press mouse button.',0
  2549.     dc.b    0    ;continuation byte
  2550.     even
  2551.  
  2552. .VError:    dc.l    es_SIZEOF
  2553.     dc.l    0
  2554.     dc.l    .Title
  2555.     dc.l    .MainText
  2556.     dc.l    .GadgetText
  2557. .LockOut:    dc.l    es_SIZEOF
  2558.     dc.l    0
  2559.     dc.l    .Title
  2560.     dc.l    .LockOutTxt
  2561.     dc.l    .Okay
  2562. .LockOutTxt:
  2563.     dc.b    'Disk block interrupt delayed by >10ms caused erroneous'
  2564.     dc.b    ' verify.',0
  2565. .Okay:    dc.b    'If you say so. Try it again!',0
  2566. .Title:    dc.b    'hackdisk.device message',0
  2567. .MainText:
  2568.     dc.b    '*** VERIFY ERROR!!! ***',$a,'Track %ld',0
  2569. .GadgetText:
  2570.     dc.b    'Retry|Cancel',0
  2571.     even
  2572.  
  2573. DISK_Write:
  2574.  
  2575. ;Error code returned in D7, as always.
  2576.  
  2577.     movem.l    d0-d5/a0-a2,-(sp)
  2578.  
  2579.     btst    #UNITB_WriteProtected,UNIT_FLAGS(A_UNIT)
  2580.     bne    .ProtError
  2581.  
  2582.     move.l    d0,d5    ;length
  2583.  
  2584. ;The meat of the write routine...
  2585.  
  2586. .WriteLoop:
  2587.     move.l    d1,d3    ;offset
  2588.     divu.w    d6,d3    ;d3.w is track #
  2589.     move.l    d3,d4
  2590.     clr.w    d4
  2591.     swap    d4    ;d4.l is byte offset into track
  2592.     bsr    MinSeek
  2593.     tst.l    d4    ;any offset?
  2594.     bne    .Complex    ;yes
  2595.     cmp.l    d6,d5    ;at least a track left?
  2596.     blo    .Complex    ;no
  2597.     move.l    a0,d0
  2598.     btst    #0,d0    ;word aligned?
  2599.     bne    .Complex    ;no, do it the long way
  2600.     move.l    a0,a2
  2601.     bsr    EncodeAndWriteTrack
  2602.     tst.l    d7
  2603.     bne    .End
  2604.     sub.l    d6,d5    ;update length
  2605.     beq    .End
  2606.     add.l    d6,a0    ;update source pointer
  2607.     add.l    d6,d1    ;update offset
  2608.     bra    .WriteLoop
  2609.  
  2610. .Complex:
  2611.  
  2612. ;This part is somewhat difficult. We check the offset and length parameters
  2613. ;to see whether they're a multiple of 512. If so, we keep track of which
  2614. ;sectors will be written in the buffer. This information is later used by
  2615. ;Update to determine whether a part of the original track must be read in.
  2616. ;(We don't attempt this optimization if the user is writing some odd number
  2617. ;of bytes...This is probably why trackdisk has the limits that it does).
  2618.  
  2619.     tst.l    d5
  2620.     beq    .End    ;nothing left, forget it
  2621.     move.l    d4,d0
  2622.     and.w    #%111111111,d0
  2623.     bne    .NoOpt
  2624.     move.l    d4,d0
  2625.     move.l    d5,d2
  2626.     and.w    #%111111111,d2
  2627.     bne    .NoOpt
  2628.     move.l    d5,d2
  2629.     lsr.l    #8,d0
  2630.     lsr.l    #1,d0    ;get starting sector number
  2631.     lsr.l    #8,d2
  2632.     lsr.l    #1,d2    ;get length in sectors
  2633.     move.l    WriteMap(A_DEVICE),d7
  2634. .OptLoop:    bset    d0,d7
  2635.     addq.b    #1,d0
  2636.     cmp.b    #32,d0
  2637.     beq    .EOpt
  2638.     subq.l    #1,d2
  2639.     bne    .OptLoop
  2640. .EOpt:    move.l    d7,WriteMap(A_DEVICE)
  2641.     moveq    #0,d7
  2642.  
  2643. ;This is normally done by ReadTrackAndDecode.
  2644.     move.b    UnitNum(A_UNIT),BufferDrive(A_DEVICE)
  2645.     move.b    TDU_CURRTRK+1(A_UNIT),BufferTrack(A_DEVICE)
  2646.     bra    .Opt    ;don't read (yet)
  2647.  
  2648. .NoOpt:    push    a0
  2649.     move.l    DecodedBuffer(A_DEVICE),a0
  2650.     bsr    ReadTrackAndDecodeBuffered
  2651.     pop    a0
  2652.     tst.l    d7
  2653.     bne    .End
  2654. .Opt:    move.l    DecodedBuffer(A_DEVICE),a1
  2655.     add.l    d4,a1    ;add byte offset into track
  2656.     sub.l    d6,d4
  2657.     neg.l    d4
  2658.     add.l    d4,d1    ;update offset
  2659.  
  2660. ;D4.L - number of bytes that could be transferred from this track
  2661. ;D5.L - number of bytes left in the entire Read request
  2662.  
  2663.     cmp.l    d5,d4
  2664.     bhs    .FinalWrite
  2665.     sub.l    d4,d5    ;update length
  2666.     move.l    d4,d0
  2667.     bsr    CopyMem
  2668.     add.l    d0,a0    ;update dest pointer
  2669.     bset    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  2670.     bra    .WriteLoop
  2671.  
  2672. .FinalWrite:
  2673.     move.l    d5,d0
  2674.     bsr    CopyMem
  2675.     bset    #DEVB_Dirty,DEV_FLAGS(A_DEVICE)
  2676. .End:    movem.l    (sp)+,d0-d5/a0-a2
  2677.     rts
  2678. .ProtError:
  2679.     moveq    #DISK_WriteProtected,d7
  2680.     bra    .End
  2681.  
  2682. MotorOff:
  2683. ;MotorOff turns off all drive motors and leaves all drives deselected
  2684.     bsr    Deselect
  2685.     bset    #CIAB_DSKMOTOR,ciabprb    ;motor off
  2686.     and.b    #~(CIAF_DSKSEL0+CIAF_DSKSEL1+CIAF_DSKSEL2+CIAF_DSKSEL3),ciabprb    ;select all drives
  2687.     bsr    Deselect
  2688.     clr.b    MotorState(A_DEVICE)
  2689.     rts
  2690.  
  2691. Inquire:
  2692.     IFND    _LVOGetUnitID
  2693. _LVOGetUnitID    equ    -30
  2694.     ENDC
  2695.     movem.l    d0-d2/a0-a1/a6,-(sp)
  2696.     moveq    #0,d2
  2697.     move.l    DiskResourceBase(A_DEVICE),a6
  2698. .Loop:    move.l    d2,d0
  2699.     SYS    GetUnitID
  2700.     moveq    #-1,d1
  2701.     cmp.l    d0,d1
  2702.     beq    .Next
  2703.     bset    d2,InquireBits(A_DEVICE)
  2704. .Next:    addq.l    #1,d2
  2705.     cmp.w    #MD_NUMUNITS,d2
  2706.     blo    .Loop
  2707.     movem.l    (sp)+,d0-d2/a0-a1/a6
  2708.     rts
  2709.  
  2710. GetDriveType:
  2711.  
  2712. ;Determines type of drive and places the proper code into DriveType(A_UNIT).
  2713. ;One of: DRIVE3_5, DRIVE5_25, DRIVE3_5_150RPM
  2714.  
  2715. ;See the Hardware Reference Manual, Appendix E for a description of
  2716. ;the procedure.
  2717.  
  2718. ;Note: Drive zero is always present. In fact, the identification 
  2719. ;scheme does not work with drive zero (except for the half-speed drive).
  2720.  
  2721.     movem.l    d0-d1/d3-d5/a0-a2/a6,-(sp)
  2722.     move.b    UnitNum(A_UNIT),d3
  2723.     addq.b    #3,d3
  2724.     moveq    #7,d1
  2725.     move.l    #ciabprb,a0
  2726.     bsr    Deselect
  2727.     moveq    #31,d4
  2728.     moveq    #0,d5    ;identification longword
  2729.  
  2730.     bclr    d1,(a0)    ;motor on
  2731.     bset    d3,(a0)    ;deselect drive
  2732.     bclr    d3,(a0)    ;select drive
  2733.  
  2734.     bset    d1,(a0)    ;motor off
  2735.     bset    d3,(a0)    ;deselect drive
  2736.     bclr    d3,(a0)    ;select drive
  2737.     bset    d3,(a0)    ;deselect drive
  2738.  
  2739. .ReadIdent:
  2740.     bclr    d3,(a0)    ;select drive
  2741.     btst    #5,ciaapra    ;test ready
  2742.     beq    .zero
  2743.     bset    d4,d5
  2744. .zero:    bset    d3,(a0)    ;deselect drive
  2745.     dbra    d4,.ReadIdent
  2746.  
  2747. ;D5 contains the drive ID.
  2748.     lea    DriveParams(A_UNIT),a0
  2749.     move.w    #(DriveParams_Sizeof/2)-1,d0
  2750. ..    clr.w    (a0)+
  2751.     dbra    d0,..
  2752.     lea    HDParams(pc),a1
  2753.     cmp.l    #DRT_150RPM,d5
  2754.     beq    .DoInitStruct
  2755.     lea    LDParams(pc),a1
  2756. ;    cmp.l    #DRT_AMIGA,d5
  2757.     tst.l    d5
  2758.     beq    .DoInitStruct
  2759.     moveq    #-1,d0
  2760.     cmp.l    d0,d5
  2761.     beq    .DoInitStruct
  2762.     lea    OldParams(pc),a1    ;5.25 inch drive
  2763. .DoInitStruct:
  2764.     moveq    #0,d0    ;area to clear
  2765.     move.l    A_UNIT,a2
  2766.     move.l    4,a6
  2767.     SYS    InitStruct
  2768. .End:    movem.l    (sp)+,d0-d1/d3-d5/a0-a2/a6
  2769.     rts
  2770.  
  2771.  
  2772. SeekZeroAll:
  2773.     movem.l    d0-d2/A_UNIT,-(sp)
  2774.     move.b    InquireBits(A_DEVICE),d0
  2775.     lea    Unit0(A_DEVICE),A_UNIT
  2776.     moveq    #0,d1
  2777.     moveq    #MD_NUMUNITS-1,d2
  2778. .Loop:    btst    d1,d0
  2779.     beq    .Next
  2780.     bsr    SeekZero
  2781. .Next:    lea    MyUnit_Sizeof(A_UNIT),A_UNIT
  2782.     addq.b    #1,d1
  2783.     dbra    d2,.Loop
  2784.     movem.l    (sp)+,d0-d2/A_UNIT
  2785.     rts
  2786.  
  2787. SeekZero:
  2788. ;Places the drive in UnitNum(A_UNIT) on track zero.
  2789. ;Drive does not need to be selected in advance.
  2790. ;Drive will be left _deselected_!
  2791.  
  2792.     movem.l    d0-d1,-(sp)
  2793.  
  2794. .StepLoop:
  2795.     bsr    SelectDriveSameMotor
  2796.     bset    #CIAB_DSKDIREC,ciabprb    ;set to "out" (lower tracks)
  2797.     btst    #CIAB_DSKTRACK0,ciaapra    ;check track zero flag
  2798.     beq    .EndStepLoop
  2799.     bset    #CIAB_DSKSTEP,ciabprb
  2800.     bclr    #CIAB_DSKSTEP,ciabprb    ;step head
  2801.     bset    #CIAB_DSKSTEP,ciabprb
  2802.     bsr    Deselect
  2803.     move.l    TDU_CALIBRATEDELAY(A_UNIT),d0
  2804.     bsr    delay
  2805.     bra    .StepLoop
  2806.  
  2807. .EndStepLoop:
  2808.     bsr    Deselect
  2809.     move.l    TDU_SETTLEDELAY(A_UNIT),d0
  2810.     bsr    delay
  2811.     clr.w    TDU_CURRTRK(A_UNIT)
  2812.     movem.l    (sp)+,d0-d1
  2813.     rts
  2814.  
  2815. CopyMemSlow:
  2816. ;Only to be called by CopyMem
  2817.     move.l    4,a6
  2818.     SYS    CopyMem
  2819.     movem.l    (sp)+,d0-d7/a0-a6
  2820.     rts
  2821.  
  2822. CopyMem:
  2823.  
  2824. ;A0 - source
  2825. ;A1 - destination
  2826. ;D0 - size
  2827.  
  2828.     movem.l    d0-d7/a0-a6,-(sp)
  2829.  
  2830.     move.l    a0,d1
  2831.     btst    #0,d1
  2832.     bne    CopyMemSlow
  2833.     move.l    a1,d1
  2834.     btst    #0,d1
  2835.     bne    CopyMemSlow
  2836.  
  2837.  
  2838. .More:    cmp.l    #512,d0
  2839.     blo    CopyMemSlow
  2840.  
  2841. ;Copy 480 bytes
  2842. n    set    0
  2843.     REPT    10
  2844.     movem.l    (a0)+,d1-d7/a2-a6
  2845.     movem.l    d1-d7/a2-a6,n*48(a1)
  2846. n    set    n+1
  2847.     ENDR
  2848. ;Copy 32 bytes
  2849.     movem.l    (a0)+,d1-d7/a2
  2850.     movem.l    d1-d7/a2,480(a1)
  2851.     lea    512(a1),a1
  2852.     sub.l    #512,d0
  2853.     bne    .More
  2854.     movem.l    (sp)+,d0-d7/a0-a6
  2855.     rts
  2856.  
  2857. LDParams:
  2858.     INITWORD    TDU_COMP10TRACK,-1
  2859.     INITWORD    TDU_COMP11TRACK,-1
  2860.     INITWORD    TDU_COMP01TRACK,80
  2861.     INITLONG    TDU_STEPDELAY,3*1000
  2862.     INITLONG    TDU_SETTLEDELAY,15*1000
  2863.     INITLONG    TDU_CALIBRATEDELAY,4*1000
  2864.  
  2865.     INITBYTE    NumTracks,160
  2866.     INITBYTE    DriveType,DRIVE3_5
  2867.     INITLONG    BytesPerDisk,901120
  2868.     INITLONG    SectorMask,%11111111111
  2869.     INITWORD    GapCount,414
  2870.     INITLONG    SectorsPerTrack,11
  2871.     INITLONG    RawBufSize,13630
  2872.  
  2873.     INITWORD    FirstSector,1666
  2874.     INITWORD    MaxValidSec,$0a00
  2875.     INITWORD    WriteDskLen,$da9e
  2876.     INITWORD    ReadDskLen,$9a9e
  2877.     INITWORD    VerifyDskLen,$9761
  2878.     dc.w    0
  2879.  
  2880. OldParams:    ;for 5.25 inch drives
  2881.     INITWORD    TDU_COMP10TRACK,-1
  2882.     INITWORD    TDU_COMP11TRACK,-1
  2883.     INITWORD    TDU_COMP01TRACK,80/2
  2884.     INITLONG    TDU_STEPDELAY,3*1000*2
  2885.     INITLONG    TDU_SETTLEDELAY,15*1000*2
  2886.     INITLONG    TDU_CALIBRATEDELAY,4*1000*2
  2887.  
  2888.     INITBYTE    NumTracks,80
  2889.     INITBYTE    DriveType,DRIVE5_25
  2890.     INITLONG    BytesPerDisk,901120/2
  2891.     INITLONG    SectorMask,%11111111111
  2892.     INITWORD    GapCount,414
  2893.     INITLONG    SectorsPerTrack,11
  2894.     INITLONG    RawBufSize,13630
  2895.  
  2896.     INITWORD    FirstSector,1666
  2897.     INITWORD    MaxValidSec,$0a00
  2898.     INITWORD    WriteDskLen,$da9e
  2899.     INITWORD    ReadDskLen,$9a9e
  2900.     INITWORD    VerifyDskLen,$9761
  2901.     dc.w    0
  2902.  
  2903. HDParams:
  2904.     INITWORD    TDU_COMP10TRACK,-1
  2905.     INITWORD    TDU_COMP11TRACK,-1
  2906.     INITWORD    TDU_COMP01TRACK,80
  2907.     INITLONG    TDU_STEPDELAY,3*1000
  2908.     INITLONG    TDU_SETTLEDELAY,15*1000
  2909.     INITLONG    TDU_CALIBRATEDELAY,4*1000
  2910.  
  2911.     INITBYTE    NumTracks,160
  2912.     INITBYTE    DriveType,DRIVE3_5_150RPM
  2913.     INITLONG    BytesPerDisk,901120*2
  2914.     INITLONG    SectorMask,%1111111111111111111111
  2915.     INITWORD    GapCount,829
  2916.     INITLONG    SectorsPerTrack,22
  2917.     INITLONG    RawBufSize,13630*2
  2918.  
  2919.     INITWORD    FirstSector,3326
  2920.     INITWORD    MaxValidSec,$1500
  2921.     INITWORD    WriteDskLen,$f53c
  2922.     INITWORD    ReadDskLen,$b53b
  2923.     INITWORD    VerifyDskLen,$aec1
  2924.     dc.w    0
  2925.  
  2926. EndCode:
  2927.  
  2928. ;************************* Northgate fix *********************************
  2929.  
  2930. ;This tiny module performs a keyboard handshake. Its purpose is to wake up a
  2931. ;Northgate keyboard on accelerated systems. If you don't fit that description
  2932. ;then just ignore it. It's harmless.
  2933.  
  2934. NRomTag:    dc.w    RTC_MATCHWORD    ;$4AFC ('illegal' opcode)
  2935.     dc.l    NRomTag
  2936.     dc.l    NEndCode    ;pointer to end of code
  2937.     dc.b    RTF_COLDSTART
  2938.     dc.b    0    ;version
  2939.     dc.b    NT_LIBRARY    ;module type (either device or library)
  2940.     dc.b    0    ;priority
  2941.     dc.l    FixName    ;name
  2942.     dc.l    FixName    ;IDString
  2943.     dc.l    Northgate    ;init routine
  2944. FixName:    dc.b    'Northgate_fix',$a,0
  2945.     even
  2946.  
  2947. Northgate:
  2948. ;Perform a keyboard handshake
  2949.     or.b    #$40,$BFEE01
  2950.     clr.b    $bfec01
  2951.     move.l    #$bfe001,a0
  2952.     move.w    #$46*3,d0
  2953. ..    move.b    (a0),(a0)
  2954.     dbra    d0,..
  2955.     and.b    #$BF,$BFEE01
  2956.     rts
  2957.  
  2958. NEndCode:
  2959.  
  2960. ;*************************** Debugging stuff *************************
  2961.  
  2962.     IFNE    INFO_LEVEL
  2963.  
  2964. KPutFmt:    move.l    a2,-(sp)
  2965.     lea    KPutChar(pc),a2
  2966.     bsr    KDoFmt
  2967.     move.l    (sp)+,a2
  2968.     rts
  2969.  
  2970. KDoFmt:    move.l    a6,-(sp)
  2971.     move.l    4,a6
  2972.     SYS    RawDoFmt
  2973.     move.l    (sp)+,a6
  2974.     rts
  2975.  
  2976. KPutChar:
  2977.  
  2978. ;Serial
  2979.     comment |
  2980.     move.l    a6,-(sp)
  2981.     move.l    4,a6
  2982.     SYS    RawPutChar
  2983.     move.l    (sp)+,a6
  2984.     rts
  2985. |
  2986.  
  2987. ;Printer
  2988.     comment |
  2989.     move.b    #$ff,$bfe301
  2990. .Print:    btst    #0,$bfd000
  2991.     bne    .Print
  2992.     move.b    d0,$bfe101
  2993.     rts
  2994. |
  2995.  
  2996. ;Memory
  2997.     tst.l    MemPtr
  2998.     bne    .OK
  2999.     move.l    #$500000,MemPtr
  3000. .OK:
  3001.     push    a0
  3002.     move.l    MemPtr(pc),a0
  3003.     move.b    d0,(a0)+
  3004.     move.l    a0,MemPtr
  3005.     pop    a0
  3006.     rts
  3007.  
  3008. MemPtr:    dc.l    0
  3009.  
  3010.     ENDC
  3011.