support for PnP disks, part 5: FAT12, ramdisk, floppies
git-svn-id: svn://kolibrios.org@4273 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -20,8 +20,7 @@ $Revision$
|
||||
; add edi,ecx
|
||||
give_back_application_data_1:
|
||||
mov esi, FDD_BUFF;FDD_DataBuffer ;0x40000
|
||||
xor ecx, ecx
|
||||
mov cx, 128
|
||||
mov ecx, 128
|
||||
cld
|
||||
rep movsd
|
||||
ret
|
||||
@@ -32,8 +31,7 @@ give_back_application_data_1:
|
||||
; add esi,ecx
|
||||
take_data_from_application_1:
|
||||
mov edi, FDD_BUFF;FDD_DataBuffer ;0x40000
|
||||
xor ecx, ecx
|
||||
mov cx, 128
|
||||
mov ecx, 128
|
||||
cld
|
||||
rep movsd
|
||||
ret
|
||||
@@ -122,6 +120,7 @@ Init_FDC_DMA:
|
||||
;* AL - выводимый байт. *
|
||||
;***********************************
|
||||
FDCDataOutput:
|
||||
; DEBUGF 1,'K : FDCDataOutput(%x)',al
|
||||
; pusha
|
||||
push eax ecx edx
|
||||
mov AH, AL ;запомнить байт в AH
|
||||
@@ -137,6 +136,7 @@ FDCDataOutput:
|
||||
je @@OutByteToFDC
|
||||
loop @@TestRS
|
||||
; Ошибка тайм-аута
|
||||
; DEBUGF 1,' timeout\n'
|
||||
mov [FDC_Status], FDC_TimeOut
|
||||
jmp @@End_5
|
||||
; Вывести байт в порт данных
|
||||
@@ -144,6 +144,7 @@ FDCDataOutput:
|
||||
inc DX
|
||||
mov AL, AH
|
||||
out DX, AL
|
||||
; DEBUGF 1,' ok\n'
|
||||
@@End_5:
|
||||
; popa
|
||||
pop edx ecx eax
|
||||
@@ -170,12 +171,14 @@ FDCDataInput:
|
||||
je @@GetByteFromFDC
|
||||
loop @@TestRS_1
|
||||
; Ошибка тайм-аута
|
||||
; DEBUGF 1,'K : FDCDataInput: timeout\n'
|
||||
mov [FDC_Status], FDC_TimeOut
|
||||
jmp @@End_6
|
||||
; Ввести байт из порта данных
|
||||
@@GetByteFromFDC:
|
||||
inc DX
|
||||
in AL, DX
|
||||
; DEBUGF 1,'K : FDCDataInput: %x\n',al
|
||||
@@End_6:
|
||||
pop DX
|
||||
pop ECX
|
||||
@@ -185,6 +188,7 @@ FDCDataInput:
|
||||
;* ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
|
||||
;*********************************************
|
||||
FDCInterrupt:
|
||||
; dbgstr 'FDCInterrupt'
|
||||
; Установить флаг прерывания
|
||||
mov [FDD_IntFlag], 1
|
||||
mov al, 1
|
||||
@@ -207,12 +211,12 @@ WaitFDCInterrupt:
|
||||
jnz @@End_7 ;прерывание произошло
|
||||
mov eax, [timer_ticks]
|
||||
sub eax, [TickCounter]
|
||||
cmp eax, 50 ;25 ;5 ;ожидать 5 тиков
|
||||
cmp eax, 200;50 ;25 ;5 ;ожидать 5 тиков
|
||||
jb @@TestRS_2
|
||||
; jl @@TestRS_2
|
||||
; Ошибка тайм-аута
|
||||
; dbgstr 'WaitFDCInterrupt: timeout'
|
||||
mov [FDC_Status], FDC_TimeOut
|
||||
; mov [flp_status],0
|
||||
@@End_7:
|
||||
popa
|
||||
ret
|
||||
@@ -221,6 +225,7 @@ WaitFDCInterrupt:
|
||||
;* ВКЛЮЧИТЬ МОТОР ДИСКОВОДА "A:" *
|
||||
;*********************************
|
||||
FDDMotorON:
|
||||
; dbgstr 'FDDMotorON'
|
||||
pusha
|
||||
; cmp [fdd_motor_status],1
|
||||
; je fdd_motor_on
|
||||
@@ -252,6 +257,20 @@ FDDMotorON_1:
|
||||
sub eax, [TickCounter]
|
||||
cmp eax, 50 ;10
|
||||
jb @@dT
|
||||
; Read results of RESET command
|
||||
push 4
|
||||
; DEBUGF 1,'K : floppy reset results:'
|
||||
@@:
|
||||
mov al, 8
|
||||
call FDCDataOutput
|
||||
call FDCDataInput
|
||||
; DEBUGF 1,' %x',al
|
||||
call FDCDataInput
|
||||
; DEBUGF 1,' %x',al
|
||||
dec dword [esp]
|
||||
jnz @b
|
||||
; DEBUGF 1,'\n'
|
||||
pop eax
|
||||
cmp [flp_number], 1
|
||||
jne fdd_motor_on_B
|
||||
mov [fdd_motor_status], 1
|
||||
@@ -275,8 +294,6 @@ save_timer_fdd_motor:
|
||||
;* ПРОВЕРКА ЗАДЕРЖКИ ВЫКЛЮЧЕНИЯ МОТОРА *
|
||||
;*****************************************
|
||||
proc check_fdd_motor_status_has_work?
|
||||
cmp [flp_status], 0
|
||||
jnz .yes
|
||||
cmp [fdd_motor_status], 0
|
||||
jz .no
|
||||
mov eax, [timer_ticks]
|
||||
@@ -303,7 +320,6 @@ check_fdd_motor_status:
|
||||
call FDDMotorOFF
|
||||
mov [fdd_motor_status], 0
|
||||
end_check_fdd_motor_status_1:
|
||||
mov [flp_status], 0
|
||||
end_check_fdd_motor_status:
|
||||
ret
|
||||
|
||||
@@ -311,6 +327,7 @@ end_check_fdd_motor_status:
|
||||
;* ВЫКЛЮЧИТЬ МОТОР ДИСКОВОДА *
|
||||
;**********************************
|
||||
FDDMotorOFF:
|
||||
; dbgstr 'FDDMotorOFF'
|
||||
push AX
|
||||
push DX
|
||||
cmp [flp_number], 1
|
||||
@@ -323,8 +340,8 @@ FDDMotorOFF_2:
|
||||
pop DX
|
||||
pop AX
|
||||
; сброс флагов кеширования в связи с устареванием информации
|
||||
mov [root_read], 0
|
||||
mov [flp_fat], 0
|
||||
or [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN
|
||||
or [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN
|
||||
ret
|
||||
|
||||
FDDMotorOFF_A:
|
||||
@@ -343,8 +360,11 @@ FDDMotorOFF_B:
|
||||
;* РЕКАЛИБРОВКА ДИСКОВОДА "A:" *
|
||||
;*******************************
|
||||
RecalibrateFDD:
|
||||
; dbgstr 'RecalibrateFDD'
|
||||
pusha
|
||||
call save_timer_fdd_motor
|
||||
; Сбросить флаг прерывания
|
||||
mov [FDD_IntFlag], 0
|
||||
; Подать команду "Рекалибровка"
|
||||
mov AL, 07h
|
||||
call FDCDataOutput
|
||||
@@ -352,10 +372,18 @@ RecalibrateFDD:
|
||||
call FDCDataOutput
|
||||
; Ожидать завершения операции
|
||||
call WaitFDCInterrupt
|
||||
; cmp [FDC_Status],0
|
||||
; je no_fdc_status_error
|
||||
; mov [flp_status],0
|
||||
;no_fdc_status_error:
|
||||
cmp [FDC_Status], 0
|
||||
jne .fail
|
||||
; Read results of RECALIBRATE command
|
||||
; DEBUGF 1,'K : floppy recalibrate results:'
|
||||
mov al, 8
|
||||
call FDCDataOutput
|
||||
call FDCDataInput
|
||||
; DEBUGF 1,' %x',al
|
||||
call FDCDataInput
|
||||
; DEBUGF 1,' %x',al
|
||||
; DEBUGF 1,'\n'
|
||||
.fail:
|
||||
call save_timer_fdd_motor
|
||||
popa
|
||||
ret
|
||||
@@ -368,6 +396,7 @@ RecalibrateFDD:
|
||||
;* Результат операции заносится в FDC_Status. *
|
||||
;*****************************************************
|
||||
SeekTrack:
|
||||
; dbgstr 'SeekTrack'
|
||||
pusha
|
||||
call save_timer_fdd_motor
|
||||
; Сбросить флаг прерывания
|
||||
@@ -402,17 +431,20 @@ SeekTrack:
|
||||
cmp AL, [FDD_Track]
|
||||
jne @@Err
|
||||
; Номер головки совпадает с заданным?
|
||||
mov AL, [FDC_ST0]
|
||||
and AL, 100b
|
||||
shr AL, 2
|
||||
cmp AL, [FDD_Head]
|
||||
jne @@Err
|
||||
; The H bit (Head Address) in ST0 will always return a "0" (c) 82077AA datasheet,
|
||||
; description of SEEK command. So we can not verify the proper head.
|
||||
; mov AL, [FDC_ST0]
|
||||
; and AL, 100b
|
||||
; shr AL, 2
|
||||
; cmp AL, [FDD_Head]
|
||||
; jne @@Err
|
||||
; Операция завершена успешно
|
||||
; dbgstr 'SeekTrack: FDC_Normal'
|
||||
mov [FDC_Status], FDC_Normal
|
||||
jmp @@Exit
|
||||
@@Err: ; Трек не найден
|
||||
; dbgstr 'SeekTrack: FDC_TrackNotFound'
|
||||
mov [FDC_Status], FDC_TrackNotFound
|
||||
; mov [flp_status],0
|
||||
@@Exit:
|
||||
call save_timer_fdd_motor
|
||||
popa
|
||||
@@ -429,6 +461,7 @@ SeekTrack:
|
||||
;* содержимое сектора будет занесено в FDD_DataBuffer. *
|
||||
;*******************************************************
|
||||
ReadSector:
|
||||
; dbgstr 'ReadSector'
|
||||
pushad
|
||||
call save_timer_fdd_motor
|
||||
; Сбросить флаг прерывания
|
||||
@@ -468,11 +501,12 @@ ReadSector:
|
||||
call GetStatusInfo
|
||||
test [FDC_ST0], 11011000b
|
||||
jnz @@Err_1
|
||||
; dbgstr 'ReadSector: FDC_Normal'
|
||||
mov [FDC_Status], FDC_Normal
|
||||
jmp @@Exit_1
|
||||
@@Err_1:
|
||||
; dbgstr 'ReadSector: FDC_SectorNotFound'
|
||||
mov [FDC_Status], FDC_SectorNotFound
|
||||
; mov [flp_status],0
|
||||
@@Exit_1:
|
||||
call save_timer_fdd_motor
|
||||
popad
|
||||
@@ -511,12 +545,10 @@ ReadSectWithRetr:
|
||||
inc [RecalRepCounter]
|
||||
cmp [RecalRepCounter], 3
|
||||
jb @@TryAgain
|
||||
; mov [flp_status],0
|
||||
@@Exit_2:
|
||||
popa
|
||||
ret
|
||||
@@Err_3:
|
||||
mov [flp_status], 0
|
||||
popa
|
||||
ret
|
||||
|
||||
@@ -531,6 +563,7 @@ ReadSectWithRetr:
|
||||
;* содержимое FDD_DataBuffer будет занесено в сектор. *
|
||||
;*******************************************************
|
||||
WriteSector:
|
||||
; dbgstr 'WriteSector'
|
||||
pushad
|
||||
call save_timer_fdd_motor
|
||||
; Сбросить флаг прерывания
|
||||
@@ -616,7 +649,6 @@ WriteSectWithRetr:
|
||||
popa
|
||||
ret
|
||||
@@Err_4:
|
||||
mov [flp_status], 0
|
||||
popa
|
||||
ret
|
||||
|
||||
@@ -642,3 +674,276 @@ GetStatusInfo:
|
||||
pop AX
|
||||
ret
|
||||
|
||||
; Interface for disk subsystem.
|
||||
; Assume fixed capacity for 1.44M.
|
||||
FLOPPY_CAPACITY = 2880 ; in sectors
|
||||
|
||||
iglobal
|
||||
align 4
|
||||
floppy_functions:
|
||||
dd .size
|
||||
dd 0 ; no close() function
|
||||
dd 0 ; no closemedia() function
|
||||
dd floppy_querymedia
|
||||
dd floppy_read
|
||||
dd floppy_write
|
||||
dd 0 ; no flush() function
|
||||
dd 0 ; no adjust_cache_size() function
|
||||
.size = $ - floppy_functions
|
||||
endg
|
||||
|
||||
uglobal
|
||||
floppy_media_flags rb 2
|
||||
n_sector dd 0 ; temporary save for sector value
|
||||
flp_number db 0 ; 1- Floppy A, 2-Floppy B
|
||||
old_track db 0 ; old value track
|
||||
flp_label rb 15*2 ; Label and ID of inserted floppy disk
|
||||
align 4
|
||||
; Hardware does not allow to work with two floppies in parallel,
|
||||
; so there is one mutex guarding access to any floppy.
|
||||
floppy_mutex MUTEX
|
||||
endg
|
||||
; Meaning of bits in floppy_media_flags
|
||||
FLOPPY_MEDIA_PRESENT = 1 ; media was present when last asked
|
||||
FLOPPY_MEDIA_NEED_RESCAN = 2 ; media was possibly changed, need to rescan
|
||||
FLOPPY_MEDIA_LABEL_CHANGED = 4 ; temporary state
|
||||
|
||||
iglobal
|
||||
floppy1_name db 'fd',0
|
||||
floppy2_name db 'fd2',0
|
||||
endg
|
||||
|
||||
; This function is called in boot process.
|
||||
; It creates filesystems /fd and/or /fd2, if the system has one/two floppy drives.
|
||||
proc floppy_init
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_init
|
||||
; First floppy is present if [DRIVE_DATA] and 0xF0 is nonzero.
|
||||
test byte [DRIVE_DATA], 0xF0
|
||||
jz .no1
|
||||
stdcall disk_add, floppy_functions, floppy1_name, 1, DISK_NO_INSERT_NOTIFICATION
|
||||
.no1:
|
||||
; Second floppy is present if [DRIVE_DATA] and 0x0F is nonzero.
|
||||
test byte [DRIVE_DATA], 0x0F
|
||||
jz .no2
|
||||
stdcall disk_add, floppy_functions, floppy2_name, 2, DISK_NO_INSERT_NOTIFICATION
|
||||
.no2:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Returns information about disk media.
|
||||
; Floppy drives do not support insert notifications,
|
||||
; DISK_NO_INSERT_NOTIFICATION is set,
|
||||
; the disk subsystem calls this function before each filesystem operation.
|
||||
; If the media has changed, return error for the first call as signal
|
||||
; to finalize work with old media and the true geometry for the second call.
|
||||
; Assume that media is (possibly) changed anytime when motor is off.
|
||||
proc floppy_querymedia
|
||||
virtual at esp+4
|
||||
.userdata dd ?
|
||||
.info dd ?
|
||||
end virtual
|
||||
; 1. Acquire the global lock.
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_lock
|
||||
mov edx, [.userdata] ; 1 for /fd, 2 for /fd2
|
||||
; 2. If the media was reported and has been changed, forget it and report an error.
|
||||
mov al, [floppy_media_flags+edx-1]
|
||||
and al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
|
||||
cmp al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
|
||||
jnz .not_reported
|
||||
.no_media:
|
||||
mov [floppy_media_flags+edx-1], 0
|
||||
.return_no_media:
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_unlock
|
||||
mov eax, DISK_STATUS_NO_MEDIA
|
||||
retn 8
|
||||
.not_reported:
|
||||
; 3. If we are in the temporary state LABEL_CHANGED, this is the second call
|
||||
; after intermediate DISK_STATUS_NO_MEDIA due to media change;
|
||||
; clear the flag and return the current geometry without rereading the bootsector.
|
||||
cmp [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
|
||||
jz .report_geometry
|
||||
; 4. Try to read the bootsector.
|
||||
mov [flp_number], dl
|
||||
mov [FDC_Status], 0
|
||||
call floppy_read_bootsector
|
||||
; 5. If reading bootsector failed, assume that media is not present.
|
||||
mov edx, [.userdata]
|
||||
cmp [FDC_Status], 0
|
||||
jnz .no_media
|
||||
; 6. Check whether the previous status is "present". If not, go to 10.
|
||||
push esi edi
|
||||
imul edi, edx, 15
|
||||
add edi, flp_label-15
|
||||
mov esi, FDD_BUFF+39
|
||||
mov ecx, 15
|
||||
test [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
|
||||
jz .set_label
|
||||
; 7. Compare the old label with the current one.
|
||||
rep cmpsb
|
||||
; 8. If the label has not changed, go to 11.
|
||||
jz .ok
|
||||
; 9. If the label has changed, store it, enter temporary state LABEL_CHANGED
|
||||
; and report DISK_STATUS_NO_MEDIA.
|
||||
; dbgstr 'floppy label changed'
|
||||
add esi, ecx
|
||||
add edi, ecx
|
||||
mov ecx, 15
|
||||
sub esi, ecx
|
||||
sub edi, ecx
|
||||
rep movsb
|
||||
mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
|
||||
pop edi esi
|
||||
jmp .return_no_media
|
||||
.set_label:
|
||||
; 10. The previous state was "not present". Copy the label.
|
||||
rep movsb
|
||||
.ok:
|
||||
pop edi esi
|
||||
.report_geometry:
|
||||
; 11. Fill DISKMEDIAINFO structure.
|
||||
mov ecx, [.info]
|
||||
and [ecx+DISKMEDIAINFO.Flags], 0
|
||||
mov [ecx+DISKMEDIAINFO.SectorSize], 512
|
||||
mov dword [ecx+DISKMEDIAINFO.Capacity], FLOPPY_CAPACITY
|
||||
and dword [ecx+DISKMEDIAINFO.Capacity+4], 0
|
||||
; 12. Update state: media is present, data are actual.
|
||||
mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
|
||||
; 13. Release the global lock and return successful status.
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
retn 8
|
||||
endp
|
||||
|
||||
proc floppy_read_bootsector
|
||||
pushad
|
||||
mov [FDD_Track], 0; Цилиндр
|
||||
mov [FDD_Head], 0; Сторона
|
||||
mov [FDD_Sector], 1; Сектор
|
||||
call FDDMotorON
|
||||
call RecalibrateFDD
|
||||
cmp [FDC_Status], 0
|
||||
jne .nothing
|
||||
call SeekTrack
|
||||
cmp [FDC_Status], 0
|
||||
jne .nothing
|
||||
call ReadSectWithRetr
|
||||
.nothing:
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
read_chs_sector:
|
||||
call calculate_chs
|
||||
call ReadSectWithRetr
|
||||
ret
|
||||
|
||||
save_chs_sector:
|
||||
call calculate_chs
|
||||
call WriteSectWithRetr
|
||||
ret
|
||||
|
||||
calculate_chs:
|
||||
mov bl, [FDD_Track]
|
||||
mov [old_track], bl
|
||||
mov ebx, 18
|
||||
xor edx, edx
|
||||
div ebx
|
||||
inc edx
|
||||
mov [FDD_Sector], dl
|
||||
mov edx, eax
|
||||
shr eax, 1
|
||||
and edx, 1
|
||||
mov [FDD_Track], al
|
||||
mov [FDD_Head], dl
|
||||
mov dl, [old_track]
|
||||
cmp dl, [FDD_Track]
|
||||
je no_seek_track_1
|
||||
call SeekTrack
|
||||
no_seek_track_1:
|
||||
ret
|
||||
|
||||
; Writes one or more sectors to the device.
|
||||
proc floppy_write
|
||||
mov dl, 1
|
||||
jmp floppy_read_write
|
||||
endp
|
||||
|
||||
; Reads one or more sectors from the device.
|
||||
proc floppy_read
|
||||
mov dl, 0
|
||||
endp
|
||||
|
||||
; Common part of floppy_read and floppy_write.
|
||||
proc floppy_read_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
|
||||
virtual at ebp-8
|
||||
.sectors_todo dd ?
|
||||
.operation db ?
|
||||
end virtual
|
||||
push edx ; save operation code to [.operation]
|
||||
; 1. Get number of sectors to read/write
|
||||
; and zero number of sectors that were actually read/written.
|
||||
mov eax, [numsectors_ptr]
|
||||
push dword [eax] ; initialize [.sectors_todo]
|
||||
and dword [eax], 0
|
||||
push ebx esi edi ; save used registers to be stdcall
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_lock
|
||||
; 3. Set floppy number for this operation.
|
||||
mov edx, [userdata]
|
||||
mov [flp_number], dl
|
||||
; 4. Read/write sector-by-sector.
|
||||
.operation_loop:
|
||||
; 4a. Check that the sector is inside the media.
|
||||
cmp dword [start_sector+4], 0
|
||||
jnz .end_of_media
|
||||
mov eax, dword [start_sector]
|
||||
cmp eax, FLOPPY_CAPACITY
|
||||
jae .end_of_media
|
||||
; 4b. For read operation, call read_chs_sector and then move data from FDD_BUFF to [buffer].
|
||||
; For write operation, move data from [buffer] to FDD_BUFF and then call save_chs_sector.
|
||||
cmp [.operation], 0
|
||||
jz .read
|
||||
mov esi, [buffer]
|
||||
mov edi, FDD_BUFF
|
||||
mov ecx, 512/4
|
||||
rep movsd
|
||||
mov [buffer], esi
|
||||
call save_chs_sector
|
||||
jmp @f
|
||||
.read:
|
||||
call read_chs_sector
|
||||
mov esi, FDD_BUFF
|
||||
mov edi, [buffer]
|
||||
mov ecx, 512/4
|
||||
rep movsd
|
||||
mov [buffer], edi
|
||||
@@:
|
||||
; 4c. If there was an error, propagate it to the caller.
|
||||
cmp [FDC_Status], 0
|
||||
jnz .fail
|
||||
; 4d. Otherwise, increment number of sectors processed and continue the loop.
|
||||
mov eax, [numsectors_ptr]
|
||||
inc dword [eax]
|
||||
inc dword [start_sector]
|
||||
dec [.sectors_todo]
|
||||
jnz .operation_loop
|
||||
; 5. Release the global lock and return with the correct status.
|
||||
push 0
|
||||
.return:
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
pop edi esi ebx ; restore used registers to be stdcall
|
||||
ret ; this translates to leave/retn N and purges local variables
|
||||
.fail:
|
||||
push -1
|
||||
jmp .return
|
||||
.end_of_media:
|
||||
push DISK_STATUS_END_OF_MEDIA
|
||||
jmp .return
|
||||
endp
|
||||
|
Reference in New Issue
Block a user