
NAME   WiniDriver
$NOLIST

;
;   OSWiniDriver
;   Call OsWiniDriver(request,pPlist,pError)
;          request WORD
;          pPlist  POINTER
;          pError  POINTER
;
;
; This is the code that handles the GRiD PChip interface.
;

CGROUP GROUP CODE
DGROUP GROUP DATA



  PUBLIC   OsWiniDriver

  EXTRN    IntAllocate:           NEAR
  EXTRN    CpFree:                NEAR
  EXTRN    CpWait:                NEAR
  EXTRN    CpSignal:              NEAR
  EXTRN    OsLookupName:          NEAR
  EXTRN    OsDeleteSemaphore:     NEAR
  EXTRN    ConHexOut:             NEAR

;  Equates

  TRUE              EQU 1
  FALSE             EQU 0

;
;   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
  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
  ePCQuickOutErrors  EQU  0C3h

;
;    Misc equates
;

  GRiDFormat            EQU   01
  NULLBYTE              EQU   0FFh
  NULLWORD              EQU   0FFFFh
  GetStatusSize         EQU   52
  dataBufSize           EQU   512
  SizeOfSectorBuffer    EQU   9
  SectorSize            EQU   0512/0256
  order                 EQU   100
  sdtMass               EQU   1      ; true
  sdtMode               EQU   0      ; visible nonremovable device
  setStatusLength       EQU   54 
  RomSize               EQU   4096
  MotorStat             EQU   BYTE PTR 3fh
  BiosDataSeg           EQU   40h
  MyIntAddr             EQU   80h

;
;   Wini Default definations
;
  ddFDCPageSize            EQU   200H
  ddFDCPageSizeWords       EQU   100H
  ddFDCLogPageSize         EQU   1F8H
  ddFDCDriveReady          EQU   1
  ddFDCBitMap              EQU   2400h
  ddFDCDirFID              EQU   2420h
  ddFDCMinDirPages         EQU   0ah
  ddFDCFlush               EQU   80H
  ddFDCBytesPerSector      EQU   200H
  ddFDCSecondSideCount     EQU   1         ; GRiD Format
  ddFDCInterleaveFactor    EQU   7         ; **** Change later

$EJECT


;
;      Structures
;


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

StatusInfo   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   ?           
StatusInfo ENDS

deviceDataSize      EQU   SIZE (statusInfo) + 4

DATA   SEGMENT   PUBLIC   'DATA'
  floppySema	               DW   ?
  bufferSize                DW   ?

  WStatus                   DB SIZE (StatusInfo) DUP (?) 
  pSectorInfoOffset         DW   ?
  pSectorInfoSeg            DW   ?

  W1Status                  DB SIZE (StatusInfo) DUP (0) 
  pW1InfoOffset             DW   ?
  pW1InfoSeg                DW   ?

  W2Status                  DB SIZE (StatusInfo) DUP (0) 
  pW2InfoOffset             DW   ?
  pW2InfoSeg                DW   ?
DATA   ENDS


$NOLIST

magicSectorNum     EQU   11

CODE   SEGMENT   PUBLIC   'CODE'
  ASSUME   CS:CGROUP, DS:DGROUP

floppyName: 
         DB 11, '#MSDosSema#'
   

;PrintRegisters PROC NEAR
;PUSH BP
;PUSHF
;PUSH AX
;MOV  AX, 0FFFFh
;PUSH AX
;CALL MyHexOut
;POP  AX
;PUSH AX
;CALL MyHexOuT
;PUSH BX
;CALL MyHexOuT
;PUSH CX
;CALL MyHexOuT
;PUSH DX
;CALL MyHexOuT
;PUSH SI
;CALL MyHexOuT
;PUSH DI
;CALL MyHexOuT
;PUSH DS
;CALL MyHexOuT
;PUSH ES
;CALL MyHexOuT
;PUSH SS
;CALL MyHexOuT
;MOV  BP, SP
;PUSH BP
;CALL MyHexOuT
;POPF
;PUSHF
;PUSHF
;CALL MyHexOuT
;POPF
;POP BP
;RET
;PrintRegisters ENDP

;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
;
;  XOR   DX, DX
;  MOV   BX, 10000
;  DIV   BX
;  PUSH  DX
;  MOV   BX, 3
;  MOV   AH, 14
;  ADD   AL, 30h
;  INT   10h
;  POP   AX
;
;  XOR   DX, DX
;  MOV   BX, 1000
;  DIV   BX
;  PUSH  DX
;  MOV   BX, 3
;  MOV   AH, 14
;  ADD   AL, 30h
;  INT   10h
;  POP   AX
;
;  XOR   DX, DX
;  MOV   BX, 100
;  DIV   BX
;  PUSH  DX
;  MOV   BX, 3
;  MOV   AH, 14
;  ADD   AL, 30h
;  INT   10h
;  POP   AX
;
;  XOR   DX, DX
;  MOV   BX, 10
;  DIV   BX
;  PUSH  DX
;  MOV   BX, 3
;  MOV   AH, 14
;  ADD   AL, 30h
;  INT   10h
;  POP   AX
;
;  MOV   BX, 3
;  MOV   AH, 14
;  ADD   AL, 30h
;  INT   10h
;
;  PUSH  AX  
;  CALL  ConHexOut
;
;  POP   SI
;  POP   DI
;  POP   ES
;  POP   DX
;  POP   CX
;  POP   BX
;  POP   BP
;  POP   AX
;  RET  2
;MyHexOut 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.
;
;
;onExit:
;         DL=device number  
;         WStatus area correctly set


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

  CMP   DL, 80h
  JNE   Select10
  MOV   SI, OFFSET DGROUP:W1Status
  JMP   SHORT Select20

Select10:
  MOV   SI, OFFSET DGROUP:W2Status

Select20:
  MOV   CX, deviceDataSize
  PUSH  DS
  POP   ES
  MOV   DI, OFFSET DGROUP:WStatus
  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 WStatus area into
;the device specific area.
;
;
;onExit:
;         W1Status or W2Status = WStatus area
;


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

  CMP   DL, 80h
  JNE   Restore10
  MOV   DI, OFFSET DGROUP:W1Status
  JMP   SHORT Restore20

Restore10:
  MOV   DI, OFFSET DGROUP:W2Status

Restore20:
  MOV   CX, deviceDataSize
  PUSH  DS
  POP   ES
  MOV   SI, OFFSET DGROUP:WStatus
  CLD
  REP   MOVSB                   ; copy device specific info into WnStatus area

  RET
Restore   ENDP
$EJECT

;     InTable: PROCEDURE CLEAN;

; This routine will see if AX is in the buffer table.
; If so, it will return the buffer ptr in ES:BX and the 
; index into the sector array in DI and set carry
; Otherwise, carry will be cleared.

InTable  PROC NEAR
  MOV  CX, magicSectorNum
  LES  BX, DWORD PTR DS:pSectorInfoOffset
  
InTable5:
  CMP  AX, WORD PTR ES:[BX]    ; is the sector in the buffer?
  JE   InTable10
  INC  BX	                 ; no, try next buffer
  INC  BX
  LOOP InTable5
  CLC
  RET

InTable10:
  MOV  DI, BX	                 ; save index into sector num array
  XCHG BL, BH	                 ; same as mult by 2^8
  ADD  BX, magicSectorNum * 2  ; point to buffer
  STC
  RET
InTable  ENDP

$EJECT

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, DS:WStatus.SectorsPerTrack
   DIV   BX                          ; Track in AX
   MOV   BX,AX                       ; save track in BX
   PUSH  BX   

   SUB   DX,DX
   MOV   CX, DS:WStatus.TracksPerCylinder
   DIV   CX                          ; Cylinder in AX
   MOV   CX,AX                       ; save Cylinder in CX

   PUSH  BX
   MOV   BX, DS:WStatus.TracksPerCylinder      ; Low in AX
   MUL   BX
   POP   BX

   SUB   BX,AX                       ; head Addr in BX

   POP   AX                          ; Track to AX
   PUSH  BX
   MOV   BX, DS:WStatus.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, DS:WStatus.SecondSideCount
   TEST  AL,GRiDFormat               ; Set for GRiD format
   JZ    DoneSector
   
   MOV   AL,DH
   TEST  AL,0ffh                     ; test for second side
   JZ    DoneSector

   MOV   AX, DS:WStatus.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: 
;   CX = track/sector
;   DS = current data segment
;
; On Exit:
;   ES:[BX] set to proper value
;   AX destroyed
;   DI destroyed



CheckBuffer PROC NEAR
  PUSH  DS
  PUSH  CX
  PUSH  SI

  LES   BX,pPlist
  LES   BX,ES:[BX].pBuffer          ; buffer to write data

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

  CMP   AX,0FE00H
  JB    NOBuffer

;
;Move data into new buffer
;
  PUSH  DS
  PUSH  ES                         ; save old seg of buffer
  LES   DI, DWORD PTR DS:pSectorInfoOffset
  MOV   WORD PTR ES:[DI], NULLWORD ; invalidate the first buffer
  MOV   DI, magicSectorNum * 2     ; point to the first buffer
  POP   DS                         ; DS:[BX] now points to buffer

  MOV   SI,BX                      ; for DS:[SI]
  MOV   CX,256
  CLD
  REP   MOVSW                      ; do it
  POP   DS                         ; restore DS
   
  MOV   BX, magicSectorNum * 2     ; BX points to sector


NoBuffer:

  POP   SI
  POP   CX
  POP   DS
  RET
CheckBuffer   ENDP

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

; parms passed into OsWiniDriver
request   EQU   WORD  PTR [BP+16]
pPlist    EQU   DWORD PTR [BP+12]
pError    EQU   DWORD PTR [BP+8]

;  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


OsWiniDriver   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
;
;
; check for supported requests
;   
;
;
;  Check for drive configuration
;
  CALL  Select
  CMP   DL, 80h
  JE    DoReq

  CMP   DL, 81h              ; only 2 drives supported.
  JE    DoReq

DeviceNotReady:
  MOV  AX,eDeviceNotReady
  JMP  Done

DoReq:
  MOV   AX,request


;
;  Initialize
;

  CMP   AX,ddInitialize
  JZ    DoInit

;
;   Get Status
;

  CMP   AX,ddGetStatus
  JNZ   Next1
  JMP   FGetStatus

Next1:   
  CMP   AX,ddDeactivate
  JNZ   Next2
  JMP   DoDeact

Next2:
;
;   SetStatus
;

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

Next3:
  PUSH  DX                   ; save the drive #
  PUSH  DS:floppySema           ; sid
  MOV   AX, NULLWORD
  PUSH  AX	                  ; timeLimit
  PUSH  SS
  LEA   AX, error
  PUSH  AX	                  ; VAR error
  CALL  CpWait
  POP   DX                   ; restore the drive #
  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

Next4:
;
;  Read
;

  CMP   AX,ddRead
  JNZ   next5
  JMP   RealRead

Next5:   
;
;  Hard Format
;

  CMP   AX,ddFormat
  JNZ   Next6
  JMP   HardFormat

Next6:
  MOV   AX,eNotSupported
  JMP   DoneCritical
$EJECT


 ;******************************
 ;	                            *
 ;      Initialize             *
 ;	                            *
 ;******************************

DoInit:
;  MOV   AH, 0
;  INT   13h	               ; call the BIOS to init

  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    DoInit5
  JMP   GoToDone

DoInit5:
; intialize some variables
  MOV   DS:WStatus.LogPageSize, ddFDCLogpageSize
  MOV   DS:WStatus.DriveReady, ddFDCDriveReady
  MOV   DS:WStatus.BitMap, ddFDCBitMap
  MOV   DS:WStatus.DirFID, ddFDCDirFID
  MOV   DS:WStatus.MinDirPages, ddFDCMinDirPages
  MOV   DS:WStatus.Flush, ddFDCFlush   
  MOV   DS:WStatus.BytesPerSector, ddFDCBytesPerSector
  MOV   DS:WStatus.InterleaveFactor, ddFDCInterleaveFactor   
  MOV   DS:WStatus.SecondSideCount, ddFDCSecondSideCount


; Get the Wini Drive parameters
  MOV   AH, 8
  LES   DI,pPLIST          ; setup ES and DI for structure
  MOV   DL,BYTE PTR ES:[DI].interfaceAddr
  INT   13h	                 ; get the drive parameters
  JNC   DoInit1
  JMP   DeviceNotReady
DoInit1:
  INC   DH
  XCHG  DL, DH
  XOR   DH, DH
  MOV   DS:WStatus.TracksPerCylinder, DX
  MOV   AL, CL
  AND   AL, 00111111b          ; mask out cylinder number
  XOR   AH, AH
  MOV   DS:WStatus.SectorsPerTrack, AX
  ROL   CL, 1	                 ; get rid of sector count
  ROL   CL, 1	                 ; xxxxxx11
  AND   CL, 3	                 ; mask out high bits
  XCHG  CL, CH                 ; xxxxxx11 11111111
  INC   CX	                 ; make it 1 relative
  MOV   DS:WStatus.NumCylinders, CX
  MOV   DS:WStatus.NumPages, CX
;  MOV   AX, DS:WStatus.TracksPerCylinder
;  MUL   CX
;  MOV   CX, DS:WStatus.SectorsPerTrack
;  MUL   CX
;  MOV   DS:WStatus.NumPages, AX

  CMP   DS:WStatus.PageSize, ddFDCPageSize   
  JNZ   AllocateBlock
  JMP   AllDone

AllocateBlock:
; Allocate the sector buffers
  XOR   AX, AX
  PUSH  AX	      ; system Pid
  
  MOV   BX, ddFDCPageSize
  ADD   BX, 2	      ; to keep track of sector num
  MOV   AX, magicSectorNum
  MUL   BX
  PUSH  AX	      ; size = magicSectorNum * (2 + ddFdcPageSize)
  MOV   DS:bufferSize, AX

  PUSH  SS
  LEA   AX, error
  PUSH  AX
  CALL  IntAllocate
  MOV   DS:pSectorInfoOffset, BX
  MOV   DS:pSectorInfoSeg, ES
  MOV   AX, error
  CMP   AX, eOk
  JNZ   GoToDone

  MOV   AX, ES
  MOV   CL, 4
  SHL   AX, CL
  ADD   AX, DS:bufferSize
  JNC   SetupBuffer

; retry for another buffer that wont cross 64k boundary
  XOR   AX, AX
  PUSH  AX	      ; system Pid
  PUSH  DS:bufferSize

  PUSH  SS
  LEA   AX, error
  PUSH  AX
  CALL  IntAllocate
  PUSH  ES
  PUSH  BX
  MOV   AX, error
  PUSH  AX

FreeTheBlock:
  PUSH  DS:pSectorInfoSeg
  PUSH  DS:pSectorInfoOffset
  PUSH  SS
  LEA   AX, error
  PUSH  AX
  CALL  CpFree
  POP   AX
  CMP   AX, eOk
  JNZ   GoToDone
  
  POP   BX              ; get the segment back
  POP   ES
  MOV   DS:pSectorInfoOffset, BX
  MOV   DS:pSectorInfoSeg, ES
  MOV   AX, ES
  MOV   CL, 4
  SHL   AX, CL
  ADD   AX, DS:bufferSize
  JNC   SetupBuffer
  MOV   AX, eInvalidMemory
  PUSH  AX
  JMP   FreeTheBlock


SetupBuffer:
; Set the sector numbers to NULLWORD
  MOV   DI, BX
  MOV   AX, NULLWORD
  MOV   CX, magicSectorNum
  CLD
  REP   STOSW


AllDone:
  MOV   AX,eOk
  MOV   DS:WStatus.PageSize, ddFDCPageSize   
GoToDone:
  PUSH  AX
  CALL  Restore               ; Put drive parms back in its own area
  POP   AX
  JMP   Done


;*******************************
;                              *
;     Deactivate               *
;                              *
;*******************************

DoDeact:
  CMP   DS:WStatus.PageSize, ddFDCPageSize
  JNE   DeactDone
  MOV   DS:WStatus.PageSize, 0   ; Flag to indicate the buffer is invalid
  PUSH  DS:pSectorInfoSeg
  PUSH  DS:pSectorInfoOffset
  PUSH  SS
  LEA   AX, error
  PUSH  AX
  CALL  CpFree
DeactDone:
  XOR   AX, AX
  PUSH  AX
  CALL  Restore
  POP   AX        
  JMP   Done

$EJECT

 ;*****************************
 ;	                *
 ;      Get Status            *
 ;	                *
 ;*****************************

FGetStatus:
  LEA   SI, DS:WStatus.PageSize
  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
  LEA   DI, DS:WStatus.PageSize     ; OFFSET WStatus.
  MOV   AX, DS                      ; SEG WStatus.
  LES   BX,pPList
  LDS   SI,ES:[BX].pBuffer          ; buffer for setstatus data
  MOV   BX, ES:[BX].len             ; length of status
  MOV   ES,AX
  MOV   CX, SetStatusLength
  CMP   BX, CX
  JGE   DoSet
  MOV   CX, BX
DoSet:
  CLD                               ; direction flag
  REP   MOVSB
  POP   DS

  MOV   AX, DS:WStatus.NumPages
  SUB   DX,DX
  DIV   DS:WStatus.SectorsPerTrack
  SUB   DX,DX
  DIV   DS:WStatus.TracksPerCylinder
  MOV   DS:WStatus.NumCylinders,AX 
  CALL  Restore                     ; Put device info back into its own area
  MOV   AX, eOk
  JMP   Done
$EJECT

 ;*******************************
 ;*	                  *
 ;*            Read             *
 ;*	                  *
 ;*******************************

RealRead:

  LES   BX, pPList
  MOV   AX, WORD PTR ES:[BX].position 
  CALL  InTable
  JNC   DoTheRead
; Transfer the buffer to the user's buffer
  PUSH  DS
  PUSH  ES
  POP   DS
  MOV   SI, BX

  LES   DI,pPlist
  LES   DI,ES:[DI].pBuffer          ; buffer to read/write data
  MOV   CX, ddFDCPageSizeWords
  CLD
  REP   MOVSW	                      ; move the data
  POP   DS
  MOV   AX, eOk
  JMP   DoneCritical


DoTheRead:
  MOV   DI, 201H                    ; read one sector
  MOV   CX, 2                       ; retry count

FDiskRead:
  PUSH   CX                         ; save retry count
  PUSH   DI

  CALL  Sector                      ; DL = Drive
	                      ; DH = head
	                      ; CH = Track
	                      ; CL = sector
	                      ; DI = request
  POP   DI
  MOV   AX,DI                       ; read/write n sectors
  MOV   AL, BYTE PTR DS:WStatus.SectorsPerTrack
  MOV   BX, CX                      ; copy of sector num
  AND   BL, 00111111b               ; mask out cylinder number
  SUB   AL, BL
  INC   AL
  CMP   AL, magicSectorNum
  JLE   Read5
  MOV   AL, magicSectorNum

Read5:
  PUSH  AX	                      ; save # sectors to read for later
  LES   BX, DWORD PTR DS:pSectorInfoOffset
  ADD   BX, magicSectorNum * 2      ; address of sector

  INT   13h	                      ; Go to the BIOS

  POP   DI                          ; # sectors to read
  POP   CX                          ; restore retry count
  JC    DiskFailRead

; Transfer the sector to the users buffer
DiskReadSuccess:
  PUSH  DI
  PUSH  DS
  PUSH  ES
  POP   DS
  MOV   SI, BX

  LES   DI,pPlist
  MOV   AX, WORD PTR ES:[DI].position ; get the sector number
  LES   DI,ES:[DI].pBuffer          ; buffer to read/write data
  MOV   CX, ddFDCPageSizeWords
  CLD
  REP   MOVSW	                      ; move the data
  POP   DS	                      ; restore data segment

; Put sector #'s into sectorNums array

  XOR   SI, SI                     ; start of array that has sector nums
  POP   DX
  MOV   CX, DX
  XOR   CH, CH

StoreNextSector:
  PUSH  CX
  CALL  InTable                     ; is this sector in the table?
  POP   CX
  JNC   Store10
  MOV   WORD PTR ES:[DI], NULLWORD  ; invalidate the sector

Store10:
  MOV   WORD PTR ES:[SI], AX        ; store sector number
  INC   AX	                      ; next sector
  INC   SI
  INC   SI	                      ; point to next element
  LOOP  StoreNextSector

  MOV   AX, eOk
  JMP   DoneCritical

DiskFailRead:

  CMP   AH, ePcCorrectedError
  JZ    DiskReadSuccess
  PUSH  AX
  XOR   AH, AH
  INT   13h	                      ; call the BIOS
  POP   AX	                      ; restore error code

  CMP   CX, 2	                      ; do at least 1 retry
  JGE   RetryRead

; exit after 1 retry for the following errors:
;   WriteProtect, BadCmd, TimeOut, Seek, Bad Address Mark

  TEST  AH, ePCQuickOutErrors
  JNZ   ReadError

RetryRead:
  LOOP  FDiskRead

; Now invalidate the buffers
ReadError:
  MOV  CX, magicSectorNum
  LES  BX, DWORD PTR DS:pSectorInfoOffset

ClearBuffer5:
  MOV  WORD PTR ES:[BX], NULLWORD
  INC  BX
  INC  BX
  LOOP ClearBuffer5
  JMP  DiskErr


 ;*******************************
 ;	                  *
 ;           Write              *
 ;	                  *
 ;*******************************

RealWrite:
  LES   BX, pPList
  MOV   AX, WORD PTR ES:[BX].position 
  CALL  InTable
  JNC   DoTheWrite
  MOV   WORD PTR ES:[DI], NULLWORD  ; invalidate the sector

DoTheWrite:
  MOV   DI,301H                     ; write one sector
  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
;  LES   BX,pPlist
;  LES   BX,ES:[BX].pBuffer          ;buffer to write data

  CALL  CheckBuffer                 ; Setup ES:[BX] to correct buffer
  POP   DI

  MOV   AX,DI                       ; read/write one sector
  INT   13h	                        ; Go to the BIOS

  POP   CX                          ; restore retry count
  JC    DiskFail
  
okHere:
  MOV   AX, eOk
  JMP   DoneCritical

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

  CMP   CX, 4	                      ; do at least 1 retry
  JGE   Retry

; exit after 1 retry for the following errors:
;   WriteProtect, BadCmd, TimeOut, Seek, Bad Address Mark

  TEST  AH, ePCQuickOutErrors
  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, eECCData
  TEST  BH, ePCECCError
  JNZ   ErrDONE

  CMP   BH, ePCCorrectedError
  JZ    OkHere

  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
  CMP   BH, ePCBadCmd
  JZ    ErrDONE
 
  MOV   AX, eOther

ErrDone:
  JMP   DoneCritical
 
;******************************
;*	                *
;*   Format Wini              *
;*	                *
;******************************

HardFormat:
; invalidate read buffer and set 1st buffer to NULLWORD.
  LES  DI, DWORD PTR DS:pSectorInfoOffset
  MOV  CX, magicSectorNum + ddFDCPageSizeWords
  MOV  AX, NULLWORD
  CLD
  REP  STOSW

  PUSH  ES
  CALL  Select                   ; set drive in DL
  POP   ES
  MOV   AX, 0F01h
  MOV   CX, 1
  MOV   BX, magicSectorNum
  SHL   BX, 1	                   ; point to sector
  INT   13h	                   ; write sector buffer

;
; Issue format command
;
  CALL  Select
  MOV   AL, ddFDCInterleaveFactor
  MOV   AH, 0F8h                    ; Format drive command using sector buffers
  MOV   CX, 1                       ; Track number, Sector Number
  MOV   DH, 0	                      ; start head
  INT   13h
  JNC   NOFDiskErr
  JMP   DiskErr                     ; IF error in Format Get Out

NOFDiskErr:
  MOV   AX, eOk


DoneCritical:
  PUSH  AX
  PUSH  DS:floppySema	      ; sid
  MOV   AX, 1	              ; mode = signalNormal
  PUSH  AX
  PUSH  AX	              ; note
  PUSH  SS
  LEA   AX, error           ; VAR error: WORD
  PUSH  AX
  CALL  CpSignal
  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


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

CODE ENDS

END
