Floppy Disk Controller — Änderungen 8037 → 8041

Zeile 1: Zeile 1:
−
{{stub}}
 
 
{{TODO|
 
{{TODO|
 
*Nach Rechtschreibfehlern suchen
 
*Nach Rechtschreibfehlern suchen
Zeile 13: Zeile 12:
 
* Bei allen Operationen, für die der Schreib-/Lesekopf bewegt werden muss, sollte eine Wartezeit eingehalten werden, bis die nächste Operation folgt, da insbesondere Disketten sehr langsame Zugriffszeiten besitzen. Bei Fehlen dieser Wartezeiten funktioniert der Treiber oft nur in Emulatoren, versagt aber auf echter Hardware!
 
* Bei allen Operationen, für die der Schreib-/Lesekopf bewegt werden muss, sollte eine Wartezeit eingehalten werden, bis die nächste Operation folgt, da insbesondere Disketten sehr langsame Zugriffszeiten besitzen. Bei Fehlen dieser Wartezeiten funktioniert der Treiber oft nur in Emulatoren, versagt aber auf echter Hardware!
 
* Der FDC kann nur Sektorangaben in [[CHS]] verarbeiten
 
* Der FDC kann nur Sektorangaben in [[CHS]] verarbeiten
 +
* Der FDC kann theoretisch bis zu vier Diskettenlaufwerke ansteuern, allerdings findet man heute wohl kein System mehr, welches mehr als zwei besitzt.
 +
* '''Diskettenlaufwerke sind sehr fehleranfällig! Deshalb muss ein Befehl oftmals mehrmals gesendet werden, bevor er funktioniert. Großzügige Timeouts sind Pflicht in jedem Treiber für Diskettenlaufwerke.'''
 +
 +
== Verhalten in Emulatoren und echter Hardware ==
 +
* [[Bochs]] unterstützt nur die Übertragung der Daten via [[DMA]]. Allerdings ist dies auch die sinnvollste Variante.
 +
* [[Virtual PC]] hat Probleme mit DMA, wenn das Auto Bit gesetzt ist. Damit der Code funktioniert, muss der DMA Trnasfer jedes Mal durch die CPU reinitialisiert werden.
  
 
== Register ==
 
== Register ==
Zeile 66: Zeile 71:
 
;ACTD-ACTA
 
;ACTD-ACTA
 
: Laufwerk D-A ist im Positionierungs-Modus
 
: Laufwerk D-A ist im Positionierungs-Modus
 +
 
==== DOR ====
 
==== DOR ====
 
{| {{Prettytable}} cellpadding="8"
 
{| {{Prettytable}} cellpadding="8"
Zeile 225: Zeile 231:
 
* Command-Phase: Der Befehl wird von der CPU an den FDC gesendet. Dafür werden die Daten wie weiter unten beschrieben in das Datenregister geschrieben. Vorher sollte getestet werden, ob dieses wirklich leer ist.
 
* Command-Phase: Der Befehl wird von der CPU an den FDC gesendet. Dafür werden die Daten wie weiter unten beschrieben in das Datenregister geschrieben. Vorher sollte getestet werden, ob dieses wirklich leer ist.
 
* Execution-Phase: Der Befehl wird vom FDC ausgeführt. Dabei sollte im Treiber eine Wartezeit eingehalten werden, da Diskettenlaufwerke sehr langsam sind. Bei einigen Befehlen wird die Execution-Phase zusätzlich durch das Senden eines IRQs beendet.
 
* Execution-Phase: Der Befehl wird vom FDC ausgeführt. Dabei sollte im Treiber eine Wartezeit eingehalten werden, da Diskettenlaufwerke sehr langsam sind. Bei einigen Befehlen wird die Execution-Phase zusätzlich durch das Senden eines IRQs beendet.
−
* Result-Phase: Bei einigen Befehlen liefert der FDC Daten zurück, z.B. ob der Befehl erfolgreich ausgeführt wurde. Diese müssen gelesen werden, damit erneut Befehle gesendet werden können.
+
* Result-Phase: Bei einigen Befehlen liefert der FDC Daten zurück, z.B. ob der Befehl erfolgreich ausgeführt wurde. Diese müssen alle gelesen werden, damit erneut Befehle gesendet werden können.
  
 
=== Allgemeine Parameter ===
 
=== Allgemeine Parameter ===
Zeile 283: Zeile 289:
 
Anmerkungen:
 
Anmerkungen:
 
* Die benötigten Daten sollten vom BIOS abgefragt werden (siehe unten)
 
* Die benötigten Daten sollten vom BIOS abgefragt werden (siehe unten)
−
* Im MSR kann eingestellt werden, ob DMA/IRQ oder keins von beidem, hier wird dann noch einmal explizit zwischen DMA (Bit gelöscht) und kein DMA (Bit gesetzt) entschieden.
+
* Im DOR kann eingestellt werden, ob DMA/IRQ oder keins von beidem, hier wird dann noch einmal explizit zwischen DMA (Bit gelöscht) und kein DMA (Bit gesetzt) entschieden.
  
  
Zeile 302: Zeile 308:
 
Anmerkungen:
 
Anmerkungen:
 
* Nach der Kalibrierung wird ein IRQ6 gesendet
 
* Nach der Kalibrierung wird ein IRQ6 gesendet
−
* Es kann passieren, dass der Befehl nicht funktioniert. Desshalb sollte mit "Interrput Status überprüfen" (8h) überprüft werden, ob der aktuelle Zylinder wirklich Null ist.
+
* Es kann passieren, dass der Befehl nicht funktioniert. Desshalb sollte mit "Interrput Status überprüfen" (8h) überprüft werden, ob Bit 4 in St0 gelöscht ist.
−
 
+
* Bei Disketten mit mehr als 80 Tracks muss dieser Befehl in jedem Fall mehrmals gesendet werden.
−
 
 
−
 
 
  
 
=== Laufwerksstatus überprüfen (4h) ===
 
=== Laufwerksstatus überprüfen (4h) ===
Zeile 337: Zeile 341:
 
Anmerkungen:
 
Anmerkungen:
 
* Dieser Befehl sollte immer gesendet werden, wenn der FDC einen IRQ 6 gesendet hat.
 
* Dieser Befehl sollte immer gesendet werden, wenn der FDC einen IRQ 6 gesendet hat.
 +
* Er muss außerdem viermal (!) nach einem Reset des FDCs gesendet werden.
 +
* Die Zylindernummer ist oftmals falsch und sollte ignoriert werden.
  
  
Zeile 356: Zeile 362:
  
 
Anmerkungen:
 
Anmerkungen:
−
* Es kann passieren, dass der Befehl nicht funktioniert. Desshalb sollte mit "Interrput Status überprüfen" (8h) überprüft werden, ob der aktuelle Zylinder wirklich Null ist.
+
* Es kann passieren, dass der Befehl nicht funktioniert. Desshalb muss mit "Interrput Status überprüfen" (8h) überprüft werden, ob Bit 5 in St0 gesetzt ist.
 
* Nach Beendigung wird ein IRQ 6 gesendet.
 
* Nach Beendigung wird ein IRQ 6 gesendet.
  
Zeile 513: Zeile 519:
 
Bevor man Daten bzw. Befehle ins Datenregister schreiben darf, muss man im MSR testen, ob das DIO-Bit gelöscht und das MRQ-Bit gesetzt ist. Erst dann ist das Datenregister leer und bereit Daten zu empfangen.
 
Bevor man Daten bzw. Befehle ins Datenregister schreiben darf, muss man im MSR testen, ob das DIO-Bit gelöscht und das MRQ-Bit gesetzt ist. Erst dann ist das Datenregister leer und bereit Daten zu empfangen.
 
<c>
 
<c>
−
VOID send_command(BYTE cmd)
+
#define NO_ERROR = 0;
 +
#define ERROR_TIMEOUT = 1;
 +
 
 +
BYTE error=NO_ERROR;
 +
 
 +
VOID send_cmd(BYTE cmd)
 
{
 
{
 
   send_data(cmd);
 
   send_data(cmd);
Zeile 520: Zeile 531:
 
VOID send_data(BYTE data)
 
VOID send_data(BYTE data)
 
{
 
{
−
   BYTE status=0;
+
   BYTE timeout;
−
   while ((status & MSR_MASK_MRQ) && !(status & MSR_MASK_DIO)) status=inb(MSR);
+
  for (timeout=0; timeout<200; timeout++)
−
     outb(DATAREG, data);
+
   {
 +
    if ( (inb(MSR) & (MSR_MASK_DATAREG|MSR_MASK_DIO2CPU)) == MSR_MASK_DATAREG)
 +
    {
 +
      outb(CMD,cmd);
 +
      error = NO_ERROR;
 +
      return;
 +
     }
 +
    sleep(5);  //5ms warten vor dem nächsten Versuch
 +
  }
 +
  error = ERROR_TIMEOUT;
 +
  return;
 
}
 
}
 
</c>
 
</c>
  
 
=== Daten lesen ===
 
=== Daten lesen ===
−
Ähnlich wie beim Senden von Daten muss beim Lesen das MRQ-Bit gesetzt und das DIO-Bit ebenfalls gesetzt sein.
+
Ähnlich wie beim Senden von Daten müssen beim Lesen das MRQ-Bit und DIO-Bit gesetzt sein.
  
 
<c>
 
<c>
 
BYTE read_data()
 
BYTE read_data()
 
{
 
{
−
   BYTE status=0;
+
   BYTE timeout;
−
   while ((status & MSR_MASK_MRQ) && !(status & MSR_MASK_DIO)) status=inb(MSR);
+
  for(timeout=0; timeout<200; timeout++)
−
  return inb(DATAREG);
+
   {
 +
    if( (inb(MSR) & (MSR_MASK_DATAREG|MSR_MASK_DIO2CPU)) == (MSR_MASK_DATAREG|MSR_MASK_DIO2CPU))
 +
    {
 +
      error = NO_ERROR;
 +
      return inb(DATA);
 +
    }
 +
    sleep(5);
 +
  }
 +
  error = ERROR_TIMEOUT;
 +
  return 0;
 
}
 
}
 
</c>
 
</c>
  
−
=== Initialisierung ===
+
=== Motor starten/anhalten ===
−
=== Auf Diskette schreiben ===
+
<c>
−
=== Von Diskette lesen ===
+
VOID start_motor(BYTE n)
 +
{
 +
  if (!drive_states[n].motor_on)
 +
  {
 +
    outb(DOR,n | (0x01<<(n+4)) | DOR_MASK_NRESET | DOR_MASK_DMA);
 +
  }
 +
}
 +
 
 +
VOID stop_motor(BYTE n)
 +
{
 +
  if (drive_states[n].motor_on)
 +
  {
 +
    outb(DOR,n | DOR_MASK_NRESET | DOR_MASK_DMA);
 +
  }
 +
}
 +
</c>
 +
 
 +
=== Laufwerk kallibrieren ===
 +
<c>
 +
VOID calibrate_drive(BYTE drive)
 +
{
 +
...TODO
 +
</c>
 +
 
 +
=== Schreib-/Lesekopf postionieren ===
 +
<c>
 +
BOOL seek_head(BYTE cyl, BYTE head, BYTE sector)
 +
{
 +
...TODO
 +
</c>
 +
 
 +
=== Reset ===
 +
<c>
 +
VOID reset()
 +
{
 +
  int i;
 +
 
 +
  outb(DOR, 0);
 +
  sleep(10);
 +
  outb(DOR, DOR_MASK_NRESET | DOR_MASK_DMA);
 +
  wait_irq();
 +
  for(i=0; i<4; i++)
 +
  {
 +
    check_interrupt_status();
 +
  }
 +
  outb(CCR, 0);
 +
 
 +
  /* TODO: zusätzlich sollten jetzt noch die Laufwerke kallibriert werden */
 +
}
 +
</c>
 +
 
 +
=== Sektoren lesen/schreiben ===
 +
Die folgende Funktion nutzt Code aus dem [[DMA#Beispielcode|DMA]] Artikel:
 +
<c>
 +
#define CMD_WRITE_SECTOR (0x05 | 0x40)
 +
#define CMD_READ_SECTOR (0x06 | 0x40)
 +
 
 +
BOOL transfer_sector(BYTE drive, BYTE cylinder, BYTE head, BYTE sector, BOOL write, VOID* buffer)
 +
{
 +
  int i;
 +
  select_drive(drive);  //TODO
 +
  start_motor(drive);    //TODO
 +
  seek_head(drive);      //TODO
 +
 
 +
  dma_begin_transfer(buffer, write);
 +
  for (i=0; i<5; i++)
 +
  {
 +
    send_command(wrie ? CMD_WRIE_SECTOR : CMD_READ_SECTOR);
 +
    send_data(drive | head<<2) );
 +
    send_data(cylinder);
 +
    send_data(head);
 +
    send_data(sector);
 +
    send_data(2);
 +
    send_data(18);
 +
    send_data(27);
 +
    send_data(0xFF);
 +
    wait_irq();
 +
    read_data();  //st0
 +
    read_data();  //st1
 +
    read_data();  //st2
 +
    read_data();  //cylinder
 +
    read_data();  //head
 +
    read_data();  //sector
 +
    read_data();  //Sektorgröße
 +
    if ( inb(MSR) & 0xC0)
 +
    {
 +
      check_interrupt_status();
 +
      return TRUE;
 +
    }
 +
  }
 +
  /* fünf Fehlversuche */
 +
  return FALSE;
 +
}
 +
</c>
  
 
== Siehe auch ==
 
== Siehe auch ==
Zeile 548: Zeile 671:
 
* [[Media:82077AA FloppyControllerDatasheet.pdf | 82077AA CHMOS Single-Chip Floppy Disk Controller Datasheet]]
 
* [[Media:82077AA FloppyControllerDatasheet.pdf | 82077AA CHMOS Single-Chip Floppy Disk Controller Datasheet]]
 
*[http://www.isdaman.com/alsos/hardware/fdc/floppy.htm http://www.isdaman.com/alsos/hardware/fdc/floppy.htm]
 
*[http://www.isdaman.com/alsos/hardware/fdc/floppy.htm http://www.isdaman.com/alsos/hardware/fdc/floppy.htm]
−
[[Kategorie:Stub]]
+
 
 
[[Kategorie:Hardware]]
 
[[Kategorie:Hardware]]