Subversion Repositories Kolibri OS

Rev

Rev 6814 | Rev 8055 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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