$PAGEWIDTH(96)    
NAME   OsDiskDriver
$LIST

;
;   OSDiskDriver
;   Call OsDskDriver(request,pPlist,pError)
;          request WORD
;          pPlist  POINTER
;          pError  POINTER
;
;

CGROUP   GROUP   CODE
DGROUP   GROUP   DATA


  PUBLIC   OsDskDriver
  PUBLIC   CurrentSide
  PUBLIC   FStatus
  PUBLIC   PcStatus

  EXTRN    Setup:        NEAR
  EXTRN    CpAllocate:   NEAR
  EXTRN    CpFree:       NEAR
  EXTRN    CpSignal:     NEAR
  EXTRN    CpWait:       NEAR
  EXTRN    OsLookupName: NEAR

; EXTRN    ConHexOut:  NEAR    (Used for debugging)


;  Equates

  TRUE     EQU    1
  FALSE    EQU    0

; parms passed into OsDskDriver

  request   EQU   WORD  PTR [BP+16]
  pPlist    EQU   DWORD PTR [BP+12]
  pError    EQU   DWORD PTR [BP+8]

  FloppyInt         EQU 120     ; interrupt 1E

;
;   System Commands Supported
;   


  ddInitialize              EQU   0
  ddDeactivate              EQU   21
  ddGetStatus               EQU   1
  ddRead                    EQU   4

  ddWrite                   EQU   5
  ddSetStatus               EQU   1

  ddSelftest                EQU   16
  ddWinControllerSelfTest   EQU   1
  ddWinControllerRamTest    EQU   2


  ddFormat                  EQU   17

  ddTrackFormat             EQU   22
  ddDriveTest               EQU   1
  ddVerifyMedia             EQU   40

;
;   System Errors
;   


  eOK               EQU   0
  eNotSupported     EQU   35
  eInvalidDrive     EQU   101
  eInvalidSector    EQU   102
  eCRCData          EQU   103
  eWriteProtect     EQU   106
  eDeviceNotReady   EQU   107
  eOther            EQU   108
  eECCData          EQU   109
  eNoAM             EQU   115
  eSeekError        EQU   116
  eInvalidMedia     EQU   235
  eInvalidMemory    EQU    11
 
;
;   PC Errors
;   


  ePCBadCmd          EQU   01H
  ePCNoAM            EQU   02H
  ePCWriteProtect    EQU   03H
  ePCInvalidSector   EQU   04H
  ePCReset           EQU   05H
  ePCInit            EQU   07H
  ePCDMA             EQU   08H
  ePCBoundry         EQU   09H
  ePCTrack           EQU   0BH
  ePCECCError        EQU   10H
  ePCCorrectedError  EQU   11H
  ePCNEC             EQU   20H
  ePCSeekError       EQU   40H
  ePCTimeout         EQU   80H
  ePcQuickOutErrs    EQU   0C3h

;
;    Misc equates
;

  GRiDFormat         EQU   01
  NULLBYTE           EQU   0FFh
  NULLWORD           EQU   0FFFFh
  GetStatusSize      EQU   52
  dataBufSize        EQU   512
  BIOSDataSeg        EQU   40h
  InternalDriveOff   EQU   67h
  InternalDriveMask  EQU   68h
  MotorStat          EQU   BYTE PTR 3fh
  enterName          EQU   1
  hornet             EQU   1
  IBMPC              EQU   2
  IBMAT              EQU   3


;
;   PC Default definations
;
  ddSB1        EQU   0EFH
  ddSB2        EQU   02H
  ddMWait      EQU   25H
  ddSecLength  EQU   02
  ddEOT        EQU   08
  ddgapLen1    EQU   2AH
  ddDTL        EQU   0FFH
  ddgapLen2    EQU   50H
  ddfillByte   EQU   0FFH
  ddheadSetl   EQU   15
  ddMStart     EQU   4

;
;   Floppy Default definations
;
  ddFDCPageSize            EQU   200H
  ddFDCLogPageSize         EQU   1F8H
  ddFDCDriveReady          EQU   1
  ddFDCMinDirPages         EQU   1
  ddFDCFlush               EQU   0EH
  ddFDCBytesPerSector      EQU   200H
  ddFDCSectorsPerTrack     EQU   9
  ddFDCTracksPerCylinder   EQU   2
  ddFDCInterleaveFactor    EQU   2

;   Parameters for the 3.5" disk drive (Used for both DD & HD)

  ddFDCNumPages3           EQU   1440
  ddFDCBitMap3             EQU   5
  ddFDCDirFID3             EQU   ddFDCBitMap3 + 1       ; 6
  ddFDCSecondSideCount3    EQU   0                      ; IBM Format
  ddFDCNumCylinders3       EQU   80

;   These would be used if 3.5" HD floppies were used in high density mode

  ddFDCSectorsPerTrack3HD  EQU   18
  ddFDCNumPages3HD         EQU   2880

;   DS DD 48TPI

  ddFDCNumPages5           EQU   720
  ddFDCBitMap5             EQU   120h
  ddFDCDirFID5             EQU   121h
  ddFDCMinDirPages5        EQU   1
  ddFDCSecondSideCount5    EQU   1         ; GRiD Format
  ddFDCNumCylinders5       EQU   40


;
;      Structures
;

PCParameterStatus   STRUC
   SB1         DB   ?
   SB2         DB   ?
   MWait       DB   ?
   SecLength   DB   ?
   EOT         DB   ?
   gapLen1     DB   ?
   DTL         DB   ?
   gapLen2     DB   ?
   fillByte    DB   ?
   headSetl    DB   ?
   MStart      DB   ?
PCParameterStatus   ENDS

pList   STRUC
   connection      DW   ?
   pBuffer         DD   ?
   position        DD   ?
   len             DW   ?
   mode            DB   ?
   drive           DB   ?
   interfaceAddr   DB   ?
   pOverflow       DD   ?
pList   ENDS

BPBDataType  STRUC
  btPerSc     DW ?
  scPerCl     DB ?
  rsvdSecs    DW ?
  numFats     DB ?
  mxRootDirs  DW ?
  nmLogSecs   DW ?
  mediaDesc   DB ?
  scPerFat    DW ?
  scPerTrk    DW ?
  nmHeads     DW ?
  nmHdnScs    DW ?
BPBDataType  ENDS

;
;   Floppy Paramater Structures
;


ParameterStatus   STRUC
   pageSize          DW   ?
   logpageSize       DW   ?
   numPages          DW   ?
   driveReady        DB   ?
   bitMap            DW   ?
   dirFID            DW   ?
   minDirPages       DW   ?
   flush             DB   ?
   devName           DB   32 DUP(?)
   bytesPerSector    DW   ?
   sectorsPerTrack   DW   ?
   tracksPerCylinder DW   ?
   interleaveFactor  DB   ?
   secondSideCount   DB   ?
   numCylinders      DW   ?
ParameterStatus   ENDS

setStatusLength     EQU  54 
deviceDataSize      EQU  SIZE (ParameterStatus) + 2

$EJECT

INITCODE   SEGMENT  PUBLIC 
  firstTimeThrough          DB   0
INITCODE ENDS


Data   SEGMENT  PUBLIC 'Data'
  EXTRN  systemType: BYTE
  EXTRN  gridMachine: BYTE

  BPBData      BpbDataType <>
  currentSide  DB   1 DUP (?)
  floppySema   DW   1 DUP (?)
  gError       DW   1 DUP (?)
  PCStatus     DB   SIZE (PCParameterStatus) DUP (?) 
  oldDiskParmsOff DW 1 DUP (?)
  oldDiskParmsSeg DW 1 DUP (?)
  goodDataBufOff  DW 1 DUP (?)
  goodDataBufSeg  DW 0

; Current drive variables
  FStatus      DB SIZE (ParameterStatus) DUP (?)
  oldTrack	    DB   1 DUP (?)
  floppyOff    DB   1 DUP (?)

; Device 0 parms
  F0Status     DB SIZE (ParameterStatus) DUP (?)
  F0oldTrack	  DB   1 DUP (?)
  F0floppyOff  DB   1 DUP (?)

; Device 1 parms
  F1Status     DB SIZE (ParameterStatus) DUP (?)
  F1oldTrack	  DB   1 DUP (?)
  F1floppyOff  DB   1 DUP (?)

; Device 2 parms
  F2Status     DB SIZE (ParameterStatus) DUP (?)
  F2oldTrack	  DB   1 DUP (?)
  F2floppyOff  DB   1 DUP (?)

; Device 3 parms
  F3Status     DB SIZE (ParameterStatus) DUP (?)
  F3oldTrack	  DB   1 DUP (?)
  F3floppyOff  DB   1 DUP (?)
Data ENDS

CODE   SEGMENT   PUBLIC   'CODE'
  ASSUME   CS:CGROUP, DS:DGROUP      ; assume data in cs

   
FloppyName DB 11, '#MSDosSema#'


; AllocateCleanDMABuffer: PROCEDURE CLEAN;
;
;  This routine will return in ES:BX a buffer that does not cross a 64k
;  DMA boundary.  AX will have the error.


AllocateCleanDMABuffer PROC NEAR

; Allocate the sector buffers
  MOV   AX, ddFDCPageSize
  PUSH  AX	      ; size = ddFDCPageSize

  PUSH  DS
  MOV   AX, OFFSET gError
  PUSH  AX
  CALL  CpAllocate
  MOV   AX, DS:gError
  CMP   AX, eOk
  JNZ   AllocateDone

  MOV   AX, ES
  MOV   CL, 4
  SHL   AX, CL
  ADD   AX, ddFDCPageSize
  JNC   AllocateDoneGood

; retry for another buffer that wont cross 64k boundary
  PUSH  ES

  MOV   AX, ddFDCPageSize
  PUSH  AX

  PUSH  DS
  MOV   AX, OFFSET gError
  PUSH  AX
  CALL  CpAllocate

  POP   DX         ; DX:0 has buffer

  PUSH  ES
  PUSH  BX
  MOV   AX, DS:gError
  PUSH  AX

FreeTheBlock:
  PUSH  DX
  XOR   AX, AX
  PUSH  AX
  PUSH  DS
  MOV   AX, OFFSET gError
  PUSH  AX
  CALL  CpFree
  POP   AX
  CMP   AX, eOk
  JNZ   AllocateDone
  
  POP   BX              ; get the segment back
  POP   ES
  MOV   AX, ES
  MOV   CL, 4
  SHL   AX, CL
  ADD   AX, ddFDCPageSize
  JNC   AllocateDoneGood

  MOV   AX, eInvalidMemory
  PUSH  AX
  MOV   DX, ES
  JMP   FreeTheBlock

AllocateDoneGood:
  MOV  AX, eOk

AllocateDone:
  RET
AllocateCleanDMABuffer ENDP
$EJECT

Select   PROC NEAR
;
;   Select will take the logical drive number passed in the
;parameter list (interface address) and select the floppy
;or the winchester device.  Leaving DL setup correctly.
;
;
;onEntry: pPlist.interfaceAddr >= 80H Winchester else floppy
;      
;onExit:
;         DL=device number  
;         FStatus current variables will be set.


  LES   DI,pPLIST          ; setup ES and DI for structure
  MOV   DL,BYTE PTR ES:[DI].interfaceAddr

  CMP   DL, 0
  JNE   Select10
  MOV   SI, OFFSET DGROUP:F0Status
  JMP   SHORT Select40

Select10:
  CMP   DL, 1
  JNE   Select20
  MOV   SI, OFFSET DGROUP:F1Status
  JMP   SHORT Select40

Select20:
  CMP   DL, 2
  JNE   Select30
  MOV   SI, OFFSET DGROUP:F2Status
  JMP   SHORT Select40

Select30:
  MOV   SI, OFFSET DGROUP:F3Status

Select40:
  MOV   CX, deviceDataSize
  PUSH  DS
  POP   ES
  MOV   DI, OFFSET DGROUP:FStatus
  CLD
  REP   MOVSB                     ; copy device specific info into WStatus area

  RET
Select   ENDP


Restore   PROC NEAR
;
;   Restore will take the logical drive number passed in the
;parameter list (interface address) and restore the FStatus area into
;the device specific area.
;
;
;onExit:
;         FnStatus = FStatus area
;


  LES   DI,pPLIST          ; setup ES and DI for structure
  MOV   DL,BYTE PTR ES:[DI].interfaceAddr

  CMP   DL, 0
  JNE   Restore10
  MOV   DI, OFFSET DGROUP:F0Status
  JMP   SHORT Restore40

Restore10:
  CMP   DL, 1
  JNE   Restore20
  MOV   DI, OFFSET DGROUP:F1Status
  JMP   SHORT Restore40

Restore20:
  CMP   DL, 2
  JNE   Restore30
  MOV   DI, OFFSET DGROUP:F2Status
  JMP   SHORT Restore40

Restore30:
  MOV   DI, OFFSET DGROUP:F3Status

Restore40:
  MOV   CX, deviceDataSize
  PUSH  DS
  POP   ES
  MOV   SI, OFFSET DGROUP:FStatus
  CLD
  REP   MOVSB                   ; copy device specific info into FnStatus area

; 
; setup new PC floppy data pointer
;
  XOR  BX, BX	                     ; get the old interrupt vector
  MOV  ES, BX
  MOV  BX, floppyInt


  CLI
  MOV   CX, oldDiskParmsOff      ; restore old int routine
  MOV   WORD PTR ES:[BX], CX
  MOV   CX, oldDiskParmsSeg
  MOV   WORD PTR ES:[BX+2], CX
  STI


  RET
Restore   ENDP
$EJECT



;MyHexOut PROC NEAR
;  PUSH  AX
;  PUSH  BP
;  MOV   BP, SP
;  MOV   AX, [BP+6]
;  PUSH  BX
;  PUSH  CX
;  PUSH  DX
;  PUSH  ES
;  PUSH  DI
;  PUSH  SI
;
;  PUSH  AX
;  CALL  ConHexOut
;
;  POP   SI
;  POP   DI
;  POP   ES
;  POP   DX
;  POP   CX
;  POP   BX
;  POP   BP
;  POP   AX
;  RET  2
;MyHexOut ENDP




Sector   PROC NEAR
;
;   Sector will take the logical sector and convert to track,sector,
;and head.  Select must be called before this routine.
;
;
;onEntry: DL contains drive number
;
;onExit:
;         DL=drive number
;         DH=head
;         CH=track
;         CL=sector


   PUSH  DX

   LES   DI,pPlist
   MOV   AX,WORD PTR ES:[DI].position

   SUB   DX,DX
   MOV   BX, FStatus.sectorsPerTrack
   DIV   BX                          ; Track in AX
   MOV   BX,AX                       ; save track in BX
   PUSH  BX   

   SUB   DX,DX
   MOV   CX, FStatus.tracksPerCylinder
   DIV   CX                          ; Cylinder in AX
   MOV   CX,AX                       ; save Cylinder in CX

   PUSH  BX
   MOV   BX, FStatus.tracksPerCylinder      ; Low in AX
   MUL   BX
   POP   BX

   SUB   BX,AX                       ; head Addr in BX

   POP   AX                          ; Track to AX
   PUSH  BX
   MOV   BX, FStatus.SectorsPerTrack      
   MUL   BX
   POP   BX
   MOV   DX,AX
   MOV   AX,WORD PTR ES:[DI].position
   SUB   AX,DX                       ; Sector number in AX

   MOV   DX,AX                       ; Sector number in DX

   MOV   AL,CL                       ; SWAP CH and CL
   MOV   CL,CH
   MOV   CH,AL                       ; low cyl number in CH

   MOV   AL,CL                       ; shift high cyl addr to upper bits
   MOV   CL,6
   SHL   AL,CL
   MOV   CL,AL                       ; shifted upper cyl number

   ADD   CL,DL                       ; sector number with 2 bits cyl in CL
   INC   CL                          ; sector number +1
         
   POP   DX                          ; drive number in DL
   MOV   DH,BL                       ; head number in DH

;   TEST  DL,080h                     ; IS the device winchester?
;   JNZ   DoneSector
   
   MOV   AL, FStatus.secondSideCount
   TEST  AL,GRiDFormat               ; Set for GRiD format
   JZ    DoneSector
   
   MOV   AL,DH
   TEST  AL,0ffh                     ; test for second side
   JZ    DoneSector

   MOV   AX, FStatus.sectorsPerTrack   ; increment for GRiD format
   ADD   CL,AL   

DoneSector:
   RET
Sector   ENDP
$EJECT

; 
; CheckBuffer: PROCEDURE CLEAN;
;
;
;  Check buffer pointer to make sure that a 64k boundry is not crossed.
; If boundry is crossed then change pointer to 'new data buffer'.
; If boundry is crossed and write command then change pointer to 'new data
; buffer' and transfer data.
;
; On Entry: 
;   DI = value to put in AX for Rom Bios
;   CX = track/sector
;
; On Exit:
;   ES:[BX] set to proper value
;   AX destroyed


CheckBuffer PROC NEAR
  PUSH  DS
  PUSH  CX
  PUSH  SI

  LDS   SI,pPlist
  LES   BX,DS:[SI].pBuffer          ;buffer to read/write data

  MOV   AX,ES          
  MOV   CL,4
  SHL   AX,CL          
  ADD   AX,BX         

  CMP   AX,0FE00H
  JB    NOBuffer
;
;Check to see if write command
;

  MOV   AX,DI
  AND   AX,0F00h
  CMP   AX,0300h               ; check for write command
  JNE   NoBuffer3

;
;Move data into new buffer
;
  PUSH  DI
  MOV   AX,ES
  MOV   DS,AX
  MOV   SI,BX
  MOV   AX, DGROUP
  MOV   ES, AX
  MOV   DI, ES:goodDataBufOff
  MOV   ES, ES:goodDataBufSeg
  MOV   CX,512
  CLD
  REP   MOVSB
  POP   DI
   
NoBuffer3:
  MOV   AX, DGROUP
  MOV   ES, AX
  MOV   BX, ES:goodDataBufOff
  MOV   ES, ES:goodDataBufSeg


NoBuffer:

  POP   SI
  POP   CX
  POP   DS
  RET
CheckBuffer   ENDP
$EJECT

;
; CheckReadBuffer: PROCEDURE CLEAN;
;
;
;  Data has now been successfully transfered.  If the pointer was transfered
; to the 'good data buffer' and the command was a read command then copy
; the data to the origional buffer.
;
; On Entry:
;   DI =  value to put in AX for Rom Bios
;
; On Exit:
;   The pl.pBuffer will be updated if necessary
;   AX destroyed
;
CheckReadBuffer PROC NEAR
  PUSH  DS
  PUSH  ES
  PUSH  CX
  PUSH  SI
  PUSH  BX
   
  LDS   SI,pPlist
  LES   BX,DS:[SI].pBuffer          ; buffer to read/write data
   
  MOV   AX,ES         ;
  MOV   CL,4
  SHL   AX,CL          ;
  ADD   AX,BX         

  CMP   AX,0FE00H
  JB    NOBuffer2
;
;check to see if the command was a read command
;
  MOV   AX,DI
  AND   AX,0F00h
  CMP   AX,0200h              ; read command
  JNE   NoBuffer2

;
;Move 'good data' into old buffer
;
  PUSH  DI
  MOV   DI,BX

  MOV   AX, DGROUP
  MOV   DS, AX
  MOV   SI, DS:goodDataBufOff
  MOV   DS, DS:goodDataBufSeg

  MOV   CX,512
  CLD
  REP   MOVSB
  POP   DI
   
NoBuffer2:
  POP   BX
  POP   SI
  POP   CX
  POP   ES
  POP   DS
  RET
CheckReadBuffer   ENDP

$EJECT
; 
;
;  OsDskDriver: PROCEDURE (req, pPl, pError) CLEAN;
;    DCL req       WORD;
;    DCL pPl       PTR;
;    DCL pError    PTR;
;

;  Locals:
pOldIntOff EQU [BP-4]
pOldIntSeg EQU [BP-2]
dataBufSeg EQU [BP-6]
dataBufOff EQU [BP-8]                ; data buffer for format
error      EQU [BP-10]
localParms EQU 10                    ; # bytes of locals


OsDskDriver   PROC FAR
  PUSH DS
  PUSH BP
  MOV  BP,SP                       ; setup BP for call variables
  SUB  SP, localParms              ; save space for locals
  MOV  AX, DGROUP
  MOV  DS, AX                      ; set data segment

;
; Set the floppy diskette parms
;

  XOR  BX, BX	                     ; get the old interrupt vector
  MOV  ES, BX
  MOV  BX, floppyInt


  CLI
  MOV   CX, WORD PTR ES:[BX]     ; save old int routine
  MOV   oldDiskParmsOff, CX
  MOV   CX, WORD PTR ES:[BX+2]
  MOV   oldDiskParmsSeg, CX

  MOV   AL, systemType
  CMP   AL, IBMAT
  JE    DontSetFloppyParms

  MOV   ES:[BX],OFFSET PcStatus     ; set new int routine
  MOV   ES:[BX+2],SEG PcStatus

DontSetFloppyParms:
  STI

;
;
;  check for supported requests
;

  CALL  Select
  CMP   DL, 4                       ; If floppy request is in range
  JB    DoReq                       ; then take it

DeviceNotReady:
  MOV  AX,eDeviceNotReady
  JMP  Done

DoReq:

; Now check to see if the floppy motor is off.

  CMP   floppyOff, 2           ; have we just returned maybe?
  JNZ   CheckMotor
  MOV   floppyOff, FALSE       ; dont check motor after returning maybe
  JMP   SHORT DoReq1           ; bypass the check this time

CheckMotor:
  MOV  CL, DL              ; get the drive
  MOV  AX, 1 
  SHL  AX, CL	             ; calculate the drive mask
  MOV  BX, BiosDataSeg
  MOV  ES, BX	             ; point to BIOS data seg
  AND  AL, ES:MotorStat    ; is the motor on?
  JNZ  DoReq1
  MOV  DS:floppyOff, TRUE     ; no, FloppyOff = TRUE

DoReq1:
  MOV   AX,request
;
;  Initialize
;

  CMP   AX,ddInitialize
  JZ    DoInit                 ; GO run init code
;
;  VerifyMedia
;

  CMP   AX, ddVerifyMedia
  JNZ   Next
  JMP   VerifyMedia

Next:
;
;   Get Status
;

  CMP   AX,ddGetStatus
  JNZ   Next1
  JMP   FGetStatus             ; GetStatus routine

Next1:   
  CMP   AX,ddDeactivate
  JNZ   Next2
  MOV   AX, 0
  JMP   Done

Next2:
;
;   Write
;

  CMP   AX,ddWrite
  JNZ   next3
  LES   DI,pPList
  MOV   CL,BYTE PTR ES:[DI].mode
  CMP   CL,ddSetStatus
  JNE   Next3
  JMP   SetStatus             ; setStatus = ddWrite, mode 1



Next3:
  PUSH  DX                 ; save the drive number
  PUSH  floppySema         ; sid
  MOV   AX, NULLWORD
  PUSH  AX                 ; timelimit
  PUSH  SS
  LEA   AX, error	         ; VAR error: WORD
  PUSH  AX
  CALL  CpWait             ; wait to get in critical section
  POP   DX                 ; restore the drive number


  MOV   AX, request
;
;   Write
;

  CMP   AX,ddWrite
  JNZ   next4
  LES   DI,pPList
  MOV   CL,BYTE PTR ES:[DI].mode
  CMP   CL,0
  JNE   Next4
  JMP   RealWrite             ; normal write

Next4:
;
;  Read
;

  CMP   AX,ddRead
  JNZ   next5
  JMP   RealRead               ; read routine

Next5:   
;
;  Hard Format
;

  CMP   AX,ddFormat
  JNZ   Next6
  JMP   HardFormat

Next6:
  MOV   AX, eNotSupported
  JMP   DoneCritical


;
;
;      Initialize
;
;

DoInit:

  INT   11h                               ; Equipment determination
  TEST  AX, 1
  JNZ   DoInit1
  JMP   DeviceNotReady

DoInit1:
  LES   DI,pPLIST          ; setup ES and DI for structure
  MOV   DL,BYTE PTR ES:[DI].interfaceAddr
  AND   AX, 0C0h                      ; determine if this drive is present
  MOV   CL, 6
  SHR   AX, CL                        ; move floppy info to LSBits
  CMP   DL, AL
  JBE   DoInit2
  JMP   DeviceNotReady

DoInit2:
  XOR   AX, AX
  MOV   floppyOff, AL                     ; floppyOff = FALSE
  MOV   FStatus.pageSize,ddFDCPageSize   
  MOV   FStatus.logPageSize,ddFDCLogpageSize
  MOV   FStatus.driveReady,ddFDCDriveReady
  MOV   FStatus.minDirPages,ddFDCMinDirPages
  MOV   FStatus.flush,ddFDCFlush   
  MOV   FStatus.bytesPerSector,ddFDCBytesPerSector
  MOV   FStatus.sectorsPerTrack,ddFDCSectorsPerTrack
  MOV   FStatus.tracksPerCylinder,ddFDCTracksPerCylinder
  MOV   FStatus.interleaveFactor,ddFDCInterleaveFactor   

; Now initialize the device specific stuff

  XOR   CX, CX                   ; Preset error indicator for old systems
  MOV   SI, DX                   ; Save drive number
  MOV   AH, 8                    ; Read drive parameters
  INT   13h
  MOV   DX, SI                   ; Restore drive number for below
  JC    FindCapacityError1
  JCXZ  FindCapacityError1       ; CX = 0 is alternate error indicator

  MOV   AX, CX
  ROL   AL, 1
  ROL   AL, 1
  AND   AL, 3
  JNZ   FindCapacityError1       ; Really bad if not zero

  XCHG  AH, AL                   ; AX = number of cylinders - 1 (0 relative)
  INC   AX                       ; AX = number of cylinders
  AND   CL, 3FH                  ; CL = sectors per track
  MUL   CL                       ; Gives AX = 360, 720 or 1440

  CMP   AX, 360                  ; 360 sectors (per side)
  JE    SmallCapacity            ; implies 5 1/4" drive

  CMP   AX, 1200                 ; 1200 sectors (per side)
  JE    SmallCapacity            ; implies 5 1/4" drive HD (but use as 5 1/4")

  CMP   AX, 720                  ; 720 sectors (per side)
  JE    LargeCapacity            ; implies 3 1/2" drive

  CMP   AX, 1440                 ; 1440 sectors (per side)
  JE    LargeCapacity            ; implies 3 1/2" HD drive (but use as 3 1/2")

FindCapacityError1:
  MOV   AL, systemType           ; If error from fnc 8 and the
  CMP   AL, IBMAT                ; system is an IBM AT then don't try
  JE    SmallCapacity            ; kludge method; just assume 5-1/4"

  MOV   AL, gridMachine          ; If PC type machine is not
  TEST  AL, 1                    ; from GRiD then
  JZ    SmallCapacity            ; assume 5 1/4" drive

  PUSH  DS
  POP   ES
  MOV   BX, OFFSET BPBData
  MOV   AH, 0D4h                 ; get media info
  INT   13h                      ; DL already setup above
  JC    LargeCapacity            ; Carry returned for internal 3.5 drive

MaybeSmallCapacity:
  CMP   BPBData.mediaDesc, 0fcH  ; f8-fb are 3.5s, fc-ff are 5.25s
  JB    LargeCapacity            ; 3.5 drive holds 720k

SmallCapacity:
  MOV   FStatus.numPages,ddFDCNumPages5
  MOV   FStatus.bitMap,ddFDCBitMap5
  MOV   FStatus.dirFID,ddFDCDirFID5
  MOV   FStatus.SecondSideCount,ddFDCSecondSideCount5
  MOV   FStatus.numCylinders,ddFDCNumCylinders5
  JMP   SHORT SetupPcStatus

LargeCapacity:
  MOV   FStatus.numPages,ddFDCNumPages3   
  MOV   FStatus.bitMap,ddFDCBitMap3
  MOV   FStatus.dirFID,ddFDCDirFID3
  MOV   FStatus.SecondSideCount,ddFDCSecondSideCount3
  MOV   FStatus.numCylinders,ddFDCNumCylinders3

SetupPcStatus:
  MOV   AL, systemType
  CMP   AL, IBMAT
  JE    doTrack
  MOV   PCStatus.SB1,ddSB1
  MOV   PCStatus.SB2,ddSB2
  MOV   PCStatus.MWait,ddMWait
  MOV   PCStatus.SecLength,ddSecLength
  MOV   PCStatus.gapLen1,ddGapLen1
  MOV   PCStatus.DTL,ddDTL
  MOV   PCStatus.gapLen2,ddGapLen2
  MOV   PCStatus.fillByte,ddFillByte
  MOV   PCStatus.headSetl,ddheadSetl
  MOV   PCStatus.MStart,ddMstart
  MOV   PCStatus.EOT,ddFDCSectorsPerTrack

doTrack:
  MOV   AL, 0ffh
  MOV   DS:oldTrack, AL        ; initialize track

  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP

  PUSH  CS
  MOV   AX, OFFSET CGROUP:FloppyName
  PUSH  AX
  PUSH  SS
  LEA   AX, error
  PUSH  AX
  CALL  OsLookupName
  MOV   DS:floppySema, AX
  MOV   AX, error
  CMP   AX, eOk
  JZ    DoInit10
  JMP   Done

DoInit10:
;  MOV   AH, 0
;  INT   13h	               ; call the BIOS

  CMP   DS:goodDataBufSeg, 0
  JE    DoInit20
  MOV   AX, eOk
  JMP   Done

DoInit20:
  CALL  AllocateCleanDMABuffer
  MOV   DS:goodDataBufSeg, ES
  MOV   DS:goodDataBufOff, BX
  JMP   Done

 ;
 ;
 ;     VerifyMedia
 ;
 ;

VerifyMedia:
  LES   DI,pPLIST                   ; setup ES and DI for structure
  CMP   floppyOff, TRUE
  JNZ   MotorOn
  MOV   AX, 2                       ; who knows if the floppy is the same
  MOV   floppyOff, 2                ; set flag that "maybe" is being returned
  JMP   SHORT EndVerify

MotorOn:
  MOV   AX, 1	                      ; floppy is the same
;  MOV   floppyOff, FALSE           ; This is alreay FALSE

EndVerify:
  MOV   WORD PTR ES:[DI].position, AX
  XOR   AX, AX
  MOV   WORD PTR ES:[DI].position + 2, AX
  JMP   Done	                      ; AX is already eOk

 ;
 ;
 ;      Get Status
 ;
 ;

FGetStatus:
  CALL  Select
  MOV   SI,OFFSET FStatus
  LES   DI,pPLIST                   ; setup ES and DI for structure
  LES   DI,ES:[DI].pBuffer          ; buffer to put msStat data
  MOV   CX,GetStatusSize
  CLD
  REP   MOVSB
  
  MOV   AX,eOk
  JMP   Done

;
;
;
;   Set Status
;
;
;

SetStatus:
  PUSH  DS
  LES   BX,pPList
  LDS   SI,ES:[BX].pBuffer          ; buffer for setstatus data

  MOV   DI,OFFSET FStatus
  MOV   AX,SEG FStatus
  MOV   ES,AX
  CLD                               ; direction flag
  MOV   CX,SetStatusLength

  REP   MOVSB
  POP   DS

  MOV   AX,FStatus.NumPages
  SUB   DX,DX
  DIV   FStatus.SectorsPerTrack
  SUB   DX,DX
  DIV   FStatus.TracksPerCylinder
  MOV   FStatus.NumCylinders,AX 

  MOV   AX, eOk
  JMP   DONE

;
;
;      Read
;
;

RealRead:
  MOV   DI,201H                ; read one sector
  MOV   pcStatus.headSetl, 0   ; no head settling time
  JMP   FDisk

 ;
 ;
 ;      Write
 ;
 ;

RealWrite:
  MOV   DI,301H                     ; write one sector


FDisk:
;
;
; Number of sectors to read/write and command setup in 
; DI on input
;
;
  
  
  MOV   CX, 4                       ; retry count

FDisk10:
  PUSH   CX                         ; save retry count
  PUSH   DI

  CALL  Sector                      ; DL = Drive
	                      ; DH = head
	                      ; CH = Track
	                      ; CL = sector
	                      ; DI = request
  POP   DI
  CALL  CheckBuffer                 ; get the correct buffer.
  MOV   AX,DI                       ; read/write one sector

  CMP   AH, 2                       ; is it a read
  JE    CallBIOS
  CMP   oldTrack, CH                ; are we on the same track??
  JNE   WriteIt
  MOV   pcStatus.headSetl, 0        ; no head settling time

WriteIt:
  MOV   oldTrack, CH                ; save the track

CALLBIOS:
  INT   13h	                      ; Go to the BIOS

  POP   CX                            ; restore retry count
  MOV   pcStatus.headSetl, ddHeadSetl ; reset head settle time
  JC    DiskFail
  
OkHere:
  CALL  CheckReadBuffer             ; get data copied if necessary
  MOV   AX,0
  JMP   DoneCritical

DiskFail:
  PUSH  AX
  XOR   AH, AH
  INT   13h	                      ; call the BIOS
  POP   AX

  CMP   CX, 4
  JGE   Retry
;
; After any # of retries, error out if one of the following errors
;   WriteProtect, TimeOut, Seek, Bad Address Mark, Bad Cmd
; Otherwise do four retries
;
  TEST  AH, ePCQuickOutErrs
  JNZ   DiskErr
Retry:
  LOOP  FDisk10


DiskErr:
;
;
; Translate PC errors to GRiD errors
; PC error in AH
;
  
  MOV   BH,AH

  MOV   AX, eWriteProtect
  CMP   BH, ePCWriteProtect
  JZ    ErrDONE
 
  MOV   AX, eCRCData
  TEST  BH, ePCECCError
  JNZ   ErrDONE
  CMP   BH, ePCCorrectedError
  JZ    ErrDone

  MOV   AX, eDeviceNotReady
  TEST  BH, ePCTimeout
  JNZ   ErrDONE
 
  MOV   AX, eInvalidSector
  TEST  BH, ePCInvalidSector
  JNZ   ErrDONE
 
  MOV   AX, eSeekError
  TEST  BH, ePCSeekError
  JNZ   ErrDONE
 
  MOV   AX, eNoAM
  TEST  BH, ePCNOAM
  JNZ   ErrDONE

  MOV   AX, eNotSupported
  TEST  BH, ePCBadCmd
  JNZ   ErrDONE
 
  MOV   AX, eOther

ErrDone:
  JMP   DoneCritical
 
;
;
;   Format Floppy
;
;

HardFormat:
  XOR   BX, BX
  MOV   ES, BX
  MOV   BX, floppyInt
  LES   BX, DWORD PTR ES:[BX]       ; Get address of floppy Disk_Base parms
  MOV   AH, ES:[BX].gapLen2         ; Save current gapLen2
  MOV   AL, ES:[BX].eot             ; Save current EOT
  PUSH  ES                          ; Save address segment
  PUSH  BX                          ; Save address offset
  PUSH  AX                          ; Save gapLen2 / End Of Track
  MOV   AX, FStatus.SectorsPerTrack ; New End Of Track
  MOV   ES:[BX].gapLen2, ddGapLen2  ; gap length for 360K (5.25) or 720K (3.5)
  MOV   ES:[BX].eot, AL             ; Set gapLen2 / EOT for smaller capacities

  XOR   CX, CX                      ; track # to format

FormatTrack:
  MOV   CurrentSide,0               ; start to format side zero

FormatTrackHead:	                   ; format head "currentSide" of track
  PUSH  CX
  PUSH  CX	                         ; save track for later

; Do address field setup
  
  PUSH  CX                          ; Push track to format
  MOV   AX, goodDataBufSeg
  PUSH  AX
  MOV   AX, goodDataBufOff
  PUSH  AX
  CALL  Setup                       ; setup interleave buffer

; select drive to format

  CALL  Select

; Issue format command

  MOV   AL, ddFDCInterleaveFactor
  MOV   AH, 05                      ; Format track command
  POP   CX
  MOV   CH, CL                      ; Track number
  MOV   CL, 1
  MOV   DH, currentSide
  MOV   ES, goodDataBufSeg
  MOV   BX, goodDataBufOff

  INT   13h                         ; Call BIOS floppy disk driver
  JC    FormatDone                  ; If error in Format Get Out

  POP   CX	                         ; track to format
  INC   currentSide                 ; format next side
  MOV   AX, FStatus.TracksPerCylinder
  CMP   AL, currentSide
  JNE   FormatTrackHead

  INC   CX                          ; go to next track
  CMP   CX, FStatus.NumCylinders    ; are we done?
  JNE   FormatTrack                 ; no

  CLC                               ; Exiting without errors

FormatDone:                         ; C => Error; NC => eOK
  POP   CX                          ; Restore gapLen2 / EOT
  POP   BX
  POP   ES                          ; Restore floppy Disk_Base address
  MOV   ES:[BX].gapLen2, CH         ; Restore original gapLen2
  MOV   ES:[BX].eot, CL             ; Restore original EOT
  JNC   FormatOkay

  JMP   DiskErr

FormatOkay:
  MOV   AX, eOk                     ; final error
; JMP   DoneCritical

DoneCritical:
  PUSH  AX
  PUSH  floppySema                  ; sid
  MOV   AX, 1	                      ; mode = signalNormal
  PUSH  AX
  PUSH  AX	                         ; note (doesn't matter)
  PUSH  SS
  LEA   AX, error
  PUSH  AX	                         ; VAR error
  CALL  CpSignal                    ; leave the critical section
  POP   AX	                         ; restore error code

Done:

; Call to done assumes error to be retured in AX

  LES   DI,pError
  MOV   WORD PTR ES:[DI],AX
  CALL  Restore                     ; restore variables to drive specific area

  MOV   SP, BP                      ; get rid of locals
  POP   BP
  POP   DS
  RET   10
OsDskDriver   ENDP



CODE ENDS

END
