þ a‹R þ w Qþ mP9     þ hý	 oP      þ nSystem-wide$NOLIST
$OPTIMIZE (3)
$INCLUDE (``OsIncs`Os.Model.Inc~Text~)

OsADQMain: DO;

/* This is Os.ADQMain.PLM.  It contains the    */
/* main entry point to the ADQ device driver.  */

/* Author: Phil Ydens                          */
/* Date:   1/15/83                             */

$INCLUDE (``Incs`PlmLits.Inc~Text~)
$INCLUDE (``OsIncs`Os.Error.Inc~Text~)
$INCLUDE (``OsIncs`Os.Constant.Inc~Text~)
$INCLUDE (``OsIncs`Os.Device.Inc~Text~)
$INCLUDE (``OsIncs`Os.Type.Inc~Text~)

$INCLUDE (``OsIncs`Os.OsSubs.Ext.Inc~Text~)
$INCLUDE (``OsIncs`Os.Tasks.Ext.Inc~Text~)


/*              Static Variables          */

DCL dummy             WORD;


/*              Public Variables          */

DCL ADQDeviceCB    ActiveDeviceCBType PUBLIC DATA
  (NULLWORD,           /* checksum */
   NULLWORD,           /* next */
   NULLWORD,           /* prev */
   0,                  /* length */
   'ADQ                                     ', /* chars (40 for PHIL) */
   @OsADQDriver,       /* entrypoint */
   NULLBYTE,           /* intAddr */
   NULLWORD,           /* PID */
   NULLWORD,           /* mode */
   0,                  /* remote */
   0,0,0);             /* unused */

/*              Externals             */

DCL osADQ     QCBType EXTERNAL;
DCL ADQSema   SidType EXTERNAL;
$EJECT

/*                   ADQAttach                 */

/* This will do an attach to the ADQ.  It will */
/* keep track of the access to ensure only read*/
/* access is allowed.                          */

ADQAttach: PROCEDURE (conn, mode, access) WORD CLEAN;
  DCL mode        BYTE;
  DCL access      BYTE;
  DCL conn        ConnectionType;

  DCL connCB      BASED conn        ADQConnCBType;

  connCB.open = FALSE;
  IF (access = shortDirAccess) OR (access = longDirAccess) THEN 
    CALL ADQOpen (conn);
  ELSE IF access <> readAccess THEN 
    RETURN (eAccess);
  connCB.mask = visibleBit;
  connCB.value = visible;
  RETURN (eOK);
  END; /* ADQAttach */


/*                   ADQOpen                     */

/* This will do an open to the ADQ.              */

ADQOpen: PROCEDURE (conn) CLEAN;
  DCL conn        ConnectionType;

  DCL connCB      BASED conn        ADQConnCBType;

  connCB.open = TRUE;
  connCB.direction = readForward;
  connCB.devEntry = osADQ.headOfQ;
  END; /* ADQOpen */
$EJECT

/*                    GetEntry                   */

/* This routine will return the next or previous */
/* entry depending on the variable direction.    */

GetEntry: PROCEDURE (conn, direction, pCurEntry) BOOLEAN CLEAN;
  DCL direction   BYTE;
  DCL conn        ConnectionType;
  DCL pCurEntry   PTR;

  DCL pDevEntry   SELECTOR;
  DCL curEntry    BASED pCurEntry   SELECTOR;
  DCL connCB      BASED conn        ADQConnCBType;
  DCL devEntry    BASED pDevEntry   ActiveDeviceCBType;

  DO WHILE TRUE;
    BEGIN
    IF direction = readForward THEN
      DO;
      IF connCB.devEntry = NULLWORD THEN
        RETURN (FALSE);
      pDevEntry, curEntry = connCB.devEntry;
      connCB.devEntry = devEntry.next;
      END;
    ELSE /* direction = readBackward */
      DO;
      IF connCB.devEntry = osADQ.headOfQ THEN
        RETURN (FALSE);
      IF connCB.devEntry = NULLWORD THEN
        connCB.devEntry = osADQ.tailOfQ;
      ELSE
        DO;
        pDevEntry = connCB.devEntry;
        connCB.devEntry = devEntry.prev;
        END;
      pDevEntry, curEntry = connCB.devEntry;
      END;
    IF (devEntry.mode AND connCB.mask) = connCB.value THEN
      RETURN (TRUE);
    END;
  END; /* GetEntry */
$EJECT

/*                    ADQSeek                    */

/* This routine will change the current device   */
/* pointer forward/backward the amount specified */
/* by pl.position.                               */

ADQSeek: PROCEDURE (conn, mode, newPosition) WORD CLEAN;
  DCL mode          BYTE;
  DCL newPosition   WORD;
  DCL conn          ConnectionType;

  DCL direction     BYTE;
  DCL done          WORD;
  DCL connCB        BASED conn         ADQConnCBType;
  
  IF NOT ((mode >= seekRelBackwards) AND (mode <= seekFromEnd)) THEN
    RETURN (eParam);
  IF (connCB.objectMode <> directoryMode) THEN
    RETURN (eAccess);

  direction = readForward;
  DO CASE (mode - seekRelBackwards);
    BEGIN

      /* 1 - seek backwards from current position */
      direction = readBackward;

      /* 2 - seek to this position */
      connCB.devEntry = osADQ.headOfQ;

      /* 3 - seek forwards from current position */
      ;

      /* 4 - seek backwards from end of file */
      DO;
      connCB.devEntry = NULLWORD;
      direction = readBackward;
      END;

    END;
  done = 0;
  DO WHILE (done < newPosition);
    BEGIN
    IF NOT (GetEntry (conn, direction, @dummy)) THEN
      RETURN (eOK);
    done = done + 1;
    END;
  RETURN (eOK);
  END; /* ADQSeek */
$EJECT

/*                ADQRead                        */

/* This routine will read a device in directory  */
/* mode.                                         */

ADQRead: PROCEDURE (conn, pBuffer, pLength) WORD CLEAN;
  DCL conn            ConnectionType;
  DCL pBuffer         PTR;
  DCL pLength         PTR;

  DCL curLoc          WORD;
  DCL done            WORD;
  DCL sizeDirEntry    WORD;
  DCL pDevEntry       SELECTOR;
  DCL pDirEntry       PTR;
  DCL pUserBuf        PTR;
  DCL userBuf         BASED pBuffer (1)     BYTE;
  DCL length          BASED pLength         WORD;
  DCL connCB          BASED conn            ADQConnCBType;
  DCL devEntry        BASED pDevEntry       ActiveDeviceCBType;
  DCL dirEntry        BASED pDirEntry       DirectoryEntryType;

  IF (connCB.objectMode <> directoryMode) THEN
    RETURN (eAccess);
  curLoc, done = 0;
  DO WHILE TRUE;
    BEGIN
    IF (done >= length) THEN
      GOTO ADQReadExit;
    IF NOT (GetEntry (conn, connCB.direction, @pDevEntry)) THEN
      GOTO ADQReadExit;

    done = done + 1;
    pDirEntry = @userBuf (curLoc);
    CALL SETB (0, @dirEntry.spare, SIZE (dirEntry.spare));
    CALL MOVB (@devEntry.length, @dirEntry.length, devEntry.length + 1);
    curLoc = curLoc + sizeOfDirectoryEntryPreamble + dirEntry.length;
    END;

ADQReadExit:
  length = done;
  RETURN (eOK);
  END; /* ADQRead */
$EJECT

/*                   ADQGetStatus                */

/* This will return status about an active conn. */

ADQGetStatus: PROCEDURE (conn, pStatus, length) CLEAN;
  DCL length       WORD;
  DCL conn         ConnectionType;
  DCL pStatus      PTR;

  DCL numEntries   WORD;
  DCL testEntry    SELECTOR;
  DCL info         StatusType;
  DCL connCB       BASED conn            ADQConnCBType;
  DCL adqCB        BASED testEntry       ActiveDeviceCBType;


  CALL SETB (0, @info, SIZE (info));
  info.open = connCB.open;
/*
  info.access = 0;
*/
  info.seek = 11b;
  info.objectMode = connCB.objectMode;
  info.pWildcardName = connCB.pWildcardName;
  IF (connCB.objectMode = directoryMode) THEN
    DO;
    numEntries = 0;
    testEntry = connCB.devEntry;
    info.direction = connCB.direction;
    CALL ADQOpen (conn);
    DO WHILE GetEntry (conn, readForward, @dummy);
      BEGIN
      numEntries = numEntries + 1;
      IF testEntry = connCB.devEntry THEN
        info.curEntry, info.filePosition = numEntries;
      END;
    connCB.devEntry = testEntry;
    connCB.direction = info.direction;
    connCB.open = info.open;
    info.fileLength, info.numEntries = numEntries;
    info.mode = adqCB.mode;
    END;
  CALL MOVB (@info, pStatus, Min (length, SIZE (info)));
  END; /* ADQGetStatus */
$EJECT

/*                  ADQSetStatus                 */

/* This will set status about an active conn.    */

ADQSetStatus: PROCEDURE (conn, pInfo, length) CLEAN;
  DCL length       WORD;
  DCL conn         ConnectionType;
  DCL pInfo        PTR;

  DCL i            WORD;
  DCL pADQEntry    SELECTOR;
  DCL pEntry       PTR;
  DCL pDataAlias   PTR;
  DCL connCB       BASED conn            ADQConnCBType;
  DCL ADQEntry     BASED pADQEntry       ActiveDeviceCBType;
  DCL statusEntry  BASED pEntry          SetStatusEntryType;
  DCL info         BASED pInfo      (1)  BYTE;
  DCL dataWords    BASED pDataAlias (1)  WORD;

  i = 0;
  DO WHILE (i < length);
    BEGIN
    pEntry = @info (i);
    pDataAlias = @statusEntry.statusData;
    IF statusEntry.entryID = setDirection THEN
      connCB.direction = statusEntry.statusData (0);
/*
    ELSE IF statusEntry.entryID = setGPIBAddress THEN
      DO;
      pADQEntry = connCB.devEntry;
      ADQEntry.intAddr = statusEntry.statusData (0);
      END;
*/
    ELSE IF statusEntry.entryID = setDeviceMask THEN
      DO;
      connCB.mask  = dataWords (0);
      connCB.value = dataWords (1);
      END;
    i = i + statusEntry.length + 3;
    END;
  END; /* ADQSetStatus */
$EJECT

/*                 Os ADQ Driver                 */

OsADQDriver: PROCEDURE (request, pPl, pError) CLEAN;
  DCL request      WORD;
  DCL pPl          PTR;
  DCL pError       PTR;

  DCL length       WORD;
  DCL conn         ConnectionType;
  DCL pBuffer      PTR;
  DCL error        BASED pError    WORD;
  DCL connCB       BASED conn      ADQConnCBType;
  DCL pl           BASED pPl       ParamListType;

  conn = pl.connection;
  length = pl.length;
  pBuffer = pl.pBuffer;
  error = eOK;
  CALL IntWait (ADQSema);
  IF request = ddInitialize THEN
    ;
  ELSE IF request = ddAttach THEN
    error = ADQAttach (conn, pl.mode, pl.numBuf);
  ELSE IF request = ddDetach THEN
    ;
  ELSE IF request = ddOpen THEN
    DO;
    IF connCB.open THEN
      error = eOpen;
    ELSE
      CALL ADQOpen (conn);
    END;
  ELSE IF request = ddGetStatus THEN
    CALL ADQGetStatus (conn, pBuffer, length);
  ELSE IF (request >= ddClose) AND (request <= ddSetStatus) THEN
    DO;
    IF NOT (connCB.open) THEN
      error = eFileNotOpen;
    ELSE IF request = ddRead THEN
      error = ADQRead (conn, pBuffer, @pl.length);
    ELSE IF request = ddSeek THEN
      error = ADQSeek (conn, pl.mode, LOW (pl.position));
    ELSE IF request = ddSetStatus THEN
      CALL ADQSetStatus (conn, pBuffer, length);
    ELSE IF request = ddClose THEN
      connCB.open = FALSE;
    ELSE
      error = eNotSupport;
    END;
  ELSE
    error = eNotSupport;
  CALL IntSignal (ADQSema);
  END; /* OsADQDriver */

END; /* ADQMain */
