X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FStorage%2FFDD%2Ffdd.c;h=f72e548cdf1f24049feebe0919729b3d6eebb4fd;hb=35580b646a841d59323953f4dfaf47e678dd9d64;hp=86cef014b6dcf13cc298dc2b64d717b58aa3f727;hpb=c254c93c067462864760a628e5946cebb0fa4d47;p=tpg%2Facess2.git diff --git a/Modules/Storage/FDD/fdd.c b/Modules/Storage/FDD/fdd.c index 86cef014..f72e548c 100644 --- a/Modules/Storage/FDD/fdd.c +++ b/Modules/Storage/FDD/fdd.c @@ -20,6 +20,7 @@ #define FDD_SEEK_TIMEOUT 10 // Timeout for a seek operation #define MOTOR_ON_DELAY 500 // Miliseconds #define MOTOR_OFF_DELAY 2000 // Miliseconds +#define FDD_MAX_READWRITE_ATTEMPTS 16 // === TYPEDEFS === /** @@ -51,6 +52,9 @@ typedef struct { static const char *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" }; static const int cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 }; static const short cPORTBASE[] = { 0x3F0, 0x370 }; +#if DEBUG +static const char *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"}; +#endif enum FloppyPorts { PORT_STATUSA = 0x0, @@ -107,7 +111,7 @@ void FDD_int_StartMotor(int disk); int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt); // === GLOBALS === -MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, NULL); +MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL); t_floppyDevice gFDD_Devices[2]; tSpinlock glFDD; volatile int gbFDD_IrqFired = 0; @@ -141,7 +145,11 @@ int FDD_Install(char **Arguments) gFDD_Devices[0].track[0] = -1; gFDD_Devices[1].track[1] = -1; - Log("[FDD ] Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]); + Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]); + + if( data == 0 ) { + return MODULE_ERR_NOTNEEDED; + } // Clear FDD IRQ Flag FDD_SensInt(0x3F0, NULL, NULL); @@ -335,44 +343,15 @@ Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk) return ret; } -/** - * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) - * \brief Read a sector from disk - * \todo Make real-hardware safe (account for read errors) -*/ -int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) +int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer) { int cyl, head, sec; int spt, base; int i; int lba = SectorAddr; + Uint8 st0, st1, st2, rcy, rhe, rse, bps; // Status Values - ENTER("iDisk XSectorAddr pBuffer", disk, SectorAddr, Buffer); - - #if USE_CACHE - FDD_AquireCacheSpinlock(); - for( i = 0; i < siFDD_SectorCacheSize; i++ ) - { - if(sFDD_SectorCache[i].timestamp == 0) continue; - if( sFDD_SectorCache[i].disk == Disk - && sFDD_SectorCache[i].sector == lba) - { - LOG("Found %i in cache %i", lba, i); - memcpy(Buffer, sFDD_SectorCache[i].data, 512); - sFDD_SectorCache[i].timestamp = now(); - FDD_FreeCacheSpinlock(); - LEAVE('i', 1); - return 1; - } - } - LOG("Read %i from Disk", lba); - FDD_FreeCacheSpinlock(); - #else - if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) { - LEAVE('i', 1); - return 1; - } - #endif + ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer); base = cPORTBASE[Disk >> 1]; @@ -383,20 +362,20 @@ int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) LEAVE('i', -1); return -1; } + LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec); - // Remove Old Timer - Time_RemoveTimer(gFDD_Devices[Disk].timer); - // Check if Motor is on - if(gFDD_Devices[Disk].motorState == 0) FDD_int_StartMotor(Disk); + LOCK(&glFDD); // Lock to stop the motor stopping on us + Time_RemoveTimer(gFDD_Devices[Disk].timer); // Remove Old Timer + // Start motor if needed + if(gFDD_Devices[Disk].motorState != 2) FDD_int_StartMotor(Disk); + RELEASE(&glFDD); LOG("Wait for the motor to spin up"); // Wait for spinup while(gFDD_Devices[Disk].motorState == 1) Threads_Yield(); - LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec); LOG("Acquire Spinlock"); - LOCK(&glFDD); // Seek to track @@ -405,6 +384,7 @@ int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT ) Threads_Yield(); if( i > FDD_SEEK_TIMEOUT ) { + RELEASE(&glFDD); LEAVE('i', 0); return 0; } @@ -412,46 +392,146 @@ int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) // Read Data from DMA LOG("Setting DMA for read"); - DMA_SetChannel(2, 512, 1); // Read 512 Bytes from channel 2 + DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2 - LOG("Sending read command"); + LOG("Sending command"); //Threads_Wait(100); // Wait for Head to settle Time_Delay(100); - FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6 - FDD_int_SendByte(base, (head << 2) | (Disk&1)); - FDD_int_SendByte(base, (Uint8)cyl); - FDD_int_SendByte(base, (Uint8)head); - FDD_int_SendByte(base, (Uint8)sec); - FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val}) - FDD_int_SendByte(base, spt); // SPT - FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default) - FDD_int_SendByte(base, 0xFF); // Data Length - - // Wait for IRQ - LOG("Waiting for Data to be read"); - FDD_WaitIRQ(); - // Read Data from DMA - LOG(" FDD_ReadSector: Reading Data"); - DMA_ReadData(2, 512, Buffer); - - // Clear Input Buffer - LOG("Clearing Input Buffer"); - FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base); - FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base); + for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ ) + { + if( Write ) + FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6 + else + FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6 + FDD_int_SendByte(base, (head << 2) | (Disk&1)); + FDD_int_SendByte(base, (Uint8)cyl); + FDD_int_SendByte(base, (Uint8)head); + FDD_int_SendByte(base, (Uint8)sec); + FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val}) + FDD_int_SendByte(base, spt); // SPT + FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default) + FDD_int_SendByte(base, 0xFF); // Data Length + + // Wait for IRQ + if( Write ) { + LOG("Writing Data"); + DMA_WriteData(2, 512, Buffer); + LOG("Waiting for Data to be written"); + FDD_WaitIRQ(); + } + else { + LOG("Waiting for data to be read"); + FDD_WaitIRQ(); + LOG("Reading Data"); + DMA_ReadData(2, 512, Buffer); + } + + // Clear Input Buffer + LOG("Clearing Input Buffer"); + // Status Values + st0 = FDD_int_GetByte(base); + st1 = FDD_int_GetByte(base); + st2 = FDD_int_GetByte(base); + + // Cylinder, Head and Sector (mutilated in some way + rcy = FDD_int_GetByte(base); + rhe = FDD_int_GetByte(base); + rse = FDD_int_GetByte(base); + // Should be the BPS set above (0x02) + bps = FDD_int_GetByte(base); + + // Check Status + // - Error Code + if(st0 & 0xC0) { + LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]); + continue; + } + // - Status Flags + if(st0 & 0x08) { LOG("Drive not ready"); continue; } + if(st1 & 0x80) { LOG("End of Cylinder"); continue; } + if(st1 & 0x20) { LOG("CRC Error"); continue; } + if(st1 & 0x10) { LOG("Controller Timeout"); continue; } + if(st1 & 0x04) { LOG("No Data Found"); continue; } + if(st1 & 0x01 || st2 & 0x01) { + LOG("No Address mark found"); + continue; + } + if(st2 & 0x40) { LOG("Deleted address mark"); continue; } + if(st2 & 0x20) { LOG("CRC error in data"); continue; } + if(st2 & 0x10) { LOG("Wrong Cylinder"); continue; } + if(st2 & 0x04) { LOG("uPD765 sector not found"); continue; } + if(st2 & 0x02) { LOG("Bad Cylinder"); continue; } + + if(bps != 0x2) { + LOG("Returned BPS = 0x%02x, not 0x02", bps); + continue; + } + + if(st1 & 0x02) { + LOG("Floppy not writable"); + i = FDD_MAX_READWRITE_ATTEMPTS+1; + break; + } + + // Success! + break; + } // Release Spinlock LOG("Realeasing Spinlock and setting motor to stop"); RELEASE(&glFDD); + if(i == FDD_MAX_READWRITE_ATTEMPTS) { + Log_Warning("FDD", "Exceeded %i attempts in %s the disk", + FDD_MAX_READWRITE_ATTEMPTS, + (Write ? "writing to" : "reading from") + ); + } + // Don't turn the motor off now, wait for a while - gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk); + gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk); - IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ); - - LEAVE('i', 1); - return 1; + if( i < FDD_MAX_READWRITE_ATTEMPTS ) { + LEAVE('i', 0); + return 0; + } + else { + LEAVE('i', 1); + return 1; + } +} + +/** + * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) + * \brief Read a sector from disk + * \todo Make real-hardware safe (account for read errors) +*/ +int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer) +{ + int ret; + + ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer); + + if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) { + LEAVE('i', 1); + return 1; + } + + // Pass to general function + ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer); + + if( ret == 0 ) { + IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ); + LEAVE('i', 1); + return 1; + } + else { + LOG("Reading failed"); + LEAVE('i', 0); + return 0; + } } /** @@ -717,8 +797,12 @@ void FDD_int_StartMotor(int disk) void FDD_int_StopMotor(int disk) { Uint8 state; + if( IS_LOCKED(&glFDD) ) return ; + ENTER("iDisk", disk); + state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT ); state &= ~( 1 << (4+disk) ); outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state ); gFDD_Devices[disk].motorState = 0; + LEAVE('-'); }