Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 4273 $
  9.  
  10.  
  11. ;**********************************************************
  12. ;  Непосредственная работа с контроллером гибкого диска
  13. ;**********************************************************
  14. ; Автор исходного текста  Кулаков Владимир Геннадьевич.
  15. ; Адаптация и доработка Mario79
  16.  
  17. ;give_back_application_data:  ; переслать приложению
  18. ;     mov edi,[TASK_BASE]
  19. ;     mov edi,[edi+TASKDATA.mem_start]
  20. ;     add edi,ecx
  21. give_back_application_data_1:
  22.         mov     esi, FDD_BUFF;FDD_DataBuffer  ;0x40000
  23.         mov     ecx, 128
  24.         cld
  25.         rep movsd
  26.         ret
  27.  
  28. ;take_data_from_application:   ; взять из приложени
  29. ;     mov esi,[TASK_BASE]
  30. ;     mov esi,[esi+TASKDATA.mem_start]
  31. ;     add esi,ecx
  32. take_data_from_application_1:
  33.         mov     edi, FDD_BUFF;FDD_DataBuffer  ;0x40000
  34.         mov     ecx, 128
  35.         cld
  36.         rep movsd
  37.         ret
  38.  
  39. ; Коды завершения операции с контроллером (FDC_Status)
  40. FDC_Normal         equ 0 ;нормальное завершение
  41. FDC_TimeOut        equ 1 ;ошибка тайм-аута
  42. FDC_DiskNotFound   equ 2 ;в дисководе нет диска
  43. FDC_TrackNotFound  equ 3 ;дорожка не найдена
  44. FDC_SectorNotFound equ 4 ;сектор не найден
  45.  
  46. ; Максимальные значения координат сектора (заданные
  47. ; значения соответствуют параметрам стандартного
  48. ; трехдюймового гибкого диска объемом 1,44 Мб)
  49. MAX_Track   equ 79
  50. MAX_Head    equ  1
  51. MAX_Sector  equ 18
  52.  
  53. uglobal
  54. ; Счетчик тиков таймера
  55. TickCounter dd ?
  56. ; Код завершения операции с контроллером НГМД
  57. FDC_Status  DB ?
  58. ; Флаг прерывания от НГМД
  59. FDD_IntFlag DB ?
  60. ; Момент начала последней операции с НГМД
  61. FDD_Time    DD ?
  62. ; Номер дисковода
  63. FDD_Type    db 0
  64. ; Координаты сектора
  65. FDD_Track   DB ?
  66. FDD_Head    DB ?
  67. FDD_Sector  DB ?
  68.  
  69. ; Блок результата операции
  70. FDC_ST0 DB ?
  71. FDC_ST1 DB ?
  72. FDC_ST2 DB ?
  73. FDC_C   DB ?
  74. FDC_H   DB ?
  75. FDC_R   DB ?
  76. FDC_N   DB ?
  77. ; Счетчик повторения операции чтени
  78. ReadRepCounter  DB ?
  79. ; Счетчик повторения операции рекалибровки
  80. RecalRepCounter DB ?
  81. endg
  82. ; Область памяти для хранения прочитанного сектора
  83. ;FDD_DataBuffer:  times 512 db 0   ;DB 512 DUP (?)
  84. fdd_motor_status db 0
  85. timer_fdd_motor  dd 0
  86.  
  87. ;*************************************
  88. ;* ИНИЦИАЛИЗАЦИЯ РЕЖИМА ПДП ДЛЯ НГМД *
  89. ;*************************************
  90. Init_FDC_DMA:
  91.         pushad
  92.         mov     al, 0
  93.         out     0x0c, al; reset the flip-flop to a known state.
  94.         mov     al, 6           ; mask channel 2 so we can reprogram it.
  95.         out     0x0a, al
  96.         mov     al, [dmamode]; 0x46 -> Read from floppy - 0x4A Write to floppy
  97.         out     0x0b, al
  98.         mov     al, 0
  99.         out     0x0c, al; reset the flip-flop to a known state.
  100.         mov     eax, 0xD000
  101.         out     0x04, al; set the channel 2 starting address to 0
  102.         shr     eax, 8
  103.         out     0x04, al
  104.         shr     eax, 8
  105.         out     0x81, al
  106.         mov     al, 0
  107.         out     0x0c, al; reset flip-flop
  108.         mov     al, 0xff;set count (actual size -1)
  109.         out     0x5, al
  110.         mov     al, 0x1;[dmasize]       ;(0x1ff = 511 / 0x23ff =9215)
  111.         out     0x5, al
  112.         mov     al, 2
  113.         out     0xa, al
  114.         popad
  115.         ret
  116.  
  117. ;***********************************
  118. ;* ЗАПИСАТЬ БАЙТ В ПОРТ ДАННЫХ FDC *
  119. ;* Параметры:                      *
  120. ;* AL - выводимый байт.            *
  121. ;***********************************
  122. FDCDataOutput:
  123. ;       DEBUGF 1,'K : FDCDataOutput(%x)',al
  124. ;        pusha
  125.         push    eax ecx edx
  126.         mov     AH, AL    ;запомнить байт в AH
  127. ; Сбросить переменную состояния контроллера
  128.         mov     [FDC_Status], FDC_Normal
  129. ; Проверить готовность контроллера к приему данных
  130.         mov     DX, 3F4h  ;(порт состояния FDC)
  131.         mov     ecx, 0x10000 ;установить счетчик тайм-аута
  132. @@TestRS:
  133.         in      AL, DX    ;прочитать регистр RS
  134.         and     AL, 0C0h  ;выделить разряды 6 и 7
  135.         cmp     AL, 80h   ;проверить разряды 6 и 7
  136.         je      @@OutByteToFDC
  137.         loop    @@TestRS
  138. ; Ошибка тайм-аута
  139. ;       DEBUGF 1,' timeout\n'
  140.         mov     [FDC_Status], FDC_TimeOut
  141.         jmp     @@End_5
  142. ; Вывести байт в порт данных
  143. @@OutByteToFDC:
  144.         inc     DX
  145.         mov     AL, AH
  146.         out     DX, AL
  147. ;        DEBUGF 1,' ok\n'
  148. @@End_5:
  149. ;        popa
  150.         pop     edx ecx eax
  151.         ret
  152.  
  153. ;******************************************
  154. ;*   ПРОЧИТАТЬ БАЙТ ИЗ ПОРТА ДАННЫХ FDC   *
  155. ;* Процедура не имеет входных параметров. *
  156. ;* Выходные данные:                       *
  157. ;* AL - считанный байт.                   *
  158. ;******************************************
  159. FDCDataInput:
  160.         push    ECX
  161.         push    DX
  162. ; Сбросить переменную состояния контроллера
  163.         mov     [FDC_Status], FDC_Normal
  164. ; Проверить готовность контроллера к передаче данных
  165.         mov     DX, 3F4h  ;(порт состояния FDC)
  166.         mov     ecx, 0x10000 ;установить счетчик тайм-аута
  167. @@TestRS_1:
  168.         in      AL, DX    ;прочитать регистр RS
  169.         and     AL, 0C0h  ;выдлить разряды 6 и 7
  170.         cmp     AL, 0C0h  ;проверить разряды 6 и 7
  171.         je      @@GetByteFromFDC
  172.         loop    @@TestRS_1
  173. ; Ошибка тайм-аута
  174. ;       DEBUGF 1,'K : FDCDataInput: timeout\n'
  175.         mov     [FDC_Status], FDC_TimeOut
  176.         jmp     @@End_6
  177. ; Ввести байт из порта данных
  178. @@GetByteFromFDC:
  179.         inc     DX
  180.         in      AL, DX
  181. ;       DEBUGF 1,'K : FDCDataInput: %x\n',al
  182. @@End_6:
  183.         pop     DX
  184.         pop     ECX
  185.         ret
  186.  
  187. ;*********************************************
  188. ;* ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
  189. ;*********************************************
  190. FDCInterrupt:
  191. ;       dbgstr 'FDCInterrupt'
  192. ; Установить флаг прерывания
  193.         mov     [FDD_IntFlag], 1
  194.         mov     al, 1
  195.         ret
  196.  
  197. ;*******************************************
  198. ;* ОЖИДАНИЕ ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
  199. ;*******************************************
  200. WaitFDCInterrupt:
  201.         pusha
  202. ; Сбросить байт состояния операции
  203.         mov     [FDC_Status], FDC_Normal
  204. ; Обнулить счетчик тиков
  205.         mov     eax, [timer_ticks]
  206.         mov     [TickCounter], eax
  207. ; Ожидать установки флага прерывания НГМД
  208. @@TestRS_2:
  209.         call    change_task
  210.         cmp     [FDD_IntFlag], 0
  211.         jnz     @@End_7           ;прерывание произошло
  212.         mov     eax, [timer_ticks]
  213.         sub     eax, [TickCounter]
  214.         cmp     eax, 200;50 ;25   ;5 ;ожидать 5 тиков
  215.         jb      @@TestRS_2
  216. ;        jl      @@TestRS_2
  217. ; Ошибка тайм-аута
  218. ;       dbgstr 'WaitFDCInterrupt: timeout'
  219.         mov     [FDC_Status], FDC_TimeOut
  220. @@End_7:
  221.         popa
  222.         ret
  223.  
  224. ;*********************************
  225. ;* ВКЛЮЧИТЬ МОТОР ДИСКОВОДА "A:" *
  226. ;*********************************
  227. FDDMotorON:
  228. ;       dbgstr 'FDDMotorON'
  229.         pusha
  230. ;        cmp     [fdd_motor_status],1
  231. ;        je      fdd_motor_on
  232.         mov     al, [flp_number]
  233.         cmp     [fdd_motor_status], al
  234.         je      fdd_motor_on
  235. ; Произвести сброс контроллера НГМД
  236.         mov     DX, 3F2h;порт управления двигателями
  237.         mov     AL, 0
  238.         out     DX, AL
  239. ; Выбрать и включить мотор дисковода
  240.         cmp     [flp_number], 1
  241.         jne     FDDMotorON_B
  242. ;        call    FDDMotorOFF_B
  243.         mov     AL, 1Ch   ; Floppy A
  244.         jmp     FDDMotorON_1
  245. FDDMotorON_B:
  246. ;        call    FDDMotorOFF_A
  247.         mov     AL, 2Dh   ; Floppy B
  248. FDDMotorON_1:
  249.         out     DX, AL
  250. ; Обнулить счетчик тиков
  251.         mov     eax, [timer_ticks]
  252.         mov     [TickCounter], eax
  253. ; Ожидать 0,5 с
  254. @@dT:
  255.         call    change_task
  256.         mov     eax, [timer_ticks]
  257.         sub     eax, [TickCounter]
  258.         cmp     eax, 50 ;10
  259.         jb      @@dT
  260. ; Read results of RESET command
  261.         push    4
  262. ;       DEBUGF 1,'K : floppy reset results:'
  263. @@:
  264.         mov     al, 8
  265.         call    FDCDataOutput
  266.         call    FDCDataInput
  267. ;       DEBUGF 1,' %x',al
  268.         call    FDCDataInput
  269. ;       DEBUGF 1,' %x',al
  270.         dec     dword [esp]
  271.         jnz     @b
  272. ;       DEBUGF 1,'\n'
  273.         pop     eax
  274.         cmp     [flp_number], 1
  275.         jne     fdd_motor_on_B
  276.         mov     [fdd_motor_status], 1
  277.         jmp     fdd_motor_on
  278. fdd_motor_on_B:
  279.         mov     [fdd_motor_status], 2
  280. fdd_motor_on:
  281.         call    save_timer_fdd_motor
  282.         popa
  283.         ret
  284.  
  285. ;*****************************************
  286. ;*  СОХРАНЕНИЕ УКАЗАТЕЛЯ ВРЕМЕНИ         *
  287. ;*****************************************
  288. save_timer_fdd_motor:
  289.         mov     eax, [timer_ticks]
  290.         mov     [timer_fdd_motor], eax
  291.         ret
  292.  
  293. ;*****************************************
  294. ;*  ПРОВЕРКА ЗАДЕРЖКИ ВЫКЛЮЧЕНИЯ МОТОРА  *
  295. ;*****************************************
  296. proc check_fdd_motor_status_has_work?
  297.         cmp     [fdd_motor_status], 0
  298.         jz      .no
  299.         mov     eax, [timer_ticks]
  300.         sub     eax, [timer_fdd_motor]
  301.         cmp     eax, 500
  302.         jb      .no
  303. .yes:
  304.         xor     eax, eax
  305.         inc     eax
  306.         ret
  307. .no:
  308.         xor     eax, eax
  309.         ret
  310. endp
  311.  
  312. align 4
  313. check_fdd_motor_status:
  314.         cmp     [fdd_motor_status], 0
  315.         je      end_check_fdd_motor_status_1
  316.         mov     eax, [timer_ticks]
  317.         sub     eax, [timer_fdd_motor]
  318.         cmp     eax, 500
  319.         jb      end_check_fdd_motor_status
  320.         call    FDDMotorOFF
  321.         mov     [fdd_motor_status], 0
  322. end_check_fdd_motor_status_1:
  323. end_check_fdd_motor_status:
  324.         ret
  325.  
  326. ;**********************************
  327. ;* ВЫКЛЮЧИТЬ МОТОР ДИСКОВОДА      *
  328. ;**********************************
  329. FDDMotorOFF:
  330. ;       dbgstr 'FDDMotorOFF'
  331.         push    AX
  332.         push    DX
  333.         cmp     [flp_number], 1
  334.         jne     FDDMotorOFF_1
  335.         call    FDDMotorOFF_A
  336.         jmp     FDDMotorOFF_2
  337. FDDMotorOFF_1:
  338.         call    FDDMotorOFF_B
  339. FDDMotorOFF_2:
  340.         pop     DX
  341.         pop     AX
  342.         ; сброс флагов кеширования в связи с устареванием информации
  343.         or      [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN
  344.         or      [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN
  345.         ret
  346.  
  347. FDDMotorOFF_A:
  348.         mov     DX, 3F2h;порт управления двигателями
  349.         mov     AL, 0Ch ; Floppy A
  350.         out     DX, AL
  351.         ret
  352.  
  353. FDDMotorOFF_B:
  354.         mov     DX, 3F2h;порт управления двигателями
  355.         mov     AL, 5h ; Floppy B
  356.         out     DX, AL
  357.         ret
  358.  
  359. ;*******************************
  360. ;* РЕКАЛИБРОВКА ДИСКОВОДА "A:" *
  361. ;*******************************
  362. RecalibrateFDD:
  363. ;       dbgstr 'RecalibrateFDD'
  364.         pusha
  365.         call    save_timer_fdd_motor
  366. ; Сбросить флаг прерывания
  367.         mov     [FDD_IntFlag], 0
  368. ; Подать команду "Рекалибровка"
  369.         mov     AL, 07h
  370.         call    FDCDataOutput
  371.         mov     AL, 00h
  372.         call    FDCDataOutput
  373. ; Ожидать завершения операции
  374.         call    WaitFDCInterrupt
  375.         cmp     [FDC_Status], 0
  376.         jne     .fail
  377. ; Read results of RECALIBRATE command
  378. ;       DEBUGF 1,'K : floppy recalibrate results:'
  379.         mov     al, 8
  380.         call    FDCDataOutput
  381.         call    FDCDataInput
  382. ;       DEBUGF 1,' %x',al
  383.         call    FDCDataInput
  384. ;       DEBUGF 1,' %x',al
  385. ;       DEBUGF 1,'\n'
  386. .fail:
  387.         call    save_timer_fdd_motor
  388.         popa
  389.         ret
  390.  
  391. ;*****************************************************
  392. ;*                    ПОИСК ДОРОЖКИ                  *
  393. ;* Параметры передаются через глобальные переменные: *
  394. ;* FDD_Track - номер дорожки (0-79);                 *
  395. ;* FDD_Head - номер головки (0-1).                   *
  396. ;* Результат операции заносится в FDC_Status.        *
  397. ;*****************************************************
  398. SeekTrack:
  399. ;       dbgstr 'SeekTrack'
  400.         pusha
  401.         call    save_timer_fdd_motor
  402. ; Сбросить флаг прерывания
  403.         mov     [FDD_IntFlag], 0
  404. ; Подать команду "Поиск"
  405.         mov     AL, 0Fh
  406.         call    FDCDataOutput
  407.         ; Передать байт номера головки/накопител
  408.         mov     AL, [FDD_Head]
  409.         shl     AL, 2
  410.         call    FDCDataOutput
  411.         ; Передать байт номера дорожки
  412.         mov     AL, [FDD_Track]
  413.         call    FDCDataOutput
  414. ; Ожидать завершения операции
  415.         call    WaitFDCInterrupt
  416.         cmp     [FDC_Status], FDC_Normal
  417.         jne     @@Exit
  418. ; Сохранить результат поиска
  419.         mov     AL, 08h
  420.         call    FDCDataOutput
  421.         call    FDCDataInput
  422.         mov     [FDC_ST0], AL
  423.         call    FDCDataInput
  424.         mov     [FDC_C], AL
  425. ; Проверить результат поиска
  426.         ; Поиск завершен?
  427.         test    [FDC_ST0], 100000b
  428.         je      @@Err
  429.         ; Заданный трек найден?
  430.         mov     AL, [FDC_C]
  431.         cmp     AL, [FDD_Track]
  432.         jne     @@Err
  433.         ; Номер головки совпадает с заданным?
  434. ; The H bit (Head Address) in ST0 will always return a "0" (c) 82077AA datasheet,
  435. ; description of SEEK command. So we can not verify the proper head.
  436. ;        mov     AL, [FDC_ST0]
  437. ;        and     AL, 100b
  438. ;        shr     AL, 2
  439. ;        cmp     AL, [FDD_Head]
  440. ;        jne     @@Err
  441.         ; Операция завершена успешно
  442. ;        dbgstr 'SeekTrack: FDC_Normal'
  443.         mov     [FDC_Status], FDC_Normal
  444.         jmp     @@Exit
  445. @@Err:  ; Трек не найден
  446. ;       dbgstr 'SeekTrack: FDC_TrackNotFound'
  447.         mov     [FDC_Status], FDC_TrackNotFound
  448. @@Exit:
  449.         call    save_timer_fdd_motor
  450.         popa
  451.         ret
  452.  
  453. ;*******************************************************
  454. ;*               ЧТЕНИЕ СЕКТОРА ДАННЫХ                 *
  455. ;* Параметры передаются через глобальные переменные:   *
  456. ;* FDD_Track - номер дорожки (0-79);                   *
  457. ;* FDD_Head - номер головки (0-1);                     *
  458. ;* FDD_Sector - номер сектора (1-18).                  *
  459. ;* Результат операции заносится в FDC_Status.          *
  460. ;* В случае успешного выполнения операции чтения       *
  461. ;* содержимое сектора будет занесено в FDD_DataBuffer. *
  462. ;*******************************************************
  463. ReadSector:
  464. ;       dbgstr 'ReadSector'
  465.         pushad
  466.         call    save_timer_fdd_motor
  467. ; Сбросить флаг прерывания
  468.         mov     [FDD_IntFlag], 0
  469. ; Установить скорость передачи 500 Кбайт/с
  470.         mov     AX, 0
  471.         mov     DX, 03F7h
  472.         out     DX, AL
  473. ; Инициализировать канал прямого доступа к памяти
  474.         mov     [dmamode], 0x46
  475.         call    Init_FDC_DMA
  476. ; Подать команду "Чтение данных"
  477.         mov     AL, 0E6h ;чтение в мультитрековом режиме
  478.         call    FDCDataOutput
  479.         mov     AL, [FDD_Head]
  480.         shl     AL, 2
  481.         call    FDCDataOutput
  482.         mov     AL, [FDD_Track]
  483.         call    FDCDataOutput
  484.         mov     AL, [FDD_Head]
  485.         call    FDCDataOutput
  486.         mov     AL, [FDD_Sector]
  487.         call    FDCDataOutput
  488.         mov     AL, 2   ;код размера сектора (512 байт)
  489.         call    FDCDataOutput
  490.         mov     AL, 18 ;+1; 3Fh  ;число секторов на дорожке
  491.         call    FDCDataOutput
  492.         mov     AL, 1Bh ;значение GPL
  493.         call    FDCDataOutput
  494.         mov     AL, 0FFh;значение DTL
  495.         call    FDCDataOutput
  496. ; Ожидаем прерывание по завершении операции
  497.         call    WaitFDCInterrupt
  498.         cmp     [FDC_Status], FDC_Normal
  499.         jne     @@Exit_1
  500. ; Считываем статус завершения операции
  501.         call    GetStatusInfo
  502.         test    [FDC_ST0], 11011000b
  503.         jnz     @@Err_1
  504. ;        dbgstr 'ReadSector: FDC_Normal'
  505.         mov     [FDC_Status], FDC_Normal
  506.         jmp     @@Exit_1
  507. @@Err_1:
  508. ;       dbgstr 'ReadSector: FDC_SectorNotFound'
  509.         mov     [FDC_Status], FDC_SectorNotFound
  510. @@Exit_1:
  511.         call    save_timer_fdd_motor
  512.         popad
  513.         ret
  514.  
  515. ;*******************************************************
  516. ;*   ЧТЕНИЕ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
  517. ;* Параметры передаются через глобальные переменные:   *
  518. ;* FDD_Track - номер дорожки (0-79);                   *
  519. ;* FDD_Head - номер головки (0-1);                     *
  520. ;* FDD_Sector - номер сектора (1-18).                  *
  521. ;* Результат операции заносится в FDC_Status.          *
  522. ;* В случае успешного выполнения операции чтения       *
  523. ;* содержимое сектора будет занесено в FDD_DataBuffer. *
  524. ;*******************************************************
  525. ReadSectWithRetr:
  526.         pusha
  527. ; Обнулить счетчик повторения операции рекалибровки
  528.         mov     [RecalRepCounter], 0
  529. @@TryAgain:
  530. ; Обнулить счетчик повторения операции чтени
  531.         mov     [ReadRepCounter], 0
  532. @@ReadSector_1:
  533.         call    ReadSector
  534.         cmp     [FDC_Status], 0
  535.         je      @@Exit_2
  536.         cmp     [FDC_Status], 1
  537.         je      @@Err_3
  538.         ; Троекратное повторение чтени
  539.         inc     [ReadRepCounter]
  540.         cmp     [ReadRepCounter], 3
  541.         jb      @@ReadSector_1
  542.         ; Троекратное повторение рекалибровки
  543.         call    RecalibrateFDD
  544.         call    SeekTrack
  545.         inc     [RecalRepCounter]
  546.         cmp     [RecalRepCounter], 3
  547.         jb      @@TryAgain
  548. @@Exit_2:
  549.         popa
  550.         ret
  551. @@Err_3:
  552.         popa
  553.         ret
  554.  
  555. ;*******************************************************
  556. ;*               ЗАПИСЬ СЕКТОРА ДАННЫХ                 *
  557. ;* Параметры передаются через глобальные переменные:   *
  558. ;* FDD_Track - номер дорожки (0-79);                   *
  559. ;* FDD_Head - номер головки (0-1);                     *
  560. ;* FDD_Sector - номер сектора (1-18).                  *
  561. ;* Результат операции заносится в FDC_Status.          *
  562. ;* В случае успешного выполнения операции записи       *
  563. ;* содержимое FDD_DataBuffer будет занесено в сектор.  *
  564. ;*******************************************************
  565. WriteSector:
  566. ;       dbgstr 'WriteSector'
  567.         pushad
  568.         call    save_timer_fdd_motor
  569. ; Сбросить флаг прерывания
  570.         mov     [FDD_IntFlag], 0
  571. ; Установить скорость передачи 500 Кбайт/с
  572.         mov     AX, 0
  573.         mov     DX, 03F7h
  574.         out     DX, AL
  575. ; Инициализировать канал прямого доступа к памяти
  576.         mov     [dmamode], 0x4A
  577.         call    Init_FDC_DMA
  578. ; Подать команду "Запись данных"
  579.         mov     AL, 0xC5 ;0x45  ;запись в мультитрековом режиме
  580.         call    FDCDataOutput
  581.         mov     AL, [FDD_Head]
  582.         shl     AL, 2
  583.         call    FDCDataOutput
  584.         mov     AL, [FDD_Track]
  585.         call    FDCDataOutput
  586.         mov     AL, [FDD_Head]
  587.         call    FDCDataOutput
  588.         mov     AL, [FDD_Sector]
  589.         call    FDCDataOutput
  590.         mov     AL, 2   ;код размера сектора (512 байт)
  591.         call    FDCDataOutput
  592.         mov     AL, 18; 3Fh  ;число секторов на дорожке
  593.         call    FDCDataOutput
  594.         mov     AL, 1Bh ;значение GPL
  595.         call    FDCDataOutput
  596.         mov     AL, 0FFh;значение DTL
  597.         call    FDCDataOutput
  598. ; Ожидаем прерывание по завершении операции
  599.         call    WaitFDCInterrupt
  600.         cmp     [FDC_Status], FDC_Normal
  601.         jne     @@Exit_3
  602. ; Считываем статус завершения операции
  603.         call    GetStatusInfo
  604.         test    [FDC_ST0], 11000000b ;11011000b
  605.         jnz     @@Err_2
  606.         mov     [FDC_Status], FDC_Normal
  607.         jmp     @@Exit_3
  608. @@Err_2:
  609.         mov     [FDC_Status], FDC_SectorNotFound
  610. @@Exit_3:
  611.         call    save_timer_fdd_motor
  612.         popad
  613.         ret
  614.  
  615. ;*******************************************************
  616. ;*   ЗАПИСЬ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
  617. ;* Параметры передаются через глобальные переменные:   *
  618. ;* FDD_Track - номер дорожки (0-79);                   *
  619. ;* FDD_Head - номер головки (0-1);                     *
  620. ;* FDD_Sector - номер сектора (1-18).                  *
  621. ;* Результат операции заносится в FDC_Status.          *
  622. ;* В случае успешного выполнения операции записи       *
  623. ;* содержимое FDD_DataBuffer будет занесено в сектор.  *
  624. ;*******************************************************
  625. WriteSectWithRetr:
  626.         pusha
  627. ; Обнулить счетчик повторения операции рекалибровки
  628.         mov     [RecalRepCounter], 0
  629. @@TryAgain_1:
  630. ; Обнулить счетчик повторения операции чтени
  631.         mov     [ReadRepCounter], 0
  632. @@WriteSector_1:
  633.         call    WriteSector
  634.         cmp     [FDC_Status], 0
  635.         je      @@Exit_4
  636.         cmp     [FDC_Status], 1
  637.         je      @@Err_4
  638.         ; Троекратное повторение чтени
  639.         inc     [ReadRepCounter]
  640.         cmp     [ReadRepCounter], 3
  641.         jb      @@WriteSector_1
  642.         ; Троекратное повторение рекалибровки
  643.         call    RecalibrateFDD
  644.         call    SeekTrack
  645.         inc     [RecalRepCounter]
  646.         cmp     [RecalRepCounter], 3
  647.         jb      @@TryAgain_1
  648. @@Exit_4:
  649.         popa
  650.         ret
  651. @@Err_4:
  652.         popa
  653.         ret
  654.  
  655. ;*********************************************
  656. ;* ПОЛУЧИТЬ ИНФОРМАЦИЮ О РЕЗУЛЬТАТЕ ОПЕРАЦИИ *
  657. ;*********************************************
  658. GetStatusInfo:
  659.         push    AX
  660.         call    FDCDataInput
  661.         mov     [FDC_ST0], AL
  662.         call    FDCDataInput
  663.         mov     [FDC_ST1], AL
  664.         call    FDCDataInput
  665.         mov     [FDC_ST2], AL
  666.         call    FDCDataInput
  667.         mov     [FDC_C], AL
  668.         call    FDCDataInput
  669.         mov     [FDC_H], AL
  670.         call    FDCDataInput
  671.         mov     [FDC_R], AL
  672.         call    FDCDataInput
  673.         mov     [FDC_N], AL
  674.         pop     AX
  675.         ret
  676.  
  677. ; Interface for disk subsystem.
  678. ; Assume fixed capacity for 1.44M.
  679. FLOPPY_CAPACITY = 2880  ; in sectors
  680.  
  681. iglobal
  682. align 4
  683. floppy_functions:
  684.         dd      .size
  685.         dd      0       ; no close() function
  686.         dd      0       ; no closemedia() function
  687.         dd      floppy_querymedia
  688.         dd      floppy_read
  689.         dd      floppy_write
  690.         dd      0       ; no flush() function
  691.         dd      0       ; no adjust_cache_size() function
  692. .size = $ - floppy_functions
  693. endg
  694.  
  695. uglobal
  696. floppy_media_flags      rb      2
  697. n_sector    dd 0  ; temporary save for sector value
  698. flp_number  db 0  ; 1- Floppy A, 2-Floppy B
  699. old_track   db 0  ; old value track
  700. flp_label   rb 15*2 ; Label and ID of inserted floppy disk
  701. align 4
  702. ; Hardware does not allow to work with two floppies in parallel,
  703. ; so there is one mutex guarding access to any floppy.
  704. floppy_mutex    MUTEX
  705. endg
  706. ; Meaning of bits in floppy_media_flags
  707. FLOPPY_MEDIA_PRESENT = 1        ; media was present when last asked
  708. FLOPPY_MEDIA_NEED_RESCAN = 2    ; media was possibly changed, need to rescan
  709. FLOPPY_MEDIA_LABEL_CHANGED = 4  ; temporary state
  710.  
  711. iglobal
  712. floppy1_name    db      'fd',0
  713. floppy2_name    db      'fd2',0
  714. endg
  715.  
  716. ; This function is called in boot process.
  717. ; It creates filesystems /fd and/or /fd2, if the system has one/two floppy drives.
  718. proc floppy_init
  719.         mov     ecx, floppy_mutex
  720.         call    mutex_init
  721. ; First floppy is present if [DRIVE_DATA] and 0xF0 is nonzero.
  722.         test    byte [DRIVE_DATA], 0xF0
  723.         jz      .no1
  724.         stdcall disk_add, floppy_functions, floppy1_name, 1, DISK_NO_INSERT_NOTIFICATION
  725. .no1:
  726. ; Second floppy is present if [DRIVE_DATA] and 0x0F is nonzero.
  727.         test    byte [DRIVE_DATA], 0x0F
  728.         jz      .no2
  729.         stdcall disk_add, floppy_functions, floppy2_name, 2, DISK_NO_INSERT_NOTIFICATION
  730. .no2:
  731.         ret
  732. endp
  733.  
  734. ; Returns information about disk media.
  735. ; Floppy drives do not support insert notifications,
  736. ; DISK_NO_INSERT_NOTIFICATION is set,
  737. ; the disk subsystem calls this function before each filesystem operation.
  738. ; If the media has changed, return error for the first call as signal
  739. ; to finalize work with old media and the true geometry for the second call.
  740. ; Assume that media is (possibly) changed anytime when motor is off.
  741. proc floppy_querymedia
  742.   virtual at esp+4
  743.     .userdata dd ?
  744.     .info dd ?
  745.   end virtual
  746. ; 1. Acquire the global lock.
  747.         mov     ecx, floppy_mutex
  748.         call    mutex_lock
  749.         mov     edx, [.userdata]        ; 1 for /fd, 2 for /fd2
  750. ; 2. If the media was reported and has been changed, forget it and report an error.
  751.         mov     al, [floppy_media_flags+edx-1]
  752.         and     al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
  753.         cmp     al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
  754.         jnz     .not_reported
  755. .no_media:
  756.         mov     [floppy_media_flags+edx-1], 0
  757. .return_no_media:
  758.         mov     ecx, floppy_mutex
  759.         call    mutex_unlock
  760.         mov     eax, DISK_STATUS_NO_MEDIA
  761.         retn    8
  762. .not_reported:
  763. ; 3. If we are in the temporary state LABEL_CHANGED, this is the second call
  764. ; after intermediate DISK_STATUS_NO_MEDIA due to media change;
  765. ; clear the flag and return the current geometry without rereading the bootsector.
  766.         cmp     [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
  767.         jz      .report_geometry
  768. ; 4. Try to read the bootsector.
  769.         mov     [flp_number], dl
  770.         mov     [FDC_Status], 0
  771.         call    floppy_read_bootsector
  772. ; 5. If reading bootsector failed, assume that media is not present.
  773.         mov     edx, [.userdata]
  774.         cmp     [FDC_Status], 0
  775.         jnz     .no_media
  776. ; 6. Check whether the previous status is "present". If not, go to 10.
  777.         push    esi edi
  778.         imul    edi, edx, 15
  779.         add     edi, flp_label-15
  780.         mov     esi, FDD_BUFF+39
  781.         mov     ecx, 15
  782.         test    [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
  783.         jz      .set_label
  784. ; 7. Compare the old label with the current one.
  785.         rep cmpsb
  786. ; 8. If the label has not changed, go to 11.
  787.         jz      .ok
  788. ; 9. If the label has changed, store it, enter temporary state LABEL_CHANGED
  789. ; and report DISK_STATUS_NO_MEDIA.
  790. ;       dbgstr 'floppy label changed'
  791.         add     esi, ecx
  792.         add     edi, ecx
  793.         mov     ecx, 15
  794.         sub     esi, ecx
  795.         sub     edi, ecx
  796.         rep movsb
  797.         mov     [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
  798.         pop     edi esi
  799.         jmp     .return_no_media
  800. .set_label:
  801. ; 10. The previous state was "not present". Copy the label.
  802.         rep movsb
  803. .ok:
  804.         pop     edi esi
  805. .report_geometry:
  806. ; 11. Fill DISKMEDIAINFO structure.
  807.         mov     ecx, [.info]
  808.         and     [ecx+DISKMEDIAINFO.Flags], 0
  809.         mov     [ecx+DISKMEDIAINFO.SectorSize], 512
  810.         mov     dword [ecx+DISKMEDIAINFO.Capacity], FLOPPY_CAPACITY
  811.         and     dword [ecx+DISKMEDIAINFO.Capacity+4], 0
  812. ; 12. Update state: media is present, data are actual.
  813.         mov     [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
  814. ; 13. Release the global lock and return successful status.
  815.         mov     ecx, floppy_mutex
  816.         call    mutex_unlock
  817.         xor     eax, eax
  818.         retn    8
  819. endp
  820.  
  821. proc floppy_read_bootsector
  822.         pushad
  823.         mov     [FDD_Track], 0; Цилиндр
  824.         mov     [FDD_Head], 0; Сторона
  825.         mov     [FDD_Sector], 1; Сектор
  826.         call    FDDMotorON
  827.         call    RecalibrateFDD
  828.         cmp     [FDC_Status], 0
  829.         jne     .nothing
  830.         call    SeekTrack
  831.         cmp     [FDC_Status], 0
  832.         jne     .nothing
  833.         call    ReadSectWithRetr
  834. .nothing:
  835.         popad
  836.         ret
  837. endp
  838.  
  839. read_chs_sector:
  840.         call    calculate_chs
  841.         call    ReadSectWithRetr
  842.         ret
  843.  
  844. save_chs_sector:
  845.         call    calculate_chs
  846.         call    WriteSectWithRetr
  847.         ret
  848.  
  849. calculate_chs:
  850.         mov     bl, [FDD_Track]
  851.         mov     [old_track], bl
  852.         mov     ebx, 18
  853.         xor     edx, edx
  854.         div     ebx
  855.         inc     edx
  856.         mov     [FDD_Sector], dl
  857.         mov     edx, eax
  858.         shr     eax, 1
  859.         and     edx, 1
  860.         mov     [FDD_Track], al
  861.         mov     [FDD_Head], dl
  862.         mov     dl, [old_track]
  863.         cmp     dl, [FDD_Track]
  864.         je      no_seek_track_1
  865.         call    SeekTrack
  866. no_seek_track_1:
  867.         ret
  868.  
  869. ; Writes one or more sectors to the device.
  870. proc floppy_write
  871.         mov     dl, 1
  872.         jmp     floppy_read_write
  873. endp
  874.  
  875. ; Reads one or more sectors from the device.
  876. proc floppy_read
  877.         mov     dl, 0
  878. endp
  879.  
  880. ; Common part of floppy_read and floppy_write.
  881. proc floppy_read_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
  882. virtual at ebp-8
  883. .sectors_todo   dd      ?
  884. .operation      db      ?
  885. end virtual
  886.         push    edx             ; save operation code to [.operation]
  887. ; 1. Get number of sectors to read/write
  888. ; and zero number of sectors that were actually read/written.
  889.         mov     eax, [numsectors_ptr]
  890.         push    dword [eax]     ; initialize [.sectors_todo]
  891.         and     dword [eax], 0
  892.         push    ebx esi edi     ; save used registers to be stdcall
  893. ; 2. Acquire the global lock.
  894.         mov     ecx, floppy_mutex
  895.         call    mutex_lock
  896. ; 3. Set floppy number for this operation.
  897.         mov     edx, [userdata]
  898.         mov     [flp_number], dl
  899. ; 4. Read/write sector-by-sector.
  900. .operation_loop:
  901. ; 4a. Check that the sector is inside the media.
  902.         cmp     dword [start_sector+4], 0
  903.         jnz     .end_of_media
  904.         mov     eax, dword [start_sector]
  905.         cmp     eax, FLOPPY_CAPACITY
  906.         jae     .end_of_media
  907. ; 4b. For read operation, call read_chs_sector and then move data from FDD_BUFF to [buffer].
  908. ; For write operation, move data from [buffer] to FDD_BUFF and then call save_chs_sector.
  909.         cmp     [.operation], 0
  910.         jz      .read
  911.         mov     esi, [buffer]
  912.         mov     edi, FDD_BUFF
  913.         mov     ecx, 512/4
  914.         rep movsd
  915.         mov     [buffer], esi
  916.         call    save_chs_sector
  917.         jmp     @f
  918. .read:
  919.         call    read_chs_sector
  920.         mov     esi, FDD_BUFF
  921.         mov     edi, [buffer]
  922.         mov     ecx, 512/4
  923.         rep movsd
  924.         mov     [buffer], edi
  925. @@:
  926. ; 4c. If there was an error, propagate it to the caller.
  927.         cmp     [FDC_Status], 0
  928.         jnz     .fail
  929. ; 4d. Otherwise, increment number of sectors processed and continue the loop.
  930.         mov     eax, [numsectors_ptr]
  931.         inc     dword [eax]
  932.         inc     dword [start_sector]
  933.         dec     [.sectors_todo]
  934.         jnz     .operation_loop
  935. ; 5. Release the global lock and return with the correct status.
  936.         push    0
  937. .return:
  938.         mov     ecx, floppy_mutex
  939.         call    mutex_unlock
  940.         pop     eax
  941.         pop     edi esi ebx     ; restore used registers to be stdcall
  942.         ret     ; this translates to leave/retn N and purges local variables
  943. .fail:
  944.         push    -1
  945.         jmp     .return
  946. .end_of_media:
  947.         push    DISK_STATUS_END_OF_MEDIA
  948.         jmp     .return
  949. endp
  950.