Hallo zusammen,
ich habe ein Problem mit dem FDC. Wenn ich Daten von der Floppy einlesen will, bekomme ich
floppy.h
floppy.c
ich habe ein Problem mit dem FDC. Wenn ich Daten von der Floppy einlesen will, bekomme ich
- von QEMU folgende Meldung:
Code: [Auswählen]
FLOPPY ERROR: fdctrl_start_transfer: dma_mode=0 direction=1- immer "S" zurück
Code: [Auswählen]
echo "TEST" | dd of=floppy.img erstellt habe. Die Lesefunktion stammt von http://forum.osdev.org/viewtopic.php?t=17274.floppy.h
Code: [Auswählen]
/*
+----------------------------------------------------------------------------------------+
| |
| LionOS File |
| |
+----------------------------------------------------------------------------------------+
| |
| Floppy |
| |
+----------------------------------------------------------------------------------------+
*/
#ifndef FLOPPY_H
#define FLOPPY_H
#define NUM_OF_FDD 1
#define NO_ERROR 0
#define ERROR_TIMEOUT 1
#define MSR 0x3F4
#define MSR_MASK_DATAREG 0x80
#define MSR_MASK_DIO2CPU 0x40
#define CMD 0x3F5
#define MCMD 0x3F2
#define RDSR 0x3F4 //reg dsr
#define RDOR 0x3F2 //Reg dor
#define FLOPPY_MSR_DIO 0x40
#define DSR_SPEED_1MBPS 0x03
#define DSR_SPEED_500KBPS 0x00
#define DSR_SPEED_300KBPS 0x01
#define DSR_SPEED_250KBPS 0x02
#define CMD_WRITE_SECTOR (0x05 | 0x40)
#define CMD_READ_SECTOR (0x06 | 0x40)
#define CMD_SEEK 0x0F
#define FLOPPY_CMD_INT_SENSE 0x08
uint8_t fddDevice;
uint8_t error = NO_ERROR;
void send_cmd(uint8_t cmd);
void send_data(uint8_t data);
uint8_t read_data();
void initFDD();
void fdHandler(cpu_state *r);
void fddwaitForIRQ();
void resetFDD();
void fddMotor(int state);
void fddChooseDevice(uint8_t id);
int floppy_seek(uint8_t cylinder);
typedef struct fdd
{
int motor;
long la; //lastaccess
int irqRes;
int cylinder;
int head;
int sector;
int size;
uint8_t status;
} fdd;
fdd fd[NUM_OF_FDD];
void floppy_int_sense();
int transfer_sector(uint32_t lba, int write, void* buffer);
int fdc_read(unsigned char *data, unsigned int sector, unsigned int offset, unsigned int length);
#define CHANNEL_ADRESS 0x04
#define CHANNEL_COUNTER 0x05
#define CHANNEL_PAGE 0x81
#include "floppy.c"
#endiffloppy.c
Code: [Auswählen]
/*
+----------------------------------------------------------------------------------------+
| |
| LionOS File |
| |
+----------------------------------------------------------------------------------------+
| |
| Floppy |
| |
+----------------------------------------------------------------------------------------+
*/
#define CMD_WRITE_SECTOR (0x05 | 0x40)
#define CMD_READ_SECTOR (0x06 | 0x40)
uint8_t read_data()
{
uint8_t timeout;
for(timeout = 0; timeout < 200; timeout++)
{
if( (inb(MSR) & (MSR_MASK_DATAREG | MSR_MASK_DIO2CPU)) == (MSR_MASK_DATAREG | MSR_MASK_DIO2CPU))
{
error = NO_ERROR;
return inb(0x3F5);
}
sleepTicks(5);
}
error = ERROR_TIMEOUT;
return 0;
}
void send_cmd(uint8_t cmd)
{
send_data(cmd);
}
void send_data(uint8_t cmd)
{
fd[fddDevice].la = getTime();
uint8_t timeout;
for (timeout = 0; timeout < 200; timeout++)
{
if ( (inb(MSR) & (MSR_MASK_DATAREG | MSR_MASK_DIO2CPU)) == MSR_MASK_DATAREG)
{
outb(CMD, cmd);
error = NO_ERROR;
return;
}
sleepTicks(1); //5ms warten vor dem nächsten Versuch
}
error = ERROR_TIMEOUT;
return;
}
/**
* Positioniert den Lesekopf ueber einen Bestimmten Zylinder.
*
* @param cylinder Zylindernummer
* @return true wenn das Positionieren gelungen ist, sonst false
*/
int floppy_seek(uint8_t cylinder)
{
DEBUG_MSG("Kopf neu positionieren");
if(fd[fddDevice].cylinder == cylinder)
{
DEBUG_MSG(" Steht bereits richtig");
return true;
}
//floppy_set_motor(true);
//floppy_clr_irqcnt();
send_cmd(CMD_SEEK);
send_cmd(fddDevice);
send_cmd(cylinder);
/*if(floppy_wait_irq(1) == false)
{
return false;
}*/
floppy_int_sense();
sleepTicks(1);
while (inb(MSR) & 0x0F) {
DEBUG_MSG("Laufwerk ist noch beschaeftigt");
sleepTicks(1);
}
if (fd[fddDevice].cylinder != cylinder) {
DEBUG_MSG("Warnung: Floppy steht nach SEEK(%d) auf %d",
cylinder, fd[fddDevice].cylinder);
}
if(fd[fddDevice].status != 0x20)
{
DEBUG_MSG(" false");
return false;
}
else
{
DEBUG_MSG(" true");
return true;
}
return true;
}
void fdHandler(cpu_state *r)
{
DEBUG_MSG("FDD Int!");
fd[fddDevice].irqRes++;
}
void resetFDD()
{
outb(MCMD, 0);
fddMotor(false);
}
void fddChooseDevice(uint8_t id)
{
fddDevice = id;
uint8_t tmp = inb(MCMD);
outb(MCMD, (tmp & (~0x03)) | fddDevice);
}
void fddMotor(int state)
{
fd[fddDevice].motor = state;
fd[fddDevice].la = getTime();
uint8_t status = inb(MCMD);
//DEBUG_MSG("FDD: State: %d", status);
if (state==true)
{
outb(MCMD, (status & 0x0F) | (0x10 << fddDevice));
}
else
{
//DEBUG_MSG("FDD: Change state from %d to %d", status, status & ~(0x10 << id));
outb(MCMD, status & ~(0x10 << fddDevice));
}
sleepTicks(5);
//Hier muss eine Sleep funktion rein!!!!
//sleepTicks(10);
}
void fddwaitForIRQ()
{
int i = fd[fddDevice].irqRes;
DEBUG_MSG("Wait for IRQ6: Arrived IRQ: %d", i);
while(1)
{
asm("nop");
if (i == fd[fddDevice].irqRes-1)
{
return;
}
}
}
/**
* Kalibriert das Laufwerk
*
* @return true wenn das Neukalibrieren gelungen ist, sonst false
*/
int FDDrecalibrate(void)
{
DEBUG_MSG("Kalibriere Laufwerk neu");
fd[fddDevice].cylinder = 255;
fddMotor(true);
int i = 0;
while ((i < 5) && (fd[fddDevice].cylinder != 0))
{
//floppy_clr_irqcnt();
send_cmd(0x07);
send_cmd(fddDevice);
//floppy_wait_irq(1);
//fddwaitForIRQ();
//FIXME Wait for IRQ Here!!!!
//loppy_int_sense();
++i;
}
return (i < 5);
}
/**
* Mir ist nicht bekannt, was diese Funktion genau macht. Sie schein aber
* notwendig zu sein.
*/
void floppy_int_sense()
{
send_cmd(FLOPPY_CMD_INT_SENSE);
fd[fddDevice].status = read_data();
fd[fddDevice].cylinder = read_data();
}
void initFDD()
{
// asm("sti");
//int i;
fddChooseDevice(0);
uint8_t fdd = cmos_read(0x10);
uint8_t fd1 = fdd & 0xF;
uint8_t fd0 = (fdd & 0xF0) >> 4;
DEBUG_MSG("CMOS Floppy == %d\nfd0 == %d, fd1 == %d", fdd, fd0, fd1);
if (!(fd0 | fd1))
{ return; }
if(fd0==0)
{
DEBUG_MSG("No floppy 0!");
//return;
}
else
{
fddChooseDevice(0);
if(fd0==1)
{
DEBUG_MSG("Floppy 0 found... Size = 360 kB");
}
else if(fd0==2)
{
DEBUG_MSG("Floppy 0 found... Size = 1.2 MB");
}
else if(fd0==3)
{
DEBUG_MSG("Floppy 0 found... Size = 720 kB");
}
else if(fd0==4)
{
DEBUG_MSG("Floppy 0 found... Size = 1.44 MB");
}
}
if(fd1==0)
{
DEBUG_MSG("No floppy 1!");
//return;
}
else if(fd1==1)
{
DEBUG_MSG("Floppy 1 found... Size = 360 kB");
}
else if(fd1==2)
{
DEBUG_MSG("Floppy 1 found... Size = 1.2 MB");
}
else if(fd1==3)
{
DEBUG_MSG("Floppy 1 found... Size = 720 kB");
}
else if(fd1==4)
{
DEBUG_MSG("Floppy 1 found... Size = 1.44 MB");
}
/*
0000b = Laufwerk nicht vorhanden
0001b = 5 1/4 - 360 kB
0010b = 5 1/4 - 1.2 MB
0011b = 3 1/2 - 720 kB
0100b = 3 1/2 - 1.44 MB (sollte eigentlich heutzutage der Standard sein)
0101b - 1111b sind unbenutzt
*/
irq_install_handler(6, fdHandler);
resetFDD();
fd[fddDevice].irqRes = 0;
outb(RDSR, DSR_SPEED_500KBPS);
outb(RDOR, 0x0C);
//fddwaitForIRQ();
//FIXME Wait for IRQ here!!!
FDDrecalibrate();
DEBUG_MSG("Test");
//TEST
//int x;
//uint32_t lba = 109;
//int transfer_sector(uint8_t cylinder, uint8_t head, uint8_t sector, int write, void* buffer)
//if ( transfer_sector(lba, 0, (void *) &x) )
//{
// DEBUG_MSG("%d",x);
//}
//sleepTicks(20);
//resetFDD();
//char c = 'A';
//transfer_sector(109, 1, (void *) &c);
unsigned char c = 'A';
unsigned char *test = &c;
fdc_read(test, 0,0,1);
DEBUG_MSG("Readed: >%c<", *test);
}
int fdc_read(unsigned char *data, unsigned int sector, unsigned int offset, unsigned int length)
{
unsigned char st0, st1, st2, rcy, rhe, rse, bps;//, cyl;
fddMotor(true);
if(!floppy_seek(sector))
{
DEBUG_MSG(" failed seek! ");
return 0;
}
//send the read command
send_cmd(CMD_READ_SECTOR );
send_data( fddDevice | (fd->head << 2)); //head and drive
send_data( fd->cylinder);
send_data( fd->head);
send_data( fd->sector);
send_data( 2); // bytes per sector (2 = 512)
send_data( 1); // "end of track" the final sector of this track (I have no idea what it does)
send_data( 0x1B); //GAP3 length
send_data( 0xFF); //data length (0xFF because bytes per sector != 0)
//get the data
//fddwaitForIRQ();//wait for it...
//GO!
int i = 0; unsigned char *tmp = data;
for(i = 0; i < 512; i++)
{
*tmp = (unsigned char) read_data();
//write_hex(*tmp);
tmp++;
}
// read status information
st0 = read_data();
//write_hex(st0);
st1 = read_data();
st2 = read_data();
/*
* These are cylinder/head/sector values, updated with some
* rather bizarre logic, that I would like to understand.
*/
rcy = read_data();
rhe = read_data();
rse = read_data();
// bytes per sector, should be what we programmed in
bps = read_data();
fddMotor(false);
return 1;
}
Hat jemand eine Idee?
Übersicht
Wiki
Hilfe
Suche
Einloggen
Registrieren
Drucken


Gespeichert
und überlege dir woher qemu weiß das es nen Disetten laufwerk hat und welche Dikette/Image wer verwenden soll. 
