Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
161 diamond 1
; Low-level driver for HDD access
2
; DMA support by Mario79
160 diamond 3
 
4
;**************************************************************************
5
;
6
;   0x600008  - first entry in cache list
7
;
8
;            +0   - lba sector
9
;            +4   - state of cache sector
10
;                   0 = empty
11
;                   1 = used for read  ( same as in hd )
12
;                   2 = used for write ( differs from hd )
13
;
14
;      +65536 - cache entries
15
;
16
;**************************************************************************
17
 
18
align 4
19
hd_read:
20
;-----------------------------------------------------------
21
; input  : eax = block to read
22
;          ebx = destination
23
;-----------------------------------------------------------
24
    push  ecx esi edi           ; scan cache
25
 
26
    mov   ecx,cache_max         ; entries in cache
27
    mov   esi,0x600000+8
28
    mov   edi,1
29
 
30
  hdreadcache:
31
 
32
    cmp   dword [esi+4],0       ; empty
33
    je    nohdcache
34
 
35
    cmp   [esi],eax             ; correct sector
36
    je    yeshdcache
37
 
38
  nohdcache:
39
 
40
    add   esi,8
41
    inc   edi
42
    dec   ecx
43
    jnz   hdreadcache
44
 
45
    call  find_empty_slot       ; ret in edi
46
    cmp   [hd_error],0
47
    jne   return_01
48
        cmp     [dma_hdd], 1
49
        jnz     .nodma
50
        call    hd_read_dma
51
        jmp     @f
52
.nodma:
53
        call    hd_read_pio
54
@@:
55
 
56
    lea   esi,[edi*8+0x600000]
57
    mov   [esi],eax             ; sector number
58
    mov   dword [esi+4],1       ; hd read - mark as same as in hd
59
 
60
  yeshdcache:
61
 
62
    mov   esi,edi
63
    shl   esi,9
64
    add   esi,0x600000+65536
65
    mov   edi,ebx
66
    mov   ecx,512/4
67
    cld
68
    rep   movsd                 ; move data
69
 return_01:
70
    pop   edi esi ecx
71
    ret
72
 
73
align 4
74
hd_read_pio:
75
    push  eax edx
76
 
77
    call  disable_ide_int
78
 
79
    call  wait_for_hd_idle
80
    cmp   [hd_error],0
81
    jne   hd_read_error
82
 
83
;    cli
84
    xor   eax,eax
85
    mov   edx,[hdbase]
86
    inc   edx
87
    out   dx,al   ; ATAFeatures регистр "особенностей"
88
    inc   edx
89
    inc   eax
90
    out   dx,al   ; ATASectorCount счётчик секторов
91
    inc   edx
92
    mov   eax,[esp+4]
93
    out   dx,al   ; ATASectorNumber регистр номера сектора
94
    shr   eax,8
95
    inc   edx
96
    out   dx,al   ; ATACylinder номер цилиндра (младший байт)
97
    shr   eax,8
98
    inc   edx
99
    out   dx,al   ; номер цилиндра (старший байт)
100
    shr   eax,8
101
    inc   edx
102
    and   al,1+2+4+8
103
    add   al,byte [hdid]
104
    add   al,128+64+32
105
    out   dx,al   ; номер головки/номер диска
106
    inc   edx
107
    mov   al,20h
108
    out   dx,al   ; ATACommand регистр команд
109
;    sti
110
 
111
    call  wait_for_sector_buffer
112
 
113
    cmp   [hd_error],0
114
    jne   hd_read_error
115
 
116
;    cli
117
    push  edi
118
    shl   edi,9
119
    add   edi,0x600000+65536
120
    mov   ecx,256
121
    mov   edx,[hdbase]
122
    cld
123
    rep   insw
124
    pop   edi
125
;    sti
126
 
127
    call  enable_ide_int
128
 
129
    pop   edx eax
130
    ret
131
 
132
disable_ide_int:
133
        mov edx,[hdbase]
134
        add edx,0x206
135
        mov al,2
136
        out dx,al
137
        ret
138
 
139
enable_ide_int:
140
        mov edx,[hdbase]
141
        add edx,0x206
142
        mov al,0
143
        out dx,al
144
        ret
145
 
146
align 4
147
hd_write:
148
;-----------------------------------------------------------
149
; input  : eax = block
150
;          ebx = pointer to memory
151
;-----------------------------------------------------------
152
    push  ecx esi edi
153
 
154
    ; check if the cache already has the sector and overwrite it
155
 
156
    mov   ecx,cache_max
157
    mov   esi,0x600000+8
158
    mov   edi,1
159
 
160
  hdwritecache:
161
 
162
    cmp   dword [esi+4],0       ; if cache slot is empty
163
    je    not_in_cache_write
164
 
165
    cmp   [esi],eax             ; if the slot has the sector
166
    je    yes_in_cache_write
167
 
168
  not_in_cache_write:
169
 
170
    add   esi,8
171
    inc   edi
172
    dec   ecx
173
    jnz   hdwritecache
174
 
175
    ; sector not found in cache
176
    ; write the block to a new location
177
 
178
    call  find_empty_slot       ; ret in edi
179
    cmp   [hd_error],0
180
    jne   hd_write_access_denied
181
 
182
    lea   esi,[edi*8+0x600000]
183
    mov   [esi],eax             ; sector number
184
 
185
  yes_in_cache_write:
186
 
187
    mov   dword [esi+4],2       ; write - differs from hd
188
 
189
    shl   edi,9
190
    add   edi,0x600000+65536
191
    mov   esi,ebx
192
    mov   ecx,512/4
193
    cld
194
    rep   movsd                 ; move data
195
 hd_write_access_denied:
196
    pop   edi esi ecx
197
    ret
198
 
199
 
200
write_cache:
201
;-----------------------------------------------------------
202
; write all changed sectors to disk
203
;-----------------------------------------------------------
204
    push  eax ecx edx esi edi
205
 
206
    ; write difference ( 2 ) from cache to hd
207
 
208
    mov   ecx,cache_max
209
    mov   esi,0x600000+8
210
    mov   edi,1
211
 
212
  write_cache_more:
213
 
214
    cmp   dword [esi+4],2       ; if cache slot is not different
215
    jne   .write_chain
216
 
217
    mov   dword [esi+4],1       ; same as in hd
218
    mov   eax,[esi]             ; eax = sector to write
219
 
220
    cmp   eax,[PARTITION_START]
221
    jb    danger
222
    cmp   eax,[PARTITION_END]
223
    ja    danger
224
 
225
        cmp     [dma_hdd], 1
226
        jnz     .nodma
227
; Объединяем запись цепочки последовательных секторов в одно обращение к диску
228
        cmp     ecx, 1
229
        jz      .nonext
230
        cmp     dword [esi+8+4], 2
231
        jnz     .nonext
232
        push    eax
233
        inc     eax
234
        cmp     eax, [esi+8]
235
        pop     eax
236
        jnz     .nonext
237
        cmp     [cache_chain_started], 1
238
        jz      @f
239
        mov     [cache_chain_started], 1
240
        mov     [cache_chain_size], 0
241
        mov     [cache_chain_pos], edi
242
        mov     [cache_chain_ptr], esi
243
@@:
244
        inc     [cache_chain_size]
245
        cmp     [cache_chain_size], 64
246
        jnz     .continue
247
        jmp     .write_chain
248
.nonext:
249
        call    flush_cache_chain
250
        mov     [cache_chain_size], 1
251
        mov     [cache_chain_ptr], esi
252
        call    write_cache_sector
253
        jmp     .continue
254
.nodma:
255
        call    cache_write_pio
256
.write_chain:
257
        call    flush_cache_chain
258
 
259
.continue:
260
  danger:
261
 
262
    add   esi,8
263
    inc   edi
264
    dec   ecx
265
    jnz   write_cache_more
266
        call    flush_cache_chain
267
 return_02:
268
    pop   edi esi edx ecx eax
269
    ret
270
 
271
flush_cache_chain:
272
        cmp     [cache_chain_started], 0
273
        jz      @f
274
        call    write_cache_chain
275
        mov     [cache_chain_started], 0
276
@@:
277
        ret
278
 
279
align 4
280
cache_write_pio:
281
    call  disable_ide_int
282
 
283
    call  wait_for_hd_idle
284
    cmp   [hd_error],0
285
    jne   hd_write_error
286
 
287
;    cli
288
    xor   eax,eax
289
    mov   edx,[hdbase]
290
    inc   edx
291
    out   dx,al
292
    inc   edx
293
    inc   eax
294
    out   dx,al
295
    inc   edx
296
    mov   eax,[esi]             ; eax = sector to write
297
    out   dx,al
298
    shr   eax,8
299
    inc   edx
300
    out   dx,al
301
    shr   eax,8
302
    inc   edx
303
    out   dx,al
304
    shr   eax,8
305
    inc   edx
306
    and   al,1+2+4+8
307
    add   al,byte [hdid]
308
    add   al,128+64+32
309
    out   dx,al
310
    inc   edx
311
    mov   al,30h
312
    out   dx,al
313
;    sti
314
 
315
    call  wait_for_sector_buffer
316
 
317
    cmp   [hd_error],0
318
    jne   hd_write_error
319
 
320
    push  ecx esi
321
 
322
;    cli
323
    mov   esi,edi
324
    shl   esi,9
325
    add   esi,0x600000+65536    ; esi = from memory position
326
    mov   ecx,256
327
    mov   edx,[hdbase]
328
    cld
329
    rep   outsw
330
;    sti
331
 
332
    call  enable_ide_int
333
    pop   esi ecx
334
 
335
    ret
336
 
337
align 4
338
find_empty_slot:
339
;-----------------------------------------------------------
340
; find empty or read slot, flush cache if next 10% is used by write
341
; output : edi = cache slot
342
;-----------------------------------------------------------
343
;    push  ecx esi
344
 
345
  search_again:
346
 
347
    mov   ecx,cache_max*10/100
348
    mov   edi,[cache_search_start]
349
 
350
  search_for_empty:
351
 
352
    inc   edi
353
    cmp   edi,cache_max
354
    jbe   inside_cache
355
    mov   edi,1
356
 
357
  inside_cache:
358
 
359
    cmp   dword [edi*8+0x600000+4],2    ; get cache slot info
360
    jb    found_slot                    ; it's empty or read
361
    dec   ecx
362
    jnz   search_for_empty
363
 
364
    call  write_cache                   ; no empty slots found, write all
365
    cmp   [hd_error],0
366
    jne   found_slot_access_denied
367
 
368
    jmp   search_again                  ; and start again
369
 
370
  found_slot:
371
 
372
    mov   [cache_search_start],edi
373
  found_slot_access_denied:
374
    ret
375
 
376
align 4
377
clear_hd_cache:
378
 
379
    push  eax ecx edi
380
    mov   edi,0x600000
381
    mov   ecx,16384
382
    xor   eax,eax
383
    cld
384
    rep   stosd                 ; clear hd cache with 0
385
    mov   [cache_search_start],eax
386
    mov   [fat_in_cache],-1
387
    mov   [fat_change],0
388
    pop   edi ecx eax
389
    ret
390
 
391
save_hd_wait_timeout:
392
 
393
    push  eax
394
    mov   eax,[timer_ticks];[0xfdf0]
395
    add   eax,300               ; 3 sec timeout
396
    mov   [hd_wait_timeout],eax
397
    pop   eax
398
    ret
399
 
400
align 4
401
check_hd_wait_timeout:
402
 
403
    push  eax
404
    mov   eax,[hd_wait_timeout]
405
    cmp   [timer_ticks], eax ;[0xfdf0],eax
406
    jg    hd_timeout_error
407
    pop   eax
408
    mov   [hd_error],0
409
    ret
410
 
411
iglobal
412
  hd_timeout_str   db 'K : FS - HD timeout',13,10,0
413
  hd_read_str      db 'K : FS - HD read error',13,10,0
414
  hd_write_str     db 'K : FS - HD write error',13,10,0
415
  hd_lba_str       db 'K : FS - HD LBA error',13,10,0
416
endg
417
 
418
hd_timeout_error:
419
 
420
    call  clear_hd_cache
421
    call  clear_application_table_status
422
    mov   esi,hd_timeout_str
423
    call  sys_msg_board_str
424
;    jmp   $
425
    mov   [hd_error],1
426
    pop   eax
427
    ret
428
 
429
hd_read_error:
430
 
431
    call  clear_hd_cache
432
    call  clear_application_table_status
433
    mov   esi,hd_read_str
434
    call  sys_msg_board_str
435
    pop   edx eax
161 diamond 436
    ret
160 diamond 437
 
438
hd_write_error:
439
 
440
    call  clear_hd_cache
441
    call  clear_application_table_status
442
    mov   esi,hd_write_str
443
    call  sys_msg_board_str
161 diamond 444
    ret
160 diamond 445
 
446
hd_write_error_dma:
447
        call    clear_hd_cache
448
        call    clear_application_table_status
449
        mov     esi, hd_write_str
450
        call    sys_msg_board_str
451
        pop     esi
161 diamond 452
        ret
160 diamond 453
 
454
hd_lba_error:
455
    call  clear_hd_cache
456
    call  clear_application_table_status
457
    mov   esi,hd_lba_str
458
    call  sys_msg_board_str
459
    jmp   LBA_read_ret
460
 
461
 
462
align 4
463
wait_for_hd_idle:
464
 
465
    push  eax edx
466
 
467
    call  save_hd_wait_timeout
468
 
469
    mov   edx,[hdbase]
470
    add   edx,0x7
471
 
472
  wfhil1:
473
 
474
    call  check_hd_wait_timeout
475
    cmp   [hd_error],0
476
    jne   @f
477
 
478
    in    al,dx
479
    test  al,128
480
    jnz   wfhil1
481
 
482
 @@:
483
 
484
    pop   edx eax
485
    ret
486
 
487
 
488
align 4
489
wait_for_sector_buffer:
490
 
491
    push  eax edx
492
 
493
    mov   edx,[hdbase]
494
    add   edx,0x7
495
 
496
    call  save_hd_wait_timeout
497
 
498
  hdwait_sbuf:                  ; wait for sector buffer to be ready
499
 
500
    call  check_hd_wait_timeout
501
    cmp   [hd_error],0
502
    jne   @f
503
 
504
    in    al,dx
505
    test  al,8
506
    jz    hdwait_sbuf
507
 
508
    mov   [hd_error],0
509
 
510
    cmp   [hd_setup],1          ; do not mark error for setup request
511
    je    buf_wait_ok
512
 
513
    test  al,1                  ; previous command ended up with an error
514
    jz    buf_wait_ok
515
 @@:
516
    mov   [hd_error],1
517
 
518
  buf_wait_ok:
519
 
520
    pop   edx eax
521
    ret
522
 
161 diamond 523
; \begin{Mario79}
160 diamond 524
align 4
525
wait_for_sector_dma_ide0:
526
        push    eax
527
        push    edx
528
        call    save_hd_wait_timeout
529
.wait:
530
        call    change_task
531
        cmp     [irq14_func], hdd_irq14
532
        jnz     .done
533
        call    check_hd_wait_timeout
534
        cmp     [hd_error], 0
535
        jz      .wait
536
        mov     [irq14_func], hdd_irq_null
537
        mov     dx, [IDEContrRegsBaseAddr]
538
        mov     al, 0
539
        out     dx, al
540
.done:
541
        pop     edx
542
        pop     eax
543
        ret
544
 
545
align 4
546
wait_for_sector_dma_ide1:
547
        push    eax
548
        push    edx
549
        call    save_hd_wait_timeout
550
.wait:
551
        call    change_task
552
        cmp     [irq15_func], hdd_irq15
553
        jnz     .done
554
        call    check_hd_wait_timeout
555
        cmp     [hd_error], 0
556
        jz      .wait
557
        mov     [irq15_func], hdd_irq_null
558
        mov     dx, [IDEContrRegsBaseAddr]
559
        add     dx, 8
560
        mov     al, 0
561
        out     dx, al
562
.done:
563
        pop     edx
564
        pop     eax
565
        ret
566
 
567
iglobal
568
align 4
569
; note that IDE descriptor table must be 4-byte aligned and do not cross 4K boundary
570
IDE_descriptor_table:
571
        dd      284000h
572
        dw      2000h
573
        dw      8000h
574
 
575
dma_cur_sector  dd      not 40h
576
irq14_func      dd      hdd_irq_null
577
irq15_func      dd      hdd_irq_null
578
endg
579
 
580
uglobal
581
; all uglobals are zeroed at boot
582
dma_process     dd      0
583
dma_slot_ptr    dd      0
584
cache_chain_pos dd      0
585
cache_chain_ptr dd      0
586
cache_chain_size        db      0
587
cache_chain_started     db      0
588
dma_task_switched       db      0
589
dma_hdd         db      0
590
endg
591
 
592
align 4
593
hdd_irq14:
594
        pushfd
595
        cli
596
        pushad
597
        mov     [irq14_func], hdd_irq_null
598
        mov     dx, [IDEContrRegsBaseAddr]
599
        mov     al, 0
600
        out     dx, al
601
        call    update_counters
602
        mov     ebx, [dma_process]
603
        cmp     [0x3000], ebx
604
        jz      .noswitch
605
        mov     [dma_task_switched], 1
606
        mov     edi, [dma_slot_ptr]
607
        mov     eax, [0x3000]
608
        mov     [dma_process], eax
609
        mov     eax, [0x3010]
610
        mov     [dma_slot_ptr], eax
611
        mov     [0x3000], ebx
612
        mov     [0x3010], edi
613
        mov     byte [0xFFFF], 1
614
        call    do_change_task
615
.noswitch:
616
        popad
617
        popfd
618
align 4
619
hdd_irq_null:
620
        ret
621
 
622
align 4
623
hdd_irq15:
624
        pushfd
625
        cli
626
        pushad
627
        mov     [irq15_func], hdd_irq_null
628
        mov     dx, [IDEContrRegsBaseAddr]
629
        add     dx, 8
630
        mov     al, 0
631
        out     dx, al
632
        call    update_counters
633
        mov     ebx, [dma_process]
634
        cmp     [0x3000], ebx
635
        jz      .noswitch
636
        mov     [dma_task_switched], 1
637
        mov     edi, [dma_slot_ptr]
638
        mov     eax, [0x3000]
639
        mov     [dma_process], eax
640
        mov     eax, [0x3010]
641
        mov     [dma_slot_ptr], eax
642
        mov     [0x3000], ebx
643
        mov     [0x3010], edi
644
        mov     byte [0xFFFF], 1
645
        call    do_change_task
646
.noswitch:
647
        popad
648
        popfd
649
        ret
650
 
651
align 4
652
hd_read_dma:
653
        push    eax
654
        push    edx
655
        mov     edx, [dma_cur_sector]
656
        cmp     eax, edx
657
        jb      .notread
658
        add     edx, 15
659
        cmp     [esp+4], edx
660
        ja      .notread
661
        mov     eax, [esp+4]
662
        sub     eax, [dma_cur_sector]
663
        shl     eax, 9
664
        add     eax, 0x284000
665
        push    ecx esi edi
666
        mov     esi, eax
667
        shl     edi, 9
668
        add     edi, 0x610000
669
        mov     ecx, 512/4
670
        cld
671
        rep     movsd
672
        pop     edi esi ecx
673
        pop     edx
674
        pop     eax
675
        ret
676
.notread:
677
        mov     eax, IDE_descriptor_table
678
        mov     dword [eax], 0x284000
679
        mov     word [eax+4], 0x2000
680
        mov     dx, [IDEContrRegsBaseAddr]
681
        cmp     [hdbase], 0x1F0
682
        jz      @f
683
        add     edx, 8
684
@@:
685
        push    edx
686
        add     edx, 4
687
        out     dx, eax
688
        pop     edx
689
        mov     al, 0
690
        out     dx, al
691
        add     edx, 2
692
        mov     al, 6
693
        out     dx, al
694
        call    wait_for_hd_idle
695
        cmp     [hd_error], 0
696
        jnz     hd_read_error
697
        call    disable_ide_int
698
        xor     eax, eax
699
        mov     edx, [hdbase]
700
        inc     edx
701
        out     dx, al
702
        inc     edx
703
        mov     eax, 10h
704
        out     dx, al
705
        inc     edx
706
        mov     eax, [esp+4]
707
        out     dx, al
708
        shr     eax, 8
709
        inc     edx
710
        out     dx, al
711
        shr     eax, 8
712
        inc     edx
713
        out     dx, al
714
        shr     eax, 8
715
        inc     edx
716
        and     al, 0xF
717
        add     al, byte [hdid]
718
        add     al, 11100000b
719
        out     dx, al
720
        inc     edx
721
        mov     al, 0xC8
722
        out     dx, al
723
        mov     dx, [IDEContrRegsBaseAddr]
724
        cmp     [hdbase], 0x1F0
725
        jz      @f
726
        add     dx, 8
727
@@:
728
        mov     al, 9
729
        out     dx, al
730
        mov     eax, [0x3000]
731
        mov     [dma_process], eax
732
        mov     eax, [0x3010]
733
        mov     [dma_slot_ptr], eax
734
        cmp     [hdbase], 0x1F0
735
        jnz     .ide1
736
        mov     [irq14_func], hdd_irq14
737
        jmp     @f
738
.ide1:
739
        mov     [irq15_func], hdd_irq15
740
@@:
741
        call    enable_ide_int
742
        cmp     [hdbase], 0x1F0
743
        jnz     .wait_ide1
744
        call    wait_for_sector_dma_ide0
745
        jmp     @f
746
.wait_ide1:
747
        call    wait_for_sector_dma_ide1
748
@@:
749
        cmp     [hd_error], 0
750
        jnz     hd_read_error
751
        pop     edx
752
        pop     eax
753
        mov     [dma_cur_sector], eax
754
        jmp     hd_read_dma
755
 
756
align 4
757
write_cache_chain:
758
        push    esi
759
        mov     eax, IDE_descriptor_table
760
        mov     edx, [cache_chain_pos]
761
        shl     edx, 9
762
        add     edx, 0x610000
763
        mov     [eax], edx
764
        movzx   edx, [cache_chain_size]
765
        shl     edx, 9
766
        mov     [eax+4], dx
767
        jmp     do_write_dma
768
write_cache_sector:
769
        push    esi
770
        mov     eax, IDE_descriptor_table
771
        mov     edx, edi
772
        shl     edx, 9
773
        add     edx, 0x610000
774
        mov     [eax], edx
775
        mov     word [eax+4], 0x200
776
do_write_dma:
777
        mov     dx, [IDEContrRegsBaseAddr]
778
        cmp     [hdbase], 0x1F0
779
        jz      @f
780
        add     edx, 8
781
@@:
782
        push    edx
783
        add     edx, 4
784
        out     dx, eax
785
        pop     edx
786
        mov     al, 0
787
        out     dx, al
788
        add     edx, 2
789
        mov     al, 6
790
        out     dx, al
791
        call    wait_for_hd_idle
792
        cmp     [hd_error], 0
793
        jnz     hd_write_error_dma
794
        call    disable_ide_int
795
        xor     eax, eax
796
        mov     edx, [hdbase]
797
        inc     edx
798
        out     dx, al
799
        inc     edx
800
        mov     al, [cache_chain_size]
801
        out     dx, al
802
        inc     edx
803
        mov     esi, [cache_chain_ptr]
804
        mov     eax, [esi]
805
        out     dx, al
806
        shr     eax, 8
807
        inc     edx
808
        out     dx, al
809
        shr     eax, 8
810
        inc     edx
811
        out     dx, al
812
        shr     eax, 8
813
        inc     edx
814
        and     al, 0xF
815
        add     al, byte [hdid]
816
        add     al, 11100000b
817
        out     dx, al
818
        inc     edx
819
        mov     al, 0xCA
820
        out     dx, al
821
        mov     dx, [IDEContrRegsBaseAddr]
822
        cmp     [hdbase], 0x1F0
823
        jz      @f
824
        add     dx, 8
825
@@:
826
        mov     al, 1
827
        out     dx, al
828
        mov     eax, [0x3000]
829
        mov     [dma_process], eax
830
        mov     eax, [0x3010]
831
        mov     [dma_slot_ptr], eax
832
        cmp     [hdbase], 0x1F0
833
        jnz     .ide1
834
        mov     [irq14_func], hdd_irq14
835
        jmp     @f
836
.ide1:
837
        mov     [irq15_func], hdd_irq15
838
@@:
839
        call    enable_ide_int
840
        mov     [dma_cur_sector], not 0x40
841
        cmp     [hdbase], 0x1F0
842
        jnz     .wait_ide1
843
        call    wait_for_sector_dma_ide0
844
        jmp     @f
845
.wait_ide1:
846
        call    wait_for_sector_dma_ide1
847
@@:
848
        cmp     [hd_error], 0
849
        jnz     hd_write_error_dma
850
        pop     esi
851
        ret
852
 
853
uglobal
854
IDEContrRegsBaseAddr    dw      ?
855
endg
161 diamond 856
; \end{Mario79}