- LEAVE('i', Length);\r
- return Length;\r
- }\r
- #endif\r
- \r
- i = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, disk);\r
- LEAVE('i', i);\r
- return i;\r
-}\r
-\r
-/**\r
- * \fn Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint32 Disk)\r
- * \brief Reads \a Count contiguous sectors from a disk\r
- * \param SectorAddr Address of the first sector\r
- * \param Count Number of sectors to read\r
- * \param Buffer Destination Buffer\r
- * \param Disk Disk Number\r
- * \return Number of sectors read\r
- * \note Used as a ::DrvUtil_ReadBlock helper\r
- */\r
-Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk)\r
-{\r
- Uint ret = 0;\r
- while(Count --)\r
- {\r
- if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 )\r
- return ret;\r
- \r
- Buffer = (void*)( (tVAddr)Buffer + 512 );\r
- SectorAddr ++;\r
- ret ++;\r
- }\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
-{\r
- int cyl, head, sec;\r
- int spt, base;\r
- int i;\r
- int lba = SectorAddr;\r
- \r
- ENTER("idisk Xlba pbuf", disk, lba, buf);\r
- \r
- #if USE_CACHE\r
- FDD_AquireCacheSpinlock();\r
- for( i = 0; i < siFDD_SectorCacheSize; i++ )\r
- {\r
- if(sFDD_SectorCache[i].timestamp == 0) continue;\r
- if(sFDD_SectorCache[i].disk == Disk\r
- && sFDD_SectorCache[i].sector == lba) {\r
- LOG("Found %i in cache %i", lba, i);\r
- memcpy(Buffer, sFDD_SectorCache[i].data, 512);\r
- sFDD_SectorCache[i].timestamp = now();\r
- FDD_FreeCacheSpinlock();\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- }\r
- LOG("Read %i from Disk", lba);\r
- FDD_FreeCacheSpinlock();\r
- #else\r
- if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- #endif\r
- \r
- base = cPORTBASE[Disk>>1];\r
- \r
- LOG("Calculating Disk Dimensions");\r
- // Get CHS position\r
- if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1) {\r
- LEAVE('i', -1);\r
- return -1;\r
- }\r
- \r
- // Remove Old Timer\r
- Time_RemoveTimer(gFDD_Devices[Disk].timer);\r
- // Check if Motor is on\r
- if(gFDD_Devices[Disk].motorState == 0) {\r
- FDD_int_StartMotor(Disk);\r
- }\r
- \r
- LOG("Wait for Motor Spinup");\r
- \r
- // Wait for spinup\r
- while(gFDD_Devices[Disk].motorState == 1) Threads_Yield();\r
- \r
- LOG("C:%i,H:%i,S:%i", cyl, head, sec);\r
- LOG("Acquire Spinlock");\r
- \r
- FDD_AquireSpinlock();\r
- \r
- // Seek to track\r
- outb(base+CALIBRATE_DRIVE, 0);\r
- i = 0;\r
- while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT ) Threads_Yield();\r
- //FDD_SensInt(base, NULL, NULL); // Wait for IRQ\r
- \r
- LOG("Setting DMA for read");\r
- \r
- //Read Data from DMA\r
- DMA_SetChannel(2, 512, 1); // Read 512 Bytes\r
- \r
- LOG("Sending read 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
- \r
- LOG("Realeasing Spinlock and Setting motor to stop");\r
- // Release Spinlock\r
- FDD_FreeSpinlock();\r
- \r
- //Set timer to turn off motor affter a gap\r
- gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk); //One Shot Timer
-\r
- #if USE_CACHE\r
- {\r
- FDD_AquireCacheSpinlock();\r
- int oldest = 0;\r
- for(i=0;i<siFDD_SectorCacheSize;i++)\r
- {\r
- if(sFDD_SectorCache[i].timestamp == 0) {\r
- oldest = i;\r
- break;\r
- }\r
- if(sFDD_SectorCache[i].timestamp < sFDD_SectorCache[oldest].timestamp)\r
- oldest = i;\r
- }\r
- sFDD_SectorCache[oldest].timestamp = now();\r
- sFDD_SectorCache[oldest].disk = Disk;\r
- sFDD_SectorCache[oldest].sector = lba;\r
- memcpy(sFDD_SectorCache[oldest].data, Buffer, 512);\r
- FDD_FreeCacheSpinlock();\r
- }\r
- #else\r
- IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );\r
- #endif\r
-
- LEAVE('i', 1);\r
- return 1;\r
-}\r
-\r
-/**\r
- * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)\r
- * \brief Write a sector to the floppy disk\r
- * \note Not Implemented\r
- */\r
-int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)\r
-{\r
- Warning("[FDD ] Read Only at the moment");\r
- return -1;\r
-}\r
-\r
-/**\r
- * \fn int FDD_int_SeekTrack(int disk, int track)\r
- * \brief Seek disk to selected track\r
- */\r
-int FDD_int_SeekTrack(int disk, int head, int track)\r
-{\r
- Uint8 sr0, cyl;\r
- int base;\r
- \r
- base = cPORTBASE[disk>>1];\r
- \r
- // Check if seeking is needed\r
- if(gFDD_Devices[disk].track[head] == track)\r
- return 1;\r
- \r
- // - Seek Head 0\r
- FDD_int_SendByte(base, SEEK_TRACK);\r
- FDD_int_SendByte(base, (head<<2)|(disk&1));\r
- FDD_int_SendByte(base, track); // Send Seek command\r
- FDD_WaitIRQ();\r
- FDD_SensInt(base, &sr0, &cyl); // Wait for IRQ\r
- if((sr0 & 0xF0) != 0x20) {
- LOG("sr0 = 0x%x", sr0);
- return 0; //Check Status
- }\r
- if(cyl != track) return 0;\r
- \r
- // Set Track in structure\r
- gFDD_Devices[disk].track[head] = track;\r
- return 1;\r
-}\r
-\r
-/**\r
- * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
- * \brief Get Dimensions of a disk\r
- */\r
-int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
-{\r
- switch(type) {\r
- case 0:\r
- return 0;\r
- \r
- // 360Kb 5.25"\r
- case 1:\r
- *spt = 9;\r
- *s = (lba % 9) + 1;\r
- *c = lba / 18;\r
- *h = (lba / 9) & 1;\r
- break;\r
- \r
- // 1220Kb 5.25"\r
- case 2:\r
- *spt = 15;\r
- *s = (lba % 15) + 1;\r
- *c = lba / 30;\r
- *h = (lba / 15) & 1;\r
- break;\r
- \r
- // 720Kb 3.5"\r
- case 3:\r
- *spt = 9;\r
- *s = (lba % 9) + 1;\r
- *c = lba / 18;\r
- *h = (lba / 9) & 1;\r
- break;\r
- \r
- // 1440Kb 3.5"\r
- case 4:\r
- *spt = 18;\r
- *s = (lba % 18) + 1;\r
- *c = lba / 36;\r
- *h = (lba / 18) & 1;\r
- //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h);\r
- break;\r
- \r
- // 2880Kb 3.5"\r
- case 5:\r
- *spt = 36;\r
- *s = (lba % 36) + 1;\r
- *c = lba / 72;\r
- *h = (lba / 32) & 1;\r
- break;\r
- \r
- default:\r
- return -2;\r
- }\r
- return 1;\r
-}\r
-\r
-/**\r
- * \fn void FDD_IRQHandler(int Num)\r
- * \brief Handles IRQ6\r
- */\r
-void FDD_IRQHandler(int Num)\r
-{\r
- fdd_irq6 = 1;\r
-}\r
-\r
-/**\r
- * \fn FDD_WaitIRQ()\r
- * \brief Wait for an IRQ6\r
- */\r
-void FDD_WaitIRQ()\r
-{\r
- // Wait for IRQ\r
- while(!fdd_irq6) Threads_Yield();\r
- fdd_irq6 = 0;\r
-}\r
-\r
-void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)\r
-{\r
- FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS);\r
- if(sr0) *sr0 = FDD_int_GetByte(base);\r
- else FDD_int_GetByte(base);\r
- if(cyl) *cyl = FDD_int_GetByte(base);\r
- else FDD_int_GetByte(base);\r
-}\r
-\r
-void FDD_AquireSpinlock()\r
-{\r
- while(fdd_inUse)\r
- Threads_Yield();\r
- fdd_inUse = 1;\r
-}\r
-\r
-inline void FDD_FreeSpinlock()\r
-{\r
- fdd_inUse = 0;\r
-}\r
-\r
-#if USE_CACHE\r
-inline void FDD_AquireCacheSpinlock()\r
-{\r
- while(siFDD_CacheInUse) Threads_Yield();\r
- siFDD_CacheInUse = 1;\r
-}\r
-inline void FDD_FreeCacheSpinlock()\r
-{\r
- siFDD_CacheInUse = 0;\r
-}\r
-#endif\r
-\r
-/**\r
- * void FDD_int_SendByte(int base, char byte)\r
- * \brief Sends a command to the controller\r
- */\r
-void FDD_int_SendByte(int base, char byte)\r
-{\r
- volatile int state;\r
- int timeout = 128;\r
- for( ; timeout--; )\r
- {\r
- state = inb(base + PORT_MAINSTATUS);\r
- if ((state & 0xC0) == 0x80)\r
- {\r
- outb(base + PORT_DATA, byte);\r
- return;\r
- }\r
- inb(0x80); //Delay\r
- }\r
- #if WARN\r
- Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
- #endif\r
-}\r
-\r
-/**\r
- * int FDD_int_GetByte(int base, char byte)\r
- * \brief Receive data from fdd controller\r
- */\r
-int FDD_int_GetByte(int base)\r
-{\r
- volatile int state;\r
- int timeout;\r
- for( timeout = 128; timeout--; )\r
- {\r
- state = inb((base + PORT_MAINSTATUS));\r
- if ((state & 0xd0) == 0xd0)\r
- return inb(base + PORT_DATA);\r
- inb(0x80);\r
- }\r
- return -1;\r
-}\r
-\r
-/**\r
- * \brief Recalibrate the specified disk\r
- */\r
-void FDD_Recalibrate(int disk)\r
-{\r
- ENTER("idisk", disk);\r
- \r
- LOG("Starting Motor");\r
- FDD_int_StartMotor(disk);\r
- // Wait for Spinup\r
- while(gFDD_Devices[disk].motorState == 1) Threads_Yield();\r
- \r
- LOG("Sending Calibrate Command");\r
- FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);\r
- FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);\r
- \r
- LOG("Waiting for IRQ");\r
- FDD_WaitIRQ();\r
- FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL);\r
- \r
- LOG("Stopping Motor");\r
- FDD_int_StopMotor(disk);\r
- LEAVE('-');\r
-}\r
-\r
-/**\r
- * \brief Reset the specified FDD controller\r
- */\r
-void FDD_Reset(int id)\r
-{\r
- int base = cPORTBASE[id];\r
- \r
- ENTER("iID", id);\r
- \r
- outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC\r
- outb(base + PORT_DIGOUTPUT, 0x0C); // Re-enable FDC (DMA and Enable)\r
- \r
- LOG("Awaiting IRQ");\r
- \r
- FDD_WaitIRQ();\r
- FDD_SensInt(base, NULL, NULL);\r
- \r
- LOG("Setting Driver Info");\r
- outb(base + PORT_DATARATE, 0); // Set data rate to 500K/s\r
- FDD_int_SendByte(base, FIX_DRIVE_DATA); // Step and Head Load Times\r
- FDD_int_SendByte(base, 0xDF); // Step Rate Time, Head Unload Time (Nibble each)\r
- FDD_int_SendByte(base, 0x02); // Head Load Time >> 1\r
- while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track\r
- while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track\r
- \r
- LOG("Recalibrating Disk");\r
- FDD_Recalibrate((id<<1)|0);\r
+ else {
+ SENDB(CMD_READ_DATA|CMD_FLAG_MFM_ENCODING);
+ }
+ SENDB( (head << 2) | (Disk&1) );
+ SENDB(cyl & 0xFF);
+ SENDB(head & 0xFF);
+ SENDB(sec & 0xFF);
+ SENDB(0x02); // Bytes Per Sector (Real BPS=128*2^{val})
+ SENDB(spt); // SPT
+ SENDB(0x1B); // Gap Length (27 is default)
+ SENDB(0xFF); // Data Length
+
+ // Wait for IRQ
+ if( Write ) {
+ LOG("Writing Data");
+ DMA_WriteData(2, 512, Buffer);
+ LOG("Waiting for Data to be written");
+ if( FDD_WaitIRQ() ) { FDD_Reset(Disk>>1); continue; }
+ }
+ else {
+ LOG("Waiting for data to be read");
+ if( FDD_WaitIRQ() ) { FDD_Reset(Disk>>1); continue; }
+ LOG("Reading Data");
+ DMA_ReadData(2, 512, Buffer);
+ }
+
+ // Clear Input Buffer
+ LOG("Clearing Input Buffer");
+ // Status Values
+ FDD_int_GetByte(base, &st0);
+ FDD_int_GetByte(base, &st1);
+ FDD_int_GetByte(base, &st2);
+
+ // Cylinder, Head and Sector (mutilated in some way)
+ FDD_int_GetByte(base, NULL); // Cylinder
+ FDD_int_GetByte(base, NULL); // Head
+ FDD_int_GetByte(base, NULL); // Sector
+ // Should be the BPS set above (0x02)
+ FDD_int_GetByte(base, &bps);
+
+ // 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");
+ // Return error without triggering the attempt count check
+ i = FDD_MAX_READWRITE_ATTEMPTS+1;
+ break;
+ }
+
+ // Success!
+ break;
+ }
+ #undef SENDB
+
+ // Release Spinlock
+ LOG("Realeasing Spinlock and setting motor to stop");
+ Mutex_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
+ FDD_int_StopMotor(Disk);
+
+ // Error check
+ 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;
+ }
+}
+
+/**
+ * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
+ * \brief Write a sector to the floppy disk
+ * \note Not Implemented
+ */
+int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
+{
+ Log_Warning("FDD", "Read Only at the moment");
+ return -1;
+}
+
+/**
+ * \brief Seek disk to selected track
+ */
+int FDD_int_SeekTrack(int disk, int head, int track)
+{
+ Uint8 sr0=0, cyl=0;
+ int base, i, bUnclean;
+
+ base = cPORTBASE[disk>>1];
+
+ // Check if seeking is needed
+ if(gFDD_Devices[disk].track[head] == track)
+ return 1;
+
+ // - Seek Head 0
+ for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
+ {
+ if(i && bUnclean) FDD_Reset(disk >> 1);
+ bUnclean = 1;
+ if(FDD_int_SendByte(base, CMD_SEEK_TRACK)) continue;
+ if(FDD_int_SendByte(base, (head<<2)|(disk&1))) continue;
+ if(FDD_int_SendByte(base, track)) continue;
+ FDD_WaitIRQ();
+ FDD_SenseInt(base, &sr0, &cyl); // Wait for IRQ
+
+ bUnclean = 0;
+ if( cyl != track )
+ continue; // Try again
+ if( (sr0 & 0xF0) != 0x20 ) {
+ LOG("sr0 = 0x%x", sr0);
+ continue ;
+ }
+
+ break;
+ }
+
+ if( i == FDD_MAX_READWRITE_ATTEMPTS ) {
+ Log_Warning("FDD", "Unable to seek to track %i on disk %i",
+ track, disk);
+ return 0;
+ }
+
+ // Set Track in structure
+ gFDD_Devices[disk].track[head] = track;
+
+ LOG("Time_Delay(100)");
+ // Wait for Head to settle
+ Time_Delay(100);
+
+ return 1;
+}
+
+/**
+ * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
+ * \brief Get Dimensions of a disk
+ */
+int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
+{
+ switch(type) {
+ case 0:
+ return 0;
+
+ // 360Kb 5.25"
+ case 1:
+ *spt = 9;
+ *s = (lba % 9) + 1;
+ *c = lba / 18;
+ *h = (lba / 9) & 1;
+ break;
+
+ // 1220Kb 5.25"
+ case 2:
+ *spt = 15;
+ *s = (lba % 15) + 1;
+ *c = lba / 30;
+ *h = (lba / 15) & 1;
+ break;
+
+ // 720Kb 3.5"
+ case 3:
+ *spt = 9;
+ *s = (lba % 9) + 1;
+ *c = lba / 18;
+ *h = (lba / 9) & 1;
+ break;
+
+ // 1440Kb 3.5"
+ case 4:
+ *spt = 18;
+ *s = (lba % 18) + 1;
+ *c = lba / 36;
+ *h = (lba / 18) & 1;
+ //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h);
+ break;
+
+ // 2880Kb 3.5"
+ case 5:
+ *spt = 36;
+ *s = (lba % 36) + 1;
+ *c = lba / 72;
+ *h = (lba / 32) & 1;
+ break;
+
+ default:
+ return -2;
+ }
+ return 1;
+}
+
+/**
+ * \fn void FDD_IRQHandler(int Num)
+ * \brief Handles IRQ6
+ */
+void FDD_IRQHandler(int Num, void *Ptr)
+{
+ gbFDD_IrqFired = 1;
+}
+
+/**
+ * \brief Wait for the FDD IRQ to fire
+ * \return Boolean failure (1 for timeout)
+ */
+inline int FDD_WaitIRQ()
+{
+ tTime end = now() + 2000;
+
+ // Wait for IRQ
+ while(!gbFDD_IrqFired && now() < end)
+ Threads_Yield();
+
+ if( !gbFDD_IrqFired ) {
+ Log_Warning("FDD", "FDD_WaitIRQ - Timeout");
+ return 1;
+ }
+
+ gbFDD_IrqFired = 0;
+ return 0;
+}
+
+void FDD_SenseInt(int base, Uint8 *sr0, Uint8 *cyl)
+{
+ FDD_int_SendByte(base, CMD_SENSE_INTERRUPT);
+ FDD_int_GetByte(base, sr0);
+ FDD_int_GetByte(base, cyl);
+}
+
+/**
+ * void FDD_int_SendByte(int base, char byte)
+ * \brief Sends a command to the controller
+ */
+int FDD_int_SendByte(int base, Uint8 byte)
+{
+ tTime end = now() + 1000; // 1s
+
+ while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
+ Threads_Yield(); //Delay
+// Time_Delay(10); //Delay
+
+ if( inb(base + PORT_MAINSTATUS) & 0x40 ) {
+ Log_Warning("FDD", "FDD_int_SendByte: DIO set, is this ok?");
+ return -2;
+ }
+
+ if( now() > end )
+ {
+ Log_Warning("FDD", "FDD_int_SendByte: Timeout sending byte 0x%x to base 0x%x", byte, base);
+ return 1;
+ }
+ outb(base + PORT_DATA, byte);
+// Log_Debug("FDD", "FDD_int_SendByte: Sent 0x%02x to 0x%x", byte, base);
+ return 0;
+}
+
+/**
+ * int FDD_int_GetByte(int base, char byte)
+ * \brief Receive data from fdd controller
+ */
+int FDD_int_GetByte(int base, Uint8 *value)
+{
+ tTime end = now() + 1000; // 1s
+
+ while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
+ Time_Delay(10);
+
+ if( !(inb(base + PORT_MAINSTATUS) & 0x40) ) {
+ Log_Warning("FDD", "FDD_int_GetByte: DIO unset, is this ok?");
+ return -2;
+ }
+
+ if( now() > end )
+ {
+ Log_Warning("FDD", "FDD_int_GetByte: Timeout reading byte from base 0x%x", base);
+ return -1;
+ }
+
+ if(value)
+ *value = inb(base + PORT_DATA);
+ else
+ inb(base + PORT_DATA);
+ return 0;
+}
+
+/**
+ * \brief Recalibrate the specified disk
+ */
+void FDD_Recalibrate(int disk)
+{
+ ENTER("idisk", disk);
+
+ LOG("Starting Motor");
+ FDD_int_StartMotor(disk);
+ // Wait for Spinup
+ while(gFDD_Devices[disk].motorState <= 1) Threads_Yield();
+
+ LOG("Sending Calibrate Command");
+ FDD_int_SendByte(cPORTBASE[disk>>1], CMD_RECALIBRATE);
+ FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);
+
+ LOG("Waiting for IRQ");
+ FDD_WaitIRQ();
+ FDD_SenseInt(cPORTBASE[disk>>1], NULL, NULL);
+
+ LOG("Stopping Motor");
+ FDD_int_StopMotor(disk);
+ LEAVE('-');
+}
+
+/**
+ * \brief Reconfigure the controller
+ */
+int FDD_Reconfigure(int ID)
+{
+ Uint16 base = cPORTBASE[ID];
+
+ ENTER("iID", ID);
+
+ FDD_int_SendByte(base, CMD_CONFIGURE);
+ FDD_int_SendByte(base, 0);
+ // Implied seek enabled, FIFO Enabled, Drive Polling Disabled, data buffer threshold 8 bytes
+ FDD_int_SendByte(base, (1 << 6) | (0 << 5) | (0 << 4) | 7);
+ FDD_int_SendByte(base, 0); // Precompensation - use default
+
+ // Commit
+ FDD_int_SendByte(base, CMD_LOCK|CMD_FLAG_MULTI_TRACK);
+ FDD_int_GetByte(base, NULL);
+
+ LEAVE('i', 0);
+ return 0;
+}
+
+/**
+ * \brief Reset the specified FDD controller
+ */
+int FDD_Reset(int id)
+{
+ Uint16 base = cPORTBASE[id];
+ Uint8 motor_state;
+
+ ENTER("iID", id);
+
+ // Reset the card
+ motor_state = inb(base + PORT_DIGOUTPUT) & 0xF0;
+ outb(base + PORT_DIGOUTPUT, motor_state|0); // Disable FDC
+ Time_Delay(1);
+ outb(base + PORT_DIGOUTPUT, motor_state|8|4); // Re-enable FDC (DMA and Enable)
+
+ // Set the data rate
+ outb(base + PORT_DATARATE, 0); // Set data rate to 500K/s
+
+ // Wait for IRQ
+ LOG("Awaiting IRQ");
+
+ FDD_WaitIRQ();
+
+ FDD_SenseInt(base, NULL, NULL);
+
+ // Specify
+ FDD_int_SendByte(base, CMD_SPECIFY); // Step and Head Load Times
+ FDD_int_SendByte(base, 0xDF); // Step Rate Time, Head Unload Time (Nibble each)
+ FDD_int_SendByte(base, 0x02); // Head Load Time >> 1
+
+ LOG("Recalibrating Disk");
+ FDD_Recalibrate((id<<1)|0);