DIRECTORY Basics USING [LongNumber], PrincOps USING [wordsPerPage], PrincOpsUtils USING [BITAND, LowHalf], DeviceCleanup USING [Item, Await], DLionInputOutput USING [IOPage, Input, Output], EthernetFace; EthernetHeadDLion: PROGRAM IMPORTS DLionInputOutput, DeviceCleanup, PrincOpsUtils EXPORTS EthernetFace = BEGIN OPEN EthernetFace; CSB: TYPE = LONG POINTER TO ControllerStatusBlock; ControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ host: physical HostNumber, input: ShortIocb, inputWakeups: WORD, output: ShortIocb, outputWakeups: WORD, missed: CARDINAL, lastInput: IOCB, -- last IOCB on input queue, valid if input#noIocb lastOutput: IOCB]; -- last IOCB on output queue, valid if output#noIocb EthernetCSBOffset: CARDINAL = 12*16 + 0; -- 0C0X IOCB: TYPE = LONG POINTER TO IOControlBlock; Base: TYPE = LONG BASE POINTER; ShortIocb: TYPE = Base RELATIVE POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ length: CARDINAL, buffer: LONG POINTER, mask: WORD, -- load location for output used: CARDINAL, -- input only completion: WORD, next: ShortIocb, spare: WORD]; -- NB: QuadWord Alignment Input: PROC [Register] RETURNS [Data] = LOOPHOLE[DLionInputOutput.Input]; Output: PROC [Command, Register] = LOOPHOLE[DLionInputOutput.Output]; Data: TYPE = RECORD [WORD]; Command: TYPE = RECORD [WORD]; eOff: Command = [0B]; eEnableTrn: Command = [1B]; eEnableRcv: Command = [1B]; eTurnOff: Command = [2B]; Register: TYPE = RECORD [[0..17B]]; eEOCtl: Register = [14B]; eEICtl: Register = [5B]; eEStatus: Register = [1B]; eHaveEther: Register = [12B]; collision: WORD = 100B; underRun: WORD = 40B; notGoodAlign: WORD = 20B; overRun: WORD = 10B; notGoodCRC: WORD = 4B; notEvenLen: WORD = 2B; eRcvEnabled: WORD = 2000B; eTrnEnabled: WORD = 400B; noIocb: ShortIocb = LOOPHOLE[0]; Shorten: PROC [iocb: IOCB] RETURNS [ShortIocb] = INLINE { RETURN[LOOPHOLE[PrincOpsUtils.LowHalf[iocb]]]}; FixAlignment: PROC [iocb: IOCB] RETURNS [IOCB] = INLINE { LOOPHOLE[iocb, Basics.LongNumber].lowbits _ PrincOpsUtils.BITAND[ LOOPHOLE[iocb, Basics.LongNumber].lowbits + 7, 177770B]; RETURN[iocb]}; MakeSureOff: PROC = INLINE { Output[eTurnOff, eEICtl]; THROUGH [0..2) UNTIL PrincOpsUtils.BITAND[Input[eEStatus], eRcvEnabled + eTrnEnabled] = 0 DO ENDLOOP}; DeviceHandle: PUBLIC TYPE = RECORD [CARDINAL]; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; nullDeviceHandle: PUBLIC DeviceHandle _ [123456B]; self: DeviceHandle = [0]; globalStateSize: PUBLIC CARDINAL _ 0; controlBlockSize: PUBLIC CARDINAL; hearSelf: PUBLIC BOOLEAN _ FALSE; csb: CSB _ DLionInputOutput.IOPage + EthernetCSBOffset; haveEther: BOOLEAN; QueueOutput: PUBLIC PROC [device: DeviceHandle, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { count: CARDINAL; p: LONG POINTER _ buffer; IF device # self THEN RETURN; count _ length - 1; DO foo: UNSPECIFIED _ (p + count)^; IF count < PrincOps.wordsPerPage THEN {foo _ p^; EXIT}; count _ count - PrincOps.wordsPerPage; ENDLOOP; cb _ FixAlignment[cb]; cb^ _ [ next: noIocb, mask: 0, spare: 1, completion: 0, used: 0, length: length - 1, buffer: buffer]; IF csb.output = noIocb THEN { csb.output _ Shorten[cb]; Output[eEnableTrn, eEOCtl]} -- poke hardware ELSE { csb.lastOutput.next _ Shorten[cb]; IF csb.output = noIocb AND cb.completion = 0 THEN { csb.output _ Shorten[cb]; Output[eEnableTrn, eEOCtl]}}; -- poke hardware csb.lastOutput _ cb}; QueueInput: PUBLIC PROC [ device: DeviceHandle, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { IF device # self THEN RETURN; cb _ FixAlignment[cb]; cb^ _ [ next: noIocb, mask: 0, spare: 0, completion: 0, used: 0, length: length, buffer: buffer]; IF csb.input # noIocb THEN csb.lastInput.next _ Shorten[cb]; IF csb.input = noIocb AND cb.completion = 0 THEN { csb.input _ Shorten[cb]; Output[eEnableRcv, eEICtl]}; csb.lastInput _ cb}; GetStatus: PUBLIC PROC [cb: IOCB] RETURNS [status: Status] = { completion: WORD; cb _ FixAlignment[cb]; IF (completion _ cb.completion) = 0 THEN RETURN[pending]; IF cb.spare = 0 THEN { IF cb.length = 177777B THEN RETURN[packetTooLong]; status _ SELECT PrincOpsUtils.BITAND[ completion, notGoodAlign + overRun + notGoodCRC + notEvenLen] FROM 0 => ok, notGoodAlign+notEvenLen => ok, -- dippled bit case - someday drippled should be returned notGoodAlign => badAlignmentButOkCrc, notGoodCRC => crc, notGoodCRC + notGoodAlign => crcAndBadAlignment, overRun, overRun + notGoodAlign, overRun + notGoodCRC, overRun + notGoodCRC + notGoodAlign => overrun, ENDCASE => otherError; IF status = ok THEN { count: CARDINAL _ cb.length; p: LONG POINTER _ cb.buffer; DO (p + count)^ _ (p + count)^; IF count < PrincOps.wordsPerPage THEN {p^ _ p^; EXIT}; count _ count - PrincOps.wordsPerPage; ENDLOOP}; RETURN[status]}; IF cb.spare = 1 THEN { IF cb.mask = 17777B THEN RETURN[tooManyCollisions]; RETURN[ SELECT PrincOpsUtils.BITAND[completion, collision + underRun] FROM 0 => ok, underRun, underRun + collision => underrun, ENDCASE => otherError]}; RETURN[otherError]}; GetRetries: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { cb _ FixAlignment[cb]; RETURN[ SELECT cb.mask FROM 1 => 0, 3 => 1, 7 => 2, 17B => 3, 37B => 4, 77B => 5, 177B => 6, 377B => 7, 777B => 8, 1777B => 9, 3777B => 10, 7777B => 11, ENDCASE => 16]}; GetPacketLength: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { cb _ FixAlignment[cb]; RETURN[cb.used]}; GetPacketsMissed: PUBLIC PROC [device: DeviceHandle] RETURNS [CARDINAL] = { RETURN[IF device # self THEN 0 ELSE csb.missed]}; GetNextDevice: PUBLIC PROC [device: DeviceHandle] RETURNS [DeviceHandle] = { IF ~haveEther THEN RETURN[nullDeviceHandle]; IF device = nullDeviceHandle THEN RETURN[self] ELSE RETURN[nullDeviceHandle]}; TurnOn: PUBLIC PROC [ device: DeviceHandle, host: physical HostNumber, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = { IF device # self THEN RETURN; MakeSureOff[]; csb^ _ [ host: host, input: noIocb, inputWakeups: inInterrupt, output: noIocb, outputWakeups: outInterrupt, missed: 0, lastInput: NIL, lastOutput: NIL]; Output[eEnableRcv, eEICtl]}; TurnOff: PUBLIC PROC [device: DeviceHandle] = { IF device # self THEN RETURN; MakeSureOff[]}; cleanupInitialized: BOOLEAN _ FALSE; savedCSB: ControllerStatusBlock; AddCleanup: PUBLIC PROC [device: DeviceHandle] = { OPEN DeviceCleanup; item: Item; oldHost: physical HostNumber; IF cleanupInitialized OR ~haveEther THEN RETURN; cleanupInitialized _ TRUE; DO SELECT Await[@item] FROM kill => MakeSureOff[]; turnOff => {MakeSureOff[]; savedCSB _ csb^; oldHost _ csb.host}; turnOn => { MakeSureOff[]; csb^ _ [ host: oldHost, -- Ugh, it would be nice if we could do something better input: noIocb, inputWakeups: 0, output: noIocb, outputWakeups: 0, missed: 0, lastInput: NIL, lastOutput: NIL]; Output[eEnableRcv, eEICtl]}; ENDCASE; ENDLOOP}; RemoveCleanup: PUBLIC PROC [device: DeviceHandle] = {}; Start: PROC = { IF (haveEther _ Input[eHaveEther] = Data[1]) THEN controlBlockSize _ SIZE[IOControlBlock] + 4 ELSE controlBlockSize _ 0 }; Start[]; END. LOG Time: October 29, 1980 11:16 AM By: Sandman, Action: create file. Time: 18-Mar-81 17:20:25 By: Sandman, Action: Removed minimum packet length test, general cleanup. ςEthernetHeadDLion.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Sandman on: 18-Mar-81 17:20:56 Blyon on : 22-Apr-81 17:43:34 Russ Atkinson (RRA) February 19, 1985 3:33:17 pm PST These are the data structures that the microcode knows about. If some other module (for example, a diagnostic) ever needs this info, it should probably get split out into a separate module. For now, it is lumped in here to avoid cluttering up the world with yet another file. completion bits other status bits Maybe we should check to be sure that the high half is zero EXPORTed TYPEs EXPORTed variables Non EXPORTed things. Note that all the state information lives in the CSBs. new iocb, hardware idle output active, add to end of chain oops, hardware went idle There is no way to remove a cleanup procedure yet, so we have a flag to avoid duplicates. Note that this does NOT really put things back together. It simply smashes things to a safe state. The intention is that the driver will notice that nothing is happening and then call TurnOff+TurnOn to reset things. That allows Pilot to reset the GMT clock on the way back from the debugger without getting tangled up with the normal Ethernet driver. Other routines to keep the rest of the world happy Κ Ά˜codešœ™Kšœ Οmœ1™Kšœ žœ˜K˜Kšžœ"žœžœ ˜9šžœžœ˜Kšžœžœžœ˜2˜Kšžœžœ˜šœ>ž˜BK˜Kšœ Ÿ9˜YK˜%K˜K˜0˜6K˜/—Kšžœ˜——šžœ žœ˜Kšœžœ ˜Kšœžœžœ ˜šž˜K˜Kšžœžœ žœ˜6K˜&Kšžœ˜ ——Kšžœ ˜—šžœžœ˜Kšžœžœžœ˜3šžœ˜šžœžœ#ž˜BK˜K˜+Kšžœ˜———Kšžœ˜K˜—š   œžœžœžœžœžœ˜9K˜šžœ˜šžœ ž˜K˜K˜K˜K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜ Kšžœ ˜K˜———š  œžœžœžœžœžœ˜>Kšœžœ ˜(K˜—š  œžœžœžœžœ˜KKšžœžœžœžœ˜1K˜—š  œžœžœžœ˜LKšžœ žœžœ˜,Kš žœžœžœžœžœ˜NK˜—š œžœžœ˜Kšœ0˜0Kšœžœ"˜AKšžœžœžœ˜K˜˜K˜EKšœ3žœžœ˜I—K˜K˜—š œžœžœ˜/Kšžœžœžœ˜-K˜—KšœY™YK˜Kšœžœžœ˜$K˜K˜ K˜š  œžœžœ˜2Kšžœ˜K˜ Kšœ˜Kšžœžœ žœžœ˜0Kšœžœ˜šž˜šžœž˜K˜K˜@˜ Kšœα™αK˜˜KšœŸ8˜GK˜AKšœžœžœ˜,—K˜—Kšžœ˜—Kšžœ˜ K˜——Kš  œžœžœ˜7K˜Kšœ2™2K˜š œžœ˜šžœ+ž˜1Kšœžœ˜+—Kšžœ˜Kšœ˜—K˜K˜K˜Kšžœ˜K˜—Kšž˜Kšœžœ#˜CK˜cK˜K˜—…—*¨