MiniEthernetDriverDLion.mesa
last edited by: BLyon on: March 12, 1981 4:37 PM
last edited by Sturgis: fixing GetEthernetHostNumber: September 23, 1983 2:18 pm
Last Edited by: Birrell, October 31, 1983 3:34 pm
DIRECTORY
Basics USING[bytesPerWord],
BufferDefs,
Checksums USING [ComputeChecksum],
DriverTypes USING [Encapsulation, EthernetPacketType],
EthernetFace,
MiniEthernetDefs,
OISCPTypes USING[bytesPerPktHeader, PacketType, BufferBody],
PrincOpsUtils USING [LongCOPY, LowHalf],
ProcessorFace USING [GetClockPulses, ProcessorID, processorID, SetMP],
PupTypes,
NSAddress USING [broadcastHostNumber, HostNumber, nullNetworkNumber, NetworkAddress, ProcessorID, SocketNumber];
MiniEthernetDriverDLion:
PROGRAM
IMPORTS Checksums, EthernetFace, PrincOpsUtils, ProcessorFace
EXPORTS MiniEthernetDefs
SHARES BufferDefs =
BEGIN OPEN EthernetFace;
active: BOOLEAN ← FALSE;
last: {in,out,reset};
knowBoardLocation: BOOLEAN ← FALSE;
myID: NSAddress.ProcessorID ← LOOPHOLE[ProcessorFace.processorID];
myHost: PupTypes.PupHostID;
myNet: PupTypes.PupNetID;
hisPupHost: PupTypes.PupHostID;
hisEthernetAddress: NSAddress.HostNumber;
Global buffer for actual data transfers.
b: BufferDefs.PupBuffer;
pupBufferSize: CARDINAL;
ether: DeviceHandle;
longIocb: ControlBlock;
global: GlobalStatePtr ← LOOPHOLE[LONG[NIL]];
wordsPerPupHeader: CARDINAL = 11; -- includes checksum, not encapsulaton?
bytesPerPupHeader: CARDINAL = wordsPerPupHeader*2;
BoardLocationUnknown: PUBLIC ERROR = CODE;
DriverNotActive: PUBLIC ERROR = CODE;
BufferOverflow: PUBLIC ERROR = CODE;
ReturnToStrangePlace: PUBLIC ERROR = CODE;
DriverNeedsSomeGlobalStorage: PUBLIC ERROR = CODE;
DontKnowHowToTranslateThings: ERROR = CODE;
ActivateDriver:
PUBLIC
PROCEDURE [
dataBuffer: LONG POINTER, -- quad word aligned!!
length: CARDINAL,
iocb: LONG POINTER,
avoidCleanup: BOOLEAN ← FALSE] RETURNS [BOOLEAN] =
BEGIN
encapsulationOffset:
CARDINAL =
LOOPHOLE[
@LOOPHOLE[0, POINTER TO BufferDefs.PupBufferObject].encapsulation];
IF ~FindTheBoard[] THEN RETURN[FALSE];
knowBoardLocation ← TRUE;
Beware of funny alignment constraints
b ← dataBuffer-encapsulationOffset+3;
pupBufferSize ← length-3-SIZE[DriverTypes.Encapsulation];
longIocb ← iocb;
[host: myHost, net: myNet] ← GetEthernet1Address[];
IF ~avoidCleanup THEN AddCleanup[ether];
allocate global storage here
TurnOn[ether,myID,0,0,global];
active ← TRUE;
last ← reset;
RETURN[TRUE];
END;
KillDriver:
PUBLIC
PROCEDURE [avoidCleanup:
BOOLEAN ←
FALSE] =
BEGIN
TurnOff[ether];
IF ~avoidCleanup THEN RemoveCleanup[ether];
knowBoardLocation ← FALSE;
END;
FindTheBoard:
PROCEDURE
RETURNS [
BOOLEAN] =
{RETURN[(ether ← GetNextDevice[nullDeviceHandle])#nullDeviceHandle]};
SendPacket:
PUBLIC
PROCEDURE [
dest: PupTypes.PupAddress,
me: PupTypes.PupSocketID,
type: PupTypes.PupType,
id: PupTypes.Pair,
data: LONG POINTER,
bytes: CARDINAL] =
BEGIN
IF ~active THEN ERROR DriverNotActive;
IF dest.host=PupTypes.allHosts
THEN
b.encapsulation.ethernetDest ← NSAddress.broadcastHostNumber
ELSE IF dest.host=hisPupHost THEN b.encapsulation.ethernetDest ← hisEthernetAddress
ELSE ERROR DontKnowHowToTranslateThings;
b.pupType ← type;
b.pupID ← id;
b.dest ← dest;
b.source ← [myNet, myHost, me];
SendPup[data, bytes];
END;
following by analogy from MiniOISCPDriverImpl.SendPacket of APilot100
ByteCount: TYPE = CARDINAL;
SendOisPacket:
PROCEDURE[
dataLength: ByteCount,
type: OISCPTypes.PacketType,
sourceSocket: NSAddress.SocketNumber,
dest: NSAddress.NetworkAddress] =
BEGIN
oisBuf: BufferDefs.OisBuffer ← LOOPHOLE[b];
oisBuf.encapsulation.ethernetDest ← dest.host;
oisBuf.encapsulation.ethernetType ← ois;
oisBuf.ois.pktLength ← dataLength + OISCPTypes.bytesPerPktHeader;
oisBuf.ois.transCntlAndPktTp ← [[FALSE, 0, 0], type];
oisBuf.ois.source ← [
net: NSAddress.nullNetworkNumber, host: myID, socket: sourceSocket];
oisBuf.ois.destination ← dest;
SetOisChecksum[oisBuf];
SendBuffer[WdsPerEthernetPacket[oisBuf.ois.pktLength]];
END;
ReturnPacket:
PUBLIC
PROCEDURE [
type: PupTypes.PupType,
data: LONG POINTER,
bytes: CARDINAL] =
BEGIN
temp: PupTypes.PupAddress;
IF ~active THEN ERROR DriverNotActive;
IF last#in THEN ERROR ReturnToStrangePlace;
b.encapsulation.ethernetDest ← b.encapsulation.ethernetSource;
b.pupType ← type;
temp ← b.dest; b.dest ← b.source; b.source ← temp;
SendPup[data, bytes];
END;
SendPup:
PROCEDURE [data:
LONG
POINTER, bytes:
CARDINAL] =
BEGIN
pupWords: CARDINAL = wordsPerPupHeader+(bytes+1)/2;
IF pupWords>pupBufferSize THEN ERROR BufferOverflow;
PrincOpsUtils.LongCOPY[to: @b.pupWords, from: data, nwords: (bytes+1)/2];
b.pupLength ← bytesPerPupHeader+bytes;
b.pupTransportControl ← 0;
b.encapsulation.ethernetType ← pup;
SetPupChecksum[b];
last ← out;
SendBuffer[pupWords];
END;
SendBuffer:
PROCEDURE [words:
CARDINAL] =
BEGIN
minWordsPerEthernetPacket: CARDINAL = (64/2)-2; --*** Should move to DriverTypes
b.encapsulation.ethernetSource ← myID;
QueueOutput[
ether, @b.encapsulation, MAX[SIZE[DriverTypes.Encapsulation]+words, minWordsPerEthernetPacket], longIocb];
THROUGH [0..
LAST[
CARDINAL])
DO
IF GetStatus[longIocb]#pending THEN EXIT;
REPEAT
FINISHED =>
BEGIN
TurnOff[ether];
TurnOn[ether,myID,0,0,global];
END;
ENDLOOP;
END;
modified in analogy to APilot100 PilotCommUtilPup.GetEthernetHostNumber
translationRequest: CARDINAL = 1;
translationResponse: CARDINAL = 2;
GetEthernet1Address:
PROCEDURE
RETURNS [
net: PupTypes.PupNetID, host: PupTypes.PupHostID] =
BEGIN
oisBuf: BufferDefs.OisBuffer ← LOOPHOLE[b];
Request:
TYPE =
MACHINE
DEPENDENT
RECORD [
id0, id1: CARDINAL, arg: WORD, who: NSAddress.ProcessorID];
request: LONG POINTER TO Request = LOOPHOLE[@oisBuf.ois.oisWords[0]];
Reply:
TYPE =
MACHINE
DEPENDENT
RECORD [
id0, id1: CARDINAL, arg: WORD, answer: PupTypes.PupAddress];
reply: LONG POINTER TO Reply = LOOPHOLE[@oisBuf.ois.oisWords[0]];
i: CARDINAL ← 1;
mySocket: NSAddress.SocketNumber ← LOOPHOLE[PrincOpsUtils.LowHalf[LOOPHOLE[ProcessorFace.GetClockPulses[]]]];
From the new OISCPCOnstants
pupAddressTranslation: NSAddress.SocketNumber ← LOOPHOLE[9];
pupAddrTransPacket: OISCPTypes.PacketType ← LOOPHOLE[6];
this has to go after debugging
ProcessorFace.SetMP[9157];
DO
TurnOff[ether];
TurnOn[ether, myID, 0, 0, global];
i ← i + 1;
request^ ← [i, i, translationRequest, myID];
SendOisPacket[
SIZE[Request]*2,
pupAddrTransPacket,
mySocket,
[NSAddress.nullNetworkNumber,
NSAddress.broadcastHostNumber,
pupAddressTranslation] ];
THROUGH [0..3)
DO
oisBuf.encapsulation.ethernetType ← LOOPHOLE[0];
QueueInput[
ether, @b.encapsulation,
pupBufferSize+SIZE[DriverTypes.Encapsulation], longIocb];
THROUGH [0..
LAST[
CARDINAL]/2)
DO
IF GetStatus[longIocb] = pending THEN LOOP;
IF GetStatus[longIocb] # ok THEN EXIT;
IF oisBuf.encapsulation.ethernetType # ois THEN EXIT;
IF oisBuf.ois.destination.host # myID THEN EXIT;
IF oisBuf.ois.source.socket # pupAddressTranslation THEN EXIT;
IF oisBuf.ois.destination.socket # mySocket THEN EXIT;
IF GetPacketLength[longIocb]
< WdsPerEthernetPacket[oisBuf.ois.pktLength] THEN EXIT;
IF oisBuf.ois.pktLength < OISCPTypes.bytesPerPktHeader THEN EXIT;
IF (reply.arg # translationResponse) THEN EXIT;
IF ~TestOisChecksum[oisBuf] THEN EXIT;
TurnOff[ether];
this has to go after debugging
ProcessorFace.SetMP[915];
RETURN [net: reply.answer.net, host: reply.answer.host]
ENDLOOP;
ENDLOOP;
ENDLOOP;
END;
de-implemented since it is not clear they have storage to use
GetEthernetHostNumber: PUBLIC PROCEDURE RETURNS [CARDINAL] =
{RETURN[GetEthernet1Address[].host]};
GetEthernetNetNumber: PUBLIC PROCEDURE RETURNS [CARDINAL] =
BEGIN
net: CARDINAL = GetEthernet1Address[].net;
RETURN[IF active THEN myNet ELSE net];
END;
RecvPacket:
PUBLIC
PROCEDURE [
source: LONG POINTER TO PupTypes.PupAddress,
me: PupTypes.PupSocketID,
data: LONG POINTER,
words: CARDINAL,
timeout: PROCEDURE RETURNS [BOOLEAN]]
RETURNS [bytes: CARDINAL, id: PupTypes.Pair, type: PupTypes.PupType] =
BEGIN
IF ~active THEN ERROR DriverNotActive;
DO
QueueInput[
ether, @b.encapsulation,
pupBufferSize+SIZE[DriverTypes.Encapsulation], longIocb];
UNTIL GetStatus[longIocb]#pending
DO
IF timeout[]
THEN
BEGIN
TurnOff[ether];
TurnOn[ether,myID,0,0,global];
last ← reset;
RETURN[MiniEthernetDefs.timedOut,[0,0],LOOPHOLE[0]];
END;
ENDLOOP;
IF GetStatus[longIocb]#ok THEN LOOP;
IF b.encapsulation.ethernetType=translation
THEN
BEGIN -- See EthernetDriver
OPEN raw: LOOPHOLE[b, BufferDefs.Buffer];
AddressPair:
TYPE =
MACHINE
DEPENDENT
RECORD [
big: NSAddress.ProcessorID,
small: PupTypes.PupHostID, filler: [0..377B]];
request: LONG POINTER TO AddressPair = LOOPHOLE[@raw.rawWords[1]];
translationRequest: CARDINAL = 10101B;
translationResponse: CARDINAL = 7070B;
IF raw.rawWords[0]#translationRequest THEN LOOP;
IF request.small#myHost THEN LOOP;
b.encapsulation.ethernetDest ← b.encapsulation.ethernetSource;
raw.rawWords[0] ← translationResponse;
request.big ← myID;
SendBuffer[1+SIZE[AddressPair]];
LOOP;
END;
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 (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;
hisPupHost ← source.host;
hisEthernetAddress ← b.encapsulation.ethernetSource;
RETURN[bytes,b.pupID,b.pupType];
ENDLOOP;
END;
SetPupChecksum:
PUBLIC
PROCEDURE [b: BufferDefs.PupBuffer] =
BEGIN
buf: LONG POINTER = @b.pupLength;
size: CARDINAL = (b.pupLength-1)/2;
(buf+size)^ ← Checksums.ComputeChecksum[cs: 0, nWords: size, p: buf];
END;
TestPupChecksum:
PUBLIC
PROC [b: BufferDefs.PupBuffer]
RETURNS [
BOOLEAN] =
BEGIN
buf: LONG POINTER = @b.pupLength;
size: CARDINAL = (b.pupLength-1)/2;
cs: CARDINAL = (buf+size)^;
RETURN[cs=177777B OR cs=Checksums.ComputeChecksum[cs: 0, nWords: size, p: buf]];
END;
following procedures in anaogy to apilot100 minioiscpdriverimpl.mesa
SetOisChecksum:
PROCEDURE [b: BufferDefs.OisBuffer] = {
b.ois.checksum ← Checksums.ComputeChecksum[
0, (b.ois.pktLength + 1 - 2)/2, @b.ois.pktLength]};
TestOisChecksum:
PROC [b: BufferDefs.OisBuffer]
RETURNS [BOOLEAN] = {
RETURN[
b.ois.checksum = Checksums.ComputeChecksum[
0, (b.ois.pktLength + 1 - 2)/2, @b.ois.pktLength]
OR b.ois.checksum = 177777B]};
WdsPerEthernetPacket:
PROC [bodyBytes:
CARDINAL]
RETURNS[wds:
CARDINAL] = {
minWdsPerEthernetPacket: CARDINAL = ((64-4)/Basics.bytesPerWord);
wds ←
SIZE[DriverTypes.Encapsulation] +
(bodyBytes + Basics.bytesPerWord-1)/Basics.bytesPerWord;
wds ← MAX[wds, minWdsPerEthernetPacket]};
IF globalStateSize # 0 THEN ERROR DriverNeedsSomeGlobalStorage;
END.
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: November 20, 1980 By: HGM+Forrest Action: DLion/EthernetTwo.
Time: February 9, 1981 12:36 PM By: Luniewski/BLyon Action: XWire => Ethernet. INcrease fudge in GetEthernet1Address to 20.
Time: July 25, 1983 3:45 pm: Sturgis: begin repairs to GetEtherNetHostNumber
RTE: July 27, 1983 3:23 pm: SendOISPacket should not test for active driver, as it is being called during the period when driver is begin activated.
Time: October 28, 1983 3:32 pm: Birrell: conversion to 5.0