MiniEthernetOneDriver.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
BLyon on: February 6, 1981 10:35 AM
Birrell, October 31, 1983 3:23 pm
Taft, January 3, 1984 5:12 pm
Russ Atkinson (RRA) February 20, 1985 6:31:56 pm PST
Hal Murray, June 3, 1986 3:57:09 pm PDT
If you make an edit in this module, consider making the same change in MiniEthernetDriver.
DIRECTORY
Basics USING [bytesPerWord],
Checksum USING [ComputeChecksum],
CommBuffer USING [],
CommDriverType USING [ethernetOneEncapsulationBytes, ethernetOneEncapsulationOffset, Encapsulation],
Endian USING [FWORD, HWORD, bytesPerHWord],
EthernetOneFace USING [GetHostNumber, GetNextDevice, GetStatusAndCollisions, GetStatusAndLength, Handle, IOCB, nullHandle, QueueInput, QueueOutput, TurnOff, TurnOn],
MiniEthernetDefs USING [timedOut],
PrincOpsUtils USING [LongCopy],
Pup USING [Address, allHosts, Host, Net, nullHost, nullNet, nullSocket, Socket],
PupBuffer USING [noChecksum, PupBufferPointer, WordsWithoutChecksum],
PupType USING [bytesOfPupOverhead, Type];
MiniEthernetOneDriver: PROGRAM
IMPORTS Checksum, EthernetOneFace, PrincOpsUtils, PupBuffer
EXPORTS CommBuffer, MiniEthernetDefs = {
Encapsulation: PUBLIC TYPE = CommDriverType.Encapsulation;
active: BOOLFALSE;
last: {in, out, reset};
myHost: Pup.Host;
myNet: Pup.Net;
Ethernet buffer. This is merely storage for MiniDriver
bufWords: CARDINAL = 300;
bufferBytes: CARDINAL = bufWords*Basics.bytesPerWord;
fudge: CARDINAL = 30;
eBuff: ARRAY [0..bufWords + fudge) OF WORD;
eBuffer: POINTER = LOOPHOLE[@eBuff];
b: PupBuffer.PupBufferPointer; -- Global buffer for actual data transfers
ether: EthernetOneFace.Handle;
longIocb: EthernetOneFace.IOCB;
bytesPerPupHeader: CARDINAL = PupType.bytesOfPupOverhead;
DriverNotActive: PUBLIC ERROR = CODE;
BufferOverflow: PUBLIC ERROR = CODE;
SendToStrangePlace: PUBLIC ERROR = CODE;
ReturnToStrangePlace: PUBLIC ERROR = CODE;
ActivateDriver: PUBLIC PROC [iocb: LONG POINTER] RETURNS [BOOL] = {
p: LONG POINTER ← @b.ovh.encap + CommDriverType.ethernetOneEncapsulationOffset;
q: LONG POINTER ← b;
fudge: LONG CARDINAL ← p - q;
IF ~FindTheBoard[] THEN RETURN[FALSE];
b ← eBuffer - fudge;
longIocb ← iocb;
myHost ← [EthernetOneFace.GetHostNumber[ether]];
myNet ← Pup.nullNet;
EthernetOneFace.TurnOn[ether, 0, 0];
active ← TRUE;
last ← reset;
RETURN[TRUE];
};
FindTheBoard: PROC RETURNS [BOOL] = {
ether ← EthernetOneFace.GetNextDevice[EthernetOneFace.nullHandle];
RETURN[ether # EthernetOneFace.nullHandle];
};
KillDriver: PUBLIC PROC = {
EthernetOneFace.TurnOff[ether];
active ← FALSE;
};
BorrowTheBuffer: PUBLIC PROC RETURNS [p: LONG POINTER, bytes: CARDINAL] = {
RETURN[eBuffer+fudge, bufferBytes];
};
SendPacket: PUBLIC PROC [dest: Pup.Address, me: Pup.Socket, type: PupType.Type, id: Endian.FWORD, data: LONG POINTER, bytes: CARDINAL] = {
words: CARDINAL = (bytes + Basics.bytesPerWord-1)/Basics.bytesPerWord;
SELECT TRUE FROM
dest.host = Pup.allHosts => b.ovh.encap.ethernetOneDest ← Pup.allHosts;
ENDCASE => ERROR SendToStrangePlace;
b.byteLength ← bytesPerPupHeader + bytes;
b.type ← type;
b.id ← id;
b.dest ← dest;
b.source.socket ← me;
PrincOpsUtils.LongCopy[to: @b.byte, from: data, nwords: words];
SendPupBuffer[];
};
ReturnPacket: PUBLIC PROC [type: PupType.Type, id: Endian.FWORD, data: LONG POINTER, bytes: CARDINAL] = {
words: CARDINAL = (bytes + Basics.bytesPerWord-1)/Basics.bytesPerWord;
temp: Pup.Socket;
IF last # in THEN ERROR ReturnToStrangePlace;
b.ovh.encap.ethernetOneDest ← b.ovh.encap.ethernetOneSource;
b.byteLength ← bytesPerPupHeader + bytes;
b.type ← type;
b.id ← id;
temp ← b.dest.socket;
b.dest ← b.source;
b.source.socket ← temp;
PrincOpsUtils.LongCopy[to: @b.byte, from: data, nwords: words];
SendPupBuffer[];
};
SendPupBuffer: PROC = {
b.hopCount ← 0;
b.spares ← 0;
b.source.net ← myNet;
b.source.host ← myHost;
SetPupChecksum[b];
b.ovh.encap.ethernetOneType ← pup;
SendBuffer[b.byteLength];
};
SendBuffer: PROC [bytes: CARDINAL] = {
IF ~active THEN ERROR DriverNotActive;
IF bytes > bufferBytes THEN ERROR BufferOverflow;
b.ovh.encap.ethernetOneSource ← myHost;
last ← out;
EthernetOneFace.QueueOutput[
ether,
@b.ovh.encap + CommDriverType.ethernetOneEncapsulationOffset,
bytes + CommDriverType.ethernetOneEncapsulationBytes,
longIocb];
THROUGH [0..LAST[CARDINAL]) DO
IF EthernetOneFace.GetStatusAndCollisions[longIocb].status # pending THEN EXIT;
REPEAT FINISHED => {
EthernetOneFace.TurnOff[ether];
EthernetOneFace.TurnOn[ether, 0, 0]; };
ENDLOOP;
};
RecvPacket: PUBLIC PROC [source: LONG POINTER TO Pup.Address, me: Pup.Socket, data: LONG POINTER, maxBytes: CARDINAL, timeout: PROC RETURNS [BOOL]] RETURNS [bytes: CARDINAL, id: Endian.FWORD, type: PupType.Type] = {
IF ~active THEN ERROR DriverNotActive;
DO
EthernetOneFace.QueueInput[
ether,
@b.ovh.encap + CommDriverType.ethernetOneEncapsulationOffset,
bufferBytes,
longIocb];
UNTIL EthernetOneFace.GetStatusAndLength[longIocb].status # pending DO
IF timeout[] THEN {
EthernetOneFace.TurnOff[ether];
EthernetOneFace.TurnOn[ether, 0, 0];
last ← reset;
RETURN[MiniEthernetDefs.timedOut, [0, 0], LOOPHOLE[0]];
};
ENDLOOP;
IF EthernetOneFace.GetStatusAndLength[longIocb].status # ok THEN LOOP;
bytes ← EthernetOneFace.GetStatusAndLength[longIocb].bytes;
IF b.ovh.encap.ethernetOneType # pup THEN LOOP;
should check words that arrived against pupLength?
check here for routing table if we ever get that complicated
IF myNet # Pup.nullNet AND myNet # b.dest.net AND b.dest.net # Pup.nullNet THEN LOOP;
IF myHost # b.dest.host THEN LOOP; -- Can't recv broadcast
IF me # b.dest.socket THEN LOOP;
IF source.net # Pup.nullNet AND source.net # b.source.net AND b.source.net # Pup.nullNet THEN
LOOP;
IF source.host # Pup.nullHost AND source.host # b.source.host THEN LOOP;
IF source.socket # Pup.nullSocket AND source.socket # b.source.socket THEN LOOP;
IF myNet = Pup.nullNet THEN myNet ← b.dest.net;
bytes ← b.byteLength - bytesPerPupHeader;
IF bytes > maxBytes THEN LOOP;
IF ~TestPupChecksum[b] THEN LOOP;
PrincOpsUtils.LongCopy[to: data, from: @b.byte, nwords: (bytes + 1)/2];
IF source.net = Pup.nullNet THEN source.net ← b.source.net;
IF source.host = Pup.nullHost THEN source.host ← b.source.host;
IF source.socket = Pup.nullSocket THEN source.socket ← b.source.socket;
last ← in;
RETURN[bytes, b.id, b.type];
ENDLOOP;
};
SetPupChecksum: PROC [b: PupBuffer.PupBufferPointer] = {
words: NAT = PupBuffer.WordsWithoutChecksum[b.byteLength];
checksumLoc: LONG POINTER TO Endian.HWORD ← @b.byteLength + words;
checksumLoc^ ← Checksum.ComputeChecksum[0, words, @b.byteLength];
};
TestPupChecksum: PROC [b: PupBuffer.PupBufferPointer] RETURNS [BOOL] = {
words: NAT = PupBuffer.WordsWithoutChecksum[b.byteLength];
checksumLoc: LONG POINTER TO Endian.HWORD ← @b.byteLength + words;
hisChecksum: Endian.HWORD ← checksumLoc^;
checksum: Endian.HWORD;
IF hisChecksum = PupBuffer.noChecksum THEN RETURN[TRUE];
checksum ← Checksum.ComputeChecksum[0, words, @b.byteLength];
RETURN[checksum = hisChecksum];
};
}.