-/*\r
- * AcessOS 0.1\r
- * Floppy Disk Access Code\r
- */\r
-#define DEBUG 0\r
-#include <acess.h>\r
-#include <modules.h>\r
-#include <fs_devfs.h>\r
-#include <tpl_drv_disk.h>\r
-#include <dma.h>\r
-#include <iocache.h>\r
-\r
-#define WARN 0\r
-\r
-// === CONSTANTS ===\r
-// --- Current Version\r
-#define FDD_VERSION ((0<<8)|(75))\r
-\r
-// --- Options\r
-#define USE_CACHE 0 // 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
-/**\r
- * \brief Representation of a floppy drive\r
- */\r
-typedef struct {\r
- int type;\r
- volatile int motorState; //2 - On, 1 - Spinup, 0 - Off\r
- int track[2];\r
- int timer;\r
- tVFS_Node Node;\r
- #if !USE_CACHE\r
- tIOCache *CacheHandle;\r
- #endif\r
-} t_floppyDevice;\r
-\r
-/**\r
- * \brief Cached Sector\r
- */\r
-typedef struct {\r
- Uint64 timestamp;\r
- Uint16 disk;\r
- Uint16 sector; // Allows 32Mb of addressable space (Plenty for FDD)\r
- Uint8 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
-// --- Filesystem\r
- int FDD_Install(char **Arguments);\r
-char *FDD_ReadDir(tVFS_Node *Node, int pos);\r
-tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, char *Name);\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
-// --- 1st Level Disk Access\r
-Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk);\r
-// --- Raw Disk Access\r
- int FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);\r
- int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);\r
-// --- Helpers\r
-void FDD_IRQHandler(int Num);\r
-void FDD_WaitIRQ();\r
-void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);\r
-inline void FDD_AquireSpinlock();\r
-inline void FDD_FreeSpinlock();\r
-#if USE_CACHE\r
-inline void FDD_AquireCacheSpinlock();\r
-inline void FDD_FreeCacheSpinlock();\r
-#endif\r
-void FDD_int_SendByte(int base, char byte);\r
- int FDD_int_GetByte(int base);\r
-void FDD_Reset(int id);\r
-void FDD_Recalibrate(int disk);\r
- int FDD_int_SeekTrack(int disk, int head, int track);\r
-void FDD_int_TimerCallback(int arg);\r
-void FDD_int_StopMotor(int disk);\r
-void FDD_int_StartMotor(int disk);\r
- int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, NULL);\r
-t_floppyDevice gFDD_Devices[2];\r
-volatile int fdd_inUse = 0;\r
-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
-int siFDD_CacheInUse = 0;\r
-int siFDD_SectorCacheSize = CACHE_SIZE;\r
-t_floppySector sFDD_SectorCache[CACHE_SIZE];\r
-#endif\r
-\r
-// === CODE ===\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
- gFDD_Devices[0].type = data >> 4;\r
- gFDD_Devices[1].type = data & 0xF;\r
- gFDD_Devices[0].track[0] = -1;\r
- gFDD_Devices[1].track[1] = -1;\r
- \r
- Log("[FDD ] Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
- \r
- // Clear FDD IRQ Flag\r
- FDD_SensInt(0x3F0, NULL, NULL);\r
- // Install IRQ6 Handler\r
- IRQ_AddHandler(6, FDD_IRQHandler);\r
- // Reset Primary FDD Controller\r
- FDD_Reset(0);\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
- gFDD_Devices[0].Node.Inode = 0;\r
- gFDD_Devices[0].Node.Flags = 0;\r
- gFDD_Devices[0].Node.NumACLs = 0;\r
- gFDD_Devices[0].Node.Read = FDD_ReadFS;\r
- gFDD_Devices[0].Node.Write = NULL;//fdd_writeFS;\r
- memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));\r
- \r
- gFDD_Devices[1].Node.Inode = 1;\r
- \r
- // Set Lengths\r
- gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];\r
- gFDD_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
- #else\r
- if( cFDD_SIZES[data >> 4] ) {\r
- gFDD_Devices[0].CacheHandle = IOCache_Create(\r
- FDD_WriteSector, 0, 512,\r
- gFDD_Devices[0].Node.Size / (512*4)\r
- ); // Cache is 1/4 the size of the disk\r
- }\r
- if( cFDD_SIZES[data & 15] ) {\r
- gFDD_Devices[1].CacheHandle = IOCache_Create(\r
- FDD_WriteSector, 0, 512,\r
- gFDD_Devices[1].Node.Size / (512*4)\r
- ); // Cache is 1/4 the size of the disk\r
- }\r
- #endif\r
- \r
- // Register with devfs\r
- DevFS_AddDevice(&gFDD_DriverInfo);\r
- \r
- return 1;\r
-}\r
-\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
- char name[2] = "0\0";\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(gFDD_Devices[pos].type == 0)\r
- return VFS_SKIP;\r
- \r
- name[0] += pos;\r
- \r
- //Return\r
- return strdup(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
- // Sanity check string\r
- if(Filename == NULL) {\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- // Check string length (should be 1)\r
- if(Filename[0] == '\0' || Filename[1] != '\0') {\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- // Get First character\r
- i = Filename[0] - '0';\r
- \r
- // Check for 1st disk and if it is present return\r
- if(i == 0 && gFDD_Devices[0].type != 0) {\r
- LEAVE('p', &gFDD_Devices[0].Node);\r
- return &gFDD_Devices[0].Node;\r
- }\r
- \r
- // Check for 2nd disk and if it is present return\r
- if(i == 1 && gFDD_Devices[1].type != 0) {\r
- LEAVE('p', &gFDD_Devices[1].Node);\r
- return &gFDD_Devices[1].Node;\r
- }\r
- \r
- // Else return null\r
- LEAVE('n');\r
- return NULL;\r
-}\r
-\r
-static const char *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};\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: return ModUtil_SetIdent(Data, "FDD");\r
- case DRV_IOCTL_VERSION: return FDD_VERSION;\r
- case DRV_IOCTL_LOOKUP: return ModUtil_LookupString((char**)casIOCTLS, Data);\r
- \r
- case DISK_IOCTL_GETBLOCKSIZE: return 512; \r
- \r
- default:\r
- return 0;\r
- }\r
-}\r
-\r
-/**\r
- * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
- * \brief Read Data from a disk\r
-*/\r
-Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
-{\r
- int i = 0;\r
- int disk;\r
- //Uint32 buf[128];\r
- \r
- ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, 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 0\r
- if((Offset & 0x1FF) || (Length & 0x1FF))\r
- {\r
- // Un-Aligned Offset/Length\r
- int startOff = Offset >> 9;\r
- int sectOff = Offset & 0x1FF;\r
- int sectors = (Length + 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), Length > 512-sectOff ? 512-sectOff : Length);\r
- \r
- // If the data size is one sector or less\r
- if(Length <= 512-sectOff)\r
- {\r
- LEAVE('X', Length);\r
- return Length; //Return\r
- }\r
- Buffer += 512-sectOff;\r
- \r
- //Read Middle Sectors\r
- for( i = 1; i < sectors - 1; i++ )\r
- {\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', Length);\r
- return Length;\r
- }\r
- else\r
- {\r
- int count = Length >> 9;\r
- int sector = Offset >> 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', 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
- * \fn Read a sector from disk\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
- FDD_Recalibrate((id<<1)|1);
-\r
- LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_TimerCallback()\r
- * \brief Called by timer\r
- */\r
-void FDD_int_TimerCallback(int arg)\r
-{\r
- ENTER("iarg", arg);\r
- if(gFDD_Devices[arg].motorState == 1)\r
- gFDD_Devices[arg].motorState = 2;\r
- Time_RemoveTimer(gFDD_Devices[arg].timer);\r
- gFDD_Devices[arg].timer = -1;\r
- LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_StartMotor(char disk)\r
- * \brief Starts FDD Motor\r
- */\r
-void FDD_int_StartMotor(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
- gFDD_Devices[disk].motorState = 1;\r
- gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)disk);\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_StopMotor(int disk)\r
- * \brief Stops FDD Motor\r
- */\r
-void FDD_int_StopMotor(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
- gFDD_Devices[disk].motorState = 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(gFDD_Devices[i].timer);\r
- FDD_int_StopMotor(i);\r
- }\r
- //IRQ_Clear(6);\r
-}\r