X-Git-Url: https://git.wirehaze.ovh/BOS.git/blobdiff_plain/e7307fb715b46f4ac09ae7781fad9dbefa1090a7..9e95ad198791394bb99ab761909d5c415011e527:/kernel/fdc/fdc.asm?ds=sidebyside diff --git a/kernel/fdc/fdc.asm b/kernel/fdc/fdc.asm index d90218d..5048e43 100755 --- a/kernel/fdc/fdc.asm +++ b/kernel/fdc/fdc.asm @@ -1,39 +1,34 @@ ;----------------------------------------------------------; -; BOS kernel Christoffer Bubach, 2004-2005. ; +; BOS kernel Christoffer Bubach, 2004-2012. ; ;----------------------------------------------------------; ; ; -; floppy disk driver originally by Craig Bamford, Dex4u. ; -; adjustments and for BOS by bubach. ; +; floppy disk driver. ; ; ; ;----------------------------------------------------------; -; NOTE: I'm almost finished with a much improved version of -; this code, that supports 2 drives of multiple types. -; I'll wait with that until next version, so you won't -; have to see a half finished mess here. ;---------------------------; ; variables and contants ; ;---------------------------; - fdd_int_done dw 0 ; is the IRQ done? - fdd_motor_on db 0 ; fdd motor on=1, off=0 - fdd_head db 0 - fdd_driveno db 0 - fdd_track db 0 - fdd_sector db 0 - - fdd_errorcode db 0 ; this the error code 00 = no error - fdd_tries db 0 ; no. of times to try, before error. - - ResultST0 db 0 - ResultST1 db 0 ; or pcn - ResultST2 db 0 - ResultST3 db 0 - ResultC db 0 - ResultH db 0 - ResultR db 0 - ResultN db 0 - ResultExtra db 0 + fdd_int_done dw 0 ; is the IRQ done? + fdd_motor_on db 0 ; fdd motor on=1, off=0 + fdd_drivehead db 0 ; ((head*4)|drive) + fdd_head db 0 + fdd_track db 0 + fdd_sector db 0 + fdd_error db 0 ; should we recalibrate + ; at next read/write? + fdd_errorcode db 0 + + result_ST0 db 0 + result_ST1 db 0 ; or pcn + result_ST2 db 0 + result_ST3 db 0 + result_C db 0 + result_H db 0 + result_R db 0 + result_N db 0 + result_extra db 0 @@ -42,22 +37,38 @@ ; ; ;------------------------------------------------------; fdc_init: - push ecx - push edi + push eax + push ebx + push ecx + push edi + push esi + + xor eax, eax ; get configuration + mov al, 0x10 ; from CMOS. + out 0x70, al + in al, 0x71 - mov cl, 0x26 ; hook interrupt 0x26 (IRQ6) - mov edi, floppy_irq - call set_int + shr al, 4 + cmp al, 4 ; a 1.44mb? + jnz .no_floppy - mov cl, 6 ; enable IRQ6 - call enable_irq + mov cl, 0x26 ; hook IRQ 6 + mov dx, 0x8 ; CS = 8 + mov edi, floppy_irq + call set_int - call fdd_reset ; reset FDC - call fdd_recalibrate + mov cl, 6 ; enable IRQ6 + call enable_irq - pop edi - pop ecx - ret + call fdd_reset ; reset FDC + + .no_floppy: + pop esi + pop edi + pop ecx + pop ebx + pop eax + ret @@ -66,24 +77,21 @@ fdc_init: ; ; ;------------------------------------------------------; floppy_irq: - pusha - push gs - push fs - push ds - push es - push esi + push ds + push eax + push ebx + + mov ax, 0x10 + mov ds, ax - or [fdd_int_done], 1 - mov al, 0x20 - out 0x20, al + mov [fdd_int_done], 1 + mov al, 0x20 + out 0x20, al - pop esi - pop es - pop ds - pop fs - pop gs - popa - iret + pop ebx + pop eax + pop ds + iret @@ -92,26 +100,26 @@ floppy_irq: ; out: cf = 1 if timeout ; ;------------------------------------------------------; wait_int: - push eax - push ecx - - mov ecx, 150 ; 150 = 1.5 seconds. - call active_delay ; timer.inc - .l1: - cmp dword [ecx], 0 ; timeup? - je .error - mov ax, [fdd_int_done] ; if not we check for int. - or ax, ax - jz .l1 - pop ecx - pop eax - clc - ret - .error: - pop ecx - pop eax - stc - ret + push eax + push ecx + + mov ecx, 150 ; 50 = 0.5 seconds. + call active_delay ; timer.inc + .l1: + cmp dword [ecx], 0 ; timeup? + je .error + mov ax, [fdd_int_done] ; if not we check for int. + or ax, ax + jz .l1 + + clc + jmp .end + .error: + stc + .end: + pop ecx + pop eax + ret @@ -120,18 +128,20 @@ wait_int: ; out: nothing ; ;------------------------------------------------------; fdd_off: - push eax - push edx - - mov dx, 0x3F2 - mov al, 0 ; all motors off.. - out dx, al - mov [fdd_motor_on], 0 + cmp [fdd_motor_on], 0 + je .end + push eax + push edx - pop edx - pop eax - ret + mov dx, 0x3F2 + mov al, 0x0c ; motor off + out dx, al + mov [fdd_motor_on], 0 + pop edx + pop eax + .end: + ret @@ -140,20 +150,23 @@ fdd_off: ; out: nothing ; ;------------------------------------------------------; fdd_on: - push eax - push edx + cmp [fdd_motor_on], 1 + je .end + push eax + push edx - mov dx, 0x3F2 ; motor 0 on.. - mov al, 0x1C - out dx, al + mov dx, 0x3F2 ; motor 0 on.. + mov al, 0x1C + out dx, al - mov ecx, 20 ; 1/5 of a sec. to speed up - call delay ; in timer.inc - mov [fdd_motor_on], 1 + mov ecx, 20 ; 1/5 of a sec. to speed up + call delay ; in timer.inc + mov [fdd_motor_on], 1 - pop edx - pop eax - ret + pop edx + pop eax + .end: + ret @@ -163,34 +176,35 @@ fdd_on: ; in: al = data byte ; ;------------------------------------------------------; fdc_sendbyte: - push edx - push ecx - push eax - - mov ecx, 150 ; 150 = 1.5 seconds. - call active_delay ; timer.inc - .l1: - cmp dword [ecx], 0 ; timeup? - je .error - mov dx, 0x3f4 ; check status reg - in al, dx - and al, 11000000b - cmp al, 10000000b ; are we ok to write - jnz .l1 - - pop eax - pop ecx - mov dx, 0x3F5 ; send byte - out dx, al - pop edx - clc - ret - .error: - pop eax - pop ecx - pop edx - stc - ret + push edx + push ecx + push eax + + mov ecx, 50 ; 50 = 0.5 seconds. + call active_delay ; timer.inc + .l1: + cmp dword [ecx], 0 ; timeup? + je .error + mov dx, 0x3f4 ; check status reg + in al, dx + and al, 0xC0 + cmp al, 0x80 ; ok to write? + jnz .l1 + + pop eax + pop ecx + mov dx, 0x3F5 ; send byte + out dx, al + pop edx + clc + ret + .error: + pop eax + pop ecx + pop edx + stc + ret + ;------------------------------------------------------; @@ -199,303 +213,310 @@ fdc_sendbyte: ; out: al = data byte ; ;------------------------------------------------------; fdc_getbyte: - push edx - push ecx - push eax - - mov ecx, 150 ; 150 = 1.5 seconds. - call active_delay ; timer.inc - .l1: - cmp dword [ecx], 0 ; timeup? - je .error - mov dx, 0x3f4 ; check status reg - in al, dx - and al, 11000000b - cmp al, 11000000b ; are we ok to read - jnz .l1 - - pop eax - pop ecx - mov dx, 0x3F5 ; get the byte - in al, dx - pop edx - clc - ret - .error: - pop eax - pop ecx - pop edx - stc - ret - + push edx + push ecx + push eax + + mov ecx, 50 ; 50 = 0.5 seconds. + call active_delay ; timer.inc + .l1: + cmp dword [ecx], 0 ; timeup? + je .error + mov dx, 0x3f4 ; check status reg + in al, dx + and al, 0xD0 + cmp al, 0xD0 ; ok to read? + jnz .l1 + + pop eax + pop ecx + mov dx, 0x3F5 ; get the byte + in al, dx + pop edx + clc + ret + .error: + pop eax + pop ecx + pop edx + stc + ret ;------------------------------------------------------; -; reset controller ; +; sense interrupt status command ; ; ; ;------------------------------------------------------; -fdd_reset: - push eax - push ecx - push edx - - mov dx, 0x3F2 - mov al, 00001000b ; no motors enabled, DMA Enabled, held FDC at reset - out dx, al ; drive A selected. - - mov ecx, 5 - call delay ; in timer.inc - - mov dx, 0x3F7 - mov al, 00000000b ; 500Kb/sec mode - out dx, al - - mov dx, 0x3F2 - or al, 00001100b ; FDC completed reset, al =0x0c. - out dx, al - - mov [fdd_int_done], 0 ; we need to wait - call wait_int ; for floppy int. - jc .error ; jump to error exit, if timeout. - - mov cx, 0x04 ; after a reset, the interrupts must be - .status: ; cleared by (four) dummy-reads. - mov al, 0x08 ; sense interrupt status command - call fdc_sendbyte - call fdc_getbyte - call fdc_getbyte - loop .status - - mov al, 0x03 ; specify command (includes next two bytes sent) - call fdc_sendbyte - mov al, 0xDF ; SRT = 3ms, HUT = 240ms - call fdc_sendbyte - mov al, 0x02 ; HLT = 16ms, ND = 0 - call fdc_sendbyte - .ok: - pop edx - pop ecx - pop eax - clc - ret - .error: - pop edx - pop ecx - pop eax - stc - ret +sensei: + push eax + mov al, 0x08 ; fdc command + call fdc_sendbyte + call fdc_getbyte + mov ah, al ; save ST0 in ah + call fdc_getbyte ; read PCN + clc + test ah, 0x80 ; test for error: + jz .end ; "invalid command" + stc + .end: + pop eax + ret ;------------------------------------------------------; -; fdd seek ; +; reset controller ; ; ; ;------------------------------------------------------; -fdd_seek: - push eax - - mov al, [ResultC] ; put what track/cylinder we are at in al - cmp [fdd_track], al ; is it the same as we want - je .ok ; yes, then leave. - - mov al, 0x0F ; seek command - call fdc_sendbyte - mov al, [fdd_driveno] ; drive # (00 = A) - call fdc_sendbyte - mov al, [fdd_track] ; cylinder # - call fdc_sendbyte - - mov [fdd_int_done], 0 - call wait_int - jc .error - - mov al, 0x08 ; sense interrupt status command - call fdc_sendbyte - call fdc_getbyte - mov ah, al ; save ST0 in ah - call fdc_getbyte ; should read PCN - - test ah, 00100000b ; test sr0 is 0x20 - jz .error ; if not we have a error :-(. - test ah,10000000b ; test sr0 is 0x80 - jnz .error ; if not we have a error :-(. - .ok: ; succsess.. :-) - pop eax - clc - ret - .error: - pop eax - stc - ret +fdd_reset: + push eax + push ecx + push edx + + mov byte [fdd_motor_on], 0 + + mov dx, 0x3f2 + mov al, 8 ; off with all motors, + out dx, al ; dma,irq etc.. + + mov ecx, 5 + call delay ; in timer.inc + + mov dx, 0x3f7 + mov al, 0 + out dx, al ; work at 500 kbit/s + + mov dx, 0x3f2 + mov al, 0x0c + out dx, al ; reenable interrupts + + mov [fdd_int_done], 0 + call wait_int ; wait for floppy int. + jc .error ; timeout? + + mov cx, 0x04 + .status: ; 4 dummy-reads. + call sensei + loop .status + + mov al, 0x03 ; specify command + call fdc_sendbyte + mov al, 0xDF ; SRT, HUT + call fdc_sendbyte + mov al, 0x02 ; HLT, ND + call fdc_sendbyte + + mov al, 1 + call fdd_recal_seek + jc .error + call fdd_off + clc + jmp .end + .error: + call fdd_off + stc + .end: + pop edx + pop ecx + pop eax + ret + +;------------------------------------------------------; +; fdd_recal_seek - fdd recalibrate/seek ; ;------------------------------------------------------; -; fdd recalibrate ; +; ; +; in: al = 0 on seek, 1 on recalibrate ; +; bl = (at seek) track ; +; bh = (at seek) ((head*4)|drive) ; ; ; ;------------------------------------------------------; -fdd_recalibrate: - push eax - - test [fdd_motor_on], 1 - jnz .l1 - call fdd_on - .l1: - mov al, 0x07 ; recalibrate command - call fdc_sendbyte - mov al, 0x00 ; selects drive a: - call fdc_sendbyte - - mov [fdd_int_done], 0 - call wait_int - jc .error - - mov al, 0x08 ; sense interrupt status command - call fdc_sendbyte - call fdc_getbyte ; read STO - mov ah, al ; save ST0 in ah - call fdc_getbyte - - test ah, 00100000b ; test sr0 is 0x20 - jz .error - test ah, 00010000b ; test sr0 is 0x80 - jnz .error +fdd_recal_seek: + push eax + + call fdd_on ; turn motor on + cmp al, 0 + jne .recalibrate + clc + cmp bl, [result_C] ; are we there yet? :D + je .ok + mov al, 0x0F ; seek command + call fdc_sendbyte + mov al, bh ; ((head*4)|drive) + call fdc_sendbyte + mov al, bl ; track + call fdc_sendbyte + mov [result_C], bl ; now on..? + jmp .get_int + .recalibrate: + mov al, 0x07 ; recalibrate command + call fdc_sendbyte + mov al, 0 ; drive number + call fdc_sendbyte + mov [result_C], 0 ; now on track 0 + .get_int: + mov [fdd_int_done], 0 + call wait_int + jc .error + + call sensei ; sense interrupt status + jc .error .ok: - mov [ResultC], 0 - pop eax - clc - ret - .error: - pop eax - stc - ret + clc + jmp .end + .error: + stc + .end: + pop eax + ret ;------------------------------------------------------; -; fdd read/write ; +; fdd_read_write - fdd read/write ; +;------------------------------------------------------; ; input: bl = 0 read, 1 write ; ; ch = track/cylinder ; ; cl = sector ; ; dh = head ; -; dl = drive (only A: drive used, 00 ) ; -; output: ah = status ; -; al = sector number read ; +; edi = address to store or read the data ; +; output: al = status ; ; cf = 0 if ok, 1 if error ; ;------------------------------------------------------; fdd_read_write: - pushad - and dh, 00000001b ; is it set to fdd_head 0 or 1? - mov [fdd_head], dh ; store it. - shl dh, 2 ; make the first 2 bits = 00 for A:. - mov [fdd_driveno], dh ; store it. - - mov [fdd_errorcode], 0x04 ; put error code in ah, just incase - cmp ch, 0x51 ; cmp if track number, is above 80 decimal (51 hex)? - jae .error ; if above jump error. - mov [fdd_track], ch ; if not above,store it. - - cmp cl, 0x13 ; cmp if fdd_sector number, is above 18 decimal (12 hex) ?. - jae .error ; if above jump error. - mov [fdd_sector], cl ; if not above,store it. - - test [fdd_motor_on], 1 - jnz .l1 - call fdd_on - .l1: - mov dx, 0x3F7 - mov al, 00000000b ; 500Kb/sec mode - out dx, al - mov [fdd_errorcode], 0x80 ; put basic error code, just in case. - - xor ecx, ecx - mov cx, 3 ; we want to try seek 3 times - .l2: - call fdd_seek ; we need to move to the right track. - jnc .l3 ; we should be on the right track. - loop .l2 - jmp .error ; timeout. - .l3: - mov dx, 0x3f4 ; check status reg (to see if DMA bit set) - in al, dx - test al, 00100000b ; test sr0 is 0x80 - jnz .error - - cmp bl, 0 - je .read_fdd - - .write_fdd: - mov bl, 2 ; channel 2 - mov esi, 512 ; bytes to write - mov ecx, 0x80000 ; page & offset - mov bh, 1 ; write floppy, "read DMA" - call dma_transfer - - mov al, 0xC5 ; write fdd_sector command - call fdc_sendbyte - jmp .cont - - .read_fdd: - mov bl, 2 ; channel 2 - mov esi, 512 ; bytes to read - mov ecx, 0x80000 ; page & offset - mov bh, 0 ; read floppy, "write DMA" - call dma_transfer - - mov al, 0xE6 ; read fdd_sector command - call fdc_sendbyte - - .cont: - mov al, [fdd_driveno] ; fdd_head no. 0, drive A: - call fdc_sendbyte - mov al, [fdd_track] ; cylinder - call fdc_sendbyte - - mov al, [fdd_head] ; head/side 0 or 1 - call fdc_sendbyte - mov al, [fdd_sector] ; sector number,starts at 1 - call fdc_sendbyte - mov al, 0x02 ; sector size - 512 bytes - call fdc_sendbyte - - mov al, 0x12 ; 18 decimal sectors to a track - call fdc_sendbyte - mov al, 0x1B ; 27 should be the gap length for a 3.5" 1.44Mb - call fdc_sendbyte - mov al, 0xFF ; not used data length, because sector size has been filled - call fdc_sendbyte - - mov [fdd_int_done], 0 - call wait_int - jc .error - - call fdc_getbyte - mov [ResultST0], al ; save result of ST0 in var - call fdc_getbyte - mov [ResultST1], al ; save result of ST1 in var - call fdc_getbyte - mov [ResultST2], al ; save result of ST2 in var - call fdc_getbyte - mov [ResultC], al ; save result of cylinder - call fdc_getbyte - mov [ResultH], al ; save result of head - call fdc_getbyte - mov [ResultR], al ; save result of sector number. - call fdc_getbyte - mov [ResultN], al ; save result of sector size - - test [ResultST0], 11000000b ; test sr0 is 0xC0 - jnz .error - mov [fdd_errorcode], 0x00 - .ok: - popad - mov ah, [fdd_errorcode] ; move error status into ah - mov al, [ResultR] - clc - ret - .error: - popad - mov ah, [fdd_errorcode] ; move error status into ah - stc - ret \ No newline at end of file + pushad + + and dh, 1 ; head 0 or 1? + mov [fdd_head], dh ; store it. + shl dh, 2 + or dh, 0 ; drive 0, fd0 + mov [fdd_drivehead], dh ; dh = ((head*4)|drive) + mov [fdd_errorcode], 0x04 ; basic error code + cmp ch, 0x51 ; check for allowed + jae .error ; track number. + mov [fdd_track], ch + cmp cl, 0x13 ; check for allowed + jae .error ; sector number. + mov [fdd_sector], cl + + cmp [fdd_error], 1 + jne .no_previous_error + mov al, 1 + call fdd_recal_seek + .no_previous_error: + call fdd_on + + mov dx, 0x3F7 + mov al, 0 ; 500Kb/sec mode + out dx, al + mov [fdd_errorcode], 0x80 ; error code + + xor ecx, ecx + mov cx, 3 ; try seek 3 times + .l2: + mov al, 0 + push ebx + mov bl, [fdd_track] + mov bh, [fdd_drivehead] ; ((head*4)|drive) + call fdd_recal_seek + pop ebx + jnc .l3 ; ok, continue. + loop .l2 + jmp .error ; timeout. + .l3: + push ebx + cmp bl, 0 + je .read_fdd + + .write_fdd: + push edi + mov esi, edi + mov edi, 0x80000 ; copy the stuff we will + mov ecx, 128 ; write to the DMA buffer + rep movsd ; 128*4=512 + pop edi + + mov bl, 2 ; channel 2 + mov esi, 512 ; bytes to write + mov ecx, 0x80000 ; page & offset + mov bh, 1 ; write floppy, read DMA + call dma_transfer + + mov al, 0xC5 ; write sector command + call fdc_sendbyte + jmp .cont + + .read_fdd: + mov bl, 2 ; channel 2 + mov esi, 512 ; bytes to read + mov ecx, 0x80000 ; page & offset + mov bh, 0 ; read floppy, write DMA + call dma_transfer + + mov al, 0xE6 ; read sector command + call fdc_sendbyte + + .cont: + pop ebx + mov al, [fdd_drivehead] ; ((head*4)|drive) + call fdc_sendbyte + mov al, [fdd_track] ; track/cylinder + call fdc_sendbyte + + mov al, [fdd_head] ; head/side 0 or 1 + call fdc_sendbyte + mov al, [fdd_sector] ; sector number + call fdc_sendbyte + mov al, 0x02 ; sector size, 512 bytes + call fdc_sendbyte + + mov al, 0x12 ; sectors to a track + call fdc_sendbyte + mov al, 0x1B ; gap length + call fdc_sendbyte + mov al, 0xFF ; data length + call fdc_sendbyte + + mov [fdd_int_done], 0 + call wait_int + jc .error + + call fdc_getbyte + mov [result_ST0], al ; ST0 + call fdc_getbyte + mov [result_ST1], al ; ST1 + call fdc_getbyte + mov [result_ST2], al ; ST2 + call fdc_getbyte + mov [result_C], al ; cylinder + call fdc_getbyte + mov [result_H], al ; head + call fdc_getbyte + mov [result_R], al ; sector number. + call fdc_getbyte + mov [result_N], al ; sector size + + test [result_ST0], 0xc0 ; test if sr0 is 0xC0 + jnz .error + cmp bl, 1 ; did we write the disk? + je .ok + + mov ecx, 512 ; sector size in bytes + mov esi, 0x80000 ; copy to dest. in edi + rep movsb + .ok: + mov [fdd_errorcode], 0 ; no error.. :D + mov [fdd_error], 0 ; no recal. next time + clc + jmp .end + .error: + mov [fdd_error], 1 ; recalibrate next time + stc + .end: + call fdd_off ; floppy motor off + popad + mov al, [fdd_errorcode] ; error status + ret \ No newline at end of file