X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FStorage%2FFDD%2Ffdd.c;h=f72e548cdf1f24049feebe0919729b3d6eebb4fd;hb=35580b646a841d59323953f4dfaf47e678dd9d64;hp=229c66acb225e306d52739db68da4191aa0dd701;hpb=d0b532198d7b4b1bb156843bbb527550c27b6a62;p=tpg%2Facess2.git diff --git a/Modules/Storage/FDD/fdd.c b/Modules/Storage/FDD/fdd.c index 229c66ac..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, @@ -81,25 +85,21 @@ enum FloppyCommands { // === PROTOTYPES === // --- Filesystem int FDD_Install(char **Arguments); +void FDD_UnloadModule(); +// --- VFS Methods char *FDD_ReadDir(tVFS_Node *Node, int pos); tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, char *Name); int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data); Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); -// --- 1st Level Disk Access +// --- Functions for IOCache/DrvUtil Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk); // --- Raw Disk Access int FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer); int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer); // --- Helpers void FDD_IRQHandler(int Num); -void FDD_WaitIRQ(); +inline void FDD_WaitIRQ(); void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl); -inline void FDD_AquireSpinlock(); -inline void FDD_FreeSpinlock(); -#if USE_CACHE -inline void FDD_AquireCacheSpinlock(); -inline void FDD_FreeCacheSpinlock(); -#endif void FDD_int_SendByte(int base, char byte); int FDD_int_GetByte(int base); void FDD_Reset(int id); @@ -111,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; @@ -145,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); @@ -194,6 +198,22 @@ int FDD_Install(char **Arguments) return MODULE_ERR_OK; } +/** + * \brief Prepare the module for removal + */ +void FDD_UnloadModule() +{ + int i; + //DevFS_DelDevice( &gFDD_DriverInfo ); + LOCK(&glFDD); + for(i=0;i<4;i++) { + Time_RemoveTimer(gFDD_Devices[i].timer); + FDD_int_StopMotor(i); + } + RELEASE(&glFDD); + //IRQ_Clear(6); +} + /** * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos) * \brief Read Directory @@ -323,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]; @@ -371,21 +362,21 @@ 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"); - - FDD_AquireSpinlock(); + LOCK(&glFDD); // Seek to track outb(base + CALIBRATE_DRIVE, 0); @@ -393,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; } @@ -400,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"); - FDD_FreeSpinlock(); + 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; + } } /** @@ -555,7 +647,7 @@ void FDD_IRQHandler(int Num) * \fn FDD_WaitIRQ() * \brief Wait for an IRQ6 */ -void FDD_WaitIRQ() +inline void FDD_WaitIRQ() { // Wait for IRQ while(!gbFDD_IrqFired) Threads_Yield(); @@ -571,16 +663,6 @@ void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl) else FDD_int_GetByte(base); } -inline void FDD_AquireSpinlock() -{ - LOCK(&glFDD); -} - -inline void FDD_FreeSpinlock() -{ - RELEASE(&glFDD) -} - /** * void FDD_int_SendByte(int base, char byte) * \brief Sends a command to the controller @@ -599,8 +681,9 @@ void FDD_int_SendByte(int base, char byte) } inb(0x80); //Delay } + #if WARN - Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base); + Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base); #endif } @@ -714,23 +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; -} - -/** - * \fn void ModuleUnload() - * \brief Prepare the module for removal - */ -void ModuleUnload() -{ - int i; - FDD_AquireSpinlock(); - for(i=0;i<4;i++) { - Time_RemoveTimer(gFDD_Devices[i].timer); - FDD_int_StopMotor(i); - } - //IRQ_Clear(6); + LEAVE('-'); }