#include <acess.h>
#include <modules.h>
#include <fs_devfs.h>
-#include <tpl_drv_disk.h>
+#include <api_drv_disk.h>
#include <dma.h>
#include <iocache.h>
PORT_CONFIGCTRL = 0x7
};
+#define CMD_FLAG_MULTI_TRACK 0x80 //!< Multitrack
+#define CMD_FLAG_MFM_ENCODING 0x40 //!< MFM Encoding Mode (Always set for read/write/format/verify)
+#define CMD_FLAG_SKIP_MODE 0x20 //!< Skip Mode (don't use)
enum FloppyCommands {
- FIX_DRIVE_DATA = 0x03,
- HECK_DRIVE_STATUS = 0x04,
- CALIBRATE_DRIVE = 0x07,
- CHECK_INTERRUPT_STATUS = 0x08,
- SEEK_TRACK = 0x0F,
- READ_SECTOR_ID = 0x4A,
- FORMAT_TRACK = 0x4D,
- READ_TRACK = 0x42,
- READ_SECTOR = 0x66,
- WRITE_SECTOR = 0xC5,
- WRITE_DELETE_SECTOR = 0xC9,
- READ_DELETE_SECTOR = 0xCC,
+ CMD_READ_TRACK = 0x02,
+ CMD_SPECIFY = 0x03,
+ CMD_SENSE_STATUS = 0x04,
+ CMD_WRITE_DATA = 0x05,
+ CMD_READ_DATA = 0x06,
+ CMD_RECALIBRATE = 0x07,
+ CMD_SENSE_INTERRUPT = 0x08,
+ CMD_WRITE_DEL_DATA = 0x09,
+ CMD_READ_SECTOR_ID = 0x0A,
+ // 0x0B - ?
+ CMD_READ_DEL_DATA = 0x0C,
+ CMD_FORMAT_TRACK = 0x0D,
+ // 0x0E - ?
+ CMD_SEEK_TRACK = 0x0F,
+ CMD_VERSION = 0x10,
+
+ CMD_LOCK = 0x14, //!< Save controller parameters
+
+ CMD_CONFIGURE = 0x13
};
// === PROTOTYPES ===
void FDD_UnloadModule();
// --- VFS Methods
char *FDD_ReadDir(tVFS_Node *Node, int pos);
-tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, char *Name);
+tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
// --- Functions for IOCache/DrvUtil
int FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);
int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);
// --- Helpers
-void FDD_IRQHandler(int Num);
+void FDD_IRQHandler(int Num, void *Ptr);
inline void FDD_WaitIRQ();
void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);
-void FDD_int_SendByte(int base, char byte);
- int FDD_int_GetByte(int base);
-void FDD_Reset(int id);
+ int FDD_int_SendByte(int base, Uint8 Byte);
+ int FDD_int_GetByte(int base, Uint8 *Byte);
+ int FDD_Reset(int id);
void FDD_Recalibrate(int disk);
+ int FDD_Reconfigure(int ID);
int FDD_int_SeekTrack(int disk, int head, int track);
void FDD_int_TimerCallback(void *Arg);
void FDD_int_StopMotor(void *Arg);
int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);
// === GLOBALS ===
-MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL);
+MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "x86_ISADMA", NULL);
t_floppyDevice gFDD_Devices[2];
-tSpinlock glFDD;
+tMutex glFDD;
volatile int gbFDD_IrqFired = 0;
tDevFS_Driver gFDD_DriverInfo = {
NULL, "fdd",
int FDD_Install(char **Arguments)
{
Uint8 data;
+ char **args = Arguments;
// Determine Floppy Types (From CMOS)
outb(0x70, 0x10);
gFDD_Devices[0].track[0] = -1;
gFDD_Devices[1].track[1] = -1;
+ if(args) {
+ for(;*args;args++)
+ {
+ if(strcmp(*args, "disable")==0)
+ return MODULE_ERR_NOTNEEDED;
+ }
+ }
+
Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);
if( data == 0 ) {
return MODULE_ERR_NOTNEEDED;
}
- // Clear FDD IRQ Flag
- FDD_SensInt(0x3F0, NULL, NULL);
// Install IRQ6 Handler
- IRQ_AddHandler(6, FDD_IRQHandler);
+ IRQ_AddHandler(6, FDD_IRQHandler, NULL);
+
+ // Ensure the FDD version is 0x90
+ {
+ Uint8 tmp = 0;
+ FDD_int_SendByte(cPORTBASE[0], CMD_VERSION);
+ FDD_int_GetByte(cPORTBASE[0], &tmp);
+ if( tmp != 0x90 ) {
+ Log_Error("FDD", "Version(0x%2x) != 0x90", tmp);
+ return MODULE_ERR_NOTNEEDED;
+ }
+ }
+
+ // Configure
+ FDD_Reconfigure(0);
+
// Reset Primary FDD Controller
- FDD_Reset(0);
+ if( FDD_Reset(0) != 0 ) {
+ return MODULE_ERR_MISC;
+ }
// Initialise Root Node
gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
void FDD_UnloadModule()
{
int i;
- //DevFS_DelDevice( &gFDD_DriverInfo );
- LOCK(&glFDD);
+ DevFS_DelDevice( &gFDD_DriverInfo );
+ Mutex_Acquire(&glFDD);
for(i=0;i<4;i++) {
Time_RemoveTimer(gFDD_Devices[i].timer);
- FDD_int_StopMotor((void*)i);
+ FDD_int_StopMotor((void *)(Uint)i);
}
- RELEASE(&glFDD);
+ Mutex_Release(&glFDD);
//IRQ_Clear(6);
}
* \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)
* \brief Read Directory
*/
-char *FDD_ReadDir(tVFS_Node *Node, int Pos)
+char *FDD_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
{
char name[2] = "0\0";
}
/**
- * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename);
+ * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *filename);
* \brief Find File Routine (for vfs_node)
*/
-tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *Filename)
+tVFS_Node *FDD_FindDir(tVFS_Node *UNUSED(Node), const char *Filename)
{
int i;
* \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data)
* \brief Stub ioctl function
*/
-int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)
+int FDD_IOCtl(tVFS_Node *UNUSED(Node), int ID, void *Data)
{
switch(ID)
{
- case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
- case DRV_IOCTL_IDENT: return ModUtil_SetIdent(Data, "FDD");
- case DRV_IOCTL_VERSION: return FDD_VERSION;
- case DRV_IOCTL_LOOKUP: return ModUtil_LookupString((char**)casIOCTLS, Data);
+ BASE_IOCTLS(DRV_TYPE_DISK, "FDD", FDD_VERSION, casIOCTLS);
case DISK_IOCTL_GETBLOCKSIZE: return 512;
int spt, base;
int i;
int lba = SectorAddr;
- Uint8 st0, st1, st2, rcy, rhe, rse, bps; // Status Values
+ Uint8 st0=0, st1=0, st2=0, bps=0; // Status Values
ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
}
LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec);
- LOCK(&glFDD); // Lock to stop the motor stopping on us
+ Mutex_Acquire(&glFDD); // Lock to stop the motor stopping on us
Time_RemoveTimer(gFDD_Devices[Disk].timer); // Remove Old Timer
// Start motor if needed
if(gFDD_Devices[Disk].motorState != 2) FDD_int_StartMotor(Disk);
- RELEASE(&glFDD);
+ Mutex_Release(&glFDD);
LOG("Wait for the motor to spin up");
while(gFDD_Devices[Disk].motorState == 1) Threads_Yield();
LOG("Acquire Spinlock");
- LOCK(&glFDD);
+ Mutex_Acquire(&glFDD);
+ #if 0
// Seek to track
outb(base + CALIBRATE_DRIVE, 0);
i = 0;
while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )
Threads_Yield();
if( i > FDD_SEEK_TIMEOUT ) {
- RELEASE(&glFDD);
+ Mutex_Release(&glFDD);
LEAVE('i', 0);
return 0;
}
//FDD_SensInt(base, NULL, NULL); // Wait for IRQ
+ #endif
// Read Data from DMA
LOG("Setting DMA for read");
- DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2
+ DMA_SetChannel(2, 512, !Write); // Read/Write 512 Bytes from channel 2
LOG("Sending command");
- //Threads_Wait(100); // Wait for Head to settle
- Time_Delay(100);
-
for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
{
if( Write )
- FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6
+ FDD_int_SendByte(base, CMD_WRITE_DATA|CMD_FLAG_MFM_ENCODING);
else
- FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6
+ FDD_int_SendByte(base, CMD_READ_DATA|CMD_FLAG_MFM_ENCODING);
FDD_int_SendByte(base, (head << 2) | (Disk&1));
FDD_int_SendByte(base, (Uint8)cyl);
FDD_int_SendByte(base, (Uint8)head);
// Clear Input Buffer
LOG("Clearing Input Buffer");
// Status Values
- st0 = FDD_int_GetByte(base);
- st1 = FDD_int_GetByte(base);
- st2 = FDD_int_GetByte(base);
+ FDD_int_GetByte(base, &st0);
+ FDD_int_GetByte(base, &st1);
+ FDD_int_GetByte(base, &st2);
- // Cylinder, Head and Sector (mutilated in some way
- rcy = FDD_int_GetByte(base);
- rhe = FDD_int_GetByte(base);
- rse = FDD_int_GetByte(base);
+ // 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)
- bps = FDD_int_GetByte(base);
+ 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; }
+ }
+ // - 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; }
LOG("No Address mark found");
continue;
}
- if(st2 & 0x40) { LOG("Deleted address mark"); 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(st1 & 0x02) {
LOG("Floppy not writable");
+ // Return error without triggering the attempt count check
i = FDD_MAX_READWRITE_ATTEMPTS+1;
break;
}
// Release Spinlock
LOG("Realeasing Spinlock and setting motor to stop");
- RELEASE(&glFDD);
+ Mutex_Release(&glFDD);
if(i == FDD_MAX_READWRITE_ATTEMPTS) {
Log_Warning("FDD", "Exceeded %i attempts in %s the disk",
// Don't turn the motor off now, wait for a while
gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)(tVAddr)Disk);
+ // Error check
if( i < FDD_MAX_READWRITE_ATTEMPTS ) {
LEAVE('i', 0);
return 0;
*/
int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
{
- Warning("[FDD ] Read Only at the moment");
+ Log_Warning("FDD", "Read Only at the moment");
return -1;
}
*/
int FDD_int_SeekTrack(int disk, int head, int track)
{
- Uint8 sr0, cyl;
+ Uint8 sr0=0, cyl=0;
int base;
base = cPORTBASE[disk>>1];
return 1;
// - Seek Head 0
- FDD_int_SendByte(base, SEEK_TRACK);
+ FDD_int_SendByte(base, CMD_SEEK_TRACK);
FDD_int_SendByte(base, (head<<2)|(disk&1));
FDD_int_SendByte(base, track); // Send Seek command
FDD_WaitIRQ();
// 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 void FDD_IRQHandler(int Num)
* \brief Handles IRQ6
*/
-void FDD_IRQHandler(int Num)
+void FDD_IRQHandler(int Num, void *Ptr)
{
gbFDD_IrqFired = 1;
}
void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)
{
- FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS);
- if(sr0) *sr0 = FDD_int_GetByte(base);
- else FDD_int_GetByte(base);
- if(cyl) *cyl = FDD_int_GetByte(base);
- else FDD_int_GetByte(base);
+ 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
*/
-void FDD_int_SendByte(int base, char byte)
+int FDD_int_SendByte(int base, Uint8 byte)
{
- volatile int state;
- int timeout = 128;
- for( ; timeout--; )
- {
- state = inb(base + PORT_MAINSTATUS);
- if ((state & 0xC0) == 0x80)
- {
- outb(base + PORT_DATA, byte);
- return;
- }
- inb(0x80); //Delay
+ tTime end = now() + 1000; // 1s
+
+ while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
+ Threads_Yield(); //Delay
+
+ if( inb(base + PORT_MAINSTATUS) & 0x40 ) {
+ Log_Warning("FDD", "FDD_int_SendByte: DIO set, is this ok?");
}
- #if WARN
- Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);
- #endif
+ if( now() < end )
+ {
+ outb(base + PORT_DATA, byte);
+// Log_Debug("FDD", "FDD_int_SendByte: Sent 0x%02x to 0x%x", byte, base);
+ return 0;
+ }
+ else
+ {
+ Log_Warning("FDD", "FDD_int_SendByte: Timeout sending byte 0x%x to base 0x%x", byte, base);
+ return 1;
+ }
}
/**
* int FDD_int_GetByte(int base, char byte)
* \brief Receive data from fdd controller
*/
-int FDD_int_GetByte(int base)
+int FDD_int_GetByte(int base, Uint8 *value)
{
- volatile int state;
- int timeout;
- for( timeout = 128; timeout--; )
+ tTime end = now() + 1000; // 1s
+
+ while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
+ Threads_Yield();
+
+ if( !(inb(base + PORT_MAINSTATUS) & 0x40) ) {
+ Log_Warning("FDD", "FDD_int_GetByte: DIO unset, is this ok?");
+ }
+
+ if( now() < end )
{
- state = inb((base + PORT_MAINSTATUS));
- if ((state & 0xd0) == 0xd0)
- return inb(base + PORT_DATA);
- inb(0x80);
+ Uint8 tmp = inb(base + PORT_DATA);
+ if(value) *value = tmp;
+// Log_Debug("FDD", "FDD_int_GetByte: Read 0x%02x from 0x%x", *value, base);
+ return 0;
+ }
+ else
+ {
+ Log_Warning("FDD", "FDD_int_GetByte: Timeout reading byte from base 0x%x", base);
+ return -1;
}
- return -1;
}
/**
while(gFDD_Devices[disk].motorState == 1) Threads_Yield();
LOG("Sending Calibrate Command");
- FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);
+ FDD_int_SendByte(cPORTBASE[disk>>1], CMD_RECALIBRATE);
FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);
LOG("Waiting for IRQ");
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
*/
-void FDD_Reset(int id)
+int FDD_Reset(int id)
{
- int base = cPORTBASE[id];
+ Uint16 base = cPORTBASE[id];
+ int retries;
ENTER("iID", id);
+
+ // Reset the card
+ outb(base + PORT_DIGOUTPUT, 0); // Disable FDC
+ // Wait 4 microseconds - or use 1 thread delay
+ Threads_Yield();
+ Threads_Yield();
+ outb(base + PORT_DIGOUTPUT, 8|4); // Re-enable FDC (DMA and Enable)
- outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC
- outb(base + PORT_DIGOUTPUT, 0x0C); // 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();
+ LOG("4x SenseInterrupt");
+ FDD_SensInt(base, NULL, NULL);
+ FDD_SensInt(base, NULL, NULL);
+ FDD_SensInt(base, NULL, NULL);
FDD_SensInt(base, NULL, NULL);
- LOG("Setting Driver Info");
- outb(base + PORT_DATARATE, 0); // Set data rate to 500K/s
- FDD_int_SendByte(base, FIX_DRIVE_DATA); // Step and Head Load Times
+ // 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
- while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track
- while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track
+
+ // Recalibrate disks
+ LOG("Recalibrate disks (16x seek)");
+ retries = 16;
+ while(FDD_int_SeekTrack(0, 0, 1) == 0 && retries --); // set track
+ if(retries < 0) LEAVE_RET('i', -1);
+
+ retries = 16;
+ while(FDD_int_SeekTrack(0, 1, 1) == 0 && retries --); // set track
+ if(retries < 0) LEAVE_RET('i', -1);
LOG("Recalibrating Disk");
FDD_Recalibrate((id<<1)|0);
FDD_Recalibrate((id<<1)|1);
- LEAVE('-');
+ LEAVE_RET('i', 0);
}
/**
*/
void FDD_int_TimerCallback(void *Arg)
{
- int disk = (int)Arg;
+ int disk = (Uint)Arg;
ENTER("iarg", disk);
if(gFDD_Devices[disk].motorState == 1)
gFDD_Devices[disk].motorState = 2;
*/
void FDD_int_StopMotor(void *Arg)
{
- Uint8 state, disk = (int)Arg;
- if( IS_LOCKED(&glFDD) ) return ;
+ Uint8 state, disk = (Uint)Arg;
+ if( Mutex_IsLocked(&glFDD) ) return ;
ENTER("iDisk", disk);
state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
gFDD_Devices[disk].motorState = 0;
LEAVE('-');
}
+