Friedrich-Alexander-Universität UnivisSuche FAU-Logo
Techn. Fakultät Willkommen am Department Informatik FAU-Logo
Logo I4
Lehrstuhl für Informatik 4
AKBP 2
 
 Vorträge
 
 PCMCIA
 Trixbus
 NE2000
 USB-Stack
 Windowmanager
Department Informatik  >  Informatik 4  >  Lehre  >  WS 2003/04  >  AKBP 2  >  Projekte  >  NE2000

NE2000 kompatibler Netzwerktreiber

Götz Manuel,
Gabriel Stefan

 

                   Ausarbeitung zum Praktikum AKBPII

vom 23.2. – 5.3.2004

 

 

 

 

von Manuel Götz

 

 

 

Übersicht:

 

1.     Allgemeines zum NE2000-Standard

 

2.     Hardware einer kompatiblen Karte

2.1. Allgemeiner Aufbau

2.2. Register

2.3. Speicher

       2.3.1. Speicherlayout

       2.3.2. Puffer

 

3.     Design eines Treibers zu NE2000

3.1. Klassen

3.2. Starten des Treibers

3.3. Initialisieren der Karte

3.4. Versenden von Paketen

3.5. Empfangen von Paketen

 

4.     Ausblick

 

5.  Literaturliste

 

 

 

 

 

1.   Allgemeines zum NE2000-Standard

 

 

Im Rahmen des Praktikums AKBPII war die Aufgabe gestellt, einen Treiber

für eine NE2000-kompatible Netzwerkkarte zu schreiben.

Zum NE2000-Standard sollte erst einmal eine kurze Entstehungsgeschichte

betrachtet werden, da sie die Intention hinter dem Design erklärt.

Er wurde das erste Mal im NatSemi (National Semiconductor) Databook

veröffentlicht. Er war allerdings nicht zur tatsächlichen Realisierung gedacht,

auch sollte auch kein späterer Hardware-Standard geschaffen werden.

Es sollte „nur“ ein Vorschlag dafür gemacht werden, was eine Ethernet-

Netzwerkkarte mindestens an Hardware zu bieten haben müsste.

Die Firma Novell jedoch, die auch damals schon eher für ihre Software bekannt

war, benötigte für ihre Software eine entsprechende Hardware. Daher übernahm

Novell einfach diesen Vorschlag.

Der Standard hat sich jedoch, nicht zuletzt aufgrund der Software von Novell,

durchgesetzt.

Auch heute werden noch NE2000-kompatible Karten erstellt und folglich

Treiber dafür geschrieben, obwohl der Standard inzwischen veraltet ist und

mit neueren Entwicklungen nur schwer konkurrieren kann. Dennoch werden

sogar NE2000-kompatible PCI-Karten gefertigt.

Allerdings kann aufgrund der Hardware-Architektur dadurch fast kein Vorteil

erzielt werden, v.a. im Bezug auf Geschwindigkeit.

 

Man sieht also: der NE2000-Standard ist ein weiteres Beispiel in der

Geschichte der Standards, die sich einfach aufgrund von aktuellen

Gegebenheiten durchgesetzt und behauptet haben, obwohl es

vielleicht vom rein technischen Standpunkt aus bessere Lösungen

gegeben hätte. Aber er existiert, ist weit verbreitet und erfreut sich auch heute

noch großer Beliebtheit.

Daher ist es aus praktischer Sicht absolut nachvollziehbar, einen Treiber für

NE2000-kompatible Karten zu schreiben und somit die Unterstützung

durch das Betriebssystem zu gewährleisten.

 

 

 

2.   Hardware einer NE2000-kompatiblen Karte

 

Die im Folgenden genannten Hardware-Spezifika bilden nur eine minimale

Ausgangsbasis, d.h. eine kompatible Karte muss z.B. über die genannten

Register verfügen, sie kann aber auch noch viele weitere besitzen und anbieten,

die im Standard nicht genannt werden. Es gibt dann im Prinzip einen

kompatiblen Modus, in dem nur die Hardware-Ressourcen, die im Standard

aufgeführt sind, genutzt werden und einen erweiterten Modus, in dem die Karte

mit all ihren Fähigkeiten angesteuert wird. Die 2. Möglichkeit ist meist die

Bessere und Schnellere, aber selbstverständlich ist ein Treiber für eine solche

Ansteuerung nicht so universell einsetzbar und kompatibel, sondern eben

kartentypspezifisch. In der Realität trifft man auch bei fast jeder

NE2000-kompatiblen Karte auf beide Möglichkeiten. Ein gutes Beispiel sind die

Realtek-Karten mit dem 8029-Chipsatz (z.B. RTL8029AS) (siehe [5]).

 

 

2.1. Allgemeiner Aufbau

 

Zu Beginn der Hardwarebeschreibung sollen erst einmal die

grundlegenden Elemente der Hardware genannt werden, mit denen man sich

als Programmierer eines Treibers auseinandersetzen muss.

Dies sind die Register, der Speicher und, nur am Rande, der FIFO.

Die Register benötigt man zur Bedienung und Konfiguration der Karte.

Im Speicher werden die eingehenden und ausgehenden Pakete

zwischengespeichert, bzw. vom und zum Arbeitsspeicher des Rechners

kopiert. Sowohl auf Register als auch auf Speicher hat der Programmierer

direkten Zugriff. Er muss den Speicher aber beim Initialisieren der Karte erst

einmal richtig konfigurieren, um ihn nutzen zu können.

Der FIFO dient der Karte, um Schwankungen in der Übertragungs-

geschwindigkeit des Netzes auszugleichen ([6], S.9). Auf diesen ist kein

softwaremäßiger Zugriff vorgesehen. Er wird daher hier nur der Vollständigkeit

halber genannt und spielt in der weiteren Betrachtung keine Rolle.

Zum besseren Verständnis zeigt folgende Grafik den Weg jedes ein- und

ausgehenden Pakets durch die Hardware

(Eingehend: von links nach rechts; Ausgehend: von rechts nach links):

 

 

 

 

 

 

 


2.2. Register

 

 

(Tabelle siehe [5], S. 11)

 

In oben stehender Tabelle erhält man einen kompletten Überblick über die

Register der Karte. Die Register sind in 3 Seiten unterteilt. Dies ist für das

Ansprechen von Bedeutung, denn bevor man ein Register lesen oder schreiben

kann, muss man zuerst einmal die Seite im Command-Register (CR) festlegen,

d.h. man braucht z.B. für jeden Register-Lesezugriff vorher noch einen

Schreibzugriff im Command-Register.

Dies erklärt, warum das Command-Register auf jeder Seite verfügbar

sein muss: man kann für dieses vorher keine Seite angeben.

Weitere wichtige Register sind z.B. die PARs (Physical Address Register).

Hier steht die Ethernet-Adresse, mit der jedes eingehende Paket

verglichen wird. Danach wird über dessen Annahme entschieden

(wenn sie mit der Zieladresse des Pakets übereinstimmt, ist das Paket

für diesen Rechner gedacht und wird angenommen).

Die Funktionen von BNRY (Boundary Register), CURR (Current Register),

PSTART und PSTOP sind für den Empfangspuffer wichtig und werden

dort näher erklärt.

Das IMR (Interrupt Mask Register) wird beim Hochfahren gesetzt (kann danach

aber noch verändert werden). In ihm bestimmt man, welche Ereignisse einen

Interrupt auslösen sollen und welche nicht.

Durch Auslesen des ISR (Interrupt Status Register) beim Eintreffen eines

Interrupts kann man erkennen, welches Ereignis den Interrupt ausgelöst hat.

Dies war ein Ausschnitt der wichtigsten Register. Einige werden später bei der

Anwendung noch genauer betrachtet. Das Wichtigste hier ist die Struktur, also

die Unterteilung in Seiten, und die Tatsache, dass einige Register auf

unterschiedlichen Seiten gelesen und geschrieben werden. Genauere und

vollständige Informationen zu den einzelnen Registern sind der Spezifikation

oder einigen Dokumenten aus der am Schluss angefügten Literaturliste zu

entnehmen. (v.a.: [5], S.11-16)

 

 

2.3. Speicher

 

2.3.1 Speicherlayout

 

Das zweite große Hardware-Element auf der Karte ist der Speicher.

Er ist untergliedert in verschiedene Bereiche, wobei die wichtigsten

sind:

- PROM

         Dieser Teil ist als persistenter ReadOnly-Speicher ausgelegt und enthält

wichtige Daten, die zum Beispiel zum Initialisieren benötigt werden und

beim Herunterfahren der Karte nicht verloren gehen dürfen([3], S.9).

 

- Puffer

         Im Puffer werden die im laufenden Betrieb ein- und ausgehenden

         Pakete zwischengespeichert, bis sie vom Treiber in den Arbeitsspeicher

geschrieben oder versandt werden.

        

Zur Veranschaulichung folgt der Aufbau des Speichers in grafischer Form.

Oben nicht näher beschriebene Teile sind dabei im weiteren Verlauf

bedeutungslos und werden nur der Korrektheit wegen angezeigt:

                           

 

                            0x0000

PROM

 
 


                          

Aliased PROM

 
                            0x001F

 

 Puffer

 
                                        0x4000

 

Aliased PROM

 
                            0x8000

 

Aliased  Puffer

 
                            0xC000

 

                            0xFFFF

 

(Grafik siehe [1], S.2)

 

Da der Puffer das Stück im Speicher ist, auf den der Treiber sicherlich die

meisten Zugriffe durchführt, soll er nun näher betrachtet werden.

 

 

2.3.2 Puffer

 

Der Puffer soll sowohl die ein-, als auch die ausgehenden Pakete speichern.

Dazu muss er bei der Initialisierung erst einmal in 2 Teile aufgespalten

werden. Dies geschieht, indem nach einem Reset der Karte die Register TPSR,

PSTART  und PSTOP gesetzt werden.

Das TPSR (Transmit Page Start Register) enthält die Adresse, an die das nächste

(falls sie nie geändert wird auch alle) zu versendende Paket geschrieben wird.

Da ein Ethernet-Paket bis zu 1514 Byte groß sein kann, sollte man nach

dieser Adresse auch mindestens so viel Platz bereitstellen und frei lassen.

Ist ein Paket an diese Stelle geschrieben worden,  muss nur noch der

Versendebefehl im Command-Register gegeben werden.

Das Paket wird dann automatisch an den FIFO auf der Karte übertragen

und von dort auf das Netz ([2], S.1+2).

Ist dies geschehen, wird einer von 2 möglichen Interrupts ausgelöst.

Entweder wurde das Paket erfolgreich versandt oder es gab einen Fehler.

Der Treiber kann dann entsprechend reagieren ([5], S.13).

Der Puffer für die empfangenen Pakete wird durch PSTART und PSTOP

begrenzt. Der Grund dafür, dass beim Empfangspuffer 2 Register zum

begrenzen nötig sind, liegt darin, dass der Empfangspuffer in Form

eines Ringpuffers aufgebaut ist.

Dieser Ringpuffer besteht aus 256 Byte großen Seiten.

Die Anzahl dieser Seiten hängt natürlich von seiner Größe ab.

PSTART beschreibt den Beginn der ersten Seite des Ringpuffers und

PSTOP den Beginn der ersten Seite, die nicht mehr gültig ist.

Innerhalb dieser Grenzen müssen alle vom FIFO erhaltenen Nachrichten

gespeichert werden.

Das folgende Bild zeigt den Aufbau des Ringpuffers, die darin dargestellten

Pointer werden im Anschluss erklärt. 

 

 

 

 

(Grafik und Beschreibung nach [2])

 

Jedes eingehende Paket wird von der Karte mit einem 4 Byte großen Header

versehen, in dem der Status des Pakets (z.B. fehlerfrei), der Beginn des nächsten Pakets (die Seite mit dem nächsten Header) und die Länge des Pakets enthalten

sind.

Um den Ringpuffer auszulesen muss man mit folgenden Registern arbeiten:

 

- BNRY(Boundary Pointer)

Der Boundary Pointer zeigt immer auf den Vorgänger der nächsten zu

lesenden Seite, die in den Arbeitsspeicher transferiert werden soll. Ist das

Paket aus dem Kartenspeicher ausgelesen und in den Arbeitsspeicher

eingelesen worden, muss der Boundary Pointer vom Treiber weitergesetzt

werden. Dies geschieht mit Hilfe des Headers, in dem die Seite, die den

Beginn des nächsten Pakets enthält, steht. Beachtet werden müssen

hierbei die durch PSTART und PSTOP definierten Grenzen des

Ringpuffers, d.h. der Boundary Pointer muss nach Überschreiten des

PSTOP-Wertes wieder beim PSTART-Wert beginnen. 

 

- CURR(Current Page Register)

Der Current Pointer zeigt auf die nächste freie Seite, in die

Pakete geschrieben werden können. Er wird nur beim Initialisieren einmal

gesetzt und danach selbstständig von der Karte verwaltet. Er beachtet

automatisch die Grenzen des Ringpuffers. Der Current Pointer sollte nach

dem Hochfahren nicht mehr vom Treiber verändert werden.

 

Um einen Überlauf des Ringpuffers zu vermeiden muss genügend Speicher

aus dem Puffer für den Empfang von Paketen bereitgestellt werden, d.h.

die Differenz von PSTOP und PSTART ist zu maximieren.

Die komplette Transferierung der Speicherinhalte ist nur über DMA-Zugriffe

möglich. Im NE2000-Standard ist kein Memory Mapping vorhergesehen, daher

muss für jeden Speicherzugriff auf Remote DMA zurückgegriffen werden.

 

 

 

3.   Design eines NE2000-kompatiblen Treibers

 

Da im 2.Kapitel die Grundlagen betreffs der Hardware gelegt wurden,

kann nun das Design eines Treibers für die NE2000-Karten erläutert werden.

Als Vorlage dient hier der im Rahmen des AKBPII-Praktikums erstellte

Treiber. Dieser kann und soll durchaus nicht als Alleinlösung gesehen werden.

Es ist mehr als ein Vorschlag gedacht, der natürlich noch verbesserungsfähig ist.

 

3.1. Klassen

 

Zu Beginn wird das grundlegende Design dargestellt.

Der Treiber wurde in 4 Klassen unterteilt, um seine Aufgaben zu erfüllen.

Das folgende Diagramm soll einen Überblick vermitteln:

 

 

 

 

 


                                                                  Meldet Treiber im System an

                                                                  Ruft benötigten Konstruktor auf

NE2000.java

 
 

 


Hilfsklasse für das Lesen und  Schreiben                                              Hilfsklasse zum transferieren und

sowohl der Register als auch des                                                                Speichern der ein- und ausgehenden

Speichers, insbesondere Puffers                                                                        Pakete

Register.java

 

Message.java

 
 

 

 

 

 

3.2. Starten des Treibers

 

Beim Hochfahren des Systems wird von der boot.rc aus über mehrere Klassen

die NE2000Finder.java aufgerufen. Diese sucht nach einer NE2000-kompatiblen

Karte im Rechner. Das Suchen geschieht mit Hilfe der Vendor ID und

Device ID, die mit allen gefundenen Netzwerkkarten verglichen wird.

Gilt eine davon als NE2000-kompatibel, war die Suche erfolgreich.

Nachdem durch die IDs der genaue Typ der Karte bekannt ist, bleibt noch zu

prüfen, ob es eine PCI- oder eine ISA-Karte ist. Bei einer ISA-Karte müssen in

der boot.rc noch zusätzliche Parameter wie die z.B. Interrupt-Nummer

angegeben werden, damit die Karte gestartet werden kann. Sind alle Angaben

plausibel, wird nun der entsprechende Konstruktor der NE2000.java gestartet.

Die verschiedenen Konstruktoren sind leider nötig, da z.B. die Realtek

initiale, nicht NE2000-kompatible Einstellungen braucht, um sie in den

kompatiblen Modus zu versetzen. Wurde der Konstruktor erfolgreich gestartet,

wird an dem zurückgelieferten Objekt noch die von der NE2000.java

angebotene Methode open() aufgerufen, die die Initialisierung der Karte

vornimmt.

 

3.3. Initialisieren der Karte

 

Durch das Initialisieren wird die Karte beim Hochfahren in einen

betriebsfähigen Zustand versetzt. Dazu müssen folgende Aufgaben erledigt

werden, die open() in der NE2000.java ausführt:

 

1.     Ein Hardware-Reset der Karte, durch Schreiben in den ResetPort.

2.     Initialisieren des DCR (Data Configuration Register)

In diesem Register werden Einstellungen vorgenommen, die v.a. die

Art der Übertragung der Daten beim DMA-Zugriff zwischen Rechner

und Karte betreffen, z.B. Byte- oder Wortweise Übertragung, die

Byte Order etc.

3.     Löschen von RBCR0, RBCR1 (Remote Byte Count Register)

Diese Register geben an, wie lang das zu übertragende Paket im Puffer

ist, bevor die Übertragung an den FIFO erfolgt.

Die Größenangabe erfolgt in Bytes.

Die Register werden initial auf 0 gesetzt.

4.     Initialisieren des RCR (Receive Configuration Register)

Die Einstellungen betreffen die ankommenden Pakete.

Man kann entscheiden, ob man beschädigte Pakete speichern möchte

oder gleich verwirft, ob man Broad- und Multicast-Pakete empfangen

möchte u.v.m.

5.     Initialisieren des TCR (Transmit Configuration Register)

In diesem Schritt wird vor allem über die Art des Loopback-Modus

entschieden, der während der restlichen Initialisierungen aktiv ist.

Es ist Modus 1 oder 2 zu wählen.

6.     Initialisieren des Ringpuffers

BNRY (Boundary Pointer), PSTART und PSTOP werden auf die

gewünschten Adressen im Puffer gesetzt. Es ist zu beachten, dass

diese 8-bit Register von einer 16-bit Adresse nur die höchstwertigen

8 bit enthalten. Aufgrund der 256 Byte großen Seiten im Ringpuffer

ist eine feinere Auflösung unnötig.

7.     Löschen des ISR (Interrupt Status Register)

Das ISR wird mit 0xFF überschrieben. Dadurch werden die im bisher

undefinierten Zustand evtl. anliegenden (hier noch unsinnigen) Interrupts

gelöscht.

8.     Initialisieren des IMR (Interrupt Mask Register)

In diesem Register entscheidet man, welche Interrupts die Karte

senden soll und welche maskiert werden sollen.

     9.  Initialisieren der PAR0-5 (Physical Address Register)

Aus dem PROM im Speicher der Karte (an Stelle 0) wird die Ethernet-

Adresse ausgelesen und anschließend in die PAR geschrieben.

Mit diesen Registern wird die Zieladresse jedes ankommenden

Pakets verglichen und dann über dessen Annahme entschieden.

9.     Initialisieren der MAR0-7 (Multicast Address Register)

Siehe 9., nur für Multicast-Pakete

     11.Initialisieren des CURR (Current Pointer)

         Der Current Pointer wird am besten auf den Wert

         (Boundary Pointer + 1) gesetzt, also eine Seite weiter im

         Ringpuffer.

     12.Setzen des Startmodus im Command-Register

         Der Stopwert im Command-Register wird gelöscht und das

         Start-Bit gesetzt. Zusätzlich wird der DMA-Zugriff aktiviert.

     13.Setzen des TCR (Transmit Configuration Register)

         Das TCR wird nun auf den Normal Mode zurückgesetzt.

         Erst jetzt ist die Karte betriebsbereit.

 

Die Reihenfolge dieser Schritte ist weitgehend einzuhalten, einige wenige

können vertauscht werden. Sind sie alle richtig ausgeführt worden, ist die Karte

nun sende- und empfangsbereit. (siehe [1], S.5; [4], S.1)

 

3.4. Versenden von Paketen

 

Zum Versenden von Paketen bietet der Treiber in der NE2000.java zwei

Methoden an, die transmit(...) und die transmit1(...).

Die transmit-Methode hat als Parameter nur ein Memory-Objekt, das

verschickt werden soll. Die transmit1-Methode bietet durch die zusätzlichen

Parameter offset und size noch die Möglichkeit, erst ab einem bestimmten offset

im Memory-Objekt mit dem Versenden zu beginnen oder die Länge in Bytes

anzugeben, die verschickt werden soll. Das hat u.a. den Vorteil, dass bei einem

40 Byte großen Paket auch nur 40 Byte versendet werden und nicht 1514, wie es

bei der transmit-Methode der Fall ist. Da die transmit-Methode einfach die

transmit1-Methode mit den zusätzlichen Parametern 0 als offset und 1514 als

size aufruft, verfahren beide Methoden im weiteren Verlauf gleich.

 

Zuerst wird geprüft, ob die Pufferstelle im Versendespeicher, an die das

Paket geschrieben werden soll, frei ist. Ist dies nicht der Fall, wird die Nachricht

in eine Liste mit zu versendenden Paketen eingehängt, die jedesmal abgearbeitet

wird, wenn ein Paket fertig versandt wurde (dies erkennt man am

entsprechenden Interrupt). Ist die Pufferstelle frei, wird zuerst einmal in die

TPSR0/1 (Transmit Page Start Register) die Adresse mit dem Beginn der

Nachricht im Puffer geschrieben. Anschließend schreibt man in die TBCR0/1

(Transmit Byte Count Register) die Länge des Pakets. Nun schreibt man noch

den Inhalt des Memory-Objekts an die in den TPSR0/1 angegebene Stelle. 

Ist dies geschehen, gibt man mit dem Command-Register den Befehl zum

Start des Versendevorgangs. (siehe [1], S.12+13; [4], S.6)

Zum Schluß muss nur noch ein leeres Memory-Objekt zurückgegeben werden.

Da die transmit-Methoden sowohl von außerhalb als auch von der Klasse selbst

aufgerufen werden können (um die Liste der zu versendenden Pakete abzu-

arbeiten), ist noch zu synchronisieren. Es darf immer nur eine transmit-Methode

auf einmal in Ausführung sein.

 

3.5. Empfangen von Paketen

 

Das Empfangen von Paketen beginnt damit, dass man einen Interrupt wegen

eines eingegangenen Pakets im Ringpuffer erhält. Dieses liest man mit Hilfe des

Headers, der die Länge des Pakets enthält, aus und hängt es in eine Liste mit

empfangenen Paketen ein. Der Header des ersten zu lesenden Pakets steht genau

an der Stelle, auf die der Boundary Pointer zeigt. Dann wird der Boundary

Pointer (BNRY) wieder richtig gesetzt, da dieser immer noch auf der Seite vor

dem Beginn des gerade ausgelesenen Pakets steht. Er wird auf die Seite vor dem

Beginn des nächsten Pakets gesetzt, dessen Adresse man ebenfalls aus dem

Header erhält. Ist dies alles geschehen, wird überprüft, ob der Boundary Pointer

genau den Wert (Current Pointer – 1) enthält, denn da das ganze Auslesen im

Interrupthandler erfolgt ist, können inzwischen weitere Pakete und Interrupts

eingetroffen sein, die ignoriert wurden, weil die Interrupts gesperrt waren.

Der Auslesevorgang wird also solange wiederholt, bis der Boundary Pointer

genau eine Seite hinter dem Current Pointer steht. Dann wurde alles ausgelesen.

Zum Schluss werden die Interrupts wieder freigegeben.

Danach wird noch einmal überprüft, ob zwischen Prüfen der Pointer und dem

Freigeben der Interrupts nicht noch ein Paket eingetroffen ist.

Sollte dies der Fall sein, beginnt man von vorne, die Interrupts werden gesperrt,

das Paket ausgelesen etc ([4], S.9).

 

Um Pakete zu empfangen muss der Empfänger einen Thread beim Treiber

anmelden. Dieser Thread wird gestartet, wenn ein Paket in die Liste der

empfangenen Pakete eingehängt wurde und wieder schlafen gelegt,

wenn die Liste leer ist oder der Empfänger keine Pakete mehr aufnehmen

kann.

Wird der Thread nicht von außerhalb gestoppt, läuft er so lange, bis kein Paket

mehr in der Liste übrig ist. Während der Thread läuft, liest er jeweils ein Paket

aus der Liste aus und gibt das Memory-Objekt mit dem Inhalt an den Empfänger

weiter. Damit der NE2000.java nicht die Memory-Objekte ausgehen, bekommt

der Thread im Gegenzug ein Memory-Objekt vom Empfänger zurück, in das

er später wieder ein anderes angekommenes Paket aufnehmen kann. 

Ist die Anzahl der Pakete, die im Treiber gespeichert werden können,

erschöpft, weil zu wenige Pakete abgeholt und immer neue empfangen

werden, wird automatisch immer das älteste Paket einfach mit einem

neueren überschrieben und geht verloren. Um die verlorenen Pakete muss sich

dann eine übergeordnete Schicht kümmern, d.h. sie muss eine Anfrage für

nochmaliges Übermitteln an den Sender stellen.

 

 

 

4.   Ausblick

 

Zum Abschluß erfolgt ein kleiner Ausblick, der zeigt, was bei der wirklichen

Implementierung des Treibers erreicht wurde. Zudem nennt er noch einige wünschenswerte Ergänzungen bzw. Modifizierungen.

 

Der Treiber läuft getestet mit 2 Karten, einer Realtek und einer Winbond.

Die Realtek läuft allerdings nicht sofort im NE2000-Modus, sondern es

müssen dafür noch gesonderte Einstellungen gemacht werden.

Daher benötigt sie auch einen eigenen Konstruktor.

 

Ein guter Ansatzpunkt zur Verbesserung wäre, den Interrupthandler wesentlich

zu verschlanken und z.B. das Auslesen eines Pakets aus dem Ringpuffer in

einem Thread durchzuführen, der vom Interrupthandler nur noch geweckt wird.

Somit müssten nicht während des gesamten Auslesens die Interrupts gesperrt

bleiben. Dies würde die Interruptlatenzzeit reduzieren.

Es war jedoch bei keinem einzigen Test mit einer realen Anwendung der Fall

war, dass die Nachrichten schneller kamen, als der Interrupthandler dies

bewältigen konnte. Die Liste für die eingehenden Nachrichten wuchs niemals.

Einzig und allein ein FloodPing ermöglichte uns überhaupt ein Prüfen dieser

Funktion. Aber auch damit lief der Treiber absolut stabil und konnte

schließlich nur durch einen überforderten Garbage Collector gestoppt werden.

 

Daraus ergibt sich abschließend, dass ein Treiber vorliegt, der im Detail sicher

noch Verbesserungen verträgt, aber auch jetzt schon seine Aufgabe mit

angemessener Performance und hoher Stabilität erledigt.

 

 

 

 

5.   Literaturliste

 

 

[1] AT/LANTIC Software Developer´s Guide

            National Semiconductor

Application Note 887

            David Milne

            May 1993

 

[2] DP8390 Network Interface Controller: An Introductory Guide

National Semiconductor

Application Note 475

May 1993

 

[3] DP83905EB-AT AT/LANTIC Hardware User´s Guide

National Semiconductor

Application Note 897

Larry Wakeman

July 1993

 

[4] Writing Drivers for the DP8390 NIC Family of Ethernet Controllers

National Semiconductor

Application Note 874

July 1993

 

[5] RTL8029AS

Realtek PCI Full-Duplex Ethernet Controller with built-in SRAM

Advanced Information

Realtek Semiconductor Corp.

 

[6] W89C940

ELANC-PCI (TWISTED-PAIR ETHER-LAN CONTROLLER WITH

PCI-INTERFACE)

Winbond

Electronics Corp.

 

 

 

 

 

  Impressum   Datenschutz Stand: 2004-03-22 10:52   Wa