Subversion Repositories Kolibri OS

Rev

Rev 4624 | Rev 4720 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4624 Rev 4700
Line 3... Line 3...
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Line 7... Line 7...
7
 
7
 
Line 8... Line 8...
8
$Revision: 4624 $
8
$Revision: 4700 $
9
 
9
 
10
 
10
 
Line 15... Line 15...
15
struct HD_DATA
15
struct HD_DATA
16
hdbase  dd      ?
16
hdbase  dd      ?
17
hdid    dd      ?
17
hdid    dd      ?
18
hdpos   dd      ?
18
hdpos   dd      ?
19
ends
19
ends
20
 
-
 
-
 
20
;-----------------------------------------------------------------------------
21
iglobal
21
iglobal
22
align 4
22
align 4
23
ide_callbacks:
23
ide_callbacks:
24
        dd      ide_callbacks.end - ide_callbacks       ; strucsize
24
        dd      ide_callbacks.end - ide_callbacks       ; strucsize
25
        dd      0       ; no close function
25
        dd      0       ; no close function
Line 33... Line 33...
33
 
33
 
34
hd0_data        HD_DATA         ?,    0, 1
34
hd0_data        HD_DATA         ?,    0, 1
35
hd1_data        HD_DATA         ?, 0x10, 2
35
hd1_data        HD_DATA         ?, 0x10, 2
36
hd2_data        HD_DATA         ?,    0, 3
36
hd2_data        HD_DATA         ?,    0, 3
-
 
37
hd3_data        HD_DATA         ?, 0x10, 4
-
 
38
hd4_data        HD_DATA         ?,    0, 5
-
 
39
hd5_data        HD_DATA         ?, 0x10, 6
-
 
40
hd6_data        HD_DATA         ?,    0, 7
-
 
41
hd7_data        HD_DATA         ?, 0x10, 8
-
 
42
hd8_data        HD_DATA         ?,    0, 9
-
 
43
hd9_data        HD_DATA         ?, 0x10, 10
-
 
44
hd10_data       HD_DATA         ?,    0, 11
37
hd3_data        HD_DATA         ?, 0x10, 4
45
hd11_data       HD_DATA         ?, 0x10, 12
38
 
46
 
39
hd_address_table:
47
ide_mutex_table:
-
 
48
        dd ide_channel1_mutex
-
 
49
        dd ide_channel2_mutex
-
 
50
        dd ide_channel3_mutex
-
 
51
        dd ide_channel4_mutex
40
        dd      0x1f0, 0x00, 0x1f0, 0x10
52
        dd ide_channel5_mutex
41
        dd      0x170, 0x00, 0x170, 0x10
53
        dd ide_channel6_mutex
42
endg
-
 
-
 
54
endg
43
 
55
;-----------------------------------------------------------------------------
44
uglobal
56
uglobal
45
ide_mutex               MUTEX
57
ide_mutex               MUTEX
46
ide_channel1_mutex      MUTEX
58
ide_channel1_mutex      MUTEX
-
 
59
ide_channel2_mutex      MUTEX
-
 
60
ide_channel3_mutex      MUTEX
-
 
61
ide_channel4_mutex      MUTEX
-
 
62
ide_channel5_mutex      MUTEX
47
ide_channel2_mutex      MUTEX
63
ide_channel6_mutex      MUTEX
48
endg
-
 
-
 
64
endg
49
 
65
;-----------------------------------------------------------------------------
50
proc ide_read stdcall uses edi, \
66
proc ide_read stdcall uses edi, \
51
        hd_data, buffer, startsector:qword, numsectors
67
        hd_data, buffer, startsector:qword, numsectors
52
        ; hd_data = pointer to hd*_data
68
        ; hd_data = pointer to hd*_data
53
        ; buffer = pointer to buffer for data
69
        ; buffer = pointer to buffer for data
Line 65... Line 81...
65
        mov     dword [ecx], 0
81
        mov     dword [ecx], 0
66
        mov     [sectors_todo], eax
82
        mov     [sectors_todo], eax
67
; 2. Acquire the global lock.
83
; 2. Acquire the global lock.
68
        mov     ecx, ide_mutex
84
        mov     ecx, ide_mutex
69
        call    mutex_lock
85
        call    mutex_lock
-
 
86
 
70
        mov     ecx, ide_channel2_mutex
87
        mov     ecx, [hd_data]
71
        mov     eax, [hd_data]
88
        mov     ecx, [ecx+HD_DATA.hdpos]
72
        push    ecx
89
        dec     ecx
73
        mov     ecx, [hd_address_table]
-
 
74
        cmp     [eax+HD_DATA.hdbase], ecx ; 0x1F0
-
 
75
        pop     ecx
90
        shr     ecx, 1
76
        jne     .IDE_Channel_2
91
        shl     ecx, 2
77
        mov     ecx, ide_channel1_mutex
92
        mov     ecx, [ecx + ide_mutex_table]
78
.IDE_Channel_2:
-
 
79
        mov     [channel_lock], ecx
93
        mov     [channel_lock], ecx
80
        call    mutex_lock
94
        call    mutex_lock
81
; 3. Convert parameters to the form suitable for worker procedures.
95
; 3. Convert parameters to the form suitable for worker procedures.
82
; Underlying procedures do not know about 64-bit sectors.
96
; Underlying procedures do not know about 64-bit sectors.
83
; Worker procedures use global variables and edi for [buffer].
97
; Worker procedures use global variables and edi for [buffer].
84
        cmp     dword [startsector+4], 0
98
        cmp     dword [startsector+4], 0
85
        jnz     .fail
99
        jnz     .fail
-
 
100
 
86
        and     [hd_error], 0
101
        and     [hd_error], 0
87
        mov     ecx, [hd_data]
102
        mov     ecx, [hd_data]
88
        mov     eax, [ecx+HD_DATA.hdbase]
103
        mov     eax, [ecx+HD_DATA.hdbase]
89
        mov     [hdbase], eax
104
        mov     [hdbase], eax
90
        mov     eax, [ecx+HD_DATA.hdid]
105
        mov     eax, [ecx+HD_DATA.hdid]
Line 96... Line 111...
96
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
111
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
97
.sectors_loop:
112
.sectors_loop:
98
; DMA read is permitted if [allow_dma_access]=1 or 2
113
; DMA read is permitted if [allow_dma_access]=1 or 2
99
        cmp     [allow_dma_access], 2
114
        cmp     [allow_dma_access], 2
100
        ja      .nodma
115
        ja      .nodma
101
        cmp     [dma_hdd], 1
-
 
102
        jnz     .nodma
-
 
103
;--------------------------------------
-
 
104
        push    eax
-
 
105
        mov     eax, [hd_address_table]
-
 
106
        cmp     [hdbase], eax ; 0x1F0
-
 
107
        pop     eax
-
 
108
        jnz     @f
-
 
Line 109... Line 116...
109
 
116
 
110
        test    [DRIVE_DATA+1], byte 10100000b
117
        cmp     [ecx+IDE_DATA.dma_hdd], 1
Line 111... Line -...
111
        jnz     .nodma
-
 
112
 
-
 
113
        jmp     .dma
-
 
114
@@:
-
 
115
        test    [DRIVE_DATA+1], byte 1010b
-
 
116
        jnz     .nodma
-
 
117
.dma:
118
        jnz     .nodma
118
;--------------------------------------
119
 
-
 
120
        call    hd_read_dma
119
        call    hd_read_dma
121
        jmp     @f
120
        jmp     @f
122
;--------------------------------------
-
 
123
.nodma:
121
.nodma:
124
        call    hd_read_pio
122
        call    hd_read_pio
125
;--------------------------------------
123
@@:
126
@@:
-
 
127
        cmp     [hd_error], 0
124
        cmp     [hd_error], 0
128
        jnz     .fail
125
        jnz     .fail
129
 
126
        mov     ecx, [numsectors]
130
        mov     ecx, [numsectors]
127
        inc     dword [ecx]     ; one more sector is read
131
        inc     dword [ecx]     ; one more sector is read
-
 
132
        dec     [sectors_todo]
128
        dec     [sectors_todo]
133
        jz      .done
129
        jz      .done
134
 
-
 
135
        inc     eax
130
        inc     eax
136
        jnz     .sectors_loop
131
        jnz     .sectors_loop
137
;--------------------------------------
132
; 5. Loop is done, either due to error or because everything is done.
138
; 5. Loop is done, either due to error or because everything is done.
133
; Release the global lock and return the corresponding status.
139
; Release the global lock and return the corresponding status.
134
.fail:
140
.fail:
-
 
141
        mov     ecx, [channel_lock]
135
        mov     ecx, [channel_lock]
142
        call    mutex_unlock
136
        call    mutex_unlock
143
 
-
 
144
        mov     ecx, ide_mutex
137
        mov     ecx, ide_mutex
145
        call    mutex_unlock
138
        call    mutex_unlock
146
 
-
 
147
        or      eax, -1
139
        or      eax, -1
148
        ret
140
        ret
149
;--------------------------------------
141
.done:
150
.done:
-
 
151
        mov     ecx, [channel_lock]
142
        mov     ecx, [channel_lock]
152
        call    mutex_unlock
143
        call    mutex_unlock
153
 
-
 
154
        mov     ecx, ide_mutex
144
        mov     ecx, ide_mutex
155
        call    mutex_unlock
145
        call    mutex_unlock
156
 
146
        xor     eax, eax
157
        xor     eax, eax
147
        ret
-
 
-
 
158
        ret
148
endp
159
endp
149
 
160
;-----------------------------------------------------------------------------
150
proc ide_write stdcall uses esi edi, \
161
proc ide_write stdcall uses esi edi, \
151
        hd_data, buffer, startsector:qword, numsectors
162
        hd_data, buffer, startsector:qword, numsectors
152
        ; hd_data = pointer to hd*_data
163
        ; hd_data = pointer to hd*_data
Line 165... Line 176...
165
        mov     dword [ecx], 0
176
        mov     dword [ecx], 0
166
        mov     [sectors_todo], eax
177
        mov     [sectors_todo], eax
167
; 2. Acquire the global lock.
178
; 2. Acquire the global lock.
168
        mov     ecx, ide_mutex
179
        mov     ecx, ide_mutex
169
        call    mutex_lock
180
        call    mutex_lock
-
 
181
 
170
        mov     ecx, ide_channel2_mutex
182
        mov     ecx, [hd_data]
171
        mov     eax, [hd_data]
183
        mov     ecx, [ecx+HD_DATA.hdpos]
172
        push    ecx
184
        dec     ecx
173
        mov     ecx, [hd_address_table]
-
 
174
        cmp     [eax+HD_DATA.hdbase], ecx ; 0x1F0
-
 
175
        pop     ecx
185
        shr     ecx, 1
176
        jne     .IDE_Channel_2
186
        shl     ecx, 2
177
        mov     ecx, ide_channel1_mutex
187
        mov     ecx, [ecx + ide_mutex_table]
178
.IDE_Channel_2:
-
 
179
        mov     [channel_lock], ecx
188
        mov     [channel_lock], ecx
180
        call    mutex_lock
189
        call    mutex_lock
181
; 3. Convert parameters to the form suitable for worker procedures.
190
; 3. Convert parameters to the form suitable for worker procedures.
182
; Underlying procedures do not know about 64-bit sectors.
191
; Underlying procedures do not know about 64-bit sectors.
183
; Worker procedures use global variables and esi for [buffer].
192
; Worker procedures use global variables and esi for [buffer].
184
        cmp     dword [startsector+4], 0
193
        cmp     dword [startsector+4], 0
185
        jnz     .fail
194
        jnz     .fail
-
 
195
 
186
        and     [hd_error], 0
196
        and     [hd_error], 0
187
        mov     ecx, [hd_data]
197
        mov     ecx, [hd_data]
188
        mov     eax, [ecx+HD_DATA.hdbase]
198
        mov     eax, [ecx+HD_DATA.hdbase]
189
        mov     [hdbase], eax
199
        mov     [hdbase], eax
190
        mov     eax, [ecx+HD_DATA.hdid]
200
        mov     eax, [ecx+HD_DATA.hdid]
Line 198... Line 208...
198
; loop until all sectors will be processed.
208
; loop until all sectors will be processed.
199
.sectors_loop:
209
.sectors_loop:
200
        mov     ecx, 16
210
        mov     ecx, 16
201
        cmp     ecx, [sectors_todo]
211
        cmp     ecx, [sectors_todo]
202
        jbe     @f
212
        jbe     @f
-
 
213
 
203
        mov     ecx, [sectors_todo]
214
        mov     ecx, [sectors_todo]
-
 
215
;--------------------------------------
204
@@:
216
@@:
205
        mov     [cache_chain_size], cl
217
        mov     [cache_chain_size], cl
206
; DMA write is permitted only if [allow_dma_access]=1
218
; DMA write is permitted only if [allow_dma_access]=1
207
        cmp     [allow_dma_access], 2
219
        cmp     [allow_dma_access], 2
208
        jae     .nodma
220
        jae     .nodma
209
        cmp     [dma_hdd], 1
-
 
210
        jnz     .nodma
-
 
211
;--------------------------------------
-
 
212
        push    eax
-
 
213
        mov     eax, [hd_address_table]
-
 
214
        cmp     [hdbase], eax ; 0x1F0
-
 
215
        pop     eax
-
 
216
        jnz     @f
-
 
Line 217... Line 221...
217
 
221
 
218
        test    [DRIVE_DATA+1], byte 10100000b
222
        cmp     [ecx+IDE_DATA.dma_hdd], 1
Line 219... Line -...
219
        jnz     .nodma
-
 
220
 
-
 
221
        jmp     .dma
-
 
222
@@:
-
 
223
        test    [DRIVE_DATA+1], byte 1010b
-
 
224
        jnz     .nodma
-
 
225
.dma:
223
        jnz     .nodma
226
;--------------------------------------
224
 
-
 
225
        call    cache_write_dma
227
        call    cache_write_dma
226
        jmp     .common
228
        jmp     .common
227
;--------------------------------------
229
.nodma:
228
.nodma:
-
 
229
        mov     [cache_chain_size], 1
230
        mov     [cache_chain_size], 1
230
        call    cache_write_pio
231
        call    cache_write_pio
231
;--------------------------------------
232
.common:
232
.common:
-
 
233
        cmp     [hd_error], 0
233
        cmp     [hd_error], 0
234
        jnz     .fail
234
        jnz     .fail
235
 
235
        movzx   ecx, [cache_chain_size]
236
        movzx   ecx, [cache_chain_size]
236
        mov     eax, [numsectors]
237
        mov     eax, [numsectors]
237
        add     [eax], ecx
238
        add     [eax], ecx
-
 
239
        sub     [sectors_todo], ecx
238
        sub     [sectors_todo], ecx
240
        jz      .done
239
        jz      .done
241
 
-
 
242
        add     [edi], ecx
240
        add     [edi], ecx
243
        jc      .fail
241
        jc      .fail
244
 
242
        shl     ecx, 9
245
        shl     ecx, 9
-
 
246
        add     esi, ecx
243
        add     esi, ecx
247
        jmp     .sectors_loop
244
        jmp     .sectors_loop
248
;--------------------------------------
245
; 5. Loop is done, either due to error or because everything is done.
249
; 5. Loop is done, either due to error or because everything is done.
246
; Release the global lock and return the corresponding status.
250
; Release the global lock and return the corresponding status.
247
.fail:
251
.fail:
-
 
252
        mov     ecx, [channel_lock]
248
        mov     ecx, [channel_lock]
253
        call    mutex_unlock
249
        call    mutex_unlock
254
 
-
 
255
        mov     ecx, ide_mutex
250
        mov     ecx, ide_mutex
256
        call    mutex_unlock
251
        call    mutex_unlock
257
 
-
 
258
        or      eax, -1
252
        or      eax, -1
259
        ret
253
        ret
260
;--------------------------------------
254
.done:
261
.done:
-
 
262
        mov     ecx, [channel_lock]
255
        mov     ecx, [channel_lock]
263
        call    mutex_unlock
256
        call    mutex_unlock
264
 
-
 
265
        mov     ecx, ide_mutex
257
        mov     ecx, ide_mutex
266
        call    mutex_unlock
258
        call    mutex_unlock
267
 
259
        xor     eax, eax
268
        xor     eax, eax
260
        ret
-
 
-
 
269
        ret
261
endp
270
endp
262
 
271
;-----------------------------------------------------------------------------
263
; This is a stub.
272
; This is a stub.
264
proc ide_querymedia stdcall, hd_data, mediainfo
273
proc ide_querymedia stdcall, hd_data, mediainfo
265
        mov     eax, [mediainfo]
274
        mov     eax, [mediainfo]
266
        mov     [eax+DISKMEDIAINFO.Flags], 0
275
        mov     [eax+DISKMEDIAINFO.Flags], 0
267
        mov     [eax+DISKMEDIAINFO.SectorSize], 512
276
        mov     [eax+DISKMEDIAINFO.SectorSize], 512
268
        or      dword [eax+DISKMEDIAINFO.Capacity], 0xFFFFFFFF
277
        or      dword [eax+DISKMEDIAINFO.Capacity], 0xFFFFFFFF
269
        or      dword [eax+DISKMEDIAINFO.Capacity+4], 0xFFFFFFFF
278
        or      dword [eax+DISKMEDIAINFO.Capacity+4], 0xFFFFFFFF
270
        xor     eax, eax
279
        xor     eax, eax
271
        ret
-
 
272
endp
280
        ret
273
 
281
endp
274
;-----------------------------------------------------------------------------
282
;-----------------------------------------------------------------------------
275
align 4
283
align 4
276
; input: eax = sector, edi -> buffer
284
; input: eax = sector, edi -> buffer
277
; output: edi = edi + 512
285
; output: edi = edi + 512
278
hd_read_pio:
-
 
279
        push    eax edx
286
hd_read_pio:
280
 
287
        push    eax edx
281
; Select the desired drive
288
; Select the desired drive
282
        mov     edx, [hdbase]
289
        mov     edx, [hdbase]
283
        add     edx, 6   ;адрес регистра головок
290
        add     edx, 6   ;адрес регистра головок
284
        mov     al, byte [hdid]
291
        mov     al, byte [hdid]
Line 285... Line 292...
285
        add     al, 128+64+32
292
        add     al, 128+64+32
-
 
293
        out     dx, al; номер головки/номер диска
286
        out     dx, al; номер головки/номер диска
294
        
287
        
295
        call    wait_for_hd_idle
288
        call    wait_for_hd_idle
-
 
289
        cmp     [hd_error], 0
296
 
290
        jne     hd_read_error
297
        cmp     [hd_error], 0
291
        
298
        jne     hd_read_error
292
; ATA with 28 or 48 bit for sector number?
299
; ATA with 28 or 48 bit for sector number?
293
        mov     eax, [esp+4]
300
        mov     eax, [esp+4]
Line 370... Line 377...
370
        cmp     [hd_error], 0
377
        cmp     [hd_error], 0
371
        jne     hd_read_error
378
        jne     hd_read_error
Line 372... Line 379...
372
 
379
 
373
        pushfd
380
        pushfd
374
        cli
-
 
375
 
381
        cli
376
        mov     ecx, 256
382
        mov     ecx, 256
377
        mov     edx, [hdbase]
383
        mov     edx, [hdbase]
378
        cld
384
        cld
379
        rep insw
385
        rep insw
Line 391... Line 397...
391
        mov     al, byte [hdid]
397
        mov     al, byte [hdid]
392
        add     al, 128+64+32
398
        add     al, 128+64+32
393
        out     dx, al ; номер головки/номер диска
399
        out     dx, al ; номер головки/номер диска
Line 394... Line 400...
394
 
400
 
-
 
401
        call    wait_for_hd_idle
395
        call    wait_for_hd_idle
402
 
396
        cmp     [hd_error], 0
403
        cmp     [hd_error], 0
Line 397... Line 404...
397
        jne     hd_write_error
404
        jne     hd_write_error
398
 
405
 
Line 548... Line 555...
548
        add     edx, 0x7
555
        add     edx, 0x7
549
;--------------------------------------
556
;--------------------------------------
550
align 4
557
align 4
551
wfhil1:
558
wfhil1:
552
        call    check_hd_wait_timeout
559
        call    check_hd_wait_timeout
-
 
560
 
553
        cmp     [hd_error], 0
561
        cmp     [hd_error], 0
554
        jne     @f
562
        jne     @f
Line 555... Line 563...
555
 
563
 
556
        in      al, dx
564
        in      al, dx
557
        test    al, 128
565
        test    al, 128
558
        jnz     wfhil1
-
 
-
 
566
        jnz     wfhil1
559
 
567
;--------------------------------------
560
@@:
568
@@:
561
        pop     edx eax
569
        pop     edx eax
562
        ret
570
        ret
563
;-----------------------------------------------------------------------------
571
;-----------------------------------------------------------------------------
Line 571... Line 579...
571
        call    save_hd_wait_timeout
579
        call    save_hd_wait_timeout
572
;--------------------------------------
580
;--------------------------------------
573
align 4
581
align 4
574
hdwait_sbuf:                  ; wait for sector buffer to be ready
582
hdwait_sbuf:                  ; wait for sector buffer to be ready
575
        call    check_hd_wait_timeout
583
        call    check_hd_wait_timeout
-
 
584
 
576
        cmp     [hd_error], 0
585
        cmp     [hd_error], 0
577
        jne     @f
586
        jne     @f
Line 578... Line 587...
578
 
587
 
579
        in      al, dx
588
        in      al, dx
Line 585... Line 594...
585
        cmp     [hd_setup], 1   ; do not mark error for setup request
594
        cmp     [hd_setup], 1   ; do not mark error for setup request
586
        je      buf_wait_ok
595
        je      buf_wait_ok
Line 587... Line 596...
587
 
596
 
588
        test    al, 1           ; previous command ended up with an error
597
        test    al, 1           ; previous command ended up with an error
-
 
598
        jz      buf_wait_ok
589
        jz      buf_wait_ok
599
;--------------------------------------
590
@@:
600
@@:
591
        mov     [hd_error], 1
-
 
-
 
601
        mov     [hd_error], 1
592
 
602
;--------------------------------------
593
buf_wait_ok:
603
buf_wait_ok:
594
        pop     edx eax
604
        pop     edx eax
595
        ret
605
        ret
596
;-----------------------------------------------------------------------------
606
;-----------------------------------------------------------------------------
Line 604... Line 614...
604
        call    save_hd_wait_timeout
614
        call    save_hd_wait_timeout
605
;--------------------------------------
615
;--------------------------------------
606
align 4
616
align 4
607
.wait:
617
.wait:
608
        call    change_task
618
        call    change_task
-
 
619
 
609
        cmp     [IDE_common_irq_param], 0
620
        cmp     [IDE_common_irq_param], 0
610
        jz      .done
621
        jz      .done
Line 611... Line 622...
611
 
622
 
-
 
623
        call    check_hd_wait_timeout
612
        call    check_hd_wait_timeout
624
 
613
        cmp     [hd_error], 0
625
        cmp     [hd_error], 0
614
        jz      .wait
-
 
615
; clear Bus Master IDE Command register
-
 
616
        pushfd
626
        jz      .wait
617
        cli
627
 
618
        mov     [IDE_common_irq_param], 0
-
 
619
        mov     dx, [IDEContrRegsBaseAddr]
-
 
620
        mov     al, 0
-
 
621
        out     dx, al
-
 
622
        popfd
628
        mov     [IDE_common_irq_param], 0
623
;--------------------------------------
-
 
624
align 4
629
;--------------------------------------
625
.done:
630
.done:
626
        pop     edx
631
        pop     edx
627
        pop     eax
632
        pop     eax
628
        ret
633
        ret
Line 634... Line 639...
634
        call    save_hd_wait_timeout
639
        call    save_hd_wait_timeout
635
;--------------------------------------
640
;--------------------------------------
636
align 4
641
align 4
637
.wait:
642
.wait:
638
        call    change_task
643
        call    change_task
-
 
644
 
639
        cmp     [IDE_common_irq_param], 0
645
        cmp     [IDE_common_irq_param], 0
640
        jz      .done
646
        jz      .done
Line 641... Line 647...
641
 
647
 
-
 
648
        call    check_hd_wait_timeout
642
        call    check_hd_wait_timeout
649
 
643
        cmp     [hd_error], 0
650
        cmp     [hd_error], 0
644
        jz      .wait
-
 
645
; clear Bus Master IDE Command register
-
 
646
        pushfd
651
        jz      .wait
647
        cli
652
 
648
        mov     [IDE_common_irq_param], 0
-
 
649
        mov     dx, [IDEContrRegsBaseAddr]
-
 
650
        add     dx, 8
-
 
651
        mov     al, 0
-
 
652
        out     dx, al
-
 
653
        popfd
653
        mov     [IDE_common_irq_param], 0
654
;--------------------------------------
-
 
655
align 4
654
;--------------------------------------
656
.done:
655
.done:
657
        pop     edx
656
        pop     edx
658
        pop     eax
657
        pop     eax
659
        ret
658
        ret
660
;-----------------------------------------------------------------------------
659
;-----------------------------------------------------------------------------
661
iglobal
660
iglobal
662
align 4
661
align 4
-
 
662
; note that IDE descriptor table must be 4-byte aligned
663
; note that IDE descriptor table must be 4-byte aligned and do not cross 4K boundary
663
; and do not cross 4K boundary
664
IDE_descriptor_table:
664
IDE_descriptor_table:
665
        dd IDE_DMA
665
        dd IDE_DMA
666
        dw 0x2000
666
        dw 0x2000
Line 671... Line 671...
671
IDE_common_irq_param db 0
671
IDE_common_irq_param db 0
672
endg
672
endg
673
;-----------------------------------------------------------------------------
673
;-----------------------------------------------------------------------------
674
uglobal
674
uglobal
675
; all uglobals are zeroed at boot
675
; all uglobals are zeroed at boot
676
dma_process         dd 0
-
 
677
dma_slot_ptr        dd 0
-
 
678
cache_chain_pos     dd 0
-
 
679
cache_chain_ptr     dd 0
676
cache_chain_ptr     dd 0
680
cache_chain_size    db 0
677
cache_chain_size    db 0
681
cache_chain_started db 0
-
 
682
dma_task_switched   db 0
-
 
683
dma_hdd             db 0
-
 
684
allow_dma_access    db 0
678
allow_dma_access    db 0
685
endg
679
endg
686
;-----------------------------------------------------------------------------
680
;-----------------------------------------------------------------------------
687
align 4
681
align 4
688
IDE_irq_14_handler:
682
IDE_irq_14_handler:
Line 691... Line 685...
691
 
685
 
692
        pushfd
686
        pushfd
693
        cli
687
        cli
694
        pushad
688
        pushad
-
 
689
        mov     [IDE_common_irq_param], 0
695
        mov     [IDE_common_irq_param], 0
690
        mov     ecx, [IDE_controller_pointer]
696
        mov     dx, [IDEContrRegsBaseAddr]
691
        mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
697
; test whether it is our interrupt?
692
; test whether it is our interrupt?
698
        add     edx, 2
693
        add     edx, 2
699
        in      al, dx
694
        in      al, dx
700
        test    al, 100b
695
        test    al, 100b
Line 713... Line 708...
713
        popad
708
        popad
714
        popfd
709
        popfd
715
        mov     al, 1
710
        mov     al, 1
716
        ret
711
        ret
717
;--------------------------------------
712
;--------------------------------------
718
align 4
-
 
719
@@:
713
@@:
720
        popad
714
        popad
721
        popfd
715
        popfd
722
;--------------------------------------
716
;--------------------------------------
723
align 4
-
 
724
.exit:
717
.exit:
725
        mov     al, 0
718
        mov     al, 0
726
        ret
719
        ret
727
;-----------------------------------------------------------------------------
720
;-----------------------------------------------------------------------------
728
align 4
721
align 4
Line 732... Line 725...
732
 
725
 
733
        pushfd
726
        pushfd
734
        cli
727
        cli
735
        pushad
728
        pushad
-
 
729
        mov     [IDE_common_irq_param], 0
736
        mov     [IDE_common_irq_param], 0
730
        mov     ecx, [IDE_controller_pointer]
737
        mov     dx, [IDEContrRegsBaseAddr]
731
        mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
738
        add     dx, 8
732
        add     dx, 8
739
; test whether it is our interrupt?
733
; test whether it is our interrupt?
740
        add     edx, 2
734
        add     edx, 2
741
        in      al, dx
735
        in      al, dx
Line 755... Line 749...
755
        popad
749
        popad
756
        popfd
750
        popfd
757
        mov     al, 1
751
        mov     al, 1
758
        ret
752
        ret
759
;--------------------------------------
753
;--------------------------------------
760
align 4
-
 
761
@@:
754
@@:
762
        popad
755
        popad
763
        popfd
756
        popfd
764
;--------------------------------------
757
;--------------------------------------
765
align 4
-
 
766
.exit:
758
.exit:
767
        mov     al, 0
759
        mov     al, 0
768
        ret
760
        ret
769
;-----------------------------------------------------------------------------
761
;-----------------------------------------------------------------------------
770
align 4
762
align 4
Line 774... Line 766...
774
 
766
 
775
        pushfd
767
        pushfd
776
        cli
768
        cli
777
        pushad
769
        pushad
-
 
770
        xor     ebx, ebx
778
        xor     ebx, ebx
771
        mov     ecx, [IDE_controller_pointer]
779
        mov     dx, [IDEContrRegsBaseAddr]
772
        mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
780
        mov     eax, IDE_common_irq_param
773
        mov     eax, IDE_common_irq_param
781
        cmp     [eax], irq14_num
774
        cmp     [eax], irq14_num
782
        mov     [eax], bl
775
        mov     [eax], bl
Line 783... Line 776...
783
        je      @f
776
        je      @f
784
 
777
 
785
        add     dx, 8
-
 
786
;--------------------------------------
778
        add     dx, 8
787
align 4
779
;--------------------------------------
788
@@:
780
@@:
789
; test whether it is our interrupt?
781
; test whether it is our interrupt?
790
        add     edx, 2
782
        add     edx, 2
Line 805... Line 797...
805
        popad
797
        popad
806
        popfd
798
        popfd
807
        mov     al, 1
799
        mov     al, 1
808
        ret
800
        ret
809
;--------------------------------------
801
;--------------------------------------
810
align 4
-
 
811
@@:
802
@@:
812
        popad
803
        popad
813
        popfd
804
        popfd
814
;--------------------------------------
805
;--------------------------------------
815
align 4
-
 
816
.exit:
806
.exit:
817
        mov     al, 0
807
        mov     al, 0
818
        ret
808
        ret
819
;-----------------------------------------------------------------------------
809
;-----------------------------------------------------------------------------
820
align 4
810
align 4
Line 822... Line 812...
822
        push    eax
812
        push    eax
823
        push    edx
813
        push    edx
824
        mov     edx, [dma_hdpos]
814
        mov     edx, [dma_hdpos]
825
        cmp     edx, [hdpos]
815
        cmp     edx, [hdpos]
826
        jne     .notread
816
        jne     .notread
-
 
817
 
827
        mov     edx, [dma_cur_sector]
818
        mov     edx, [dma_cur_sector]
828
        cmp     eax, edx
819
        cmp     eax, edx
829
        jb      .notread
820
        jb      .notread
-
 
821
 
830
        add     edx, 15
822
        add     edx, 15
831
        cmp     [esp+4], edx
823
        cmp     [esp+4], edx
832
        ja      .notread
824
        ja      .notread
-
 
825
 
833
        mov     eax, [esp+4]
826
        mov     eax, [esp+4]
834
        sub     eax, [dma_cur_sector]
827
        sub     eax, [dma_cur_sector]
835
        shl     eax, 9
828
        shl     eax, 9
836
        add     eax, (OS_BASE+IDE_DMA)
829
        add     eax, (OS_BASE+IDE_DMA)
-
 
830
 
837
        push    ecx esi
831
        push    ecx esi
838
        mov     esi, eax
832
        mov     esi, eax
839
 
-
 
840
        mov     ecx, 512/4
833
        mov     ecx, 512/4
841
        cld
834
        cld
842
        rep movsd
835
        rep movsd
843
        pop     esi ecx
836
        pop     esi ecx
-
 
837
 
844
        pop     edx
838
        pop     edx
845
        pop     eax
839
        pop     eax
846
        ret
840
        ret
-
 
841
;--------------------------------------
847
.notread:
842
.notread:
848
; set data for PRD Table
843
; set data for PRD Table
849
        mov     eax, IDE_descriptor_table
844
        mov     eax, IDE_descriptor_table
850
        mov     dword [eax], IDE_DMA
845
        mov     dword [eax], IDE_DMA
851
        mov     word [eax+4], 0x2000
846
        mov     word [eax+4], 0x2000
852
        sub     eax, OS_BASE
847
        sub     eax, OS_BASE
853
; select controller Primary or Secondary
848
; select controller Primary or Secondary
-
 
849
;       mov     ecx,[IDE_controller_pointer]
-
 
850
        mov     ecx, [hdpos]
-
 
851
        dec     ecx
-
 
852
        shr     ecx, 2
-
 
853
        imul    ecx, sizeof.IDE_DATA
-
 
854
        add     ecx, IDE_controller_1
-
 
855
        mov     [IDE_controller_pointer], ecx
854
        mov     dx, [IDEContrRegsBaseAddr]
856
        mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
-
 
857
 
855
        push    eax
858
        push    eax
856
        mov     eax, [hd_address_table]
859
        mov     eax, [hdpos]
-
 
860
        dec     eax
857
        cmp     [hdbase], eax ; 0x1F0
861
        test    eax, 10b
858
        pop     eax
862
        pop     eax
859
        jz      @f
863
        jz      @f
-
 
864
 
860
        add     edx, 8
865
        add     edx, 8
-
 
866
;--------------------------------------
861
@@:
867
@@:
862
        push    edx
868
        push    edx
863
; Bus Master IDE PRD Table Address
869
; Bus Master IDE PRD Table Address
864
        add     edx, 4
870
        add     edx, 4
865
; save IDE_descriptor_table
871
; save IDE_descriptor_table
Line 879... Line 885...
879
        mov     al, byte [hdid]
885
        mov     al, byte [hdid]
880
        add     al, 128+64+32
886
        add     al, 128+64+32
881
        out     dx, al ; номер головки/номер диска
887
        out     dx, al ; номер головки/номер диска
Line 882... Line 888...
882
 
888
 
-
 
889
        call    wait_for_hd_idle
883
        call    wait_for_hd_idle
890
 
884
        cmp     [hd_error], 0
891
        cmp     [hd_error], 0
885
        jnz     hd_read_error
-
 
886
 
892
        jnz     hd_read_error
887
; ATA with 28 or 48 bit for sector number?
893
; ATA with 28 or 48 bit for sector number?
888
        mov     eax, [esp+4]
894
        mov     eax, [esp+4]
889
; -10h because the PreCache hits the boundary between lba28 and lba48
895
; -10h because the PreCache hits the boundary between lba28 and lba48
890
; 10h = 16  - size of PreCache
896
; 10h = 16  - size of PreCache
Line 959... Line 965...
959
        mov     al, 25h ; READ DMA EXT
965
        mov     al, 25h ; READ DMA EXT
960
        out     dx, al ; ATACommand регистр команд
966
        out     dx, al ; ATACommand регистр команд
961
;--------------------------------------
967
;--------------------------------------
962
.continue:
968
.continue:
963
; select controller Primary or Secondary
969
; select controller Primary or Secondary
-
 
970
        mov     ecx, [IDE_controller_pointer]
964
        mov     dx, [IDEContrRegsBaseAddr]
971
        mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
-
 
972
 
965
        mov     eax, [hd_address_table]
973
        mov     eax, [hdpos]
-
 
974
        dec     eax
966
        cmp     [hdbase], eax ; 0x1F0
975
        test    eax, 10b
967
        jz      @f
976
        jz      @f
-
 
977
 
968
        add     dx, 8
978
        add     dx, 8
-
 
979
;--------------------------------------
969
@@:
980
@@:
970
; set write to memory and Start Bus Master
981
; set write to memory and Start Bus Master
971
        mov     al, 9
982
        mov     al, 9
972
        out     dx, al
983
        out     dx, al
Line 973... Line 984...
973
 
984
 
974
        mov     eax, [CURRENT_TASK]
985
        mov     eax, [hdpos]
975
        mov     [dma_process], eax
-
 
976
 
986
        dec     eax
977
        mov     eax, [TASK_BASE]
-
 
978
        mov     [dma_slot_ptr], eax
-
 
979
 
-
 
980
        mov     eax, [hd_address_table]
-
 
981
        cmp     [hdbase], eax ; 0x1F0
987
        test    eax, 10b
Line 982... Line 988...
982
        jnz     .ide1
988
        jnz     .ide1
983
 
989
 
-
 
990
        mov     [IDE_common_irq_param], irq14_num
984
        mov     [IDE_common_irq_param], irq14_num
991
        jmp     @f
985
        jmp     @f
992
;--------------------------------------
-
 
993
.ide1:
986
.ide1:
994
        mov     [IDE_common_irq_param], irq15_num
987
        mov     [IDE_common_irq_param], irq15_num
995
;--------------------------------------
988
@@:
996
@@:
989
        popfd
997
        popfd
-
 
998
; wait for interrupt
990
; wait for interrupt
999
        mov     eax, [hdpos]
991
        mov     eax, [hd_address_table]
1000
        dec     eax
-
 
1001
        test    eax, 10b
992
        cmp     [hdbase], eax ; 0x1F0
1002
        jnz     .wait_ide1
993
        jnz     .wait_ide1
1003
 
-
 
1004
        call    wait_for_sector_dma_ide0
994
        call    wait_for_sector_dma_ide0
1005
        jmp     @f
995
        jmp     @f
1006
;--------------------------------------
-
 
1007
.wait_ide1:
996
.wait_ide1:
1008
        call    wait_for_sector_dma_ide1
997
        call    wait_for_sector_dma_ide1
1009
;--------------------------------------
998
@@:
1010
@@:
-
 
1011
        cmp     [hd_error], 0
999
        cmp     [hd_error], 0
1012
        jnz     hd_read_error
1000
        jnz     hd_read_error
1013
 
1001
        mov     eax, [hdpos]
1014
        mov     eax, [hdpos]
1002
        mov     [dma_hdpos], eax
1015
        mov     [dma_hdpos], eax
-
 
1016
        pop     edx
1003
        pop     edx
1017
        pop     eax
1004
        pop     eax
1018
 
1005
        mov     [dma_cur_sector], eax
1019
        mov     [dma_cur_sector], eax
1006
        jmp     hd_read_dma
1020
        jmp     hd_read_dma
1007
;-----------------------------------------------------------------------------
1021
;-----------------------------------------------------------------------------
1008
cache_write_dma:
1022
cache_write_dma:
1009
        mov     eax, [cache_chain_ptr] ; for what?
1023
        mov     eax, [cache_chain_ptr] ; for what?
1010
        push    esi
1024
        push    esi
1011
; set data for PRD Table
1025
; set data for PRD Table
-
 
1026
        mov     eax, IDE_descriptor_table
1012
        mov     eax, IDE_descriptor_table
1027
        mov     edx, eax
1013
        mov     edx, eax
1028
 
1014
        pusha
1029
        pusha
1015
        mov     edi, (OS_BASE+IDE_DMA)
1030
        mov     edi, (OS_BASE+IDE_DMA)
1016
        mov     dword [edx], IDE_DMA
1031
        mov     dword [edx], IDE_DMA
1017
        movzx   ecx, [cache_chain_size]
1032
        movzx   ecx, [cache_chain_size]
1018
        shl     ecx, 9
1033
        shl     ecx, 9
1019
        mov     word [edx+4], cx
1034
        mov     word [edx+4], cx
1020
        shr     ecx, 2
1035
        shr     ecx, 2
1021
        cld
1036
        cld
-
 
1037
        rep movsd
1022
        rep movsd
1038
        popa
1023
        popa
1039
 
-
 
1040
        sub     eax, OS_BASE
-
 
1041
; select controller Primary or Secondary
-
 
1042
;       mov     ecx,[IDE_controller_pointer]
-
 
1043
        mov     ecx, [hdpos]
-
 
1044
        dec     ecx
-
 
1045
        shr     ecx, 2
-
 
1046
        imul    ecx, sizeof.IDE_DATA
1024
        sub     eax, OS_BASE
1047
        add     ecx, IDE_controller_1
-
 
1048
        mov     [IDE_controller_pointer], ecx
1025
; select controller Primary or Secondary
1049
        mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
1026
        mov     dx, [IDEContrRegsBaseAddr]
1050
 
-
 
1051
        push    eax
1027
        push    eax
1052
        mov     eax, [hdpos]
1028
        mov     eax, [hd_address_table]
1053
        dec     eax
1029
        cmp     [hdbase], eax ; 0x1F0
1054
        test    eax, 10b
-
 
1055
        pop     eax
1030
        pop     eax
1056
        jz      @f
-
 
1057
 
1031
        jz      @f
1058
        add     edx, 8
1032
        add     edx, 8
1059
;--------------------------------------
1033
@@:
1060
@@:
1034
        push    edx
1061
        push    edx
1035
; Bus Master IDE PRD Table Address
1062
; Bus Master IDE PRD Table Address
Line 1051... Line 1078...
1051
        mov     al, byte [hdid]
1078
        mov     al, byte [hdid]
1052
        add     al, 128+64+32
1079
        add     al, 128+64+32
1053
        out     dx, al ; номер головки/номер диска
1080
        out     dx, al ; номер головки/номер диска
Line 1054... Line 1081...
1054
 
1081
 
-
 
1082
        call    wait_for_hd_idle
1055
        call    wait_for_hd_idle
1083
 
1056
        cmp     [hd_error], 0
1084
        cmp     [hd_error], 0
1057
        jnz     hd_write_error_dma
-
 
1058
 
1085
        jnz     hd_write_error_dma
1059
; ATA with 28 or 48 bit for sector number?
1086
; ATA with 28 or 48 bit for sector number?
1060
        mov     esi, [cache_chain_ptr]
1087
        mov     esi, [cache_chain_ptr]
1061
        mov     eax, [esi]
1088
        mov     eax, [esi]
1062
; -40h because the PreCache hits the boundary between lba28 and lba48
1089
; -40h because the PreCache hits the boundary between lba28 and lba48
Line 1132... Line 1159...
1132
        mov     al, 35h ; WRITE DMA EXT
1159
        mov     al, 35h ; WRITE DMA EXT
1133
        out     dx, al ; ATACommand регистр команд
1160
        out     dx, al ; ATACommand регистр команд
1134
;--------------------------------------
1161
;--------------------------------------
1135
.continue:
1162
.continue:
1136
; select controller Primary or Secondary
1163
; select controller Primary or Secondary
-
 
1164
        mov     ecx, [IDE_controller_pointer]
1137
        mov     dx, [IDEContrRegsBaseAddr]
1165
        mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
-
 
1166
 
1138
        mov     eax, [hd_address_table]
1167
        mov     eax, [hdpos]
-
 
1168
        dec     eax
1139
        cmp     [hdbase], eax ; 0x1F0
1169
        test    eax, 10b
1140
        jz      @f
1170
        jz      @f
-
 
1171
 
1141
        add     dx, 8
1172
        add     dx, 8
-
 
1173
;--------------------------------------
1142
@@:
1174
@@:
1143
; set write to device and Start Bus Master
1175
; set write to device and Start Bus Master
1144
        mov     al, 1
1176
        mov     al, 1
1145
        out     dx, al
1177
        out     dx, al
-
 
1178
 
1146
        mov     eax, [CURRENT_TASK]
1179
        mov     eax, [hdpos]
1147
        mov     [dma_process], eax
1180
        dec     eax
1148
        mov     eax, [TASK_BASE]
1181
        test    eax, 10b
1149
        mov     [dma_slot_ptr], eax
-
 
1150
        mov     eax, [hd_address_table]
-
 
1151
        cmp     [hdbase], eax ; 0x1F0
-
 
1152
        jnz     .ide1
1182
        jnz     .ide1
Line 1153... Line 1183...
1153
 
1183
 
1154
        mov     [IDE_common_irq_param], irq14_num
1184
        mov     [IDE_common_irq_param], irq14_num
-
 
1185
        jmp     @f
1155
        jmp     @f
1186
;--------------------------------------
1156
.ide1:
1187
.ide1:
-
 
1188
        mov     [IDE_common_irq_param], irq15_num
1157
        mov     [IDE_common_irq_param], irq15_num
1189
;--------------------------------------
1158
@@:
1190
@@:
1159
        popfd
1191
        popfd
1160
; wait for interrupt
1192
; wait for interrupt
-
 
1193
        mov     [dma_cur_sector], not 0x40
1161
        mov     [dma_cur_sector], not 0x40
1194
 
-
 
1195
        mov     eax, [hdpos]
1162
        mov     eax, [hd_address_table]
1196
        dec     eax
1163
        cmp     [hdbase], eax ; 0x1F0
1197
        test    eax, 10b
-
 
1198
        jnz     .wait_ide1
1164
        jnz     .wait_ide1
1199
 
-
 
1200
        call    wait_for_sector_dma_ide0
1165
        call    wait_for_sector_dma_ide0
1201
 
-
 
1202
        jmp     @f
1166
        jmp     @f
1203
;--------------------------------------
1167
.wait_ide1:
1204
.wait_ide1:
-
 
1205
        call    wait_for_sector_dma_ide1
1168
        call    wait_for_sector_dma_ide1
1206
;--------------------------------------
1169
@@:
1207
@@:
1170
        cmp     [hd_error], 0
1208
        cmp     [hd_error], 0
1171
        jnz     hd_write_error_dma
1209
        jnz     hd_write_error_dma
1172
        pop     esi
1210
        pop     esi
1173
        ret
1211
        ret
1174
;-----------------------------------------------------------------------------
-
 
1175
uglobal
-
 
1176
align 4
-
 
1177
IDEContrProgrammingInterface dd ?
-
 
1178
IDE_Interrupt   dw ?
-
 
1179
IDEContrRegsBaseAddr         dw ?
-
 
1180
IDE_BAR0_val    dw ?
-
 
1181
IDE_BAR1_val    dw ?
-
 
1182
IDE_BAR2_val    dw ?
-
 
1183
IDE_BAR3_val    dw ?
-
 
1184
endg
-
 
1185
;-----------------------------------------------------------------------------
-
 
1186
 
1212
;-----------------------------------------------------------------------------
1187
proc clear_pci_ide_interrupts
1213
proc clear_pci_ide_interrupts
-
 
1214
        mov     esi, pcidev_list
-
 
1215
;--------------------------------------
1188
        mov     esi, pcidev_list
1216
align 4
1189
.loop:
1217
.loop:
1190
        mov     esi, [esi+PCIDEV.fd]
1218
        mov     esi, [esi+PCIDEV.fd]
1191
        cmp     esi, pcidev_list
1219
        cmp     esi, pcidev_list
-
 
1220
        jz      .done
1192
        jz      .done
1221
 
1193
        cmp     [esi+PCIDEV.class], 0x01018F
1222
        cmp     [esi+PCIDEV.class], 0x01018F
-
 
1223
        jnz     .loop
1194
        jnz     .loop
1224
 
1195
        mov     ah, [esi+PCIDEV.bus]
1225
        mov     ah, [esi+PCIDEV.bus]
1196
        mov     al, 2
1226
        mov     al, 2
1197
        mov     bh, [esi+PCIDEV.devfn]
1227
        mov     bh, [esi+PCIDEV.devfn]
1198
        mov     bl, 0x20
1228
        mov     bl, 0x20
-
 
1229
        call    pci_read_reg
1199
        call    pci_read_reg
1230
 
1200
        and     eax, 0FFFCh
1231
        and     eax, 0FFFCh
1201
        mov     edx, eax
1232
        mov     edx, eax
1202
        add     edx, 2
1233
        add     edx, 2
1203
        in      al, dx
1234
        in      al, dx
Line 1210... Line 1241...
1210
        DEBUGF 1,'port[%x] = %x ',dx,al
1241
        DEBUGF 1,'port[%x] = %x ',dx,al
1211
        out     dx, al
1242
        out     dx, al
1212
        in      al, dx
1243
        in      al, dx
1213
        DEBUGF 1,'-> %x\n',al
1244
        DEBUGF 1,'-> %x\n',al
1214
        jmp     .loop
1245
        jmp     .loop
-
 
1246
;--------------------------------------
1215
.done:
1247
.done:
1216
        ret
1248
        ret
1217
endp
1249
endp
-
 
1250
;-----------------------------------------------------------------------------