Subversion Repositories Kolibri OS

Rev

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

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