Subversion Repositories Kolibri OS

Rev

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