#define FDD_SEEK_TIMEOUT 10 // Timeout for a seek operation\r
#define MOTOR_ON_DELAY 500 // Miliseconds\r
#define MOTOR_OFF_DELAY 2000 // Miliseconds\r
+#define FDD_MAX_READWRITE_ATTEMPTS 16\r
\r
// === TYPEDEFS ===\r
/**\r
static const char *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };\r
static const int cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };\r
static const short cPORTBASE[] = { 0x3F0, 0x370 };\r
+#if DEBUG\r
+static const char *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"};\r
+#endif\r
\r
enum FloppyPorts {\r
PORT_STATUSA = 0x0,\r
return ret;\r
}\r
\r
-/**\r
- * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
- * \brief Read a sector from disk\r
- * \todo Make real-hardware safe (account for read errors)\r
-*/\r
-int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer)\r
{\r
int cyl, head, sec;\r
int spt, base;\r
int i;\r
int lba = SectorAddr;\r
+ Uint8 st0, st1, st2, rcy, rhe, rse, bps; // Status Values\r
\r
ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);\r
\r
- if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- \r
base = cPORTBASE[Disk >> 1];\r
\r
LOG("Calculating Disk Dimensions");\r
while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )\r
Threads_Yield();\r
if( i > FDD_SEEK_TIMEOUT ) {\r
+ RELEASE(&glFDD);\r
LEAVE('i', 0);\r
return 0;\r
}\r
\r
// Read Data from DMA\r
LOG("Setting DMA for read");\r
- DMA_SetChannel(2, 512, 1); // Read 512 Bytes from channel 2\r
+ DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2\r
\r
- LOG("Sending read command");\r
+ LOG("Sending command");\r
\r
//Threads_Wait(100); // Wait for Head to settle\r
Time_Delay(100);\r
- FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6\r
- FDD_int_SendByte(base, (head << 2) | (Disk&1));\r
- FDD_int_SendByte(base, (Uint8)cyl);\r
- FDD_int_SendByte(base, (Uint8)head);\r
- FDD_int_SendByte(base, (Uint8)sec);\r
- FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val})\r
- FDD_int_SendByte(base, spt); // SPT\r
- FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default)\r
- FDD_int_SendByte(base, 0xFF); // Data Length\r
\r
- // Wait for IRQ\r
- LOG("Waiting for Data to be read");\r
- FDD_WaitIRQ();\r
- \r
- // Read Data from DMA\r
- LOG(" FDD_ReadSector: Reading Data");\r
- DMA_ReadData(2, 512, Buffer);\r
- \r
- // Clear Input Buffer\r
- LOG("Clearing Input Buffer");\r
- FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
- FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
+ for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )\r
+ {\r
+ if( Write )\r
+ FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6\r
+ else\r
+ FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6\r
+ FDD_int_SendByte(base, (head << 2) | (Disk&1));\r
+ FDD_int_SendByte(base, (Uint8)cyl);\r
+ FDD_int_SendByte(base, (Uint8)head);\r
+ FDD_int_SendByte(base, (Uint8)sec);\r
+ FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val})\r
+ FDD_int_SendByte(base, spt); // SPT\r
+ FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default)\r
+ FDD_int_SendByte(base, 0xFF); // Data Length\r
+ \r
+ // Wait for IRQ\r
+ if( Write ) {\r
+ LOG("Writing Data");\r
+ DMA_WriteData(2, 512, Buffer);\r
+ LOG("Waiting for Data to be written");\r
+ FDD_WaitIRQ();\r
+ }\r
+ else {\r
+ LOG("Waiting for data to be read");\r
+ FDD_WaitIRQ();\r
+ LOG("Reading Data");\r
+ DMA_ReadData(2, 512, Buffer);\r
+ }\r
+ \r
+ // Clear Input Buffer\r
+ LOG("Clearing Input Buffer");\r
+ // Status Values\r
+ st0 = FDD_int_GetByte(base);\r
+ st1 = FDD_int_GetByte(base);\r
+ st2 = FDD_int_GetByte(base);\r
+ \r
+ // Cylinder, Head and Sector (mutilated in some way\r
+ rcy = FDD_int_GetByte(base);\r
+ rhe = FDD_int_GetByte(base);\r
+ rse = FDD_int_GetByte(base);\r
+ // Should be the BPS set above (0x02)\r
+ bps = FDD_int_GetByte(base);\r
+ \r
+ // Check Status\r
+ // - Error Code\r
+ if(st0 & 0xC0) {\r
+ LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]);\r
+ continue;\r
+ }\r
+ // - Status Flags\r
+ if(st0 & 0x08) { LOG("Drive not ready"); continue; }\r
+ if(st1 & 0x80) { LOG("End of Cylinder"); continue; }\r
+ if(st1 & 0x20) { LOG("CRC Error"); continue; }\r
+ if(st1 & 0x10) { LOG("Controller Timeout"); continue; }\r
+ if(st1 & 0x04) { LOG("No Data Found"); continue; }\r
+ if(st1 & 0x01 || st2 & 0x01) {\r
+ LOG("No Address mark found");\r
+ continue;\r
+ }\r
+ if(st2 & 0x40) { LOG("Deleted address mark"); continue; }\r
+ if(st2 & 0x20) { LOG("CRC error in data"); continue; }\r
+ if(st2 & 0x10) { LOG("Wrong Cylinder"); continue; }\r
+ if(st2 & 0x04) { LOG("uPD765 sector not found"); continue; }\r
+ if(st2 & 0x02) { LOG("Bad Cylinder"); continue; }\r
+ \r
+ if(bps != 0x2) {\r
+ LOG("Returned BPS = 0x%02x, not 0x02", bps);\r
+ continue;\r
+ }\r
+ \r
+ if(st1 & 0x02) {\r
+ LOG("Floppy not writable");\r
+ i = FDD_MAX_READWRITE_ATTEMPTS;\r
+ break;\r
+ }\r
+ }\r
\r
// Release Spinlock\r
LOG("Realeasing Spinlock and setting motor to stop");\r
RELEASE(&glFDD);\r
\r
// Don't turn the motor off now, wait for a while\r
- 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);\r
\r
- IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );\r
-
- LEAVE('i', 1);\r
- return 1;\r
+ if( i < FDD_MAX_READWRITE_ATTEMPTS ) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ else {\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+}\r
+\r
+/**\r
+ * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+ * \brief Read a sector from disk\r
+ * \todo Make real-hardware safe (account for read errors)\r
+*/\r
+int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+{\r
+ int ret;\r
+ \r
+ ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);\r
+ \r
+ if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ \r
+ // Pass to general function\r
+ ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer);
+\r
+ if( ret == 0 ) {\r
+ IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ else {\r
+ LOG("Reading failed");\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
}\r
\r
/**\r