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

wirehaze git hosting

5048e4304de43647e54d8037f44c964b0c57f85a
[BOS.git] / kernel / fdc / fdc.asm
1 ;----------------------------------------------------------;
2 ; BOS kernel Christoffer Bubach, 2004-2012. ;
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_drivehead db 0 ; ((head*4)|drive)
16 fdd_head db 0
17 fdd_track db 0
18 fdd_sector db 0
19 fdd_error db 0 ; should we recalibrate
20 ; at next read/write?
21 fdd_errorcode db 0
22
23 result_ST0 db 0
24 result_ST1 db 0 ; or pcn
25 result_ST2 db 0
26 result_ST3 db 0
27 result_C db 0
28 result_H db 0
29 result_R db 0
30 result_N db 0
31 result_extra db 0
32
33
34
35 ;------------------------------------------------------;
36 ; initializes the floppy disk driver ;
37 ; ;
38 ;------------------------------------------------------;
39 fdc_init:
40 push eax
41 push ebx
42 push ecx
43 push edi
44 push esi
45
46 xor eax, eax ; get configuration
47 mov al, 0x10 ; from CMOS.
48 out 0x70, al
49 in al, 0x71
50
51 shr al, 4
52 cmp al, 4 ; a 1.44mb?
53 jnz .no_floppy
54
55 mov cl, 0x26 ; hook IRQ 6
56 mov dx, 0x8 ; CS = 8
57 mov edi, floppy_irq
58 call set_int
59
60 mov cl, 6 ; enable IRQ6
61 call enable_irq
62
63 call fdd_reset ; reset FDC
64
65 .no_floppy:
66 pop esi
67 pop edi
68 pop ecx
69 pop ebx
70 pop eax
71 ret
72
73
74
75 ;------------------------------------------------------;
76 ; floppy IRQ ;
77 ; ;
78 ;------------------------------------------------------;
79 floppy_irq:
80 push ds
81 push eax
82 push ebx
83
84 mov ax, 0x10
85 mov ds, ax
86
87 mov [fdd_int_done], 1
88 mov al, 0x20
89 out 0x20, al
90
91 pop ebx
92 pop eax
93 pop ds
94 iret
95
96
97
98 ;------------------------------------------------------;
99 ; wait for a floppy int ;
100 ; out: cf = 1 if timeout ;
101 ;------------------------------------------------------;
102 wait_int:
103 push eax
104 push ecx
105
106 mov ecx, 150 ; 50 = 0.5 seconds.
107 call active_delay ; timer.inc
108 .l1:
109 cmp dword [ecx], 0 ; timeup?
110 je .error
111 mov ax, [fdd_int_done] ; if not we check for int.
112 or ax, ax
113 jz .l1
114
115 clc
116 jmp .end
117 .error:
118 stc
119 .end:
120 pop ecx
121 pop eax
122 ret
123
124
125
126 ;------------------------------------------------------;
127 ; fdd motor off ;
128 ; out: nothing ;
129 ;------------------------------------------------------;
130 fdd_off:
131 cmp [fdd_motor_on], 0
132 je .end
133 push eax
134 push edx
135
136 mov dx, 0x3F2
137 mov al, 0x0c ; motor off
138 out dx, al
139 mov [fdd_motor_on], 0
140
141 pop edx
142 pop eax
143 .end:
144 ret
145
146
147
148 ;------------------------------------------------------;
149 ; fdd motor on ;
150 ; out: nothing ;
151 ;------------------------------------------------------;
152 fdd_on:
153 cmp [fdd_motor_on], 1
154 je .end
155 push eax
156 push edx
157
158 mov dx, 0x3F2 ; motor 0 on..
159 mov al, 0x1C
160 out dx, al
161
162 mov ecx, 20 ; 1/5 of a sec. to speed up
163 call delay ; in timer.inc
164 mov [fdd_motor_on], 1
165
166 pop edx
167 pop eax
168 .end:
169 ret
170
171
172
173 ;------------------------------------------------------;
174 ; send a data byte to the FDC ;
175 ; ;
176 ; in: al = data byte ;
177 ;------------------------------------------------------;
178 fdc_sendbyte:
179 push edx
180 push ecx
181 push eax
182
183 mov ecx, 50 ; 50 = 0.5 seconds.
184 call active_delay ; timer.inc
185 .l1:
186 cmp dword [ecx], 0 ; timeup?
187 je .error
188 mov dx, 0x3f4 ; check status reg
189 in al, dx
190 and al, 0xC0
191 cmp al, 0x80 ; ok to write?
192 jnz .l1
193
194 pop eax
195 pop ecx
196 mov dx, 0x3F5 ; send byte
197 out dx, al
198 pop edx
199 clc
200 ret
201 .error:
202 pop eax
203 pop ecx
204 pop edx
205 stc
206 ret
207
208
209
210 ;------------------------------------------------------;
211 ; read a data byte from the FDC ;
212 ; ;
213 ; out: al = data byte ;
214 ;------------------------------------------------------;
215 fdc_getbyte:
216 push edx
217 push ecx
218 push eax
219
220 mov ecx, 50 ; 50 = 0.5 seconds.
221 call active_delay ; timer.inc
222 .l1:
223 cmp dword [ecx], 0 ; timeup?
224 je .error
225 mov dx, 0x3f4 ; check status reg
226 in al, dx
227 and al, 0xD0
228 cmp al, 0xD0 ; ok to read?
229 jnz .l1
230
231 pop eax
232 pop ecx
233 mov dx, 0x3F5 ; get the byte
234 in al, dx
235 pop edx
236 clc
237 ret
238 .error:
239 pop eax
240 pop ecx
241 pop edx
242 stc
243 ret
244
245
246
247 ;------------------------------------------------------;
248 ; sense interrupt status command ;
249 ; ;
250 ;------------------------------------------------------;
251 sensei:
252 push eax
253
254 mov al, 0x08 ; fdc command
255 call fdc_sendbyte
256 call fdc_getbyte
257 mov ah, al ; save ST0 in ah
258 call fdc_getbyte ; read PCN
259 clc
260 test ah, 0x80 ; test for error:
261 jz .end ; "invalid command"
262 stc
263 .end:
264 pop eax
265 ret
266
267
268
269 ;------------------------------------------------------;
270 ; reset controller ;
271 ; ;
272 ;------------------------------------------------------;
273 fdd_reset:
274 push eax
275 push ecx
276 push edx
277
278 mov byte [fdd_motor_on], 0
279
280 mov dx, 0x3f2
281 mov al, 8 ; off with all motors,
282 out dx, al ; dma,irq etc..
283
284 mov ecx, 5
285 call delay ; in timer.inc
286
287 mov dx, 0x3f7
288 mov al, 0
289 out dx, al ; work at 500 kbit/s
290
291 mov dx, 0x3f2
292 mov al, 0x0c
293 out dx, al ; reenable interrupts
294
295 mov [fdd_int_done], 0
296 call wait_int ; wait for floppy int.
297 jc .error ; timeout?
298
299 mov cx, 0x04
300 .status: ; 4 dummy-reads.
301 call sensei
302 loop .status
303
304 mov al, 0x03 ; specify command
305 call fdc_sendbyte
306 mov al, 0xDF ; SRT, HUT
307 call fdc_sendbyte
308 mov al, 0x02 ; HLT, ND
309 call fdc_sendbyte
310
311 mov al, 1
312 call fdd_recal_seek
313 jc .error
314 call fdd_off
315 clc
316 jmp .end
317 .error:
318 call fdd_off
319 stc
320 .end:
321 pop edx
322 pop ecx
323 pop eax
324 ret
325
326
327
328 ;------------------------------------------------------;
329 ; fdd_recal_seek - fdd recalibrate/seek ;
330 ;------------------------------------------------------;
331 ; ;
332 ; in: al = 0 on seek, 1 on recalibrate ;
333 ; bl = (at seek) track ;
334 ; bh = (at seek) ((head*4)|drive) ;
335 ; ;
336 ;------------------------------------------------------;
337 fdd_recal_seek:
338 push eax
339
340 call fdd_on ; turn motor on
341 cmp al, 0
342 jne .recalibrate
343 clc
344 cmp bl, [result_C] ; are we there yet? :D
345 je .ok
346 mov al, 0x0F ; seek command
347 call fdc_sendbyte
348 mov al, bh ; ((head*4)|drive)
349 call fdc_sendbyte
350 mov al, bl ; track
351 call fdc_sendbyte
352 mov [result_C], bl ; now on..?
353 jmp .get_int
354 .recalibrate:
355 mov al, 0x07 ; recalibrate command
356 call fdc_sendbyte
357 mov al, 0 ; drive number
358 call fdc_sendbyte
359 mov [result_C], 0 ; now on track 0
360 .get_int:
361 mov [fdd_int_done], 0
362 call wait_int
363 jc .error
364
365 call sensei ; sense interrupt status
366 jc .error
367 .ok:
368 clc
369 jmp .end
370 .error:
371 stc
372 .end:
373 pop eax
374 ret
375
376
377
378 ;------------------------------------------------------;
379 ; fdd_read_write - fdd read/write ;
380 ;------------------------------------------------------;
381 ; input: bl = 0 read, 1 write ;
382 ; ch = track/cylinder ;
383 ; cl = sector ;
384 ; dh = head ;
385 ; edi = address to store or read the data ;
386 ; output: al = status ;
387 ; cf = 0 if ok, 1 if error ;
388 ;------------------------------------------------------;
389 fdd_read_write:
390 pushad
391
392 and dh, 1 ; head 0 or 1?
393 mov [fdd_head], dh ; store it.
394 shl dh, 2
395 or dh, 0 ; drive 0, fd0
396 mov [fdd_drivehead], dh ; dh = ((head*4)|drive)
397 mov [fdd_errorcode], 0x04 ; basic error code
398 cmp ch, 0x51 ; check for allowed
399 jae .error ; track number.
400 mov [fdd_track], ch
401 cmp cl, 0x13 ; check for allowed
402 jae .error ; sector number.
403 mov [fdd_sector], cl
404
405 cmp [fdd_error], 1
406 jne .no_previous_error
407 mov al, 1
408 call fdd_recal_seek
409 .no_previous_error:
410 call fdd_on
411
412 mov dx, 0x3F7
413 mov al, 0 ; 500Kb/sec mode
414 out dx, al
415 mov [fdd_errorcode], 0x80 ; error code
416
417 xor ecx, ecx
418 mov cx, 3 ; try seek 3 times
419 .l2:
420 mov al, 0
421 push ebx
422 mov bl, [fdd_track]
423 mov bh, [fdd_drivehead] ; ((head*4)|drive)
424 call fdd_recal_seek
425 pop ebx
426 jnc .l3 ; ok, continue.
427 loop .l2
428 jmp .error ; timeout.
429 .l3:
430 push ebx
431 cmp bl, 0
432 je .read_fdd
433
434 .write_fdd:
435 push edi
436 mov esi, edi
437 mov edi, 0x80000 ; copy the stuff we will
438 mov ecx, 128 ; write to the DMA buffer
439 rep movsd ; 128*4=512
440 pop edi
441
442 mov bl, 2 ; channel 2
443 mov esi, 512 ; bytes to write
444 mov ecx, 0x80000 ; page & offset
445 mov bh, 1 ; write floppy, read DMA
446 call dma_transfer
447
448 mov al, 0xC5 ; write sector command
449 call fdc_sendbyte
450 jmp .cont
451
452 .read_fdd:
453 mov bl, 2 ; channel 2
454 mov esi, 512 ; bytes to read
455 mov ecx, 0x80000 ; page & offset
456 mov bh, 0 ; read floppy, write DMA
457 call dma_transfer
458
459 mov al, 0xE6 ; read sector command
460 call fdc_sendbyte
461
462 .cont:
463 pop ebx
464 mov al, [fdd_drivehead] ; ((head*4)|drive)
465 call fdc_sendbyte
466 mov al, [fdd_track] ; track/cylinder
467 call fdc_sendbyte
468
469 mov al, [fdd_head] ; head/side 0 or 1
470 call fdc_sendbyte
471 mov al, [fdd_sector] ; sector number
472 call fdc_sendbyte
473 mov al, 0x02 ; sector size, 512 bytes
474 call fdc_sendbyte
475
476 mov al, 0x12 ; sectors to a track
477 call fdc_sendbyte
478 mov al, 0x1B ; gap length
479 call fdc_sendbyte
480 mov al, 0xFF ; data length
481 call fdc_sendbyte
482
483 mov [fdd_int_done], 0
484 call wait_int
485 jc .error
486
487 call fdc_getbyte
488 mov [result_ST0], al ; ST0
489 call fdc_getbyte
490 mov [result_ST1], al ; ST1
491 call fdc_getbyte
492 mov [result_ST2], al ; ST2
493 call fdc_getbyte
494 mov [result_C], al ; cylinder
495 call fdc_getbyte
496 mov [result_H], al ; head
497 call fdc_getbyte
498 mov [result_R], al ; sector number.
499 call fdc_getbyte
500 mov [result_N], al ; sector size
501
502 test [result_ST0], 0xc0 ; test if sr0 is 0xC0
503 jnz .error
504 cmp bl, 1 ; did we write the disk?
505 je .ok
506
507 mov ecx, 512 ; sector size in bytes
508 mov esi, 0x80000 ; copy to dest. in edi
509 rep movsb
510 .ok:
511 mov [fdd_errorcode], 0 ; no error.. :D
512 mov [fdd_error], 0 ; no recal. next time
513 clc
514 jmp .end
515 .error:
516 mov [fdd_error], 1 ; recalibrate next time
517 stc
518 .end:
519 call fdd_off ; floppy motor off
520 popad
521 mov al, [fdd_errorcode] ; error status
522 ret