-- File: Boss.mesa, Last Edit:
-- MAS April 17, 1980 11:02 PM
-- HGM November 12, 1979 5:33 PM

-- Copyright Xerox Corporation 1979, 1980

DIRECTORY
StatsDefs: FROM "StatsDefs" USING [StatIncr, StatsGetCounters, StatsGetText],
CommUtilDefs: FROM "CommUtilDefs" USING [
AllocateLockedNode, LockCode, UnlockCode, SetDebuggingPointer],
DriverDefs: FROM "DriverDefs" USING [
doDebug, doStats, Glitch, GiantVector,
pupRouter, wordsPerIocb,
PutOnGlobalDoneQueue, GetInputBuffer,
FreeQueueDestroy, FreeQueueMake,
CreateDefaultEthernetDriver,
Network, DispatcherOff, DispatcherOn,
DispatcherCold, QueueCold],
PupDefs: FROM "PupDefs"; -- EXPORTs

Boss: MONITOR
IMPORTS StatsDefs, CommUtilDefs, DriverDefs
EXPORTS DriverDefs, PupDefs
SHARES DriverDefs =
BEGIN OPEN CommUtilDefs, DriverDefs;

-- SemiPublic things for others
firstNetwork: PUBLIC Network ← NIL;
giantVector: PUBLIC LONG POINTER TO GiantVector;
useCount: PUBLIC CARDINAL ← 0;

state: {off, ready} ← off;

IocbNotBigEnough: PUBLIC ERROR = CODE;
CommPackageNotActive: PUBLIC ERROR = CODE;

GetDoStats: PUBLIC PROCEDURE RETURNS [BOO
LEAN] =
BEGIN
RETURN[doStats];
END;

-- This code is a bit delicate. There are probably many funny cases that won’t work correctly. In particular, there is a race condition between adding/delet
ing a driver and adding/deleting a router.

AddDeviceToChain: PUBLIC PROCEDURE [ netwo
rk: Network, iocbSize: CARDINAL ] =
BEGIN
-- Add new drivers to the end of the chain so that the n
ormal Ethernet driver will be network zero.
tail: Network ← firstNetwork;
i: CARDINAL ← 1;
UNTIL (iocbSize MOD 4)=0 DO iocbSize ← iocbSize+1; ENDLOOP;
IF state=off THEN wordsPerIocb ← MAX[wordsPerIocb,iocbSize]
ELSE IF iocbSize>wordsPerIocb THEN Glitch[IocbNotBigEnough];
IF state=ready THEN LockCode[network.interrupt];
IF useCount>0 THEN
BEGIN
network.activateDriver[];
DriverDefs.pupRouter.addNetwork[network];
END;
IF firstNetwork=NIL THEN
BEGIN firstNetwork ← network; network.index ← 1; RETURN; END;
UNTIL tail.next=NIL DO tail ← tail.next; i ← i+1; ENDLOOP;
tail.nex
t ← network;
networ
k.index ← i+1;
END;

RemoveDeviceFromChain: PUBLIC ENTRY PROCEDURE [ network: Network ] =
BEGIN
tail: Network ← firstNetwork;
IF useCount>0 THEN
BEGIN
DriverDefs.pupRouter.removeNetwork[network];
network.deactivateDriver[];
END;
IF state=ready THEN UnlockCode[network.interrupt];
IF firstNetwork=network THEN firstNetwork←network.next
ELSE
BEGIN
UNTIL tail.next=network DO tail←tail.next; ENDLOOP;
tail.next ← network.next;
END;
-- network.index is not updated. It is used
only to collect Gateway statistics.
END;

GetDeviceChain: PUBLIC PROCEDURE RETURNS [ Network ] =
BEGIN
IF state#ready THEN Glitch[CommPackageNotActive];
RETURN[firstNetwork];
END;

-- This may be called at a
ny time. It does nothing if already ready.
PupPackageReady: PUBLIC ENTRY PROCED
URE =
BEGIN
CommPackageReady[];
END;

CommPackageReady: INTERNAL PROCEDURE =
BEGIN
network: Network;
IF useCount=0 AND firstNetwork=NIL THEN [] ← CreateDefaultEthernetDriver[];
IF state=ready THEN RETURN;
-- On the Alto, MakeImage forgets low memory
IF doDebug THEN CommUtilDefs.SetDebuggingPointer[giantVector];
IF doStats THEN LockCode[StatsDefs.StatIncr];
LockCode[DriverDefs.GetInputBuffer]; -- QueueLocked(Tiny)
LockCode[DriverDefs.PutOnGlobalDoneQueue]; -- DispatcherLocked(Fast)
FreeQueueMake[];
DispatcherOn[];
FOR network←firstNetwork,network.next UNTIL network=NIL DO
LockCode[network.interr
upt];
END
LOOP;
state ← ready;
END;

CommPackageGo: PUBLIC ENTRY PROCEDURE =
BEGIN
network: Network;
-- On the Alto, MakeImage forgets low memory
IF doDebug THEN CommUtilDefs.SetDebuggingPointer[giantVector];
CommPackageReady[];
IF (useCount←useCount+1)>1 THEN RETURN;
FOR network←firstNetwork,network.next UNTIL network=NIL DO
net
work.activateDriver[];
ENDLOOP;
END;

CommPackageOff: PUBLIC ENTRY PROCEDURE =
BEGIN
network: Network;
IF (useCount←useCount-1)#0 THEN RETURN;
FOR network←firstNetwork,network.next UNTIL network=NIL DO
network.deactivateDriver[];
UnlockCode[network.interrupt];
ENDLOOP;
DispatcherOff[];
FreeQueueDestroy[];
IF doStats THEN UnlockCode[StatsDefs.StatIncr];
UnlockCode[DriverDefs.GetInputBuffer]; -- QueueLocked(Tiny)
UnlockCode[DriverDefs.PutOnGlobalDoneQueue]; -- D
ispatcherLocked(Tiny)
state ← off;
END;


-- initialization
IF doDebug THEN
BEGIN
giantVector ← CommUtilDefs.AllocateLockedNode[SIZE[GiantVector]];
CommUtilDefs.SetDebuggingPointer[giantVector];
giantVector.statCounters ← IF doStats THEN StatsDefs.StatsGetCounters[] ELSE NIL;
giantVector.statStrings ← IF doStats THEN StatsDefs.StatsGetText[] ELSE NIL;
giantVector.slaThings ← giantVector.prThings ← NIL;
END;
START DriverDefs.DispatcherCold;
START DriverDefs.QueueCold;
END. -- Boss