;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RDOS operating system
; Copyright (C) 1988-2000, Leif Ekblad
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version. The only exception to this rule
; is for commercial usage in embedded systems. For information on
; usage in commercial embedded systems, contact embedded@rdos.net
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
;
; The author of this program may be contacted at leif@rdos.net
;
; IDE.ASM
; IDE disk driver
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

INCLUDE ..\driver.def
INCLUDE ..\user.def
INCLUDE ..\os.def
INCLUDE ..\user.inc
INCLUDE ..\os.inc
INCLUDE ..\drive.inc
INCLUDE ..\os\protseg.def
INCLUDE pci.inc

LBA_MODE        = 1
LBA_48          = 2

part_struc      STRUC

part_status         DB ?
part_start_head     DB ?
part_start_cyl_sector   DW ?
part_type           DB ?
part_end_head       DB ?
part_end_cyl_sector     DW ?
part_start_sector       DD ?
part_sectors        DD ?

part_struc      ENDS

drive_data      STRUC

drive_lba_flags         DB ?
drive_precomp           DB ?
drive_sectors_per_cyl       DW ?
drive_heads             DW ?
drive_cyls              DW ?
drive_sectors_per_unit      DW ?
drive_units             DW ?
drive_lba_sectors           DD ?
disc_io_base    DW ?
disc_ide_sel    DW ?
disc_sel            DW ?
disc_thread             DW ?
disc_sub_unit           DB ?
disc_nr             DB ?

disc_model          DB 40 DUP(?)

drive_data      ENDS

ide_data    STRUC

IdeThread       DW ?
IdeIoBase       DW ?
DriveSelArr     DW 2 DUP(?)
IdeSection      section_typ <>
IntFlag     DB ?

ide_data    ENDS

MAX_PCI_COUNT = 16
PCI_NAME_SIZE = 16

data    SEGMENT byte public 'DATA'

pci_thread      DW ?
ide_pci_curr    DW ?
ide_pci_count   DW ?
ide_io_arr      DW MAX_PCI_COUNT DUP(?)
ide_pci_arr     DW MAX_PCI_COUNT DUP(?)

pci_curr_ptr    DW ?
pci_unit_ptr    DW ?
pci_name_str    DB PCI_NAME_SIZE DUP(?)

data    ENDS

    .386p

code    SEGMENT byte public use16 'CODE'

    assume cs:code


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       IDE_INT
;
;       DESCRIPTION:    IDE INTERRUPT
;
;       PARAMETERS:     
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ide_int Proc far
    mov ds:IntFlag,1
    mov bx,ds:IdeThread
    Signal
    retf32
ide_int Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       IDE_PCI_INT
;
;       DESCRIPTION:    PCI IDE INTERRUPT
;
;       PARAMETERS:     
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ide_pci_int Proc far
    mov dx,ds:IdeIoBase
    or dx,dx
    jz ide_pci_int_base_ok
;
    add dx,7
    in al,dx

ide_pci_int_base_ok:    
    mov ds:IntFlag,1
    mov bx,ds:IdeThread
    Signal
    retf32
ide_pci_int Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       CheckReady
;
;       DESCRIPTION:    Wait for ready
;
;       PARAMETERS:     DS      IDE_DATA
;           DX      Io base
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckReady      PROC near
    push ax
    push cx
    push dx
;
    add dx,7
    mov cx,10000

CheckBusyLoop:
    in al,dx
    test al,80h
    clc
    jz CheckReadyDone
;       
    mov ax,50
    WaitMicroSec
;       
    loop CheckBusyLoop
    
    stc
    
CheckReadyDone:
    pop dx
    pop cx
    pop ax
    ret
CheckReady      ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       WaitReady
;
;       DESCRIPTION:    Wait for DRDY signal
;
;       PARAMETERS:     DS      IDE_DATA
;           DX      Io base
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

WaitReady       PROC near
    push ax
    push cx
    push dx
;
    add dx,7
    mov cx,10000

WaitReadyLoop:
    in al,dx
    test al,40h
    clc
    jnz WaitReadyDone
;       
    mov ax,50
    WaitMicroSec
;       
    loop WaitReadyLoop
    
    stc
    
WaitReadyDone:
    pop dx
    pop cx
    pop ax
    ret
WaitReady       ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       WaitDrq
;
;       DESCRIPTION:    Wait for data request
;
;       PARAMETERS:     DS      IDE_DATA
;           DX      Disc io base
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

WaitDrq Proc near
    push ax
    push cx
    push dx
;
    mov cx,10000
    add dx,7
WaitDrqLoop:
    in al,dx
    test al,8
    clc
    jnz WaitDrqDone 
    mov ax,50
    WaitMicroSec
    loop WaitDrqLoop
    stc
WaitDrqDone:
    pop dx
    pop cx
    pop ax
    ret
WaitDrq Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       CheckStatus
;
;       DESCRIPTION:    Check transfer status
;
;       PARAMETERS:     DS      IDE_DATA
;           DX      Disc io base
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckStatus     Proc near
    push ax
    push dx
;
    add dx,7
    in al,dx
    test al,80h
    jnz CheckStatusFail
    test al,20h
    jnz CheckStatusFail
    test al,40h
    jz CheckStatusFail
    test al,10h
    jz CheckStatusFail
    test al,1
    clc
    jz CheckStatusDone
    sub dx,6
    in al,dx
CheckStatusFail:
    stc
CheckStatusDone:
    pop dx
    pop ax
    ret
CheckStatus     Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       SetupIdeTaskFile
;
;       DESCRIPTION:    Setup IDE comp. task file
;
;       PARAMETERS:     DS      IDE_DATA
;               FS      Disc sel
;               AH      Precomp
;               BH      Head #
;               BL      Sector
;               CX      Number of sectors
;               DX      Cylinder
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SetupIdeTaskFile    Proc near
    push ax
    push bx
    push dx
;
    push dx
    mov dx,fs:disc_io_base
    add dx,7
    in al,dx
    clc
    test al,80h
    jz SetupIdeNotBusy
;
    sub dx,7
    call CheckReady

SetupIdeNotBusy:    
    pop dx
    jc SetupIdeTaskDone
;       
    push dx
    mov dx,fs:disc_io_base
    inc dx
;
    jmp short $+2
    mov al,ah
    out dx,al
    inc dx
;
    jmp short $+2
    mov ax,cx
    out dx,al
    inc dx
;
    jmp short $+2
    mov al,bl
    out dx,al
    inc dx
;
    pop ax
    jmp short $+2
    out dx,al
    inc dx
;
    jmp short $+2
    mov al,ah
    out dx,al
    inc dx
;
    mov al,fs:disc_sub_unit
    shl al,4
    or al,bh
    or al,0A0h
    out dx,al
;
    mov dx,fs:disc_io_base
    add dx,7
    in al,dx
    test al,40h
    clc
    jnz SetupIdeTaskDone
;
    sub dx,7
    call WaitReady
    
SetupIdeTaskDone:
    pop dx
    pop bx
    pop ax
    ret
SetupIdeTaskFile    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       SetupLbaTaskFile
;
;       DESCRIPTION:    Setup LBA comp. task file
;
;       PARAMETERS:     DS      IDE_DATA
;               FS      Disc sel
;               AH      Precomp
;               CX      Number of sectors
;               EDX     Sector #
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SetupLbaTaskFile    Proc near
    push ax
    push bx
    push dx
;
    push dx
    mov dx,fs:disc_io_base
    add dx,7
    in al,dx
    clc
    test al,80h
    jz SetupLbaNotBusy
;
    sub dx,7
    call CheckReady

SetupLbaNotBusy:    
    pop dx
    jc SetupLbaTaskDone
;
    test fs:drive_lba_flags,LBA_48
    jnz SetupLba48

SetupLba24:
    push edx
    mov dx,fs:disc_io_base
    inc dx
;
    jmp short $+2
    mov al,ah
    out dx,al
    inc dx
;
    jmp short $+2
    mov al,cl
    out dx,al
    inc dx
;
    pop ax
    jmp short $+2
    out dx,al
    inc dx
;
    mov al,ah
    jmp short $+2
    out dx,al
    inc dx
;
    pop ax
    jmp short $+2
    out dx,al
    inc dx
;
    mov bl,ah
    mov al,fs:disc_sub_unit
    shl al,4
    or al,bl
    or al,0E0h
    out dx,al
;
    mov dx,fs:disc_io_base
    add dx,7
    in al,dx
    test al,40h
    clc
    jnz SetupLbaTaskDone
;
    sub dx,7
    call WaitReady
    jmp SetupLbaTaskDone

SetupLba48:
    push edx
;
    mov dx,fs:disc_io_base
    add dx,6
;
    mov al,fs:disc_sub_unit
    shl al,4
    or al,40h
    out dx,al
;
    mov dx,fs:disc_io_base
    add dx,2
;
    mov al,ch
    out dx,al
    inc dx
;
    pop eax
    rol eax,8
;    
    jmp short $+2
    out dx,al
    inc dx
;
    jmp short $+2
    xor al,al
    out dx,al
    inc dx
;
    jmp short $+2
    xor al,al
    out dx,al
;
    sub dx,3
    jmp short $+2
    mov al,cl
    out dx,al
    inc dx
;
    ror eax,8
    jmp short $+2
    out dx,al
    inc dx
;
    ror eax,8
    jmp short $+2
    out dx,al
    inc dx
;
    ror eax,8
    jmp short $+2
    out dx,al
    inc dx
    clc
    
SetupLbaTaskDone:
    pop dx
    pop bx
    pop ax
    ret
SetupLbaTaskFile    Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       ReadTaskFile
;
;       DESCRIPTION:    Read data from device
;
;       PARAMETERS:     DS      IDE SEGMENT
;               AL      COMMAND CODE
;               CX      Number of sectors
;           DX      Disc io base
;               ES:EDI  Logical address of buffer
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadTaskFile    Proc near
    push cx
    push edi
;
    ClearSignal
    push dx
    add dx,7
    out dx,al
    pop dx
    
ReadTaskFileInt:
    push eax
    push edx
    GetSystemTime
    add eax,1193 * 500
    adc edx,0
    WaitForSignalWithTimeout
    pop edx
    pop eax
;       
    push dx
    add dx,7
    in al,dx
    pop dx
    test al,80h
    jnz ReadTaskFileInt
;
    push ecx
    mov ecx,256
    rep ins word ptr es:[edi],dx
    pop ecx
    call CheckStatus
    jc ReadTaskFileDone
    loop ReadTaskFileInt
    clc
    
ReadTaskFileDone:
    pop edi
    pop cx
    ret
ReadTaskFile    ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       WriteTaskFile
;
;       DESCRIPTION:    Write data to device
;
;       PARAMETERS:     DS      IDE SEGMENT
;               AL      Command code
;               CX      Number of sectors
;           DX      Disc io base
;               ES:EDI  Logical address of buffer
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

WriteTaskFile   PROC near
    push ax
    push cx
    push edi
;
    ClearSignal
    push dx
    add dx,7
    out dx,al
    pop dx
    
WriteTaskFileInt:
    call WaitDrq
    jc WriteTaskFileDone
;       
    push cx
    mov cx,256
    
WriteTaskFileLoop:
    mov ax,es:[edi]
    add edi,2
    out dx,ax
    loop WriteTaskFileLoop
    pop cx

WriteTaskFileWait:       
    push eax
    push edx
    GetSystemTime
    add eax,1193 * 500
    adc edx,0
    WaitForSignalWithTimeout
    pop edx
    pop eax
;       
    push dx
    add dx,7
    in al,dx
    pop dx
    test al,80h
    jnz WriteTaskFileWait
;
    call CheckStatus
    jc WriteTaskFileDone
;       
    loop WriteTaskFileInt
    clc
    
WriteTaskFileDone:
    pop edi
    pop cx
    pop ax
    ret
WriteTaskFile   ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       ReadDrive
;
;       DESCRIPTION:    Read data
;
;       PARAMETERS:     FS      Disc sel
;               BX      Sector #
;               CX      Number of sectors
;               EDX     Unit #
;               EDI     Logical address of buffer
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadDrive       Proc near
    push bx
    mov ds,fs:disc_ide_sel
    EnterSection ds:IdeSection
    GetThread
    mov ds:IdeThread,ax
    mov ax,fs:disc_io_base
    mov ds:IdeIoBase,ax
    pop bx
    test fs:drive_lba_flags,LBA_MODE
    jz ReadDriveIde

ReadDriveLba:
    push edx
    movzx eax,fs:drive_sectors_per_unit
    mul edx
    movzx ebx,bx
    add eax,ebx
    mov edx,eax
    mov ah,fs:drive_precomp
    call SetupLbaTaskFile
    pop edx
    jmp ReadDriveStart

ReadDriveIde:
    push bx
    mov ax,bx
    div byte ptr fs:drive_sectors_per_cyl
    mov bh,al
    mov bl,ah
    inc bl
    mov ah,fs:drive_precomp
    call SetupIdeTaskFile
    pop bx

ReadDriveStart:
    jc ReadDriveDone
;
    push dx     
    mov al,20h
    test fs:drive_lba_flags,LBA_48
    jz ReadDriveLbaOk
;
    or al,4

ReadDriveLbaOk:    
    mov dx,fs:disc_io_base
    call ReadTaskFile
    pop dx

ReadDriveDone:
    pushf
    mov ds:IdeThread,0
    mov ds:IdeIoBase,0
    LeaveSection ds:IdeSection
    popf
    ret
ReadDrive       Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       WriteDrive
;
;       DESCRIPTION:    Write data
;
;       PARAMETERS:     FS      Disc sel
;               BX      Sector #
;               CX      Number of sectors
;               EDX     Unit #
;               EDI     Logical address of buffer
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

WriteDrive      Proc near
    push bx
    mov ds,fs:disc_ide_sel
    EnterSection ds:IdeSection
    GetThread
    mov ds:IdeThread,ax
    mov ax,fs:disc_io_base
    mov ds:IdeIoBase,ax
    pop bx
    test fs:drive_lba_flags,LBA_MODE
    jz WriteDriveIde

WriteDriveLba:
    push edx
    movzx eax,fs:drive_sectors_per_unit
    mul edx
    movzx ebx,bx
    add eax,ebx
    mov edx,eax
    mov ah,fs:drive_precomp
    call SetupLbaTaskFile
    pop edx
    jmp WriteDriveStart

WriteDriveIde:
    push bx
    mov ax,bx
    div byte ptr fs:drive_sectors_per_cyl
    mov bh,al
    mov bl,ah
    inc bl
    mov ah,fs:drive_precomp
    call SetupIdeTaskFile
    pop bx

WriteDriveStart:
    jc WriteDriveDone
;
    push dx     
    mov al,30h
    test fs:drive_lba_flags,LBA_48
    jz WriteDriveLbaOk
;
    or al,4

WriteDriveLbaOk:    
    mov dx,fs:disc_io_base
    call WriteTaskFile
    pop dx
    
WriteDriveDone:
    pushf
    mov ds:IdeThread,0
    mov ds:IdeIoBase,0
    LeaveSection ds:IdeSection
    popf
    ret
WriteDrive      Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       GetDriveParams
;
;       DESCRIPTION:    Get drive param
;
;       PARAMETERS:     DS      IDE SEGMENT
;               FS      DRIVE SEL
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

GetDriveParams  Proc near
    push es
    pushad
;
    mov ax,flat_sel
    mov es,ax
    mov eax,200h
    AllocateSmallLinear
    mov edi,edx
;
    mov fs:drive_lba_flags,0
    mov fs:drive_precomp,0FFh
    xor dx,dx
    xor bx,bx
    mov cx,1
    mov ah,fs:drive_precomp
    call SetupIdeTaskFile
    jc get_drive_param_done
;
    mov al,0ECh
    mov dx,fs:disc_io_base
    call ReadTaskFile
    jc get_drive_param_done
;
    xor edx,edx
    mov ecx,10

get_drive_copy_model:
    mov eax,es:[edi+edx+36h]
    mov dword ptr fs:[edx].disc_model,eax
    add edx,4
    loop get_drive_copy_model    
;
    mov ax,es:[edi+166]
    test ax,4000h
    jz get_drive_param24

get_drive_param48:
    mov edx,es:[edi+204]
    mov eax,es:[edi+200]
    or edx,edx
    jz get_drive_param_save48
;
    mov eax,0FFFFFFFFh

get_drive_param_save48:
    cmp eax,es:[edi+120]
    jb get_drive_param24
;    
    or fs:drive_lba_flags,LBA_48
    jmp get_drive_param_sectors_ok

get_drive_param24:
    mov eax,es:[edi+120]

get_drive_param_sectors_ok:
    mov fs:drive_lba_sectors,eax
    mov ax,word ptr es:[edi+2]
    mov fs:drive_cyls,ax
    mov ax,es:[edi+6]
    mov fs:drive_heads,ax
    mov ax,es:[edi+12]
    mov fs:drive_sectors_per_cyl,ax
;
    mov ax,es:[edi+98]
    test ax,200h
    jz get_drive_param_done
;    
    or fs:drive_lba_flags,LBA_MODE
    mov cx,1
    mov ah,fs:drive_precomp
    xor edx,edx
    call SetupLbaTaskFile
    jc get_drive_param_done
;
    mov al,20h
    test fs:drive_lba_flags,LBA_48
    jz get_drive_param_check
;
    or al,4

get_drive_param_check:    
    mov dx,fs:disc_io_base
    call ReadTaskFile       
    jnc get_drive_param_done
;
    mov fs:drive_lba_flags,0
    mov bh,0
    mov bl,1
    mov cx,1
    xor dx,dx
    call SetupIdeTaskFile
    jc get_drive_param_done
;
    mov al,20h
    mov dx,fs:disc_io_base
    call ReadTaskFile

get_drive_param_done:
    pushf
    mov ecx,200h
    mov edx,edi
    FreeLinear
    popf
;
    popad
    pop es
    ret
GetDriveParams  Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       CalcParam
;
;       DESCRIPTION:    Calculate various parameters
;
;       PARAMETERS:     DS      IDE SEGMENT
;               FS      DRIVE SEL
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CalcParam       Proc near
    pushad
;
    mov ax,fs:drive_sectors_per_cyl
    mul fs:drive_heads
    mov fs:drive_sectors_per_unit,ax
;
    movzx eax,ax
    mov esi,eax
    movzx edi,fs:drive_cyls 
    mul edi
    mov edi,eax
;
    test fs:drive_lba_flags,LBA_MODE
    jz calc_param_chs
;
    cmp edi,fs:drive_lba_sectors
    jae calc_param_chs
;
    mov eax,1
    mov edx,fs:drive_lba_sectors

calc_param_lba_norm_loop:
    shl eax,1
    shr edx,1
    cmp eax,edx
    jc calc_param_lba_norm_loop
;
    mov esi,edx
    mov ebx,esi
    mov ecx,edx

calc_param_lba_chs_loop:
    xor edx,edx
    mov eax,fs:drive_lba_sectors
    div esi
    cmp ecx,edx
    jc calc_param_lba_chs_next
;       
    mov ecx,edx
    mov ebx,esi
    or edx,edx
    jz calc_param_lba_chs_ok

calc_param_lba_chs_next:
    inc esi
    cmp esi,eax
    jbe calc_param_lba_chs_loop
;
    xor edx,edx
    mov eax,fs:drive_lba_sectors
    div ebx

calc_param_lba_chs_ok:
    mov edx,eax
    mov eax,ebx
    jmp calc_param_chs_ok
    
calc_param_chs:
    xor edx,edx
    mov eax,edi
    div esi
    mov edx,esi
    xchg eax,edx

calc_param_chs_ok:
    mov fs:drive_sectors_per_unit,ax
    mov fs:drive_units,dx
    mul dx
    push dx
    push ax
;
    mov eax,fs:drive_lba_sectors
    xor edx,edx
    movzx ecx,fs:drive_sectors_per_cyl
    div ecx
    xor edx,edx
    movzx ecx,fs:drive_heads
    div ecx

calc_param_bios_loop:
    cmp eax,1024
    jbe calc_param_bios_ok
;
    test cx,80h
    jnz calc_param_bios_max_head
;
    shl cx,1
    shr eax,1
    jmp calc_param_bios_loop

calc_param_bios_max_head:
    mov ax,1024
    mov cx,0FFh

calc_param_bios_ok:
    mov fs:drive_heads,cx
    mov fs:drive_cyls,ax
;
    pop fs:drive_lba_sectors
;
    popad
    ret
CalcParam       Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       ChsToLba
;
;       DESCRIPTION:    Convert CHS to LBA
;
;       PARAMETERS:     DS      IDE SEGMENT
;               FS      DRIVE SEGMENT
;               ES:EDI  CHS address
;
;       RETURNS:    EDX     LBA address
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ChsToLba    Proc near
    push eax
    push ecx
;
    mov cl,es:[edi+2]
    movzx ax,byte ptr es:[edi+1]
    and al,0C0h
    shl ax,2
    mov ch,ah
    cmp cx,1023
    je chs_to_lba_fail
;
    movzx eax,fs:drive_heads
    movzx ecx,cx
    mul ecx
    movzx ecx,byte ptr es:[edi]
    add ecx,eax
    movzx eax,fs:drive_sectors_per_cyl
    mul ecx
    movzx ecx,byte ptr es:[edi+1]
    and cl,3Fh
    add eax,ecx
    dec eax
    mov edx,eax
    jmp chs_to_lba_done

chs_to_lba_fail:
    xor edx,edx

chs_to_lba_done:
    pop ecx
    pop eax
    ret
ChsToLba    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       InstallPartition
;
;       DESCRIPTION:    Install partition
;
;       PARAMETERS:     DS      IDE SEGMENT
;               ES      FLAT_SEL
;               FS      Disc sel
;               CL      PARTITION TYPE
;               EDX     START SECTOR
;               EAX     NUMBER OF SECTORS
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

fs_unknown      DB 'UNKNOWN '
fs_fat12    DB 'FAT12   '
fs_fat16    DB 'FAT16   '
fs_fat32    DB 'FAT32   '
fs_hpfs     DB 'HPFS    '
fs_rdfs     DB 'RDFS    '
fs_flashfs  DB 'FLASHFS '

FsTab:
fs00    DW OFFSET fs_unknown
fs01    DW OFFSET fs_fat12
fs02    DW OFFSET fs_unknown
fs03    DW OFFSET fs_unknown
fs04    DW OFFSET fs_fat16
fs05    DW OFFSET fs_unknown
fs06    DW OFFSET fs_fat16
fs07    DW OFFSET fs_hpfs
fs08    DW OFFSET fs_unknown
fs09    DW OFFSET fs_unknown
fs0A    DW OFFSET fs_unknown
fs0B    DW OFFSET fs_fat32
fs0C    DW OFFSET fs_fat32
fs0D    DW OFFSET fs_unknown
fs0E    DW OFFSET fs_unknown
fs0F    DW OFFSET fs_unknown
fs10    DW OFFSET fs_unknown
fs11    DW OFFSET fs_unknown
fs12    DW OFFSET fs_unknown
fs13    DW OFFSET fs_unknown
fs14    DW OFFSET fs_unknown
fs15    DW OFFSET fs_unknown
fs16    DW OFFSET fs_unknown
fs17    DW OFFSET fs_unknown
fs18    DW OFFSET fs_unknown
fs19    DW OFFSET fs_unknown
fs1A    DW OFFSET fs_unknown
fs1B    DW OFFSET fs_unknown
fs1C    DW OFFSET fs_unknown
fs1D    DW OFFSET fs_unknown
fs1E    DW OFFSET fs_unknown
fs1F    DW OFFSET fs_unknown
fs20    DW OFFSET fs_unknown
fs21    DW OFFSET fs_unknown
fs22    DW OFFSET fs_unknown
fs23    DW OFFSET fs_unknown
fs24    DW OFFSET fs_unknown
fs25    DW OFFSET fs_unknown
fs26    DW OFFSET fs_unknown
fs27    DW OFFSET fs_unknown
fs28    DW OFFSET fs_unknown
fs29    DW OFFSET fs_unknown
fs2A    DW OFFSET fs_unknown
fs2B    DW OFFSET fs_unknown
fs2C    DW OFFSET fs_unknown
fs2D    DW OFFSET fs_unknown
fs2E    DW OFFSET fs_unknown
fs2F    DW OFFSET fs_unknown
fs30    DW OFFSET fs_unknown
fs31    DW OFFSET fs_unknown
fs32    DW OFFSET fs_unknown
fs33    DW OFFSET fs_unknown
fs34    DW OFFSET fs_unknown
fs35    DW OFFSET fs_unknown
fs36    DW OFFSET fs_unknown
fs37    DW OFFSET fs_unknown
fs38    DW OFFSET fs_unknown
fs39    DW OFFSET fs_unknown
fs3A    DW OFFSET fs_unknown
fs3B    DW OFFSET fs_unknown
fs3C    DW OFFSET fs_unknown
fs3D    DW OFFSET fs_unknown
fs3E    DW OFFSET fs_unknown
fs3F    DW OFFSET fs_unknown
fs40    DW OFFSET fs_unknown
fs41    DW OFFSET fs_unknown
fs42    DW OFFSET fs_unknown
fs43    DW OFFSET fs_unknown
fs44    DW OFFSET fs_unknown
fs45    DW OFFSET fs_unknown
fs46    DW OFFSET fs_unknown
fs47    DW OFFSET fs_unknown
fs48    DW OFFSET fs_unknown
fs49    DW OFFSET fs_unknown
fs4A    DW OFFSET fs_unknown
fs4B    DW OFFSET fs_unknown
fs4C    DW OFFSET fs_unknown
fs4D    DW OFFSET fs_unknown
fs4E    DW OFFSET fs_unknown
fs4F    DW OFFSET fs_unknown
fs50    DW OFFSET fs_unknown
fs51    DW OFFSET fs_unknown
fs52    DW OFFSET fs_unknown
fs53    DW OFFSET fs_unknown
fs54    DW OFFSET fs_unknown
fs55    DW OFFSET fs_unknown
fs56    DW OFFSET fs_unknown
fs57    DW OFFSET fs_unknown
fs58    DW OFFSET fs_unknown
fs59    DW OFFSET fs_unknown
fs5A    DW OFFSET fs_unknown
fs5B    DW OFFSET fs_unknown
fs5C    DW OFFSET fs_unknown
fs5D    DW OFFSET fs_unknown
fs5E    DW OFFSET fs_unknown
fs5F    DW OFFSET fs_unknown
fs60    DW OFFSET fs_unknown
fs61    DW OFFSET fs_unknown
fs62    DW OFFSET fs_unknown
fs63    DW OFFSET fs_unknown
fs64    DW OFFSET fs_unknown
fs65    DW OFFSET fs_unknown
fs66    DW OFFSET fs_unknown
fs67    DW OFFSET fs_unknown
fs68    DW OFFSET fs_unknown
fs69    DW OFFSET fs_unknown
fs6A    DW OFFSET fs_unknown
fs6B    DW OFFSET fs_unknown
fs6C    DW OFFSET fs_unknown
fs6D    DW OFFSET fs_unknown
fs6E    DW OFFSET fs_unknown
fs6F    DW OFFSET fs_unknown
fs70    DW OFFSET fs_unknown
fs71    DW OFFSET fs_unknown
fs72    DW OFFSET fs_unknown
fs73    DW OFFSET fs_unknown
fs74    DW OFFSET fs_unknown
fs75    DW OFFSET fs_unknown
fs76    DW OFFSET fs_unknown
fs77    DW OFFSET fs_unknown
fs78    DW OFFSET fs_unknown
fs79    DW OFFSET fs_unknown
fs7A    DW OFFSET fs_unknown
fs7B    DW OFFSET fs_unknown
fs7C    DW OFFSET fs_unknown
fs7D    DW OFFSET fs_unknown
fs7E    DW OFFSET fs_unknown
fs7F    DW OFFSET fs_unknown
fs80    DW OFFSET fs_unknown
fs81    DW OFFSET fs_unknown
fs82    DW OFFSET fs_unknown
fs83    DW OFFSET fs_unknown
fs84    DW OFFSET fs_unknown
fs85    DW OFFSET fs_unknown
fs86    DW OFFSET fs_unknown
fs87    DW OFFSET fs_unknown
fs88    DW OFFSET fs_unknown
fs89    DW OFFSET fs_unknown
fs8A    DW OFFSET fs_unknown
fs8B    DW OFFSET fs_unknown
fs8C    DW OFFSET fs_unknown
fs8D    DW OFFSET fs_unknown
fs8E    DW OFFSET fs_unknown
fs8F    DW OFFSET fs_unknown
fs90    DW OFFSET fs_unknown
fs91    DW OFFSET fs_unknown
fs92    DW OFFSET fs_unknown
fs93    DW OFFSET fs_unknown
fs94    DW OFFSET fs_unknown
fs95    DW OFFSET fs_unknown
fs96    DW OFFSET fs_unknown
fs97    DW OFFSET fs_unknown
fs98    DW OFFSET fs_unknown
fs99    DW OFFSET fs_unknown
fs9A    DW OFFSET fs_unknown
fs9B    DW OFFSET fs_unknown
fs9C    DW OFFSET fs_unknown
fs9D    DW OFFSET fs_unknown
fs9E    DW OFFSET fs_unknown
fs9F    DW OFFSET fs_unknown
fsA0    DW OFFSET fs_unknown
fsA1    DW OFFSET fs_unknown
fsA2    DW OFFSET fs_unknown
fsA3    DW OFFSET fs_unknown
fsA4    DW OFFSET fs_unknown
fsA5    DW OFFSET fs_unknown
fsA6    DW OFFSET fs_unknown
fsA7    DW OFFSET fs_unknown
fsA8    DW OFFSET fs_unknown
fsA9    DW OFFSET fs_unknown
fsAA    DW OFFSET fs_unknown
fsAB    DW OFFSET fs_unknown
fsAC    DW OFFSET fs_unknown
fsAD    DW OFFSET fs_unknown
fsAE    DW OFFSET fs_rdfs
fsAF    DW OFFSET fs_flashfs
fsB0    DW OFFSET fs_unknown
fsB1    DW OFFSET fs_unknown
fsB2    DW OFFSET fs_unknown
fsB3    DW OFFSET fs_unknown
fsB4    DW OFFSET fs_unknown
fsB5    DW OFFSET fs_unknown
fsB6    DW OFFSET fs_unknown
fsB7    DW OFFSET fs_unknown
fsB8    DW OFFSET fs_unknown
fsB9    DW OFFSET fs_unknown
fsBA    DW OFFSET fs_unknown
fsBB    DW OFFSET fs_unknown
fsBC    DW OFFSET fs_unknown
fsBD    DW OFFSET fs_unknown
fsBE    DW OFFSET fs_unknown
fsBF    DW OFFSET fs_unknown
fsC0    DW OFFSET fs_unknown
fsC1    DW OFFSET fs_unknown
fsC2    DW OFFSET fs_unknown
fsC3    DW OFFSET fs_unknown
fsC4    DW OFFSET fs_unknown
fsC5    DW OFFSET fs_unknown
fsC6    DW OFFSET fs_unknown
fsC7    DW OFFSET fs_unknown
fsC8    DW OFFSET fs_unknown
fsC9    DW OFFSET fs_unknown
fsCA    DW OFFSET fs_unknown
fsCB    DW OFFSET fs_unknown
fsCC    DW OFFSET fs_unknown
fsCD    DW OFFSET fs_unknown
fsCE    DW OFFSET fs_unknown
fsCF    DW OFFSET fs_unknown
fsD0    DW OFFSET fs_unknown
fsD1    DW OFFSET fs_unknown
fsD2    DW OFFSET fs_unknown
fsD3    DW OFFSET fs_unknown
fsD4    DW OFFSET fs_unknown
fsD5    DW OFFSET fs_unknown
fsD6    DW OFFSET fs_unknown
fsD7    DW OFFSET fs_unknown
fsD8    DW OFFSET fs_unknown
fsD9    DW OFFSET fs_unknown
fsDA    DW OFFSET fs_unknown
fsDB    DW OFFSET fs_unknown
fsDC    DW OFFSET fs_unknown
fsDD    DW OFFSET fs_unknown
fsDE    DW OFFSET fs_unknown
fsDF    DW OFFSET fs_unknown
fsE0    DW OFFSET fs_unknown
fsE1    DW OFFSET fs_unknown
fsE2    DW OFFSET fs_unknown
fsE3    DW OFFSET fs_unknown
fsE4    DW OFFSET fs_unknown
fsE5    DW OFFSET fs_unknown
fsE6    DW OFFSET fs_unknown
fsE7    DW OFFSET fs_unknown
fsE8    DW OFFSET fs_unknown
fsE9    DW OFFSET fs_unknown
fsEA    DW OFFSET fs_unknown
fsEB    DW OFFSET fs_unknown
fsEC    DW OFFSET fs_unknown
fsED    DW OFFSET fs_unknown
fsEE    DW OFFSET fs_unknown
fsEF    DW OFFSET fs_unknown
fsF0    DW OFFSET fs_unknown
fsF1    DW OFFSET fs_unknown
fsF2    DW OFFSET fs_unknown
fsF3    DW OFFSET fs_unknown
fsF4    DW OFFSET fs_unknown
fsF5    DW OFFSET fs_unknown
fsF6    DW OFFSET fs_unknown
fsF7    DW OFFSET fs_unknown
fsF8    DW OFFSET fs_unknown
fsF9    DW OFFSET fs_unknown
fsFA    DW OFFSET fs_unknown
fsFB    DW OFFSET fs_unknown
fsFC    DW OFFSET fs_unknown
fsFD    DW OFFSET fs_unknown
fsFE    DW OFFSET fs_unknown
fsFF    DW OFFSET fs_unknown

InstallPartition    Proc near
    push es
    pushad
;
    cmp cl,7
    jne install_check_type
;
    push eax
;
    push edx
    mov eax,200h
    AllocateSmallLinear
    mov edi,edx
    pop edx
;
    push edx
    mov eax,edx
    xor edx,edx
    movzx ecx,word ptr fs:drive_sectors_per_unit
    div ecx
    mov bx,dx
    mov edx,eax
    mov ecx,1
    call ReadDrive
    pop edx
;
    push ds
    push edx
    mov eax,10h
    AllocateSmallGlobalMem
    mov ax,flat_sel
    mov ds,ax
    mov edx,edi
    lea esi,[edi+36h]
    xor edi,edi
    movs dword ptr es:[edi],ds:[esi]
    movs dword ptr es:[edi],ds:[esi]
    movs dword ptr es:[edi],ds:[esi]
    movs dword ptr es:[edi],ds:[esi]
    xor ecx,ecx
    FreeLinear
;
    pop edx
    pop ds
;
    pop ecx
    xor edi,edi
    IsFileSystemAvailable
    jc install_part_free
;
    AllocateStaticDrive
    mov ah,fs:disc_nr
    OpenDrive
;
    InstallFileSystem
    clc

install_part_free:
    pushf
    FreeMem
    popf
    jmp install_part_done

install_check_type:
    mov di,cs
    mov es,di
    movzx di,cl
    shl di,1

install_part_test_avail:
    mov ecx,eax
    mov di,word ptr cs:[di].FsTab
    movzx edi,di
    IsFileSystemAvailable
    jc install_part_done
;
    AllocateStaticDrive
    mov ah,fs:disc_nr
    OpenDrive
;
    InstallFileSystem
    clc

install_part_done:
    popad
    pop es
    ret
InstallPartition    Endp

    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       read_drive
;
;       DESCRIPTION:    Read drive
;
;       PARAMETERS:     FS      Disc selector
;               ESI     Disc handle array
;               ECX     Entries
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

read_drive      Proc near
    mov ds,fs:disc_ide_sel
    EnterSection ds:IdeSection
    mov bp,3

read_drive_retry_loop:
    ClearSignal
    GetThread
    mov ds:IdeThread,ax
    mov ax,fs:disc_io_base
    mov ds:IdeIoBase,ax
;
    test fs:drive_lba_flags,LBA_MODE
    jz read_drive_ide

read_drive_lba:
    mov edx,es:[edi].dh_unit
    movzx eax,fs:drive_sectors_per_unit
    mul edx
    movzx ebx,es:[edi].dh_sector
    add eax,ebx
    mov edx,eax
    mov ah,fs:drive_precomp
    call SetupLbaTaskFile
    jmp read_drive_start

read_drive_ide:
    mov edx,es:[edi].dh_unit
    mov ax,es:[edi].dh_sector
    div byte ptr fs:drive_sectors_per_cyl
    mov bh,al
    mov bl,ah
    inc bl
    mov ah,fs:drive_precomp
    call SetupIdeTaskFile

read_drive_start:
    jc read_drive_fail
;
    mov al,20h
    test fs:drive_lba_flags,LBA_48
    jz read_drive_lba_ok
;
    or al,4

read_drive_lba_ok:    
    mov dx,fs:disc_io_base
    add dx,7
    out dx,al

read_sector_loop:
    push eax
    GetSystemTime
    add eax,1193 * 500
    adc edx,0
    WaitForSignalWithTimeout
    pop eax
;       
    mov dx,fs:disc_io_base
    add dx,7
    in al,dx
    test al,80h
    jnz read_sector_loop
;    
    mov dx,fs:disc_io_base
    call CheckStatus
    jc read_drive_retry
;       
    mov dx,fs:disc_io_base
    add dx,7
    in al,dx
    test al,8
    clc
    jnz read_drive_drq_ok
;
    call WaitDrq
    jc read_drive_retry

read_drive_drq_ok:
    mov dx,fs:disc_io_base
    push cx
    push edi
    mov edi,es:[edi].dh_data
    mov ecx,256
    rep ins word ptr es:[edi],dx
    pop edi
    pop cx
    jmp read_drive_ok

read_drive_retry:
    int 3
    sub bp,1
    jnz read_drive_retry_loop

read_drive_fail:
    mov es:[edi].dh_state,STATE_BAD
    mov bx,fs:disc_sel
    DiscRequestCompleted
;
    mov bp,3
    add esi,4
    mov edi,es:[esi]
    sub cx,1
    jnz read_drive_retry_loop
    jmp read_drive_done

read_drive_ok:
    mov eax,es:[edi].dh_data
    mov es:[edi].dh_state,STATE_USED
    mov bx,fs:disc_sel
    DiscRequestCompleted
;
    add esi,4
    mov edi,es:[esi]
    sub cx,1
    jnz read_sector_loop

read_drive_done:
    LeaveSection ds:IdeSection
    ret
read_drive      Endp

    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       write_drive
;
;       DESCRIPTION:    Perform a write request
;
;       PARAMETERS:     FS      Disc selector
;               ESI     Disc handle array
;               ECX     Entries
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

write_drive     Proc near
    mov ds,fs:disc_ide_sel
    EnterSection ds:IdeSection
    mov bp,3

write_drive_retry_loop:
    ClearSignal
    GetThread
    mov ds:IdeThread,ax
    mov ax,fs:disc_io_base
    mov ds:IdeIoBase,ax
;
    test fs:drive_lba_flags,LBA_MODE
    jz write_drive_ide

write_drive_lba:
    mov edx,es:[edi].dh_unit
    movzx eax,fs:drive_sectors_per_unit
    mul edx
    movzx ebx,es:[edi].dh_sector
    add eax,ebx
    mov edx,eax
    mov ah,fs:drive_precomp
    call SetupLbaTaskFile
    jmp write_drive_start

write_drive_ide:
    mov edx,es:[edi].dh_unit
    mov ax,es:[edi].dh_sector
    div byte ptr fs:drive_sectors_per_cyl
    mov bh,al
    mov bl,ah
    inc bl
    mov ah,fs:drive_precomp
    call SetupIdeTaskFile

write_drive_start:
    jc write_drive_retry
;
    mov al,30h
    test fs:drive_lba_flags,LBA_48
    jz write_drive_lba_ok
;
    or al,4

write_drive_lba_ok:    
    mov dx,fs:disc_io_base
    add dx,7
    out dx,al

write_sector_loop:
    mov dx,fs:disc_io_base
    call WaitDrq
    jc write_drive_retry
;       
    mov dx,fs:disc_io_base
    push cx
    push esi
    mov esi,es:[edi].dh_data
    mov ecx,256
    rep outs word ptr dx,es:[esi]
    pop esi
    pop cx

write_sector_wait:
    push eax
    GetSystemTime
    add eax,1193 * 500
    adc edx,0
    WaitForSignalWithTimeout
    pop eax
;       
    mov dx,fs:disc_io_base
    add dx,7
    in al,dx
    test al,80h
    jnz write_sector_wait
;       
    mov dx,fs:disc_io_base
    call CheckStatus
    jnc write_drive_ok

write_drive_retry:
    sub bp,1
    jnz write_drive_retry_loop

write_drive_fail:
    int 3
    mov es:[edi].dh_state,STATE_BAD
    mov bx,fs:disc_sel
    DiscRequestCompleted
;       
    mov bp,3
    add esi,4
    mov edi,es:[esi]
    sub cx,1
    jnz write_drive_retry_loop
    jmp write_drive_done

write_drive_ok:
    mov es:[edi].dh_state,STATE_USED
    mov bx,fs:disc_sel
    DiscRequestCompleted
;
    add esi,4
    mov edi,es:[esi]
    sub cx,1
    jnz write_sector_loop

write_drive_done:
    LeaveSection ds:IdeSection
    ret
write_drive     Endp

    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       perform_one
;
;       DESCRIPTION:    Perform one request
;
;       PARAMETERS:     FS      Disc selector
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

perform_one     Proc near

perform_one_loop:
    mov ecx,255
    GetDiscRequestArray
    jc perform_one_done
;
    mov edi,es:[esi]
    mov al,es:[edi].dh_state
    cmp al,STATE_EMPTY
    je perform_one_read
;
    cmp al,STATE_DIRTY
    je perform_one_write
;
    cmp al,STATE_SEQ
    jne perform_one_done

perform_one_write:
    call write_drive
    jmp perform_one_loop

perform_one_read:
    call read_drive
    jmp perform_one_loop

perform_one_done:
    ret
perform_one     Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       DISCBUF_THREAD
;
;       DESCRIPTION:    Thread to handle disc buffer queue
;
;       PARAMETERS:     FS      Disc handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

discbuf_thread:
    AddThreadInt
    mov ax,flat_sel
    mov es,ax
;
    GetThread
    mov fs:disc_thread,ax
    mov bx,fs:disc_sel
    mov ds,fs:disc_ide_sel

discbuf_thread_loop:
    WaitForDiscRequest
    call perform_one
    jmp discbuf_thread_loop


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       INSTALL_TIMEOUT1
;
;       DESCRIPTION:    Install unit timeout
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

install_timeout1    Proc far
    push ds
    push ax
    push bx
;
    mov ax,ide_data_sel1
    mov ds,ax
    mov bx,ds:IdeThread
    Signal
;
    pop bx
    pop ax
    pop ds
    retf32
install_timeout1    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       INSTALL_TIMEOUT2
;
;       DESCRIPTION:    Install unit timeout
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

install_timeout2    Proc far
    push ds
    push ax
    push bx
;
    mov ax,ide_data_sel2
    mov ds,ax
    mov bx,ds:IdeThread
    Signal
;
    pop bx
    pop ax
    pop ds
    retf32
install_timeout2    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       INSTALL_UNIT
;
;       DESCRIPTION:    Install a unit
;
;       PARAMETERS:     AL      UNIT #
;           DX      IO BASE
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

disc0   DB 'Ide Drive 0',0
disc1   DB 'Ide Drive 1',0
disc2   DB 'Ide Drive 2',0
disc3   DB 'Ide Drive 3',0

disc_name_tab1:
dnt100  DW OFFSET disc0
dnt101  DW OFFSET disc1

disc_name_tab2:
dnt200  DW OFFSET disc2
dnt201  DW OFFSET disc3

install_unit    Proc near
    mov ds:IntFlag,0
    ClearSignal
    call CheckReady
    jc install_unit_done
;
    cmp dx,1F0h
    je inst_timeout_primary
;       
    mov edi,OFFSET install_timeout2
    jmp inst_timeout_start

inst_timeout_primary:   
    mov edi,OFFSET install_timeout1

inst_timeout_start:
    push ax
    push dx
    GetSystemTime
    add eax,119300
    adc edx,0
    mov bx,cs
    mov es,bx
    mov bx,cs
    StartTimer
    pop dx
    pop ax
;
    push ax
;
    push dx
    add dx,6
    shl al,4
    or al,0A0h
    out dx,al
    inc dx
;
    jmp short $+2
    mov al,0ECh
    out dx,al
    pop dx
;
    WaitForSignal
    StopTimer
    pop ax
;
    push ax
    mov cx,256
    
install_unit_read:
    in ax,dx
    loop install_unit_read
;
    mov al,ds:IntFlag
    or al,al
    stc
    jz install_unit_check_done
;       
    call CheckStatus

install_unit_check_done:
    pop ax
    jc install_unit_done
;
    push ax
    mov eax,SIZE drive_data
    AllocateSmallGlobalMem
    mov ax,es
    mov fs,ax
    pop ax
;
    mov fs:disc_sub_unit,al
    mov fs:disc_io_base,dx
    call GetDriveParams
    jnc install_unit_ok
;
    xor ax,ax
    mov fs,ax
    FreeMem
    stc
    jmp install_unit_done

install_unit_ok:
    movzx bx,al
    shl bx,1
    mov ds:[bx].DriveSelArr,fs
;
    mov ecx,10000h
    mov bx,fs
    InstallDisc
    mov fs:disc_sel,bx
    mov fs:disc_nr,al
    mov fs:disc_ide_sel,ds
;
    call CalcParam
    mov ax,fs:drive_sectors_per_unit
    movzx edx,fs:drive_units
    mov cx,512
    mov si,fs:drive_sectors_per_cyl
    mov di,fs:drive_heads
    mov bx,fs:disc_sel
    SetDiscParam
;
    GetDiscVendorInfoBuf
    mov al,'I'
    stosb
    mov al,'D'
    stosb
    mov al,'E'
    stosb
    mov al,':'
    stosb
    mov cx,10
    mov si,OFFSET disc_model
    rep movs dword ptr es:[di],fs:[si]
;
    push ds
    mov ax,cs
    mov ds,ax
    mov es,ax
    movzx di,fs:disc_sub_unit
    add di,di
    mov dx,fs:disc_io_base
    cmp dx,1F0h
    je install_primary
;       
    mov di,word ptr cs:[di].disc_name_tab2
    jmp install_cr_thread

install_primary:    
    mov di,word ptr cs:[di].disc_name_tab1

install_cr_thread:
    mov si,OFFSET discbuf_thread
    mov ax,2
    mov cx,stack0_size
    CreateThread
    pop ds
    clc

install_unit_done:
    ret
install_unit    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       INSTALL_PCI_TIMEOUT
;
;       DESCRIPTION:    Install unit timeout
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

install_pci_timeout    Proc far
    push ds
    push ax
    push bx
;
    mov ax,SEG data
    mov ds,ax
    mov bx,ds:pci_thread
    Signal
;
    pop bx
    pop ax
    pop ds
    retf32
install_pci_timeout    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       INSTALL_PCI_UNIT
;
;       DESCRIPTION:    Install a PCI unit
;
;       PARAMETERS:     AL      UNIT #
;                       DX      IO BASE
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

install_pci_unit    Proc near
    push es
    pushad
;    
    mov di,es:pci_unit_ptr
    push ax
    add al,'0'
    mov es:[di],al
    pop ax
;    
    mov ds:IntFlag,0
    ClearSignal
    call CheckReady
    jc install_pci_unit_done
;
    push ax
    push dx
;
    GetThread
    mov ds:IdeThread,ax
    mov ds:IdeIoBase,dx
;    
    GetSystemTime
    add eax,119300
    adc edx,0
    mov bx,cs
    mov es,bx
    mov bx,cs
    mov edi,OFFSET install_pci_timeout
    StartTimer
;    
    pop dx
    pop ax
;
    push ax
;
    push dx
    add dx,6
    shl al,4
    or al,0A0h
    out dx,al
    inc dx
;
    jmp short $+2
    mov al,0ECh
    out dx,al
    pop dx
;
    WaitForSignal
    StopTimer
    pop ax
;
    push ax
    mov cx,256
    
install_pci_unit_read:
    in ax,dx
    loop install_pci_unit_read
;
    mov al,ds:IntFlag
    or al,al
    stc
    jz install_pci_unit_check_done
;       
    call CheckStatus

install_pci_unit_check_done:
    pop ax
    jc install_pci_unit_done
;
    push ax
    mov eax,SIZE drive_data
    AllocateSmallGlobalMem
    mov ax,es
    mov fs,ax
    pop ax
;
    mov fs:disc_sub_unit,al
    mov fs:disc_io_base,dx
    call GetDriveParams
    jnc install_pci_unit_ok
;
    xor ax,ax
    mov fs,ax
    FreeMem
    stc
    jmp install_pci_unit_done

install_pci_unit_ok:
    movzx bx,al
    shl bx,1
    mov ds:[bx].DriveSelArr,fs
;
    mov ecx,10000h
    mov bx,fs
    InstallDisc
    mov fs:disc_sel,bx
    mov fs:disc_nr,al
    mov fs:disc_ide_sel,ds
;
    call CalcParam
    mov ax,fs:drive_sectors_per_unit
    movzx edx,fs:drive_units
    mov cx,512
    mov si,fs:drive_sectors_per_cyl
    mov di,fs:drive_heads
    mov bx,fs:disc_sel
    SetDiscParam
;
    push ds
    mov ax,cs
    mov ds,ax
;
    mov ax,SEG data    
    mov es,ax
    mov di,OFFSET pci_name_str
    mov si,OFFSET discbuf_thread
    mov ax,2
    mov cx,stack0_size
    CreateThread
    pop ds
    clc

install_pci_unit_done:
    mov ds:IdeThread,0
;
    popad
    pop es
    ret
install_pci_unit    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       DISC_ASSIGN1
;
;       DESCRIPTION:    Assign discs on primary adapter
;
;       PARAMETERS:     
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

disc_assign1    Proc far
    mov dx,1F7h
    in al,dx
    and al,7Fh
    cmp al,7Fh
    je disc_assign1_done
;    
    mov ax,ide_data_sel1
    mov ds,ax
    GetThread
    mov ds:IdeThread,ax
;       
    mov al,0
    mov dx,1F0h
    call install_unit
;       
    mov al,1
    mov dx,1F0h
    call install_unit
    mov ds:IdeThread,0

disc_assign1_done:
    retf32
disc_assign1    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       DISC_ASSIGN2
;
;       DESCRIPTION:    Assign discs
;
;       PARAMETERS:     
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

disc_assign2    Proc far
    mov dx,177h
    in al,dx
    and al,7Fh
    cmp al,7Fh
    je disc_assign2_done
;    
    mov ax,ide_data_sel2
    mov ds,ax
    GetThread
    mov ds:IdeThread,ax
;       
    mov al,0
    mov dx,170h
    call install_unit
;       
    mov al,1
    mov dx,170h
    call install_unit
    mov ds:IdeThread,0

disc_assign2_done:
    retf32
disc_assign2    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       DISC_ASSIGN_PCI
;
;       DESCRIPTION:    Assign PCI discs
;
;       PARAMETERS:     
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

disc_pci_name   DB 'Ide Pci ',0

disc_assign_pci    Proc far
    mov ax,SEG data
    mov es,ax
    mov es:ide_pci_curr,0
    mov di,OFFSET pci_name_str
    mov si,OFFSET disc_pci_name

disc_assign_name_loop:    
    lods byte ptr cs:[si]
    stosb
    or al,al
    jnz disc_assign_name_loop
;
    dec di
    mov es:pci_curr_ptr,di
    mov al,'0'
    stosb
    mov al,':'
    stosb
    mov es:pci_unit_ptr,di
    mov al,'0'
    stosb
    xor al,al
    stosb
;
    xor bx,bx
    mov cx,es:ide_pci_count
    or cx,cx
    jz disc_assign_pci_done

disc_assign_pci_loop:    
    mov dx,es:[bx].ide_io_arr
    mov ds,es:[bx].ide_pci_arr
;    
    GetThread
    mov es:pci_thread,ax
;       
    mov al,0
    call install_pci_unit
;       
    mov al,1
    call install_pci_unit
    mov es:pci_thread,0
;
    mov di,es:pci_curr_ptr
    inc byte ptr es:[di]
;
    add bx,2
    loop disc_assign_pci_loop

disc_assign_pci_done:
    retf32
disc_assign_pci    Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       DRIVE_ASSIGN1
;
;       DESCRIPTION:    Drive assign, pass 1
;
;       PARAMETERS:     BX      Disc handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

drive_assign1   Proc far
    mov fs,bx
    mov ds,fs:disc_ide_sel
;
    mov ax,flat_sel
    mov es,ax
    mov eax,200h
    AllocateSmallLinear
    mov edi,edx
;
    mov ecx,1
    xor bx,bx
    xor edx,edx
    call ReadDrive
;
    mov esi,1BEh

drive_assign_loop1:
    mov cl,es:[esi+edi].part_type
    or cl,cl
    jz drive_assign_free1
;
    mov eax,es:[esi+edi].part_sectors
    mov edx,es:[esi+edi].part_start_sector
    call InstallPartition

drive_assign_next_part1:
    add si,10h
    cmp si,1FEh
    jne drive_assign_loop1

drive_assign_free1:
    mov ecx,200h
    mov edx,edi
    FreeLinear
;
    retf32
drive_assign1   Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       InstallExtended
;
;       DESCRIPTION:    Install extended partion on drive
;
;       PARAMETERS:     DS      IDE SEGMENT
;               ES      FLAT_SEL
;               FS      Disc sel
;               EDX     Current sector
;               EDI     200H buffer with partition sector
;               ESI     Partition offset
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

InstallExtended Proc near
    mov ebp,edx
    mov eax,200h
    AllocateSmallLinear
    mov edi,edx
;
    mov eax,ebp
    xor edx,edx
    movzx ecx,word ptr fs:drive_sectors_per_unit
    div ecx
    mov bx,dx
    mov edx,eax
;
    mov ecx,1
    call ReadDrive
;
    mov esi,1BEh

install_ext_loop1:
    mov cl,es:[esi+edi].part_type
    or cl,cl
    jz install_ext_next_part1
;
    cmp cl,5
    je install_ext_next_part1
;
    cmp cl,0Fh
    je install_ext_next_part1
;
    push ebp
    push edi
;
    mov eax,es:[esi+edi].part_sectors
    lea edi,[esi+edi+1]
    call ChsToLba
    or edx,edx
    jnz install_ext_do
;
    mov edx,es:[edi+7]
    add edx,ebp

install_ext_do:
    call InstallPartition
    pop edi
    pop ebp

install_ext_next_part1:
    add si,10h
    cmp si,1FEh
    jne install_ext_loop1
;
    mov esi,1BEh

install_ext_loop2:
    mov cl,es:[esi+edi].part_type
    or cl,cl
    jz install_ext_next_part2
;
    cmp cl,5
    je install_ext_install2
;
    cmp cl,0Fh
    jne install_ext_next_part2

install_ext_install2:
    push esi
    push edi
    push ebp
;
    lea edi,[esi+edi+1]
    call ChsToLba
    or edx,edx
    jnz install_ext_link
;
    mov edx,es:[edi+7]
    add edx,ebp

install_ext_link:
    call InstallExtended
;
    pop ebp
    pop edi
    pop esi

install_ext_next_part2:
    add si,10h
    cmp si,1FEh
    jne install_ext_loop2
;
    mov ecx,200h
    mov edx,edi
    FreeLinear
    ret
InstallExtended Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       DRIVE_ASSIGN2
;
;       DESCRIPTION:    Assign disc drives, pass 2
;
;       PARAMETERS:     BX      Disc handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

drive_assign2   Proc far
    mov ax,flat_sel
    mov es,ax
    mov fs,bx
    mov ds,fs:disc_ide_sel
;
    mov eax,200h
    AllocateSmallLinear
    mov edi,edx
;
    mov ecx,1
    xor bx,bx
    xor edx,edx
    call ReadDrive
;
    mov esi,1BEh

drive_assign_loop2:
    mov cl,es:[esi+edi].part_type
    or cl,cl
    jz drive_assign_next_part2
;
    cmp cl,5
    je drive_assign_install2
;
    cmp cl,0Fh
    jne drive_assign_next_part2

drive_assign_install2:
    push esi
    push edi
;
    lea edi,[esi+edi+1]
    call ChsToLba
    or edx,edx
    jnz drive_assign_ext
;
    mov edx,es:[edi+7]

drive_assign_ext:
    call InstallExtended
;
    pop edi
    pop esi

drive_assign_next_part2:
    add si,10h
    cmp si,1FEh
    jne drive_assign_loop2
;
    mov ecx,200h
    mov edx,edi
    FreeLinear
;
    mov bx,fs:disc_sel
    StartDisc
    clc
    retf32
drive_assign2   Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       DEMAND_MOUNT
;
;       DESCRIPTION:    Mount disc drive on demand
;
;       PARAMETERS:     BX      Disc handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

demand_mount    Proc far
    retf32
demand_mount    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       ERASE
;
;       DESCRIPTION:    Erase sectors
;
;       PARAMETERS:     BX      Disc handle
;           EDX     Start sector
;           ECX     Number of sectors
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

erase   Proc far
    stc
    retf32
erase   Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       GetIdeDisc
;
;       description:    Get disc # for a physical disc unit
;
;       PARAMETERS:     BL      IDE disc #
;
;       RETURNS:    AL      disc #
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

get_ide_disc_name DB 'Get IDE Disc',0

get_ide_disc    Proc far
    push ds
    push bx
;
    cmp bl,2
    jae get_ide_second
;    
    mov ax,ide_data_sel1
    verr ax
    jnz get_ide_fail
;
    mov ds,ax
    movzx bx,bl
    add bx,bx
    mov bx,ds:[bx].DriveSelArr
    or bx,bx
    jz get_ide_fail
;
    mov ds,bx
    mov al,ds:disc_nr
    clc
    jmp get_ide_done

get_ide_second:
    sub bl,2
    cmp bl,4
    jae get_ide_pci
;    
    mov ax,ide_data_sel2
    verr ax
    jnz get_ide_fail
;
    mov ds,ax
    movzx bx,bl
    add bx,bx
    mov bx,ds:[bx].DriveSelArr
    or bx,bx
    jz get_ide_fail
;
    mov ds,bx
    mov al,ds:disc_nr
    clc
    jmp get_ide_done

get_ide_pci:
    sub bl,2
    push cx
    push si
;    
    mov ax,SEG data
    mov ds,ax
    mov cx,ds:ide_pci_count
    or cx,cx
    jz get_ide_pci_fail
;    
    mov si,OFFSET ide_pci_arr

get_ide_pci_loop:
    cmp bl,2
    jb get_ide_pci_check
;
    sub bl,2
    add si,2
    sub cx,1
    jnz get_ide_pci_loop

get_ide_pci_fail:
    stc
    jmp get_ide_pci_done

get_ide_pci_check:
    mov ds,ds:[si]
    movzx bx,bl
    add bx,bx
    mov bx,ds:[bx].DriveSelArr
    or bx,bx
    jz get_ide_pci_fail
;
    mov ds,bx
    mov al,ds:disc_nr
    clc
        
get_ide_pci_done:
    pop si
    pop cx    
    jmp get_ide_done

get_ide_fail:
    stc
    
get_ide_done:    
    pop bx
    pop ds    
    retf32
get_ide_disc    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:       INIT
;
;       DESCRIPTION:    Init device
;
;       PARAMETERS:     
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

disc_ctrl1:
dct100  DD OFFSET disc_assign1,     SEG code
dct101  DD OFFSET drive_assign1,    SEG code
dct102  DD OFFSET drive_assign2,    SEG code
dct103  DD OFFSET demand_mount,     SEG code
dct104  DD OFFSET erase,            SEG code

disc_ctrl2:
dct200  DD OFFSET disc_assign2,     SEG code
dct201  DD OFFSET drive_assign1,    SEG code
dct202  DD OFFSET drive_assign2,    SEG code
dct203  DD OFFSET demand_mount,     SEG code
dct204  DD OFFSET erase,            SEG code

disc_ctrl_pci:
dcp200  DD OFFSET disc_assign_pci,  SEG code
dcp201  DD OFFSET drive_assign1,    SEG code
dcp202  DD OFFSET drive_assign2,    SEG code
dcp203  DD OFFSET demand_mount,     SEG code
dcp204  DD OFFSET erase,            SEG code


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           CheckPciBar
;
;           DESCRIPTION:    Check single PCI bar for valid IDE drive
;
;       PARAMETERS:         SI      IO port
;                           AL      IRQ
;
;           RETURNS:        
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckPciBar    Proc near
    or si,si
    stc
    jz cpbDone
;    
    push ax
    push dx
    mov dx,si
    add dx,7
    in al,dx
    pop dx
    and al,7Fh
    jz cpbFailPop
;    
    cmp al,7Fh
    jne cpbOk

cpbFailPop:    
    stc
    pop ax
    jmp cpbDone

cpbOk:
    pop ax
;    
    mov di,es:ide_pci_count
    add di,di
    mov es:[di].ide_io_arr,si
;
    push ds
    push es
    push ax    
    mov eax,SIZE ide_data
    AllocateSmallGlobalMem
    mov ax,es
    mov ds,ax
    InitSection ds:IdeSection
    pop ax
    pop es
;       
    mov ds:IdeThread,0
    mov ds:IdeIoBase,0
    mov ds:DriveSelArr,0
    mov ds:DriveSelArr+2,0
    mov es:[di].ide_pci_arr,ds
;
    push es
    push bx
;    
    mov ah,12h
    mov bx,cs
    mov es,bx
    mov edi,OFFSET ide_pci_int
    RequestIrqHandler
;
    pop bx
    pop es
    pop ds
;
    inc es:ide_pci_count
    clc

cpbDone:
    ret
CheckPciBar Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           CheckPciIde
;
;           DESCRIPTION:    Check for PCI IDE devices
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckPciIde Proc near
    xor ax,ax
    mov bh,1
    mov bl,1
    FindPciClassAll
    jc cpiDone
;
    mov cl,10h
    ReadPciDword
    mov cl,al    
    and ax,0FFFCh
    mov bp,ax
;    
    cmp ax,1F0h
    je cpiBar1Done
;    
    test cl,1
    jz cpiBar1Done
;
    mov si,ax
    GetPciIrqNr
    jc cpiBar1Done
;
    call CheckPciBar

cpiBar1Done:
    mov cl,18h
    ReadPciDword
    mov cl,al    
    and ax,0FFFCh
;    
    cmp ax,170h
    je cpiBar3Done
;    
    test cl,1
    jz cpiBar3Done
;
    mov si,ax
    GetPciIrqNr
    jc cpiBar3Done
;    
    call CheckPciBar

cpiBar3Done:
    mov dx,1

cpiLoop:
    mov ax,dx
    mov bh,1
    mov bl,1
    FindPciClassAll
    jc cpiDone
;   
    mov cl,10h
    ReadPciDword
    mov cl,al
    and ax,0FFFCh
    cmp ax,bp
    je cpiDone
;    
    cmp es:ide_pci_count,MAX_PCI_COUNT
    je cpiDone
;    
    cmp ax,1F0h
    je cpiNextBar1Done
;       
    test cl,1
    jz cpiNextBar1Done
;
    mov si,ax
    GetPciIrqNr
    jc cpiNextBar1Done
;    
    call CheckPciBar    

cpiNextBar1Done:
    mov cl,18h
    ReadPciDword
    mov cl,al
    and ax,0FFFCh
;       
    test cl,1
    jz cpiNextBar3Done
;    
    cmp ax,170h
    je cpiNextBar3Done
;
    mov si,ax
    GetPciIrqNr
    jc cpiNextBar3Done
;    
    call CheckPciBar

cpiNextBar3Done:    
    inc dx
    jmp cpiLoop
    
cpiDone:
    ret
CheckPciIde Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           CheckPciSata
;
;           DESCRIPTION:    Check for PCI SATA devices
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckPciSata Proc near
    xor ax,ax
    mov bh,1
    mov bl,6
    FindPciClassAll
    jc cpaDone
;
    mov cl,10h
    ReadPciDword
    mov cl,al    
    and ax,0FFFCh
    mov bp,ax
;    
    cmp ax,1F0h
    je cpaBar1Done
;    
    test cl,1
    jz cpaBar1Done
;
    mov si,ax
    GetPciIrqNr
    jc cpaBar1Done
;    
    call CheckPciBar

cpaBar1Done:
    mov cl,18h
    ReadPciDword
    mov cl,al    
    and ax,0FFFCh
;    
    cmp ax,170h
    je cpaBar3Done
;    
    test cl,1
    jz cpaBar3Done
;
    mov si,ax
    GetPciIrqNr
    jc cpaBar3Done
;    
    call CheckPciBar

cpaBar3Done:
    mov dx,1

cpaLoop:
    mov ax,dx
    mov bh,1
    mov bl,6
    FindPciClassAll
    jc cpaDone
;   
    mov cl,10h
    ReadPciDword
    mov cl,al
    and ax,0FFFCh
    cmp ax,bp
    je cpaDone
;    
    cmp es:ide_pci_count,MAX_PCI_COUNT
    je cpaDone
;    
    cmp ax,1F0h
    je cpaNextBar1Done
;       
    test cl,1
    jz cpaNextBar1Done
;
    mov si,ax
    GetPciIrqNr
    jc cpaNextBar1Done
;    
    call CheckPciBar    

cpaNextBar1Done:
    mov cl,18h
    ReadPciDword
    mov cl,al
    and ax,0FFFCh
;       
    test cl,1
    jz cpaNextBar3Done
;    
    cmp ax,170h
    je cpaNextBar3Done
;
    mov si,ax
    GetPciIrqNr
    jc cpaNextBar3Done
;    
    call CheckPciBar

cpaNextBar3Done:    
    inc dx
    jmp cpaLoop
    
cpaDone:
    ret
CheckPciSata Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           Init_ide
;
;           DESCRIPTION:    inits adpater
;
;       PARAMETERS:     
;
;           RETURNS:        
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

init_ide    Proc far
    push ds
    push es
    pusha
;
    xor bp,bp
    mov ax,cs
    mov ds,ax
    mov es,ax

init_ide_primary:
    mov dx,1F7h
    in al,dx
    and al,7Fh
    cmp al,7Fh
    je init_ide_second
;
    inc bp
    mov edi,OFFSET disc_ctrl1
    HookInitDisc
;
    mov eax,SIZE ide_data
    mov bx,ide_data_sel1
    AllocateFixedSystemMem
    mov ax,es
    mov ds,ax
    InitSection ds:IdeSection
;       
    mov ds:IdeThread,0
    mov ds:IdeIoBase,0
    mov ds:DriveSelArr,0
    mov ds:DriveSelArr+2,0
;
    mov al,0Eh
    mov ah,12h
    mov bx,ide_data_sel1
    mov ds,bx
    mov bx,cs
    mov es,bx
    mov edi,OFFSET ide_int
    RequestIrqHandler

init_ide_second:
    mov dx,177h
    in al,dx
    and al,7Fh
    cmp al,7Fh
    je init_ide_done
;
    inc bp
    mov edi,OFFSET disc_ctrl2
    HookInitDisc
;
    mov eax,SIZE ide_data
    mov bx,ide_data_sel2
    AllocateFixedSystemMem
    mov ax,es
    mov ds,ax
    InitSection ds:IdeSection
    mov ds:IdeThread,0
    mov ds:IdeIoBase,0
    mov ds:DriveSelArr,0
    mov ds:DriveSelArr+2,0
;
    mov al,0Fh
    mov ah,12h
    mov bx,ide_data_sel2
    mov ds,bx
    mov bx,cs
    mov es,bx
    mov edi,OFFSET ide_int
    RequestIrqHandler

init_ide_done:
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov esi,OFFSET get_ide_disc
    mov edi,OFFSET get_ide_disc_name
    xor dx,dx
    mov ax,get_ide_disc_nr
    RegisterBimodalUserGate

init_ide_pci:
    mov ax,SEG data
    mov es,ax
    mov es:ide_pci_count,0
;
    call CheckPciIde
    mov ax,ahci_code_sel
    verr ax
    jz init_ide_check_count
;
    call CheckPciSata

init_ide_check_count:    
    mov cx,es:ide_pci_count
    or cx,cx
    jz init_ide_exit
;    
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov edi,OFFSET disc_ctrl_pci
    HookInitDisc

init_ide_exit:
    EndDiscHandler
;
    popa
    pop es
    pop ds
    retf32
init_ide    Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           Init_net
;
;           DESCRIPTION:    inits adpater
;
;       PARAMETERS:     
;
;           RETURNS:        
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

init    PROC far
    BeginDiscHandler
;
    mov ax,cs
    mov es,ax
    mov edi,OFFSET init_ide
    HookInitPci
    clc
    ret
init    ENDP

code    ENDS

    END init