DataMuseum.dk

Presents historical artifacts from the history of:

Bogika Butler

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Bogika Butler

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦06a9e7bb1⟧ TextFile

    Length: 52736 (0xce00)
    Types: TextFile
    Names: »MCCM.SA«

Derivation

└─⟦8fc713706⟧ Bits:30009789/_.ft.Ibm2.50007356.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »MCCM.SA« 

TextFile

 
æ*****************************************************************
                        Copyright 1984 by
                        NCR Corporation
                        Dayton, Ohio  U.S.A.
                        All Rights Reserved
******************************************************************
                        EOS Software produced by:
                        NCR Systems Engineering - Copenhagen
                        Copenhagen
                        DENMARK
*****************************************************************å
 
æ
         MMMM       MMMM    CCCCCCCCC    CCCCCCCCC MMMM       MMMM
         MMMMM     MMMMM  CCCCCCCCCCC  CCCCCCCCCCC MMMMM     MMMMM
         MMMMMM   MMMMMM CCCCC        CCCCC        MMMMMM   MMMMMM
         MMMM MM MM MMMM CCCC         CCCC         MMMM MM MM MMMM
         MMMM  MMM  MMMM CCCC         CCCC         MMMM  MMM  MMMM
         MMMM       MMMM CCCCC        CCCCC        MMMM       MMMM
         MMMM       MMMM  CCCCCCCCCCC  CCCCCCCCCCC MMMM       MMMM
         MMMM       MMMM    CCCCCCCCC    CCCCCCCCC MMMM       MMMM
 
 
                                 M C C M
 
                                  I P C
 
                               M O D U L E
 
 
               (DRIVER MODULE FOR MOTOROLA'S MCCM CONTROLLER)
                           EOS Operating System
 
The MCCM Ipc Module drives Motorola's Multi-Channel Communications Module
     through the Intelligent Peripheral Controller interface.
 
The module adheres to the EOS architectural standard for i/o-families.
 
The MCCM object manages a number of driver objects. A driver object is an
     access object which the MCCM object creates on call to the Assign-entry.
     The driver object is the 'access-path' to one of the devices (terminal
     or printer) which are operated by the MCCM controller. The controller
     operates up to eight devices numbered 0 through 7.
 
The driver object (or Line object) has Read- and Write-entries, and the
     user may wait for a break-condition on the object.
 
In this version only one of possibly several Line objects opened to the
     same device may have the exclusive i/o-reservation.
 
 
 
Copyright NCR Corporation 1983
 
Written:     April 1983
By:          Peter Mikkelsen, SE-Copenhagen.
 
Version id:  00/02  83-06-21
Last update: 83-09-12
 
To be changed:
 
å
æ$Eå
æ$H=0å
æ
OVERVIEW OF THE MODULE'S TEXT:                                      PAGE
==============================
 
Export description
Import description
Constants and types
Global routines:
 
å
OBJECT PROGRAM Mccm;
æ$L-å
æ$F=FAMILY.UNIV.IDå
æ$F=FAMILY.KNEL.IDå
æ$F=FAMILY.ALLOC.IDå
æ$F=FAMILY.SCHED.IDå
æ$F=FAMILY.OBJDIR.IDå
const OrgSys=4002;
æ$F=PASINCLU.MIKTYPES.SAå
æ$L+å
æ$Eå
(* removed 83-06-02
æ***** E X P O R T   D E S C R I P T I O N *****å
æ***********************************************å
 
OBJECT Ipc;
  CONST
    minDevno=0;  maxDevno=7;
  TYPE
    devnos=minDevno..maxDevno;
    IoType=integer;
 
  ENTRY Assign
    (OUT driver: ref æLAO or DAOå;
     IN iomode: IoType;
     IN devName: fullId);
        æ Creates a Line or Disc access object which acts a driver for the
          specified device. The access object attempts to reserve the use
          of the device as specified by 'iomode'å
 
  PRIVATE Close  ætermination procå
    (IN driver: ref;
        env: ref ækernel suppliedå);
        æ Cancels the reservations held by the driver å
 
  ENTRY ScanFiles
    (OUT scanOwner: ref æScanå);
        æ Not implemented in this demo-version å
 
  ENTRY RenameFile; ærejectå
  ENTRY CreateLink; ærejectå
  ENTRY DeleteLink; ærejectå
 
  ENTRY InitIpcSys
    (IN vector,level: integer;
     IN chanAddr: address);
        æ Initializes the Ipc object with controller specific info å
 
  ENTRY CreateFile
    (IN devName: fullId;
     IN devno: integer
    æIN hwConfig, swConfig: integerå);
        æ Ties a name to the device given by 'devno'. The configuration
          parameters are used to configurate MCCM devices each time it
          is Assign'ed (with ReadWriteRight) å
 
  ENTRY DeleteFile
    (IN devName: fullId);
        æ Deletes a device description. Drivers open to the device are
          abortedå
 
 
æ$Eå
  OBJECT Line; ære-entrantå
    æ This object acts as an access-path to a terminal or printer.
      Although several line objects to the same device may exist, only
      one of them is active at a time (the other objects reject all
      calls), namely the one with the (exclusive) r-, w-, or rw-Reserv
      iomode.
 
      Concurrency rules: (demo-version)
        All i/o calls are processed First-Come-First-Served. A process may
        wait independently for break on the driver object with i/o-
        reservation.
 
      Break condition:
        When a break condition occurs, all processes waiting in the driver
        object are returned with a break status (except the WaitBreak
        process which is returned with ok-status). Subsequent i/o
        calls will be rejected with break status until WaitReady is
        called and has returned.
 
      Speed up of calls:
        I/o calls:  Normally not possible to speed up (at least not if the
        i/o-operation has been sent to the ipc).
 
        WaitBreak: May be speeded up without affecting any other calls.
    å
 
    TYPE
      bufSpace=ARRAY Æ1..addrMaxÅ OF byte;
      bufRef=^^ ÆÅ bufSpace;
 
    ENTRY ReadSeq
      (IN segment: bufRef;
       OUT byteCount: integer);
          æ Returns one or more text- and/or command-records from the
            input stream. The call returns as soon as a record is avail-
            able from the stream or when 'buf' can hold no more records.
 
            Example: A text-record and a NL-record are often returned
            together because both records become available at the same
            time when a NL is received from the device.
 
            'Buf' must be able to hold at least a text-record with one
            character and a NL-record (i.e. 'buf's minimum length is
            6 bytes).
 
            'Count' returns the number of bytes defined in 'buf'. å
 
    ENTRY WriteSeq
      (IN segment: bufRef;
       OUT byteCount: integer);
          æ Gives the driver object a number of text- and/or command-
            records to put on the output stream. Only complete records
            are treated; incomplete records are ignored (i.e. no error
            reaction). 'Count' returns the number of bytes used from
            'buf'. 'Count' may be less than 'buf's length if
 
               (1) a device error or break condition occured preventing
                   the complete transfer. 'Count' corresponds to the last
                   byte of the last record to be successfully transmitted.
                   Result <> ok.
 
               (2) 'buf' contains an incomplete record. 'Count' indicates
                   how many complete records was accepted (by pointing
                   to the last byte of the last record to be accepted).
                   Result = ok. å
æ$Eå
    ENTRY ReadRandom;        æ reject å
    ENTRY WriteRandom;       æ reject å
    ENTRY Seek( IN baseMode; IN offset; OUT pos);
    ENTRY SetMode;           æ not demo å
    ENTRY GetFileInf
      (OUT ioSys: ref;
       OUT localId: integer;
       OUT fileName: fullId;
       OUT devClass: devClass;
       OUT bytesAllocated: integer; OUT dataBytes: integer;
       OUT minBufSize: integer; OUT cylSize æ=no of repeats å);
    ENTRY SetRights;         æ reject å
    ENTRY CheckRights;       æ not demo å
    ENTRY MoveRights;        æ not demo å æ necessary????? å
    ENTRY NewLink;           æ reject å
    ENTRY AllocSize;         æ reject å
    ENTRY DataSize;          æ reject å
 
    ENTRY WaitBreak;
          æ Waits for a break condition in the driver object. The called
            driver object must have an i/o-reservation. At most one process may
            wait in the entry independently of any concurrent i/o-calls
            to the object å
 
    ENTRY WaitReady;
          æ Clears the break condition status of the device. Dummy if there
            is no break condition on the device. The entry requires that
            the object called holds an i/o-reservation å
 
  END æLineå;
CONST IoFamily=4;
æ***** ERROR CONSTANTS *****å
CONST
  FileNotFound      =3;
  FileNameExists    =4;
  RightsOccupied    =6;
  PhysIoError       =8;
  AttentionPending  =10;
ænon-standard error constantså
  alreadyNamed=100;   æCreate: devno is already namedå
  alreadyWaiting=101; æWaitBreak: one process already waiting for breakå
END æIpcå;
end remove 83-06-02 *)
æ$F=FAMILY.IOSYS.IDå
CONST
ænon-standard error constantså
  alreadyNamed=100;   æCreate: devno is already namedå
  alreadyWaiting=101; æWaitBreak: one process already waiting for breakå
æotherå
  minDevno=0;  maxDevno=7;
TYPE
  devnos=minDevno..maxDevno;
 
æ$Eå
æ***** C O N S T A N T S   A N D   T Y P E S *****å
æ*************************************************å
CONST
  æ characters å
    nul=0;
    stx=2;
    etx=3;
    cr=13;
 
  æ text format records å
    nlLength=-3; æ 2 bytes å
    nlCom=cr;    æ 1 byte  å
 
  æ module constants å
    maxIdLength=48; æ # significant characters of a fullId in this module å
    kernelStack=100; æsupervisor stack on interrupt å
 
  æ default device constants å
    defOptions=0; æecho, don't configure, conversational modeå
    defHwConfig=16#8E4E00FF; æ8E: 8 bits, no parity, 1 stop bit, configure
                              4E: 9600 bps, direct connect, EOT turnaround
                              00: -
                              FF: max line size=255å
    defSwConfig=16#80000000; æ80: echo, configure
                              00: conversational mode
                              00: (poll chars)
                              00:  --"--å
 
  æ Ipc constants å
    æpacket sizeså
      rwSize=21;
      configSize=15;
      haltSize=7;
    æchannel commandså
      readCom=16#10;
      writeCom=16#20;
      configCom=16#40;
      haltCom=16#50;
    ædevice commandså
      ipcFormatted=16#01;
      ipcImage=16#02;
      stdDevCom=16#01;
    æstatus classeså
      completion=16#70;
      abortClass=16#71;
      solicited=16#72;
      unsolicited=16#80;
    æstatus valueså
      noErrors=       0;
      endConfig=      1;
      breakSt=        2;
      notReady=       3;
      outOfPaper=     7;
      devBusy=     16#C;
 
æ$Eå
æ***** Ipc Command and Status Packets *****å
TYPE
  outHead=RECORD  æ common header of command packets å
    stx:        byte;
    packetId:   byte;
    size:       byte;
    devno:      byte;
    chanCom:    byte;
    devCom:     byte;  æ6 byteså
  END;
  inHead=RECORD  æ common header of status packets å
    stx:        byte;
    packetId:   byte;
    size:       byte;
    devno:      byte;
    chanCom:    byte;
    statusClass:byte;
    status:     word;  æ8 byteså
  END;
  okind=(rwMess,verifyMess,haltMess,configMess);
  outMess=RECORD
    dummy: byte; æalignå
    CASE kind: okind OF
      rwMess:                  æ read/write å
         (h0:         outHead;
          blocks0:    word;
          blkSize0:   word;
          DMAaddress: integer;
          filler:     word;
          options:    integer; æ or sector # å
          etx0:       byte);
 
      verifyMess:
         (h1:         outHead; æ verify CRC, Format track etc. å
          blocks1:    word;
          blkSize1:   word;
          sectorNo1:  integer;
          etx1:       byte);
 
      haltMess:
         (h2:         outHead; æ clear fault, format disk, halt, ready å
          etx2:       byte);
 
      configMess:
         (h3:         outHead; æ configure å
          hwConfig:   integer;
          swConfig:   integer;
          etx3:       byte);
  END;
  iKind=(okAnsw,notReAnsw,crcAnsw,udcStAnsw,mccmStAnsw);
  inMess=RECORD æ status packet å
    dummy: byte; æalignå
    CASE kind: iKind OF
      okAnsw:
         (h0:         inHead;  æ UDC: no error (i/o)           å
          blocks:     word;    æ MCCM: no error, parity, break å
          blockSize:  word;
          DMAaddress: address;
          filler:     word;
          etx0:       byte);
 
      notReAnsw:
         (h1:         inHead;  æ device not ready etc. å
          etx1:       byte);
 
      crcAnsw:
         (h2:         inHead;  æ UDC CRC-error å
          blockNo:    integer;
          etx2:       byte);
 
      udcStAnsw:
         (h3:         inHead;  æ UDC device status (unsolicited) å
          noLogBlock: integer;
          etx3:       byte);
 
      mccmStAnsw:
         (h4:         inHead;  æ MCCM device status (solicited and  å
          devStat:    integer;
          hwConfig:   integer;
          swConfig:   integer;
          etx4:       byte);
  END;
 
  requestState=(ipcNotStarted,ipcStarted,ipcAnswered);
 
  ipcRequest=RECORD
    æ output message = command packet å
    o: outMess;
    i: inMess;
    state: requestState;
  END;
æ$Eå
æ***** Ipc object *****å
TYPE
  maxFullId=ARRAY Æ1..maxIdLengthÅ OF char;
  countRec=RECORD
    transfers,   æ# i/o-transfers started in the driver å
    repeats,     æ# reated i/o-transferså
    q1,          æ# req's received when one other request occupies driverå
    q2,          æ# req's received when two other requests occupies driverå
    q3: integer; æ# req's received when three other requests occupies driverå
  END;
  ipcData=RECORD
    break:       ARRAY ÆdevnosÅ OF boolean; æ break conditions å
    ipcReserved: integer;  æ # processes waiting in ipc object å
    ackFifo:     ARRAY ÆdevnosÅ OF devnos; æ fifo of requests waiting å
    ackFifoFirst,                          æ for the use of the ipc-  å
    ackFifoLast: devnos;                   æ channel.                 å
    chanAddr:    address; æabsolute address of channel registerså
    requests:    ARRAY ÆdevnosÅ OF ipcRequest;
    vector,              æ interrupt vector å
    level:       byte;   æ interrupt level  å
    dir:         ARRAY ÆdevnosÅ OF RECORD  æ directory å
                                     name: maxFullId;
                                     nameLength: 0..maxIdLength;
                                     hwConfig,
                                     swConfig: integer
                                   END;
    count:       ARRAY ÆdevnosÅ OF countRec;
  END;
  drivLocRef=^^drivLocals;
  ipcLocRef=^^ipcLocals;
  ipcLocals=RECORD  æ local pointers in Ipc object å
    code:         ^^;
    ownLocaldata: ^^ipcData; æcreated by Stubå
    localdata:    ^^ipcData; æcopy of ownLocaldata to become residentå
    currDriver:   ARRAY ÆdevnosÅ OF drivLocRef; æenvelope ptr's to drivers
                                                  with i/o-reservationå
    stubRef:      ^^ObjDir;       æinserted by the Stubå
    iSchedRef:    ^^Scheduler;    æinserted by the Stubå
    schedRef:     ^^Scheduler;    æinserted by the Stubå
    allocRef:     ^^Allocate;     æinserted by the Stubå
    egoEnv:       ipcLocRef;      æinserted by the Stubå
    interruptPtr: ^^;  ækernel's interrupt pointerå
    ipcGate:      gateRef;
    dirGate:      gateRef; æprotects the 'dir'-datastructure, the 'drivers'
                       manager set, and the reservation status per deviceå
    drivers:      ARRAY ÆdevnosÅ OF drivLocRef; æmanager set of driver obj'så
    ownSet:       ^^; æowner set for ipcGate, complete cond's, and breakCond
                                                                 cond'så
    egoObj : ^^;
  END;
æ$Eå
æ***** Driver object types *****å
  drivData=RECORD  æ local data in Driver object å
    devno:        devnos;
    reserv:       IoType;
    mode:         RECORD
                    timeout: integer;
                    options: integer
                    æretries, verify etc?å
                  END;
    devReserved:  integer;
    waitBreak:    boolean;
    waitEmpty:    boolean;
    count:        countRec;
    rbBase,
    rbLast:       integer;  æspecifies used part of readBufå
    afterNL:      integer;  æonly used in UNIX modeå
    æ only for disk
      currPos:    integer;
      discSize,
      cylSize,
      blockSize:  integer å
  END;
 
  buf256= ARRAY Æ1..256Å  OF char;
  buf1024=ARRAY Æ1..1024Å OF char;
 
  drivLocals=RECORD
    code:      ^^;
    localdata: ^^drivData;
    ipc:       ipcLocRef; æto managerå
    complete:  condRef;
    breakCond: condRef;
    schedQ:    condRef; æFCFS queueå
    empty:     condRef; æsignalled when no processes wait for i/o in objå
    ownSet:    ^^; æowner set for 'complete' and 'breakCond'å
    auxBuf:    ^^buf1024; æfor Unix writeså
    readBuf:   ^^buf256; æline read-a-head in UNIX modeå
    readFifo:  ^^Gate; æprotects readBufå
  END;
æ$Eå
æ***** E X T E R N A L   P R O C E D U R E S *****å
æ*************************************************å
PROCEDURE startIpc
  (vector: byte;
   devno: devnos);
  FORWARD;
 
PROCEDURE intmccm;
  FORWARD;
æ$Eå
æ***** G L O B A L   P R O C E D U R E S *****å
æ*********************************************å
 
procedure checkOk
  (res: resultType);
  ægenerates exception on a bad result, but does not test outputå
begin
  if res.main<>ok then exception(res);
end;
 
æ GetLength and putLength are used to insert, resp. retrieve, the length
  fields in the text record format å
TYPE
  tagMode=(wordMode,byteMode);
  convInt=RECORD
    fill: byte; æto align word and byteså
    CASE tag: tagMode OF
      wordMode: (w: word);
      byteMode: (u1,u2: byte);
  END;
 
FUNCTION getLength
  (VAR b: blockPtr)
  : integer;
  VAR conv: convInt;
BEGIN
  conv.tag:=byteMode;
  conv.u1:=bÆ1Å;  conv.u2:=bÆ2Å;
  conv.tag:=wordMode;
  getLength:=conv.w;
END æ***getLength***å;
 
PROCEDURE putLength
  (VAR b: blockPtr;
   length: integer);
  VAR conv: convInt;
BEGIN
  conv.tag:=wordMode;
  conv.w:=length;
  conv.tag:=byteMode;
  bÆ1Å:=conv.u1;  bÆ2Å:=conv.u2;
END æ***putLength***å;
 
PROCEDURE putNL
  (VAR b: blockPtr);
BEGIN
  putLength(b,nlLength);
  bÆ3Å:=nlCom;
END æ***putNL***å;
æ$Eå
æ----- AckFifo Routines -----å
 
æ   The following routines operate on the AckFifo datastructure. The
    AckFifo is a FIFO-type queue for ipcRequests waiting for access to
    the channel.
 
       putAckFifo:   insert request at the end of the fifo queue
       getAckFifo:   get next request in queue
       removeAckFifo: remove a specific request from the queue.
 
    The number of requests waiting in the AckFifo queue is indicated by
    'ipcReserved' (namely one less than this figure).
 
    The AckFifo datastructure is dimensioned so that overflow never
    occurs (there is room for one request per device).
å
PROCEDURE putAckFifo
  (devno: devnos;
   VAR c: ipcData);
   var i: integer;
BEGIN
   c.ackFifoLast:=(c.ackFifoLast+1) MOD (maxDevno+1);
   c.ackFifoÆc.ackFifoLastÅ:=devno;
æ#b# i:=c.ackFifoFirst;
printVar('^^^^putAckFifo, first= ', i);
i:=c.ackFifoLast;
printVar('^^^^putAckFifo, last= ', i);
printVar('^^^^putAckFifo, ackfifo= ',c.ackFifo);
 #e#å
END æ***putAckFifo***å;
 
(* implemented in interrupt procedure
FUNCTION getAckFifo
  (VAR c: ipcData)
  : devnos;
BEGIN
  getAckFifo:=c.ackFifoÆc.ackFifoFirstÅ;
  c.ackFifoFirst:=(c.ackFifoFirst+1) MOD (maxDevno+1);
END æ***getAckFifo***å;
*)
(* removed 83-04-25
PROCEDURE removeAckFifo
  (devno: devnos;
   VAR c: ipcData);
  VAR i: devnos;
BEGIN
  æassert: c.ipcReserved>0å
  i:=c.ackFifoFirst;
  WHILE c.ackFifoÆiÅ<>devno AND i<>c.ackFifoLast DO
    i:=(i+1) MOD (maxDevno+1);
  END;
  IF c.ackFifoÆiÅ<>devno THEN exception(systemError);
  WHILE i<>c.ackFifoLast DO BEGIN
    c.ackFifoÆiÅ:=c.ackFifoÆ(i+1) MOD (maxDevno+1)Å;
    i:=(i+1) MOD (maxDevno+1);
  END;
  c.ackFifoLast:=(c.ackFifoLast+maxDevno) MOD (maxDevno+1);
           æi.e. decrease ackFifoLastå
END æ***removeAckFifo***å;
end 83-04-25 *)
æ$Eå
PROCEDURE sendReq
  (VAR complete: condRef;
   VAR req: ipcRequest;
   devno: devnos;
   VAR c: ipcData);
  VAR ignore: ResultType;
      retry: boolean;
BEGIN
  c.requestsÆdevnoÅ:=req;
  REPEAT
    c.requestsÆdevnoÅ.state:=ipcNotStarted;
    c.ipcReserved:=c.ipcReserved+1;
    IF c.ipcReserved>1 THEN putAckFifo(devno,c)
    ELSE startIpc(c.vector,devno);
    ignore:=complete.Wait;
    retry:=(c.requestsÆdevnoÅ.i.h0.statusClass=completion) AND
           (c.requestsÆdevnoÅ.i.h0.status=devBusy);
  UNTIL NOT retry;
  req.i:=c.requestsÆdevnoÅ.i; æreturn answerå
END æ***sendReq***å;
æ$Eå
æ***** L I N E   O B J E C T   I M P L E M E N T A T I O N *****å
æ***************************************************************å
 
PROGRAM lineImplement OBJECT Fao WITH drivLocals;
 
æ***** LOCAL ROUTINES *****å
 
FUNCTION objStatus
  (VAR d: drivData;
   VAR c: ipcData;
   reserv: IoType)
  : resultType;
BEGIN
  IF NOT ((reserv=NoRights) OR
          (d.reserv=ReadWriteRight) OR
          (d.reserv=reserv)) THEN
    objStatus:=genRes(-EntryIllegal,Universal,0)
  ELSE IF c.breakÆd.devnoÅ THEN
    objStatus:=genRes(-BreakPending,IoFamily,0);
END æ***objStatus***å;
 
æ$Eå
æ----- doIo -----å
 
æ Function doIo is the central routine controlling the synchronization and
  sceduling of i/o requests from the driver object. Although it is textually
  placed here in the driver object, it logically belongs to both the driver
  and ipc objects å
 
FUNCTION doIo
  (VAR buf: ref;
   base: integer; æbase of data in bufå
   VAR req: ipcRequest;
   reserv: IoType;
   VAR d: drivData)
  : resultType;
  VAR
    i: integer;
    use: IoType;
    res: ResultType;
BEGIN
  res.main:=ok;
  req.o.kind:=rwMess; æread/write kindå
  IN
    CASE reserv OF
      ReadRight: use:=WriteRight;
      WriteRight: use:=ReadRight;
      OTHERWISE use:=reserv;
    END;
    check(ipc^^.ipcGate.Resident(buf; use));
    WITH c=ipc^^.localdata^^ DO BEGIN
      check(ipc^^.ipcGate.Lock);
      IN ægate lockedå
        checkOk(objStatus(d,c,reserv));
        d.devReserved:=d.devReserved+1;
        d.count.transfers:=d.count.transfers+1;
        IN æd.devReserved increasedå
          IF d.devReserved>1 THEN BEGIN
æprintVar('.....doIo scheduling queue..... devReserved= ',d.devReserved);å
            æupdate countRecå
            WITH d.count DO BEGIN
              IF d.devReserved=2 THEN q1:=q1+1
              ELSE IF d.devReserved=3 THEN q2:=q2+1
              ELSE q3:=q3+1;
            END;
         æ  check(Propagate(propReject)); kernel-errorå
              check(schedQ.Wait); æmay be speeded upå
         æ  check(Propagate(propNone));   kernel-errorå
            check(objStatus(d,c,reserv));
          END;
          æ do i/o å
          check(IoBegin(buf,req.o.DMAaddress,i,i));
          req.o.DMAaddress:=req.o.DMAaddress+base; æstart of text in bufå
          sendReq(complete,req,d.devno,c); æsend request to ipcå
          check(IoEnd(buf,i,i,i));
          IF NOT ((req.i.h0.statusClass=completion) AND
                  (req.i.h0.status=ok)) THEN
            IF ((req.i.h0.statusClass=completion) AND
                (req.i.h0.status=2)) THEN
            BEGIN
              check(breakCond.Signal);
              exception(genRes(-BreakPending,IoFamily,0));
            END ELSE BEGIN
 printVar('mccm: bad result, req.i= ', req.i);
              exception(genRes(PhysIoError,IoFamily,0));
            END;
        DO IF res.main=ok THEN res:=getException;
        d.devReserved:=d.devReserved-1;
        IF d.devReserved>0 THEN
          check(schedQ.Signal) æstart next in queue to this deviceå
        ELSE IF d.waitEmpty THEN BEGIN
          d.waitEmpty:=false;
          check(empty.Signal);
        END;
      DO IF res.main=ok THEN res:=getException;
      check(ipc^^.ipcGate.Open);
    END æwithå;
  DO IF res.main=ok THEN res:=getException;
  doIo:=res;
END æ***doIo***å;
 
æ$Eå
ENTRY ReadSeq
  æIN segment: bufRef; OUT byteCount: integerå
  WITH RECORD
    t: ^^;
    buf: bufRef;
  END;
  CONST
    readComOverhead=6; æ# bytes which must be available for overhead in Readå
    lf=10; cr=13; ctrlD=4;
  VAR
    readLength: integer;
    i: integer;
    res: ResultType;
    req: ipcRequest;
    mode: integer;
    intPtr: ^ integer;
    echoLF: boolean;
    c: char;
    base, last: integer;
    stop: boolean;
BEGIN
  res.main:=ok;
  echoLF:=false;
  check(readFifo.Lock);
  IN
    IF NextValArg(intPtr) THEN BEGIN
      mode:=intPtr^;
      IF NOT ((mode=Image) OR (mode=Unix) OR (mode=Formatted)) THEN
        exception(genRes(-DataValueIllegal,Universal,-2));
    END ELSE mode:=Image;
 
æ  printVar('Readseq called, mode= ',mode);  å
   IF mode=Unix THEN BEGIN æinserted 83-09-12å
     WITH d=localdata^^ DO BEGIN
       IF d.rbBase=d.rbLast THEN BEGIN
         æreadBuf is empty - read a new lineå
         æ set up read request å
          req.o.kind:=rwMess; æread/writeå
          req.o.h0.stx:=        stx;
          req.o.h0.packetId:=   0;
          req.o.h0.size:=       rwSize;
          req.o.h0.devno:=      d.devno;
          req.o.h0.chanCom:=    readCom;
          req.o.h0.devCom:=ipcFormatted;
          req.o.blocks0:=       1;
          req.o.blkSize0:=      80;
          req.o.options:=       d.mode.options;
          req.o.etx0:=          etx;
          checkOk(doIo(readBuf,0,req,ReadRight,d));
          d.rbBase:=0;;  d.rbLast:=req.i.blockSize+1 ælfå;
          WITH b=readBuf^^ DO bÆd.rbLastÅ:=chr(lf);
       END;
       base:=d.rbBase;  last:=d.rbLast;
     END æwith localdataå;
     i:=1;  stop:=false;  byteCount:=0;
     WITH dest=segment^^, source=readBuf^^ DO BEGIN
       REPEAT
         c:=sourceÆbase+iÅ;
         IF c=chr(cr) THEN c:=chr(lf);
         IF c<>chr(ctrlD) THEN BEGIN
           destÆiÅ:=ord(c);
           byteCount:=byteCount+1;
         END;
         i:=i+1;
         stop:=(c=chr(ctrlD)) OR (c=chr(lf)) OR (base+i>last)
                              OR (i>elements(dest));
       UNTIL stop;
     END æwith dest,sourceå;
     WITH d=localdata^^ DO d.rbBase:=base+i-1;
   END ELSE BEGIN
 
    check(Copy(segment,buf)); æbecause of Resident-operationå
    WITH b=buf^^ DO readLength:=elements(b);
    IF mode=Formatted THEN readLength:=readLength-readComOverhead;
    IF readLength<=0 THEN
      exception(genRes(-DataValueIllegal,Universal,4));
    WITH d=localdata^^ DO BEGIN
      æ set up read request å
        req.o.kind:=rwMess; æread/writeå
        req.o.h0.stx:=        stx;
        req.o.h0.packetId:=   0;
        req.o.h0.size:=       rwSize;
        req.o.h0.devno:=      d.devno;
        req.o.h0.chanCom:=    readCom;
        IF readLength=1 THEN req.o.h0.devCom:=ipcImage
        ELSE                 req.o.h0.devCom:=ipcFormatted;
        req.o.blocks0:=       1;
        req.o.blkSize0:=      readLength;
        req.o.options:=       d.mode.options;
        req.o.etx0:=          etx;
      CASE mode OF
        Unix,
        Image: checkOk(doIo(buf,0,req,ReadRight,d));
        Formatted: checkOk(doIo(buf,2,req,ReadRight,d));
      END;
      WITH b=buf^^ DO BEGIN
        byteCount:=req.i.blockSize;
        IF mode=Unix THEN BEGIN
          IF readLength=1 THEN BEGIN
            IF bÆ1Å=13 æcrå THEN BEGIN
              bÆ1Å:=10 ælfå;
              æimage mode: only carriage return echoedå
              echoLF:=true;
              d.afterNL:=0;
            END;
          END ELSE BEGIN
            IF byteCount<readLength THEN BEGIN
              byteCount:=byteCount+1;
              bÆbyteCountÅ:=10;
              d.afterNL:=0;
              æformatted mode: newline echoed okå
            END;
          END;
        END ELSE BEGIN
          IF mode=Formatted THEN BEGIN
            IF byteCount=readLength THEN BEGIN
              byteCount:=byteCount+2;
              putLength(b,byteCount);
            END ELSE BEGIN
              IF byteCount>0 THEN BEGIN
                byteCount:=byteCount+2;
                putLength(b,byteCount);
              END;
              WITH b2=bÆbyteCount+1..byteCount+3Å DO putNL(b2);
              byteCount:=byteCount+3;
              d.afterNL:=0;
            END æelseå;
          END; æFormattedå
        END æelseå;
      END æwithå;
      IF echoLF THEN BEGIN
        æmodify 'req' to echo a single LF charå
        req.o.h0.chanCom:=writeCom;
        req.o.h0.devCom:=ipcImage;
        req.o.blkSize0:=1;
        checkOk(doIo(buf,byteCount-1,req,WriteRight,d));
      END;
    END æwithå;
 END æif-then-elseå;
  DO IF res.main=ok THEN res:=getException;
  check(readFifo.Open);
æ printVar('readseq, bytecount= ',bytecount); å
  ObjReturn(res);
END æ***ReadSeq***å;
æ$Eå
ENTRY WriteSeq
  æIN segment: bufRef; OUT byteCount: integerå
  WITH RECORD
    t: ^^;
    buf: bufRef;
  END;
  CONST ht=9;  space=32;
  VAR bLength,
      recLength: integer;
      mode: integer;
      intPtr: ^ integer;
      u3: byte;
      res: resultType;
      finish: boolean;
      req: ipcRequest;
      sourcePos: integer;
      destPos: integer;
      afterNL: integer;
BEGIN
 res.main:=ok;
 IN
  IF NextValArg(intPtr) THEN BEGIN
    mode:=intPtr^;
    IF NOT ((mode=Formatted) OR (mode=Unix) OR (mode=Image)) THEN
      exception(genRes(-DataValueIllegal,Universal,-2));
  END ELSE mode:=Image;
  IF mode=Unix THEN BEGIN
    sourcePos:=1;
    destPos:=1;
    WITH d=localdata^^ Do afterNL:=d.afterNL;
    WITH source=segment^^, dest=auxBuf^^ DO BEGIN
      bLength:=elements(source);
      WHILE (sourcePos<=bLength) AND
            (destPos<=bytes(buf1024)) DO BEGIN
 
        IF sourceÆsourcePosÅ=ht THEN BEGIN ætab modulo 8å
          REPEAT
                 destÆdestPosÅ:=chr(space);
                 destPos:=destPos+1;
                 afterNL:=afterNL+1;
          UNTIL (afterNL MOD 8 = 0) OR (destPos>bytes(buf1024));
        END ELSE BEGIN
          destÆdestPosÅ:=chr(sourceÆsourcePosÅ);
          destPos:=destPos+1;
          afterNL:=afterNL+1;
          IF sourceÆsourcePosÅ=10 THEN BEGIN
            destÆdestPosÅ:=chr(13);
            destPos:=destPos+1;
            afterNL:=0;
          END;
        END;
        sourcePos:=sourcePos+1;
      END;
      bLength:=destPos-1;
    END;
    with d=localdata^^ do d.afterNL:=afterNL;
    check(Copy(auxBuf,buf));
  END ELSE BEGIN
    check(Copy(segment,buf)); æbecause of Resident-operationå
    WITH b=buf^^ DO bLength:=elements(b);
  END;
  WITH d=localdata^^ DO BEGIN
    byteCount:=0;
    CASE mode OF
     Unix,
     Image: BEGIN
      req.o.kind:=rwMess;
      WITH req.o DO BEGIN
        h0.stx:= stx;
        h0.packetId:=0;
        h0.size:=rwSize;
        h0.devno:=d.devno;
        h0.chanCom:=writeCom;
        h0.devCom:=ipcImage;
      END;
      req.o.blocks0:=1;
      req.o.options:=d.mode.options;
      req.o.etx0:=etx;
      req.o.blksize0:=bLength;
      checkOk(doIo(buf,0,req,WriteRight,d));
      byteCount:=req.i.blockSize;
      d.afterNL:=afterNL;
     END;
 
     Formatted: BEGIN
      finish:=bLength<3 æminimum rec sizeå;
      WHILE NOT finish DO BEGIN
        WITH b=buf^^, b2=bÆbyteCount+1..bLengthÅ DO BEGIN
          recLength:=getLength(b2);
          u3:=b2Æ3Å;
        END;
        finish:=(recLength=0 æstop sentinelå) OR
                (bLength<byteCount+abs(recLength) æincomplete recordå);
        IF NOT finish THEN BEGIN
          æ prepare 'req': fill in default values å
            req.o.kind:=rwMess; æread/writeå
            WITH req.o DO BEGIN
              h0.stx:= stx;
              h0.packetId:=0;
              h0.size:=rwSize;
              h0.devno:=d.devno;
              h0.chanCom:=writeCom;
              h0.devCom:=ipcImage;
            END;
            req.o.blocks0:=1;
            æ'req.o.blkSize0' must be suppliedå
            æreq.o.DMAaddress to be supplied later when buffer
             becomes fixed in the memory (IoBegin) å
            req.o.options:=d.mode.options;
            req.o.etx0:=etx;
          IF recLength>0 THEN BEGIN ætext recordå
            req.o.blkSize0:=recLength-2 æfor length fieldå;
            checkOk(doIo(buf,byteCount+2,req,WriteRight,d));
            byteCount:=byteCount+recLength;
          END ELSE BEGIN
            IF (recLength=nlLength) AND (u3=nlCom) THEN BEGIN ænl-recordå
               æoutput a single CR character -- use the one in buf (nlCom)å
              req.o.h0.devCom:=ipcFormatted;
              req.o.blkSize0:=1; æcr charå
              checkOk(doIo(buf,byteCount+2,req,WriteRight,d));
              byteCount:=byteCount+3;
            END ELSE BEGIN
              ætext format errorå
              exception(genRes(-DataValueIllegal,Universal,4));
            END;
          END;
        END æif not finishå;
        finish:=finish OR (bLength-byteCount<3 æminimum rec sizeå);
      END æwhileå;
     END;
   END æcaseå;
  END æwithå;
 DO IF res.main=ok THEN res:=getException;
 ObjReturn(res);
END æ***WriteSeq***å;
æ$Eå
ENTRY ReadRandom
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY WriteRandom
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY Seek æ baseMode, offset, out pos å
  WITH RECORD t: ^^; END;
BEGIN
  if ( baseMode=fromEnd ) and ( offset = 0 ) then
    with d=localdata^^ do
      d.rbBase:= d.rbLast;  æposition:= after last charå
  pos:=0; ædummyå
END;
 
ENTRY SetRights
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY CheckRights
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY MoveRights
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY NewLink
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY GetFileInf
  WITH RECORD t: ^^; END;
CONST shift16=16#10000;
VAR i,j:integer;
BEGIN
  checkOk( copy(ipc^^.egoObj,ioSys));
  with d=localdata^^ , ip=ipc^^.ownLocaldata^^ do begin
    localId:= (256+ip.vector) * shift16 + d.devno;
    if maxIdLength >= elements(fileName)
       then i:= elements(filename)
       else i:= maxIdLength - 1;
    for j:= 1 to i do filenameÆjÅ:=ip.dirÆd.devnoÅ.nameÆjÅ;
    fileNameÆi+1Å:= chr(0);
    devClass:= 1; æ 1=terminal å
    bytesAllocated:= d.rbLast - d.rbBase;
    dataBytes:= bytesAllocated;
    minBufSize := 1;
    cylSize:= d.count.repeats;
  end æwithå;
END ;
 
 
ENTRY SetMode
  WITH RECORD t: ^^; END;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY DataSize WITH tempRefs;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
ENTRY AllocSize WITH tempRefs;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
æ$Eå
ENTRY WaitBreak
  WITH RECORD t: ^^; END;
  VAR res: resultType;
BEGIN
  res.main:=ok;
  WITH d=localdata^^, c=ipc^^.localdata^^ DO BEGIN
    IN
      check(ipc^^.ipcGate.Lock);
      IN æipcGate lockedå
        IF d.waitBreak THEN exception(genRes(-alreadyWaiting,IoFamily,0));
        IF d.reserv=NoRights THEN exception(genRes(-EntryIllegal,Universal,0));
        IF NOT c.breakÆd.devnoÅ  THEN BEGIN
          d.waitBreak:=true;
        æ check(Propagate(propReject));  kernel-errorå
            res:=breakCond.Wait;
          æcheck(Propagate(propNone));å
          d.waitBreak:=false;
        END;
      DO IF res.main=ok THEN res:=getException;
      check(ipc^^.ipcGate.Open);
    DO IF res.main=ok THEN res:=getException;
  END æwithå;
  ObjReturn(res);
END æ***WaitBreak***å;
 
ENTRY WaitReady
  WITH RECORD t: ^^; END;
  VAR res:resultType;
BEGIN
  res.main:=ok;
  WITH d=localdata^^, c=ipc^^.localdata^^ DO BEGIN
    check(ipc^^.ipcGate.Lock);
      IN
        IF d.reserv=NoRights THEN
          exception(genRes(-EntryIllegal,Universal,0));
        IF c.breakÆd.devnoÅ THEN BEGIN
          IF d.devReserved>0 THEN BEGIN
            æThis code should actually never be executed because of the
             kernel's scheduling strategy for gates and conditionså
            d.waitEmpty:=true;  check(empty.Wait);
            check(empty.signal); æif more processes are waitingå
          END;
          c.breakÆd.devnoÅ:=false;
        END;
      DO IF res.main=ok THEN res:=getException;
    check(ipc^^.ipcGate.Open);
  END æwithå;
  ObjReturn(res);
END æ***WaitReady***å;
 
entry dup with temprefs;
BEGIN  ObjReturn(genRes(-EntryIllegal,Universal,2));  END;
 
OTHERWISE LineOther
  WITH RECORD t: ^^; END;
BEGIN
  exception(genRes(-EntryIllegal,Universal,2));
END æ***OtherFunc***å;
 
END æ lineImplement å;
æ$Eå
æ***** I P C   O B J E C T   I M P L E M E N T A T I O N *****å
æ*************************************************************å
 
PROGRAM mccmImplement OBJECT IoSys WITH ipcLocals;
 
PRIVATE Close
  (IN driver, env: ref ækernel suppliedå);
 
æ***** LOCAL ROUTINES *****å
 
FUNCTION same
  (dirIndex: integer;
   id: fullId;
   VAR d: ipcData)
  : boolean;
æcompares the two fullid'så
  VAR i, length: integer;
      stop: boolean;
BEGIN
  length:=d.dirÆdirIndexÅ.nameLength;
  stop:=length<>elements(id);
  i:=1;
  WHILE (i<=length) AND NOT stop DO BEGIN
    stop:=d.dirÆdirIndexÅ.nameÆiÅ<>idÆiÅ;
    i:=i+1;
  END;
  same:=NOT stop;
END æ***same***å;
 
FUNCTION search
  (id: fullId;
   VAR d: ipcData)
  : devnos;
  VAR i: integer;
      found: boolean;
BEGIN
  i:=minDevno;
  found:=false;
  WHILE (i<=maxDevno) AND NOT found DO BEGIN
    found:=same(i,id,d);
    IF NOT found THEN i:=i+1;
  END;
  IF NOT found THEN
    exception(genRes(-FileNotFound,IoFamily,-1));
  search:=i;
END æ***search***å;
æ$Eå
æ***** ENTRIES *****************************************å
æ*******************************************************å
 
ENTRY InitIpcSys
  æIN vector, level: integer; IN chanAddr: addresså
  WITH RECORD
    t: ^^;
    tempOwn:^^;
  END;
  VAR intprocAddr: address;
      i: integer;
      res: resultType;
BEGIN
  res.main:=ok;
  æcreate dirGateå
    check(schedRef.NewGate(OUT dirGate));
  æcreate ipcGateå
    check(iSchedRef.NewGate(OUT tempOwn;level));
    check(Copy(tempOwn,ipcGate));
    check(MoveOwn(tempOwn,ownSet));
    check(ipcGate.Resident(ipcGate));
  æcreate interrupt ptrå
    check(iSchedRef.NewChannel(OUT interruptPtr, IN code;
                                 vector,level,kernelStack,addr(intmccm)));
  æis it necessary to make code segment resident?????å
  æmake localdata residentå
    check(Copy(ownLocalData,localdata));
    check(ipcGate.Resident(localdata));
  æinitialize localdataå
    WITH d=localdata^^ DO BEGIN
      d.chanAddr:=chanAddr;
      d.vector:=vector;
      d.level:=level;
      FOR i:=minDevno TO maxDevno DO BEGIN
        d.dirÆiÅ.nameLength:=0;
        WITH d.countÆiÅ DO BEGIN
          transfers:=0;  repeats:=0;
          q1:=0;  q2:=0;  q3:=0;
        END;
      END;
      d.ipcReserved:=0;
      d.ackFifoFirst:=minDevno+1;  d.ackFifoLast:=minDevno;
    END;
  check(MakeReentrant(egoEnv));
  ObjReturn(res);
END æ***ENTRY Init***å;
æ$Eå
ENTRY CreateFile
  ædevName: fullId; devno: devnos (hwConfig, swConfig: integer)å
  WITH RECORD
    t:^^;
  END;
  VAR intPtr: ^integer;
      i,length: integer;
      res: resultType;
BEGIN
  res.main:=ok;
  check(dirGate.Lock);
  IN ædirGate lockedå
    WITH d=localdata^^ DO BEGIN
      IF d.dirÆdevnoÅ.nameLength<>0 THEN
        exception(genRes(-alreadyNamed,IoFamily,-2));
      FOR i:=minDevno TO maxDevno DO
        IF same(i,devName,d) THEN
          exception(genRes(-FileNameExists,IoFamily,-1));
      length:=elements(devName);
      IF length>maxIdLength THEN length:=maxIdLength;
      WITH d.dirÆdevnoÅ DO BEGIN
        FOR i:=1 TO length DO nameÆiÅ:=devNameÆiÅ;
        nameLength:=length;
        æoptional parameterså
          IF NextValArg(intPtr) THEN hwConfig:=intPtr^
          ELSE hwConfig:=defHwConfig;
          IF NextValArg(intPtr) THEN swConfig:=intPtr^
          ELSE swConfig:=defSwConfig;
      END æwithå;
    END æwithå;
  DO res:=getException;
  check(dirGate.Open);
  ObjReturn(res);
END æ***ENTRY Create***å;
æ$Eå
ENTRY DeleteFile
  ædevName: fullIdå
  WITH RECORD
    t:^^;
    refDriver: ^^;
  END;
  VAR devno: devnos;
      stop,
      res: resultType;
BEGIN
  res.main:=ok;
  check(dirGate.Lock);
  IN  ædirGate lockedå
    WITH d=localdata^^ DO BEGIN
      devno:=search(devName,d);
      d.dirÆdevnoÅ.nameLength:=0;
      æabort any drivers open to the deviceå
        stop:=FirstInSet(driversÆdevnoÅ,refDriver);
        WHILE stop.main=ok DO BEGIN
          check(Abort(refDriver));
          stop:=NextInSet(driversÆdevnoÅ,refDriver);
        END;
    END æwithå;
  DO IF res.main=ok THEN res:=getException;
  check(dirGate.Open);
  ObjReturn(res);
END æ***ENTRY Delete***å;
æ$Eå
ENTRY Assign
  æOUT ownedFao: ref; IN fileName: fullId; ioRights:ioTypeå
  WITH RECORD
    t:^^;
    tempMan: ^^drivLocals;
    tempEnv: ^^drivLocals;
  END;
  VAR s: sizeType;
      res, ignore: resultType;
      i: integer;
      devno: devnos;
      req: ipcRequest;
BEGIN
  res.main:=ok;
  æcreate access objectå
    ignore:=ClearSize(s);
    ignore:=AddEnv(s,refs(drivLocals)); ignore:=AddSeg(s,bytes(drivData));
    check(allocRef.NewObj(OUT ownedFao; makeSize(2000,500), OUT i));
    ignore:=ClearSize(s);
    check(DeclGen(ownedFao,tempMan,tempEnv,refs(drivLocals),Close,s,s,
                  refs(lineImplement),bytes(lineImplement),0,
                  addr(lineImplement),s,true));
    IN  æenvelope createdå
      check(Copy(code,tempMan^^.code));
      check(Copy(egoEnv,tempMan^^.ipc));
      check(ipcGate.Resident(tempMan^^.ipc));
      check(schedRef.NewGate(OUT tempMan^^.readFifo));
      æcomplete condå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.complete));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.complete));
      æbreakCondå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.breakCond));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.breakCond));
      æschedQå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.schedQ));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.schedQ));
      æemptyå
        check(ipcGate.NewCond(OUT tempMan^^.ownSet));
        check(Copy(tempMan^^.ownSet,tempMan^^.empty));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.empty));
      ælocaldataå
        check(NewSeg(tempMan^^.ownSet,bytes(drivData)));
        check(Copy(tempMan^^.ownSet,tempMan^^.localdata));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.localdata));
      æauxBufå
        check(NewSeg(tempMan^^.auxBuf,bytes(buf1024)));
      æreadBufå
        check(NewSeg(tempMan^^.ownSet,bytes(buf256)));
        check(Copy(tempMan^^.ownSet,tempMan^^.readBuf));
        IF ioRights<>NoRights THEN
          check(ipcGate.Resident(tempMan^^.readBuf));
      check(dirGate.Lock);
      IN  ædirGate lockedå
        WITH d=localdata^^ DO BEGIN
          devno:=search(fileName,d);
          WITH c=tempMan^^.localdata^^ DO BEGIN
            c.devno:=devno;
            c.reserv:=ioRights;
            c.mode.options:=defOptions;
           æc.mode.timeout:=?;å
            c.devReserved:=0;
            c.waitBreak:=false;
            c.waitEmpty:=false;
            c.afterNL:=0;
            c.rbBase:=0;
            c.rbLast:=c.rbBase;  æi.e., emptyå
            WITH c.count DO BEGIN
              transfers:=0;  repeats:=0;
              q1:=0;  q2:=0;  q3:=0;
            END;
          END;
          æcheck the ioRights reservationå
          IF ioRights<>NoRights THEN BEGIN
            IF SameEntity(currDriverÆdevnoÅ,void) THEN BEGIN
              check(Copy(tempMan,currDriverÆdevnoÅ));
              check(ipcGate.Resident(currDriverÆdevnoÅ));
              d.breakÆdevnoÅ:=false;
            END ELSE BEGIN
              exception(genRes(-RightsOccupied,IoFamily,0));
            END;
          END;
        END æwithå;
      DO BEGIN
        ignore:=dirGate.Open;
        exception(getException);
      END;
      check(dirGate.Open);
      IF ioRights<>NoRights THEN BEGIN
        æconfigurate deviceå
        WITH req.o, d=localdata^^ DO BEGIN
          kind:=configMess; æconfigureå
          h3.stx:=stx;
          h3.packetId:=2;
          h3.size:=configSize;
          h3.devno:=devno;
          h3.chanCom:=configCom;
          h3.devCom:=stdDevCom;
          hwConfig:=d.dirÆdevnoÅ.hwConfig;
          swConfig:=d.dirÆdevnoÅ.swConfig;
          etx3:=etx;
          check(ipcGate.Resident(tempEnv)); æmust be resident for i/oå
          check(ipcGate.Lock); æmust be locked to do i/oå
            sendReq(tempEnv^^.complete,req,devno,d);
          check(ipcGate.Open);
          req.i.kind:=mccmStAnsw; æconfig completed -- hopefullyå
          IF NOT ((req.i.h4.statusClass=solicited) AND
                  (req.i.h4.status=endConfig)) THEN
            exception(genRes(PhysIoError,IoFamily,0));
        END æwithå;
      END æifå;
      check(MakeReentrant(tempMan));
      check(MoveMan(tempMan,driversÆdevnoÅ));
    DO BEGIN
      ignore:=DelEnv(ownedFao,tempMan);
      IF res.main=ok THEN res:=getException;
      æ'ownedFao' is deleted automatically by kernel when result is rejectå
    END;
    ObjReturn(res);
END æ***ENTRY Assign***å;
æ$Eå
PRIVATE Close
  æIN driver,env: ref (kernel supplied)å
  WITH RECORD
    t: ^^;
  END;
  VAR devno: devnos;
BEGIN
  check(ipcGate.Lock);
  WITH e=env:drivLocRef, c=e^^.localdata^^, d=localdata^^ DO BEGIN
    devno:=c.devno;
    d.countÆdevnoÅ:=c.count;
  END;
  check(ipcGate.Open);
  check(DelEnv(driver,driversÆdevnoÅ));
  check(Dealloc(driver,driver));
END æ***ENTRY Close***å;
 
ENTRY ScanFiles
  WITH RECORD
    t: ^^;
  END;
BEGIN
  exception(genRes(-EntryIllegal,Universal,2));
END æ***ENTRY InitScan***å;
 
ENTRY CreateLink WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY DeleteLink WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY RenameFile WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY Exclude WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY Include WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
ENTRY InitFileSys WITH tempRefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
entry cloneFil with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
entry clonecon with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
entry waitsign with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
private closeclon with temprefs;
BEGIN exception(genRes(-EntryIllegal,Universal,2)); END;
 
OTHERWISE IpcOther
  WITH RECORD t: ^^; END;
BEGIN
  exception(genRes(-EntryIllegal,Universal,2));
ENDæ***OtherFunc***å;
 
END æ mccmImplement å;
æ$Eå
æ$L-å
(*////////////////////////////////////////////////////////////////////////
 
TYPE addrSpace=ARRAY Æaddrmin..16777200Å OF byte;
æ**************************************************************************å
æ****************************** T E S T S T U B ***************************å
æ**************************************************************************å
object Stub;
  entry BootInit;
  entry e2;
end;
program implTeststub object stub
  with record
    code: ^^;
    bootset: ownSet;
    alloc,
    sched,
    intsched: ^^;
    fullspace: ^^ ÆÅ addrSpace;
    defvirt,
    ego,
    egoenv,
    bootproc: ^^;
    mccmOwn:IoSysRefType; mccmMan:^^; mccmChannel:^^; tao0,tao1:^^FaoRefType;
    p2: ^^;
  end;
 
type textLine=array Æ1..90Å of byte;
 
procedure putline (UNIV s: blockPtr; t: blockPtr);
  var i,length: integer;
begin
  length:=elements(s);
  if length>80 then length:=80;
  putLength(t,length+2);
  for i:= 1 to length do tÆi+2Å:=sÆiÅ;
  with tt=tÆlength+3..length+5Å do putNL(tt);
end;
 
private termMccm with tempRefs;
begin printText('mccmobj terminated') end;
 
entry BootInit with record t:^^; tempEnv: ^^ipcLocals; stack:^^; end;
  const mccmfirst=16#ff1000; mccmvector=247; mccmlevel=4;
  var s: sizeType;
      count: integer;
      i: integer;
      devno: devnos;
      term0,term1: string8;
      buf: textLine;
      prompt, attPrompt: textLine;
      res: ResultType;
begin
  in
    check(alloc.NewObj(mccmOwn;makeSize(5000,2000),out count));
    check(DeclGen(mccmOwn,mccmMan,tempEnv,refs(ipcLocals),termMccm,
                  makeSize(0,0),makeSize(0,0),refs(mccmImplement),
                  bytes(mccmImplement),0,addr(mccmImplement),
                  makeSize(0,0),true));
    check(Copy(code,    tempEnv^^.code));
    check(Copy(ego,     tempEnv^^.stubRef));
    check(Copy(intsched,tempEnv^^.iSchedRef));
    check(Copy(sched,   tempEnv^^.schedRef));
    check(Copy(alloc,   tempEnv^^.allocRef));
    check(Copy(tempEnv, tempEnv^^.egoEnv));
    check(NewSeg(tempEnv^^.ownLocaldata,bytes(ipcData)));
    check(mccmOwn.InitIpcSys(;mccmvector,mccmlevel,mccmfirst));
 
    term0:=str8('term0         ');
    term1:=str8('term1         ');
    devno:=0;   check(mccmOwn.CreateFile(;term0,devno));
    devno:=1;   check(mccmOwn.CreateFile(;term1,devno));
 æ  check(alloc.NewObj(stack;makeSize(50000,10000),out count));
    check(CallExtend(stack,mccmOwn,Assign,out tao;ReadWriteRight,termName));
 å
    check(mccmOwn.Assign(out tao0; term0,ReadWriteRight));
    check(mccmOwn.Assign(out tao1; term1,ReadWriteRight));
 
    check(tao0.WaitBreak);
    check(tao0.WaitReady);
 
    putline('input:',prompt);
    putline('att0',attPrompt);
 
    check(sched.NewProc(out p2; makeSize(50000,10000)));
    check(DeclProc(p2,e2));
 
    printText('BEGIN copy-loop ');
    æcopy from term0 to term1å
    repeat
      IN
        repeat
          check(tao0.Writeseq(var in out prompt; out count));
          check(tao0.ReadSeq(var in out buf; out count));
          res:=tao1.WriteSeq(var in out buf; out count);
        until false;
      DO BEGIN
printText('**********attention on term0**********');
        check(tao0.WaitReady);
        check(tao0.WriteSeq(var in out attPrompt; out count));
      END;
    until false;
  do printText('teststub.Init exception');
end;
 
entry e2 with tempRefs;
  var s: sizeType;
      count: integer;
      i: integer;
      devno: devnos;
      term0,term1: string8;
      buf: textLine;
      prompt, attPrompt: textLine;
      res: ResultType;
begin
  in
    putline('input:',prompt);
    putline('att1',attPrompt);
 
    printText('BEGIN att-loop ');
    æcopy from term1 to term0, but only on attå
    repeat
      IN
        repeat
          check(tao1.WaitBreak);  check(tao1.WaitReady);
          check(tao1.Writeseq(var in out prompt; out count));
          check(tao1.ReadSeq(var in out buf; out count));
          res:=tao0.WriteSeq(var in out buf; out count);
        until false;
      DO BEGIN
printText('**********error on term1**********');
      END;
    until false;
  do printText('teststub.e2 exception');
end; æe2å
 
 
 
otherwise o with tempRefs;
begin printText('teststub.otherwise') end;
 
end æteststubå;
////////////////////////////////////////////////////////////////////*)
æ$L+å
æ$Eå
INITIALIZE
  mccmImplement 'mccm':
    allocRef 'allocate',
    schedRef 'scheduler',
    iSchedRef 'intscheduler',
    stubRef 'objdir',
    egoEnv '**',
    egoObj '*',
    ownLocaldata
æ implTeststub 'teststub':å
END.
 
«eof»