<> <> <> <> <> <> <<>> DIRECTORY Basics USING [bytesPerWord, LongMult, LongDiv], BufferDefs USING [Buffer, OisBuffer, PupBuffer, PupBufferObject], Checksums USING [ComputeChecksum], DriverTypes USING [Encapsulation, EthernetPacketType], EthernetFace USING [AddCleanup, ControlBlock, DeviceHandle, GetNextDevice, GetPacketLength, GetStatus, GlobalStatePtr, globalStateSize, HostNumber, nullDeviceHandle, QueueInput, QueueOutput, RemoveCleanup, TurnOff, TurnOn], MiniEthernetDefs USING [timedOut], OISCPTypes USING [bytesPerPktHeader, PacketType, BufferBody], PrincOpsUtils USING [LongCopy, LowHalf], ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses, ProcessorID, processorID, SetMP], PupTypes USING [allHosts, Pair, PupAddress, PupHostID, PupNetID, PupSocketID, PupType], NSAddress USING [broadcastHostNumber, HostNumber, nullNetworkNumber, NetworkAddress, ProcessorID, SocketNumber]; MiniEthernetDriverDLion: PROGRAM IMPORTS Basics, Checksums, EthernetFace, PrincOpsUtils, ProcessorFace EXPORTS MiniEthernetDefs SHARES BufferDefs = { OPEN EthernetFace; active: BOOL _ FALSE; last: {in,out,reset}; knowBoardLocation: BOOL _ FALSE; myID: NSAddress.ProcessorID _ LOOPHOLE[ProcessorFace.processorID]; myHost: PupTypes.PupHostID; myNet: PupTypes.PupNetID; hisPupHost: PupTypes.PupHostID; hisEthernetAddress: NSAddress.HostNumber; <> 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 PROC [dataBuffer: LONG POINTER, length: CARDINAL, iocb: LONG POINTER, avoidCleanup: BOOL _ FALSE] RETURNS [BOOL] = { <> encapsulationOffset: CARDINAL = LOOPHOLE[ @LOOPHOLE[0, POINTER TO BufferDefs.PupBufferObject].encapsulation]; IF ~FindTheBoard[] THEN RETURN[FALSE]; knowBoardLocation _ TRUE; ProcessorFace.SetMP[816--MPCodes.germEthernetDriverStarting--]; <> b _ dataBuffer-encapsulationOffset+3; pupBufferSize _ length-3-SIZE[DriverTypes.Encapsulation]; longIocb _ iocb; [host: myHost, net: myNet] _ GetEthernet1Address[]; IF ~avoidCleanup THEN AddCleanup[ether]; <> TurnOn[ether,myID,0,0,global]; active _ TRUE; last _ reset; RETURN[TRUE]; }; KillDriver: PUBLIC PROC [avoidCleanup: BOOL _ FALSE] = { TurnOff[ether]; IF ~avoidCleanup THEN RemoveCleanup[ether]; knowBoardLocation _ FALSE; }; FindTheBoard: PROC RETURNS [BOOL] = { RETURN[(ether _ GetNextDevice[nullDeviceHandle])#nullDeviceHandle]; }; SendPacket: PUBLIC PROC [dest: PupTypes.PupAddress, me: PupTypes.PupSocketID, type: PupTypes.PupType, id: PupTypes.Pair, data: LONG POINTER, bytes: CARDINAL] = { 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]; }; <> ByteCount: TYPE = CARDINAL; SendOisPacket: PROC[ dataLength: ByteCount, type: OISCPTypes.PacketType, sourceSocket: NSAddress.SocketNumber, dest: NSAddress.NetworkAddress] = { 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]]; }; ReturnPacket: PUBLIC PROC [type: PupTypes.PupType, data: LONG POINTER, bytes: CARDINAL] = { 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]; }; SendPup: PROC [data: LONG POINTER, bytes: CARDINAL] = { 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]; }; SendBuffer: PROC [words: CARDINAL] = { 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 => { TurnOff[ether]; TurnOn[ether,myID,0,0,global]; }; ENDLOOP; }; <> translationRequest: CARDINAL = 1; translationResponse: CARDINAL = 2; GetEthernet1Address: PROC RETURNS [net: PupTypes.PupNetID, host: PupTypes.PupHostID] = { 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]]; pulsesPerSec: LONG CARDINAL _ Basics.LongMult[1000, Basics.LongDiv[100000, ProcessorFace.microsecondsPerHundredPulses]+1]; <> timeoutPulses: LONG CARDINAL _ 0; i: CARDINAL _ 1; mySocket: NSAddress.SocketNumber _ LOOPHOLE[PrincOpsUtils.LowHalf[LOOPHOLE[ProcessorFace.GetClockPulses[]]]]; <> pupAddressTranslation: NSAddress.SocketNumber _ LOOPHOLE[9]; pupAddrTransPacket: OISCPTypes.PacketType _ LOOPHOLE[6]; THROUGH [0..15] DO timeoutPulses _ timeoutPulses + pulsesPerSec; ENDLOOP; <> DO startPulses: LONG CARDINAL = ProcessorFace.GetClockPulses[]; TurnOff[ether]; TurnOn[ether, myID, 0, 0, global]; i _ i + 1; request^ _ [i, i, translationRequest, myID]; SendOisPacket[ SIZE[Request]*Basics.bytesPerWord, pupAddrTransPacket, mySocket, [NSAddress.nullNetworkNumber, NSAddress.broadcastHostNumber, pupAddressTranslation] ]; WHILE (ProcessorFace.GetClockPulses[] - startPulses) <= timeoutPulses DO oisBuf.encapsulation.ethernetType _ LOOPHOLE[0]; QueueInput[ ether, @b.encapsulation, pupBufferSize+SIZE[DriverTypes.Encapsulation], longIocb]; WHILE (ProcessorFace.GetClockPulses[] - startPulses) <= timeoutPulses 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]; RETURN [net: reply.answer.net, host: reply.answer.host] ENDLOOP; ENDLOOP; 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, pupBufferSize+SIZE[DriverTypes.Encapsulation], longIocb]; UNTIL GetStatus[longIocb]#pending DO IF timeout[] THEN { TurnOff[ether]; TurnOn[ether,myID,0,0,global]; last _ reset; RETURN[MiniEthernetDefs.timedOut,[0,0],LOOPHOLE[0]]; }; ENDLOOP; IF GetStatus[longIocb]#ok THEN LOOP; IF b.encapsulation.ethernetType=translation THEN { -- 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; }; IF b.encapsulation.ethernetType#pup THEN LOOP; <> <> 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; }; SetPupChecksum: PUBLIC PROC [b: BufferDefs.PupBuffer] = { buf: LONG POINTER = @b.pupLength; size: CARDINAL = (b.pupLength-1)/2; (buf+size)^ _ Checksums.ComputeChecksum[cs: 0, nWords: size, p: buf]; }; TestPupChecksum: PUBLIC PROC [b: BufferDefs.PupBuffer] RETURNS [BOOL] = { 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]]; }; <> SetOisChecksum: PROC [b: BufferDefs.OisBuffer] = { b.ois.checksum _ Checksums.ComputeChecksum[ 0, (b.ois.pktLength + 1 - 2)/2, @b.ois.pktLength]}; TestOisChecksum: PROC [b: BufferDefs.OisBuffer] RETURNS [BOOL] = { 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; }. LOG <> <> <> <> <> <> <> <> < Ethernet. INcrease fudge in GetEthernet1Address to 20.>> <<>> <> <> <> <> <> <<>>