-- File: PhoneHeadDicentra.mesa - last edit: -- AOF 15-Feb-88 9:12:42 -- HGM 29-Nov-84 18:06:13 -- Copyright (C) 1983, 1984, 1988 by Xerox Corporation. All rights reserved. DIRECTORY DicentraInputOutput USING [ InterruptLevel, IOAddress, Output, SetPhonelineCSB, SetWakeupMask], Environment USING [Byte], Inline USING [BITAND, BITOR, LowHalf], MultibusAddresses USING [ dialer0, dialer1, dialer2, IOAddress, modem0, scc0, scc1, scc2, scc3], NewRS232CFace USING [ Command, CommandStatus, ControlRecord, DeviceStatus, LineNumber, Operation, OperationPtr, ParameterHandle, ParameterStatus, ResetRecord, RS232CClientType, TransferStatus], PhoneFace USING [Line, Status], ResidentHeap USING [Alignment, HeapLocation], ResidentMemory USING [Allocate]; PhoneHeadDicentra: PROGRAM IMPORTS Inline, DicentraInputOutput, ResidentMemory EXPORTS NewRS232CFace, PhoneFace = BEGIN Line: TYPE = PhoneFace.Line; Status: TYPE = PhoneFace.Status; sendTail, recvTail: ARRAY Line OF IOCB; csb: LONG POINTER TO CSB = AllocateCSB[]; CSB: TYPE = ARRAY Line OF ControlBlock; ControlBlock: TYPE = RECORD [ tranState: WORD, tranIOCB: ShortIOCB, tranIOCBMapped: LONG POINTER, recvState: WORD, recvIOCB: ShortIOCB, recvIOCBMapped: LONG POINTER, tranUnderruns: CARDINAL, tranUnused: ARRAY [9..12) OF WORD, recvMissed: CARDINAL, recvAborted: CARDINAL, recvAbortIdle: CARDINAL, recvAbortEx: CARDINAL]; IOCB: TYPE = LONG POINTER TO ControlBlockRecord; ShortIOCB: TYPE = POINTER TO ControlBlockRecord; offset: CARDINAL = SIZE[NewRS232CFace.Operation]; controlBlockSize: PUBLIC <<PhoneFace>> CARDINAL ← SIZE[ControlBlockRecord]; operationSize: PUBLIC <<NewRS232CFace>> CARDINAL ← SIZE[NewRS232CFace.Operation] + controlBlockSize; operationAlignment: PUBLIC <<NewRS232CFace>> ResidentHeap.Alignment ← a1; operationLocation: PUBLIC <<NewRS232CFace>> ResidentHeap.HeapLocation ← first64K; ControlBlockRecord: PUBLIC TYPE = RECORD [ next: ShortIOCB, status: WORD, buffer: LONG POINTER, bytes: CARDINAL, bytesLeft: CARDINAL, unused: ARRAY [6..8) OF WORD, finger: LONG POINTER, mapped: LONG POINTER, spare: ARRAY [12..16) OF WORD ]; lines: CARDINAL = 8; numberOfLines: PUBLIC NewRS232CFace.LineNumber ← lines; NoSuchLine: ERROR = CODE; Handle: PUBLIC <<NewRS232CFace>> TYPE = RECORD[line: Line, flag: CARDINAL]; nilHandle: PUBLIC <<NewRS232CFace>> Handle ← [lines, LAST[CARDINAL]]; channels: ARRAY [0..lines) OF LONG POINTER TO Words = [ LOOPHOLE[MultibusAddresses.scc0 + 10H], -- Chan A LOOPHOLE[MultibusAddresses.scc0 + 00H], -- Chan B LOOPHOLE[MultibusAddresses.scc1 + 10H], LOOPHOLE[MultibusAddresses.scc1 + 00H], LOOPHOLE[MultibusAddresses.scc2 + 10H], -- Chan A LOOPHOLE[MultibusAddresses.scc2 + 00H], -- Chan B LOOPHOLE[MultibusAddresses.scc3 + 10H], LOOPHOLE[MultibusAddresses.scc3 + 00H]]; interruptVect: ARRAY [0..lines) OF WORD = [0, 0, 10H, 10H, 20H, 20H, 30H, 30H]; baudRateNumber: ARRAY [0..lines) OF WORD = [014H, 014H, 077H, 077H, 077H, 077H, 077H, 077H]; Words: TYPE = RECORD [ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15: WORD]; TurnOn, Initialize: PUBLIC <<PhoneFace, NewRS232CFace>> PROC[ interruptBits: WORD] = BEGIN SetupTestClocks[]; csb↑ ← ALL[ [ tranState: 0, tranIOCB: NIL, tranIOCBMapped: NIL, recvState: 0, recvIOCB: NIL, recvIOCBMapped: NIL, tranUnderruns: 0, tranUnused: ALL[0], recvMissed: 0, recvAborted: 0, recvAbortIdle: 0, recvAbortEx: 0 ] ]; FOR line: Line IN [0..lines) DO InitChip[line]; ENDLOOP; FOR line: Line IN [0..lines) DO ResetLine[line]; ENDLOOP; DicentraInputOutput.SetWakeupMask[interruptBits, phoneLine]; DicentraInputOutput.SetPhonelineCSB[csb]; END; InitializeCleanup: PUBLIC <<NewRS232CFace>> PROC[] = {}; --InitializeCleanup SetupTestClocks: PROCEDURE = BEGIN SetupTestClock[MultibusAddresses.modem0, 00BH]; -- LCa for first 2 lines at 56KB SetupTestClock[MultibusAddresses.dialer0, 041H]; -- LCb for next 2 lines at 9600 SetupTestClock[MultibusAddresses.dialer1, 041H]; -- LCc for next 2 lines at 9600 SetupTestClock[MultibusAddresses.dialer2, 041H]; -- LCd for next 2 lines at 9600 END; SetupTestClock: PROC[chip: DicentraInputOutput.IOAddress, ticks: CARDINAL] = BEGIN DicentraInputOutput.Output[001H, chip + 000H]; -- Master Interrupt Control ← Reset DicentraInputOutput.Output[000H, chip + 000H]; -- Master Interrupt Control ← No Reset DicentraInputOutput.Output[010H, chip + 001H]; -- Master Config Control ← Enable Port C and Cnt3 DicentraInputOutput.Output[000H, chip + 01AH]; -- Cnt3 MSB DicentraInputOutput.Output[ticks, chip + 01BH]; -- Cnt3 LSB DicentraInputOutput.Output[0C2H, chip + 01EH]; -- Cnt3 Mode ← Sq Out DicentraInputOutput.Output[006H, chip + 00CH]; -- Cnt3 Command ← Go END; InitChip: PROC[line: Line] = BEGIN chan: LONG POINTER TO Words = channels[line]; chanB: LONG POINTER TO Words = channels[Inline.BITOR[line, 1]]; IF line > lines THEN ERROR NoSuchLine; DicentraInputOutput.Output[002H, @chanB.r0]; -- Shift Left (ADR0 is ignored) DicentraInputOutput.Output[0C9H, @chan.r9]; -- Hardware Reset, MIE, V, VIS DicentraInputOutput.Output[interruptVect[line], @chan.r2]; -- Int Vector Base END; InitiateCommand: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, command: NewRS232CFace.Command] RETURNS[commandStatus: NewRS232CFace.CommandStatus] = {RETURN[inProgress]}; --InitiateCommand InitiateReceive: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, operation: NewRS232CFace.OperationPtr] RETURNS [transferStatus: NewRS232CFace.TransferStatus] = BEGIN QueueInput[ handle.line, LOOPHOLE[operation + offset], operation.dataBuffer, operation.bufferByteLength]; RETURN[inProgress]; END; --InitiateReceive InitiateResetStatusBits: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, resetRecord: NewRS232CFace.ResetRecord] RETURNS [commandStatus: NewRS232CFace.CommandStatus] = {RETURN[inProgress]}; --InitiateResetStatusBits InitiateSetControlBits: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, controlRecord: NewRS232CFace.ControlRecord] RETURNS [commandStatus: NewRS232CFace.CommandStatus] = {RETURN[inProgress]}; --InitiateSetControlBits InitiateSetParameters: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, parameters: NewRS232CFace.ParameterHandle] RETURNS[parameterStatus: NewRS232CFace.ParameterStatus] = {RETURN[inProgress]}; --InitiateSetParameters InitiateTransmit: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, operation: NewRS232CFace.OperationPtr] RETURNS [transferStatus: NewRS232CFace.TransferStatus] = BEGIN QueueOutput[ handle.line, LOOPHOLE[operation + offset], operation.dataBuffer, operation.bufferByteLength]; RETURN[inProgress]; END; --InitiateTransmit PollCommand: PUBLIC <<NewRS232CFace>> PROC[handle: Handle] RETURNS [commandStatus: NewRS232CFace.CommandStatus] = {RETURN[completed]}; --PollCommand PollReceiveOrTransmit: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, operation: NewRS232CFace.OperationPtr] RETURNS[ bytesTransferred: CARDINAL, transferStatus: NewRS232CFace.TransferStatus] = BEGIN OPEN iocb: LOOPHOLE[operation + offset, IOCB]; SELECT TRUE FROM (iocb.status = 00000H) => RETURN[0, inProgress]; --either send or receive (iocb.status = 0FFFFH) => RETURN[iocb.bytes - iocb.bytesLeft - 1, success]; --send success (Inline.BITAND[iocb.status, 0FFH] = 087H) => RETURN[iocb.bytes - iocb.bytesLeft - 1, success]; --receive okay (iocb.status = 00001H) => RETURN[0, invalidFrame]; --receive packetToLong (Inline.BITAND[iocb.status, 020H] # 0) => RETURN[0, dataLost]; --receive overrun (Inline.BITAND[iocb.status, 040H] # 0) => RETURN[0, checksumError]; --crc ENDCASE => RETURN[0, deviceError]; --receive or transmit otherError END; --PollReceiveOrTransmit PollSetControlBits: PUBLIC <<NewRS232CFace>> PROC[handle: Handle] RETURNS [commandStatus: NewRS232CFace.CommandStatus] = {RETURN[completed]}; --PollSetControlBits PollSetParameters: PUBLIC <<NewRS232CFace>> PROC[handle: Handle] RETURNS[parameterStatus: NewRS232CFace.ParameterStatus] = {RETURN[completed]}; --PollSetParameters ReleaseHandle: PUBLIC <<NewRS232CFace>> PROC[handle: Handle] RETURNS [nilHandle: Handle] = {RETURN[nilHandle]}; --ReleaseHandle ResetStatusBits: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, resetRecord: NewRS232CFace.ResetRecord] = {}; SetControlBits: PUBLIC <<NewRS232CFace>> PROC[ handle: Handle, controlRecord: NewRS232CFace.ControlRecord] = {}; TurnOff: PUBLIC <<PhoneFace>> PROC = BEGIN DicentraInputOutput.SetPhonelineCSB[NIL]; END; ResetLine: PUBLIC <<PhoneFace>> PROC[line: Line] = BEGIN chan: LONG POINTER TO Words = channels[line]; IF line > lines THEN ERROR NoSuchLine; DicentraInputOutput.Output[000H, @chan.r1]; -- Disable all ints DicentraInputOutput.SetPhonelineCSB[csb]; -- Just in case csb[line].tranIOCB ← NIL; csb[line].tranState ← 0; csb[line].recvIOCB ← NIL; csb[line].recvState ← 0; DicentraInputOutput.Output[interruptVect[line], @chan.r2]; -- Int Vector Base DicentraInputOutput.Output[020H, @chan.r4]; -- SDLC DicentraInputOutput.Output[013H, @chan.r1]; -- Rx All Int, Tx Int En, Ext Int En DicentraInputOutput.Output[0D9H, @chan.r3]; -- 8bits/char, Hunt, CRC, RxE DicentraInputOutput.Output[0EBH, @chan.r5]; -- DTR, 8bits/char, TxE, RTS, CRC DicentraInputOutput.Output[07EH, @chan.r7]; -- Flag Char DicentraInputOutput.Output[084H, @chan.r10]; -- CRC←1, Abort on Underrun DicentraInputOutput.Output[080H, @chan.r15]; -- Enable Ext Int on Abort DicentraInputOutput.Output[070H, @chan.r0]; -- Reset Rx CRC, Error Reset DicentraInputOutput.Output[090H, @chan.r0]; -- Reset Tx CRC, Reset Ext/Sts Int DicentraInputOutput.Output[008H, @chan.r11]; -- External Clocks IF FALSE THEN BEGIN DicentraInputOutput.Output[baudRateNumber[line], @chan.r12]; -- Low byte of time constant DicentraInputOutput.Output[000H, @chan.r13]; -- High byte of time constant DicentraInputOutput.Output[003H, @chan.r14]; -- Baud Rate Gen from PClk DicentraInputOutput.Output[050H, @chan.r11]; -- Clocks from BR Gen END; END; GetPacketsMissed: PUBLIC <<PhoneFace>> PROC[line: Line] RETURNS [CARDINAL] = BEGIN IF line > lines THEN ERROR NoSuchLine; RETURN[csb[line].recvMissed] END; QueueOutput: PUBLIC <<PhoneFace>> PROC[ line: Line, iocb: IOCB, buffer: LONG POINTER, bytes: CARDINAL] = BEGIN chan: LONG POINTER TO Words = channels[line]; firstByte: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte = buffer; IF line > lines THEN ERROR NoSuchLine; iocb.status ← 0; iocb.next ← NIL; iocb.buffer ← buffer; iocb.bytes ← bytes; IF csb[line].tranIOCB = NIL THEN BEGIN csb[line].tranIOCB ← Inline.LowHalf[iocb]; DicentraInputOutput.Output[080H, @chan.r0]; -- Reset Tx CRC DicentraInputOutput.Output[firstByte[0], @chan.r8]; -- Send first data byte END ELSE BEGIN sendTail[line].next ← Inline.LowHalf[iocb]; IF csb[line].tranIOCB = NIL AND iocb.status = 0 THEN -- Rats, lost race BEGIN csb[line].tranIOCB ← Inline.LowHalf[iocb]; DicentraInputOutput.Output[080H, @chan.r0]; -- Reset Tx CRC DicentraInputOutput.Output[firstByte[0], @chan.r8]; -- Send first data byte END; END; sendTail[line] ← iocb; END; GetDeviceStatus: PUBLIC <<NewRS232CFace>> PROC[handle: Handle] RETURNS[deviceStatus: NewRS232CFace.DeviceStatus] = BEGIN END; --GetDeviceStatus GetHandle: PUBLIC <<NewRS232CFace>> PROC[ lineNumber: NewRS232CFace.LineNumber, rs232cClient: NewRS232CFace.RS232CClientType ← normalClient] RETURNS [handle: Handle] = {RETURN[[lineNumber, LAST[CARDINAL]]]}; GetNextLine: PUBLIC <<NewRS232CFace>> PROC[ lineNumber: NewRS232CFace.LineNumber] RETURNS [nextLineNumber: NewRS232CFace.LineNumber] = {RETURN[IF (lineNumber ← lineNumber.SUCC) < lines THEN lineNumber ELSE NewRS232CFace.LineNumber.FIRST]}; --GetNextLine GetSendStatus: PUBLIC <<PhoneFace>> PROC[iocb: IOCB] RETURNS [status: Status] = BEGIN IF iocb.status = 0 THEN RETURN[pending]; SELECT iocb.status FROM 0FFFFH => RETURN[ok]; ENDCASE => RETURN[underrun]; END; QueueInput: PUBLIC <<PhoneFace>> PROC[ line: Line, iocb: IOCB, buffer: LONG POINTER, bytes: CARDINAL] = BEGIN iocb.status ← 0; iocb.next ← NIL; iocb.buffer ← buffer; iocb.bytes ← bytes; IF line > lines THEN ERROR NoSuchLine; IF csb[line].recvIOCB = NIL THEN BEGIN csb[line].recvIOCB ← Inline.LowHalf[iocb] END ELSE BEGIN recvTail[line].next ← Inline.LowHalf[iocb]; IF csb[line].recvIOCB = NIL AND iocb.status = 0 THEN -- lost race csb[line].recvIOCB ← Inline.LowHalf[iocb]; END; recvTail[line] ← iocb; END; GetRecvStatus: PUBLIC <<PhoneFace>> PROC[iocb: IOCB] RETURNS [status: Status] = BEGIN IF iocb.status = 0 THEN RETURN[pending]; IF iocb.status = 1 THEN RETURN[packetTooLong]; IF Inline.BITAND[iocb.status, 020H] # 0 THEN RETURN[overrun]; IF Inline.BITAND[iocb.status, 040H] # 0 THEN RETURN[crc]; SELECT Inline.BITAND[iocb.status, 0FFH] FROM 087H => RETURN[ok]; ENDCASE => RETURN[otherError]; END; GetPacketLength: PUBLIC <<PhoneFace>> PROC[iocb: IOCB] RETURNS [bytes: CARDINAL] = BEGIN RETURN[iocb.bytes - iocb.bytesLeft - 1]; END; AllocateCSB: PROCEDURE RETURNS [base: LONG POINTER] = BEGIN pages: CARDINAL = 1; base ← ResidentMemory.Allocate[hyperspace, pages]; END; SetupTestClocks[]; END.