MODULE Ethernet3Com90x;
IMPORT SYSTEM, Machine, KernelLog, Modules, Objects,
PCI, Plugins, Network, Kernel;
CONST
Name = "3Com90x#";
Desc = "3Com Etherlink XL ethernet driver";
MaxPkt = 1514;
MTU = MaxPkt-14;
EarlyThresh = MAX(LONGINT);
ReceiveBuffers = 128;
SendTimeout = 5*1000;
NewTries = 32;
MediaMask = {20..23};
Base10T = {}; Base10Coax = {21, 20};
MII = {22, 21}; Auto = {23};
Eprom230 = 0; InvertMIIPower = 1;
Model90x = 0; Model90xB = 1; Model90xC = 2;
TYPE
MemRangeArray = ARRAY 2 OF Machine.Range;
DPD = POINTER TO RECORD
dummy : CHAR;
nextPhysAdr: LONGINT;
status: SET;
frag: ARRAY 5 OF RECORD
dataPhysAdr: LONGINT;
dataLen: LONGINT
END;
dst, src: ARRAY 6 OF CHAR;
type: INTEGER;
physAdr: LONGINT;
END;
UPD = POINTER TO RECORD
dummy : CHAR;
nextPhysAdr: LONGINT;
status: SET;
frag: ARRAY 3 OF RECORD
dataPhysAdr: LONGINT;
dataLen: LONGINT
END;
dst, src: ARRAY 6 OF CHAR;
type: INTEGER;
physAdr: LONGINT;
buffer: Network.Buffer;
next: UPD;
END;
VAR
installed: LONGINT;
NdnTxReclaimError, NdnTxStatusOverflow, NdnMaxCollisions, NdnTxUnderrun, NdnTxJabber, NnewRetry,
NspuriousComplete, NupOverrun, NupRuntFrame, NupAlignmentError, NupCrcError, NupOversizedFrame,
NupOverflow, NbadSize, Ninterrupt, NintHostError, NintTxComplete, NintRxEarly, NintRequested,
NintUpdateStats, NintLinkEvent, NintDnComplete, NintUpComplete, NstatCarrierLost,
NstatSqeErrors, NstatMultipleCollisions, NstatSingleCollisions, NstatLateCollisions, NstatRxOverruns,
NstatFramesXmittedOk, NstatFramesRcvdOk, NstatFramesDeferred, NstatBytesRcvdOk,
NstatBytesXmittedOk, NstatBadSSD, NupCompleteLoops, NsendTimeouts: LONGINT;
TYPE
Timer = OBJECT (Kernel.Timer)
VAR
ms: LONGINT;
c: Controller;
quit: BOOLEAN;
PROCEDURE &Init2*(c: Controller);
BEGIN
SELF.c := c; SELF.quit := FALSE; SELF.ms := 1;
Init
END Init2;
BEGIN {ACTIVE}
WHILE ~quit DO
c.HandleInterrupt();
Sleep(ms);
END
END Timer;
Controller* = OBJECT
VAR
base, irq*: LONGINT;
dev: LinkDevice;
flags: SET;
model: LONGINT;
media: SET;
dpd: DPD;
upd: UPD;
bus, pdev, fct: LONGINT;
interrupted: BOOLEAN;
timer: Timer;
PROCEDURE HandleInterrupt;
VAR type, len: LONGINT; status: SET; int: INTEGER; ch: CHAR; buf: Network.Buffer;
BEGIN
interrupted := TRUE;
Machine.AtomicInc(Ninterrupt);
Machine.Portin16(base+0EH, SYSTEM.VAL(INTEGER, status));
IF 1 IN status THEN
Machine.AtomicInc(NintHostError)
END;
IF 2 IN status THEN
Machine.AtomicInc(NintTxComplete);
Machine.Portout8(base+1BH, 0X)
END;
IF 5 IN status THEN
Machine.AtomicInc(NintRxEarly)
END;
IF 6 IN status THEN
Machine.AtomicInc(NintRequested)
END;
IF 7 IN status THEN
Machine.AtomicInc(NintUpdateStats);
SetWindow(base, 6);
Machine.Portin8(base+0, ch); Machine.AtomicAdd(NstatCarrierLost, ORD(ch));
Machine.Portin8(base+1, ch); Machine.AtomicAdd(NstatSqeErrors, ORD(ch));
Machine.Portin8(base+2, ch); Machine.AtomicAdd(NstatMultipleCollisions, ORD(ch));
Machine.Portin8(base+3, ch); Machine.AtomicAdd(NstatSingleCollisions, ORD(ch));
Machine.Portin8(base+4, ch); Machine.AtomicAdd(NstatLateCollisions, ORD(ch));
Machine.Portin8(base+5, ch); Machine.AtomicAdd(NstatRxOverruns, ORD(ch));
Machine.Portin8(base+6, ch); Machine.AtomicAdd(NstatFramesXmittedOk, ORD(ch));
Machine.Portin8(base+7, ch); Machine.AtomicAdd(NstatFramesRcvdOk, ORD(ch));
Machine.Portin8(base+9, ch);
Machine.AtomicAdd(NstatFramesXmittedOk, ORD(ch) DIV 16 MOD 16 * 100H);
Machine.AtomicAdd(NstatFramesRcvdOk, ORD(ch) MOD 16 * 100H);
Machine.Portin8(base+8, ch); Machine.AtomicAdd(NstatFramesDeferred, ORD(ch));
Machine.Portin16(base+0AH, int); Machine.AtomicAdd(NstatBytesRcvdOk, LONG(int) MOD 10000H);
Machine.Portin16(base+0CH, int); Machine.AtomicAdd(NstatBytesXmittedOk, LONG(int) MOD 10000H);
SetWindow(base, 4);
Machine.Portin8(base+0CH, ch); Machine.AtomicAdd(NstatBadSSD, ORD(ch));
Machine.Portin8(base+0DH, ch);
Machine.AtomicAdd(NstatBytesXmittedOk, ORD(ch) DIV 16 MOD 16 * 10000H);
Machine.AtomicAdd(NstatBytesRcvdOk, ORD(ch) MOD 16 * 10000H)
END;
IF 8 IN status THEN
Machine.AtomicInc(NintLinkEvent)
END;
IF 9 IN status THEN
Machine.AtomicInc(NintDnComplete)
END;
IF 10 IN status THEN
Machine.AtomicInc(NintUpComplete);
IF 15 IN upd.status THEN
REPEAT
Machine.AtomicInc(NupCompleteLoops);
IF upd.status * {14,16..20,24} = {} THEN
len := SYSTEM.VAL(LONGINT, upd.status * {0..12}) - 14;
IF (len >= 60-14) & (len <= MTU) THEN
buf := upd.buffer;
IF buf # NIL THEN
buf := upd.buffer;
type := LONG(SYSTEM.ROT(upd.type, 8)) MOD 10000H;
buf.ofs := 0;
buf.len := len;
buf.calcChecksum := {};
buf.src := SYSTEM.VAL(Network.LinkAdr, upd.src);
dev.QueueBuffer(buf, type);
ELSE
Machine.AtomicInc(NupOverflow);
END;
BufferToUPD(Network.GetNewBuffer(), upd);
ELSE
Machine.AtomicInc(NbadSize)
END
ELSE
ASSERT((14 IN upd.status) & (upd.status * {16..20,24} # {}));
IF 16 IN upd.status THEN Machine.AtomicInc(NupOverrun) END;
IF 17 IN upd.status THEN Machine.AtomicInc(NupRuntFrame) END;
IF 18 IN upd.status THEN Machine.AtomicInc(NupAlignmentError) END;
IF 19 IN upd.status THEN Machine.AtomicInc(NupCrcError) END;
IF 20 IN upd.status THEN Machine.AtomicInc(NupOversizedFrame) END;
IF 24 IN upd.status THEN Machine.AtomicInc(NupOverflow) END
END;
upd.status := {}; upd := upd.next;
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 3001H))
UNTIL ~(15 IN upd.status)
ELSE
Machine.AtomicInc(NspuriousComplete)
END
END;
IF status * {0, 5, 6, 9, 10} # {} THEN
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SHORT(6800H +
SYSTEM.VAL(LONGINT, status * {0, 5, 6, 9, 10}))))
END
END HandleInterrupt;
PROCEDURE &Init*(dev: LinkDevice; base, irq, model: LONGINT; flags, media: SET);
VAR res, i: LONGINT;
BEGIN
SELF.interrupted := FALSE;
SELF.base := base; SELF.irq := irq; SELF.dev := dev; SELF.model := model; SELF.media := media;
SELF.flags := flags;
dev.ctrl := SELF;
InitDPD(dpd);
InitUPD(upd);
InitAddress(dev);
SYSTEM.MOVE(SYSTEM.ADR(dev.local[0]), SYSTEM.ADR(dpd.src[0]), 6);
InitInterface(SELF);
InitRegisters(SELF);
IF (irq >= 1) & (irq <= 15) THEN
KernelLog.Enter; KernelLog.String("Install Handler IRQ = "); KernelLog.Hex(irq, -3); KernelLog.Exit;
Objects.InstallHandler(SELF.HandleInterrupt, Machine.IRQ0+irq)
END;
Network.registry.Add(dev, res);
ASSERT(res = Plugins.Ok);
INC(installed);
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 6000H));
i := 0;
WHILE (i < 100) & ~interrupted DO
Objects.Yield;
INC(i)
END;
IF ~interrupted THEN
KernelLog.Enter; KernelLog.String("Install Timer"); KernelLog.Exit;
NEW(timer, SELF)
ELSE
KernelLog.Enter; KernelLog.String("No need for Timer"); KernelLog.Exit
END
END Init;
PROCEDURE Finalize;
VAR item: UPD;
BEGIN {EXCLUSIVE}
IF timer # NIL THEN
KernelLog.Enter; KernelLog.String("Remove Timer"); KernelLog.Exit;
timer.quit := TRUE
END;
ResetTx(base);
ResetRx(SELF, FALSE);
Objects.RemoveHandler(HandleInterrupt, Machine.IRQ0+irq);
Network.registry.Remove(dev);
dev.ctrl := NIL; dev := NIL;
item := upd;
REPEAT
Network.ReturnBuffer(item.buffer);
item.buffer := NIL;
item := item.next;
UNTIL item = upd;
END Finalize;
END Controller;
TYPE
LinkDevice* = OBJECT (Network.LinkDevice)
VAR
hdr: ARRAY Network.MaxPacketSize OF CHAR;
ctrl*: Controller;
PROCEDURE DoSend(dst: Network.LinkAdr; type: LONGINT; VAR l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
VAR
dpd: DPD;
t: Kernel.MilliTimer;
h3n, h4n, dn, hn, hlen, len, base, i: LONGINT;
h3phys, h4phys, dphys, hphys: MemRangeArray;
PROCEDURE PutToDPD(n: LONGINT; VAR phys: MemRangeArray);
VAR j: LONGINT;
BEGIN
FOR j := 0 TO n-1 DO
dpd.frag[i].dataPhysAdr := Machine.Ensure32BitAddress (phys[j].adr);
dpd.frag[i].dataLen := Machine.Ensure32BitAddress (phys[j].size);
INC(i);
END;
END PutToDPD;
BEGIN {EXCLUSIVE}
base := ctrl.base; dpd := ctrl.dpd;
SYSTEM.MOVE(SYSTEM.ADR(dst[0]), SYSTEM.ADR(dpd.dst[0]), 6);
dpd.type := SYSTEM.ROT(SHORT(type), 8);
IssueCommand(base, 3002H);
CheckTransmission(base);
Machine.TranslateVirtual(SYSTEM.ADR(l3hdr[0]), h3len, h3n, h3phys);
Machine.TranslateVirtual(SYSTEM.ADR(l4hdr[0]), h4len, h4n, h4phys);
Machine.TranslateVirtual(SYSTEM.ADR(data[dofs]), dlen, dn, dphys);
ASSERT(h3n <= 2);
ASSERT(h4n <= 2);
ASSERT(dn <= 2);
i := 1;
IF h3n + h4n + dn > 4 THEN
Network.Copy(l3hdr, hdr, 0, 0, h3len);
Network.Copy(l4hdr, hdr, 0, h3len, h4len);
hlen := h3len + h4len;
Machine.TranslateVirtual(SYSTEM.ADR(hdr[0]), hlen, hn, hphys);
PutToDPD(hn, hphys);
ELSE
PutToDPD(h3n, h3phys);
PutToDPD(h4n, h4phys);
END;
PutToDPD(dn, dphys);
INC(dpd.frag[i-1].dataLen, SHORT(80000000H));
len := h3len + h4len + len +14;
ASSERT((len >= 14) & (len <= MaxPkt));
dpd.status := SYSTEM.VAL(SET, len);
Machine.Portout32(base+24H, dpd.physAdr);
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 3003H));
Kernel.SetTimer(t, SendTimeout);
REPEAT
Machine.Portin32(base+24H, i)
UNTIL (i = 0) OR Kernel.Expired(t);
IF i # 0 THEN Machine.AtomicInc(NsendTimeouts) END;
INC(sendCount)
END DoSend;
PROCEDURE Finalize(connected: BOOLEAN);
BEGIN
ctrl.Finalize;
Finalize^(connected);
END Finalize;
END LinkDevice;
PROCEDURE SetWindow(base, window: LONGINT);
BEGIN
ASSERT((0 <= window) & (window <= 7));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SHORT(800H + window)))
END SetWindow;
PROCEDURE ReadConfig(base, reg: LONGINT; flags: SET; VAR word: INTEGER);
VAR x: INTEGER;
BEGIN
ASSERT((0 <= reg) & (reg < 64));
SetWindow(base, 0);
IF Eprom230 IN flags THEN INC(reg, 230H) ELSE INC(reg, 80H) END;
Machine.Portout16(base+0AH, SYSTEM.VAL(INTEGER, SHORT(reg)));
REPEAT
Machine.Portin16(base+0AH, x)
UNTIL ~(15 IN SYSTEM.VAL(SET, LONG(x)));
Machine.Portin16(base+0CH, word)
END ReadConfig;
PROCEDURE InitAddress(d: LinkDevice);
VAR base, i: LONGINT; flags: SET; word: ARRAY 3 OF INTEGER;
BEGIN
base := d.ctrl.base;
flags := d.ctrl.flags;
ReadConfig(base, 0AH, flags, word[0]);
ReadConfig(base, 0BH, flags, word[1]);
ReadConfig(base, 0CH, flags, word[2]);
SetWindow(base, 2);
FOR i := 0 TO 2 DO
word[i] := SYSTEM.ROT(word[i], 8);
d.local[2*i] := CHR(word[i] MOD 100H);
d.local[2*i+1] := CHR(word[i] DIV 100H MOD 100H);
Machine.Portout16(base+2*i, word[i]);
Machine.Portout16(base+6+2*i, SYSTEM.VAL(INTEGER, 0))
END;
FOR i := 0 TO 5 DO d.broadcast[i] := 0FFX END
END InitAddress;
PROCEDURE GetSetting(s: ARRAY OF CHAR): LONGINT;
VAR i: LONGINT; name, val: ARRAY 32 OF CHAR;
BEGIN
i := 0; WHILE s[i] # 0X DO name[i] := s[i]; INC(i) END;
name[i] := CHR(ORD("0") + installed); name[i+1] := 0X;
Machine.GetConfig(name, val);
IF val[0] = 0X THEN
name[i] := 0X; Machine.GetConfig(name, val)
END;
i := 0;
RETURN Machine.StrToInt(i, val)
END GetSetting;
PROCEDURE InitInterface(ctrl: Controller);
VAR config: SET; base, media: LONGINT;
BEGIN
base := ctrl.base;
SetWindow(base, 3);
Machine.Portin32(base, SYSTEM.VAL (LONGINT, config));
media := GetSetting("3C90xMedia");
IF media # 0 THEN
ASSERT((media >= 1) & (media <= 9));
ctrl.media := SYSTEM.VAL(SET, SYSTEM.LSH(media-1, 20)) * MediaMask;
Machine.Portout32(base, SYSTEM.VAL (LONGINT, config - MediaMask + ctrl.media))
ELSIF ~(24 IN config) THEN
ctrl.media := config * MediaMask
ELSE
media := SYSTEM.VAL(LONGINT, ctrl.media);
Machine.Portout32(base, SYSTEM.VAL (LONGINT, config - MediaMask + ctrl.media));
KernelLog.Enter; KernelLog.String(ctrl.dev.name); KernelLog.String(" auto-selection not supported"); KernelLog.Exit;
END
;KernelLog.Enter; KernelLog.String("Media = "); KernelLog.Hex(media, 0); KernelLog.Exit;
END InitInterface;
PROCEDURE IssueCommand(base, cmd: LONGINT);
VAR word: INTEGER;
BEGIN
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SHORT(cmd)));
REPEAT
Machine.Portin16(base+0EH, word)
UNTIL ~(12 IN SYSTEM.VAL(SET, LONG(word)))
END IssueCommand;
PROCEDURE ResetTx(base: LONGINT);
BEGIN
IssueCommand(base, 5800H);
Machine.Portout32(base+24H, SYSTEM.VAL(LONGINT, 0))
END ResetTx;
PROCEDURE ResetRx(ctrl: Controller; setThresh: BOOLEAN);
VAR base: LONGINT;
BEGIN
base := ctrl.base;
IssueCommand(base, 2800H);
IF setThresh THEN
IF EarlyThresh DIV 4 > 7FFH THEN
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 8FFFH));
Machine.Portout32(base+20H, SYSTEM.VAL(LONGINT, 0H))
ELSE
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 8800H + EarlyThresh DIV 4));
Machine.Portout32(base+20H, SYSTEM.VAL(LONGINT, 20H))
END
END;
Machine.Portout32(base+38H, ctrl.upd.physAdr);
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 8007H))
END ResetRx;
PROCEDURE CheckTransmission(base: LONGINT);
VAR status: SET; enable, reset: BOOLEAN; ch: CHAR;
BEGIN
enable := FALSE; reset := FALSE;
LOOP
Machine.Portin8(base+1BH, ch);
status := SYSTEM.VAL(SET, LONG(ORD(ch)));
IF ~(7 IN status) THEN EXIT END;
IF 1 IN status THEN Machine.AtomicInc(NdnTxReclaimError) END;
IF 2 IN status THEN Machine.AtomicInc(NdnTxStatusOverflow); enable := TRUE END;
IF 3 IN status THEN Machine.AtomicInc(NdnMaxCollisions); enable := TRUE END;
IF 4 IN status THEN Machine.AtomicInc(NdnTxUnderrun); reset := TRUE END;
IF 5 IN status THEN Machine.AtomicInc(NdnTxJabber); reset := TRUE END;
Machine.Portout8(base+1BH, ch)
END;
IF reset THEN IssueCommand(base, 5800H); enable := TRUE END;
IF enable THEN Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 4800H)) END
END CheckTransmission;
PROCEDURE InitDPD(VAR dpd: DPD);
VAR i, n: LONGINT; phys: MemRangeArray;
BEGIN
i := 0;
LOOP
NEW(dpd);
Machine.TranslateVirtual(SYSTEM.ADR(dpd.nextPhysAdr), SYSTEM.SIZEOF(DPD), n, phys);
IF n = 1 THEN EXIT END;
INC(i); Machine.AtomicInc(NnewRetry);
IF i = NewTries THEN HALT(3802) END
END;
ASSERT(phys[0].size = SYSTEM.SIZEOF(DPD));
dpd.physAdr := Machine.Ensure32BitAddress (phys[0].adr);
ASSERT(dpd.physAdr MOD 8 = 0);
dpd.nextPhysAdr := 0;
dpd.frag[0].dataPhysAdr := Machine.Ensure32BitAddress ((SYSTEM.ADR(dpd.dst[0])-SYSTEM.ADR(dpd.nextPhysAdr)) + dpd.physAdr);
dpd.frag[0].dataLen := 14
END InitDPD;
PROCEDURE InitUPD(VAR upd: UPD);
VAR i, j, n: LONGINT; head, tail: UPD; phys: MemRangeArray;
BEGIN
head := NIL; tail := NIL;
FOR j := 1 TO ReceiveBuffers DO
i := 0;
LOOP
NEW(upd);
Machine.TranslateVirtual(SYSTEM.ADR(upd.nextPhysAdr), SYSTEM.SIZEOF(UPD), n, phys);
IF n = 1 THEN EXIT END;
INC(i); Machine.AtomicInc(NnewRetry);
IF i = NewTries THEN HALT(3803) END
END;
ASSERT(phys[0].size = SYSTEM.SIZEOF(UPD));
upd.physAdr := Machine.Ensure32BitAddress (phys[0].adr);
ASSERT(upd.physAdr MOD 8 = 0);
upd.status := {};
upd.frag[0].dataPhysAdr := Machine.Ensure32BitAddress ((SYSTEM.ADR(upd.dst[0])-SYSTEM.ADR(upd.nextPhysAdr)) + upd.physAdr);
upd.frag[0].dataLen := 14;
BufferToUPD(Network.GetNewBuffer(), upd);
IF head # NIL THEN
upd.next := head; upd.nextPhysAdr := head.physAdr
ELSE
upd.next := NIL; upd.nextPhysAdr := 0; tail := upd
END;
head := upd
END;
tail.next := head; tail.nextPhysAdr := head.physAdr
END InitUPD;
PROCEDURE BufferToUPD(buffer: Network.Buffer; upd: UPD);
VAR
n, i: LONGINT;
phys: MemRangeArray;
BEGIN
ASSERT(upd # NIL);
IF buffer # NIL THEN
Machine.TranslateVirtual(SYSTEM.ADR(buffer.data[0]), LEN(buffer.data), n, phys);
ASSERT(n <= 2);
FOR i := 1 TO n DO
upd.frag[i].dataPhysAdr := Machine.Ensure32BitAddress (phys[i-1].adr); upd.frag[i].dataLen := Machine.Ensure32BitAddress (phys[i-1].size)
END;
INC(upd.frag[n].dataLen, SHORT(80000000H));
ELSE
upd.frag[0].dataLen := 14;
INC(upd.frag[0].dataLen, SHORT(80000000H));
END;
upd.buffer := buffer;
END BufferToUPD;
PROCEDURE InitRegisters(ctrl: Controller);
VAR base, duplex, i: LONGINT; word: INTEGER; full: BOOLEAN; ch: CHAR; flags: SET;
BEGIN
base := ctrl.base;
flags := ctrl.flags;
IF InvertMIIPower IN flags THEN
SetWindow(base, 2);
Machine.Portin16(base+0CH, word);
word := SHORT(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, LONG(word)) + {14}));
Machine.Portout16(base+0CH, word);
KernelLog.Enter; KernelLog.String("Invert MII Power "); KernelLog.Hex(word, 0); KernelLog.Exit;
END;
IF ctrl.media = Base10Coax THEN
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 1000H))
ELSE
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 0B800H))
END;
duplex := GetSetting("3C90xDuplex");
IF duplex = 0 THEN
ReadConfig(base, 0DH, flags, word);
full := (15 IN SYSTEM.VAL(SET, LONG(word)))
ELSE
full := (duplex = 2)
END;
SetWindow(base, 3);
IF full THEN
KernelLog.Enter; KernelLog.String(ctrl.dev.name); KernelLog.String(" full-duplex"); KernelLog.Exit;
Machine.Portout16(base+6, SYSTEM.VAL(INTEGER, 20H))
ELSE
KernelLog.Enter; KernelLog.String(ctrl.dev.name); KernelLog.String(" half-duplex"); KernelLog.Exit;
Machine.Portout16(base+6, SYSTEM.VAL(INTEGER, 0))
END;
ResetTx(base);
ResetRx(ctrl, TRUE);
SetWindow(base, 7);
IF ctrl.model = Model90x THEN
Machine.Portout8(base+2FH, CHR((MaxPkt+255) DIV 256))
END;
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 7FF6H));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SYSTEM.VAL(LONGINT, {1, 6, 7, 10}) + 7000H));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 6F69H));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 0B000H));
SetWindow(base, 5);
Machine.Portin16(base+0AH, word);
KernelLog.Enter; KernelLog.String("IntEnable = "); KernelLog.Hex(word, 4); KernelLog.Exit;
SetWindow(base, 6);
FOR i := 0 TO 9 DO Machine.Portin8(base+i, ch) END;
Machine.Portin16(base+0AH, word);
Machine.Portin16(base+0CH, word);
SetWindow(base, 4);
Machine.Portin8(base+0CH, ch);
Machine.Portin8(base+0DH, ch);
Machine.Portin16(base+6, word);
Machine.Portout16(base+6, SYSTEM.VAL(INTEGER, SHORT(SYSTEM.VAL(LONGINT,
SYSTEM.VAL(SET, LONG(word)) + {6}))));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 0A800H));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 2000H));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 4800H));
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 3001H))
END InitRegisters;
PROCEDURE ScanPCI(vendor, device, model: LONGINT; flags, media: SET);
VAR index, bus, dev, fct, res, base, irq, i: LONGINT; d: LinkDevice; c: Controller; name: Plugins.Name;
BEGIN
index := 0;
WHILE (PCI.FindPCIDevice(device, vendor, index, bus, dev, fct) = PCI.Done) & (installed < 10) DO
res := PCI.ReadConfigDword(bus, dev, fct, PCI.Adr0Reg, base); ASSERT(res = PCI.Done);
ASSERT(ODD(base)); DEC(base);
res := PCI.ReadConfigByte(bus, dev, fct, PCI.IntlReg, irq); ASSERT(res = PCI.Done);
NEW(d, Network.TypeEthernet, MTU, 6);
name := Name;
i := 0; WHILE name[i] # 0X DO INC(i) END;
name[i] := CHR(ORD("0") + installed);
name[i+1] := 0X;
d.SetName(name);
d.desc := Desc;
NEW(c, d, base, irq, model, flags, media);
c.bus := bus; c.pdev := dev; c.fct := fct;
INC(index)
END
END ScanPCI;
PROCEDURE Install*;
BEGIN {EXCLUSIVE}
IF installed = 0 THEN
ScanPCI(10B7H, 9200H, Model90xC, {}, Auto);
ScanPCI(10B7H, 6055H, Model90xB, {Eprom230, InvertMIIPower}, MII);
ScanPCI(10B7H, 9055H, Model90xB, {}, Auto);
ScanPCI(10B7H, 9056H, Model90xB, {}, MII);
ScanPCI(10B7H, 9004H, Model90xB, {}, Auto);
ScanPCI(10B7H, 9005H, Model90xB, {}, Auto);
ScanPCI(10B7H, 9050H, Model90x, {}, MII);
ScanPCI(10B7H, 9000H, Model90x, {}, Base10T);
ScanPCI(10B7H, 9001H, Model90x, {}, Base10T)
END;
END Install;
PROCEDURE Remove*;
VAR table: Plugins.Table; i: LONGINT;
BEGIN {EXCLUSIVE}
Network.registry.GetAll(table);
IF table # NIL THEN
FOR i := 0 TO LEN(table)-1 DO
IF table[i] IS LinkDevice THEN table[i](LinkDevice).Finalize(TRUE) END
END
END;
installed := 0;
END Remove;
PROCEDURE Kick*;
VAR i, base: LONGINT; table: Plugins.Table;
BEGIN
Network.registry.GetAll(table);
IF table # NIL THEN
FOR i := 0 TO LEN(table)-1 DO
IF table[i] IS LinkDevice THEN
base := table[i](LinkDevice).ctrl.base;
KernelLog.Enter; KernelLog.String(table[i].name); KernelLog.Exit;
Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 6000H));
END
END
END;
END Kick;
PROCEDURE Dump*;
VAR i, base, win: LONGINT; int: INTEGER; table: Plugins.Table;
PROCEDURE Byte(reg: ARRAY OF CHAR; ofs: LONGINT);
VAR x: CHAR;
BEGIN
KernelLog.String(reg); KernelLog.Char("=");
Machine.Portin8(base+ofs, x);
KernelLog.Hex(ORD(x), -2); KernelLog.Char(" ")
END Byte;
PROCEDURE Word(reg: ARRAY OF CHAR; ofs: LONGINT);
VAR x: INTEGER;
BEGIN
KernelLog.String(reg); KernelLog.Char("=");
Machine.Portin16(base+ofs, x);
KernelLog.Hex(LONG(x) MOD 10000H, 8); KernelLog.Char(" ")
END Word;
PROCEDURE DWord(reg: ARRAY OF CHAR; ofs: LONGINT);
VAR x: LONGINT;
BEGIN
KernelLog.String(reg); KernelLog.Char("=");
Machine.Portin32(base+ofs, x);
KernelLog.Hex(x, 8); KernelLog.Char(" ")
END DWord;
PROCEDURE PCIWord(reg: ARRAY OF CHAR; ofs: LONGINT);
VAR x, res: LONGINT; ctrl: Controller;
BEGIN
ctrl := table[i](LinkDevice).ctrl;
KernelLog.String(reg); KernelLog.Char("=");
res := PCI.ReadConfigWord(ctrl.bus, ctrl.pdev, ctrl.fct, ofs, x);
KernelLog.Hex(x MOD 10000H, 8); KernelLog.Char(" ")
END PCIWord;
BEGIN
Network.registry.GetAll(table);
IF table # NIL THEN
FOR i := 0 TO LEN(table)-1 DO
IF table[i] IS LinkDevice THEN
base := table[i](LinkDevice).ctrl.base;
KernelLog.Enter;
KernelLog.String(table[i].name); KernelLog.Char(" ");
Machine.Portin16(base+0EH, int); win := ASH(int, -13) MOD 8;
KernelLog.String("Window="); KernelLog.Int(win, 1); KernelLog.Char(" ");
Byte("TxPktId", 18H); Byte("Timer", 1AH); Byte("TxStatus", 1BH);
DWord("DmaCtrl", 20H);
DWord("DnListPtr", 24H); Byte("DnBurstThresh", 2AH);
Byte("DnPriorityThresh", 2CH); Byte("DnPoll", 2DH);
DWord("UpPktStatus", 30H); Word("FreeTimer", 34H);
Word("Countdown", 36H); DWord("UpListPtr", 38H);
Byte("UpPriorityThresh", 3CH); Byte("UpPoll", 3DH);
Byte("UpBurstThresh", 3EH); DWord("RealTimeCnt", 40H);
Word("DnMaxBurst", 78H); Word("UpMaxBurst", 7AH);
SetWindow(base, 0);
DWord("0.BiosRomAddr", 4); Byte("0.BiosRomData", 8);
Word("0.EepromCommand", 0AH); Word("0.EepromData", 0CH);
Word("0.IntStatus", 0EH);
SetWindow(base, 1);
Word("1.IntStatus", 0EH);
SetWindow(base, 2);
Word("2.StationAddress-0", 0); Word("2.StationAddress-2", 2); Word("2.StationAddress-4", 4);
Word("2.StationMask-0", 6); Word("2.StationMask-2", 8); Word("2.StationMask-4", 0AH);
Word("2.ResetOptions", 0CH); Word("2.IntStatus", 0EH);
SetWindow(base, 3);
DWord("3.InternalConfig", 0); Word("3.MaxPktSize", 4);
Word("3.MacControl", 6); Word("3.MediaOptions", 8);
Word("3.RxFree", 0AH); Word("3.TxFree", 0CH);
Word("3.IntStatus", 0EH);
SetWindow(base, 4);
Word("4.VcoDiagnostic", 2); Word("4.FifoDiagnostic", 4);
Word("4.NetworkDiagnostic", 6); Word("4.PhysicalMgmt", 8);
Word("4.MediaStatus", 0AH); Byte("4.BadSSD", 0CH);
Byte("4.UpperBytesOk", 0DH); Word("4.IntStatus", 0EH);
SetWindow(base, 5);
Word("5.TxStartThresh", 0); Word("5.RxEarlyThresh", 6);
Byte("5.RxFilter", 8); Byte("5.TxReclaimThresh", 9);
Word("5.InterruptEnable", 0AH); Word("5.IndicationEnable", 0CH);
Word("5.IntStatus", 0EH);
SetWindow(base, 6);
Byte("6.CarrierLost", 0); Byte("6.SqeErrors", 1);
Byte("6.MultipleCollisions", 2); Byte("6.SingleCollisions", 3);
Byte("6.LateCollisions", 4); Byte("6.RxOverruns", 5);
Byte("6.FramesXmittedOk", 6); Byte("6.FramesRcvdOk", 7);
Byte("6.FramesDeferred", 8); Byte("6.UpperFramesOk", 9);
Word("6.BytesRcvdOk", 0AH); Word("6.BytesXmittedOk", 0CH);
Word("6.IntStatus", 0EH);
SetWindow(base, 7);
Word("7.VlanMask", 0); Word("7.VlanEtherType", 4);
Word("7.PowerMgmtEvent", 0CH); Word("7.IntStatus", 0EH);
SetWindow(base, win);
Byte("Timer", 1AH); Byte("TxStatus", 1BH);
DWord("DMACtrl", 20H); DWord("DnListPtr", 24);
Byte("DnBurstThresh", 2AH);
Byte("DnPriorityThresh", 2CH); Byte("DnPoll", 2DH);
DWord("UpPktStatus", 30H);
Word("FreeTimer", 34H); Word("Countdown", 36H);
DWord("UpListPtr", 38H);
Byte("UpPriorityThresh", 3CH); Byte("UpPoll", 3DH); Byte("UpBurstThresh", 3EH);
DWord("RealTimeCnt", 40H);
Word("DnMaxBurst", 78H); Word("UpMaxBurst", 7AH);
PCIWord("Status", 02H);
KernelLog.Exit
END
END
END;
END Dump;
PROCEDURE Cleanup;
BEGIN
IF Modules.shutdown = Modules.None THEN
Remove;
END
END Cleanup;
BEGIN
installed := 0;
Modules.InstallTermHandler(Cleanup)
END Ethernet3Com90x.
(*
History:
17.10.2003 mvt Changed for new Network interface
05.11.2003 mvt Implemented DMA directly to Network.Buffer
! System.Free Ethernet3Com90x ~
Aos.Call Ethernet3Com90x.Install
Aos.Call Ethernet3Com90x.Remove
TestNet.ShowDevices
TestNet.SetDevice "3Com90x#0"
TestNet.SendBroadcast
TestNet.SendTest 1
System.State Ethernet3Com90x ~
Aos.Call Ethernet3Com90x.Kick
Aos.Call Ethernet3Com90x.Kick2
Aos.Call Ethernet3Com90x.Dump
Aos.Call Ethernet3Com90x.TestCount 100000
NetSystem.Start
NetSystem.Stop
ftp://reali@lillian.ethz.ch
*)