Subversion Repositories Kolibri OS

Rev

Rev 1198 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1159 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
1206 hidnplayr 8
$Revision: 1206 $
1159 hidnplayr 9
 
10
 
11
;**********************************************************
12
;  Непосредственная работа с контроллером гибкого диска
13
;**********************************************************
14
; Автор исходного текста  Кулаков Владимир Геннадьевич.
15
; Адаптация и доработка Mario79
16
 
17
;give_back_application_data:  ; переслать приложению
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
23
     xor ecx,ecx
24
     mov cx,128
25
     cld
26
     rep movsd
27
     ret
28
 
29
;take_data_from_application:   ; взять из приложени
30
;     mov esi,[TASK_BASE]
31
;     mov esi,[esi+TASKDATA.mem_start]
32
;     add esi,ecx
33
take_data_from_application_1:
34
     mov edi,FDD_BUFF   ;FDD_DataBuffer  ;0x40000
35
     xor ecx,ecx
36
     mov cx,128
37
     cld
38
     rep movsd
39
     ret
40
 
41
; Коды завершения операции с контроллером (FDC_Status)
42
FDC_Normal         equ 0 ;нормальное завершение
43
FDC_TimeOut        equ 1 ;ошибка тайм-аута
44
FDC_DiskNotFound   equ 2 ;в дисководе нет диска
45
FDC_TrackNotFound  equ 3 ;дорожка не найдена
46
FDC_SectorNotFound equ 4 ;сектор не найден
47
 
48
; Максимальные значения координат сектора (заданные
49
; значения соответствуют параметрам стандартного
50
; трехдюймового гибкого диска объемом 1,44 Мб)
51
MAX_Track   equ 79
52
MAX_Head    equ  1
53
MAX_Sector  equ 18
54
 
55
uglobal
56
; Счетчик тиков таймера
57
TickCounter dd ?
58
; Код завершения операции с контроллером НГМД
59
FDC_Status  DB ?
60
; Флаг прерывания от НГМД
61
FDD_IntFlag DB ?
62
; Момент начала последней операции с НГМД
63
FDD_Time    DD ?
64
; Номер дисковода
65
FDD_Type    db 0
66
; Координаты сектора
67
FDD_Track   DB ?
68
FDD_Head    DB ?
69
FDD_Sector  DB ?
70
 
71
; Блок результата операции
72
FDC_ST0 DB ?
73
FDC_ST1 DB ?
74
FDC_ST2 DB ?
75
FDC_C   DB ?
76
FDC_H   DB ?
77
FDC_R   DB ?
78
FDC_N   DB ?
79
; Счетчик повторения операции чтени
80
ReadRepCounter  DB ?
81
; Счетчик повторения операции рекалибровки
82
RecalRepCounter DB ?
83
endg
84
; Область памяти для хранения прочитанного сектора
85
;FDD_DataBuffer:  times 512 db 0   ;DB 512 DUP (?)
86
fdd_motor_status db 0
87
timer_fdd_motor  dd 0
88
 
89
;*************************************
90
;* ИНИЦИАЛИЗАЦИЯ РЕЖИМА ПДП ДЛЯ НГМД *
91
;*************************************
92
Init_FDC_DMA:
93
        pushad
94
        mov al,0
95
        out 0x0c,al     ; reset the flip-flop to a known state.
96
        mov al,6                ; mask channel 2 so we can reprogram it.
97
        out 0x0a,al
98
        mov al,[dmamode] ; 0x46 -> Read from floppy - 0x4A Write to floppy
99
        out 0x0b,al
100
        mov al,0
101
        out 0x0c,al     ; reset the flip-flop to a known state.
102
        mov eax,0xD000
103
        out 0x04,al     ; set the channel 2 starting address to 0
104
        shr eax,8
105
        out 0x04,al
106
        shr eax,8
107
        out 0x81,al
108
        mov al,0
109
        out 0x0c, al    ; reset flip-flop
110
        mov al, 0xff    ;set count (actual size -1)
111
        out 0x5, al
112
        mov al,0x1  ;[dmasize]       ;(0x1ff = 511 / 0x23ff =9215)
113
        out 0x5,al
114
        mov al,2
115
        out 0xa,al
116
        popad
117
        ret
118
 
119
;***********************************
120
;* ЗАПИСАТЬ БАЙТ В ПОРТ ДАННЫХ FDC *
121
;* Параметры:                      *
122
;* AL - выводимый байт.            *
123
;***********************************
124
FDCDataOutput:
125
;        pusha
126
        push eax ecx edx
127
        mov     AH,AL     ;запомнить байт в AH
128
; Сбросить переменную состояния контроллера
129
        mov     [FDC_Status],FDC_Normal
130
; Проверить готовность контроллера к приему данных
131
        mov     DX,3F4h   ;(порт состояния FDC)
132
        mov     ecx, 0x10000 ;установить счетчик тайм-аута
133
@@TestRS:
134
        in      AL,DX     ;прочитать регистр RS
135
        and     AL,0C0h   ;выделить разряды 6 и 7
136
        cmp     AL,80h    ;проверить разряды 6 и 7
137
        je      @@OutByteToFDC
138
        loop    @@TestRS
139
; Ошибка тайм-аута
140
        mov     [FDC_Status],FDC_TimeOut
141
        jmp @@End_5
142
; Вывести байт в порт данных
143
@@OutByteToFDC:
144
        inc     DX
145
        mov     AL,AH
146
        out     DX,AL
147
@@End_5:
148
;        popa
149
        pop edx ecx eax
150
        ret
151
 
152
;******************************************
153
;*   ПРОЧИТАТЬ БАЙТ ИЗ ПОРТА ДАННЫХ FDC   *
154
;* Процедура не имеет входных параметров. *
155
;* Выходные данные:                       *
156
;* AL - считанный байт.                   *
157
;******************************************
158
FDCDataInput:
159
        push    ECX
160
        push    DX
161
; Сбросить переменную состояния контроллера
162
        mov     [FDC_Status],FDC_Normal
163
; Проверить готовность контроллера к передаче данных
164
        mov     DX,3F4h   ;(порт состояния FDC)
165
        xor     CX,CX     ;установить счетчик тайм-аута
166
@@TestRS_1:
167
        in      AL,DX     ;прочитать регистр RS
168
        and     AL,0C0h   ;выдлить разряды 6 и 7
169
        cmp     AL,0C0h   ;проверить разряды 6 и 7
170
        je      @@GetByteFromFDC
171
        loop    @@TestRS_1
172
; Ошибка тайм-аута
173
        mov     [FDC_Status],FDC_TimeOut
174
        jmp @@End_6
175
; Ввести байт из порта данных
176
@@GetByteFromFDC:
177
        inc     DX
178
        in      AL,DX
179
@@End_6:  pop     DX
180
        pop     ECX
181
        ret
182
 
183
;*********************************************
184
;* ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
185
;*********************************************
186
FDCInterrupt:
187
; Установить флаг прерывани
188
        mov     [FDD_IntFlag],1
189
        ret
190
 
191
 
192
;******************************************
193
;* УСТАНОВИТЬ НОВЫЙ ОБРАБОТЧИК ПРЕРЫВАНИЙ *
194
;*             НГМД                       *
195
;******************************************
196
SetUserInterrupts:
197
         mov     [fdc_irq_func],FDCInterrupt
198
         ret
199
 
200
;*******************************************
201
;* ОЖИДАНИЕ ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
202
;*******************************************
203
WaitFDCInterrupt:
204
        pusha
205
; Сбросить байт состояния операции
206
        mov     [FDC_Status],FDC_Normal
207
; Сбросить флаг прерывани
208
        mov     [FDD_IntFlag],0
209
; Обнулить счетчик тиков
210
        mov     eax,[timer_ticks]
211
        mov     [TickCounter],eax
212
; Ожидать установки флага прерывания НГМД
213
@@TestRS_2:
214
        cmp     [FDD_IntFlag],0
215
        jnz     @@End_7           ;прерывание произошло
216
        call    change_task
217
        mov     eax,[timer_ticks]
218
        sub     eax,[TickCounter]
219
        cmp     eax,50  ;25   ;5 ;ожидать 5 тиков
220
        jb      @@TestRS_2
221
;        jl      @@TestRS_2
222
; Ошибка тайм-аута
223
        mov     [FDC_Status],FDC_TimeOut
224
;        mov   [flp_status],0
225
@@End_7:  popa
226
        ret
227
 
228
;*********************************
229
;* ВКЛЮЧИТЬ МОТОР ДИСКОВОДА "A:" *
230
;*********************************
231
FDDMotorON:
232
        pusha
233
;        cmp     [fdd_motor_status],1
234
;        je      fdd_motor_on
235
        mov     al,[flp_number]
236
        cmp     [fdd_motor_status],al
237
        je      fdd_motor_on
238
; Произвести сброс контроллера НГМД
239
        mov     DX,3F2h ;порт управления двигателями
240
        mov     AL,0
241
        out     DX,AL
242
; Выбрать и включить мотор дисковода
243
        cmp     [flp_number],1
244
        jne     FDDMotorON_B
245
;        call    FDDMotorOFF_B
246
        mov     AL,1Ch    ; Floppy A
247
        jmp     FDDMotorON_1
248
FDDMotorON_B:
249
;        call    FDDMotorOFF_A
250
        mov     AL,2Dh    ; Floppy B
251
FDDMotorON_1:
252
        out     DX,AL
253
; Обнулить счетчик тиков
254
        mov     eax,[timer_ticks]
255
        mov     [TickCounter],eax
256
; Ожидать 0,5 с
257
@@dT:
258
        call    change_task
259
        mov     eax,[timer_ticks]
260
        sub     eax,[TickCounter]
261
        cmp     eax,50  ;10
262
        jb      @@dT
263
        cmp     [flp_number],1
264
        jne     fdd_motor_on_B
265
        mov     [fdd_motor_status],1
266
        jmp     fdd_motor_on
267
fdd_motor_on_B:
268
        mov     [fdd_motor_status],2
269
fdd_motor_on:
270
        call    save_timer_fdd_motor
271
        popa
272
        ret
273
 
274
;*****************************************
275
;*  СОХРАНЕНИЕ УКАЗАТЕЛЯ ВРЕМЕНИ         *
276
;*****************************************
277
save_timer_fdd_motor:
278
        mov     eax,[timer_ticks]
279
        mov     [timer_fdd_motor],eax
280
        ret
281
 
282
;*****************************************
283
;*  ПРОВЕРКА ЗАДЕРЖКИ ВЫКЛЮЧЕНИЯ МОТОРА  *
284
;*****************************************
1198 clevermous 285
align 4
1159 hidnplayr 286
check_fdd_motor_status:
287
        cmp     [fdd_motor_status],0
288
        je      end_check_fdd_motor_status_1
289
        mov     eax,[timer_ticks]
290
        sub     eax,[timer_fdd_motor]
291
        cmp     eax,500
292
        jb      end_check_fdd_motor_status
293
        call    FDDMotorOFF
294
        mov     [fdd_motor_status],0
295
end_check_fdd_motor_status_1:
296
        mov     [flp_status],0
297
end_check_fdd_motor_status:
298
        ret
299
 
300
;**********************************
301
;* ВЫКЛЮЧИТЬ МОТОР ДИСКОВОДА      *
302
;**********************************
303
FDDMotorOFF:
304
        push    AX
305
        push    DX
306
        cmp     [flp_number],1
307
        jne     FDDMotorOFF_1
308
        call    FDDMotorOFF_A
309
        jmp     FDDMotorOFF_2
310
FDDMotorOFF_1:
311
        call    FDDMotorOFF_B
312
FDDMotorOFF_2:
313
        pop     DX
314
        pop     AX
315
        ; сброс флагов кеширования в связи с устареванием информации
316
        mov    [root_read],0
317
        mov    [flp_fat],0
318
        ret
319
 
320
FDDMotorOFF_A:
321
        mov     DX,3F2h ;порт управления двигателями
322
        mov     AL,0Ch  ; Floppy A
323
        out     DX,AL
324
        ret
325
 
326
FDDMotorOFF_B:
327
        mov     DX,3F2h ;порт управления двигателями
328
        mov     AL,5h  ; Floppy B
329
        out     DX,AL
330
        ret
331
 
332
;*******************************
333
;* РЕКАЛИБРОВКА ДИСКОВОДА "A:" *
334
;*******************************
335
RecalibrateFDD:
336
        pusha
337
        call    save_timer_fdd_motor
338
; Подать команду "Рекалибровка"
339
        mov     AL,07h
340
        call    FDCDataOutput
341
        mov     AL,00h
342
        call    FDCDataOutput
343
; Ожидать завершения операции
344
        call    WaitFDCInterrupt
345
;        cmp    [FDC_Status],0
346
;        je    no_fdc_status_error
347
;        mov   [flp_status],0
348
;no_fdc_status_error:
349
        call    save_timer_fdd_motor
350
        popa
351
        ret
352
 
353
;*****************************************************
354
;*                    ПОИСК ДОРОЖКИ                  *
355
;* Параметры передаются через глобальные переменные: *
356
;* FDD_Track - номер дорожки (0-79);                 *
357
;* FDD_Head - номер головки (0-1).                   *
358
;* Результат операции заносится в FDC_Status.        *
359
;*****************************************************
360
SeekTrack:
361
        pusha
362
        call    save_timer_fdd_motor
363
; Подать команду "Поиск"
364
        mov     AL,0Fh
365
        call    FDCDataOutput
366
        ; Передать байт номера головки/накопител
367
        mov     AL,[FDD_Head]
368
        shl     AL,2
369
        call    FDCDataOutput
370
        ; Передать байт номера дорожки
371
        mov     AL,[FDD_Track]
372
        call    FDCDataOutput
373
; Ожидать завершения операции
374
        call    WaitFDCInterrupt
375
        cmp     [FDC_Status],FDC_Normal
376
        jne     @@Exit
377
; Сохранить результат поиска
378
        mov     AL,08h
379
        call    FDCDataOutput
380
        call    FDCDataInput
381
        mov     [FDC_ST0],AL
382
        call    FDCDataInput
383
        mov     [FDC_C],AL
384
; Проверить результат поиска
385
        ; Поиск завершен?
386
        test    [FDC_ST0],100000b
387
        je      @@Err
388
        ; Заданный трек найден?
389
        mov     AL,[FDC_C]
390
        cmp     AL,[FDD_Track]
391
        jne     @@Err
392
        ; Номер головки совпадает с заданным?
393
        mov     AL,[FDC_ST0]
394
        and     AL,100b
395
        shr     AL,2
396
        cmp     AL,[FDD_Head]
397
        jne     @@Err
398
        ; Операция завершена успешно
399
        mov     [FDC_Status],FDC_Normal
400
        jmp @@Exit
401
@@Err:  ; Трек не найден
402
        mov     [FDC_Status],FDC_TrackNotFound
403
;        mov   [flp_status],0
404
@@Exit:
405
        call    save_timer_fdd_motor
406
        popa
407
        ret
408
 
409
;*******************************************************
410
;*               ЧТЕНИЕ СЕКТОРА ДАННЫХ                 *
411
;* Параметры передаются через глобальные переменные:   *
412
;* FDD_Track - номер дорожки (0-79);                   *
413
;* FDD_Head - номер головки (0-1);                     *
414
;* FDD_Sector - номер сектора (1-18).                  *
415
;* Результат операции заносится в FDC_Status.          *
416
;* В случае успешного выполнения операции чтения       *
417
;* содержимое сектора будет занесено в FDD_DataBuffer. *
418
;*******************************************************
419
ReadSector:
420
        pushad
421
        call    save_timer_fdd_motor
422
; Установить скорость передачи 500 Кбайт/с
423
        mov     AX,0
424
        mov     DX,03F7h
425
        out     DX,AL
426
; Инициализировать канал прямого доступа к памяти
427
        mov     [dmamode],0x46
428
        call    Init_FDC_DMA
429
; Подать команду "Чтение данных"
430
        mov     AL,0E6h  ;чтение в мультитрековом режиме
431
        call    FDCDataOutput
432
        mov     AL,[FDD_Head]
433
        shl     AL,2
434
        call    FDCDataOutput
435
        mov     AL,[FDD_Track]
436
        call    FDCDataOutput
437
        mov     AL,[FDD_Head]
438
        call    FDCDataOutput
439
        mov     AL,[FDD_Sector]
440
        call    FDCDataOutput
441
        mov     AL,2    ;код размера сектора (512 байт)
442
        call    FDCDataOutput
443
        mov     AL,18  ;+1; 3Fh  ;число секторов на дорожке
444
        call    FDCDataOutput
445
        mov     AL,1Bh  ;значение GPL
446
        call    FDCDataOutput
447
        mov     AL,0FFh ;значение DTL
448
        call    FDCDataOutput
449
; Ожидаем прерывание по завершении операции
450
        call    WaitFDCInterrupt
451
        cmp     [FDC_Status],FDC_Normal
452
        jne     @@Exit_1
453
; Считываем статус завершения операции
454
        call    GetStatusInfo
455
        test    [FDC_ST0],11011000b
456
        jnz     @@Err_1
457
        mov     [FDC_Status],FDC_Normal
458
        jmp @@Exit_1
459
@@Err_1:  mov     [FDC_Status],FDC_SectorNotFound
460
;        mov   [flp_status],0
461
@@Exit_1:
462
        call    save_timer_fdd_motor
463
        popad
464
        ret
465
 
466
;*******************************************************
467
;*   ЧТЕНИЕ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
468
;* Параметры передаются через глобальные переменные:   *
469
;* FDD_Track - номер дорожки (0-79);                   *
470
;* FDD_Head - номер головки (0-1);                     *
471
;* FDD_Sector - номер сектора (1-18).                  *
472
;* Результат операции заносится в FDC_Status.          *
473
;* В случае успешного выполнения операции чтения       *
474
;* содержимое сектора будет занесено в FDD_DataBuffer. *
475
;*******************************************************
476
ReadSectWithRetr:
477
        pusha
478
; Обнулить счетчик повторения операции рекалибровки
479
        mov     [RecalRepCounter],0
480
@@TryAgain:
481
; Обнулить счетчик повторения операции чтени
482
        mov     [ReadRepCounter],0
483
@@ReadSector_1:
484
        call    ReadSector
485
        cmp     [FDC_Status],0
486
        je      @@Exit_2
487
        cmp     [FDC_Status],1
488
        je      @@Err_3
489
        ; Троекратное повторение чтени
490
        inc     [ReadRepCounter]
491
        cmp     [ReadRepCounter],3
492
        jb      @@ReadSector_1
493
        ; Троекратное повторение рекалибровки
494
        call    RecalibrateFDD
495
        call    SeekTrack
496
        inc     [RecalRepCounter]
497
        cmp     [RecalRepCounter],3
498
        jb      @@TryAgain
499
;        mov   [flp_status],0
500
@@Exit_2:
501
        popa
502
        ret
503
@@Err_3:
504
        mov   [flp_status],0
505
        popa
506
        ret
507
 
508
;*******************************************************
509
;*               ЗАПИСЬ СЕКТОРА ДАННЫХ                 *
510
;* Параметры передаются через глобальные переменные:   *
511
;* FDD_Track - номер дорожки (0-79);                   *
512
;* FDD_Head - номер головки (0-1);                     *
513
;* FDD_Sector - номер сектора (1-18).                  *
514
;* Результат операции заносится в FDC_Status.          *
515
;* В случае успешного выполнения операции записи       *
516
;* содержимое FDD_DataBuffer будет занесено в сектор.  *
517
;*******************************************************
518
WriteSector:
519
        pushad
520
        call    save_timer_fdd_motor
521
; Установить скорость передачи 500 Кбайт/с
522
        mov     AX,0
523
        mov     DX,03F7h
524
        out     DX,AL
525
; Инициализировать канал прямого доступа к памяти
526
        mov     [dmamode],0x4A
527
        call    Init_FDC_DMA
528
; Подать команду "Запись данных"
529
        mov     AL,0xC5  ;0x45  ;запись в мультитрековом режиме
530
        call    FDCDataOutput
531
        mov     AL,[FDD_Head]
532
        shl     AL,2
533
        call    FDCDataOutput
534
        mov     AL,[FDD_Track]
535
        call    FDCDataOutput
536
        mov     AL,[FDD_Head]
537
        call    FDCDataOutput
538
        mov     AL,[FDD_Sector]
539
        call    FDCDataOutput
540
        mov     AL,2    ;код размера сектора (512 байт)
541
        call    FDCDataOutput
542
        mov     AL,18; 3Fh  ;число секторов на дорожке
543
        call    FDCDataOutput
544
        mov     AL,1Bh  ;значение GPL
545
        call    FDCDataOutput
546
        mov     AL,0FFh ;значение DTL
547
        call    FDCDataOutput
548
; Ожидаем прерывание по завершении операции
549
        call    WaitFDCInterrupt
550
        cmp     [FDC_Status],FDC_Normal
551
        jne     @@Exit_3
552
; Считываем статус завершения операции
553
        call    GetStatusInfo
554
        test    [FDC_ST0],11000000b  ;11011000b
555
        jnz     @@Err_2
556
        mov     [FDC_Status],FDC_Normal
557
        jmp @@Exit_3
558
@@Err_2:  mov     [FDC_Status],FDC_SectorNotFound
559
@@Exit_3:
560
        call    save_timer_fdd_motor
561
        popad
562
        ret
563
 
564
;*******************************************************
565
;*   ЗАПИСЬ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
566
;* Параметры передаются через глобальные переменные:   *
567
;* FDD_Track - номер дорожки (0-79);                   *
568
;* FDD_Head - номер головки (0-1);                     *
569
;* FDD_Sector - номер сектора (1-18).                  *
570
;* Результат операции заносится в FDC_Status.          *
571
;* В случае успешного выполнения операции записи       *
572
;* содержимое FDD_DataBuffer будет занесено в сектор.  *
573
;*******************************************************
574
WriteSectWithRetr:
575
        pusha
576
; Обнулить счетчик повторения операции рекалибровки
577
        mov     [RecalRepCounter],0
578
@@TryAgain_1:
579
; Обнулить счетчик повторения операции чтени
580
        mov     [ReadRepCounter],0
581
@@WriteSector_1:
582
        call    WriteSector
583
        cmp     [FDC_Status],0
584
        je      @@Exit_4
585
        cmp     [FDC_Status],1
586
        je      @@Err_4
587
        ; Троекратное повторение чтени
588
        inc     [ReadRepCounter]
589
        cmp     [ReadRepCounter],3
590
        jb      @@WriteSector_1
591
        ; Троекратное повторение рекалибровки
592
        call    RecalibrateFDD
593
        call    SeekTrack
594
        inc     [RecalRepCounter]
595
        cmp     [RecalRepCounter],3
596
        jb      @@TryAgain_1
597
@@Exit_4:
598
        popa
599
        ret
600
@@Err_4:
601
        mov   [flp_status],0
602
        popa
603
        ret
604
 
605
;*********************************************
606
;* ПОЛУЧИТЬ ИНФОРМАЦИЮ О РЕЗУЛЬТАТЕ ОПЕРАЦИИ *
607
;*********************************************
608
GetStatusInfo:
609
        push    AX
610
        call    FDCDataInput
611
        mov     [FDC_ST0],AL
612
        call    FDCDataInput
613
        mov     [FDC_ST1],AL
614
        call    FDCDataInput
615
        mov     [FDC_ST2],AL
616
        call    FDCDataInput
617
        mov     [FDC_C],AL
618
        call    FDCDataInput
619
        mov     [FDC_H],AL
620
        call    FDCDataInput
621
        mov     [FDC_R],AL
622
        call    FDCDataInput
623
        mov     [FDC_N],AL
624
        pop     AX
625
        ret
626