| Zeile 5: | Zeile 5: | ||
== Einführung == | == Einführung == | ||
=== Vorwort === | === Vorwort === | ||
| − | Wenn ich hier von | + | Wenn ich hier von „Bytes“ spreche, meine ich acht Bit große Einheiten. Zwei Bytes (16 Bit) sind ein Word und vier Bytes (32 Bit) ein DWord. Acht Bytes (64 Bit) sind ein QWord. Wenn ich keine Endianess explizit angebe, dann ist Little Endian gemeint. |
=== Grundlagen === | === Grundlagen === | ||
| Zeile 22: | Zeile 22: | ||
== Zugriff == | == Zugriff == | ||
=== Grundlagen === | === Grundlagen === | ||
| − | Die | + | Die „direkt“ erreichbaren Register (ein Portzugriff) sind nur ein kleiner Teil der gesamten Register der Karte. Neben ihnen gibt es noch die CSR (Control and Status Register) und die BCR (Bus Control Register). Um auf sie zuzugreifen, muss zuerst die Adresse des Registers in den 16-Bit-I/O-Port RAP (Register Address Port) geschrieben werden. Betrifft diese Adresse eines der CSR, so kann der Wert anschließend am 16-Bit-I/O-Port RDP (Register Data Port) ausgelesen oder verändert werden. Betrifft die Adresse eines der BCR, so handelt es sich nicht um den RDP, sondern um den BDP (BCR Data Port). |
=== Initialisierung === | === Initialisierung === | ||
| Zeile 33: | Zeile 33: | ||
4. Nun muss ein STOP-Reset ausgeführt werden. Dies wird erreicht, indem 0x04 nach CSR0 geschrieben wird. | 4. Nun muss ein STOP-Reset ausgeführt werden. Dies wird erreicht, indem 0x04 nach CSR0 geschrieben wird. | ||
| − | 5. Puffer zum Senden und Empfangen initialisieren; beide müssen 2 kB groß und physisch kontinuierlich sein. | + | 5. Puffer zum Senden und Empfangen initialisieren; beide müssen 2 kB groß und physisch kontinuierlich sein. |
6. Nun muss die Karte initialisiert werden. Dies geschieht mittels eines Initialization Block, der folgendermaßen aussieht: | 6. Nun muss die Karte initialisiert werden. Dies geschieht mittels eines Initialization Block, der folgendermaßen aussieht: | ||
| Zeile 49: | Zeile 49: | ||
uint32_t transmit_descriptor; | uint32_t transmit_descriptor; | ||
} __attribute__((packed));</c> | } __attribute__((packed));</c> | ||
| − | + | „reservedX“-Felder sind reserviert. „mode“ ist 0x8000, wenn die Karte in den Promiscuous-Mode geschaltet werden soll (Alle Pakete empfangen, nicht nur Broadcasts und die für die eigene MAC-Adresse), sonst 0x0000. „receive_length“ gibt die Anzahl der Empfangsdeskriptoren an, dazu später. „transfer_length“ enthält im Gegensatz dazu die Anzahl der Sendedeskriptoren. Beide Werte können auf 3 gesetzt werden, dies entspricht jeweils acht Deskriptoren. „physical_address“ enthält die MAC-Adresse der Karte. „logical_address“ kann auf 0 gesetzt werden. „receive_descriptor“ enthält die physische Adresse zu einem 2-kB-Puffer, „transmit_descriptor“ zu einem anderen. Beide Puffer müssen physisch kontinuierlich sein und an 16-Bytes-Grenzen ausgerichtet. | |
7. Jetzt müssen die Empfangs- und Sendedeskriptoren initialisiert werden. So ein Deskriptor sieht so aus: | 7. Jetzt müssen die Empfangs- und Sendedeskriptoren initialisiert werden. So ein Deskriptor sieht so aus: | ||
| Zeile 59: | Zeile 59: | ||
uint32_t avail; | uint32_t avail; | ||
} __attribute__((packed));</c> | } __attribute__((packed));</c> | ||
| − | + | „address“ gibt die physische Adresse eines 2-kB-Puffers (physisch kontinuierlich) an, „flags“ und „flags2“ enthalten Flags (siehe unten), „avail“ kann vom Benutzer (also von dir) frei verwendet werden. Bei den Empfangsdeskriptoren muss das OWN-Bit (0x80000000) im „flags“-Feld gesetzt werden, zudem müssen die Bits 0 bis 11 des „flags“-Feldes auf 0x7FF gesetzt werden (negative Länge des Puffers, also -2048). Außerdem müssen in beiden Deskriptortypen die Bits 12 bis 15 (0x0000F000) im „flags“-Feld gesetzt werden. Die acht Empfangsdeskriptoren müssen hintereinander in den Puffer geschrieben werden, der in das „receive_descriptor“-Feld des Initialization Blocks eingetragen wurde. Die acht Sendedeskriptoren müssen analog dazu in den Puffer geschrieben werden, der in das „transmit_descriptor“-Feld eingetragen wurde. | |
8. Wenn auch die Deskriptoren initialisiert sind, sollte der Initialization Block bei der Karte registriert werden. Hierzu werden die niederwertigen 16 Bits der physischen Adresse in das CSR1-Register und die höherwertigen in das CSR2-Register geschrieben. | 8. Wenn auch die Deskriptoren initialisiert sind, sollte der Initialization Block bei der Karte registriert werden. Hierzu werden die niederwertigen 16 Bits der physischen Adresse in das CSR1-Register und die höherwertigen in das CSR2-Register geschrieben. | ||
| Zeile 95: | Zeile 95: | ||
Wenn ein Interrupt eintrifft, dann zeigt das CSR0-Register den Grund dafür an. Ist das ERR-Bit (0x00008000) gesetzt, so trat ein Fehler auf. | Wenn ein Interrupt eintrifft, dann zeigt das CSR0-Register den Grund dafür an. Ist das ERR-Bit (0x00008000) gesetzt, so trat ein Fehler auf. | ||
| − | Wenn das TINT-Flag (0x00000200) gesetzt ist, dann wurde ein Sendedeskriptor abgearbeitet. Ob erfolgreich oder nicht, dass steht im entsprechenden Deskriptor. Ist im | + | Wenn das TINT-Flag (0x00000200) gesetzt ist, dann wurde ein Sendedeskriptor abgearbeitet. Ob erfolgreich oder nicht, dass steht im entsprechenden Deskriptor. Ist im „flags“-Feld das ERROR-Bit gesetzt (0x40000000), dann trat ein Fehler auf, ansonsten wurde das Paket gesendet. Die „flags“-Felder (also „flags“ und „flags2“) des Deskriptors sollten dann auf 0 gesetzt werden. |
| − | Sollte das RINT-Flag (0x00000400) gesetzt sein, dann wurde ein Paket abgearbeitet. Siehe dazu | + | Sollte das RINT-Flag (0x00000400) gesetzt sein, dann wurde ein Paket abgearbeitet. Siehe dazu „Empfangen von Paketen“. |
Am Ende der ISR sollte der Inhalt des CSR0-Registers dorthin zurückgeschrieben werden, um der Karte anzuzeigen, dass der Interrupt abgearbeitet wurde. | Am Ende der ISR sollte der Inhalt des CSR0-Registers dorthin zurückgeschrieben werden, um der Karte anzuzeigen, dass der Interrupt abgearbeitet wurde. | ||
=== Senden eines Pakets === | === Senden eines Pakets === | ||
| − | Um ein Paket zu senden, muss die physische Adresse des entsprechenden Datenpuffers in das | + | Um ein Paket zu senden, muss die physische Adresse des entsprechenden Datenpuffers in das „address“-Felds des nächsten Sendedeskriptors geschrieben werden (zuerst Deskriptor 0, dann 1 und so weiter bis Deskriptor 7 (also der achte), danach wieder von vorn beginnen). „flags2“ zeigt ein, ob ein Fehler beim Senden geschehen ist, sollte daher vom Treiber auf 0 gesetzt werden. Im „flags“-Feld muss nun das OWN-Bit gesetzt werden (0x80000000), um der Karte den Deskriptor zu „übergeben“. Desweiteren sollten STP (Start of Packet, 0x02000000) und ENP (End of Packet, 0x01000000) gesetzt werden – dies zeigt an, dass die Daten nicht aufgeteilt werden, sondern dass es sich um ein einzelnes Ethernetpaket handelt. Weiterhin müssen die Bits 12-15 gesetzt werden (0x0000F000, sind wohl reserviert) und die Bits 0-11 geben die '''negative''' Größe des Pakets an. |
Nun könnte man einfach warten, bis die Karte sich das Paket abholt. Alternativ dazu kann man auch das TDMD-Bit (0x08) in CSR0 setzen (Also 0x48 nach CSR0 schreiben, um die Interrupts aktiviert zu lassen), um diese Wartezeit abzukürzen. | Nun könnte man einfach warten, bis die Karte sich das Paket abholt. Alternativ dazu kann man auch das TDMD-Bit (0x08) in CSR0 setzen (Also 0x48 nach CSR0 schreiben, um die Interrupts aktiviert zu lassen), um diese Wartezeit abzukürzen. | ||
| Zeile 137: | Zeile 137: | ||
memcpy(ncard->linear_transmit_buffer[current_descriptor], buffer, length); | memcpy(ncard->linear_transmit_buffer[current_descriptor], buffer, length); | ||
//Die physische Adresse (also ncard->physical_transmit_buffer[current_descriptor]) sollte schon bei der | //Die physische Adresse (also ncard->physical_transmit_buffer[current_descriptor]) sollte schon bei der | ||
| − | //Initialisierung in das | + | //Initialisierung in das „address“-Feld geschrieben worden sein |
ncard->linear_transmit_descriptor[current_descriptor].flags2 = 0; | ncard->linear_transmit_descriptor[current_descriptor].flags2 = 0; | ||
ncard->linear_transmit_descriptor[current_descriptor].flags = 0x8030F000 | ((-length) & 0x7FF); | ncard->linear_transmit_descriptor[current_descriptor].flags = 0x8030F000 | ((-length) & 0x7FF); | ||
| Zeile 144: | Zeile 144: | ||
=== Empfangen von Paketen === | === Empfangen von Paketen === | ||
| − | Sobald ein Paket empfangen wurde (das heißt, die ISR wurde aufgerufen und das RINT-Flag im CR0-Register ist gesetzt), müssen alle Empfangsdeskriptoren ab dem aktuellen abgearbeitet werden, bis das OWN-Bit (0x80000000 im | + | Sobald ein Paket empfangen wurde (das heißt, die ISR wurde aufgerufen und das RINT-Flag im CR0-Register ist gesetzt), müssen alle Empfangsdeskriptoren ab dem aktuellen abgearbeitet werden, bis das OWN-Bit (0x80000000 im „flags“-Feld) bei einem gesetzt ist. Denn alle Deskriptoren mit gelöschtem OWN-Bit wurden gerade von der Karte bearbeitet. Zum Abholen der Daten sollte dann das OWN-Bit gesetzt werden und die Daten können aus dem im Deskriptor angegebenen Puffer kopiert werden. Die Anzahl der Bytes steht in den Bits 0 bis 11 des „flags2“-Feldes. Zu diesen Daten gehört auch eine 4 Bytes lange CRC32-Checksumme am Ende des Pakets. |
| − | Die Daten sollten nur dann gelesen werden, wenn das ERROR-Bit (0x40000000) im | + | Die Daten sollten nur dann gelesen werden, wenn das ERROR-Bit (0x40000000) im „flags“-Feld nicht gesetzt ist. Außerdem sollten die Bits STP und ENP (0x02000000 bzw. 0x01000000) – ebenfalls im „flags“-Feld – beide gesetzt sein. |
Beispielcode: | Beispielcode: | ||
| Zeile 178: | Zeile 178: | ||
* [http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21510.pdf Umfangreiche Spezifikation für die Am79C973 (PCnet-FAST III) und Am79C975] | * [http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21510.pdf Umfangreiche Spezifikation für die Am79C973 (PCnet-FAST III) und Am79C975] | ||
* [http://www.amd.com/us-en/assets/content_type/DownloadableAssets/22351.pdf AMD-Hardware-Spezifikation] | * [http://www.amd.com/us-en/assets/content_type/DownloadableAssets/22351.pdf AMD-Hardware-Spezifikation] | ||
| − | * [http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21485_pt1.pdf Umfangreiche Spezifikation für die Am79C972 (PCnet-FAST+)] | + | * [http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21485_pt1.pdf Umfangreiche Spezifikation für die Am79C972 (PCnet-FAST+)] – sollte zur Am79C973 (PCnet-FAST III) kompatibel sein |
[[Kategorie:Tutorials]] | [[Kategorie:Tutorials]] | ||
[[Kategorie:Netzwerkkarte]] | [[Kategorie:Netzwerkkarte]] | ||