Added DMA and FDD drivers to the tree
authorJohn Hodge <[email protected]>
Thu, 1 Oct 2009 07:56:45 +0000 (15:56 +0800)
committerJohn Hodge <[email protected]>
Thu, 1 Oct 2009 07:56:45 +0000 (15:56 +0800)
Kernel/drv/dma.c [new file with mode: 0644]
Kernel/drv/fdd.c [new file with mode: 0644]

diff --git a/Kernel/drv/dma.c b/Kernel/drv/dma.c
new file mode 100644 (file)
index 0000000..0fae172
--- /dev/null
@@ -0,0 +1,94 @@
+/*\r
+ * AcessOS 1.0\r
+ * DMA Driver\r
+ */\r
+#include <common.h>\r
+\r
+#define DMA_SIZE       (0x2400)\r
+#define DMA_ADDRESS(c) ((c)*DMA_SIZE+0x500)    //Save Space for IDT and BDA\r
+\r
+#define LOWB(x)        ((x)&0xFF)\r
+#define HIB(x) (((x)>>8)&0xFF)\r
+#define HIW(x) (((x)>>16)&0xFFFF)\r
+\r
+typedef struct {\r
+       int     mode;\r
+       char    *address;\r
+} t_dmaChannel;\r
+\r
+const Uint8 cMASKPORT [8] = { 0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4 };\r
+const Uint8 cMODEPORT [8] = { 0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6 };\r
+const Uint8 cCLEARPORT[8] = { 0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8 };\r
+const Uint8 cPAGEPORT [8] = { 0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A };\r
+const Uint8 cADDRPORT [8] = { 0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC };\r
+const Uint8 cCOUNTPORT[8] = { 0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE };\r
+\r
+char   *dma_addresses[8];\r
+t_dmaChannel   dma_channels[8];\r
+\r
+/**\r
+ * \fn void DMA_Install()\r
+ * \brief Initialise DMA channels\r
+ */\r
+void DMA_Install()\r
+{\r
+       int i;\r
+       for(i=8;i--;)\r
+       {\r
+               outb( cMASKPORT[i], 0x04 | (i & 0x3) ); // mask channel\r
+               outb( cCLEARPORT[i], 0x00 );\r
+               outb( cMODEPORT[i], 0x48 | (i & 0x3) ); //Read Flag\r
+               outb( 0xd8, 0xff);      //Reset Flip-Flop\r
+               outb( cADDRPORT[i], LOWB(DMA_ADDRESS(i)) );     // send address\r
+               outb( cADDRPORT[i], HIB(DMA_ADDRESS(i)) );      // send address\r
+               outb( 0xd8, 0xff);      //Reset Flip-Flop\r
+               outb( cCOUNTPORT[i], LOWB(DMA_SIZE) );      // send size\r
+               outb( cCOUNTPORT[i], HIB(DMA_SIZE) );       // send size\r
+               outb( cPAGEPORT[i], LOWB(HIW(DMA_ADDRESS(i))) );        // send page\r
+               outb( cMASKPORT[i], i & 0x3 );              // unmask channel\r
+               \r
+               dma_channels[i].mode = 0;\r
+               dma_addresses[i] = (char*)DMA_ADDRESS(i);\r
+               dma_addresses[i] += 0xC0000000;\r
+       }\r
+}\r
+\r
+/**\r
+ * \fn void DMA_SetChannel(int channel, int length, int read)\r
+ * \brief Set DMA Channel Length and RW\r
+ */\r
+void DMA_SetChannel(int channel, int length, int read)\r
+{\r
+       channel &= 7;\r
+       read = read && 1;\r
+       if(length > DMA_SIZE)   length = DMA_SIZE;\r
+       length --;      //Adjust for DMA\r
+       //__asm__ __volatile__ ("cli");\r
+       outb( cMASKPORT[channel], 0x04 | (channel & 0x3) );             // mask channel\r
+       outb( cCLEARPORT[channel], 0x00 );\r
+       outb( cMODEPORT[channel], (0x44 + (!read)*4) | (channel & 0x3) );\r
+       outb( cADDRPORT[channel], LOWB(DMA_ADDRESS(channel)) );         // send address\r
+       outb( cADDRPORT[channel], HIB(DMA_ADDRESS(channel)) );          // send address\r
+       outb( cPAGEPORT[channel], HIW(DMA_ADDRESS(channel)) );          // send page\r
+       outb( cCOUNTPORT[channel], LOWB(length) );      // send size\r
+       outb( cCOUNTPORT[channel], HIB(length) );       // send size\r
+       outb( cMASKPORT[channel], channel & 0x3 );              // unmask channel\r
+       dma_addresses[channel] = (char*)DMA_ADDRESS(channel);\r
+       dma_addresses[channel] += 0xC0000000;\r
+       //__asm__ __volatile__ ("sti");\r
+}\r
+\r
+/**\r
+ * \fn void DMA_ReadData(int channel, int count, void *buffer)\r
+ * \brief Read data from a DMA buffer\r
+ */\r
+int DMA_ReadData(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
+       //LogF("memcpy(*0x%x, dma_channels[channel].address, count)\n", buffer\r
+       memcpy(buffer, dma_addresses[channel], count);\r
+       return 0;\r
+}\r
diff --git a/Kernel/drv/fdd.c b/Kernel/drv/fdd.c
new file mode 100644 (file)
index 0000000..2325696
--- /dev/null
@@ -0,0 +1,738 @@
+/*\r
+ * AcessOS 0.1\r
+ * Floppy Disk Access Code\r
+ */\r
+#define DEBUG  0\r
+#include <common.h>\r
+#include <modules.h>\r
+#include <fs_devfs.h>\r
+#include <tpl_drv_common.h>\r
+#include <dma.h>\r
+\r
+#define WARN   0\r
+\r
+// Version Information\r
+#define FDD_VER_MAJ     0\r
+#define FDD_VER_MIN    75\r
+\r
+#define USE_CACHE      1       // Use Sector Cache\r
+#define        CACHE_SIZE      32      // Number of cachable sectors\r
+#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
+\r
+// === TYPEDEFS ===\r
+typedef struct {\r
+        int    type;\r
+       volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off\r
+        int    track[2];\r
+        int    timer;\r
+       char    Name[2];\r
+       tVFS_Node       Node;\r
+} t_floppyDevice;\r
+\r
+typedef struct {\r
+       Uint64  timestamp;\r
+       Uint16  disk;\r
+       Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)\r
+       char    data[512];\r
+} t_floppySector;\r
+\r
+// === CONSTANTS ===\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
+\r
+enum FloppyPorts {\r
+       PORT_STATUSA    = 0x0,\r
+       PORT_STATUSB    = 0x1,\r
+       PORT_DIGOUTPUT  = 0x2,\r
+       PORT_MAINSTATUS = 0x4,\r
+       PORT_DATARATE   = 0x4,\r
+       PORT_DATA               = 0x5,\r
+       PORT_DIGINPUT   = 0x7,\r
+       PORT_CONFIGCTRL = 0x7\r
+};\r
+\r
+enum FloppyCommands {\r
+       FIX_DRIVE_DATA  = 0x03,\r
+       HECK_DRIVE_STATUS       = 0x04,\r
+       CALIBRATE_DRIVE = 0x07,\r
+       CHECK_INTERRUPT_STATUS = 0x08,\r
+       SEEK_TRACK              = 0x0F,\r
+       READ_SECTOR_ID  = 0x4A,\r
+       FORMAT_TRACK    = 0x4D,\r
+       READ_TRACK              = 0x42,\r
+       READ_SECTOR             = 0x66,\r
+       WRITE_SECTOR    = 0xC5,\r
+       WRITE_DELETE_SECTOR     = 0xC9,\r
+       READ_DELETE_SECTOR      = 0xCC,\r
+};\r
+\r
+// === PROTOTYPES ===\r
+char   *FDD_ReadDir(tVFS_Node *Node, int pos);\r
+tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, char *Name);\r
+static int     fdd_readSector(int disk, int lba, void *buf);\r
+void   FDD_WaitIRQ();\r
+void   FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);\r
+static void    FDD_AquireSpinlock();\r
+static void    inline FDD_FreeSpinlock();\r
+#if USE_CACHE\r
+static inline void FDD_AquireCacheSpinlock();\r
+static inline void FDD_FreeCacheSpinlock();\r
+#endif\r
+static void    sendbyte(int base, char byte);\r
+static int     getbyte(int base);\r
+static int     seekTrack(int disk, int head, int track);\r
+static void    stop_motor(int disk);\r
+static void    start_motor(int disk);\r
+static int     get_dims(int type, int lba, int *c, int *h, int *s, int *spt);\r
+ int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+ int   FDD_Install(char **Arguments);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x004B, FDD, FDD_Install, NULL, NULL);\r
+static t_floppyDevice  fdd_devices[2];\r
+static volatile int    fdd_inUse = 0;\r
+static volatile int    fdd_irq6 = 0;\r
+tDevFS_Driver  gFDD_DriverInfo = {\r
+       NULL, "fdd",\r
+       {\r
+       .Size = -1,\r
+       .NumACLs = 1,\r
+       .ACLs = &gVFS_ACL_EveryoneRX,\r
+       .Flags = VFS_FFLAG_DIRECTORY,\r
+       .ReadDir = FDD_ReadDir,\r
+       .FindDir = FDD_FindDir,\r
+       .IOCtl = FDD_IOCtl\r
+       }\r
+};\r
+#if USE_CACHE\r
+static int     siFDD_CacheInUse = 0;\r
+static int     siFDD_SectorCacheSize = CACHE_SIZE;\r
+static t_floppySector  sFDD_SectorCache[CACHE_SIZE];\r
+#endif\r
+\r
+//=== CODE ===\r
+/**\r
+ * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
+ * \brief Read Directory\r
+ */\r
+char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
+{\r
+       //Update Accessed Time\r
+       //gFDD_DrvInfo.rootNode.atime = now();\r
+       \r
+       //Check for bounds\r
+       if(pos >= 2 || pos < 0)\r
+               return NULL;\r
+       \r
+       if(fdd_devices[pos].type == 0)\r
+               return VFS_SKIP;\r
+       \r
+       //Return\r
+       return fdd_devices[pos].Name;\r
+}\r
+\r
+/**\r
+ * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename);\r
+ * \brief Find File Routine (for vfs_node)\r
+ */\r
+tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename)\r
+{\r
+       int i;\r
+       \r
+       ENTER("sfilename", filename);\r
+       \r
+       if(filename == NULL)    return NULL;\r
+       \r
+       //Check string length (should be 1)\r
+       if(filename[0] == '\0') return NULL;\r
+       if(filename[1] != '\0') return NULL;\r
+       \r
+       //Get First char\r
+       i = filename[0] - '0';\r
+       \r
+       // Check for 1st disk and if it is present return\r
+       if(i == 0 && fdd_devices[0].type != 0)\r
+               return &fdd_devices[0].Node;\r
+       \r
+       // Check for 2nd disk and if it is present return\r
+       if(i == 1 && fdd_devices[1].type != 0)\r
+               return &fdd_devices[1].Node;\r
+       \r
+       // Else return null\r
+       return NULL;\r
+}\r
+\r
+/**\r
+ * \fn Uint64 fdd_readFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+ * \brief Read Data from a disk\r
+*/\r
+Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+       int i = 0;\r
+       int     disk;\r
+       Uint32  buf[128];\r
+       \r
+       ENTER("xoff xlen pbuffer", off, len, buffer)\r
+       \r
+       if(node == NULL) {\r
+               LEAVE('i', -1);\r
+               return -1;\r
+       }\r
+       \r
+       if(node->Inode != 0 && node->Inode != 1) {\r
+               LEAVE('i', -1);\r
+               return -1;\r
+       }\r
+       \r
+       disk = node->Inode;\r
+       \r
+       // Update Accessed Time\r
+       node->ATime = now();\r
+       \r
+       if((off & 0x1FF) || (len & 0x1FF))\r
+       {\r
+               // Un-Aligned Offset/Length\r
+                int    startOff = off>>9;\r
+                int    sectOff = off&0x1FF;\r
+                int    sectors = (len+0x1FF)>>9;\r
+       \r
+               LOG("Non-aligned Read");\r
+               \r
+               //Read Starting Sector\r
+               if(!fdd_readSector(disk, startOff, buf))\r
+                       return 0;\r
+               memcpy(buffer, (char*)(buf+sectOff), len>512-sectOff?512-sectOff:len);\r
+               \r
+               //If the data size is one sector or less\r
+               if(len <= 512-sectOff) {\r
+                       LEAVE('X', len);\r
+                       return len;     //Return\r
+               }\r
+               buffer += 512-sectOff;\r
+       \r
+               //Read Middle Sectors\r
+               for(i=1;i<sectors-1;i++)        {\r
+                       if(!fdd_readSector(disk, startOff+i, buf)) {\r
+                               LEAVE('i', -1);\r
+                               return -1;\r
+                       }\r
+                       memcpy(buffer, buf, 512);\r
+                       buffer += 512;\r
+               }\r
+       \r
+               //Read End Sectors\r
+               if(!fdd_readSector(disk, startOff+i, buf))\r
+                       return 0;\r
+               memcpy(buffer, buf, (len&0x1FF)-sectOff);\r
+               
+               LEAVE('X', len);\r
+               return len;\r
+       }\r
+       else\r
+       {\r
+                int    count = len >> 9;\r
+                int    sector = off >> 9;\r
+               LOG("Aligned Read");\r
+               //Aligned Offset and Length - Simple Code\r
+               for(i=0;i<count;i++)\r
+               {\r
+                       fdd_readSector(disk, sector, buf);\r
+                       memcpy(buffer, buf, 512);\r
+                       buffer += 512;\r
+                       sector++;\r
+               }
+               LEAVE('i', len);\r
+               return len;\r
+       }\r
+}\r
+\r
+/**\r
+ * \fn static int fdd_readSector(int disk, int lba, void *buf)\r
+ * \fn Read a sector from disk\r
+*/\r
+int fdd_readSector(int disk, int lba, void *buf)\r
+{\r
+        int    cyl, head, sec;\r
+        int    spt, base;\r
+        int    i;\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(buf, 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
+       #endif\r
+       \r
+       base = cPORTBASE[disk>>1];\r
+       \r
+       LOG("Calculating Disk Dimensions");\r
+       //Get CHS position\r
+       if(get_dims(fdd_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(fdd_devices[disk].timer);\r
+       // Check if Motor is on\r
+       if(fdd_devices[disk].motorState == 0) {\r
+               start_motor(disk);\r
+       }\r
+       \r
+       LOG("Wait for Motor Spinup");\r
+       \r
+       // Wait for spinup\r
+       while(fdd_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(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
+       sendbyte(base, READ_SECTOR);    // Was 0xE6\r
+       sendbyte(base, (head << 2) | (disk&1));\r
+       sendbyte(base, (Uint8)cyl);\r
+       sendbyte(base, (Uint8)head);\r
+       sendbyte(base, (Uint8)sec);\r
+       sendbyte(base, 0x02);   // Bytes Per Sector (Real BPS=128*2^{val})\r
+       sendbyte(base, spt);    // SPT\r
+       sendbyte(base, 0x1B);   // Gap Length (27 is default)\r
+       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, buf);\r
+       \r
+       // Clear Input Buffer\r
+       LOG("Clearing Input Buffer");\r
+       getbyte(base); getbyte(base); getbyte(base);\r
+       getbyte(base); getbyte(base); getbyte(base); 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
+       fdd_devices[disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, stop_motor, (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, buf, 512);\r
+               FDD_FreeCacheSpinlock();\r
+       }\r
+       #endif\r
+
+       LEAVE('i', 1);\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn static int seekTrack(int disk, int track)\r
+ * \brief Seek disk to selected track\r
+ */\r
+static 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(fdd_devices[disk].track[head] == track)\r
+               return 1;\r
+       \r
+       // - Seek Head 0\r
+       sendbyte(base, SEEK_TRACK);\r
+       sendbyte(base, (head<<2)|(disk&1));\r
+       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
+       fdd_devices[disk].track[head] = track;\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn static int get_dims(int type, int lba, int *c, int *h, int *s, int *spt)\r
+ * \brief Get Dimensions of a disk\r
+ */\r
+static int get_dims(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
+               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 int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
+ * \brief Stub ioctl function\r
+ */\r
+int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
+{\r
+       switch(id)\r
+       {\r
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;\r
+       case DRV_IOCTL_IDENT:   memcpy(data, "FDD\0", 4);       return 1;\r
+       case DRV_IOCTL_VERSION: return (FDD_VER_MAJ<<8)|FDD_VER_MIN;\r
+       default:        return 0;\r
+       }\r
+}\r
+\r
+/**\r
+ * \fn void fdd_handler(void)\r
+ * \brief Handles IRQ6\r
+ */\r
+void fdd_handler(void)\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
+       sendbyte(base, CHECK_INTERRUPT_STATUS);\r
+       if(sr0) *sr0 = getbyte(base);\r
+       else    getbyte(base);\r
+       if(cyl) *cyl = getbyte(base);\r
+       else    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 sendbyte(int base, char byte)\r
+ * \brief Sends a command to the controller\r
+ */\r
+static void 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_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
+       #endif\r
+}\r
+\r
+/**\r
+ * int getbyte(int base, char byte)\r
+ * \brief Receive data from fdd controller\r
+ */\r
+static 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
+void FDD_Recalibrate(int disk)\r
+{\r
+       ENTER("idisk", disk);\r
+       \r
+       LOG("Starting Motor");\r
+       start_motor(disk);\r
+       // Wait for Spinup\r
+       while(fdd_devices[disk].motorState == 1)        Threads_Yield();\r
+       \r
+       LOG("Sending Calibrate Command");\r
+       sendbyte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);\r
+       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
+       stop_motor(disk);\r
+       LEAVE('-');\r
+}\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
+       sendbyte(base, FIX_DRIVE_DATA); // Step and Head Load Times\r
+       sendbyte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)\r
+       sendbyte(base, 0x02);   // Head Load Time >> 1\r
+       while(seekTrack(0, 0, 1) == 0); // set track\r
+       while(seekTrack(0, 1, 1) == 0); // set track\r
+       \r
+       LOG("Recalibrating Disk");\r
+       FDD_Recalibrate((id<<1)|0);\r
+       FDD_Recalibrate((id<<1)|1);
+\r
+       LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \fn void fdd_timer()\r
+ * \brief Called by timer\r
+ */\r
+static void fdd_timer(int arg)\r
+{\r
+       ENTER("iarg", arg);\r
+       if(fdd_devices[arg].motorState == 1)\r
+               fdd_devices[arg].motorState = 2;\r
+       Time_RemoveTimer(fdd_devices[arg].timer);\r
+       fdd_devices[arg].timer = -1;\r
+       LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \fn void start_motor(char disk)\r
+ * \brief Starts FDD Motor\r
+ */\r
+static void start_motor(int disk)\r
+{\r
+       Uint8   state;\r
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
+       state |= 1 << (4+disk);\r
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
+       fdd_devices[disk].motorState = 1;\r
+       fdd_devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, fdd_timer, (void*)disk);     //One Shot Timer\r
+}\r
+\r
+/**\r
+ * \fn void stop_motor(int disk)\r
+ * \brief Stops FDD Motor\r
+ */\r
+static void stop_motor(int disk)\r
+{\r
+       Uint8   state;\r
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
+       state &= ~( 1 << (4+disk) );\r
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
+    fdd_devices[disk].motorState = 0;\r
+}\r
+\r
+/**\r
+ * \fn int FDD_Install(char **Arguments)\r
+ * \brief Installs floppy driver\r
+ */\r
+int FDD_Install(char **Arguments)\r
+{\r
+       Uint8 data;\r
+       \r
+       // Determine Floppy Types (From CMOS)\r
+       outb(0x70, 0x10);\r
+       data = inb(0x71);\r
+       fdd_devices[0].type = data >> 4;\r
+       fdd_devices[1].type = data & 0xF;\r
+       fdd_devices[0].track[0] = -1;\r
+       fdd_devices[1].track[1] = -1;\r
+       \r
+       // Clear FDD IRQ Flag\r
+       FDD_SensInt(0x3F0, NULL, NULL);\r
+       // Install IRQ6 Handler\r
+       IRQ_AddHandler(6, fdd_handler);\r
+       // Reset Primary FDD Controller\r
+       FDD_Reset(0);\r
+       \r
+       Log("[FDD ] Detected Disk 0: %s and Disk 1: %s\n", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
+       \r
+       // Initialise Root Node\r
+       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime\r
+               = gFDD_DriverInfo.RootNode.ATime = now();\r
+       \r
+       // Initialise Child Nodes\r
+       fdd_devices[0].Name[0] = '0';   fdd_devices[0].Name[1] = '\0';\r
+       fdd_devices[0].Node.Inode = 0;\r
+       fdd_devices[0].Node.Flags = 0;\r
+       fdd_devices[0].Node.NumACLs = 0;\r
+       fdd_devices[0].Node.Read = FDD_ReadFS;\r
+       fdd_devices[0].Node.Write = NULL;//fdd_writeFS;\r
+       memcpy(&fdd_devices[1].Node, &fdd_devices[0].Node, sizeof(tVFS_Node));\r
+       fdd_devices[1].Name[0] = '1';\r
+       fdd_devices[1].Node.Inode = 1;\r
+       \r
+       // Set Lengths\r
+       fdd_devices[0].Node.Size = cFDD_SIZES[data >> 4];\r
+       fdd_devices[1].Node.Size = cFDD_SIZES[data & 0xF];\r
+       \r
+       // Create Sector Cache\r
+       #if USE_CACHE\r
+       //sFDD_SectorCache = malloc(sizeof(*sFDD_SectorCache)*CACHE_SIZE);\r
+       //siFDD_SectorCacheSize = CACHE_SIZE;\r
+       #endif\r
+       \r
+       // Register with devfs\r
+       DevFS_AddDevice(&gFDD_DriverInfo);\r
+       \r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn void ModuleUnload()\r
+ * \brief Prepare the module for removal\r
+ */\r
+void ModuleUnload()\r
+{\r
+       int i;\r
+       FDD_AquireSpinlock();\r
+       for(i=0;i<4;i++) {\r
+               Time_RemoveTimer(fdd_devices[i].timer);\r
+               stop_motor(i);\r
+       }\r
+       //IRQ_Clear(6);\r
+}\r

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