Subversion Repositories Kolibri OS

Rev

Rev 9932 | Details | Compare with Previous | Last modification | View Log | RSS feed

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