;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision: 5363 $ ;********************************************************** ; Непосредственная работа с контроллером гибкого диска ;********************************************************** ; Автор исходного текста Кулаков Владимир Геннадьевич. ; Адаптация и доработка Mario79 ;give_back_application_data: ; переслать приложению ; mov edi,[TASK_BASE] ; mov edi,[edi+TASKDATA.mem_start] ; add edi,ecx give_back_application_data_1: mov esi, FDD_BUFF;FDD_DataBuffer ;0x40000 mov ecx, 128 cld rep movsd ret ;take_data_from_application: ; взять из приложени ; mov esi,[TASK_BASE] ; mov esi,[esi+TASKDATA.mem_start] ; add esi,ecx take_data_from_application_1: mov edi, FDD_BUFF;FDD_DataBuffer ;0x40000 mov ecx, 128 cld rep movsd ret ; Коды завершения операции с контроллером (FDC_Status) FDC_Normal equ 0 ;нормальное завершение FDC_TimeOut equ 1 ;ошибка тайм-аута FDC_DiskNotFound equ 2 ;в дисководе нет диска FDC_TrackNotFound equ 3 ;дорожка не найдена FDC_SectorNotFound equ 4 ;сектор не найден ; Максимальные значения координат сектора (заданные ; значения соответствуют параметрам стандартного ; трехдюймового гибкого диска объемом 1,44 Мб) MAX_Track equ 79 MAX_Head equ 1 MAX_Sector equ 18 uglobal ; Счетчик тиков таймера TickCounter dd ? ; Код завершения операции с контроллером НГМД FDC_Status DB ? ; Флаг прерывания от НГМД FDD_IntFlag DB ? ; Момент начала последней операции с НГМД FDD_Time DD ? ; Номер дисковода FDD_Type db 0 ; Координаты сектора FDD_Track DB ? FDD_Head DB ? FDD_Sector DB ? ; Блок результата операции FDC_ST0 DB ? FDC_ST1 DB ? FDC_ST2 DB ? FDC_C DB ? FDC_H DB ? FDC_R DB ? FDC_N DB ? ; Счетчик повторения операции чтени ReadRepCounter DB ? ; Счетчик повторения операции рекалибровки RecalRepCounter DB ? endg ; Область памяти для хранения прочитанного сектора ;FDD_DataBuffer: times 512 db 0 ;DB 512 DUP (?) fdd_motor_status db 0 timer_fdd_motor dd 0 ;************************************* ;* ИНИЦИАЛИЗАЦИЯ РЕЖИМА ПДП ДЛЯ НГМД * ;************************************* Init_FDC_DMA: pushad mov al, 0 out 0x0c, al; reset the flip-flop to a known state. mov al, 6 ; mask channel 2 so we can reprogram it. out 0x0a, al mov al, [dmamode]; 0x46 -> Read from floppy - 0x4A Write to floppy out 0x0b, al mov al, 0 out 0x0c, al; reset the flip-flop to a known state. mov eax, 0xD000 out 0x04, al; set the channel 2 starting address to 0 shr eax, 8 out 0x04, al shr eax, 8 out 0x81, al mov al, 0 out 0x0c, al; reset flip-flop mov al, 0xff;set count (actual size -1) out 0x5, al mov al, 0x1;[dmasize] ;(0x1ff = 511 / 0x23ff =9215) out 0x5, al mov al, 2 out 0xa, al popad ret ;*********************************** ;* ЗАПИСАТЬ БАЙТ В ПОРТ ДАННЫХ FDC * ;* Параметры: * ;* AL - выводимый байт. * ;*********************************** FDCDataOutput: ; DEBUGF 1,'K : FDCDataOutput(%x)',al ; pusha push eax ecx edx mov AH, AL ;запомнить байт в AH ; Сбросить переменную состояния контроллера mov [FDC_Status], FDC_Normal ; Проверить готовность контроллера к приему данных mov DX, 3F4h ;(порт состояния FDC) mov ecx, 0x10000 ;установить счетчик тайм-аута @@TestRS: in AL, DX ;прочитать регистр RS and AL, 0C0h ;выделить разряды 6 и 7 cmp AL, 80h ;проверить разряды 6 и 7 je @@OutByteToFDC loop @@TestRS ; Ошибка тайм-аута ; DEBUGF 1,' timeout\n' mov [FDC_Status], FDC_TimeOut jmp @@End_5 ; Вывести байт в порт данных @@OutByteToFDC: inc DX mov AL, AH out DX, AL ; DEBUGF 1,' ok\n' @@End_5: ; popa pop edx ecx eax ret ;****************************************** ;* ПРОЧИТАТЬ БАЙТ ИЗ ПОРТА ДАННЫХ FDC * ;* Процедура не имеет входных параметров. * ;* Выходные данные: * ;* AL - считанный байт. * ;****************************************** FDCDataInput: push ECX push DX ; Сбросить переменную состояния контроллера mov [FDC_Status], FDC_Normal ; Проверить готовность контроллера к передаче данных mov DX, 3F4h ;(порт состояния FDC) mov ecx, 0x10000 ;установить счетчик тайм-аута @@TestRS_1: in AL, DX ;прочитать регистр RS and AL, 0C0h ;выдлить разряды 6 и 7 cmp AL, 0C0h ;проверить разряды 6 и 7 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 ret ;********************************************* ;* ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД * ;********************************************* FDCInterrupt: ; dbgstr 'FDCInterrupt' ; Установить флаг прерывания mov [FDD_IntFlag], 1 mov al, 1 ret ;******************************************* ;* ОЖИДАНИЕ ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД * ;******************************************* WaitFDCInterrupt: pusha ; Сбросить байт состояния операции mov [FDC_Status], FDC_Normal ; Обнулить счетчик тиков mov eax, [timer_ticks] mov [TickCounter], eax ; Ожидать установки флага прерывания НГМД @@TestRS_2: call change_task cmp [FDD_IntFlag], 0 jnz @@End_7 ;прерывание произошло mov eax, [timer_ticks] sub eax, [TickCounter] cmp eax, 200;50 ;25 ;5 ;ожидать 5 тиков jb @@TestRS_2 ; jl @@TestRS_2 ; Ошибка тайм-аута ; dbgstr 'WaitFDCInterrupt: timeout' mov [FDC_Status], FDC_TimeOut @@End_7: popa ret ;********************************* ;* ВКЛЮЧИТЬ МОТОР ДИСКОВОДА "A:" * ;********************************* FDDMotorON: ; dbgstr 'FDDMotorON' pusha ; cmp [fdd_motor_status],1 ; je fdd_motor_on mov al, [flp_number] cmp [fdd_motor_status], al je fdd_motor_on ; Произвести сброс контроллера НГМД mov DX, 3F2h;порт управления двигателями mov AL, 0 out DX, AL ; Выбрать и включить мотор дисковода cmp [flp_number], 1 jne FDDMotorON_B ; call FDDMotorOFF_B mov AL, 1Ch ; Floppy A jmp FDDMotorON_1 FDDMotorON_B: ; call FDDMotorOFF_A mov AL, 2Dh ; Floppy B FDDMotorON_1: out DX, AL ; Обнулить счетчик тиков mov eax, [timer_ticks] mov [TickCounter], eax ; Ожидать 0,5 с @@dT: call change_task mov eax, [timer_ticks] 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 jmp fdd_motor_on fdd_motor_on_B: mov [fdd_motor_status], 2 fdd_motor_on: call save_timer_fdd_motor popa ret ;***************************************** ;* СОХРАНЕНИЕ УКАЗАТЕЛЯ ВРЕМЕНИ * ;***************************************** save_timer_fdd_motor: mov eax, [timer_ticks] mov [timer_fdd_motor], eax ret ;***************************************** ;* ПРОВЕРКА ЗАДЕРЖКИ ВЫКЛЮЧЕНИЯ МОТОРА * ;***************************************** proc check_fdd_motor_status_has_work? cmp [fdd_motor_status], 0 jz .no mov eax, [timer_ticks] sub eax, [timer_fdd_motor] cmp eax, 500 jb .no .yes: xor eax, eax inc eax ret .no: xor eax, eax ret endp align 4 check_fdd_motor_status: cmp [fdd_motor_status], 0 je end_check_fdd_motor_status_1 mov eax, [timer_ticks] sub eax, [timer_fdd_motor] cmp eax, 500 jb end_check_fdd_motor_status call FDDMotorOFF mov [fdd_motor_status], 0 end_check_fdd_motor_status_1: end_check_fdd_motor_status: ret ;********************************** ;* ВЫКЛЮЧИТЬ МОТОР ДИСКОВОДА * ;********************************** FDDMotorOFF: ; dbgstr 'FDDMotorOFF' push AX push DX cmp [flp_number], 1 jne FDDMotorOFF_1 call FDDMotorOFF_A jmp FDDMotorOFF_2 FDDMotorOFF_1: call FDDMotorOFF_B FDDMotorOFF_2: pop DX pop AX ; сброс флагов кеширования в связи с устареванием информации or [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN or [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN ret FDDMotorOFF_A: mov DX, 3F2h;порт управления двигателями mov AL, 0Ch ; Floppy A out DX, AL ret FDDMotorOFF_B: mov DX, 3F2h;порт управления двигателями mov AL, 5h ; Floppy B out DX, AL ret ;******************************* ;* РЕКАЛИБРОВКА ДИСКОВОДА "A:" * ;******************************* RecalibrateFDD: ; dbgstr 'RecalibrateFDD' pusha call save_timer_fdd_motor ; Сбросить флаг прерывания mov [FDD_IntFlag], 0 ; Подать команду "Рекалибровка" mov AL, 07h call FDCDataOutput mov AL, 00h call FDCDataOutput ; Ожидать завершения операции call WaitFDCInterrupt cmp [FDC_Status], 0 jne .fail ; Read results of RECALIBRATE command ; DEBUGF 1,'K : floppy recalibrate results:' mov al, 8 call FDCDataOutput call FDCDataInput push eax ; DEBUGF 1,' %x',al call FDCDataInput ; DEBUGF 1,' %x',al ; DEBUGF 1,'\n' pop eax test al, 0xC0 jz @f mov [FDC_Status], FDC_DiskNotFound @@: .fail: call save_timer_fdd_motor popa ret ;***************************************************** ;* ПОИСК ДОРОЖКИ * ;* Параметры передаются через глобальные переменные: * ;* FDD_Track - номер дорожки (0-79); * ;* FDD_Head - номер головки (0-1). * ;* Результат операции заносится в FDC_Status. * ;***************************************************** SeekTrack: ; dbgstr 'SeekTrack' pusha call save_timer_fdd_motor ; Сбросить флаг прерывания mov [FDD_IntFlag], 0 ; Подать команду "Поиск" mov AL, 0Fh call FDCDataOutput ; Передать байт номера головки/накопител mov AL, [FDD_Head] shl AL, 2 call FDCDataOutput ; Передать байт номера дорожки mov AL, [FDD_Track] call FDCDataOutput ; Ожидать завершения операции call WaitFDCInterrupt cmp [FDC_Status], FDC_Normal jne @@Exit ; Сохранить результат поиска mov AL, 08h call FDCDataOutput call FDCDataInput mov [FDC_ST0], AL call FDCDataInput mov [FDC_C], AL ; Проверить результат поиска ; Поиск завершен? test [FDC_ST0], 100000b je @@Err ; Заданный трек найден? mov AL, [FDC_C] cmp AL, [FDD_Track] 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 @@Exit: call save_timer_fdd_motor popa ret ;******************************************************* ;* ЧТЕНИЕ СЕКТОРА ДАННЫХ * ;* Параметры передаются через глобальные переменные: * ;* FDD_Track - номер дорожки (0-79); * ;* FDD_Head - номер головки (0-1); * ;* FDD_Sector - номер сектора (1-18). * ;* Результат операции заносится в FDC_Status. * ;* В случае успешного выполнения операции чтения * ;* содержимое сектора будет занесено в FDD_DataBuffer. * ;******************************************************* ReadSector: ; dbgstr 'ReadSector' pushad call save_timer_fdd_motor ; Сбросить флаг прерывания mov [FDD_IntFlag], 0 ; Установить скорость передачи 500 Кбайт/с mov AX, 0 mov DX, 03F7h out DX, AL ; Инициализировать канал прямого доступа к памяти mov [dmamode], 0x46 call Init_FDC_DMA ; Подать команду "Чтение данных" mov AL, 0E6h ;чтение в мультитрековом режиме call FDCDataOutput mov AL, [FDD_Head] shl AL, 2 call FDCDataOutput mov AL, [FDD_Track] call FDCDataOutput mov AL, [FDD_Head] call FDCDataOutput mov AL, [FDD_Sector] call FDCDataOutput mov AL, 2 ;код размера сектора (512 байт) call FDCDataOutput mov AL, 18 ;+1; 3Fh ;число секторов на дорожке call FDCDataOutput mov AL, 1Bh ;значение GPL call FDCDataOutput mov AL, 0FFh;значение DTL call FDCDataOutput ; Ожидаем прерывание по завершении операции call WaitFDCInterrupt cmp [FDC_Status], FDC_Normal jne @@Exit_1 ; Считываем статус завершения операции 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 @@Exit_1: call save_timer_fdd_motor popad ret ;******************************************************* ;* ЧТЕНИЕ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ) * ;* Параметры передаются через глобальные переменные: * ;* FDD_Track - номер дорожки (0-79); * ;* FDD_Head - номер головки (0-1); * ;* FDD_Sector - номер сектора (1-18). * ;* Результат операции заносится в FDC_Status. * ;* В случае успешного выполнения операции чтения * ;* содержимое сектора будет занесено в FDD_DataBuffer. * ;******************************************************* ReadSectWithRetr: pusha ; Обнулить счетчик повторения операции рекалибровки mov [RecalRepCounter], 0 @@TryAgain: ; Обнулить счетчик повторения операции чтени mov [ReadRepCounter], 0 @@ReadSector_1: call ReadSector cmp [FDC_Status], 0 je @@Exit_2 cmp [FDC_Status], 1 je @@Err_3 ; Троекратное повторение чтени inc [ReadRepCounter] cmp [ReadRepCounter], 3 jb @@ReadSector_1 ; Троекратное повторение рекалибровки call RecalibrateFDD call SeekTrack inc [RecalRepCounter] cmp [RecalRepCounter], 3 jb @@TryAgain @@Exit_2: popa ret @@Err_3: popa ret ;******************************************************* ;* ЗАПИСЬ СЕКТОРА ДАННЫХ * ;* Параметры передаются через глобальные переменные: * ;* FDD_Track - номер дорожки (0-79); * ;* FDD_Head - номер головки (0-1); * ;* FDD_Sector - номер сектора (1-18). * ;* Результат операции заносится в FDC_Status. * ;* В случае успешного выполнения операции записи * ;* содержимое FDD_DataBuffer будет занесено в сектор. * ;******************************************************* WriteSector: ; dbgstr 'WriteSector' pushad call save_timer_fdd_motor ; Сбросить флаг прерывания mov [FDD_IntFlag], 0 ; Установить скорость передачи 500 Кбайт/с mov AX, 0 mov DX, 03F7h out DX, AL ; Инициализировать канал прямого доступа к памяти mov [dmamode], 0x4A call Init_FDC_DMA ; Подать команду "Запись данных" mov AL, 0xC5 ;0x45 ;запись в мультитрековом режиме call FDCDataOutput mov AL, [FDD_Head] shl AL, 2 call FDCDataOutput mov AL, [FDD_Track] call FDCDataOutput mov AL, [FDD_Head] call FDCDataOutput mov AL, [FDD_Sector] call FDCDataOutput mov AL, 2 ;код размера сектора (512 байт) call FDCDataOutput mov AL, 18; 3Fh ;число секторов на дорожке call FDCDataOutput mov AL, 1Bh ;значение GPL call FDCDataOutput mov AL, 0FFh;значение DTL call FDCDataOutput ; Ожидаем прерывание по завершении операции call WaitFDCInterrupt cmp [FDC_Status], FDC_Normal jne @@Exit_3 ; Считываем статус завершения операции call GetStatusInfo test [FDC_ST0], 11000000b ;11011000b jnz @@Err_2 mov [FDC_Status], FDC_Normal jmp @@Exit_3 @@Err_2: mov [FDC_Status], FDC_SectorNotFound @@Exit_3: call save_timer_fdd_motor popad ret ;******************************************************* ;* ЗАПИСЬ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ) * ;* Параметры передаются через глобальные переменные: * ;* FDD_Track - номер дорожки (0-79); * ;* FDD_Head - номер головки (0-1); * ;* FDD_Sector - номер сектора (1-18). * ;* Результат операции заносится в FDC_Status. * ;* В случае успешного выполнения операции записи * ;* содержимое FDD_DataBuffer будет занесено в сектор. * ;******************************************************* WriteSectWithRetr: pusha ; Обнулить счетчик повторения операции рекалибровки mov [RecalRepCounter], 0 @@TryAgain_1: ; Обнулить счетчик повторения операции чтени mov [ReadRepCounter], 0 @@WriteSector_1: call WriteSector cmp [FDC_Status], 0 je @@Exit_4 cmp [FDC_Status], 1 je @@Err_4 ; Троекратное повторение чтени inc [ReadRepCounter] cmp [ReadRepCounter], 3 jb @@WriteSector_1 ; Троекратное повторение рекалибровки call RecalibrateFDD call SeekTrack inc [RecalRepCounter] cmp [RecalRepCounter], 3 jb @@TryAgain_1 @@Exit_4: popa ret @@Err_4: popa ret ;********************************************* ;* ПОЛУЧИТЬ ИНФОРМАЦИЮ О РЕЗУЛЬТАТЕ ОПЕРАЦИИ * ;********************************************* GetStatusInfo: push AX call FDCDataInput mov [FDC_ST0], AL call FDCDataInput mov [FDC_ST1], AL call FDCDataInput mov [FDC_ST2], AL call FDCDataInput mov [FDC_C], AL call FDCDataInput mov [FDC_H], AL call FDCDataInput mov [FDC_R], AL call FDCDataInput mov [FDC_N], AL 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