Subversion Repositories Kolibri OS

Rev

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