Subversion Repositories Kolibri OS

Rev

Rev 4429 | Blame | Compare with Previous | 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.         push    eax
  383. ;       DEBUGF 1,' %x',al
  384.         call    FDCDataInput
  385. ;       DEBUGF 1,' %x',al
  386. ;       DEBUGF 1,'\n'
  387.         pop     eax
  388.         test    al, 0xC0
  389.         jz      @f
  390.         mov     [FDC_Status], FDC_DiskNotFound
  391. @@:
  392. .fail:
  393.         call    save_timer_fdd_motor
  394.         popa
  395.         ret
  396.  
  397. ;*****************************************************
  398. ;*                    ПОИСК ДОРОЖКИ                  *
  399. ;* Параметры передаются через глобальные переменные: *
  400. ;* FDD_Track - номер дорожки (0-79);                 *
  401. ;* FDD_Head - номер головки (0-1).                   *
  402. ;* Результат операции заносится в FDC_Status.        *
  403. ;*****************************************************
  404. SeekTrack:
  405. ;       dbgstr 'SeekTrack'
  406.         pusha
  407.         call    save_timer_fdd_motor
  408. ; Сбросить флаг прерывания
  409.         mov     [FDD_IntFlag], 0
  410. ; Подать команду "Поиск"
  411.         mov     AL, 0Fh
  412.         call    FDCDataOutput
  413.         ; Передать байт номера головки/накопител
  414.         mov     AL, [FDD_Head]
  415.         shl     AL, 2
  416.         call    FDCDataOutput
  417.         ; Передать байт номера дорожки
  418.         mov     AL, [FDD_Track]
  419.         call    FDCDataOutput
  420. ; Ожидать завершения операции
  421.         call    WaitFDCInterrupt
  422.         cmp     [FDC_Status], FDC_Normal
  423.         jne     @@Exit
  424. ; Сохранить результат поиска
  425.         mov     AL, 08h
  426.         call    FDCDataOutput
  427.         call    FDCDataInput
  428.         mov     [FDC_ST0], AL
  429.         call    FDCDataInput
  430.         mov     [FDC_C], AL
  431. ; Проверить результат поиска
  432.         ; Поиск завершен?
  433.         test    [FDC_ST0], 100000b
  434.         je      @@Err
  435.         ; Заданный трек найден?
  436.         mov     AL, [FDC_C]
  437.         cmp     AL, [FDD_Track]
  438.         jne     @@Err
  439.         ; Номер головки совпадает с заданным?
  440. ; The H bit (Head Address) in ST0 will always return a "0" (c) 82077AA datasheet,
  441. ; description of SEEK command. So we can not verify the proper head.
  442. ;        mov     AL, [FDC_ST0]
  443. ;        and     AL, 100b
  444. ;        shr     AL, 2
  445. ;        cmp     AL, [FDD_Head]
  446. ;        jne     @@Err
  447.         ; Операция завершена успешно
  448. ;        dbgstr 'SeekTrack: FDC_Normal'
  449.         mov     [FDC_Status], FDC_Normal
  450.         jmp     @@Exit
  451. @@Err:  ; Трек не найден
  452. ;       dbgstr 'SeekTrack: FDC_TrackNotFound'
  453.         mov     [FDC_Status], FDC_TrackNotFound
  454. @@Exit:
  455.         call    save_timer_fdd_motor
  456.         popa
  457.         ret
  458.  
  459. ;*******************************************************
  460. ;*               ЧТЕНИЕ СЕКТОРА ДАННЫХ                 *
  461. ;* Параметры передаются через глобальные переменные:   *
  462. ;* FDD_Track - номер дорожки (0-79);                   *
  463. ;* FDD_Head - номер головки (0-1);                     *
  464. ;* FDD_Sector - номер сектора (1-18).                  *
  465. ;* Результат операции заносится в FDC_Status.          *
  466. ;* В случае успешного выполнения операции чтения       *
  467. ;* содержимое сектора будет занесено в FDD_DataBuffer. *
  468. ;*******************************************************
  469. ReadSector:
  470. ;       dbgstr 'ReadSector'
  471.         pushad
  472.         call    save_timer_fdd_motor
  473. ; Сбросить флаг прерывания
  474.         mov     [FDD_IntFlag], 0
  475. ; Установить скорость передачи 500 Кбайт/с
  476.         mov     AX, 0
  477.         mov     DX, 03F7h
  478.         out     DX, AL
  479. ; Инициализировать канал прямого доступа к памяти
  480.         mov     [dmamode], 0x46
  481.         call    Init_FDC_DMA
  482. ; Подать команду "Чтение данных"
  483.         mov     AL, 0E6h ;чтение в мультитрековом режиме
  484.         call    FDCDataOutput
  485.         mov     AL, [FDD_Head]
  486.         shl     AL, 2
  487.         call    FDCDataOutput
  488.         mov     AL, [FDD_Track]
  489.         call    FDCDataOutput
  490.         mov     AL, [FDD_Head]
  491.         call    FDCDataOutput
  492.         mov     AL, [FDD_Sector]
  493.         call    FDCDataOutput
  494.         mov     AL, 2   ;код размера сектора (512 байт)
  495.         call    FDCDataOutput
  496.         mov     AL, 18 ;+1; 3Fh  ;число секторов на дорожке
  497.         call    FDCDataOutput
  498.         mov     AL, 1Bh ;значение GPL
  499.         call    FDCDataOutput
  500.         mov     AL, 0FFh;значение DTL
  501.         call    FDCDataOutput
  502. ; Ожидаем прерывание по завершении операции
  503.         call    WaitFDCInterrupt
  504.         cmp     [FDC_Status], FDC_Normal
  505.         jne     @@Exit_1
  506. ; Считываем статус завершения операции
  507.         call    GetStatusInfo
  508.         test    [FDC_ST0], 11011000b
  509.         jnz     @@Err_1
  510. ;        dbgstr 'ReadSector: FDC_Normal'
  511.         mov     [FDC_Status], FDC_Normal
  512.         jmp     @@Exit_1
  513. @@Err_1:
  514. ;       dbgstr 'ReadSector: FDC_SectorNotFound'
  515.         mov     [FDC_Status], FDC_SectorNotFound
  516. @@Exit_1:
  517.         call    save_timer_fdd_motor
  518.         popad
  519.         ret
  520.  
  521. ;*******************************************************
  522. ;*   ЧТЕНИЕ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
  523. ;* Параметры передаются через глобальные переменные:   *
  524. ;* FDD_Track - номер дорожки (0-79);                   *
  525. ;* FDD_Head - номер головки (0-1);                     *
  526. ;* FDD_Sector - номер сектора (1-18).                  *
  527. ;* Результат операции заносится в FDC_Status.          *
  528. ;* В случае успешного выполнения операции чтения       *
  529. ;* содержимое сектора будет занесено в FDD_DataBuffer. *
  530. ;*******************************************************
  531. ReadSectWithRetr:
  532.         pusha
  533. ; Обнулить счетчик повторения операции рекалибровки
  534.         mov     [RecalRepCounter], 0
  535. @@TryAgain:
  536. ; Обнулить счетчик повторения операции чтени
  537.         mov     [ReadRepCounter], 0
  538. @@ReadSector_1:
  539.         call    ReadSector
  540.         cmp     [FDC_Status], 0
  541.         je      @@Exit_2
  542.         cmp     [FDC_Status], 1
  543.         je      @@Err_3
  544.         ; Троекратное повторение чтени
  545.         inc     [ReadRepCounter]
  546.         cmp     [ReadRepCounter], 3
  547.         jb      @@ReadSector_1
  548.         ; Троекратное повторение рекалибровки
  549.         call    RecalibrateFDD
  550.         call    SeekTrack
  551.         inc     [RecalRepCounter]
  552.         cmp     [RecalRepCounter], 3
  553.         jb      @@TryAgain
  554. @@Exit_2:
  555.         popa
  556.         ret
  557. @@Err_3:
  558.         popa
  559.         ret
  560.  
  561. ;*******************************************************
  562. ;*               ЗАПИСЬ СЕКТОРА ДАННЫХ                 *
  563. ;* Параметры передаются через глобальные переменные:   *
  564. ;* FDD_Track - номер дорожки (0-79);                   *
  565. ;* FDD_Head - номер головки (0-1);                     *
  566. ;* FDD_Sector - номер сектора (1-18).                  *
  567. ;* Результат операции заносится в FDC_Status.          *
  568. ;* В случае успешного выполнения операции записи       *
  569. ;* содержимое FDD_DataBuffer будет занесено в сектор.  *
  570. ;*******************************************************
  571. WriteSector:
  572. ;       dbgstr 'WriteSector'
  573.         pushad
  574.         call    save_timer_fdd_motor
  575. ; Сбросить флаг прерывания
  576.         mov     [FDD_IntFlag], 0
  577. ; Установить скорость передачи 500 Кбайт/с
  578.         mov     AX, 0
  579.         mov     DX, 03F7h
  580.         out     DX, AL
  581. ; Инициализировать канал прямого доступа к памяти
  582.         mov     [dmamode], 0x4A
  583.         call    Init_FDC_DMA
  584. ; Подать команду "Запись данных"
  585.         mov     AL, 0xC5 ;0x45  ;запись в мультитрековом режиме
  586.         call    FDCDataOutput
  587.         mov     AL, [FDD_Head]
  588.         shl     AL, 2
  589.         call    FDCDataOutput
  590.         mov     AL, [FDD_Track]
  591.         call    FDCDataOutput
  592.         mov     AL, [FDD_Head]
  593.         call    FDCDataOutput
  594.         mov     AL, [FDD_Sector]
  595.         call    FDCDataOutput
  596.         mov     AL, 2   ;код размера сектора (512 байт)
  597.         call    FDCDataOutput
  598.         mov     AL, 18; 3Fh  ;число секторов на дорожке
  599.         call    FDCDataOutput
  600.         mov     AL, 1Bh ;значение GPL
  601.         call    FDCDataOutput
  602.         mov     AL, 0FFh;значение DTL
  603.         call    FDCDataOutput
  604. ; Ожидаем прерывание по завершении операции
  605.         call    WaitFDCInterrupt
  606.         cmp     [FDC_Status], FDC_Normal
  607.         jne     @@Exit_3
  608. ; Считываем статус завершения операции
  609.         call    GetStatusInfo
  610.         test    [FDC_ST0], 11000000b ;11011000b
  611.         jnz     @@Err_2
  612.         mov     [FDC_Status], FDC_Normal
  613.         jmp     @@Exit_3
  614. @@Err_2:
  615.         mov     [FDC_Status], FDC_SectorNotFound
  616. @@Exit_3:
  617.         call    save_timer_fdd_motor
  618.         popad
  619.         ret
  620.  
  621. ;*******************************************************
  622. ;*   ЗАПИСЬ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
  623. ;* Параметры передаются через глобальные переменные:   *
  624. ;* FDD_Track - номер дорожки (0-79);                   *
  625. ;* FDD_Head - номер головки (0-1);                     *
  626. ;* FDD_Sector - номер сектора (1-18).                  *
  627. ;* Результат операции заносится в FDC_Status.          *
  628. ;* В случае успешного выполнения операции записи       *
  629. ;* содержимое FDD_DataBuffer будет занесено в сектор.  *
  630. ;*******************************************************
  631. WriteSectWithRetr:
  632.         pusha
  633. ; Обнулить счетчик повторения операции рекалибровки
  634.         mov     [RecalRepCounter], 0
  635. @@TryAgain_1:
  636. ; Обнулить счетчик повторения операции чтени
  637.         mov     [ReadRepCounter], 0
  638. @@WriteSector_1:
  639.         call    WriteSector
  640.         cmp     [FDC_Status], 0
  641.         je      @@Exit_4
  642.         cmp     [FDC_Status], 1
  643.         je      @@Err_4
  644.         ; Троекратное повторение чтени
  645.         inc     [ReadRepCounter]
  646.         cmp     [ReadRepCounter], 3
  647.         jb      @@WriteSector_1
  648.         ; Троекратное повторение рекалибровки
  649.         call    RecalibrateFDD
  650.         call    SeekTrack
  651.         inc     [RecalRepCounter]
  652.         cmp     [RecalRepCounter], 3
  653.         jb      @@TryAgain_1
  654. @@Exit_4:
  655.         popa
  656.         ret
  657. @@Err_4:
  658.         popa
  659.         ret
  660.  
  661. ;*********************************************
  662. ;* ПОЛУЧИТЬ ИНФОРМАЦИЮ О РЕЗУЛЬТАТЕ ОПЕРАЦИИ *
  663. ;*********************************************
  664. GetStatusInfo:
  665.         push    AX
  666.         call    FDCDataInput
  667.         mov     [FDC_ST0], AL
  668.         call    FDCDataInput
  669.         mov     [FDC_ST1], AL
  670.         call    FDCDataInput
  671.         mov     [FDC_ST2], AL
  672.         call    FDCDataInput
  673.         mov     [FDC_C], AL
  674.         call    FDCDataInput
  675.         mov     [FDC_H], AL
  676.         call    FDCDataInput
  677.         mov     [FDC_R], AL
  678.         call    FDCDataInput
  679.         mov     [FDC_N], AL
  680.         pop     AX
  681.         ret
  682.  
  683. ; Interface for disk subsystem.
  684. ; Assume fixed capacity for 1.44M.
  685. FLOPPY_CAPACITY = 2880  ; in sectors
  686.  
  687. iglobal
  688. align 4
  689. floppy_functions:
  690.         dd      .size
  691.         dd      0       ; no close() function
  692.         dd      0       ; no closemedia() function
  693.         dd      floppy_querymedia
  694.         dd      floppy_read
  695.         dd      floppy_write
  696.         dd      0       ; no flush() function
  697.         dd      0       ; no adjust_cache_size() function
  698. .size = $ - floppy_functions
  699. endg
  700.  
  701. uglobal
  702. floppy_media_flags      rb      2
  703. n_sector    dd 0  ; temporary save for sector value
  704. flp_number  db 0  ; 1- Floppy A, 2-Floppy B
  705. old_track   db 0  ; old value track
  706. flp_label   rb 15*2 ; Label and ID of inserted floppy disk
  707. align 4
  708. ; Hardware does not allow to work with two floppies in parallel,
  709. ; so there is one mutex guarding access to any floppy.
  710. floppy_mutex    MUTEX
  711. endg
  712. ; Meaning of bits in floppy_media_flags
  713. FLOPPY_MEDIA_PRESENT = 1        ; media was present when last asked
  714. FLOPPY_MEDIA_NEED_RESCAN = 2    ; media was possibly changed, need to rescan
  715. FLOPPY_MEDIA_LABEL_CHANGED = 4  ; temporary state
  716.  
  717. iglobal
  718. floppy1_name    db      'fd',0
  719. floppy2_name    db      'fd2',0
  720. endg
  721.  
  722. ; This function is called in boot process.
  723. ; It creates filesystems /fd and/or /fd2, if the system has one/two floppy drives.
  724. proc floppy_init
  725.         mov     ecx, floppy_mutex
  726.         call    mutex_init
  727. ; First floppy is present if [DRIVE_DATA] and 0xF0 is nonzero.
  728.         test    byte [DRIVE_DATA], 0xF0
  729.         jz      .no1
  730.         stdcall disk_add, floppy_functions, floppy1_name, 1, DISK_NO_INSERT_NOTIFICATION
  731. .no1:
  732. ; Second floppy is present if [DRIVE_DATA] and 0x0F is nonzero.
  733.         test    byte [DRIVE_DATA], 0x0F
  734.         jz      .no2
  735.         stdcall disk_add, floppy_functions, floppy2_name, 2, DISK_NO_INSERT_NOTIFICATION
  736. .no2:
  737.         ret
  738. endp
  739.  
  740. ; Returns information about disk media.
  741. ; Floppy drives do not support insert notifications,
  742. ; DISK_NO_INSERT_NOTIFICATION is set,
  743. ; the disk subsystem calls this function before each filesystem operation.
  744. ; If the media has changed, return error for the first call as signal
  745. ; to finalize work with old media and the true geometry for the second call.
  746. ; Assume that media is (possibly) changed anytime when motor is off.
  747. proc floppy_querymedia
  748.   virtual at esp+4
  749.     .userdata dd ?
  750.     .info dd ?
  751.   end virtual
  752. ; 1. Acquire the global lock.
  753.         mov     ecx, floppy_mutex
  754.         call    mutex_lock
  755.         mov     edx, [.userdata]        ; 1 for /fd, 2 for /fd2
  756. ; 2. If the media was reported and has been changed, forget it and report an error.
  757.         mov     al, [floppy_media_flags+edx-1]
  758.         and     al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
  759.         cmp     al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
  760.         jnz     .not_reported
  761. .no_media:
  762.         mov     [floppy_media_flags+edx-1], 0
  763. .return_no_media:
  764.         mov     ecx, floppy_mutex
  765.         call    mutex_unlock
  766.         mov     eax, DISK_STATUS_NO_MEDIA
  767.         retn    8
  768. .not_reported:
  769. ; 3. If we are in the temporary state LABEL_CHANGED, this is the second call
  770. ; after intermediate DISK_STATUS_NO_MEDIA due to media change;
  771. ; clear the flag and return the current geometry without rereading the bootsector.
  772.         cmp     [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
  773.         jz      .report_geometry
  774. ; 4. Try to read the bootsector.
  775.         mov     [flp_number], dl
  776.         mov     [FDC_Status], 0
  777.         call    floppy_read_bootsector
  778. ; 5. If reading bootsector failed, assume that media is not present.
  779.         mov     edx, [.userdata]
  780.         cmp     [FDC_Status], 0
  781.         jnz     .no_media
  782. ; 6. Check whether the previous status is "present". If not, go to 10.
  783.         push    esi edi
  784.         imul    edi, edx, 15
  785.         add     edi, flp_label-15
  786.         mov     esi, FDD_BUFF+39
  787.         mov     ecx, 15
  788.         test    [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
  789.         jz      .set_label
  790. ; 7. Compare the old label with the current one.
  791.         rep cmpsb
  792. ; 8. If the label has not changed, go to 11.
  793.         jz      .ok
  794. ; 9. If the label has changed, store it, enter temporary state LABEL_CHANGED
  795. ; and report DISK_STATUS_NO_MEDIA.
  796. ;       dbgstr 'floppy label changed'
  797.         add     esi, ecx
  798.         add     edi, ecx
  799.         mov     ecx, 15
  800.         sub     esi, ecx
  801.         sub     edi, ecx
  802.         rep movsb
  803.         mov     [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
  804.         pop     edi esi
  805.         jmp     .return_no_media
  806. .set_label:
  807. ; 10. The previous state was "not present". Copy the label.
  808.         rep movsb
  809. .ok:
  810.         pop     edi esi
  811. .report_geometry:
  812. ; 11. Fill DISKMEDIAINFO structure.
  813.         mov     ecx, [.info]
  814.         and     [ecx+DISKMEDIAINFO.Flags], 0
  815.         mov     [ecx+DISKMEDIAINFO.SectorSize], 512
  816.         mov     dword [ecx+DISKMEDIAINFO.Capacity], FLOPPY_CAPACITY
  817.         and     dword [ecx+DISKMEDIAINFO.Capacity+4], 0
  818. ; 12. Update state: media is present, data are actual.
  819.         mov     [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
  820. ; 13. Release the global lock and return successful status.
  821.         mov     ecx, floppy_mutex
  822.         call    mutex_unlock
  823.         xor     eax, eax
  824.         retn    8
  825. endp
  826.  
  827. proc floppy_read_bootsector
  828.         pushad
  829.         mov     [FDD_Track], 0; Цилиндр
  830.         mov     [FDD_Head], 0; Сторона
  831.         mov     [FDD_Sector], 1; Сектор
  832.         call    FDDMotorON
  833.         call    RecalibrateFDD
  834.         cmp     [FDC_Status], 0
  835.         jne     .nothing
  836.         call    SeekTrack
  837.         cmp     [FDC_Status], 0
  838.         jne     .nothing
  839.         call    ReadSectWithRetr
  840. .nothing:
  841.         popad
  842.         ret
  843. endp
  844.  
  845. read_chs_sector:
  846.         call    calculate_chs
  847.         call    ReadSectWithRetr
  848.         ret
  849.  
  850. save_chs_sector:
  851.         call    calculate_chs
  852.         call    WriteSectWithRetr
  853.         ret
  854.  
  855. calculate_chs:
  856.         mov     bl, [FDD_Track]
  857.         mov     [old_track], bl
  858.         mov     ebx, 18
  859.         xor     edx, edx
  860.         div     ebx
  861.         inc     edx
  862.         mov     [FDD_Sector], dl
  863.         mov     edx, eax
  864.         shr     eax, 1
  865.         and     edx, 1
  866.         mov     [FDD_Track], al
  867.         mov     [FDD_Head], dl
  868.         mov     dl, [old_track]
  869.         cmp     dl, [FDD_Track]
  870.         je      no_seek_track_1
  871.         call    SeekTrack
  872. no_seek_track_1:
  873.         ret
  874.  
  875. ; Writes one or more sectors to the device.
  876. proc floppy_write
  877.         mov     dl, 1
  878.         jmp     floppy_read_write
  879. endp
  880.  
  881. ; Reads one or more sectors from the device.
  882. proc floppy_read
  883.         mov     dl, 0
  884. endp
  885.  
  886. ; Common part of floppy_read and floppy_write.
  887. proc floppy_read_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
  888. virtual at ebp-8
  889. .sectors_todo   dd      ?
  890. .operation      db      ?
  891. end virtual
  892.         push    edx             ; save operation code to [.operation]
  893. ; 1. Get number of sectors to read/write
  894. ; and zero number of sectors that were actually read/written.
  895.         mov     eax, [numsectors_ptr]
  896.         push    dword [eax]     ; initialize [.sectors_todo]
  897.         and     dword [eax], 0
  898.         push    ebx esi edi     ; save used registers to be stdcall
  899. ; 2. Acquire the global lock.
  900.         mov     ecx, floppy_mutex
  901.         call    mutex_lock
  902. ; 3. Set floppy number for this operation.
  903.         mov     edx, [userdata]
  904.         mov     [flp_number], dl
  905. ; 4. Read/write sector-by-sector.
  906. .operation_loop:
  907. ; 4a. Check that the sector is inside the media.
  908.         cmp     dword [start_sector+4], 0
  909.         jnz     .end_of_media
  910.         mov     eax, dword [start_sector]
  911.         cmp     eax, FLOPPY_CAPACITY
  912.         jae     .end_of_media
  913. ; 4b. For read operation, call read_chs_sector and then move data from FDD_BUFF to [buffer].
  914. ; For write operation, move data from [buffer] to FDD_BUFF and then call save_chs_sector.
  915.         cmp     [.operation], 0
  916.         jz      .read
  917.         mov     esi, [buffer]
  918.         mov     edi, FDD_BUFF
  919.         mov     ecx, 512/4
  920.         rep movsd
  921.         mov     [buffer], esi
  922.         call    save_chs_sector
  923.         jmp     @f
  924. .read:
  925.         call    read_chs_sector
  926.         mov     esi, FDD_BUFF
  927.         mov     edi, [buffer]
  928.         mov     ecx, 512/4
  929.         rep movsd
  930.         mov     [buffer], edi
  931. @@:
  932. ; 4c. If there was an error, propagate it to the caller.
  933.         cmp     [FDC_Status], 0
  934.         jnz     .fail
  935. ; 4d. Otherwise, increment number of sectors processed and continue the loop.
  936.         mov     eax, [numsectors_ptr]
  937.         inc     dword [eax]
  938.         inc     dword [start_sector]
  939.         dec     [.sectors_todo]
  940.         jnz     .operation_loop
  941. ; 5. Release the global lock and return with the correct status.
  942.         push    0
  943. .return:
  944.         mov     ecx, floppy_mutex
  945.         call    mutex_unlock
  946.         pop     eax
  947.         pop     edi esi ebx     ; restore used registers to be stdcall
  948.         ret     ; this translates to leave/retn N and purges local variables
  949. .fail:
  950.         push    -1
  951.         jmp     .return
  952. .end_of_media:
  953.         push    DISK_STATUS_END_OF_MEDIA
  954.         jmp     .return
  955. endp
  956.