MiniEthernetDriver.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
DIRECTORY
BufferDefs USING [PupBuffer],
DriverTypes USING [ethernetEncapsulationOffset],
EthernetOneFace USING [AddCleanup, ControlBlock, DeviceHandle, GetEthernet1Address, GetNextDevice, GetStatus, GlobalStatePtr, nullDeviceHandle, QueueInput, QueueOutput, RemoveCleanup, TurnOff, TurnOn],
MiniEthernetDefs USING [timedOut],
PrincOpsUtils USING [LongCopy],
PupTypes USING [Pair, PupAddress, PupHostID, PupNetID, PupSocketID, PupType];
MiniEthernetDriver: PROGRAM
IMPORTS PrincOpsUtils, EthernetOneFace
EXPORTS MiniEthernetDefs
SHARES BufferDefs
= { OPEN EthernetOneFace;
active: BOOLFALSE;
last: {in, out, reset};
knowBoardLocation: BOOLFALSE;
myHost: PupTypes.PupHostID;
myNet: PupTypes.PupNetID;
hisEtherHost: PupTypes.PupHostID; -- separate value in case we are talking through a gateway
hisNet: PupTypes.PupNetID;
b: BufferDefs.PupBuffer; -- Global buffer for actual data transfers
bufferSize: CARDINAL;
ether: DeviceHandle;
longIocb: ControlBlock;
global: GlobalStatePtr;
wordsPerPupHeader: CARDINAL = 11;
bytesPerPupHeader: CARDINAL = wordsPerPupHeader*2;
BoardLocationUnknown: PUBLIC ERROR = CODE;
DriverNotActive: PUBLIC ERROR = CODE;
BufferOverflow: PUBLIC ERROR = CODE;
ReturnToStrangePlace: PUBLIC ERROR = CODE;
ActivateDriver: PUBLIC PROC [ dataBuffer: LONG POINTER, length: CARDINAL, iocb: LONG POINTER, avoidCleanup: BOOLFALSE] RETURNS [BOOL] = {
p: LONG POINTER ← @b.encapsulation + DriverTypes.ethernetEncapsulationOffset;
q: LONG POINTER ← b;
fudge: LONG CARDINAL ← p - q;
net, host: CARDINAL;
IF ~FindTheBoard[] THEN RETURN[FALSE];
knowBoardLocation ← TRUE;
b ← dataBuffer - fudge;
bufferSize ← length;
longIocb ← iocb;
[net, host] ← GetEthernet1Address[ether];
myHost ← [host];
myNet ← [net];
hisNet ← [0];
IF ~avoidCleanup THEN AddCleanup[ether];
allocate global storage
TurnOn[ether, myHost, 0, 0, global];
active ← TRUE;
last ← reset;
RETURN[TRUE];
};
KillDriver: PUBLIC PROC [avoidCleanup: BOOLFALSE] = {
TurnOff[ether];
IF ~avoidCleanup THEN RemoveCleanup[ether];
knowBoardLocation ← FALSE;
};
GetEthernetHostNumber: PUBLIC PROC RETURNS [CARDINAL] = {
net, host: CARDINAL;
IF NOT knowBoardLocation THEN ERROR BoardLocationUnknown;
[net, host] ← GetEthernet1Address[ether];
RETURN[host];
};
GetEthernetNetNumber: PUBLIC PROC RETURNS [CARDINAL] = {
net, host: CARDINAL;
IF NOT knowBoardLocation THEN ERROR BoardLocationUnknown;
[net, host] ← GetEthernet1Address[ether];
RETURN[IF active THEN myNet ELSE net];
};
FindTheBoard: PROC RETURNS [BOOL] = {
ether ← GetNextDevice[nullDeviceHandle];
RETURN[ether # nullDeviceHandle];
};
SendPacket: PUBLIC PROC [ dest: PupTypes.PupAddress, me: PupTypes.PupSocketID, type: PupTypes.PupType, id: PupTypes.Pair, data: LONG POINTER, bytes: CARDINAL] = {
words: CARDINAL ← 2 + wordsPerPupHeader + (bytes + 1)/2;
IF ~active THEN ERROR DriverNotActive;
IF words > bufferSize THEN ERROR BufferOverflow;
Don't use constructor since that clobbers preceding 4 words
b.encapsulation.ethernetOneDest ← IF dest.net#myNet AND dest.net=hisNet AND hisNet#0 THEN hisEtherHost ELSE dest.host;
b.encapsulation.ethernetOneSource ← myHost;
b.encapsulation.ethernetType ← pup;
b.pupLength ← bytesPerPupHeader + bytes;
b.pupTransportControl ← 0;
b.pupType ← type;
b.pupID ← id;
b.dest ← dest;
b.source ← [myNet, myHost, me];
PrincOpsUtils.LongCopy[to: @b.pupWords, from: data, nwords: (bytes + 1)/2];
SetPupChecksum[b];
last ← out;
QueueOutput[
ether, @b.encapsulation + DriverTypes.ethernetEncapsulationOffset, words,
longIocb];
THROUGH [0..LAST[CARDINAL]) DO
IF GetStatus[longIocb] # pending THEN EXIT;
REPEAT
FINISHED =>
{ TurnOff[ether]; TurnOn[ether, myHost, 0, 0, global]; };
ENDLOOP;
};
ReturnPacket: PUBLIC PROC [ type: PupTypes.PupType, data: LONG POINTER, bytes: CARDINAL] = {
words: CARDINAL ← 2 + wordsPerPupHeader + (bytes + 1)/2;
temp: PupTypes.PupAddress;
IF ~active THEN ERROR DriverNotActive;
IF words > bufferSize THEN ERROR BufferOverflow;
IF last # in THEN ERROR ReturnToStrangePlace;
Don't use constructor since that clobbers preceding 4 words
b.encapsulation.ethernetOneDest ← b.encapsulation.ethernetOneSource;
b.encapsulation.ethernetOneSource ← myHost;
b.encapsulation.ethernetType ← pup;
b.pupLength ← bytesPerPupHeader + bytes;
b.pupTransportControl ← 0;
b.pupType ← type;
temp ← b.dest;
b.dest ← b.source;
b.source ← temp;
PrincOpsUtils.LongCopy[to: @b.pupWords, from: data, nwords: (bytes + 1)/2];
SetPupChecksum[b];
last ← out;
QueueOutput[
ether, @b.encapsulation + DriverTypes.ethernetEncapsulationOffset, words,
longIocb];
THROUGH [0..LAST[CARDINAL]) DO
IF GetStatus[longIocb] # pending THEN EXIT;
REPEAT
FINISHED =>
{ TurnOff[ether]; TurnOn[ether, myHost, 0, 0, global]; };
ENDLOOP;
};
RecvPacket: PUBLIC PROC [ source: LONG POINTER TO PupTypes.PupAddress, me: PupTypes.PupSocketID, data: LONG POINTER, words: CARDINAL, timeout: PROC RETURNS [BOOL]] RETURNS [bytes: CARDINAL, id: PupTypes.Pair, type: PupTypes.PupType] = {
IF ~active THEN ERROR DriverNotActive;
DO
QueueInput[
ether, @b.encapsulation + DriverTypes.ethernetEncapsulationOffset,
bufferSize, longIocb];
UNTIL GetStatus[longIocb] # pending DO
IF timeout[] THEN {
TurnOff[ether];
TurnOn[ether, myHost, 0, 0, global];
last ← reset;
RETURN[MiniEthernetDefs.timedOut, [0, 0], LOOPHOLE[0]];
};
ENDLOOP;
IF GetStatus[longIocb] # ok THEN LOOP;
IF b.encapsulation.ethernetType # pup THEN LOOP;
should check words that arrived against pupLength?
check here for routing table if we ever get that complicated
IF myNet # 0 AND myNet # b.dest.net AND b.dest.net # 0 THEN LOOP;
IF myHost # b.dest.host THEN LOOP; -- Can't recv broadcast
IF me # b.dest.socket THEN LOOP;
IF source.net # 0 AND source.net # b.source.net AND b.source.net # 0 THEN
LOOP;
IF source.host # 0 AND source.host # b.source.host THEN LOOP;
IF source.socket # [0, 0] AND source.socket # b.source.socket THEN LOOP;
IF ~TestPupChecksum[b] THEN LOOP;
IF myNet = 0 THEN myNet ← b.dest.net;
IF hisNet=0 THEN {hisNet ← b.source.net; hisEtherHost ← [b.encapsulation.ethernetOneSource]};
IF (b.pupLength - bytesPerPupHeader) > words*2 THEN LOOP;
bytes ← b.pupLength - bytesPerPupHeader;
PrincOpsUtils.LongCopy[to: data, from: @b.pupWords, nwords: (bytes + 1)/2];
IF source.net = 0 THEN source.net ← b.source.net;
IF source.host = 0 THEN source.host ← b.source.host;
IF source.socket = [0, 0] THEN source.socket ← b.source.socket;
last ← in;
RETURN[bytes, b.pupID, b.pupType];
ENDLOOP;
};
checksum: {software} = software;
SetPupChecksum: PUBLIC PROC [b: BufferDefs.PupBuffer] = {
size: CARDINAL ← (b.pupLength - 1)/2;
checksumLoc: LONG POINTER ← @b.pupLength + size;
cs, t: CARDINAL;
SELECT checksum FROM
software => {
p: LONG POINTER TO ARRAY [0..0) OF WORD = LOOPHOLE[@b.pupLength];
i: CARDINAL;
cs ← 0;
FOR i IN [0..size) DO
t ← cs + p[i];
cs ← (IF cs > t THEN t + 1 ELSE t);
cs ← (IF cs >= 100000B THEN cs*2 + 1 ELSE cs*2);
ENDLOOP;
IF cs = 177777B THEN cs ← 0;
checksumLoc^ ← cs;
};
ENDCASE => NULL;
};
TestPupChecksum: PUBLIC PROC [b: BufferDefs.PupBuffer] RETURNS [BOOL] = {
size: CARDINAL ← ((LOOPHOLE[b.pupLength - 1, CARDINAL])/2);
checksumLoc: LONG POINTER ← @b.pupLength + size;
cs, t: CARDINAL;
IF checksumLoc^ = 177777B THEN RETURN[TRUE];
SELECT checksum FROM
software => {
p: LONG POINTER TO ARRAY [0..0) OF WORD = LOOPHOLE[@b.pupLength];
i: CARDINAL;
cs ← 0;
FOR i IN [0..size) DO
t ← cs + p[i];
cs ← (IF cs > t THEN t + 1 ELSE t);
cs ← (IF cs >= 100000B THEN cs*2 + 1 ELSE cs*2);
ENDLOOP;
IF cs = 177777B THEN cs ← 0;
};
ENDCASE => NULL;
RETURN[checksumLoc^ = cs];
};
}.
LOG
Time: January 29, 1980 6:00 PM By: Dalal Action: fixed Core Software AR 2658.
Time: February 7, 1980 11:18 PM By: Knutsen Action: ioPage now a long pointer. Initialize host socket right.
INTEGER Divide
Time: February 9, 1980 2:43 PM By: Knutsen/HGM Action: fix clobber of 4 words before buffer
Time: April 20, 1980 4:03 PM By: HGM Action: Faceification, add ReturnPacket and timedOut
Time: April 28, 1980 7:36 PM By: HGM Action: Fix QueueOutput bug (again!) in RecvPacket
Time: July 2, 1980 5:44 PM By: HGM Action: Delete "DriverTypes." in front of pupEthernetPacket
Time: August 20, 1980 2:23 PM By: BLyon Action: renamed EthernetFace to EthernetOneFace.
Time: October 31, 1983 3:22 pm By: Birrell Action: conversion to 5.0.
January 3, 1984 4:49 pm Taft Maintain separate hisEtherHost value to permit booting through gateways.