]> wirehaze git hosting - BOS.git/blob - kernel/fdc/fdc.asm

wirehaze git hosting

81b4997ae62a850c91c88de5418b71e7e00edad2
[BOS.git] / kernel / fdc / fdc.asm
1 ;----------------------------------------------------------;
2 ; BOS kernel Christoffer Bubach, 2004-2005. ;
3 ;----------------------------------------------------------;
4 ; ;
5 ; floppy disk driver. ;
6 ; ;
7 ;----------------------------------------------------------;
8
9
10 ;---------------------------;
11 ; variables and contants ;
12 ;---------------------------;
13 fdd_int_done dw 0 ; is the IRQ done?
14 fdd_motor_on db 0 ; fdd motor on=1, off=0
15 fdd_head db 0
16 fdd_driveno db 0
17 fdd_track db 0
18 fdd_sector db 0
19
20 fdd_errorcode db 0 ; this the error code 00 = no error
21 fdd_tries db 0 ; no. of times to try, before error.
22
23 ResultST0 db 0
24 ResultST1 db 0 ; or pcn
25 ResultST2 db 0
26 ResultST3 db 0
27 ResultC db 0
28 ResultH db 0
29 ResultR db 0
30 ResultN db 0
31 ResultExtra db 0
32
33
34
35 ;------------------------------------------------------;
36 ; initializes the floppy disk driver ;
37 ; ;
38 ;------------------------------------------------------;
39 fdc_init:
40 push ecx
41 push edi
42
43 mov cl, 0x26 ; hook interrupt 0x26 (IRQ6)
44 mov edi, floppy_irq
45 call set_int
46
47 mov cl, 6 ; enable IRQ6
48 call enable_irq
49
50 call fdd_reset ; reset FDC
51 call fdd_recalibrate
52
53 pop edi
54 pop ecx
55 ret
56
57
58
59 ;------------------------------------------------------;
60 ; floppy IRQ ;
61 ; ;
62 ;------------------------------------------------------;
63 floppy_irq:
64 pusha
65 push gs
66 push fs
67 push ds
68 push es
69 push esi
70
71 or [fdd_int_done], 1
72 mov al, 0x20
73 out 0x20, al
74
75 pop esi
76 pop es
77 pop ds
78 pop fs
79 pop gs
80 popa
81 iret
82
83
84
85 ;------------------------------------------------------;
86 ; wait for a floppy int ;
87 ; out: cf = 1 if timeout ;
88 ;------------------------------------------------------;
89 wait_int:
90 push eax
91 push ecx
92
93 mov ecx, 150 ; 150 = 1.5 seconds.
94 call active_delay ; timer.inc
95 .l1:
96 cmp dword [ecx], 0 ; timeup?
97 je .error
98 mov ax, [fdd_int_done] ; if not we check for int.
99 or ax, ax
100 jz .l1
101 pop ecx
102 pop eax
103 clc
104 ret
105 .error:
106 pop ecx
107 pop eax
108 stc
109 ret
110
111
112
113 ;------------------------------------------------------;
114 ; fdd motor off ;
115 ; out: nothing ;
116 ;------------------------------------------------------;
117 fdd_off:
118 push eax
119 push edx
120
121 mov dx, 0x3F2
122 mov al, 0 ; all motors off..
123 out dx, al
124 mov [fdd_motor_on], 0
125
126 pop edx
127 pop eax
128 ret
129
130
131
132
133 ;------------------------------------------------------;
134 ; fdd motor on ;
135 ; out: nothing ;
136 ;------------------------------------------------------;
137 fdd_on:
138 push eax
139 push edx
140
141 mov dx, 0x3F2 ; motor 0 on..
142 mov al, 0x1C
143 out dx, al
144
145 mov ecx, 20 ; 1/5 of a sec. to speed up
146 call delay ; in timer.inc
147 mov [fdd_motor_on], 1
148
149 pop edx
150 pop eax
151 ret
152
153
154
155 ;------------------------------------------------------;
156 ; send a data byte to the FDC ;
157 ; ;
158 ; in: al = data byte ;
159 ;------------------------------------------------------;
160 fdc_sendbyte:
161 push edx
162 push ecx
163 push eax
164
165 mov ecx, 150 ; 150 = 1.5 seconds.
166 call active_delay ; timer.inc
167 .l1:
168 cmp dword [ecx], 0 ; timeup?
169 je .error
170 mov dx, 0x3f4 ; check status reg
171 in al, dx
172 and al, 11000000b
173 cmp al, 10000000b ; are we ok to write
174 jnz .l1
175
176 pop eax
177 pop ecx
178 mov dx, 0x3F5 ; send byte
179 out dx, al
180 pop edx
181 clc
182 ret
183 .error:
184 pop eax
185 pop ecx
186 pop edx
187 stc
188 ret
189
190
191 ;------------------------------------------------------;
192 ; read a data byte from the FDC ;
193 ; ;
194 ; out: al = data byte ;
195 ;------------------------------------------------------;
196 fdc_getbyte:
197 push edx
198 push ecx
199 push eax
200
201 mov ecx, 150 ; 150 = 1.5 seconds.
202 call active_delay ; timer.inc
203 .l1:
204 cmp dword [ecx], 0 ; timeup?
205 je .error
206 mov dx, 0x3f4 ; check status reg
207 in al, dx
208 and al, 11000000b
209 cmp al, 11000000b ; are we ok to read
210 jnz .l1
211
212 pop eax
213 pop ecx
214 mov dx, 0x3F5 ; get the byte
215 in al, dx
216 pop edx
217 clc
218 ret
219 .error:
220 pop eax
221 pop ecx
222 pop edx
223 stc
224 ret
225
226
227
228
229 ;------------------------------------------------------;
230 ; reset controller ;
231 ; ;
232 ;------------------------------------------------------;
233 fdd_reset:
234 push eax
235 push ecx
236 push edx
237
238 mov dx, 0x3F2
239 mov al, 00001000b ; no motors enabled, DMA Enabled, held FDC at reset
240 out dx, al ; drive A selected.
241
242 mov ecx, 5
243 call delay ; in timer.inc
244
245 mov dx, 0x3F7
246 mov al, 00000000b ; 500Kb/sec mode
247 out dx, al
248
249 mov dx, 0x3F2
250 or al, 00001100b ; FDC completed reset, al =0x0c.
251 out dx, al
252
253 mov [fdd_int_done], 0 ; we need to wait
254 call wait_int ; for floppy int.
255 jc .error ; jump to error exit, if timeout.
256
257 mov cx, 0x04 ; after a reset, the interrupts must be
258 .status: ; cleared by (four) dummy-reads.
259 mov al, 0x08 ; sense interrupt status command
260 call fdc_sendbyte
261 call fdc_getbyte
262 call fdc_getbyte
263 loop .status
264
265 mov al, 0x03 ; specify command (includes next two bytes sent)
266 call fdc_sendbyte
267 mov al, 0xDF ; SRT = 3ms, HUT = 240ms
268 call fdc_sendbyte
269 mov al, 0x02 ; HLT = 16ms, ND = 0
270 call fdc_sendbyte
271 .ok:
272 pop edx
273 pop ecx
274 pop eax
275 clc
276 ret
277 .error:
278 pop edx
279 pop ecx
280 pop eax
281 stc
282 ret
283
284
285
286
287 ;------------------------------------------------------;
288 ; fdd seek ;
289 ; ;
290 ;------------------------------------------------------;
291 fdd_seek:
292 push eax
293
294 mov al, [ResultC] ; put what track/cylinder we are at in al
295 cmp [fdd_track], al ; is it the same as we want
296 je .ok ; yes, then leave.
297
298 mov al, 0x0F ; seek command
299 call fdc_sendbyte
300 mov al, [fdd_driveno] ; drive # (00 = A)
301 call fdc_sendbyte
302 mov al, [fdd_track] ; cylinder #
303 call fdc_sendbyte
304
305 mov [fdd_int_done], 0
306 call wait_int
307 jc .error
308
309 mov al, 0x08 ; sense interrupt status command
310 call fdc_sendbyte
311 call fdc_getbyte
312 mov ah, al ; save ST0 in ah
313 call fdc_getbyte ; should read PCN
314
315 test ah, 00100000b ; test sr0 is 0x20
316 jz .error ; if not we have a error :-(.
317 test ah,10000000b ; test sr0 is 0x80
318 jnz .error ; if not we have a error :-(.
319 .ok: ; succsess.. :-)
320 pop eax
321 clc
322 ret
323 .error:
324 pop eax
325 stc
326 ret
327
328
329 ;------------------------------------------------------;
330 ; fdd recalibrate ;
331 ; ;
332 ;------------------------------------------------------;
333 fdd_recalibrate:
334 push eax
335
336 test [fdd_motor_on], 1
337 jnz .l1
338 call fdd_on
339 .l1:
340 mov al, 0x07 ; recalibrate command
341 call fdc_sendbyte
342 mov al, 0x00 ; selects drive a:
343 call fdc_sendbyte
344
345 mov [fdd_int_done], 0
346 call wait_int
347 jc .error
348
349 mov al, 0x08 ; sense interrupt status command
350 call fdc_sendbyte
351 call fdc_getbyte ; read STO
352 mov ah, al ; save ST0 in ah
353 call fdc_getbyte
354
355 test ah, 00100000b ; test sr0 is 0x20
356 jz .error
357 test ah, 00010000b ; test sr0 is 0x80
358 jnz .error
359 .ok:
360 mov [ResultC], 0
361 pop eax
362 clc
363 ret
364 .error:
365 pop eax
366 stc
367 ret
368
369
370
371 ;------------------------------------------------------;
372 ; fdd read/write ;
373 ; input: bl = 0 read, 1 write ;
374 ; ch = track/cylinder ;
375 ; cl = sector ;
376 ; dh = head ;
377 ; dl = drive (only A: drive used, 00 ) ;
378 ; output: ah = status ;
379 ; al = sector number read ;
380 ; cf = 0 if ok, 1 if error ;
381 ;------------------------------------------------------;
382 fdd_read_write:
383 pushad
384 and dh, 00000001b ; is it set to fdd_head 0 or 1?
385 mov [fdd_head], dh ; store it.
386 shl dh, 2 ; make the first 2 bits = 00 for A:.
387 mov [fdd_driveno], dh ; store it.
388
389 mov [fdd_errorcode], 0x04 ; put error code in ah, just incase
390 cmp ch, 0x51 ; cmp if track number, is above 80 decimal (51 hex)?
391 jae .error ; if above jump error.
392 mov [fdd_track], ch ; if not above,store it.
393
394 cmp cl, 0x13 ; cmp if fdd_sector number, is above 18 decimal (12 hex) ?.
395 jae .error ; if above jump error.
396 mov [fdd_sector], cl ; if not above,store it.
397
398 test [fdd_motor_on], 1
399 jnz .l1
400 call fdd_on
401 .l1:
402 mov dx, 0x3F7
403 mov al, 00000000b ; 500Kb/sec mode
404 out dx, al
405 mov [fdd_errorcode], 0x80 ; put basic error code, just in case.
406
407 xor ecx, ecx
408 mov cx, 3 ; we want to try seek 3 times
409 .l2:
410 call fdd_seek ; we need to move to the right track.
411 jnc .l3 ; we should be on the right track.
412 loop .l2
413 jmp .error ; timeout.
414 .l3:
415 mov dx, 0x3f4 ; check status reg (to see if DMA bit set)
416 in al, dx
417 test al, 00100000b ; test sr0 is 0x80
418 jnz .error
419
420 cmp bl, 0
421 je .read_fdd
422
423 .write_fdd:
424 mov bl, 2 ; channel 2
425 mov esi, 512 ; bytes to write
426 mov ecx, 0x80000 ; page & offset
427 mov bh, 1 ; write floppy, "read DMA"
428 call dma_transfer
429
430 mov al, 0xC5 ; write fdd_sector command
431 call fdc_sendbyte
432 jmp .cont
433
434 .read_fdd:
435 mov bl, 2 ; channel 2
436 mov esi, 512 ; bytes to read
437 mov ecx, 0x80000 ; page & offset
438 mov bh, 0 ; read floppy, "write DMA"
439 call dma_transfer
440
441 mov al, 0xE6 ; read fdd_sector command
442 call fdc_sendbyte
443
444 .cont:
445 mov al, [fdd_driveno] ; fdd_head no. 0, drive A:
446 call fdc_sendbyte
447 mov al, [fdd_track] ; cylinder
448 call fdc_sendbyte
449
450 mov al, [fdd_head] ; head/side 0 or 1
451 call fdc_sendbyte
452 mov al, [fdd_sector] ; sector number,starts at 1
453 call fdc_sendbyte
454 mov al, 0x02 ; sector size - 512 bytes
455 call fdc_sendbyte
456
457 mov al, 0x12 ; 18 decimal sectors to a track
458 call fdc_sendbyte
459 mov al, 0x1B ; 27 should be the gap length for a 3.5" 1.44Mb
460 call fdc_sendbyte
461 mov al, 0xFF ; not used data length, because sector size has been filled
462 call fdc_sendbyte
463
464 mov [fdd_int_done], 0
465 call wait_int
466 jc .error
467
468 call fdc_getbyte
469 mov [ResultST0], al ; save result of ST0 in var
470 call fdc_getbyte
471 mov [ResultST1], al ; save result of ST1 in var
472 call fdc_getbyte
473 mov [ResultST2], al ; save result of ST2 in var
474 call fdc_getbyte
475 mov [ResultC], al ; save result of cylinder
476 call fdc_getbyte
477 mov [ResultH], al ; save result of head
478 call fdc_getbyte
479 mov [ResultR], al ; save result of sector number.
480 call fdc_getbyte
481 mov [ResultN], al ; save result of sector size
482
483 test [ResultST0], 11000000b ; test sr0 is 0xC0
484 jnz .error
485 mov [fdd_errorcode], 0x00
486 .ok:
487 popad
488 mov ah, [fdd_errorcode] ; move error status into ah
489 mov al, [ResultR]
490 clc
491 ret
492 .error:
493 popad
494 mov ah, [fdd_errorcode] ; move error status into ah
495 stc
496 ret