cd_drv.inc
mxlgv_KolibriDev/src/kernel/blkdev/cd_drv.inc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision: 8054 $

;-----------------------------------------------------------------------------
;**********************************************************
;  Direct work with CD (ATAPI) device
;**********************************************************
; Author of a part of the source code -  Kulakov Vladimir Gennadievich
; Adaptation, revision and development -  Mario79, <Lrz>

; Maximum number of repeats of a read operation
MaxRetr = 10
; Maximum waiting time for ready to receive a command
; (in ticks)
BSYWaitTime = 1000  ;2
NoTickWaitTime = 0xfffff
CDBlockSize = 2048
;********************************************
;*        READING SECTOR WITH REPEATS       *
;*      Repeated reads on failures          *
;********************************************
ReadCDWRetr:
;-----------------------------------------------------------
; input  : eax = block to read
;          ebx = destination
;-----------------------------------------------------------
        pushad
        mov     eax, [CDSectorAddress]
        mov     ebx, [CDDataBuf_pointer]
        call    cd_calculate_cache
        xor     edi, edi
        add     esi, 8
        inc     edi
;--------------------------------------
align 4
.hdreadcache:
        cmp     [esi], eax      ; correct sector
        je      .yeshdcache

        add     esi, 8
        inc     edi
        dec     ecx
        jnz     .hdreadcache

        call    find_empty_slot_CD_cache ; ret in edi

        push    edi
        push    eax
        call    cd_calculate_cache_2
        shl     edi, 11
        add     edi, eax
        mov     [CDDataBuf_pointer], edi
        pop     eax
        pop     edi

        call    ReadCDWRetr_1
        cmp     [DevErrorCode], 0
        jne     .exit

        mov     [CDDataBuf_pointer], ebx
        call    cd_calculate_cache_1
        lea     esi, [edi*8+esi]
        mov     [esi], eax      ; sector number
;--------------------------------------
.yeshdcache:
        mov     esi, edi
        shl     esi, 11 ;9
        push    eax
        call    cd_calculate_cache_2
        add     esi, eax
        pop     eax
        mov     edi, ebx ;[CDDataBuf_pointer]
        mov     ecx, 512 ;/4
        cld
        rep movsd               ; move data
;--------------------------------------
.exit:
        popad
        ret
;-----------------------------------------------------------------------------
ReadCDWRetr_1:
        pushad
; Loop until the command is successful or the number of attempts is over
        mov     ecx, MaxRetr
;--------------------------------------
align 4
@@NextRetr:
; Send a command
;*************************************************
;*      FULL READ OF COMPACT DISK SECTOR         *
;* User data, subchannel                         *
;* information and control information are read  *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disc number on channel;          *
;* CDSectorAddress - address of reading sector.  *
;* The data is read into the CDDataBuf array.    *
;*************************************************
;ReadCD:
        push    ecx
; Flush the packet command buffer
        call    clear_packet_buffer
; Generate a packet command to read a data sector
; Set the command code Read CD
        mov     [PacketCommand], byte 0x28 ;0xBE
; Set the sector address
        mov     ax, word [CDSectorAddress+2]
        xchg    al, ah
        mov     word [PacketCommand+2], ax
        mov     ax, word [CDSectorAddress]
        xchg    al, ah
        mov     word [PacketCommand+4], ax
; Set the number of sectors to read
        mov     [PacketCommand+8], byte 1
; Send a command
        call    SendPacketDatCommand
        pop     ecx

        test    eax, eax
        jz      @@End_4

        or      ecx, ecx        ;{SPraid.simba} (for cd load)
        jz      @@End_4

        dec     ecx

        cmp     [timer_ticks_enable], 0
        jne     @f

        mov     eax, NoTickWaitTime
;--------------------------------------
align 4
.wait:
        dec     eax
        jz      @@NextRetr

        jmp     .wait
;--------------------------------------
align 4
@@:
        loop    @@NextRetr
;--------------------------------------
@@End_4:
        mov     dword [DevErrorCode], eax
        popad
        ret
;-----------------------------------------------------------------------------
; General purpose procedures to execute packet commands in PIO Mode
; Maximum allowable waiting time for the device to respond to a packet command (in ticks)
;-----------------------------------------------------------------------------
MaxCDWaitTime = 1000 ;200 ;10 seconds
uglobal
; Memory area for generating a packet command
PacketCommand:
                 rb 12  ;DB 12 DUP (?)
; address of reading data sector
CDSectorAddress:   dd ?
; Start time of the next disk operation
TickCounter_1     dd 0
; Time to start waiting for device readiness
WURStartTime      dd 0
; pointer to buffer to read data into
CDDataBuf_pointer dd 0
endg
;-----------------------------------------------------------------------------
;****************************************************
;*    SEND TO ATAPI DEVICE PACKET COMMAND,          *
;* THAT MEANS TRASMIT ONE DATA SECTOR OF SIZE       *
;*     2048 BYTE FROM DEVICE TO HOST                *
;* Input parameters are passed through global       *
;* variables:                                       *
;* ChannelNumber - channel number;                  *
;* DiskNumber - disk number on channel.             *
;* PacketCommand - 12-byte command packet;          *
;* CDBlockSize - size of receiving data block.      *
; return eax DevErrorCode
;****************************************************
SendPacketDatCommand:
        xor     eax, eax
; Set CHS mode
        mov     byte [ATAAddressMode], al
; Send ATA command to send packet command
        mov     byte [ATAFeatures], al
        mov     byte [ATASectorCount], al
        mov     byte [ATASectorNumber], al
; Load the size of the sending block
        mov     [ATAHead], al
        mov     [ATACylinder], CDBlockSize
        mov     [ATACommand], 0xA0
        call    SendCommandToHDD_1
        test    eax, eax
        jnz     @@End_8    ; finish, saving the error code
; Waiting for the drive to be ready to receive a packet command
        mov     dx, [ATABasePortAddr]
        add     dx, 7    ; port 1x7h
        mov     ecx, NoTickWaitTime
;--------------------------------------
align 4
@@WaitDevice0:
        cmp     [timer_ticks_enable], 0
        jne     @f

        dec     ecx
        jz      @@Err1_1

        jmp     .test
;--------------------------------------
align 4
@@:
        call    change_task
        ; Check command execution time
        mov     eax, [timer_ticks]
        sub     eax, [TickCounter_1]
        cmp     eax, BSYWaitTime
        ja      @@Err1_1   ; time out error
        ; Check readiness
;--------------------------------------
align 4
.test:
        in      al, dx
        test    al, 0x80  ; BSY signal state
        jnz     @@WaitDevice0

        test    al, 1     ; ERR signal state
        jnz     @@Err6

        test    al, 0x8   ; DRQ signal state
        jz      @@WaitDevice0
; Send a packet command
        cli
        mov     dx, [ATABasePortAddr]
        mov     ax, [PacketCommand]
        out     dx, ax
        mov     ax, [PacketCommand+2]
        out     dx, ax
        mov     ax, [PacketCommand+4]
        out     dx, ax
        mov     ax, [PacketCommand+6]
        out     dx, ax
        mov     ax, [PacketCommand+8]
        out     dx, ax
        mov     ax, [PacketCommand+10]
        out     dx, ax
        sti
; Waiting for data to be ready
        mov     dx, [ATABasePortAddr]
        add     dx, 7  ; port 1x7h
        mov     ecx, NoTickWaitTime
;--------------------------------------
align 4
@@WaitDevice1:
        cmp     [timer_ticks_enable], 0
        jne     @f

        dec     ecx
        jz      @@Err1_1

        jmp     .test_1
;--------------------------------------
align 4
@@:
        call    change_task
        ; Check command execution time
        mov     eax, [timer_ticks]
        sub     eax, [TickCounter_1]
        cmp     eax, MaxCDWaitTime
        ja      @@Err1_1   ; time out error
        ; Check readiness
;--------------------------------------
align 4
.test_1:
        in      al, dx
        test    al, 0x80  ; BSY signal state
        jnz     @@WaitDevice1

        test    al, 1    ; ERR signal state
        jnz     @@Err6_temp

        test    al, 0x8  ; DRQ signal state
        jz      @@WaitDevice1
; Receive data block from controller
        mov     edi, [CDDataBuf_pointer]
        ; Load controller's data register address
        mov     dx, [ATABasePortAddr]
        ; Load the block size in bytes into the counter
        xor     ecx, ecx
        mov     cx, CDBlockSize
        ; Calculate block size in 16-bit words
        shr     cx, 1 ; divide block size by 2
        ; Receive data block
        cli
        cld
        rep insw
        sti
;--------------------------------------
; Successful completion of data receive
@@End_8:
        xor     eax, eax
        ret
;--------------------------------------
; Write error code
@@Err1_1:
        xor     eax, eax
        inc     eax
        ret
;--------------------------------------
@@Err6_temp:
        mov     eax, 7
        ret
;--------------------------------------
@@Err6:
        mov     eax, 6
        ret
;-----------------------------------------------------------------------------
;***********************************************
;*  SEND TO ATAPI DEVICE PACKET COMMAND,       *
;*     THAT DOESNT MEAN TRANSMIT DATA          *
;* Input parameters are passed through global  *
;* variables:                                  *
;* ChannelNumber - channel number;             *
;* DiskNumber - disk number on channel.        *
;* PacketCommand - 12-byte command packet.     *
;***********************************************
SendPacketNoDatCommand:
        pushad
        xor     eax, eax
; Set CHS mode
        mov     byte [ATAAddressMode], al
; Send ATA command to send packet command
        mov     byte [ATAFeatures], al
        mov     byte [ATASectorCount], al
        mov     byte [ATASectorNumber], al
        mov     word [ATACylinder], ax
        mov     byte [ATAHead], al
        mov     [ATACommand], 0xA0
        call    SendCommandToHDD_1
        test    eax, eax
        jnz     @@End_9  ; finish, saving the error code
; Waiting for the drive to be ready to receive a packet command
        mov     dx, [ATABasePortAddr]
        add     dx, 7  ; port 1x7h
;--------------------------------------
align 4
@@WaitDevice0_1:
        call    change_task
        ; Check waiting time
        mov     eax, [timer_ticks]
        sub     eax, [TickCounter_1]
        cmp     eax, BSYWaitTime
        ja      @@Err1_3  ; time out error
        ; Check readiness
        in      al, dx
        test    al, 0x80  ; BSY signal state
        jnz     @@WaitDevice0_1

        test    al, 1     ; ERR signal state
        jnz     @@Err6_1

        test    al, 0x8   ; DRQ signal state
        jz      @@WaitDevice0_1
; Send packet command
;        cli
        mov     dx, [ATABasePortAddr]
        mov     ax, word [PacketCommand]
        out     dx, ax
        mov     ax, word [PacketCommand+2]
        out     dx, ax
        mov     ax, word [PacketCommand+4]
        out     dx, ax
        mov     ax, word [PacketCommand+6]
        out     dx, ax
        mov     ax, word [PacketCommand+8]
        out     dx, ax
        mov     ax, word [PacketCommand+10]
        out     dx, ax
;        sti
        cmp     [ignore_CD_eject_wait], 1
        je      @@clear_DEC
; Waiting for confirmation of command receive
        mov     dx, [ATABasePortAddr]
        add     dx, 7  ; port 1x7h
;--------------------------------------
align 4
@@WaitDevice1_1:
        call    change_task
        ; Check command execution time
        mov     eax, [timer_ticks]
        sub     eax, [TickCounter_1]
        cmp     eax, MaxCDWaitTime
        ja      @@Err1_3   ; time out error
        ; Wait for device release
        in      al, dx
        test    al, 0x80   ; BSY signal state
        jnz     @@WaitDevice1_1

        test    al, 1      ; ERR signal state
        jnz     @@Err6_1

        test    al, 0x40   ; DRDY signal state
        jz      @@WaitDevice1_1
;--------------------------------------
@@clear_DEC:
        and     [DevErrorCode], 0
        popad
        ret
;--------------------------------------
; Write error code
@@Err1_3:
        xor     eax, eax
        inc     eax
        jmp     @@End_9
;--------------------------------------
@@Err6_1:
        mov     eax, 6
;--------------------------------------
@@End_9:
        mov     [DevErrorCode], eax
        popad
        ret
;-----------------------------------------------------------------------------
;****************************************************
;*          SEND COMMAND TO GIVEN DISK              *
;* Input parameters are passed through the global   *
;* variables:                                       *
;* ChannelNumber - channel number (1 or 2);         *
;* DiskNumber - disk number (0 or 1);               *
;* ATAFeatures - "features";                        *
;* ATASectorCount - sector count;                   *
;* ATASectorNumber - initial sector number;         *
;* ATACylinder - initial cylinder number;           *
;* ATAHead - initial head number;                   *
;* ATAAddressMode - addressing mode (0-CHS, 1-LBA); *
;* ATACommand - command code.                       *
;* If the function finished successfully:           *
;* in ATABasePortAddr - base address of HDD;        *
;* in DevErrorCode - zero.                          *
;* If error has occured then in DevErrorCode will   *
;* be the error code.                               *
;****************************************************
SendCommandToHDD_1:
; Check the addressing mode code
        cmp     [ATAAddressMode], 1
        ja      @@Err2_4
; Check the channel number correctness
        movzx   ebx, [ChannelNumber]
        dec     ebx
        cmp     ebx, 1
        ja      @@Err3_4
; Set the base address
        shl     ebx, 2
        mov     eax, [cdpos]
        dec     eax
        shr     eax, 2
        imul    eax, sizeof.IDE_DATA
        add     eax, IDE_controller_1
        add     eax, ebx
        mov     ax, [eax+IDE_DATA.BAR0_val]
        mov     [ATABasePortAddr], ax
; Waiting for HDD ready to receive a command
        ; Choose desired disk
        mov     dx, [ATABasePortAddr]
        add     dx, 6   ; address of the heads register
        mov     al, [DiskNumber]
        cmp     al, 1   ; check the disk number
        ja      @@Err4_4

        shl     al, 4
        or      al, 10100000b
        out     dx, al
        ; Waiting for disk ready
        inc     dx
        mov     eax, [timer_ticks]
        mov     [TickCounter_1], eax
        mov     ecx, NoTickWaitTime
;--------------------------------------
align 4
@@WaitHDReady_2:
        cmp     [timer_ticks_enable], 0
        jne     @f

        dec     ecx
        jz      @@Err1_4

        jmp     .test
;--------------------------------------
align 4
@@:
        call    change_task
        ; Check waiting time
        mov     eax, [timer_ticks]
        sub     eax, [TickCounter_1]
        cmp     eax, BSYWaitTime ;300    ; wait for 3 seconds
        ja      @@Err1_4   ; time out error
;--------------------------------------
align 4
.test:
        in      al, dx ; Read the state register
        ; Check the state of BSY signal
        test    al, 0x80
        jnz     @@WaitHDReady_2
        ; Check the state of DRQ signal
        test    al, 0x8
        jnz     @@WaitHDReady_2
; load command to controller's registers
        cli
        mov     dx, [ATABasePortAddr]
        inc     dx      ; "features" register
        mov     al, [ATAFeatures]
        out     dx, al
        inc     dx      ; sector counter
        mov     al, [ATASectorCount]
        out     dx, al
        inc     dx      ; sector number register
        mov     al, [ATASectorNumber]
        out     dx, al
        inc     dx      ; cylinder number (low byte)
        mov     ax, [ATACylinder]
        out     dx, al
        inc     dx      ; cylinder number (high byte)
        mov     al, ah
        out     dx, al
        inc     dx      ; head number / disk number
        mov     al, [DiskNumber]
        shl     al, 4
        cmp     [ATAHead], 0xF ; check head number
        ja      @@Err5_4

        or      al, [ATAHead]
        or      al, 10100000b
        mov     ah, [ATAAddressMode]
        shl     ah, 6
        or      al, ah
        out     dx, al
; Send command
        mov     al, [ATACommand]
        inc     dx      ; command register
        out     dx, al
        sti
;--------------------------------------
@@End_10:
        xor     eax, eax
        ret
;--------------------------------------
; Write error code
@@Err1_4:
        xor     eax, eax
        inc     eax
        ret
;--------------------------------------
@@Err2_4:
        mov     eax, 2
        ret
;--------------------------------------
@@Err3_4:
        mov     eax, 3
        ret
;--------------------------------------
@@Err4_4:
        mov     eax, 4
        ret
;--------------------------------------
@@Err5_4:
        mov     eax, 5
        ret
;-----------------------------------------------------------------------------
;*************************************************
;*    WAIT FOR THE DEVICE IS READY FOR WORK      *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel.          *
;*************************************************
WaitUnitReady:
        pusha
; Remember the peration start time
        mov     eax, [timer_ticks]
        mov     [WURStartTime], eax
; Clear the packet command buffer
        call    clear_packet_buffer
; Generate TEST UNIT READY command
        mov     [PacketCommand], word 0
; waiting loop for device readiness
        mov     ecx, NoTickWaitTime
;--------------------------------------
align 4
@@SendCommand:
        ; Send readiness check command
        call    SendPacketNoDatCommand
        cmp     [timer_ticks_enable], 0
        jne     @f

        cmp     [DevErrorCode], 0
        je      @@End_11

        dec     ecx
        jz      .Error

        jmp     @@SendCommand
;--------------------------------------
align 4
@@:
        call    change_task
        ; Check the error code
        cmp     [DevErrorCode], 0
        je      @@End_11
        ; Check waiting time
        mov     eax, [timer_ticks]
        sub     eax, [WURStartTime]
        cmp     eax, MaxCDWaitTime
        jb      @@SendCommand
;--------------------------------------
.Error:
        ; time out error
        mov     [DevErrorCode], 1
;--------------------------------------
@@End_11:
        popa
        ret
;-----------------------------------------------------------------------------
;*************************************************
;*            FORBID DISK CHANGE                 *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel.          *
;*************************************************
prevent_medium_removal:
        pusha
; Clear the packet command buffer
        call    clear_packet_buffer
; Set command code
        mov     [PacketCommand], byte 0x1E
; Set "Forbid" code
        mov     [PacketCommand+4], byte 11b
; Send command
        call    SendPacketNoDatCommand
        mov     eax, ATAPI_IDE0_lock
        add     eax, [cdpos]
        dec     eax
        mov     [eax], byte 1
        popa
        ret
;-----------------------------------------------------------------------------
;*************************************************
;*            ALLOW DISK CHANGE                  *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel.          *
;*************************************************
allow_medium_removal:
        pusha
; Clear the packet command buffer
        call    clear_packet_buffer
; Set command code
        mov     [PacketCommand], byte 0x1E
; unset "Forbid" code
        mov     [PacketCommand+4], byte 0
; Send command
        call    SendPacketNoDatCommand
        mov     eax, ATAPI_IDE0_lock
        add     eax, [cdpos]
        dec     eax
        mov     [eax], byte 0
        popa
        ret
;-----------------------------------------------------------------------------
;*************************************************
;*         LOAD DISK TO THE DRIVE                *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel.          *
;*************************************************
LoadMedium:
        pusha
; Clear the packet command buffer
        call    clear_packet_buffer
; Generate START/STOP UNIT command
        ; Set command code
        mov     [PacketCommand], word 0x1B
        ; Set disk loading operation
        mov     [PacketCommand+4], word 00000011b
; Send command
        call    SendPacketNoDatCommand
        popa
        ret
;-----------------------------------------------------------------------------
;*************************************************
;*         REMOVE THE DISK FROM THE DRIVE        *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel.          *
;*************************************************
EjectMedium:
        pusha
; Clear the packet command buffer
        call    clear_packet_buffer
; Generate START/STOP UNIT command
        ; Set command code
        mov     [PacketCommand], word 0x1B
        ; Set the operation to eject disk
        mov     [PacketCommand+4], word 00000010b
; Send command
        call    SendPacketNoDatCommand
        popa
        ret
;-----------------------------------------------------------------------------
;*************************************************
;* Check the event of pressing the eject button  *
;*                                               *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel.          *
;*************************************************
proc check_ATAPI_device_event_has_work?
        mov     eax, [timer_ticks]
        sub     eax, [timer_ATAPI_check]
        cmp     eax, 100
        jb      .no

        xor     eax, eax
        inc     eax
        ret
;--------------------------------------
.no:
        xor     eax, eax
        ret
endp
;-----------------------------------------------------------------------------
align 4
check_ATAPI_device_event:
        pusha
        mov     eax, [timer_ticks]
        sub     eax, [timer_ATAPI_check]
        cmp     eax, 100
        jb      .end_1

        pushfd
        mov     al, [DRIVE_DATA+1]
        and     al, 11b
        cmp     al, 10b
        jz      .ide3
;--------------------------------------
.ide2_1:
        mov     al, [DRIVE_DATA+1]
        and     al, 1100b
        cmp     al, 1000b
        jz      .ide2
;--------------------------------------
.ide1_1:
        mov     al, [DRIVE_DATA+1]
        and     al, 110000b
        cmp     al, 100000b
        jz      .ide1
;--------------------------------------
.ide0_1:
        mov     al, [DRIVE_DATA+1]
        and     al, 11000000b
        cmp     al, 10000000b
        jz      .ide0
;--------------------------------------
.ide7_1:
        mov     al, [DRIVE_DATA+6]
        and     al, 11b
        cmp     al, 10b
        jz      .ide7
;--------------------------------------
.ide6_1:
        mov     al, [DRIVE_DATA+6]
        and     al, 1100b
        cmp     al, 1000b
        jz      .ide6
;--------------------------------------
.ide5_1:
        mov     al, [DRIVE_DATA+6]
        and     al, 110000b
        cmp     al, 100000b
        jz      .ide5
;--------------------------------------
.ide4_1:
        mov     al, [DRIVE_DATA+6]
        and     al, 11000000b
        cmp     al, 10000000b
        jz      .ide4
;--------------------------------------
.ide11_1:
        mov     al, [DRIVE_DATA+11]
        and     al, 11b
        cmp     al, 10b
        jz      .ide11
;--------------------------------------
.ide10_1:
        mov     al, [DRIVE_DATA+11]
        and     al, 1100b
        cmp     al, 1000b
        jz      .ide10
;--------------------------------------
.ide9_1:
        mov     al, [DRIVE_DATA+11]
        and     al, 110000b
        cmp     al, 100000b
        jz      .ide9
;--------------------------------------
.ide8_1:
        mov     al, [DRIVE_DATA+11]
        and     al, 11000000b
        cmp     al, 10000000b
        jz      .ide8
;--------------------------------------
.end:
        popfd
        mov     eax, [timer_ticks]
        mov     [timer_ATAPI_check], eax
;--------------------------------------
.end_1:
        popa
        ret
;-----------------------------------------------------------------------------
.ide3:
        cli
        cmp     [ATAPI_IDE3_lock], 1
        jne     .ide2_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel2_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 2
        mov     [DiskNumber], 1
        mov     [cdpos], 4
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide2_1
;-----------------------------------------------------------------------------
.ide2:
        cli
        cmp     [ATAPI_IDE2_lock], 1
        jne     .ide1_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel2_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 2
        mov     [DiskNumber], 0
        mov     [cdpos], 3
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide1_1
;-----------------------------------------------------------------------------
.ide1:
        cli
        cmp     [ATAPI_IDE1_lock], 1
        jne     .ide0_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel1_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 1
        mov     [DiskNumber], 1
        mov     [cdpos], 2
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide0_1
;-----------------------------------------------------------------------------
.ide0:
        cli
        cmp     [ATAPI_IDE0_lock], 1
        jne     .ide7_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel1_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 1
        mov     [DiskNumber], 0
        mov     [cdpos], 1
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide7_1
;-----------------------------------------------------------------------------
.ide7:
        cli
        cmp     [ATAPI_IDE7_lock], 1
        jne     .ide6_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel4_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 2
        mov     [DiskNumber], 1
        mov     [cdpos], 8
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide6_1
;-----------------------------------------------------------------------------
.ide6:
        cli
        cmp     [ATAPI_IDE6_lock], 1
        jne     .ide5_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel4_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 2
        mov     [DiskNumber], 0
        mov     [cdpos], 7
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide5_1
;-----------------------------------------------------------------------------
.ide5:
        cli
        cmp     [ATAPI_IDE5_lock], 1
        jne     .ide4_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel3_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 1
        mov     [DiskNumber], 1
        mov     [cdpos], 6
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide4_1
;-----------------------------------------------------------------------------
.ide4:
        cli
        cmp     [ATAPI_IDE4_lock], 1
        jne     .ide11_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel3_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 1
        mov     [DiskNumber], 0
        mov     [cdpos], 5
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide11_1
;-----------------------------------------------------------------------------
.ide11:
        cli
        cmp     [ATAPI_IDE11_lock], 1
        jne     .ide10_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel6_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 2
        mov     [DiskNumber], 1
        mov     [cdpos], 12
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide10_1
;-----------------------------------------------------------------------------
.ide10:
        cli
        cmp     [ATAPI_IDE10_lock], 1
        jne     .ide9_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel6_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 2
        mov     [DiskNumber], 0
        mov     [cdpos], 11
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide9_1
;-----------------------------------------------------------------------------
.ide9:
        cli
        cmp     [ATAPI_IDE9_lock], 1
        jne     .ide8_1

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel5_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 1
        mov     [DiskNumber], 1
        mov     [cdpos], 10
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .ide8_1
;-----------------------------------------------------------------------------
.ide8:
        cli
        cmp     [ATAPI_IDE8_lock], 1
        jne     .end

        cmp     [cd_status], 0
        jne     .end

        mov     ecx, ide_channel5_mutex
        call    mutex_lock
        call    reserve_ok2
        mov     [ChannelNumber], 1
        mov     [DiskNumber], 0
        mov     [cdpos], 9
        call    GetEvent_StatusNotification
        cmp     [CDDataBuf+4], byte 1
        jne     @f

        call    .eject
;--------------------------------------
@@:
        call    syscall_cdaudio.free
        jmp     .end
;-----------------------------------------------------------------------------
.eject:
        call    clear_CD_cache
        call    allow_medium_removal
        mov     [ignore_CD_eject_wait], 1
        call    EjectMedium
        mov     [ignore_CD_eject_wait], 0
        ret
;-----------------------------------------------------------------------------
iglobal
timer_ATAPI_check dd 0
ATAPI_IDE0_lock db 0
ATAPI_IDE1_lock db 0
ATAPI_IDE2_lock db 0
ATAPI_IDE3_lock db 0
ATAPI_IDE4_lock db 0
ATAPI_IDE5_lock db 0
ATAPI_IDE6_lock db 0
ATAPI_IDE7_lock db 0
ATAPI_IDE8_lock db 0
ATAPI_IDE9_lock db 0
ATAPI_IDE10_lock db 0
ATAPI_IDE11_lock db 0
ignore_CD_eject_wait db 0
endg
;-----------------------------------------------------------------------------
;*************************************************
;* Get an event or device status message         *
;*                                               *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel           *
;*************************************************
GetEvent_StatusNotification:
        pusha
        mov     [CDDataBuf_pointer], CDDataBuf
; Clear the packet command buffer
        call    clear_packet_buffer
; Set command code
        mov     [PacketCommand], byte 4Ah
        mov     [PacketCommand+1], byte 00000001b
; Set message class request
        mov     [PacketCommand+4], byte 00010000b
; Size of allocated area
        mov     [PacketCommand+7], byte 8h
        mov     [PacketCommand+8], byte 0h
; Send command
        call    SendPacketDatCommand
        popa
        ret
;-----------------------------------------------------------------------------
;*************************************************
; Read information from TOC (Table of contents)  *
;* Input parameters are passed through global    *
;* variables:                                    *
;* ChannelNumber - channel number;               *
;* DiskNumber - disk number on channel           *
;*************************************************
Read_TOC:
        pusha
        mov     [CDDataBuf_pointer], CDDataBuf
; Clear the packet command buffer
        call    clear_packet_buffer
; Generate a packet command to read a data sector
        mov     [PacketCommand], byte 0x43
        ; Set format
        mov     [PacketCommand+2], byte 1
; Size of allocated area
        mov     [PacketCommand+7], byte 0xFF
        mov     [PacketCommand+8], byte 0h
; Send a command
        call    SendPacketDatCommand
        popa
        ret
;-----------------------------------------------------------------------------
;*****************************************************
;* DETERMINE THE TOTAL NUMBER OF SECTORS ON THE DISK *
;* Input parameters are passed through global        *
;* variables:                                        *
;* ChannelNumber - channel number;                   *
;* DiskNumber - disk number on channel               *
;*****************************************************
;ReadCapacity:
;       pusha
;; Clear the packet command buffer
;       call  clear_packet_buffer
;; Set the buffer size in bytes
;       mov     [CDBlockSize],8
;; Generate READ CAPACITY command
;       mov     [PacketCommand],word 25h
;; Send command
;       call    SendPacketDatCommand
;       popa
;       ret
;-----------------------------------------------------------------------------
clear_packet_buffer:
; Clear the packet command buffer
        and     [PacketCommand], dword 0
        and     [PacketCommand+4], dword 0
        and     [PacketCommand+8], dword 0
        ret
;-----------------------------------------------------------------------------
