Fixed lack of error handling in FDD driver, also abstracted the Read/Write
authorJohn Hodge <[email protected]>
Sat, 27 Mar 2010 03:11:55 +0000 (11:11 +0800)
committerJohn Hodge <[email protected]>
Sat, 27 Mar 2010 03:11:55 +0000 (11:11 +0800)
operations into one common function.

Kernel/drv/dma.c
Kernel/include/dma.h
Modules/Storage/FDD/fdd.c

index 750b180..1f356cd 100644 (file)
@@ -105,3 +105,19 @@ int DMA_ReadData(int channel, int count, void *buffer)
        memcpy(buffer, dma_addresses[channel], count);\r
        return 0;\r
 }\r
+\r
+/**\r
+ * \fn void DMA_WriteData(int channel, int count, void *buffer)\r
+ * \brief Write data to a DMA buffer\r
+ */\r
+int DMA_WriteData(int channel, int count, void *buffer)\r
+{\r
+       if(channel < 0 || channel > 7)\r
+               return -1;\r
+       if(count < 0 || count > DMA_SIZE)\r
+               return -2;\r
+       \r
+       memcpy(dma_addresses[channel], buffer, count);\r
+       \r
+       return 0;\r
+}\r
index 5b0bbda..b1a6d1a 100644 (file)
@@ -6,5 +6,6 @@
 
 extern void    DMA_SetChannel(int channel, int length, int read);
 extern int     DMA_ReadData(int channel, int count, void *buffer);
+extern int     DMA_WriteData(int channel, int count, void *buffer);
 
 #endif
index 793e76c..e54e774 100644 (file)
@@ -20,6 +20,7 @@
 #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
@@ -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\"" };\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
@@ -339,25 +343,16 @@ Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk)
        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
@@ -389,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 )\r
                Threads_Yield();\r
        if( i > FDD_SEEK_TIMEOUT ) {\r
+               RELEASE(&glFDD);\r
                LEAVE('i', 0);\r
                return 0;\r
        }\r
@@ -396,46 +392,136 @@ int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
                \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

UCC git Repository :: git.ucc.asn.au