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 MiniEthernetDriverDLion.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. BLyon on: March 12, 1981 4:37 PM Sturgis: fixing GetEthernetHostNumber: September 23, 1983 2:18 pm Birrell, October 31, 1983 3:34 pm Russ Atkinson (RRA) March 14, 1985 5:08:09 pm PST Global buffer for actual data transfers. Note: dataBuffer must be quad word aligned Beware of funny alignment constraints allocate global storage here following by analogy from MiniOISCPDriverImpl.SendPacket of APilot100 modified in analogy to APilot100 PilotCommUtilPup.GetEthernetHostNumber This is a conservative (high) estimate of the # of pulses in a second From the new OISCPCOnstants RRA: Since we don't trust the multiplication to stay within the bounds supported by microcode, we do this in a simple-minded loop. should check words that arrived against pupLength? check here for routing table if we ever get that complicated following procedures in anaogy to apilot100 minioiscpdriverimpl.mesa 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 Russ Atkinson (RRA) March 14, 1985 5:05:29 pm PST GetEthernet1Address fixed to not send packets too quickly. There is a 15 second timeout, which is calculated entirely in microcode. Κ U˜codešœ™Kšœ Οmœ1™˜EKšžœ˜Kšžœ ˜Kšœžœ˜—K˜Kšœžœžœ˜K˜Kšœžœžœ˜ K˜Kšœžœ˜BK˜K˜K˜K˜)˜Kšœ(™(—K˜Kšœžœ˜K˜K˜Kšœžœžœžœ˜-K˜Kšœžœ Οc'˜KKšœžœ˜2K˜Kšœžœžœžœ˜*Kšœžœžœžœ˜%Kšœžœžœžœ˜$Kšœžœžœžœ˜*Kšœžœžœžœ˜2Kšœžœžœ˜+K˜šΟnœžœžœžœžœ žœžœžœžœžœžœžœ˜‹Kšœ*™*šœžœžœ˜)Kšœžœžœžœ,˜C—Kšžœžœžœžœ˜&Kšœžœ˜KšœŸ&œ˜?Kšœ%™%K˜%Kšœžœ˜9K˜K˜3Kšžœžœ˜(Kšœ™K˜Kšœ žœ˜K˜ Kšžœžœ˜ Kšœ˜K˜—š   œžœžœžœžœ˜8K˜Kšžœžœ˜+Kšœžœ˜Kšœ˜K˜—š  œžœžœžœ˜%Kšžœ=˜CKšœ˜—K˜š   œžœžœhžœžœ žœ˜‘Kšžœ žœžœ˜&šžœž˜#K˜<—Kšžœžœžœ2˜SKšžœžœ˜(K˜K˜ K˜K˜K˜Kšœ˜K˜—KšœE™EKšœ žœžœ˜š  œžœ˜’Kšœžœ˜+K˜.K˜(K˜AKšœ!žœ˜9K˜YK˜K˜K˜7Kšœ˜K˜—š   œžœžœ žœžœ žœ˜[K˜Kšžœ žœžœ˜&Kšžœ žœžœ˜+K˜>K˜K˜2K˜Kšœ˜K˜—š  œžœžœžœ žœ˜7Kšœ žœ!˜3Kšžœžœžœ˜4KšœI˜IK˜&K˜K˜#K˜K˜ K˜Kšœ˜K˜—š  œžœ žœ˜&KšœžœŸ ˜QK˜&Kšœ&žœžœI˜wšžœžœžœž˜Kšžœžœžœ˜)šžœžœ˜K˜K˜Kšœ˜—Kšžœ˜—Kšœ˜K˜—KšœG™GKšœžœ˜!Kšœžœ˜"š œžœžœ7˜XKšœžœ˜+š œ žœžœž œžœ˜*Kšœ žœžœ˜;—Kš œ žœžœžœ žœ˜Eš œžœžœž œžœ˜(Kšœ žœžœ˜<—Kš œžœžœžœ žœ˜Ašœžœžœ_˜zKšœE™E—Kšœžœžœ˜!Kšœžœ˜Kšœ#žœžœ#˜mK˜Kšœ™Kšœ0žœ˜Kšžœ*žœžœ˜6KšžœHžœžœ˜TKšžœ5žœžœ˜AKšžœ#žœžœ˜/Kšžœžœžœ˜&K˜Kšžœ1˜7Kšžœ˜—Kšžœ˜—Kšžœ˜—Kšœ˜K˜—š  œžœžœ žœžœžœ6žœžœ žœ žœžœžœžœ žœ0˜λKšžœ žœžœ˜&šž˜˜ K˜Kšœžœ'˜9—šžœž˜$šžœ žœ˜K˜K˜K˜ Kšžœ!žœ˜4Kšœ˜—Kšžœ˜—Kšžœžœžœ˜$šžœ*ž˜0KšœŸ˜Kšžœžœ˜)š œ žœžœž œžœ˜.K˜K˜.—Kš œ žœžœžœžœ˜BKšœžœ ˜&Kšœžœ ˜&Kšžœ$žœžœ˜0Kšžœžœžœ˜"K˜>K˜&K˜Kšœ žœ˜ Kšžœ˜Kšœ˜—Kšžœ"žœžœ˜.——Kšœ2™2šœ<™