Google
 

Trailing-Edge - PDP-10 Archives - BB-P363B-SM_1985 - mcb/drivers/kdp.b16
There are no other files named kdp.b16 in the archive.
module KDP (	! DDM driver for KMC11/DUP11
		ident = 'X04230',
		language (bliss16)
		) =
begin

!
!                    COPYRIGHT (c) 1980, 1981, 1982
!                    DIGITAL EQUIPMENT CORPORATION
!                        Maynard, Massachusetts
!
!     This software is furnished under a license and may  be  used
!     and copied only in accordance with the terms of such license
!     and with the inclusion of the above copyright notice.   This
!     software  or any other copies thereof may not be provided or
!     otherwise made available to any other person.  No  title  to
!     and ownership of the software is hereby transferred.
!
!     The information  in  this  software  is  subject  to  change
!     without  notice  and should not be construed as a commitment
!     by DIGITAL EQUIPMENT CORPORATION.
!
!     DIGITAL assumes no responsibility for the use or reliability
!     of  its  software  on  equipment  which  is  not supplied by
!     DIGITAL.
!

!++
!
! FACILITY: MCB KDP Driver
!
! ABSTRACT:
!
!	This is the DDM process which services the KMC11 microprocessor
!	which controls DUP11 synchronous line devices.
!
! ENVIRONMENT: MCB V3.0
!
! AUTHOR: Alan D. Peckham	CREATION DATE: 10-Jan-81
!
! MODIFIED BY:
!
!	S. I. GOLDFARB, 25-MAR-1977
!	R. H. ROSENBAUM, 30-AUG-1977
!	L. J. TWAITS, 10-SEP-1977
!	D. B. TUTTLE, 10-OCT-1977
!
!	Alan D. Peckham, 16-APR-80: Version 4
! 01	- Update to operate under MCB V3.0
! 02	- Update for MCB V3.1
! 03	- Rewrite in BLISS
! 04	- Only initialize KMC once during process initialization calls.
! 05	- Add Network Management event logging.
! 06	- Correct DDCMP data message bug in CITBA.
! 07	- Mark transmit buffer chain on transmitter underrun
!	  and return if finished.
! 08	- Optimize BDADR routine in MACRO-11.
!	  Fix buffer descriptor mapping bug.
! 09	- Split off Network Management code.
! 10	- Change SET_DESCRIPTOR to BDADR in transmit underrun error in COCTL.
! 11	- Change abort-DLXCP to DDXCP in KDPXME.
! 12	- Add control of DUPLEX, CLOCK, and LOOPBACK.
! 13	- Adapt to using new UNIBUS address converion routines.
! 14	- Fix signal bug in KDPNMX.
! 15	- Correct DSR event logging.
! 16	- Keep count of transmit/receive buffers to the KMC
!	  so that kills are done properly.
! 17	- Fix CTLGET to pass NM parameters to higher layer.
! 18	- Eliminate SIGNAL_STOP conditions and maintain error counters.
! 19	- Stop assign loop on RDB-get failure in GET_RECEIVE_BUFFERS.
! 20	- Use new microcode (X1.4) to set maintenance mode
!	  during control-in and eliminate SET_DUP_MODE.
! 21	- Optimize code in TIMPIN.
!	  If killing receives or transmits,
!	  do not increment DF_ASSIGNABLE_*_COUNT.
!	  Added RETURNED_RECEIVE_BUFFER routine to centralize accounting.
!	  Handle stack overflow problem of CALL$P overruns:
!	   Change COMPLETE to continue control processing indirectly
!	   by scheduling the CTL CCB to ourselves.
! 22	- Still haven't found our receive_BA bug.
!	  Centralize receive BA checking into RECEIVE_CCB.
!	  Remove RETURNED_RECEIVE_BUFFER.
! 23	- Found bug!  It is interaction between unfinished KILCRA
!	  and CTLSTP.  Solution:
!	    If D_PENDING_CONTROL_CCBS is non-empty (kill in progress),
!	    then queue CTLSTP CCB on it and go away.
!	    When kill completes, COMPLETE all CCBs on this queue.
!	    This continues the CTLSTP.   Yay!!!!!
!--
!
! INCLUDE FILES:
!

library 'MCBLIB';

library 'XPORT';

library 'NMXLIB';

library 'KDPDAT';

!
! TABLE OF CONTENTS:
!

linkage
    LINKAGE_CCB_DESC = jsr (register = 4, register = 1),
    LINKAGE_CSR = jsr (register = 1),
    LINKAGE_CSR_MC_LNG = jsr (register = 1, register = 2, register = 3),
    LINKAGE_DESC_STS = jsr (register = 1, register = 3),
    LINKAGE_PORT = jsr (register = 1),
    LINKAGE_RING_POOL_COUNT = jsr (register = 2, register = 3,register = 4),
    LINKAGE_STS = jsr (register = 3),
    KDP_CCB = jsr (register = 4) : preserve (0) nopreserve (1, 3),
    KDP_EDB = jsr (; register = 3),
    KDP_LKG_DB_DESC_CCB = jsr (register = 5, register = 1; register = 4);

forward routine
    ASSIGN_RECEIVE_BUFFER : LINKAGE_CCB novalue,
    ASSIGN_TRANSMIT_BUFFER : novalue,
    CIBAS : CALL$,
    CICTL : CALL$,
    CIRBA : CALL$,
    CIRBK : CALL$,
    CITBA : CALL$,
    CITBK : CALL$,
    COBAD : CALL$ novalue,
    COCTL : CALL$ novalue,
    COMPLETE : LINKAGE_DB_CCB novalue,
    CORBA : CALL$ novalue,
    COTBA : CALL$ novalue,
    CTLGET : MCB_DB_CCB novalue,
    CTLSET : MCB_DB_CCB novalue,
    CTLSTP : MCB_DB_CCB novalue,
    CTLSTR : MCB_DB_CCB novalue,
    DEVICE_BROKEN : LINKAGE_DB novalue,
    GET_RECEIVE_BUFFERS : novalue,
    GIVE_TO_KMC : KDP_CCB novalue,
    INITIALIZE_CHARACTERISTICS : novalue,
    INITIALIZE_DESCRIPTOR_LIST : LINKAGE_RING_POOL_COUNT novalue,
    KDPCTL : MCB_DB_CCB_MOD novalue,
    KDPKIL : MCB_DB_CCB_MOD novalue,
    KDPTIM : MCB_DB_MOD novalue,
    KDPXME : MCB_DB_CCB_MOD novalue,
    KILCRA : MCB_DB_CCB novalue,
    KILKIL : MCB_DB_CCB novalue,
    KILXKL : MCB_DB_CCB novalue,
    PARAMETER_DEVICE_REGISTERS : KDP_REG novalue,
    POLLING_FAILURE : novalue,
    RECEIVE_CCB : KDP_LKG_DB_DESC_CCB,
    RECEIVE_DONE : LINKAGE_DESC_STS novalue,
    RECEIVE_KILLED : novalue,
    SET_DESCRIPTOR : LINKAGE_CCB_DESC,
    TIMLTM : MCB_DB novalue,
    TIMPIN : MCB_DB novalue,
    TIMPWF : MCB_DB novalue,
    TIMRDB : MCB_DB_CCB novalue,
    TRANSMIT_DONE : LINKAGE_DESC_STS novalue,
    TRANSMIT_KILLED : novalue;

!
! MACROS:
!

macro
    BDADR (LOW, HIGH) =
	begin

	local
	    ADDR;

	$MCB_CONVERT_FROM_UBA_ADDRESS (LOW, HIGH, ADDR);
	.ADDR
	end %;

!
! EQUATED SYMBOLS:
!

literal
    FALSE = 1 EQL 0,
    NO_OPERATION = 0,
    POLLING_THRESHOLD = 4,
    TRUE = 1 EQL 1;

global literal
    %name ('D.LEN') = D_LEN*%upval,
    %name ('E.LEN') = E_LEN*%upval;

!+
! POLLING CLASS TABLE FOR DETERMINING LIMITS FOR GIVEN SPEED
!
! ENTRIES ARE SET FOR THE STANDARD SPEED ENTRIES:
!
!	NUM	BAUD	NUM	BAUD	NUM	BAUD
!	0	50.	1	75.	2	110.
!	3	134.5	4	150.	5	300.
!	6	600.	7	1200.	10	1800.
!	11	2000.	12	2400.	13	3600.
!	14	4800.	15	7200.	16	9600.
!	17	EXT
!-

macro
    HIPOL (index) =
	ch$rchar (ch$ptr (HIPOL_STRING, index)) %,
    LOPOL (index) =
	ch$rchar (ch$ptr (LOPOL_STRING, index)) %;

bind
    HIPOL_STRING = uplit (%char (
	4, 4, 4,
	4, 4, 4,
	4, 4, 4,
	4, 4, 3,
	2, 1, 1,
	0)),
    LOPOL_STRING = uplit (%char (
	12, 12, 12,
	12, 12, 12,
	12, 12, 12,
	12, 12, 8,
	6, 5, 3,
	0));

!
! OWN STORAGE:
!

external routine
    $DSPCR : novalue,
    $RDBRT : novalue;

$MCB_PROCESS (
    NAME = KDP,					! Process name
    DDM_DISPATCH = TABLE$ ($DSPCR, FC_CCP,	! DDM dispatch vector:
	(FC_XME, KDPXME),			!  Transmit enable
	(FC_RCE, $RDBRT),			!  Receive enable
	(FC_KIL, KDPKIL),			!  Kill enable
	(FC_CTL, KDPCTL),			!  Control enable
	(FC_TIM, KDPTIM)))			!  Timeout

!
! EXTERNAL REFERENCES:
!

external routine
    REGISTER_NXM : KDP_CSR_NUM,
    KDPNMI : novalue;

external
    MCB$GAW_PROCESS_DATA_BASE : vector [2],
    MCB$GW_PROCESS_HANDLE,
    MCB$GW_RDB_SIZE;		! Size of RDB buffer.

bind
    DB_BIAS = MCB$GAW_PROCESS_DATA_BASE [0];

macro
    GET_DUP_DATA_BASE (NAME) =
	%if %declared (NAME)
	%then map NAME : ref DUP_DATA_BASE
	%else bind NAME = .MCB$GAW_PROCESS_DATA_BASE [1] : DUP_DATA_BASE
	%fi %;
routine ASSIGN_RECEIVE_BUFFER (CCB) : LINKAGE_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = available RDB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);
    DB [D_ASSIGNABLE_RECEIVE_COUNT] = .DB [D_ASSIGNABLE_RECEIVE_COUNT] - 1;
    DB [D_ASSIGNED_RECEIVE_COUNT] = .DB [D_ASSIGNED_RECEIVE_COUNT] + 1;
    CCB [C_CNT] = .MCB$GW_RDB_SIZE;
    CCB [C_STS] = CIRBA;
    GIVE_TO_KMC (.CCB);
    end;			!of routine ASSIGN_RECEIVE_BUFFER
routine ASSIGN_TRANSMIT_BUFFER : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);

    if .DB [D_ASSIGNABLE_TRANSMIT_COUNT] neq 0
    then

	if $MCB_DEQUEUE_CCB (DB [D_ASSIGNABLE_TRANSMIT_CCBS], CCB)
	then
	    begin
	    DB [D_ASSIGNABLE_TRANSMIT_COUNT] = .DB [D_ASSIGNABLE_TRANSMIT_COUNT] - 1;
	    DB [D_ASSIGNED_TRANSMIT_COUNT] = .DB [D_ASSIGNED_TRANSMIT_COUNT] + 1;
	    CCB [C_STS] = CITBA;
	    GIVE_TO_KMC (.CCB);
	    end;

    end;			!of routine ASSIGN_TRANSMIT_BUFFER
routine CIBAS (CCB, PORT) : CALL$ =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	PORT = address of KMC data port buffer.
!	CCB = address of request CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS),
	PORT : ref vector [2];

    local
	EDB : ref block field (E_FIELDS),
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    EDB = .DB [D_EXT_ADDR];
    PORT [0] = 0;
    PORT [1] = .EDB [E_REGISTER] and %o'017770';
    DB [DF_DUP_CSR_SET] = TRUE;
    COMPLETE (DB [D_TIM], .CCB);
    MAP$ (.SAVE_MAP);
    BAS
    end;			!of routine CIBAS
routine CICTL (CCB, PORT) : CALL$ =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	PORT = address of KMC data port buffer.
!	CCB = address of request CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS),
	PORT : ref vector [2];

    local
	SAVE_MAP;

    SMAP$ (SAVE_MAP);
    begin

    local
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    MAP$ (.DB_BIAS);
    EDB = .DB [D_EXT_ADDR];
    PORT [0] = .EDB [E_POLLING_RATE];
    PORT [1] = .EDB [E_CTL];
    DB [DF_ENABLED] = .EDB [$SUB_FIELD (E_CTL, CT_ENB)];
    COMPLETE (DB [D_TIM], .CCB);
    end;
    MAP$ (.SAVE_MAP);
    CTL
    end;			!of routine CICTL
routine CIRBA (CCB, PORT) : CALL$ =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of request CCB.
!	PORT = address of KMC data port buffer.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS),
	PORT : ref vector [2];

    local
	DESC : ref vector,
	EDB : ref block field (E_FIELDS),
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    EDB = .DB [D_EXT_ADDR];
    DESC = .EDB [E_NEXT_RECEIVE_DESCRIPTOR];
    EDB [E_NEXT_RECEIVE_DESCRIPTOR] = .DESC [0];
    PORT [0] = .DESC [1];
    PORT [1] = .DESC [2];
    DESC = DESC [3];
    CCB [C_STS] = SET_DESCRIPTOR (.CCB, .DESC);
    EDB = EDB [E_ASSIGNED_RECEIVE_CCBS];
    $MCB_QUEUE_CCB (.EDB, .CCB);
    MAP$ (.SAVE_MAP);
    RBA
    end;			!of routine CIRBA
routine CIRBK (CCB, PORT) : CALL$ =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	PORT = address of KMC data port buffer.
!	CCB = address of request CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS),
	PORT : ref vector [2];

    local
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    PORT [0] = 0;
    PORT [1] = BIT_MASK [BA_KIL];
    $MCB_QUEUE_CCB (DB [D_PENDING_CONTROL_CCBS], .CCB);

    if not .DB [DF_DUP_CSR_SET] then RECEIVE_KILLED ();

    MAP$ (.SAVE_MAP);
    RBA
    end;			!of routine CIRBK
routine CITBA (CCB, PORT) : CALL$ =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of request CCB.
!	PORT = address of KMC data port buffer.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS),
	PORT : ref vector [2];

    local
	DESC : ref vector,
	EDB : ref block field (E_FIELDS),
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    EDB = .DB [D_EXT_ADDR];
    DESC = .EDB [E_NEXT_TRANSMIT_DESCRIPTOR];
    EDB [E_NEXT_TRANSMIT_DESCRIPTOR] = .DESC [0];
    PORT [0] = .DESC [1];
    PORT [1] = .DESC [2];
    DESC = DESC [3];
    CCB [C_STS] = SET_DESCRIPTOR (.CCB, .DESC);
    $MCB_QUEUE_CCB (EDB [E_ASSIGNED_TRANSMIT_CCBS], .CCB);
    block [DESC [0], BD_SOM] = 1;
    block [.CCB [C_STS], BD_EOM] = 1;

    if .EDB [$SUB_FIELD (E_CTL, CT_DEC)]
    then
	begin

	if .block [DESC [0], BD_LBD] eql 0
	then
	    begin
	    block [DESC [0], BD_EOM] = 1;
	    block [DESC [3], BD_SOM] = 1;
	    end;

	end;

    if .CCB [C_MOD] eql FM_SYN
    then
	block [DESC [0], BD_SYN] = 1;

    DB [D_TIM] = .DB [D_TRANSMIT_TIMEOUT];
    ASSIGN_TRANSMIT_BUFFER ();
    MAP$ (.SAVE_MAP);
    TBA
    end;			!of routine CITBA
routine CITBK (CCB, PORT) : CALL$ =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	PORT = address of KMC data port buffer.
!	CCB = address of request CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS),
	PORT : ref vector [2];

    local
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    PORT [0] = 0;
    PORT [1] = BIT_MASK [BA_KIL];
    $MCB_QUEUE_CCB (DB [D_PENDING_CONTROL_CCBS], .CCB);

    if not .DB [DF_DUP_CSR_SET] then TRANSMIT_KILLED ();

    MAP$ (.SAVE_MAP);
    TBA
    end;			!of routine CITBK
global routine COBAD (REG) : CALL$ novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	REG = address of KMC register buffer.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	REG : ref block field (KDP_FIELDS);

    local
	SAVE_MAP;

    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    begin
    GET_DUP_DATA_BASE (DB);

    bind
	EDB = .DB [D_EXT_ADDR] : block field (E_FIELDS);

    DB [DF_DUP_CSR_SET] = FALSE;
    DB [DF_ENABLED] = FALSE;
    DB [D_ASSIGNABLE_RECEIVE_COUNT] = 0;
    DB [D_ASSIGNABLE_TRANSMIT_COUNT] = 0;
    $NM_PLL_EVENT (4, .EDB [E_ENTITY],	%(Communications Interface Error)%
	PARAMETER_DEVICE_REGISTERS (.REG));
    end;
    MAP$ (.SAVE_MAP);
    end;			!of routine COBAD
global routine COCTL (REG) : CALL$ novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	REG = address of KMC register buffer.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	REG : ref block field (KDP_FIELDS);

    macro
	$return =
	    begin
	    MAP$ (.SAVE_MAP);
	    return
	    end %;

    local
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    DB [D_TIM] = 0;
    case .REG [$SUB_FIELD (SEL6, 0, 0, 8, 1)] from 6 to 22 of
	set

	[6] :				! Abort
	    begin

	    local
		CCB : ref block field (C_FIELDS);

	    if not RECEIVE_CCB (DB [D_TIM], 0; CCB) then $return;

	    $MCB_RETURN_RDB (.CCB);
	    end;

	[8] :				! Receive DDCMP Header CRC Error
	    begin
	    RECEIVE_DONE (BDADR (.REG [$SUB_FIELD (SEL4, BA_LOW)], .REG [$SUB_FIELD (SEL6, BA_HIGH)]), CE_HFE);
	    end;

	[10] :				! Receive Data CRC Error
	    begin
	    RECEIVE_DONE (BDADR (.REG [$SUB_FIELD (SEL4, BA_LOW)], .REG [$SUB_FIELD (SEL6, BA_HIGH)]), CE_DCR);
	    end;

	[12] :				! No Buffer Assigned
	    begin
	    COUNTER_INCREMENT (DB, D_NO_BUFFER_ASSIGNED);
	    COUNTER_INCREMENT (DB, D_PERFORMANCE_ERRORS);
	    end;

	[14] :				! Data Set Ready (DSR) Transition
	    begin

	    literal
		OFF = 0,
		ON = 1;

	    bind
		EDB = .DB [D_EXT_ADDR] : block field (E_FIELDS);

	    local
		STATE;

	    DB [DF_DSR] = not .DB [DF_DSR];
	    STATE = (if .DB [DF_DSR] then ON else OFF);
	    $NM_PLL_EVENT (0, .EDB [E_ENTITY],
		PARAMETER_C_1 (1, STATE));
	    end;

	[16] :				! Nonexsistent Memory
	    begin
	    COUNTER_INCREMENT (DB, D_NONEXISTENT_MEMORY);
	    COUNTER_INCREMENT (DB, D_DEVICE_ERRORS);
	    DEVICE_BROKEN (DB [D_TIM]);
	    end;

	[18] :				! Transmit Underrun
	    begin

	    bind
		EDB = .DB [D_EXT_ADDR] : block field (E_FIELDS);

	    local
		DESC : ref block field (BD_FIELDS);

	    DESC = BDADR (.REG [$SUB_FIELD (SEL4, BA_LOW)], .REG [$SUB_FIELD (SEL6, BA_HIGH)]);
	    DB [DF_TRANSMIT_UNDERRUN] = TRUE;

	    if .DESC [BD_LBD] then TRANSMIT_DONE (.DESC, CE_UDR);

	    POLLING_FAILURE ();
	    $NM_PLL_EVENT (5, .EDB [E_ENTITY],
		PARAMETER_DEVICE_REGISTERS (.REG));
	    end;

	[20] :				! Receiver Overrun
	    begin

	    bind
		EDB = .DB [D_EXT_ADDR] : block field (E_FIELDS);

	    POLLING_FAILURE ();
	    RECEIVE_DONE (BDADR (.REG [$SUB_FIELD (SEL4, BA_LOW)], .REG [$SUB_FIELD (SEL6, BA_HIGH)]), CE_ROV);
	    $NM_PLL_EVENT (5, .EDB [E_ENTITY],
		PARAMETER_DEVICE_REGISTERS (.REG));
	    end;

	[22] :				! Kill Complete

	    if .REG [$SUB_FIELD (SEL2, IN_I_O)]
	    then
		RECEIVE_KILLED ()
	    else
		TRANSMIT_KILLED ();

	[inrange, outrange] :
	    begin
	    COUNTER_INCREMENT (DB, D_INVALID_ERROR_CODE);
	    COUNTER_INCREMENT (DB, D_DEVICE_ERRORS);
	    DEVICE_BROKEN (DB [D_TIM]);
	    end;
	tes;

    GET_RECEIVE_BUFFERS ();
    MAP$ (.SAVE_MAP);
    end;			!of routine COCTL
routine COMPLETE (DB, CCB) : LINKAGE_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	DB = DUP data base
!	CCB = CCB to complete
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);

    selectone .CCB [C_FNC] of
	set
	[FC_AST] :
	    $MCB_RETURN_CCB (.CCB);
	[FC_CTL] :
	    begin
	    CCB [C_PIX] = .MCB$GW_PROCESS_HANDLE;
	    $MCB_SCHEDULE_CCB (.CCB);
	    end;
	[otherwise] :
	    begin
	    CCB [C_LIX] = .DB [D_LIX];
	    DDKCP$ (.CCB, CS_SUC)
	    end;
	tes

    end;			!of routine COMPLETE
global routine CORBA (REG) : CALL$ novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	REG = address of KMC register buffer.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	REG : ref block field (KDP_FIELDS);

    macro
	$return =
	    begin
	    MAP$ (.SAVE_MAP);
	    return
	    end %;

    local
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);

    if not .REG [$SUB_FIELD (SEL6, BA_EOM)]
    then
	begin

	if not .DB [DF_TRUNCATING_RECEIVE]
	then
	    begin
	    DB [DF_TRUNCATING_RECEIVE] = TRUE;
	    RECEIVE_DONE (BDADR (.REG [$SUB_FIELD (SEL4, BA_LOW)], .REG [$SUB_FIELD (SEL6, BA_HIGH)]), CE_MTL);
	    end
	else
	    begin

	    local
		CCB : ref block field (C_FIELDS);

	    if not RECEIVE_CCB (DB [D_TIM], 0; CCB) then $return;

	    $MCB_RETURN_RDB (.CCB);
	    end;

	end
    else
	begin

	if POLLING_THRESHOLD gtr .DB [D_POLLING_THRESHOLD]
	then
	    DB [D_POLLING_THRESHOLD] = .DB [D_POLLING_THRESHOLD] + 1;

	if not .DB [DF_TRUNCATING_RECEIVE]
	then
	    RECEIVE_DONE (BDADR (.REG [$SUB_FIELD (SEL4, BA_LOW)], .REG [$SUB_FIELD (SEL6, BA_HIGH)]), CS_SUC)
	else
	    begin

	    local
		CCB : ref block field (C_FIELDS);

	    DB [DF_TRUNCATING_RECEIVE] = FALSE;

	    if not RECEIVE_CCB (DB [D_TIM], 0; CCB) then $return;

	    $MCB_RETURN_RDB (.CCB);
	    end;

	end;

    GET_RECEIVE_BUFFERS ();
    MAP$ (.SAVE_MAP);
    end;			!of routine CORBA
global routine COTBA (REG) : CALL$ novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	REG = address of KMC register buffer.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	REG : ref block field (KDP_FIELDS);

    macro
	$return =
	    begin
	    MAP$ (.SAVE_MAP);
	    return
	    end %;

    local
	CCB : ref block field (C_FIELDS),
	DESC : ref block field (BD_FIELDS),
	SAVE_MAP;

    GET_DUP_DATA_BASE (DB);
    SMAP$ (SAVE_MAP);
    MAP$ (.DB_BIAS);
    DESC = BDADR (.REG [$SUB_FIELD (SEL4, BA_LOW)], .REG [$SUB_FIELD (SEL6, BA_HIGH)]);

    if not .DESC [BD_LBD] then $return;

    if not .DB [DF_TRANSMIT_UNDERRUN]
    then
	begin

	if POLLING_THRESHOLD gtr .DB [D_POLLING_THRESHOLD]
	then
	     DB [D_POLLING_THRESHOLD] = .DB [D_POLLING_THRESHOLD] + 1;

	TRANSMIT_DONE (.DESC, CS_SUC);
	end
    else
	begin
	DB [DF_TRANSMIT_UNDERRUN] = FALSE;
	TRANSMIT_DONE (.DESC, CE_UDR);
	end;

    MAP$ (.SAVE_MAP);
    end;			!of routine COTBA
routine CTLGET (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    GET_DUP_DATA_BASE (DB);

    map
	CCB : ref block field (C_FIELDS);

    bind
	EDB = .DB [D_EXT_ADDR] : block field (E_FIELDS);

    CALL$P (KMCPRM, .DB [D_KMC_PIX], .CCB);
    CCB [C_PRM2] = .EDB [E_REGISTER];
    CCB [$SUB_FIELD (C_PRM5, 0, 0, 8, 1)] = .EDB [ES_XMT];
    CCB [$SUB_FIELD (C_PRM5, 0, 8, 8, 1)] = .EDB [ES_RCV];
    DDCCP$ (.CCB, CS_SUC);
    end;			!of routine CTLGET
routine CTLSET (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    GET_DUP_DATA_BASE (DB);

    map
	CCB : ref block field (C_FIELDS);

    DB [DF_HALF_DUPLEX] = .CCB [C_PRM2];
    DB [DF_CONTROLLER_LOOPBACK] = .CCB [C_PRM3];
    DB [DF_INTERNAL_CLOCK] = .CCB [C_PRM4];
    DDCCP$ (.CCB, CS_SUC);
    end;			!of routine CTLSET
routine CTLSTP (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    local
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);

    if not .DB [DF_LINE_ACTIVE] then return DDCCP$ (.CCB, CS_SUC);

    DB [DF_STOPPING_LINE] = TRUE;
    EDB = .DB [D_EXT_ADDR];

    if .DB [DF_ENABLED]
    then
	begin
	EDB [E_CTL] = 0;
	CCB [C_STS] = CICTL;
	GIVE_TO_KMC (.CCB);
	return;
	end;

    if .vector [DB [D_PENDING_CONTROL_CCBS], 0] neqa 0
    then
	begin
	$MCB_QUEUE_CCB (DB [D_PENDING_CONTROL_CCBS], .CCB);
	return;
	end;

    DB [D_ASSIGNABLE_RECEIVE_COUNT] = 0;
    DB [D_ASSIGNABLE_TRANSMIT_COUNT] = 0;
    $MCB_CANCEL_RDB_REQUEST ();

    if .DB [D_ASSIGNED_RECEIVE_COUNT] neq 0
    then
	begin
	DB [DF_KILLING_RECEIVES] = TRUE;
	CCB [C_STS] = CIRBK;
	GIVE_TO_KMC (.CCB);
	return;
	end;

    if .DB [D_ASSIGNED_TRANSMIT_COUNT] neq 0
    then
	begin
	DB [DF_KILLING_TRANSMITS] = TRUE;
	CCB [C_STS] = CITBK;
	GIVE_TO_KMC (.CCB);
	return;
	end;

    $MCB_DISABLE_LONG_TIMER ();
    CALL$P (KMCSTP, .DB [D_KMC_PIX], .DB [D_UNIT]);
    DB [DF_DUP_CSR_SET] = FALSE;
    DB [DF_STOPPING_LINE] = FALSE;
    DB [DF_LINE_ACTIVE] = FALSE;
    CCB [C_LIX] = .DB [D_LIX];
    DDCCP$ (.CCB, CS_SUC);
    end;			!of routine CTLSTP
routine CTLSTR (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);

    if .DB [DF_LINE_ACTIVE] then return DDCCP$ (.CCB, CS_SUC);


    if not .DB [DF_STARTING_LINE]
    then
	begin

	local
	    EDB : ref block field (E_FIELDS);

	EDB = .DB [D_EXT_ADDR];

	if .EDB [E_REGISTER] lssa %o'160000' then return DDCCP$ (.CCB, CE_ABO);

	if REGISTER_NXM (.EDB [E_REGISTER], 4) then return DDCCP$ (.CCB, CE_ABO);

	if not CALL$P (KMCSTR, .DB [D_KMC_PIX], .DB [D_UNIT], .MCB$GW_PROCESS_HANDLE)
	then
	    return DDCCP$ (.CCB, CE_ABO);

	DB [D_LIX] = .CCB [C_LIX];
	$MCB_ENABLE_LONG_TIMER ();
	DB [DF_STARTING_LINE] = TRUE;
	end;

    if not .DB [DF_DUP_CSR_SET]
    then
	begin
	CCB [C_STS] = CIBAS;
	GIVE_TO_KMC (.CCB);
	return;
	end;

    if not .DB [DF_ENABLED]
    then
	begin
	INITIALIZE_CHARACTERISTICS ();
	DB [DF_DSR] = FALSE;
	CCB [C_STS] = CICTL;
	GIVE_TO_KMC (.CCB);
	return;
	end;

    DB [D_ASSIGNABLE_TRANSMIT_COUNT] = 2;
    DB [D_ASSIGNABLE_RECEIVE_COUNT] = 2;
    GET_RECEIVE_BUFFERS ();
    DB [DF_STARTING_LINE] = FALSE;
    DB [DF_LINE_ACTIVE] = TRUE;
    CCB [C_LIX] = .DB [D_LIX];
    DDCCP$ (.CCB, CS_SUC);
    end;			!of routine CTLSTR
routine DEVICE_BROKEN (DB) : LINKAGE_DB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    GET_DUP_DATA_BASE (DB);
    DB [DF_ENABLED] = FALSE;
    DB [DF_DUP_CSR_SET] = FALSE;
    end;			!of routine DEVICE_BROKEN
routine GET_RECEIVE_BUFFERS : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    GET_DUP_DATA_BASE (DB);

    while .DB [D_ASSIGNABLE_RECEIVE_COUNT] neq 0 do
	begin

	local
	    CCB : ref block field (C_FIELDS);

	if $MCB_GET_RDB (CCB)
	then
	    begin
	    CCB [C_FNC] = 0;
	    ASSIGN_RECEIVE_BUFFER (.CCB);
	    end
	else
	    begin
	    $MCB_REQUEST_RDB ();
	    exitloop;
	    end;

	end;

    end;			!of routine GET_RECEIVE_BUFFERS
routine GIVE_TO_KMC (CCB) : KDP_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of service CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);
    CCB [C_LIX] = .DB [D_UNIT];
    CCB [C_PIX] = .MCB$GW_PROCESS_HANDLE;
    CALL$P (KMCQUE, .DB [D_KMC_PIX], .CCB);
    end;			!of routine GIVE_TO_KMC
routine INITIALIZE_CHARACTERISTICS : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    EDB = .DB [D_EXT_ADDR];
    EDB [E_CTL] = BIT_MASK [CT_ENB];

    if .EDB [ES_PRT] eql EP_DEC
    then
	EDB [$SUB_FIELD (E_CTL, CT_DEC)] = 1;

    if .DB [DF_HALF_DUPLEX]
    then
	EDB [$SUB_FIELD (E_CTL, CT_DUP)] = 1;

    if .DB [DF_INTERNAL_CLOCK]
    then
	begin

	if .DB [DF_CONTROLLER_LOOPBACK]
	then
	    EDB [$SUB_FIELD (E_CTL, CT_MNT)] = 1
	else
	    EDB [$SUB_FIELD (E_CTL, CT_MNT)] = 2;

	end;

    EDB [E_POLLING_RATE] = LOPOL [.EDB [ES_XMT]];
    DB [D_POLLING_THRESHOLD] = POLLING_THRESHOLD;
    end;			!of routine INITIALIZE_CHARACTERISTICS
routine INITIALIZE_DESCRIPTOR_LIST (RING, POOL, COUNT) : LINKAGE_RING_POOL_COUNT novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	RING = address of ring to link descriptor list into.
!	POOL = address vector of memory available for descriptors.
!	COUNT = number of descriptors to put in list.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	RING = constructed descriptor list added to this ring.
!	POOL = advanced over allocated descriptors.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	DESC : ref vector;

    GET_DUP_DATA_BASE (DB);
    DESC = ..POOL;
    begin

    local
	BIAS;

    $MCB_CONVERT_TO_UBA_ADDRESS ((.DB [D_EXT_BIAS], DESC [3]), DESC [1], BIAS);
    DESC [2] = BIAS = .BIAS^14;
    end;

    if ..RING neq 0
    then
	begin
	DESC [0] = ...RING;
	..RING = DESC [0];
	end
    else
	.RING = DESC [0] = DESC [0];

    .POOL = DESC [3 + .COUNT*BD_LEN];
    end;			!of routine INITIALIZE_DESCRIPTOR_LIST
routine KDPCTL (DB, CCB, MODIFIER) : MCB_DB_CCB_MOD novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of CTL CCB.
!	MODIFIER = control function modifier (from C_MOD of CCB).
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    external routine
	$CCBRT;

    DISPATCH$ (.MODIFIER,
	TABLE$ ($DSPCR, FD_CTL,		! Control dispatch table:
	    (FM_STR, CTLSTR),		!  Start line
	    (FM_STP, CTLSTP),		!  Stop line
	    (FM_SET, CTLSET),		!  Set characteristics
	    (FM_GET, CTLGET)),		!  Get characteristics
	(.DB, .CCB),
	MCB_DB_CCB);
    end;			!of routine KDPCTL
routine KDPKIL (DB, CCB, MODIFIER) : MCB_DB_CCB_MOD novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of CTL CCB.
!	MODIFIER = control function modifier (from C_MOD of CCB).
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    DISPATCH$ (
	.MODIFIER,
	TABLE$ ($DSPCR, FD_KIL,		! Kill dispatch table:
	    (FM_KIL, KILKIL),		!  Transmit and receive kill
	    (FM_CRA, KILCRA),		!  Receive kill
	    (FM_XKL, KILXKL)),		!  Transmit kill
	(.DB, .CCB),
	MCB_DB_CCB);
    end;			!of routine KDPKIL
routine KDPTIM (DB, MODIFIER) : MCB_DB_MOD novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	MODIFIER = timer function modifier.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    DISPATCH$ (
	.MODIFIER,
	TABLE$ ($DSPCR, FD_TIM,		! Timer dispatch table:
	    (FM_LTM, TIMLTM),		!  Long timer
	    (FM_RDB, TIMRDB),		!  RDB available
	    (FM_PWF, TIMPWF),		!  Power failure
	    (FM_PIN, TIMPIN)),		!  Process initialization
	(.DB),
	MCB_DB);
    end;			!of routine KDPTIM
routine KDPXME (DB, CCB, MODIFIER) : MCB_DB_CCB_MOD novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of transmit CCB.
!	MODIFIER = transmit function modifier (from C_MOD of CCB).
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);

    if .DB [DF_LINE_ACTIVE]
    then
	begin

	local
	    SEG_CNT;

	$MCB_QUEUE_CCB (DB [D_ASSIGNABLE_TRANSMIT_CCBS], .CCB);
	SEG_CNT = .DB [D_MAXIMUM_TRANSMIT_SEGMENTS];

	do
	    begin

	    if (SEG_CNT = .SEG_CNT - 1) lss 0
	    then
		return SIGNAL_STOP (KDP$_SEG, .DB [$SUB_FIELD (D_ASSIGNABLE_TRANSMIT_CCBS, LIST_LAST)]);

	    end
	while (CCB = .CCB [C_CHN]) neq 0;

	ASSIGN_TRANSMIT_BUFFER ();
	end
    else
	begin
	CCB [C_LIX] = .DB [D_LIX];
	DDXCP$ (.CCB, CE_ABO);
	end;

    end;			!of routine KDPXME
routine KILCRA (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of kill CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    local
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    EDB = .DB [D_EXT_ADDR];

    if .DB [D_ASSIGNED_RECEIVE_COUNT] neq 0
    then
	begin
	DB [DF_KILLING_RECEIVES] = TRUE;
	DB [D_ASSIGNABLE_RECEIVE_COUNT] = 0;
	CCB [C_STS] = CIRBK;
	GIVE_TO_KMC (.CCB);
	end
    else
	COMPLETE (DB [D_TIM], .CCB);

    end;			!of routine KILCRA
routine KILKIL (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of kill CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    local
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    EDB = .DB [D_EXT_ADDR];

    if .DB [D_ASSIGNED_RECEIVE_COUNT] eql 0
    then
	return KILXKL (DB [D_TIM], .CCB);

    DB [DF_KILLING_RECEIVES] = TRUE;
    DB [D_ASSIGNABLE_RECEIVE_COUNT] = 0;

    if .DB [D_ASSIGNED_TRANSMIT_COUNT] neq 0
    then
	begin
	DB [DF_KILLING_TRANSMITS] = TRUE;
	DB [D_ASSIGNABLE_TRANSMIT_COUNT] = 0;
	end;

    CCB [C_STS] = CIRBK;
    GIVE_TO_KMC (.CCB);
    end;			!of routine KILKIL
routine KILXKL (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of kill CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    local
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    EDB = .DB [D_EXT_ADDR];

    if .DB [D_ASSIGNED_TRANSMIT_COUNT] neq 0
    then
	begin
	DB [DF_KILLING_TRANSMITS] = TRUE;
	DB [D_ASSIGNABLE_TRANSMIT_COUNT] = 0;
	CCB [C_STS] = CITBK;
	GIVE_TO_KMC (.CCB);
	end
    else
	COMPLETE (DB [D_TIM], .CCB);

    end;			!of routine KILXKL
global routine PARAMETER_DEVICE_REGISTERS

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
       (REG : ref vector)
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
	: KDP_REG novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    decr COUNT from 4 to 1 do
	begin
	PARAMETER_H_2 (0, REG [0]);
	REG = REG [1];
	end;

    end;			!of routine PARAMETER_DEVICE_REGISTERS
routine POLLING_FAILURE : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS),
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    DB [D_POLLING_THRESHOLD] = .DB [D_POLLING_THRESHOLD] - 1;

    if .DB [D_POLLING_THRESHOLD] neq 0 then return;

    EDB = .DB [D_EXT_ADDR];

    if .EDB [E_POLLING_RATE] eqlu HIPOL [.EDB [ES_XMT]]
    then

	if $MCB_GET_CCB (CCB)
	then
	    begin
	    COUNTER_INCREMENT (DB, D_POLLING_ADJUSTMENT);
	    COUNTER_INCREMENT (DB, D_PERFORMANCE_ERRORS);
	    EDB [E_POLLING_RATE] = .EDB [E_POLLING_RATE] - 1;
	    DB [D_POLLING_THRESHOLD] = POLLING_THRESHOLD;
	    CCB [C_FNC] = FC_AST;
	    CCB [C_STS] = CICTL;
	    GIVE_TO_KMC (.CCB);
	    end
	else
	    DB [D_POLLING_THRESHOLD] = .DB [D_POLLING_THRESHOLD] + 1;

    end;			!of routine POLLING_FAILURE
routine RECEIVE_CCB (DB, DESC; CCB) : KDP_LKG_DB_DESC_CCB =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	DESC = terminated descriptor.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS),
	DESC : ref block field (BD_FIELDS);

    local
	QUE;

    GET_DUP_DATA_BASE (DB);
    QUE = block [.DB [D_EXT_ADDR], E_ASSIGNED_RECEIVE_CCBS];

    if not $MCB_DEQUEUE_CCB (.QUE, CCB)
    then
	begin
	COUNTER_INCREMENT (DB, D_RECEIVE_BA_ERROR);
	COUNTER_INCREMENT (DB, D_DEVICE_ERRORS);
	DEVICE_BROKEN (DB [D_TIM]);
	return FALSE;
	end;

    if .DESC neq 0
    then
	if .CCB [C_STS] neq .DESC
	then
	    begin
	    $MCB_STACK_CCB (.QUE, .CCB);
	    COUNTER_INCREMENT (DB, D_RECEIVE_BA_ERROR);
	    COUNTER_INCREMENT (DB, D_DEVICE_ERRORS);
	    DEVICE_BROKEN (DB [D_TIM]);
	    return FALSE;
	    end;

    DB [D_ASSIGNED_RECEIVE_COUNT] = .DB [D_ASSIGNED_RECEIVE_COUNT] - 1;

    if not .DB [DF_KILLING_RECEIVES]
    then
	DB [D_ASSIGNABLE_RECEIVE_COUNT] = .DB [D_ASSIGNABLE_RECEIVE_COUNT] + 1;

    CCB [C_CNT] = .DESC [BD_CC];
    TRUE
    end;			!of routine RECEIVE_CCB
routine RECEIVE_DONE (DESC, STS) : LINKAGE_DESC_STS novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	DESC = terminated descriptor.
!	STS = return status code for receive CCB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	DESC : ref block field (BD_FIELDS);

    local
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);

    if not RECEIVE_CCB (DB [D_TIM], .DESC; CCB) then return;

    CCB [C_LIX] = .DB [D_LIX];
    CCB [C_FNC] = FC_RCE;
    CCB [C_MOD] = 0;
    DDRCP$ (.CCB, .STS);
    end;			!of routine RECEIVE_DONE
routine RECEIVE_KILLED : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    GET_DUP_DATA_BASE (DB);
    DB [DF_KILLING_RECEIVES] = FALSE;
    DB [DF_TRUNCATING_RECEIVE] = FALSE;
    DB [D_ASSIGNED_RECEIVE_COUNT] = 0;

    if .DB [DF_ENABLED]
    then
	DB [D_ASSIGNABLE_RECEIVE_COUNT] = 2;

    while TRUE do
	begin

	local
	    CCB : ref block field (C_FIELDS);

	if not $MCB_DEQUEUE_CCB (block [.DB [D_EXT_ADDR], E_ASSIGNED_RECEIVE_CCBS], CCB) then exitloop;

	$MCB_RETURN_RDB (.CCB);
	end;

    GET_RECEIVE_BUFFERS ();
    begin

    local
	CCB : ref block field (C_FIELDS);

    if $MCB_DEQUEUE_CCB (DB [D_PENDING_CONTROL_CCBS], CCB)
    then

	if .DB [DF_KILLING_TRANSMITS]
	then
	    begin
	    CCB [C_STS] = CITBK;
	    GIVE_TO_KMC (.CCB);
	    end
	else
	    do
		COMPLETE (DB [D_TIM], .CCB)
	    while $MCB_DEQUEUE_CCB (DB [D_PENDING_CONTROL_CCBS], CCB);

    end;
    end;			!of routine RECEIVE_KILLED
routine SET_DESCRIPTOR (CCB, DESC) : LINKAGE_CCB_DESC =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = address of CCB chain.
!	DESC = address of buffer descriptor list.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!	Address of last buffer descriptor used.
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	NEXT_CCB : ref block field (C_FIELDS),
	NEXT_DESC : ref block field (BD_FIELDS);

    NEXT_CCB = .CCB;
    NEXT_DESC = .DESC;

    do
	begin

	local
	    HIGH;

	$MCB_CONVERT_TO_UBA_ADDRESS ((.NEXT_CCB [C_BIAS], .NEXT_CCB [C_ADDR]),
	    NEXT_DESC [BD_LOW], HIGH);
	NEXT_DESC [BD_CC] = .NEXT_CCB [C_CNT];
	NEXT_DESC [%fieldexpand (BD_HIGH, 0), 0, %bpval, 0] = .HIGH^%fieldexpand (BD_HIGH, 1);
	NEXT_DESC = NEXT_DESC [BD_LEN, 0, %bpval, 1];
	end
    while (NEXT_CCB = .NEXT_CCB [C_CHN]) neq 0;

    NEXT_DESC = NEXT_DESC [-BD_LEN, 0, %bpval, 1];
    NEXT_DESC [BD_LBD] = 1;
    .NEXT_DESC
    end;			!of routine SET_DESCRIPTOR
routine TIMLTM (DB) : MCB_DB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    EDB = .DB [D_EXT_ADDR];

    if .EDB [$SUB_FIELD (E_ASSIGNED_TRANSMIT_CCBS, LIST_FIRST)] neq 0 and
	not .DB [DF_KILLING_TRANSMITS]
    then
	begin

	local
	    CCB : ref block field (C_FIELDS);

	if not $MCB_GET_CCB (CCB) then return DB [D_TIM] = .DB [D_TIM] + 1;

	CCB [C_FNC] = FC_AST;
	KILXKL (DB [D_TIM], .CCB);
	end;

    end;			!of routine TIMLTM
routine TIMPIN (DB) : MCB_DB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	DESC : ref vector,
	EDB : ref block field (E_FIELDS);

    GET_DUP_DATA_BASE (DB);
    MAP$ (DB_BIAS = .DB [D_EXT_BIAS]);
    EDB = .DB [D_EXT_ADDR];
    DB [DF_HALF_DUPLEX] = .EDB [EF_HDX];
    DESC = EDB [E_DESCRIPTORS];

    decr CNT from 2 to 1 do
	INITIALIZE_DESCRIPTOR_LIST (EDB [E_NEXT_TRANSMIT_DESCRIPTOR], DESC, .DB [D_MAXIMUM_TRANSMIT_SEGMENTS]);

    decr CNT from 2 to 1 do
	INITIALIZE_DESCRIPTOR_LIST (EDB [E_NEXT_RECEIVE_DESCRIPTOR], DESC, 1);

    if .DB [D_UNIT] eql 0
    then
	begin

	local
	    KMC_PIX;

	if $MCB_SET_PROCESS (, KMC_PIX)
	then
	    begin
	    DB [D_KMC_PIX] = .KMC_PIX;
	    CALL$P (KMCDB, .KMC_PIX, .DB_BIAS, vector [DB [D_TIM], -K_LEN]);
	    end;

	end
    else
	begin

	bind
	    DB0 = vector [DB [D_TIM], .DB [D_UNIT]*-D_LEN] : block field (D_FIELDS);

	DB [D_KMC_PIX] = .DB0 [D_KMC_PIX];
	end;

    KDPNMI ();
    end;			!of routine TIMPIN
routine TIMPWF (DB) : MCB_DB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    NO_OPERATION
    end;			!of routine TIMPWF
routine TIMRDB (DB, CCB) : MCB_DB_CCB novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	CCB = available RDB.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    GET_DUP_DATA_BASE (DB);

    if .DB [D_ASSIGNABLE_RECEIVE_COUNT] neq 0
    then
	ASSIGN_RECEIVE_BUFFER (.CCB)
    else
	$MCB_RETURN_RDB (.CCB);

    end;			!of routine TIMRDB
routine TRANSMIT_DONE (DESC, STS) : LINKAGE_DESC_STS novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	DESC = terminated descriptor address.
!	STS = completion status.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	DESC : ref block field (BD_FIELDS);

    local
	CCB : ref block field (C_FIELDS),
	QUE;

    GET_DUP_DATA_BASE (DB);
    QUE = block [.DB [D_EXT_ADDR], E_ASSIGNED_TRANSMIT_CCBS];

    if not $MCB_DEQUEUE_CCB (.QUE, CCB)
    then
	begin
	COUNTER_INCREMENT (DB, D_TRANSMIT_BA_ERROR);
	COUNTER_INCREMENT (DB, D_DEVICE_ERRORS);
	DEVICE_BROKEN (DB [D_TIM]);
	return;
	end;

    if .CCB [C_STS] neq .DESC
    then
	begin
	$MCB_STACK_CCB (.QUE, .CCB);
	COUNTER_INCREMENT (DB, D_TRANSMIT_BA_ERROR);
	COUNTER_INCREMENT (DB, D_DEVICE_ERRORS);
	DEVICE_BROKEN (DB [D_TIM]);
	return;
	end;

    DB [D_TIM] = 0;
    DB [D_ASSIGNED_TRANSMIT_COUNT] = .DB [D_ASSIGNED_TRANSMIT_COUNT] - 1;

    if not .DB [DF_KILLING_TRANSMITS]
    then
	DB [D_ASSIGNABLE_TRANSMIT_COUNT] = .DB [D_ASSIGNABLE_TRANSMIT_COUNT] + 1;

    CCB [C_LIX] = .DB [D_LIX];
    DDXCP$ (.CCB, .STS);
    ASSIGN_TRANSMIT_BUFFER ();
    end;			!of routine TRANSMIT_DONE
routine TRANSMIT_KILLED : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    GET_DUP_DATA_BASE (DB);
    DB [DF_KILLING_TRANSMITS] = FALSE;
    DB [DF_TRANSMIT_UNDERRUN] = FALSE;
    DB [D_ASSIGNED_TRANSMIT_COUNT] = 0;

    if .DB [DF_ENABLED]
    then
	DB [D_ASSIGNABLE_TRANSMIT_COUNT] = 2;

    while TRUE do
	begin

	local
	    CCB : ref block field (C_FIELDS);

	if not $MCB_DEQUEUE_CCB (block [.DB [D_EXT_ADDR], E_ASSIGNED_TRANSMIT_CCBS], CCB)
	then

	    if not $MCB_DEQUEUE_CCB (DB [D_ASSIGNABLE_TRANSMIT_CCBS], CCB)
	    then
		exitloop;

	CCB [C_LIX] = .DB [D_LIX];
	DDXCP$ (.CCB, CE_ABO);
	end;

    while TRUE do
	begin

	local
	    CCB : ref block field (C_FIELDS);

	if not $MCB_DEQUEUE_CCB (DB [D_PENDING_CONTROL_CCBS], CCB) then exitloop;

	COMPLETE (DB [D_TIM], .CCB);
	end;

    end;			!of routine TRANSMIT_KILLED
end
eludom