Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
2288 clevermous 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
5363 yogev_ezra 3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
2288 clevermous 4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
8
$Revision: 9932 $
9
 
10
 
11
;**********************************************************
8054 rgimad 12
;  Direct work with floppy disk drive
2288 clevermous 13
;**********************************************************
8055 rgimad 14
; Source code author -  Kulakov Vladimir Gennadievich.
15
; Adaptation and improvement -  Mario79.
2288 clevermous 16
 
17
give_back_application_data_1:
18
        mov     esi, FDD_BUFF;FDD_DataBuffer  ;0x40000
4273 clevermous 19
        mov     ecx, 128
2288 clevermous 20
        cld
21
        rep movsd
22
        ret
23
 
24
take_data_from_application_1:
25
        mov     edi, FDD_BUFF;FDD_DataBuffer  ;0x40000
4273 clevermous 26
        mov     ecx, 128
2288 clevermous 27
        cld
28
        rep movsd
29
        ret
30
 
8054 rgimad 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
2288 clevermous 37
 
8054 rgimad 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)
7136 dunkaist 41
MAX_Track   = 79
42
MAX_Head    =  1
43
MAX_Sector  = 18
2288 clevermous 44
 
45
uglobal
8054 rgimad 46
; Timer tick counter
2288 clevermous 47
TickCounter dd ?
8054 rgimad 48
; Operation completion code with the floppy disk drive controller
2288 clevermous 49
FDC_Status  DB ?
8054 rgimad 50
; Interrupt flag from floppy disk drive
2288 clevermous 51
FDD_IntFlag DB ?
8054 rgimad 52
; The moment of the beginning of the last operation with FDD
2288 clevermous 53
FDD_Time    DD ?
8054 rgimad 54
; Drive number
2288 clevermous 55
FDD_Type    db 0
8054 rgimad 56
; Sector coordinates
2288 clevermous 57
FDD_Track   DB ?
58
FDD_Head    DB ?
59
FDD_Sector  DB ?
60
 
8054 rgimad 61
; Operation result block
2288 clevermous 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 ?
8054 rgimad 69
; Read operation repetition counter
2288 clevermous 70
ReadRepCounter  DB ?
8054 rgimad 71
; Recalibration operation repetition counter
2288 clevermous 72
RecalRepCounter DB ?
73
endg
8054 rgimad 74
; Memory area for storing the readed sector
2288 clevermous 75
;FDD_DataBuffer:  times 512 db 0   ;DB 512 DUP (?)
76
fdd_motor_status db 0
77
timer_fdd_motor  dd 0
78
 
8054 rgimad 79
;**************************************
80
;* INITIALIZATION OF DMA MODE FOR FDD *
81
;**************************************
2288 clevermous 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
;***********************************
8054 rgimad 110
;* WRITE BYTE TO FDC DATA PORT     *
111
;* Parameters:                     *
112
;* AL - byte to write.             *
2288 clevermous 113
;***********************************
114
FDCDataOutput:
4273 clevermous 115
;       DEBUGF 1,'K : FDCDataOutput(%x)',al
2288 clevermous 116
;        pusha
117
        push    eax ecx edx
8054 rgimad 118
        mov     AH, AL    ; remember byte to AH
119
; Reset controller state variable
2288 clevermous 120
        mov     [FDC_Status], FDC_Normal
8054 rgimad 121
; Check the readiness of the controller to receive data
122
        mov     DX, 3F4h  ; (FDC state port)
123
        mov     ecx, 0x10000 ; set timeout counter
2288 clevermous 124
@@TestRS:
8054 rgimad 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
2288 clevermous 128
        je      @@OutByteToFDC
129
        loop    @@TestRS
8054 rgimad 130
; Time out error
4273 clevermous 131
;       DEBUGF 1,' timeout\n'
2288 clevermous 132
        mov     [FDC_Status], FDC_TimeOut
133
        jmp     @@End_5
8054 rgimad 134
; Write byte to data port
2288 clevermous 135
@@OutByteToFDC:
136
        inc     DX
137
        mov     AL, AH
138
        out     DX, AL
4273 clevermous 139
;        DEBUGF 1,' ok\n'
2288 clevermous 140
@@End_5:
141
;        popa
142
        pop     edx ecx eax
143
        ret
144
 
145
;******************************************
8054 rgimad 146
;*   READ BYTE FROM FDC DATA PORT         *
147
;* Procedure doesnt have input params.    *
148
;* Output :                               *
149
;* AL - byte read.                        *
2288 clevermous 150
;******************************************
151
FDCDataInput:
152
        push    ECX
153
        push    DX
8054 rgimad 154
; Reset controller state variable
2288 clevermous 155
        mov     [FDC_Status], FDC_Normal
8054 rgimad 156
; Check the readiness of the controller to receive data
157
        mov     DX, 3F4h  ;(FDC state port)
158
        mov     ecx, 0x10000 ; set timeout counter
2288 clevermous 159
@@TestRS_1:
8054 rgimad 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
2288 clevermous 163
        je      @@GetByteFromFDC
164
        loop    @@TestRS_1
8054 rgimad 165
; Time out error
4273 clevermous 166
;       DEBUGF 1,'K : FDCDataInput: timeout\n'
2288 clevermous 167
        mov     [FDC_Status], FDC_TimeOut
168
        jmp     @@End_6
8054 rgimad 169
; Get byte from data port
2288 clevermous 170
@@GetByteFromFDC:
171
        inc     DX
172
        in      AL, DX
4273 clevermous 173
;       DEBUGF 1,'K : FDCDataInput: %x\n',al
2288 clevermous 174
@@End_6:
175
        pop     DX
176
        pop     ECX
177
        ret
178
 
179
;*********************************************
8054 rgimad 180
;* FDC INTERRUPT HANDLER                     *
2288 clevermous 181
;*********************************************
182
FDCInterrupt:
4273 clevermous 183
;       dbgstr 'FDCInterrupt'
8054 rgimad 184
; Set the interrupt flag
2288 clevermous 185
        mov     [FDD_IntFlag], 1
3771 mario79 186
        mov     al, 1
2288 clevermous 187
        ret
188
 
189
;*******************************************
8054 rgimad 190
;* WAIT FOR INTERRUPT FROM FDC             *
2288 clevermous 191
;*******************************************
192
WaitFDCInterrupt:
193
        pusha
8054 rgimad 194
; Reset operation status byte
2288 clevermous 195
        mov     [FDC_Status], FDC_Normal
8054 rgimad 196
; Zero out the tick counter
2288 clevermous 197
        mov     eax, [timer_ticks]
198
        mov     [TickCounter], eax
8054 rgimad 199
; Wait for the floppy disk interrupt flag to be set
2288 clevermous 200
@@TestRS_2:
3771 mario79 201
        call    change_task
2288 clevermous 202
        cmp     [FDD_IntFlag], 0
8054 rgimad 203
        jnz     @@End_7           ; interrupt occured
2288 clevermous 204
        mov     eax, [timer_ticks]
205
        sub     eax, [TickCounter]
8054 rgimad 206
        cmp     eax, 200;50 ;25   ;5 ; wait 5 ticks
2288 clevermous 207
        jb      @@TestRS_2
208
;        jl      @@TestRS_2
8054 rgimad 209
; Time out error
4273 clevermous 210
;       dbgstr 'WaitFDCInterrupt: timeout'
2288 clevermous 211
        mov     [FDC_Status], FDC_TimeOut
212
@@End_7:
213
        popa
214
        ret
215
 
8054 rgimad 216
;***********************************
217
;* Turn on the motor of drive "A:" *
218
;***********************************
2288 clevermous 219
FDDMotorON:
4273 clevermous 220
;       dbgstr 'FDDMotorON'
2288 clevermous 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
8054 rgimad 227
; Reset the FDD controller
228
        mov     DX, 3F2h  ; motor control port
2288 clevermous 229
        mov     AL, 0
230
        out     DX, AL
8054 rgimad 231
; Select and turn on the drive motor
2288 clevermous 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
8054 rgimad 242
; Zero out the tick counter
2288 clevermous 243
        mov     eax, [timer_ticks]
244
        mov     [TickCounter], eax
8054 rgimad 245
; wait 0.5 s
2288 clevermous 246
@@dT:
247
        call    change_task
248
        mov     eax, [timer_ticks]
249
        sub     eax, [TickCounter]
250
        cmp     eax, 50 ;10
251
        jb      @@dT
4273 clevermous 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
2288 clevermous 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
;*****************************************
8054 rgimad 278
;*  SAVING TIME STAMP                    *
2288 clevermous 279
;*****************************************
280
save_timer_fdd_motor:
281
        mov     eax, [timer_ticks]
282
        mov     [timer_fdd_motor], eax
283
        ret
284
 
285
;*****************************************
8054 rgimad 286
;*  CHECK THE MOTOR SHUTDOWN DELAY       *
2288 clevermous 287
;*****************************************
3534 clevermous 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
 
2288 clevermous 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
;**********************************
8054 rgimad 319
;* TURN OFF MOTOR OF DRIVE        *
2288 clevermous 320
;**********************************
321
FDDMotorOFF:
4273 clevermous 322
;       dbgstr 'FDDMotorOFF'
2288 clevermous 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
8054 rgimad 334
        ; clearing caching flags due to information obsolescence
4273 clevermous 335
        or      [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN
336
        or      [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN
2288 clevermous 337
        ret
338
 
339
FDDMotorOFF_A:
8054 rgimad 340
        mov     DX, 3F2h  ; motor control port
341
        mov     AL, 0Ch   ; Floppy A
2288 clevermous 342
        out     DX, AL
343
        ret
344
 
345
FDDMotorOFF_B:
8054 rgimad 346
        mov     DX, 3F2h  ; motor control port
347
        mov     AL, 5h    ; Floppy B
2288 clevermous 348
        out     DX, AL
349
        ret
350
 
351
;*******************************
8054 rgimad 352
;* RECALIBRATE DRIVE "A:"      *
2288 clevermous 353
;*******************************
354
RecalibrateFDD:
4273 clevermous 355
;       dbgstr 'RecalibrateFDD'
2288 clevermous 356
        pusha
357
        call    save_timer_fdd_motor
8054 rgimad 358
; Clear the interrupt flag
4273 clevermous 359
        mov     [FDD_IntFlag], 0
8054 rgimad 360
; Send the "Recalibration" command
2288 clevermous 361
        mov     AL, 07h
362
        call    FDCDataOutput
6814 dunkaist 363
        mov     AL, [flp_number]
364
        dec     AL
2288 clevermous 365
        call    FDCDataOutput
8054 rgimad 366
; Wait for the operation to complete
2288 clevermous 367
        call    WaitFDCInterrupt
4273 clevermous 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
4695 clevermous 375
        push    eax
4273 clevermous 376
;       DEBUGF 1,' %x',al
377
        call    FDCDataInput
378
;       DEBUGF 1,' %x',al
379
;       DEBUGF 1,'\n'
4695 clevermous 380
        pop     eax
381
        test    al, 0xC0
382
        jz      @f
383
        mov     [FDC_Status], FDC_DiskNotFound
384
@@:
4273 clevermous 385
.fail:
2288 clevermous 386
        call    save_timer_fdd_motor
387
        popa
388
        ret
389
 
390
;*****************************************************
8054 rgimad 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.     *
2288 clevermous 396
;*****************************************************
397
SeekTrack:
4273 clevermous 398
;       dbgstr 'SeekTrack'
2288 clevermous 399
        pusha
400
        call    save_timer_fdd_motor
8054 rgimad 401
; Clear the interrupt flag
4115 mario79 402
        mov     [FDD_IntFlag], 0
8054 rgimad 403
; Send "Search" command
2288 clevermous 404
        mov     AL, 0Fh
405
        call    FDCDataOutput
8054 rgimad 406
        ; Send head / drive number byte
2288 clevermous 407
        mov     AL, [FDD_Head]
408
        shl     AL, 2
409
        call    FDCDataOutput
8054 rgimad 410
        ; Send track number byte
2288 clevermous 411
        mov     AL, [FDD_Track]
412
        call    FDCDataOutput
8054 rgimad 413
; Wait for the operation to complete
2288 clevermous 414
        call    WaitFDCInterrupt
415
        cmp     [FDC_Status], FDC_Normal
416
        jne     @@Exit
8054 rgimad 417
; Save search result
2288 clevermous 418
        mov     AL, 08h
419
        call    FDCDataOutput
420
        call    FDCDataInput
421
        mov     [FDC_ST0], AL
422
        call    FDCDataInput
423
        mov     [FDC_C], AL
8054 rgimad 424
; Check search result
425
        ; Is search finished?
2288 clevermous 426
        test    [FDC_ST0], 100000b
427
        je      @@Err
8054 rgimad 428
        ; Is the specified track found?
2288 clevermous 429
        mov     AL, [FDC_C]
430
        cmp     AL, [FDD_Track]
431
        jne     @@Err
8054 rgimad 432
        ; Does the head number match the specified one?
4273 clevermous 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
8054 rgimad 440
        ; Operation completed successfully
4273 clevermous 441
;        dbgstr 'SeekTrack: FDC_Normal'
2288 clevermous 442
        mov     [FDC_Status], FDC_Normal
443
        jmp     @@Exit
8054 rgimad 444
@@Err:  ; Track not found
4273 clevermous 445
;       dbgstr 'SeekTrack: FDC_TrackNotFound'
2288 clevermous 446
        mov     [FDC_Status], FDC_TrackNotFound
447
@@Exit:
448
        call    save_timer_fdd_motor
449
        popa
450
        ret
451
 
452
;*******************************************************
8054 rgimad 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.   *
2288 clevermous 461
;*******************************************************
462
ReadSector:
4273 clevermous 463
;       dbgstr 'ReadSector'
2288 clevermous 464
        pushad
465
        call    save_timer_fdd_motor
8054 rgimad 466
; Clear the interrupt flag
4115 mario79 467
        mov     [FDD_IntFlag], 0
8054 rgimad 468
; Set transmit speed to 500 Kb / s
2288 clevermous 469
        mov     AX, 0
470
        mov     DX, 03F7h
471
        out     DX, AL
8054 rgimad 472
; Initialize the DMA channel
2288 clevermous 473
        mov     [dmamode], 0x46
474
        call    Init_FDC_DMA
8054 rgimad 475
; Send "Data read" command
476
        mov     AL, 0E6h ; reading in multi-track mode
2288 clevermous 477
        call    FDCDataOutput
478
        mov     AL, [FDD_Head]
479
        shl     AL, 2
6814 dunkaist 480
        or      AL, [flp_number]
481
        dec     AL
2288 clevermous 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
8054 rgimad 489
        mov     AL, 2   ; sector size code (512 byte)
2288 clevermous 490
        call    FDCDataOutput
8054 rgimad 491
        mov     AL, 18 ;+1; 3Fh  ;number of sectors per track
2288 clevermous 492
        call    FDCDataOutput
8054 rgimad 493
        mov     AL, 1Bh ; GPL value
2288 clevermous 494
        call    FDCDataOutput
8054 rgimad 495
        mov     AL, 0FFh; DTL value
2288 clevermous 496
        call    FDCDataOutput
8054 rgimad 497
; Waiting for an interrupt at the end of the operation
2288 clevermous 498
        call    WaitFDCInterrupt
499
        cmp     [FDC_Status], FDC_Normal
500
        jne     @@Exit_1
8054 rgimad 501
; Read the operation completion status
2288 clevermous 502
        call    GetStatusInfo
503
        test    [FDC_ST0], 11011000b
504
        jnz     @@Err_1
4273 clevermous 505
;        dbgstr 'ReadSector: FDC_Normal'
2288 clevermous 506
        mov     [FDC_Status], FDC_Normal
507
        jmp     @@Exit_1
508
@@Err_1:
4273 clevermous 509
;       dbgstr 'ReadSector: FDC_SectorNotFound'
2288 clevermous 510
        mov     [FDC_Status], FDC_SectorNotFound
511
@@Exit_1:
512
        call    save_timer_fdd_motor
513
        popad
514
        ret
515
 
516
;*******************************************************
8054 rgimad 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.   *
2288 clevermous 525
;*******************************************************
526
ReadSectWithRetr:
527
        pusha
8054 rgimad 528
; Reset the recalibration repetition counter
2288 clevermous 529
        mov     [RecalRepCounter], 0
530
@@TryAgain:
8054 rgimad 531
; Reset the read operation retry counter
2288 clevermous 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
8054 rgimad 539
        ; Three times repeat reading
2288 clevermous 540
        inc     [ReadRepCounter]
541
        cmp     [ReadRepCounter], 3
542
        jb      @@ReadSector_1
8054 rgimad 543
        ; Three times repeat recalibration
2288 clevermous 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
;*******************************************************
8054 rgimad 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     *
2288 clevermous 565
;*******************************************************
566
WriteSector:
4273 clevermous 567
;       dbgstr 'WriteSector'
2288 clevermous 568
        pushad
569
        call    save_timer_fdd_motor
8054 rgimad 570
; Clear the interrupt flag
4115 mario79 571
        mov     [FDD_IntFlag], 0
8054 rgimad 572
; Set transmit speed to 500 Kb / s
2288 clevermous 573
        mov     AX, 0
574
        mov     DX, 03F7h
575
        out     DX, AL
8054 rgimad 576
; Initialize the DMA channel
2288 clevermous 577
        mov     [dmamode], 0x4A
578
        call    Init_FDC_DMA
8054 rgimad 579
; Send "Write data" command
580
        mov     AL, 0xC5 ;0x45  ; write in multi-track mode
2288 clevermous 581
        call    FDCDataOutput
582
        mov     AL, [FDD_Head]
583
        shl     AL, 2
6814 dunkaist 584
        or      AL, [flp_number]
585
        dec     AL
2288 clevermous 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
8054 rgimad 593
        mov     AL, 2   ; sector size code (512 bytes)
2288 clevermous 594
        call    FDCDataOutput
8054 rgimad 595
        mov     AL, 18; 3Fh  ; sectors per track
2288 clevermous 596
        call    FDCDataOutput
8054 rgimad 597
        mov     AL, 1Bh ; GPL value
2288 clevermous 598
        call    FDCDataOutput
8054 rgimad 599
        mov     AL, 0FFh; DTL value
2288 clevermous 600
        call    FDCDataOutput
8054 rgimad 601
; Waiting for an interrupt at the end of the operation
2288 clevermous 602
        call    WaitFDCInterrupt
603
        cmp     [FDC_Status], FDC_Normal
604
        jne     @@Exit_3
8054 rgimad 605
; Reading the completion status of the operation
2288 clevermous 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
;*******************************************************
8054 rgimad 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     *
2288 clevermous 627
;*******************************************************
628
WriteSectWithRetr:
629
        pusha
8054 rgimad 630
; Reset the recalibration repetition counter
2288 clevermous 631
        mov     [RecalRepCounter], 0
632
@@TryAgain_1:
8054 rgimad 633
; Reset the read operation retry counter
2288 clevermous 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
8054 rgimad 641
        ; Three times repeat writing
2288 clevermous 642
        inc     [ReadRepCounter]
643
        cmp     [ReadRepCounter], 3
644
        jb      @@WriteSector_1
8054 rgimad 645
        ; Three times repeat recalibration
2288 clevermous 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
;*********************************************
8054 rgimad 659
;* GET INFORMATION ABOUT THE RESULT OF THE OPERATION
2288 clevermous 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
 
4273 clevermous 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
8054 rgimad 826
        mov     [FDD_Track], 0  ; Cylinder
827
        mov     [FDD_Head], 0   ; Head
828
        mov     [FDD_Sector], 1 ; Sector
4273 clevermous 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