Code: Select all
#include<hal.h>
#include"floppy.h"
#include"dma.h"
#include"bitoper.h"
#include"conio.h"
int CurDrive = 0;
extern void puts(char*);
static volatile bool IRQFire = false;
extern void cerror(char*);
extern void cinfo(char*);
#include "visio.h"
void WaitIRQ()
{
int i=0;
while(!IRQFire)
{
i++;
if(i==3000){cerror("Waiting IRQ timed out.");return;}
sleep(1);
}
IRQFire = false;
}
__declspec(naked) void FloppyIrq()
{
_asm
{
pushad
}
IRQFire=true;
eoimsg(6);
_asm
{
popad
iretd
}
}
short irq = 6;
bool FloppyDMAinit(unsigned char* buffer)
{
union
{
unsigned char addressbyte[4];
unsigned char countbyte[4];
unsigned long val;
}address, count;
address.val=(unsigned)buffer;
count.val=(unsigned)disk->SectorSize-1;
if ((address.val>>24)||(count.val >> 16)||(((address.val&0xffff)+count.val)>>16))return false;
DmaReset();
MaskChannel(2);
DmaResetFlipFlop(1);
DmaSetAddress(2,address.addressbyte[0],address.addressbyte[1]);
DmaResetFlipFlop(1);
DmaSetCount(2,count.countbyte[0],count.countbyte[1]);
DmaSetRead(2);
outb(0x0e, 0xff);
return true;
}
void MotorControl(char no=0,bool sw=true)
{
if(no>3)
{
cerror("Can't control motor on unexistent floppy drive.");
return;
}
unsigned char motor;
switch (no)
{
case 0:
motor=MotorDriveZero;
break;
case 1:
motor=MotorDriveOne;
break;
case 2:
motor=MotorDriveTwo;
break;
case 3:
motor=MotorDriveThree;
break;
}
if(sw&&!Convert(disk->Motors,no))
{
outb(DigitalOutReg, motor|EnableIRQDMA|Reset);
ChangeBit(&disk->Motors,no,true);
}
else if(!sw&&Convert(disk->Motors,no))
{
outb(DigitalOutReg, Reset);
ChangeBit(&disk->Motors,no,false);
}
if(disk->PhysicalSize==Small)sleep(200);
else if(disk->PhysicalSize==Big)sleep(300);
else cerror("Physical floppy size not defined.");
}
void SendCommandByte(unsigned char cmd)
{
for (int i = 0; i < 500; i++)
if (inb(MainStatusReg) & 0x80)
return outb(FifoReg, cmd);
}
unsigned char ReadDataByte()
{
for (int i = 0; i < 500; i++)
if (inb(MainStatusReg) & 0x80)
return inb(FifoReg);
return 0;
}
void CheckInt(unsigned int* st0, unsigned int* cyl)
{
SendCommandByte(SenseInterrupt);
*st0 = ReadDataByte();
*cyl = ReadDataByte();
}
int recalibrate()
{
unsigned int st0, cyl;
if (CurDrive >= 4)
return -2;
for (int i = 0; i < 10; i++)
{
SendCommandByte(ReCalibrate);
SendCommandByte(CurDrive);
WaitIRQ ();
CheckInt(&st0,&cyl);
if (!cyl)
{
return 0;
}
}
cerror("Failed to recalibrate.");
return -1;
}
int FloppySeek(unsigned char cyl, unsigned char head)
{
unsigned int st0, cyl0;
if (CurDrive >= 4)
return -1;
for (int i = 0; i < 10; i++ )
{
SendCommandByte(Seek);
SendCommandByte(head<<2|CurDrive);
SendCommandByte(cyl);
WaitIRQ();
CheckInt(&st0,&cyl0);
if(cyl0==cyl)
return 0;
}
cerror("Failed to seek floppy.");
return -1;
}
extern void cinfo(char*);
void reset()
{
unsigned int st0, cyl;
outb(ControlReg, 0);
outb(DigitalOutReg, 0);
outb(DigitalOutReg, EnableIRQDMA|Reset);
WaitIRQ();
for (int i=0; i<4; i++)CheckInt(&st0,&cyl);
outb (ControlReg, Normal);
recalibrate();
}
#include "visio.h"
void FloppyInit()
{
disk=new Floppy;
disk->Motors=0;
disk->DataSize=NormalS;
disk->PhysicalSize=Small;
disk->SectorSize=512;
disk->SPT=18;
stvect(38, FloppyIrq);
MotorControl(CurDrive);
reset();
}
void SelectDrive(char no)
{
switch (no)
{
case 0:
outb(DigitalOutReg, DriveZero);break;
case 1:
outb(DigitalOutReg, 0);break;
case 2:
outb(DigitalOutReg, 0);break;
case 3:
outb(DigitalOutReg, 0);break;
}
}
void* ReadSector(int lba)
{
int Head=0, Track=0, Sector=1;
Head=(lba%(disk->SPT*2))/disk->SPT;
Track=lba/(disk->SPT*2);
Sector=lba%disk->SPT+1;
cinfo("About to select drive...");
SelectDrive(CurDrive);
cinfo("Recalibarate...");
recalibrate();
cinfo("Seeking...");
if(FloppySeek(Track,Head))return 0;
cinfo("Initializing DMA...");
FloppyDMAinit((unsigned char*)131072);
cinfo("Read to channel 2.");
DmaSetRead(2);
SendCommandByte(Read|MT|SK|MF);
SendCommandByte((Head<<2)|CurDrive);
SendCommandByte(Track);
SendCommandByte(Head);
SendCommandByte(Sector);
SendCommandByte(2);
SendCommandByte(Sector+1);
SendCommandByte(0x27);
SendCommandByte(0xff);
WaitIRQ();
for (int i = 0; i<7; i++)
ReadDataByte();
cinfo("Finished.");
return (void*)131072;
}
void* getInfo()
{
return disk;
}