/* This file is part of the Hardware Control Functions Light (HCF-light) library
   to control the Lucent Technologies WaveLAN/IEEE Network I/F Card.
   The HCF is the implementation of the Wireless Connection I/F (WCI).
   
   The HCF-light files are a subset of the HCF files. The complete set offers a
   number of additional facilities, e.g. firmware download, Etherner-II encapsulation,
   additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support,
   Configuration Management.
   This complete set is explicitely not in the Public Domain but can be made 
   available under certain restriction. (see the pointer below for support)
   
   The HCF-light files are free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
   
   At the time of this writing, you can request for support at:
   betasupport@wavelan.com
   
   Documentation is expected to be available in the week of 8 Februari 1999

*/


/**************************************************************************************************************
*
* FILE   :	HCF.CPP *************** 2.0 ***********************************************************************
*
* DATE    :	2001/08/17 14:26:32   1.3
*
* AUTHOR :	Nico Valster
*
* DESC   :	HCF Routines hcf_action, hcf_connect, hcf_disable
*						 hcf_disconnect, hcf_download, hcf_enable, hcf_generate_int
*						 hcf_get_info, hcf_get_data, hcf_service_nic
*						 hcf_put_info, hcf_put_data, hcf_register_mailbox, hcf_send,
*						 hcf_send_diag_msg
*			Local Support Routines for above procedures
*
*			Customizable via HCFCFG.H, which is included by HCF.H
*
***************************************************************************************************************
* COPYRIGHT (c) 1995			 by AT&T.	 				All Rights Reserved
* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies.	All Rights Reserved
*
* At the sole discretion of Lucent Technologies parts of this source may be extracted
* and placed in the Public Domain under the GPL.
* This extraction takes place by means of an AWK-script acting on embedded tags.
* The AWK script is:
 *	BEGIN { c = 0 }
 *	{ if ( c == 0 ) i = 1}			#if in @HCF_L>..@HCF_L< block, skip
 *	{ if (name != FILENAME ) name = FILENAME }
 *	
 *	{ if ( i && c == 0  ) { print ; hcf_l_cnt++ } }
 *	#{ if ( i ) { print ; hcf_l_cnt++ } }
 *	#{if ( c == 0 ) { printf("N%d", c) ; hcf_l_cnt++ } }
 *	#{if ( c == 1 ) { printf("E%d", c) ; hcf_l_cnt++ } }
 *	
 *	#END { printf("%s:: HCF lines: %d, HCF_Light lines: %d", name, NR, hcf_l_cnt ) }
*
* and is not in any sense derived from the extracted source. 
*
**************************************************************************************************************/





/****************************************************************************
wvlan_hcf.c,v
Revision 1.3  2001/08/17 14:26:32  root
*** empty log message ***

Revision 1.2  2000/01/06 23:30:52  root
*** empty log message ***

 * 
 *    Rev 1.0   02 Feb 1999 14:32:28   NVALST
 * Initial revision.
Revision 1.3  1999/02/01 22:58:40  nico
*** empty log message ***
 * 
 *    Rev 2.12   29 Jan 1999 10:48:40   NVALST
 * 
 *    Rev 1.108   28 Jan 1999 14:43:18   NVALST
 * intermediate, once more correction of loop in hcf_service_nic + download
 * passed to Marc
 * 
****************************************************************************/

/**************************************************************************************************************
*
* CHANGE HISTORY
*

  960702 - NV
	Original Entry - derived from WaveLAN-I HCF 2.12


*
* ToDo
*
 1:	For all/most functions, update "MSF-accessible fields of Result Block:" entry
 2: Use the "numbered comments" in the NARRATIVE consistently, i.e. hcf_put_info
 3: hcf_put_data, hcf_send, hcf_send_diag_msg
	once the dust is settled whether hcf_put_data or hcf_send is the appropriate place is to specify port,
	it can be considered whether part of the hcf_send_diag_msg and hcf_send can be isolated in a common
	routine.
 4:	hcf_send_diag_msg:
  	- what are the appropriate return values
	- once the dust is settled whether type should or shouldn't be parameter of hcf_send_diag_msg, it can
	  be decided whether the HFX_TX_CNTL_ABS update at each call is needed
 5:	hcf_service_nic, hcf_send, hcf_send_diag_msg etc
 	check for a CONSISTENT strategy for the testing of IFB_CardStat, for presence, enabled, ports
 6:	Decide on the relative merits of HCF_ACT_ASSERT_OFF/_ON versus CFG_REG_MSF_ASSERT
	

*
* Implementation Notes
*
 -	C++ style cast is not used to keep DA-C happy
 -	a leading marker of //! is used. The purpose of such a sequence is to help the
	(maintenance) programmer to understand the flow
 	An example in hcf_action( HCF_ACT_802_3 ) is
	//!		ifbp->IFB_RxFence = 0;
	which is superfluous because IFB_RxFence gets set at every hcf_service_nic but
	it shows to the (maintenance) programmer it is an intentional omission at
	the place where someone could consider it most appropriate at first glance
 -	using near pointers in a model where ss!=ds is an invitation for disaster, so be aware of how you specify
 	your model and how you define variables which are used at interrupt time
 -	Once the comment "the value of -1 for parameter len is meaningless but it guarantees that the next call
 	to bap_ini is interpreted as an initial call, causing the BAP to be really initialized." was considered
 	useful information. Does this trick still lingers somewhere;?
 -	remember that sign extension on 32 bit platforms may cause problems unless code is carefully constructed,
 	e.g. use "(hcf_16)~foo" rather than "~foo"

	
*
* Miscellaneous Notes
*
 -	AccessPoint performance could be improved by adding a hcf_send_pif_msg equivalent of hcf_send_diag_msg


*************************************************************************************************************/

#include "wvlan_hcf.h"				// HCF and MSF common include file
#include "wvlan_hcfdef.h"			// HCF specific include file

/*************************************************************************************************************/
/***************************************  PROTOTYPES  ********************************************************/
/*************************************************************************************************************/
// moving these prototypes to HCFDEF.H turned out to be less attractive in the HCF-light generation
STATIC int			aux_cntl( IFBP ifbp, hcf_16 cmd );
STATIC int			calibrate( IFBP ifbp );
STATIC int			cmd_wait( IFBP ifbp, int cmd_code, int par_0 );
STATIC void			enable_int(IFBP ifbp, int event );
       int			hcf_initialize( IFBP ifbp );
STATIC int			ini_hermes( IFBP ifbp );
STATIC void	 		isr_info( IFBP ifbp );
STATIC int			put_info( IFBP ifbp, LTVP ltvp	);
STATIC hcf_16		alloc( IFBP ifbp, int len );


/**************************************************************************************************************
******************************* D A T A    D E F I N I T I O N S **********************************************
**************************************************************************************************************/

STATIC hcf_8 BASED hcf_rev[] = "\nHCF1.3\n";

/* Note that the "BASED" construction (supposedly) only amounts to something in the small memory model.
 * In that case CS and DS are equal, so we can ignore the consequences of casting the BASED cfg_drv_...
 * structure to hcf_16
 * Note that the whole BASED riggamarole is needlessly complicated because both the Microsoft Compiler and
 * Linker are unnecessary restrictive in what far pointer manipulation they allow
 */


/* 
	The below table accessed via a computed index was the original implementation for hcf_get_info with 
	CFG_DRV_IDENTITY, CFG_DRV_SUP_RANGE, CFG_DRV_ACT_RANGE_PRI, CFG_DRV_ACT_RANGE_STA, CFG_DRV_ACT_RANGE_HSI
	as type. However it was reported that the 68K compiler for MAC OS is unable to initialize pointers.
	Accepting this story at face value, the HCF is coded around this problem by implementing a direct access..
	To save part of the invested effort, the original table is kept as comment.

STATIC LTV_STRCT*   BASED xxxx[ ] = {
	(LTV_STRCT*)&cfg_drv_identity,      //CFG_DRV_IDENTITY              0x0826
	(LTV_STRCT*)&cfg_drv_sup_range,     //CFG_DRV_SUP_RANGE             0x0827
	(LTV_STRCT*)&cfg_drv_act_range_pri, //CFG_DRV_ACT_RANGE_PRI         0x0828
	(LTV_STRCT*)&cfg_drv_act_range_sta  //CFG_DRV_ACT_RANGE_STA         0x0829
	(LTV_STRCT*)&cfg_drv_act_range_hsi	//CFG_DRV_ACT_RANGE_HSI			0x082A
  };
*/


/**************************************************************************************************************
************************** T O P   L E V E L   H C F   R O U T I N E S ****************************************
**************************************************************************************************************/


/*******************************************************************************************************************


.MODULE			hcf_action
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			NW4
.APPLICATION	Card configuration
.DESCRIPTION	Changes the run-time Card behavior

.ARGUMENTS
  int hcf_action(IFBP ifbp, hcf_action_cmd action )
.RETURNS
  int

  MSF-accessible fields of Result Block: -

.NARRATIVE

 Name:	hcf_action

 Summary: Changes the run-time Card behavior

 Parameters:
  ifbp	address of the Interface Block

  action	number identifying the type of change

  o HCF_ACT_INT_ON		enable interrupt generation by WaveLAN NIC
  o HCF_ACT_INT_OFF		disable interrupt generation by WaveLAN NIC
  o HCF_ACT_CARD_IN		MSF reported Card insertion
  o HCF_ACT_CARD_OUT	MSF reported Card removal

 Returns:
  o	HCF_ACT_INT_OFF
		0: no interrupt pending
		1: interrupt pending
  o	all other
		0 (((however, see the special treatment for HCF_ACT_INT_ON)))

 Remarks:
  o	HCF_ACT_INT_OFF/HCF_ACT_INT_ON codes may be nested but must be balanced. The INT_OFF/INT_ON housekeeping
	is initialized by hcf_connect with a call of hcf_action with INT_OFF, causing the interrupt generation
	mechanism to be disabled at first. This suits MSF implementation based on a polling strategy. An MSFT
	based on a interrupt strategy must call hcf_action with INT_ON in its initialization logic.

  o To prevent I/O while the I/O space is no longer owned by the HCF, due to a card swap, no I/O is allowed
	when the CARD_STAT_PRESENT bit of IFB_CardStat is off.

.DIAGRAM
 2: IFB_IntOffCnt is used to balance the INT_OFF and INT_ON calls.
 4: Disabling of the interrupts is simply achieved by writing a zero to the Hermes IntEn register
 5: To be able to return the information to the MSF whether an interrupt is actually pending, the Hermes
	EvStat register is sampled and compared against the current IFB_IntEnMask value
 6:	Originally the construction "if ( ifbp->IFB_IntOffCnt-- <= 1 )" was used in stead of
 	"if ( --ifbp->IFB_IntOffCnt == 0 )". This serviced to get around the unsigned logic, but as additional
 	"benefit" it seemed the most optimal "fail safe" code (in the sense of shortest/quickest path in error
 	free flows, fail safe in the sense of too many INT_ON invocations compared to INT_OFF). However when a
 	real life MSF programmer ran to a MSF sequence problem, exactly causing that problem, he was annoyed
 	with this fail safe code. As a consequence it is taken out. As a side-effect of this unhappy MSF programmer
 	adventures to find his problem, the return status is defined to reflect the IFBIntOffCnt, Note that this 
 	is solely intended for aid debugging, no MSF logic should depend on this feature, No garuantees for the 
 	future are given.
 	Enabling of the interrupts is achieved by writing the contents of IFB_IntEnMask to the Hermes IntEn
 	register.
 7:	Since the card is present again, it must be re-initialized. Since this may be another card we may as well 
 	clear all bits in IFB_CardStat and set only the "present" bit. 
 	The first call to hcf_enable will restore the contents of HREG_INT_EN register taking the 
 	HCF_ACT_IN_ON/OFF history in account.
 9:	The MSF must call hcf_action with HCF_ACT_CARD_OUT when the MSF detects a card removal (e.g. when the MSF
	is notified by the CAD). As a minimum, the "present" bit in IFB_CardStat must be reset, however since
	the card insertion will clear all other bits, the simplest solution is to clear IFB_CardStat here as well.
	As a result of the resetting of the CARD_STAT_PRESENT bit, no hcf-function except hcf_action with
	HCF_ACT_CARD_IN results in card I/O anymore. However hcf_functions may still perform their other
	activities, e.g. hcf_get_info_mb still supplies a MBIB if one is available.
	As a result of the resetting of the CARD_STAT_INI bit, the call to hcf_initialize by hcf_action with
	HCF_ACT_CARD_IN results in re-initialization of the NIC.
.ENDOC				END DOCUMENTATION


**************************************************************************************************************/
int hcf_action( IFBP ifbp, 					//address of the Interface Block
				hcf_action_cmd action		/*number identifying the type of change
											*/
 				) {

int		rc = HCF_SUCCESS;
//int		i, j;
//hcf_16	scratch[2];

	

	switch (action) {
	  case HCF_ACT_INT_OFF:						// Disable Interrupt generation
		ifbp->IFB_IntOffCnt++;																			/* 2 */
		if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
			OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_INT_EN, 0 ); 										/* 4 */
			if ( IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ) & ifbp->IFB_IntEnMask ) {				/* 5 */
				rc = HCF_INT_PENDING;
			}
		}
		break;
		
	  case HCF_ACT_INT_ON:						// Enable Interrupt generation
		if ( --ifbp->IFB_IntOffCnt == 0 ) {																/* 6 */
			if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
				OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_INT_EN, ifbp->IFB_IntEnMask );
			}
		}
		rc = ifbp->IFB_IntOffCnt;
		break;
		
	  case  HCF_ACT_CARD_IN:					// MSF reported Card insertion							/* 7 */
		ifbp->IFB_CardStat = CARD_STAT_PRESENT;
		hcf_initialize ( ifbp );

		if ( ifbp->IFB_CardStat & CARD_STAT_ENABLED ) {
		  (void)hcf_enable( ifbp, 0 );
		}
		break;
	
	  case 	HCF_ACT_CARD_OUT:  					// MSF reported Card removal							/* 9 */
		ifbp->IFB_CardStat = 0;
		break;
		
		
	  case 	HCF_ACT_TALLIES:					// Hermes Inquire Tallies (F100) command				/*12 */
		action = (hcf_action_cmd)(action - HCF_ACT_TALLIES + CFG_TALLIES);
		if ( ifbp->IFB_CardStat & CARD_STAT_ENABLED ) {
		  rc = cmd_wait( ifbp, HCMD_INQUIRE, action );
		}  		
		break;
		
		
		

	  default:
		break;
	}
	return rc;
}/* hcf_action */



/*******************************************************************************************************************

.MODULE			hcf_connect
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
.DESCRIPTION	Initializes Card and HCF housekeeping

.ARGUMENTS
  void hcf_connect( IFBP ifbp, hcf_io io_base )

.RETURNS
	n.a.

  MSF-accessible fields of Result Block:
	IFB_IOBase				entry parameter io_base
	IFB_IORange				HREG_IO_RANGE (0x40)
	IFB_HCFVersionMajor		the major part of the PVCS maintained version number
	IFB_HCFVersionMinor		the minor part of the PVCS maintained version number
	IFB_Version				version of the IFB layout (0x01 for this release)
	
.NARRATIVE

 Parameters:
	ifbp		address of the Interface Block
	io_base		I/O Base address of the NIC


  Hcf_connect grants access right for the HCF to the IFB and initializes the HCF housekeeping part of the
  IFB. Hcf_connect does not perform any I/O.

  The HCF-Version fields are set dynamically, because I do not know of any C mechanism to have the compiler
  and the version control system (PVCS) cooperate to achieve this at compile time.  The HCFVersions fields are
  constructed by collecting and shifting the low order nibbles of the PVCS controlled ASCII representation.
  Note that the low order nibble of a space (0x20) nicely coincides with the low order nibble of an ASCII '0'
  (0x30). Also note that the code breaks when major or minor number exceeds 99.


.DIAGRAM
 1:	patch_catch is called as early in the flow as the C-entry code allows to help the HCF debugger as much as
	possible.  The philosophy behind patch_catch versus a simple direct usage of the INT_3 macro is explained
	in the description of patch_catch
 2:	The IFB is zero-filled.
 	This presets IFB_CardStat and IFB_TickIni at appropriate values for hcf_initialize.
10: In addition to the MSF readable fields mentioned in the description section, the following HCF specific
	fields are given their actual value:
	  -	a number of fields as side effect of the calls of hcf_action (see item 14)
	  -	IFB_Magic
	IFB_VERSION, which reflects the version of the IFB layout, is defined in HCF.H
14:	Hcf_connect defaults to "no interrupt generation" (by calling hcf_action with the appropriate parameter),
	"802.3 frame type" and "no card present" (implicitly achieved by the zero-filling of the IFB).
	Depending on HCFL, the 802.3 frame type is either initialized in line or by calling hcf_action.
	
.NOTICE
  If io_base ever needs to be dynamic, it may be more logical to pass
	- io_base at hcf_enable or
	- have a separate hcf_put_config command or
	- demand a hcf_disconnect - hcf_connect sequence
	
.NOTICE
  On platforms where the NULL-pointer is not a bit-pattern of all zeros, the zero-filling of the IFB results
  in an seemingly incorrect initialization of IFB_MBp. The implementation of the MailBox manipulation in
  put_mb_info protects against the absence of a MailBox based on IFB_MBSize, IFB_MBWp and ifbp->IFB_MBRp. This
  has ramifications on the initialization of the MailBox via hcf_put_info with the CFG_REG_MB type.

.ENDOC				END DOCUMENTATION
-------------------------------------------------------------------------------------------------------------*/
void hcf_connect( IFBP ifbp, 					//address of the Interface Block
				  hcf_io io_base				//I/O Base address of the NIC
				) {

hcf_8 *q;

#if defined _M_I86TM
#endif // _M_I86TM
	

	for ( q = (hcf_8*)&ifbp[1]; q > (hcf_8*)ifbp; *--q = 0) /*NOP*/;									/* 2 */

	ifbp->IFB_Version	= IFB_VERSION;					  												/* 10*/
	ifbp->IFB_IOBase	= io_base;
	ifbp->IFB_IORange	= HREG_IO_RANGE;
	ifbp->IFB_Magic		= HCF_MAGIC;
	ifbp->IFB_HCFVersionMajor	= (hcf_8)( (hcf_rev[REV_OFFSET] << 4 | hcf_rev[REV_OFFSET+1]) & 0x0F );
	ifbp->IFB_HCFVersionMinor	= (hcf_8)( hcf_rev[REV_OFFSET+4] == ' ' ?
								  		   hcf_rev[REV_OFFSET+3] & 0x0F :
								  		   (hcf_rev[REV_OFFSET+3] << 4 | hcf_rev[REV_OFFSET+4]) & 0x0F );

	(void)hcf_action(ifbp, HCF_ACT_INT_OFF );															/* 14*/
    ifbp->IFB_FSBase = HFS_ADDR_DEST_ABS;
	return;
}/* hcf_connect	*/





/*******************************************************************************************************************

.MODULE			hcf_disable
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
.DESCRIPTION    Disables data transmission and reception
.ARGUMENTS
  int hcf_disable( IFBP ifbp, hcf_16 port )

.RETURNS
	HCF_SUCCESS
	HCF_ERR_NO_NIC
	HCF_ERR_TIME_OUT (via cmd_wait)
	HCF_FAILURE (via cmd_wait)
	
  MSF-accessible fields of Result Block:
   	IFB_CardStat  -	reset CARD_STAT_ENABLED bit iff at completion no port enabled anymore

.NARRATIVE

  Parameters:
	ifbp		address of the Interface Block

  Condition Settings:
	Card Interrupts	  - Unchanged
					  -	Disabled (Note that the value of IFB_IntOffCnt is unchanged)
					    					  

.NOTICE
 o  hcf_disable may disable the card interrupts, however it does NOT influence IFB_IntOffCnt.
	This way it is symmetrical with hcf_enable, which does NOT enable the card interrupts.	
	
**************************************************************************************************************/
int hcf_disable( IFBP ifbp, hcf_16 port ) {

int					rc;
//hcf_16				p_bit;

		rc = cmd_wait( ifbp, HCMD_DISABLE | (port << 8 ), 0 );
		ifbp->IFB_CardStat &= (hcf_16)~CARD_STAT_ENABLED;
		(void)hcf_action( ifbp, HCF_ACT_INT_OFF );														/* 40 */
		ifbp->IFB_IntOffCnt--;
	return rc;
}/* hcf_disable */



/*******************************************************************************************************************


.MODULE			hcf_disconnect
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			NW4
.APPLICATION	Card Connection for WaveLAN based drivers and utilities
.DESCRIPTION
  Disable transmission and reception, release the IFB
.ARGUMENTS
  void hcf_disconnect( IFBP ifbp )
.RETURNS
  void

  MSF-accessible fields of Result Block:
  	IFB_CardStat	cleared

.NARRATIVE
  Parameters:
	ifbp		address of the Interface Block

  Description:
	Brings the NIC in quiescent state by calling hcf_initialize, thus preventing any interrupts in the future.

.DIAGRAM
 1:	hcf_initialize gives a justification to execute the Hermes Initialize command only when really needed.
 	Despite this basic philosophy and although the HCF can determine whether the NIC is initialized based
 	on IFB_CardStat, the minimal set of actions to initialize the Hermes is always done by calling
 	ini_hermes.
 5:	clear all IFB fields
 	The clearing of IFB_CardStat prevents I/O on any subsequent hcf_function

.ENDOC				END DOCUMENTATION
-------------------------------------------------------------------------------------------------------------*/
void hcf_disconnect( IFBP ifbp ) {

hcf_8 *q;


	ini_hermes( ifbp );

	for ( q = (hcf_8*)&ifbp[1]; q > (hcf_8*)ifbp; *--q = 0) /*NOP*/;									/* 5 */

}/* hcf_disconnect */





/*******************************************************************************************************************


.MODULE			hcf_enable
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
.DESCRIPTION    Enables data transmission and reception
.ARGUMENTS
  int hcf_enable( IFBP ifbp, hcf_16 port )
.RETURNS
	HCF_SUCCESS
	HCF_ERR_TIME_OUT (via cmd_wait)
	HCF_FAILURE (via cmd_wait)

  MSF-accessible fields of Result Block

  Condition Settings:
	Card Interrupts: Off if IFB_IntOffCnt > 0; On if IFB_IntOffCnt == 0
					 (Note that the value of IFB_IntOffCnt is unchanged)

.NARRATIVE
  Parameters:
  	ifbp	address of the Interface Block

  Description:

	hcf_enable takes successively the following actions:
 6:	If the requested port is disabled and if the NIC is present, the Hermes Enable command is executed.
	If CARD_STAT_PRESENT is off, the body of hcf_enable must be skipped to prevent I/O because the I/O space
	may no longer owned by the HCF, due to a card swap.
	The IFB_IntEnMask is set to allow Info events, Receive events and Allocate events to generate interrupts
	and effectuated if appropriate based on IFB_IntOffCnt by calling enable_int.
	Note that since the effect of interrupt enabling has no effect on IFB_IntOffCnt, this code may
	be called not only at the transition from disabled to enabled but whenever a port is enabled.
12:	When the port successfully changes from disabled to enabled - including the case when no NIC is
	present - , the NIC status as reflected by IFB_CardStat must change to enabled

.DIAGRAM

.NOTICE
  When the Hermes enable cmd is given, the static configuration of the Hermes is done.
.ENDOC				END DOCUMENTATION

-------------------------------------------------------------------------------------------------------------*/
int hcf_enable( IFBP ifbp, hcf_16 port ) {

int	rc;


	
	if ( (ifbp->IFB_CardStat & CARD_STAT_PRESENT) == 0 
	   ) { rc = HCF_ERR_NO_NIC;	}	/* 6 */
	else {
		rc = HCF_SUCCESS;
			rc = cmd_wait( ifbp, HCMD_ENABLE | ( port << 8 ), 0 );
			if ( rc == HCF_SUCCESS ) enable_int( ifbp, HREG_EV_INFO | HREG_EV_RX | HREG_EV_ALLOC );		/* 8 */
	}
	if ( rc == HCF_SUCCESS || rc == HCF_ERR_NO_NIC ) {
		ifbp->IFB_CardStat |= CARD_STAT_ENABLED;
	}
	return rc;

}/* hcf_enable */



/*******************************************************************************************************************


.MODULE			hcf_get_data
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
.DESCRIPTION
	Obtains received message data parts from NIC RAM
.ARGUMENTS
	int hcf_get_data( IFBP ifbp, int offset, wci_bufp bufp, int len )
	Card Interrupts disabled
.RETURNS
	hcf_16
		zero			NIC not removed during data copying process
		HCF_ERR_NO_NIC	NIC removed during data copying process
		......

  MSF-accessible fields of Result Block: -

.NARRATIVE
	parameters:
		ifbp		address of the Interface Block
		offset		offset (in bytes) in buffer in NIC RAM to start copy process
		len			length (in bytes) of data to be copied
		bufp		char pointer, address of buffer in PC RAM

	When hcf_service_nic reports the availability of data, hcf_get_data can be
	called to copy that data from NIC RAM to PC RAM.

	Hcf_get_data copies the number of bytes requested by the parameter len from
	NIC RAM to PC RAM. If len is larger than the (remaining) length of the
	message, undefined data is appended to the message. This implies that if
	hcf_get_data is called while the last hcf_service_nic reported no data
	available, undefined data is copied.

	Hcf_get_data starts the copy process at the offset requested by the
	parameter offset, e.g. offset HFS_ADDR_DEST will start copying from the
	Destination Address, the very begin of the 802.3 framemessage.
	In case of a fragmented PC RAM buffer, it is the responsibility of the MSF,
	to specify as offset the cumulative values of the len parameters of the
	preceeding hcf_get_data calls. This I/F gives a MSF the facility to read
	(part of) a message and then read it again.
	
.DIAGRAM
.ENDOC				END DOCUMENTATION


-------------------------------------------------------------------------------------------------------------*/
int hcf_get_data( IFBP ifbp, int offset, wci_bufp bufp, int len ) {

int rc = HCF_SUCCESS;
//int	tlen;


	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {	
		if ( offset < 0 ) offset -= HFS_STAT;
		else {
			offset += ifbp->IFB_FSBase;
	    }
		if ( rc == HCF_SUCCESS ) rc = hcfio_string( ifbp, BAP_1, ifbp->IFB_RxFID, offset, bufp, 0, len, IO_IN );
	}
	return rc;
}/* hcf_get_data */




/**************************************************************************************************************


 Name:	hcf_get_info

 Summary: Obtains transient and persistent configuration information from the
	Card and from the HCF

 Parameters:
  ifbp	address of the Interface Block

  ltvp	address of LengthTypeValue structure specifying the "what" and the "how much" of the information
  		to be collected from the HCF or from the Hermes

 Returns:
	int
		..... ????????????????	

 Remarks: Transfers operation information and transient and persistent
 	configuration information from the Card and from the HCF to the MSF.
	The exact layout of the provided data structure
	depends on the action code. Copying stops if either the complete
	Configuration Information is copied or if the number of bytes indicated
	by len is copied.  Len acts as a safe guard against Configuration
	Information blocks which have different sizes for different Hermes
	versions, e.g. when later versions support more tallies than earlier
	versions. It is a consious decision that unused parts of the PC RAM buffer are not cleared.

 Remarks: The only error against which is protected is the "Read error"
	as result of Card removal. Only the last hcf_io_string need
	to be protected because if the first fails the second will fail
	as well. Checking for cmd_wait errors is supposed superfluous because
	problems in cmd_wait are already caught or will be caught by
	hcf_enable.
	
	
 3:	tallying of "No inquire space" is done by cmd_wait

 Note:
	the codes for type are "cleverly" chosen to be identical to the RID
	

 7:	The return status of cmd_wait and the first hcfio_in_string can be ignored, because when one fails, the
 	other fails via the IFB_TimStat mechanism
		
**************************************************************************************************************/
int hcf_get_info(IFBP ifbp, LTVP ltvp ) {

int				rc = HCF_ERR_LEN;
//hcf_io			reg;
hcf_16			i, len;
hcf_16			type;						//don't change type to unsigned cause of "is it a RID" test
hcf_16 			*q;							//source pointer (Tally-part of IFB)
//hcf_16 FAR 		*bq;						//source pointer (Identity or Range records)	;?why bq and not e.g. wq
wci_recordp		p = ltvp->val;				//destination word pointer (in LTV record)
//wci_bufp		cp = (wci_bufp)ltvp->val;	//destination char pointer (in LTV record)

	
	len = ltvp->len;
	type = ltvp->typ;
	
	if ( len > 1 ) {
	
		rc = HCF_SUCCESS;
		switch ( type ) {
			
#if MSF_COMPONENT_ID != COMP_ID_AP1
		  case CFG_TALLIES:																				/* 3 */
			ltvp->len = len = _min( len, (hcf_16)(HCF_TOT_TAL_CNT + HCF_TOT_TAL_CNT + 1) );
			q = (hcf_16*)/*(wci_recordp)*/&ifbp->IFB_NIC_Tallies; //.TxUnicastFrames;
			while ( --len ) *p++ = *q++;
			(void)hcf_action( ifbp, HCF_ACT_TALLIES );
			break;
#endif //COMP_ID_AP1

			

			
			
		  default:
			rc = HCF_ERR_NO_NIC;
			if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
				rc = HCF_ERR_TIME_OUT;			
				  	if ( type < CFG_RID_CFG_MIN ) {
				  		ltvp->len = 0;
				  	} else {
						(void)cmd_wait( ifbp, HCMD_ACCESS, type );											/* 7 */
						(void)hcfio_string( ifbp, BAP_1, type, 0, (wci_bufp)&i, 1, sizeof(hcf_16), IO_IN );
						ltvp->len = _min( i, len );
						rc = hcfio_string( ifbp, BAP_1, type, sizeof(hcf_16), (wci_bufp)&ltvp->typ, 1, MUL_BY_2(ltvp->len), IO_IN );
						if ( rc == HCF_SUCCESS && i > len ) rc = HCF_ERR_LEN;
					}
			}
		}
	}
	return rc;

}/* hcf_get_info */


/*******************************************************************************************************************

.MODULE			hcf_initialize  ;?in fact an hcf-support routine, given an hcf_... name just in case we want to
								  export it over the WCI later
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
.DESCRIPTION    ..........., in addition, a light-weight diagnostic test of the NIC
.ARGUMENTS
  int hcf_initialize( IFBP ifbp )

.RETURNS
	HCF_SUCCESS
	HCF_ERR_NO_NIC
	HCF_ERR_TIME_OUT;
	HCF_FAILURE (via cmd_wait)
				(via hcf_get_info)
	HCF_ERR_INCOMP_PRI
	HCF_ERR_INCOMP_STA	
	
  MSF-accessible fields of Result Block:
   	IFB_DUIFRscInd, IFB_NotifyRscInd, IFB_PIFRscInd cleared
   	IFB_MBInfoLen, IFB_RxLen, IFB_RxStat cleared
   	IFB_CardStat  -	CARD_STAT_ENA_0	through CARD_STAT_ENA_6
				  -	CARD_STAT_INCOMP_PRI
				  -	CARD_STAT_INCOMP_STA
   	

.NARRATIVE

  Parameters:
	ifbp		address of the Interface Block

  hcf_initialize will successively:
  -	initialize the NIC by calling ini_hermes
  -	calibrate the S/W protection timer against the Hermes Timer by calling calibrate

  Condition Settings:
	Card Interrupts: Disabled  (Note that the value of IFB_IntOffCnt is unchanged)

  Remarks: since hcf_initialize is the first step in the initialization of the card and since the strategy is to
   detect problems as a side effect of "necessary" actions, hcf_initialize has, in deviation of the general
   strategy, an additional "wait for busy bit drop" at all places where Hermes commands are executed. An
   additional complication is that no calibrated value for the protection count can be assumed since it is
   part of the first execution of hcf_disable to determine this calibrated value (a catch 22). The initial
   value (set at INI_TICK_INI by hcf_connect) of the protection count is considered safe, because:
   o the HCF does not use the pipeline mechanism of Hermes commands.
   o the likelihood of failure (the only time when protection count is relevant) is small.
   o the time will be sufficiently large on a fast machine (busy bit drops on good NIC before counter expires)
   o the time will be sufficiently small on a slow machine (counter expires on bad NIC before the enduser
     switches the power off in despair
	IFB_TickIni is used in cmd_wait to protect the Initialize command. The time needed to wrap a 32 bit counter
	around is longer than many humans want to wait, hence the more or less arbitrary value of 0x10000L is
	chosen, assuming it does not take too long on an XT and is not too short on a scream-machine.
	Once we passed the CARD_STAT_PRESENT test on IFB_CardStat, the other bits can be reset. This is needed
	to have a dynamical adjustment of the Station/Primary Incompatibility flags.
	Especially IFB_TimStat must be cleared (new round, new chances)

 Remarks: First the HCF disables the generation of card interrupts. Next it waits for the Busy bit in the
   Command register to drop (the additional safety required for hcf_initialize as described above). If the Hermes
   passes this superficial health test, the Hermes Initialize command is executed. The Initialize command acts
   as the "best possible" reset under HCF control. A more "severe/reliable" reset is under MSF control via the
   COR register.

 Remarks: If the Initialize of the Hermes succeeds, the S/W protection counter is calibrated if not already
   calibrated. This calibration is "reasonably" accurate because the Hermes is in a quiet state as a result of
   the Initialize command. The hcf_put_info function is used to program the Hermes Tick for its minimum
   interval (1024 microseconds). Programming the Tick interval terminates the old interval timing immediately
   and starts the new interval. Due to this ad-hoc switch the first interval has a larger inaccuracy. By
   timing immediately a second interval the accuracy improves due to the synchronization of HCF and Hermes.
   After this second interval, the Hermes Tick is programmed for its default value of 1 second again.

.NARRATIVE
 2:	Clear all fields of the IFB except those which need to survive hcf_initialize. This is intended to make
 	the behavior and - as a consequence - the debugging of the HCF more reproduceable.

 3:	Disable the interrupt generation facility (see also #30)
 5: Depending on whether there is selective disabling of a single port or a collective disabling of
	all ports a specific bit or all bits representing the enabled ports are reset. In case of "all ports"
	none of the other bits except CARD_STAT_ENABLED is relevant, so as an easy implementation all those
	other bits are cleared.
	The individual bits conveyed in IFB_CardStat are historically grown. To leave the WCI unchanged, the
	individual "port enabled" bits are scattered through IFB_CardStat. As a consequence there is some bit
	arithmetic involved to convert a port number to a bit flag
	The masking of port with HCF_PORT_MASK is a cheap safeguard against I/F violations by the MSF. If the MSF
	supplies an invalid bit pattern, unwanted bits may end up in Hermes Command register via Disable command
	with unpredictable effects.
 7: Check whether CARD_STAT_PRESENT bit of IFB_CardStat is on. If not the remainder of hcf_initialize must be
	skipped to prevent I/O because the I/O space may no longer owned by the HCF, due to a card swap.
12:	When a single port must be disabled AND it is not the only enabled port, that port is selectively
	disabled. If all ports or the only enabled port is to be disabled, the disabling is skipped and the
	Hermes Initiate command is supposed to take care of it all.
16: perform a superficial Hermes health test. Note that in hcf_initialize all (or at least most) activities are
	checked for conditions like "Busy bit should drop". If such a condition is not met in time, hcf_initialize
	returns an error code. Hcf_functions which are only called during "normal" operations may ignore such
	events. Their only obligation is to prevent that the code hangs.
	Note that early models of the Hermes needed some arbitrary read before the first write activity to operate
	stable (ref tracker 27). This code achieves that function as a side effect.
18:	Initialize the Hermes. The results of this way of initialization depends on the capabilities of the Hermes
  	firmware. Therefore, the Hermes H/W controlled bits, like those in the evitable register are not guaranteed
  	to be cleared as result of the initialize command. However it is guaranteed that no more events are in the
    pipeline. Ack-ing indiscriminately all events resolves this problem. An alternative would be to use the
    resulting value of "IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT )" rather than 0xFFFF to specifically
    only reset those events which are set. This strategy is considered to be only more aesthetically pleasing
    (if that).
20:	Perform some housekeeping tasks
  - Write HCF_MAGIC as signature to S/W support register 0.  This signature is used to detect card removal
	wherever the presence of the card is critical while HCF may not yet have been informed by the MSF of the
	removal of the card.  Note that this task can not be postponed because that would cause the hcfio_in_string
	called by hcf_get_info to fail
22:

	  -	IFB_TickIni	must be initialized (at INI_TICK_INI) to prevent that actions like hcf_put_info immediately
	    after hcf_connect (that is without intervening hcf_disable) at an absent (or failing) NIC take too
	    long.  Note that this is a legal hcf-sequence according to the WCI-specification.




	IFB_TickIni is the value used to initialize the S/W protection counter in a way which makes the
	expiration period more or less independent of the processor speed. If IFB_TickIni is not yet calibrated,
	it is done now.
	First off all the Hermes Tick period is programmed for a "reasonable" interval, currently 8092 or 8k
	microseconds, by means of hcf_put_info. Note that IFB_DLTarget, which is guaranteed to get the correct
	value later on in hcf_enable, is misused as re-entrant storage for the RID used to program the Tick period.
	The HCF synchronizes itself with the Hermes timer by waiting for the first timer tick. This synchronizing is done by
	ack-ing the Tick regardless of its current value. This guarantees Tick becomes low. Then Tick is sampled
	till it is high, which guarantees a new complete interval starts in the Hermes. Tick is acked again and
	another Tick is awaited. This period is as accurate as we can get.
	To diminish the chance that in a pre-emptive environment IFB_TickIni is calibrated too low because the HCF
	just happens to loose control during this calibration, the calibration is performed 10 times and the
	largest value is used.
	IFB_TickIni is then set at approximately 1 second by multiplying that largest value by 128. The 8k
	microseconds interval and the multiplication by 128 are chosen as a compromise between accuracy of
	the calibration. time consumed by the calibration and possibilities for the compiler to optimize
	the arithmetic.
26:	Finally the Hermes Tick period is programmed for a "reasonable" runtime interval, currently 1 second
	(1,000,000/1,024 kilo-microseconds), by means of hcf_put_info (again the available CONCATENATED storage
	is misused)
	Note that in case of failure, IFB_TickIni ends up as INI_TICK_INI, which is a supposedly acceptable
	value to handle the rare case of a broken card.
30: The Supplier Range of the Primary Firmware function is retrieved from the Hermes and checked against
	the Top and Bottom level supported by this HCF.
	If the primary firmware does not supply this RID or supplies the "old" HardwareStructure Info, the
	Primary Compatibility check is skipped. These conditions are recognized based on the length field supplied
	by the Hermes. ;?is this wise in the post-GCA area
32: In case of a HCF compiled for station functionality, the Supplier Range of the Station Firmware function
	is retrieved from the Hermes and checked against the Top and Bottom level supported by this HCF.
	Note that the Firmware can have multiple Variants, but that the HCF currently only supports a single
	variant.
40:	Perform some more housekeeping tasks
  -	Decrement ifbp->IFB_IntOffCnt to compensate side effect of ACT_INT_OFF action at begin of hcf_initialize (see
	#2). This can not be handled by calling hcf_action with HCF_ACT_ON, because this could as undesirable
	side effect actually enable interrupts
	
.NOTICE
 o  For all practical WCI purposes there is no practical difference between a Hermes disable command at all
	individual ports and an hermes initialize command
 o  hcf_initialize disables the card interrupts, however it does NOT influence IFB_IntOffCnt.
	This way it is symmetrical with hcf_enable, which does NOT enable the card interrupts.	


   	IFB_CardStat  -	CARD_STAT_INCOMP_PRI
				  -	CARD_STAT_INCOMP_STA
   	
 5:	The house keeping is done, consisting of the steps:
	- allocate a Tx Frame Structure for the protocol stack
	- allocate a Tx Frame Structure for the utility
	- allocate a Information Frame Structure for the Notify command
	Note that a subsequent allocate is only performed if the preceding one
	succeeded
	- if all allocates succeeded, the Resource Indicators corresponding
	  with the Tx Frames are set


**************************************************************************************************************/
int hcf_initialize( IFBP ifbp ) {

int		rc;
//hcf_16	*p;
hcf_8	*q;


	for ( q = (hcf_8*)&ifbp->IFB_PIFRscInd; q < (hcf_8*)&ifbp[1]; *q++ = 0) /*NOP*/;					/* 2 */

//	if ( (ifbp->IFB_CardStat & CARD_STAT_INI) == 0 ) {				//present but not initialized	/* 7 */
	do { //;?CARD_STAT_PRESENT check superfluous as long as hcf_initialize is not defined on the WCI
		rc = ini_hermes( ifbp );
		if ( rc != HCF_SUCCESS ) break;																/* 32*/
		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0, HCF_MAGIC );									/* 20*/
		rc = calibrate( ifbp );   																	/* 22*/
		if ( rc != HCF_SUCCESS ) break;

#if defined MSF_COMPONENT_ID  //;?interesting question at which level HCFL interacts		
#endif // MSF_COMPONENT_ID
        ifbp->IFB_CardStat |= CARD_STAT_INI;	//consider this as sufficient to reach CARD_STAT_INI?	/* 24*/
		if ( rc != HCF_SUCCESS ) break;   //;? apparently this still should follow the moved IFB_DLTarget logic but
											//;? think this over for the different scenarios
		if ( ( ifbp->IFB_PIF_FID    = alloc( ifbp, HFS_TX_ALLOC_SIZE )  ) == 0		||				/* 5 */
			 ( ifbp->IFB_DUIF_FID   = alloc( ifbp, HFS_TX_ALLOC_SIZE )  ) == 0  ) {
			rc = HCF_FAILURE;
		} else {
			ifbp->IFB_PIFRscInd = ifbp->IFB_DUIFRscInd = 1;

		}
	} while ( 0 ); //pseudo goto-less, accept "warning: conditional expression is constant"

	return rc;
}/* hcf_initialize */


/*******************************************************************************************************************


.MODULE			hcf_put_data
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
.ARGUMENTS
	void hcf_put_data( IFBP ifbp, wci_bufp bufp, int len, hcf_16 port )
	Card Interrupts disabled

.RETURNS
	void

  MSF-accessible fields of Result Block: -

.DESCRIPTION	Transfers (part of) transmit message to the NIC and handles
	the Ethernet-II encapsulation if applicable
.NARRATIVE
	parameters:
		ifbp		address of the Interface Block
		bufp		char pointer, address of buffer in PC RAM
		len			length (in bytes) of data to be copied
		port		HCF_PORT_0 - HCF_PORT_6 .........;?
					HCF_PUT_DATA_RESET


	Refer to hcf_service;?non-existing reference, for a concise description about possible
	relation/sequencing of hcf_put_data in the Interrupt Service Routine
	
	In essence, hcf_put_data copies the number of bytes specified by parameter len from the location in PC
	RAM specified by bufp to the NIC RAM buffer associated with the Protocol Stack dedicated FID.
	The first call succeeding hcf_send (or hcf_enable), writes the first byte at offset HFS_ADDR_DEST in
	the transmit data buffer, successive hcf_put_data calls continue where the preceeding hcf_put_data stopped.
	
	IFB_FrameType determines whether the message in the PC RAM buffer is interpreted as an 802.3 or 802.11
	frame.  This influences:
 	o the position where the first byte of the initial hcf_put_data is stored
 	o Only in case of the 802.3 frame type, hcf_put_data checks whether the frame is an Ethernet-II rather
 	  than an "official" 802.3 frame. The E-II check is based on the length/type field in the MAC header. If
 	  this field has a value larger than 1500, E-II is assumed. The implementation of this test fails if the
	  length/type field is split over 2 hcf_put_data calls.
	  If E-II is recognized, the length field HFS_LEN_ABS is skipped for the time being and a SNAP header is
	  inserted starting at HFS_DAT_ABS. This SNAP header represents either RFC1042 or Bridge-Tunnel
	  encapsulation, depending on whether the type is absent or present in enc_trans_tbl.
 	o In case of the 802.11 frame type, hcf_put_data checks whether the complete header + length field is
 	  written (note that part of the header may be written by previous hcf_put_data calls and part may be
 	  written by this call).  If so, the next byte is written at HFS_DAT_ABS (the 802.3 header area is skipped)

	It is allowed to write the 802.3 header, 802.11 header and/or data in fragments, e.g. the first
	hcf_put_data call writes 18 bytes starting at location HFS_ADDR_1_ABS and the second call writes 6 more
	bytes starting at location HFS_ADDR_4. Although Address part #4 is not present in some 802.11 headers,
	all 4 addressing parts and the length field must be written in case of 802.11. Once the complete header
	is written, the data part is written starting from offset HFS_DAT_ABS.

	Hcf_put_data does not check for transmit buffer overflow because the Hermes does this protection.
	In case of a transmit buffer overflow, the surplus which does not fit in the buffer is simply dropped.
	Note that this possibly results in the transmission of incomplete frames.

.DIAGRAM
1*: If the card is not present, prevent all I/O because "our" I/O base may have been given away to someone
	else in a CS/SS environment.  Also no I/O should be performed if the NIC is not enabled. However
	an MSF which calls hcf_put_data while the NIC is not enabled probably contains a logic flaw (or has a
	strategy which was not foreseen at the time this was written)
10* HCF_PUT_DATA_RESET discards all the data put by preceeding hcf_put_data calls and resets the HCF
	housekeeping just the same as after an hcf_send triggered allocate event.
	Note: To make the WCI fail-safe, invalid port numbers are silently rejected by treating them as 
	HCF_PUT_DATA_RESET. Note that the assumption is that this should never ever occure in a debugged MSF and 
	that during debugging the ASSERT is sufficient support to help the MSF programmer.
2*:	This statement is only true at the first hcf_put_data call after an hcf_send result or hcf_enable
	The housekeeping is done.
 	o the PIFRscInd is cleared, so the MSF can not begin another hcf_put_data/hcf_send sequence
	before completing the current one
 	o the Tx Encoding flag (TxFrameType) is cleared
 	o the index to the first free position in the FID (IFB_PIFLoadIdx) is initialized based on IFB_FSBase.
 	  IFB_FSBase is initialized when hcf_action is called with HCF_ACT_802_3 or HCF_ACT_802_11
3*:	Pay Attention: it may seem attractive to change this code, e.g. to save the superfluous call to
	hcfio_out_string when the Destination and Source address are written by the preceeding call and the
	current call starts at the length/type field. However this code is "reasonably carefully" crafted
	to take in account all boundary conditions. It is very easy to make a change which does not work under
	all feasible split ups of the message in fragments.
	First IFB_PIFLoadIdx is checked.
	  - If IFB_PIFLoadIdx points past HFS_LEN_ABS, the preceeding call(s) to hcf_put_data already passed the
	  length/type field. As a consequence the fragment can be concatenated to the data already copied to
	  NIC RAM.
	  - If IFB_PIFLoadIdx does not point past HFS_LEN_ABS, the current fragment may or may not contain part of
	  the Destination and/or Source Address and it may or may not contain the length/type field.
	  If the fragment contains addressing information or -in case of 802.11- length info , this information
	  is copied/concatenated to the NIC RAM buffer. The working variables (pointer and length of fragment) as
	  well as the IFB_PIFLoadIdx are adjusted.
	The semi-obscure differences in the boundary testing are caused by:
	  o 802.11: the "below the boundary" area is Addr1, Addr2, Addr3, Ctrl, Adrr4 + DataLen and the "above"
	  	area is the "real" data
	  o 802.3: the "below the boundary" area is DestAddr + SrcAddr and the "above" area is the length +
	  	"real" data
	  o E-II: the "below the boundary" area is DestAddr + SrcAddr, then there is a "virtual" area with the
	  	SNAP header (which will in the end include the HCF calculated length)  and the "above" area is the
	  	"protocol stack length" (is in reality the type code) + "real" data
4*:	If there is still data left, IFB_PIFLoadIdx may need adjustment (802.11 and E-II encapsulation).  Again
	note that this length check is crucial to prevent mis-manipulation of IFB_PIFLoadIdx in case the header
	is written in multiple fragments.
	In case of 802.3, the E-II check is done. In case of E-II, the encapsulation type (RFC1042 versus
	Bridge-Tunnel) is determined and the corresponding SNAP header is written to NIC RAM and
	IFB_PIFLoadIdx is adjusted.
6*:	All data which is not already copied under 3*, is copied here.
	In case of 802.11, the HFS_DAT field is the first field written by this code.
	In case of 802.3, the HFS_LEN field is the first field written by this code.
	In case of E-II encapsulation, the HFS_TYPE field is the first field written by this code.
	Note that in case of E-II encapsulation, the HFS_LEN field is not written by hcf_put_data at all, but by
	hcf_send because the data length is not	known till all fragments have been processed.
	
.NOTE	
	The possible split of a single hcf_put_data call into 2 calls to hcfio_out_string results in 2 calls
	to bap_ini, which may be unexpected while you are debugging, but is never the less the intended behavior.
	Along the same line a call of hcfio_out_string with a value of 0 for parameter len may be unexpected, e.g.
	when the len parameter of hcf_put_data is either 1 or 2, the latter depending on the odd/even aspects of
	IFB_PIFLoadIdx.	
	
	
	
.NOTE
	The test on PIFRscInd to distinguish the initial hcf_put_data from subsequent calls is not thread safe.
	It is assumed that threaded MSFs have their own mechanism to assure that hcf_put_data calls belonging to
	a single frame are atomic with respect to each other. It is also assumed that the MSF takes care that
	the hcf_put_data calls of multiple frames do not run concurrent
	
	
.ENDOC				END DOCUMENTATION


-------------------------------------------------------------------------------------------------------------*/
void hcf_put_data( IFBP ifbp, wci_bufp bufp, int len, hcf_16 port ) {

int		idx;				//working index into Tx Frame structure, presume MSF control
//int		tlen;				//working type/length of frame, working length for partial copy of frame
	

	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {															/* 1 */
			if ( ifbp->IFB_PIFRscInd ) {																	/* 2 */
				ifbp->IFB_PIFRscInd = 0;
				ifbp->IFB_PIFLoadIdx = ifbp->IFB_FSBase;    //;?<HCF_L> should result in 0
			}
			
			idx = ifbp->IFB_PIFLoadIdx;
			ifbp->IFB_PIFLoadIdx += (hcf_16)len;
			(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, idx, bufp, 0, len, IO_OUT);		/* 6 */
	}
	return;
}/* hcf_put_data */


/**************************************************************************************************************


 Name:	hcf_put_info

 Summary: Transfers operation information and transient and persistent
 	configuration information to the Card.

 Parameters:
  ifbp	address of the Interface Block

  type	specifies the RID (as defined by Hermes I/F)

  bufp	address in NIC RAM where record data is located

   len	length of data (in bytes)

.NARRATIVE

 Remarks:
	CFG_NOTIFY: only runs after hcf_enable

 Remarks: Configuration information is copied from the provided data
	structure into the Card. The exact layout of the provided data
	structure depends on the action code. Also the mechanism used to copy
	the data to the card depends on the action code. In order to make the
	changes which are based on the Access command (see support routine put_info)
	sustain over activities like hcf_diagnose and recovery from PCMCIA card
	insertion, the data associated with these particular action codes, is
	saved in the IF-block. The codes for this type are "cleverly" chosen to
	be identical to the RID.
	
	bufp is defined as a pointer to items of type hcf_16 because of the
	correlation with the Hermes definition
	
	
.DIAGRAM

.NOTICE
	Future enhancements in the functionality offered by the WCI and/or implementation aspects of the HCF
	may warrant filtering on the type-field of the LTV to recognize non-MSF accessible records, e.g. CFG_TICK
	
**************************************************************************************************************/

int hcf_put_info( IFBP ifbp,
				  LTVP ltvp		/*number identifying the type of change
<PRE>
									CFG_INFO_FRAME_MIN	lowest value representing an Information Frame
									CFG_NOTIFY			Handover Address
										
									CFG_TALLIES			Communications Tallies
									CFG_SCAN			Scan results
										                        	
									CFG_LINK_STAT 		Link Status
									CFG_ASSOC_STAT		Association Status
								
</PRE>							*/
			    ) {

//int			cnt = 3;
//hcf_16		i = ltvp->len - 1;
int			rc = HCF_SUCCESS;

	
	if ( CFG_RID_CFG_MIN <= ltvp->typ && ltvp->typ <= CFG_RID_CFG_MAX ) {
      	//all codes between 0xFC00 and 0xFCFF are passed to Hermes)
//		if ( ( ifbp->IFB_CardStat & CARD_STAT_PRI_STA_PRES ) == CARD_STAT_PRESENT ) {
//			do {
//				rc = hcfio_string( ifbp, BAP_1,
//								   ltvp->typ, 0, (wci_bufp)ltvp, 2, MUL_BY_2(ltvp->len + 1), IO_OUT_CHECK );
//			} while ( cnt-- && rc != HCF_SUCCESS );
//			if ( rc == HCF_SUCCESS ) rc = cmd_wait( ifbp, HCMD_ACCESS + HCMD_ACCESS_WRITE, ltvp->typ );
//			if ( rc == HCF_SUCCESS ) rc = put_info( ifbp, ltvp );

		rc = put_info( ifbp, ltvp );
//		}
	}	
	return rc;
}/* hcf_put_info */





/******************************************************************************************************************

.MODULE			hcf_send
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
.DESCRIPTION	Transmit a message on behalf of the protocol stack
.ARGUMENTS
	void hcf_send( IFBP ifbp , hcf_send_type type )
	Card Interrupts disabled

.RETURNS
	void

  MSF-accessible fields of Result Block: -

.NARRATIVE
	Hcf_send transmits the Protocol Stack message loaded in NIC RAM by the
	preceeding hcf_put_data calls.

.DIAGRAM
1:	The actual data length (the number of bytes in the Tx Frame structure
	following the 802.3/802.11 Header Info blocks, is determined by
	IFB_PIFLoadIdx, the index in the Transmit Frame Structure to store the
	"next" byte. Note that this value must be compensated for the header info
	by subtracting HFS_DAT.
2/3:TxFrameType - which is based on the preceding hcf_put_data calls - defines
	whether the actual data length is written to the 802.11 or 802.3 Header Info
	block.
2:	In case of 802.11, the entry parameter type is augmented to reflect	802.11
	before it is written to the Control Field block.
3:	In case of 802.3, the actual length must be converted from the native
	format of the Host (Little Endian in case of an 80x86) to Big Endian before
	it is written to the 802.3 Header Info block.
4:	The actual send+reclaim command is performed by the routine send.
7:	The return status of hcfio_in_string can be ignored, because when it fails, cmd_wait will fail via the
 	IFB_TimStat mechanism
.NOTICE
  ;?This comment is definitely out of date
  The choice to let hcf_send calculate the actual data length as
  IFB_PIFLoadIdx - HFS_DAT, implies that hcf_put_data with the HFS_LUCENT
  mechanism MUST be used to write the Data Info Block. A change in this I/F
  will impact hcf_send as well.
  An alternative would be to have a parameter datlen. If datlen is zero, the
  current behavior is used. If datlen has a non-zero value, its value is used
  as the actual data length (without validating against HCF_MAX_MSG and without
  validating the total number of bytes put by hcf_put_data).

.NOTICE
  hcf_put_data/send leave the responsibility to only send messages on enabled ports at the MSF level.
  This is considered the strategy which is sufficiently adequate for all "robust" MSFs, have the least
  processor utilization and being still acceptable robust at the WCI !!!!!
.ENDOC				END DOCUMENTATION

------------------------------------------------------------------------------------------------------------*/
int hcf_send( IFBP ifbp , hcf_16 port ) {	//;?note that port is unused due to ambivalence about what the "right" I/F is

int	rc = HCF_SUCCESS;


	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {												/* 1 */	
		/* H/W Pointer problem detection */	
		if ( ifbp->IFB_BAP_0[0] != ifbp->IFB_FSBase ) {	//;?<HCF _L> should BE HARD CODED, also add to send diag msg	/* 30*/
			rc = hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, ifbp->IFB_PIFLoadIdx, NULL, 0, 0, IO_OUT_CHECK );
			
			if ( rc == HCF_FAILURE ) {
				ifbp->IFB_PIFRscInd = 1;
			}
		}
		if ( rc == HCF_SUCCESS ) {
			if ( /*ifbp->IFB_FrameType == ENC_802_11 || */ ifbp->IFB_TxFrameType == ENC_TX_E_II ) {		/* 2 */
				ifbp->IFB_PIFLoadIdx -= HFS_DAT_ABS;		//actual length of frame					/* 1 */
				CNV_INT_TO_BIG_NP(&ifbp->IFB_PIFLoadIdx);  //;?is it worthwhile to have this additional macro
				(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, HFS_LEN_ABS,
										(wci_bufp)&ifbp->IFB_PIFLoadIdx, 0, 2, IO_OUT );			/* 7 */
			}
//			send( ifbp, ifbp->IFB_PIF_FID, port | ifbp->IFB_FrameType );								/* 4 */
			(void)cmd_wait( ifbp, HCMD_TX + HCMD_RECL, ifbp->IFB_PIF_FID );			//justify "void"
		}
		/* reset the BAP pointer for the Tx Framestructure, note that we access the BAP not the NIC RAM
		 * after we relinguished control of the Tx FID to the Hermes
		 */
		(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, ifbp->IFB_FSBase, NULL, 0, 0, IO_IN );
	}
	return rc;
} /* hcf_send */



/*******************************************************************************************************************

.MODULE			hcf_send_diag_msg
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
.DESCRIPTION	Transmit a message on behalf of the Driver-Utility I/F
.ARGUMENTS
	void hcf_send_diag_msg( IFBP ifbp, wci_bufp bufp, hcf_16 len )
	Card Interrupts disabled

.RETURNS
	void

  MSF-accessible fields of Result Block: -

.NARRATIVE
	Hcf_send_diag_msg transmits the message
.DIAGRAM

 2:

 4: Based on the assumption that hcf_send_diag_msg is called at a low frequency, HFS_TX_CNTL_ABS is written
  	on each call rather than using an IFB-field to remember the previous value and update only if needed


.ENDOC				END DOCUMENTATION

-------------------------------------------------------------------------------------------------------------*/
int hcf_send_diag_msg( IFBP ifbp, hcf_16 type, wci_bufp bufp, int len ) {

int rc = HCF_SUCCESS;


	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
		rc = HCF_ERR_BUSY; //;?more appropriate value needed
		if ( ifbp->IFB_DUIFRscInd ) {																	/* 2 */
			rc = hcfio_string( ifbp, BAP_0, ifbp->IFB_DUIF_FID, HFS_ADDR_DEST_ABS, bufp, 0, len, IO_OUT_CHECK );
			if ( rc == HCF_SUCCESS ) {
				ifbp->IFB_DUIFRscInd = 0;
				(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, HFS_TX_CNTL_ABS, 		//justify void
								  (wci_bufp)&type, 1, 2, IO_OUT );								/* 4 */
				(void)cmd_wait( ifbp, HCMD_TX + HCMD_RECL, ifbp->IFB_DUIF_FID );			
			}
		}
	}
	return rc;
} /* hcf_send_diag_msg */





/*******************************************************************************************************************


.MODULE			hcf_service_nic
.LIBRARY 		HCF
.TYPE 			function
.SYSTEM			msdos
.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
.DESCRIPTION	Provides received message and link status information
.ARGUMENTS
	int	hcf_service_nic(IFBP ifbp )
	Card Interrupts disabled

.RETURNS
	int
		all the bits of the Hermes evitable register, which are encountered during execution of hcf_service_nic
		the "pseudo"-events HREG_EV_NO_CARD, HREG_EV_DUIF_RX
	MSF-accessible fields of Result Block
		IFB_RxLen			0 or Frame size as reported by LAN Controller
		IFB_RxStat
		IFB_MBInfoLen
		IFB_PIFRscInd
		IFB_DUIFRscInd
		IFB_NotifyRscInd
		IFB_HCF_Tallies


.NARRATIVE
	hcf_service_nic is primarily intended to be part of the Interrupt Service Routine.
	hcf_service_nic is presumed to neither interrupt other HCF-tasks nor to be interrupted by other HCF-tasks.
	A way to achieve this is to precede hcf_service_nic as well as all other HCF-tasks with a call to
	hcf_action to disable the card interrupts and, after all work is completed, with a call to hcf_action to
	restore (which is not necessarily the same as enabling) the card interrupts.
	In case of a polled environment, it is assumed that the MSF programmer is sufficiently familiar with the
	specific requirements of that environment to translate the interrupt strategy to a polled strategy.
	
	hcf_service_nic services the following Hermes events:
		HREG_EV_INFO		Asynchronous Information Frame
		HREG_EV_INFO_DROP	WMAC did not have sufficient RAM to build Unsolicited Information Frame
		HREG_EV_ALLOC		Asynchronous part of Allocation/Reclaim completed
		HREG_EV_RX			the detection of the availability of received messages

	If a message is available, its length is reflected by the IFB_RxLen field of the IFB. This length
	reflects the 802.3 message length (i.e. the data itself but not the Destination Address, Source Address,
	DataLength field nor the SAP-header in case of decapsulation by the HCF).
	If no message is available, IFB_RxLen is zero.

  **Buffer free strategy
	When hcf_service_nic reports the availability of a message, the MSF can access that message or parts
	thereof, by means of hcf_get_data calls till the next call of hcf_service_nic. Therefore it must be
	prevented that the LAN Controller writes new data in the buffer associated with the last hcf_service_nic
	report.
	As a consequence hcf_service_nic is the only procedure which can free receive buffers for re-use by the
	LAN Controller. Freeing a buffer is done implicitly by acknowledging the Rx event to the Hermes. The
	strategy of hcf_service_nic is to free the buffer it has reported as containing an available message in
	the preceeding call (assuming there was an available message).
	A consequence of this strategy is that the Interrupt Service Routine of the MSF must repeatedly call
	hcf_service_nic till hcf_service_nic returns "no message available". It can be reasoned that
	hcf_action( INT_ON ) should not be given before the MSF has completely processed a reported Rx-frame. The
	reason is that the INT_ON action is guaranteed to cause a (Rx-)interrupt (the MSF is processing a
	Rx-frame, hence the Rx-event bit in the Hermes register must be active). This interrupt will cause
	hcf_service_nic to be called, which will cause the ack-ing of the "last" Rx-event to the Hermes,
	causing the Hermes to discard the associated NIC RAM buffer.


.DIAGRAM
 2: IFB_RxLen and IFB_RxStat must be cleared before the NIC presence check otherwise these values may stay
 	non-zero if the NIC is pulled out at an inconvenient moment
 4: If the card is not present, prevent all I/O because "our" I/O base may have been given away to someone
	else in a CS/SS environment.
	The MSF may have considerable latency in informing the HCF of the card removal by means of an hcf_disable.
	To prevent that hcf_service_nic reports bogus information to the MSF with all - possibly difficult to
	debug - undesirable side effects, hcf_service_nic pays performance wise the prize to use the momentanuous
	NIC presence test by checking the contents of the Hermes register HREG_SW_0 against the value HCF_MAGIC.
 6:	The return status of hcf_service_nic is defined as reflecting all interrupt causes this call has run into,
 	hence an accumulator is needed. This return status services ONLY to help the MSF programmer to debug the
 	total system.
 	When the card is removed, the pseudo event HREG_EV_NO_CARD is reported.
 	NOTE, the HREG_EV_NO_CARD bit is explicitly not intended for the MSF to detect NIC removal. The MSF must
 	use its own - environment specific - means for that.
10:	ack the "old" Rx-event. See "Buffer free strategy" above for more explanation.
    IFB_RxFID, IFB_RxLen and IFB_RxStat must be cleared to bring both the internal HCF house keeping as the
    information supplied to the MSF in the state "no frame received"
12:	The evitable register of the Hermes is sampled and all non-Rx activities are handled.
 	The non-Rx activities are:
	 -	Alloc.  The corresponding FID register is sampled, and based on this FID, either the IFB_PIFRscInd,
	 	the IFB_DUIFRscInd or the IFB_NotifyRscInd is raised.
	 	Note that no ASSERT is performed to check whether the RscInd corresponding with the sampled 
	 	HREG_ALLOC_FID has a zero value. It is felt that this obscures the code to the reader while adding
	 	little practical value
	 -	LinkEvent (including solicited and unsolicited tallies) are handled by procedure isr_info.
	 -	Info drop events are handled by incrementing a tally
14:	All the non-Rx/non-Cmd activities are acknowledged. Combining all these acknowledgements to a single 
	place, is considered an optimization.
	Note that the Rx-acknowledgement is explicitly not included, as justified in "Buffer free strategy" above.
	Note that the Cmd-acknowledgement is explicitly not included, because all command handling is handled 
	in line.
16:	The handling of the non-Rx activities, may have bought the Hermes sufficient time to raise an Rx event
	in the evitable register (assuming an other Rx event was pending and this loop through hcf_service_nic
	acknowledged an Rx event). Therefore the evitable register is sampled again. If a frame is available,
	the FID of that frame and the characteristics (status and length) are read from the NIC. These values are, 
	after Endianess conversion if needed, stored in IFB_RxStat and IFB_RxLen. IFB_RxLen is also adjusted for 
	the size of the 802.3 MAC header. Note: Whether this adjustment is the correct/most optimal for 802.11
	is debatable, however it is paramount that IFB_RxFID and IFB_RxLEN must either be both zero or both
	non-zero to get a coherent behavior of the MSF+HCF.
18:	If the Hermes frame status reflects an error - which can only occure in promiscuous mode - the frame
	is not further processed and control is passed back to the MSF
20:	WMP messages are processed by copying them to the MailBox. Accu is updated to reflect the reception
	of the WMP frame to the debugger and sample is modified to go once more through the loop in the hope 
	to process the next pending Rx frame.
22: Both in 802.11 mode and 802.3_pure mode, the frame is not further processed (no decapsulation) and 
	control is passed back to the MSF.
	In 802.3 mode the HCF checks whether decaposulation is needed (i.e. the Hermes reported Tunnel
	encapsulation or the Hermes reported 1042 Encapsulation and the frame type does not match one of the 
	values in enc_trans_tbl.
	The actual decapsulation takes place on the fly in hcf_get_data, based on the value of IFB_RxFence.
	Note that in case of decapsulation the SNAP header is not passed to the MSF, hence IFB_RxLen must be 
	compensated for the SNAP header length
	
.NOTICES
    To make it possible to discriminate between a message without payload (only MAC addresses and implicit
    the length) it is a convenient I/F to add 14 ( space occupied by MAC addresses and Length) to the
    Hermes reported payload. So the maintenance programmer should be forwarned when considering changing
    this strategy. Also the impact on 802.11 should be considered ;?
.ENDOC				END DOCUMENTATION

-------------------------------------------------------------------------------------------------------------*/
int	hcf_service_nic(IFBP ifbp ) {

int		accu = HREG_EV_NO_CARD;
hcf_16	sample, tmp;


    ifbp->IFB_RxLen = ifbp->IFB_RxStat = 0;																		/* 2 */
	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT && IN_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0) == HCF_MAGIC ) {	/* 4 */
		accu = 0;																								/* 6 */
        if ( ifbp->IFB_RxFID ) {								    											/*10 */
            OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_RX );
            ifbp->IFB_RxFID = ifbp->IFB_RxLen = ifbp->IFB_RxStat = 0;
        }
        sample = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT );												/*12*/
        accu |= sample;

        if ( sample & HREG_EV_INFO )		isr_info( ifbp );
        if ( sample & HREG_EV_ALLOC ) {
            tmp = IN_PORT_WORD(ifbp->IFB_IOBase + HREG_ALLOC_FID );
            if ( tmp == ifbp->IFB_PIF_FID ) ifbp->IFB_PIFRscInd = 1;
            else if ( tmp == ifbp->IFB_DUIF_FID ) ifbp->IFB_DUIFRscInd = 1;
                 else {
                    ifbp->IFB_NotifyRscInd = 1;
                 }
        }
        tmp = sample & (hcf_16)~(HREG_EV_RX | HREG_EV_CMD );													/*14 */
        if ( tmp ) OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, tmp );

        sample = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT );												/*16 */
        if ( sample & HREG_EV_RX ) {
            ifbp->IFB_RxFID = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_RX_FID);
            (void)hcfio_string(ifbp, BAP_1, ifbp->IFB_RxFID, HFS_STAT_ABS, (wci_bufp)&ifbp->IFB_RxStat, 1, 2, IO_IN );
            (void)hcfio_string(ifbp, BAP_1, ifbp->IFB_RxFID, HFS_DAT_LEN_ABS, (wci_bufp)&ifbp->IFB_RxLen, 1,2,IO_IN );
            ifbp->IFB_RxLen += HFS_DAT;
        }
    }
	return accu;
}/* hcf_service_nic */





/**************************************************************************************************************
************************** H C F   S U P P O R T   R O U T I N E S ********************************************
**************************************************************************************************************/



/******************************************************************************************************************


.MODULE			alloc
.LIBRARY 		HCF_SUP
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Support for HCFR routines
.DESCRIPTION	allocates a (TX or Notify) FID in NIC RAM and clears it

.ARGUMENTS

.RETURNS
  0:	failure
  <>0:	PIF value

.NARRATIVE


.DIAGRAM
 1:	execute the allocate command by calling cmd_wait
 2: wait till either the alloc event or a time-out occures
 3: if the alloc event occures,
 	- read the FID to return it to the caller of alloc
 	- acknowledge the alloc event
 	- clear the storage allocated in NIC RAM (see notice below)
 4:	since alloc is only called after an Hermes initialize command but before the Hermes enable, a failing
	allocation is considered a H/W failure, hence the Miscellaneous Error tally is incremented
	
.NOTICE
 o  Clearing the FID is not only an aesthetical matter, it is also the cheapest (code-size) way to enforce
 	  -	correlation between IFB_TxCntl (which is cleared by hcf_disable) and the field HFS_TX_CNTL_ABS of a
 		IFB_PIF_FID
 	  -	zero value of the field HFS_TX_CNTL_ABS of a IFB_DUIF_FID (hcf_send_diag_msg only supports port 0)
 	
  Note that Card Interrupts are disabled as a side effect of hcf_disable when alloc is called.  This is a
  necessary condition, otherwise the ISR can get control, causing hcf_service_nic to run.  This would
  constitute an error because hcf_service_nic needs a defined IFB_PIF_FID and IFB_DUIF_FID to manipulate
  IFB_PIFRscInd and IFB_DUIFRscInd

  The put_info functions must be called before the alloc calls because of cnfMaxDataLength ;?Really, what is the catch
 	
 	
.DIAGRAM
.ENDOC				END DOCUMENTATION
*/
/*-----------------------------------------------------------------------------------------------------------*/
hcf_16 alloc( IFBP ifbp, int len ) {

hcf_32 prot_cnt = ifbp->IFB_TickIni;
hcf_16 pif		= 0;
hcf_16 zero		= 0;

	if ( cmd_wait( ifbp, HCMD_ALLOC, len ) == HCF_SUCCESS ) {											/* 1 */
		while ( prot_cnt ) {
			prot_cnt--;
			if ( IN_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_STAT ) & HREG_EV_ALLOC ) {						/* 2 */
				pif = IN_PORT_WORD(ifbp->IFB_IOBase + HREG_ALLOC_FID );									/* 3 */
				OUT_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_ALLOC );
				(void)hcfio_string( ifbp, BAP_0, pif, 0, (wci_bufp)&zero, 0, 2, IO_OUT );	//justify void
				len = DIV_BY_2( len );
				while ( --len ) OUT_PORT_WORD( ifbp->IFB_IOBase + BAP_0, 0 );
				break;
			}
		}
	}
	return pif;
}/* alloc */









/******************************************************************************************************************

.MODULE			calibrate
.LIBRARY 		HCF_SUP
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Support for HCFR routines
.DESCRIPTION	

.ARGUMENTS
  int calibrate( IFBP ifbp )
	
.RETURNS
  HCF_SUCCESS
  HCF_ERR_TIME_OUT
  HCF_..... (via hcf_put_info)

.NARRATIVE
  o
  o


.DIAGRAM
 1:	
 2:
 	
.NOTICE
 o
 	
.DIAGRAM
.ENDOC				END DOCUMENTATION
*/
/*-----------------------------------------------------------------------------------------------------------*/
int calibrate( IFBP ifbp ) {

LTV_STRCT	x;					// initialization with "= { 2, CFG_TICK_TIME};" causes memset 
								// to be used under some compilers
int			cnt = 10;
int			rc = HCF_SUCCESS;
hcf_32		prot_cnt;

//	if ( ifbp->IFB_TickIni == 0 ) {										                        	/* 22*/
	x.len = 2;
	x.typ = CFG_TICK_TIME;
	x.val[0] = CNV_LITTLE_TO_INT( 8 );	//no compile time conversion available
	rc = hcf_put_info( ifbp, &x );
	ifbp->IFB_TickIni = 0;												                        	/* 22*/
	while ( rc == HCF_SUCCESS && --cnt ) {
		prot_cnt = 0;
		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_TICK );
		while ( (IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ) & HREG_EV_TICK) == 0 &&
				++prot_cnt <= INI_TICK_INI ) /*NOP*/;
		ifbp->IFB_TickIni = _max( ifbp->IFB_TickIni, prot_cnt);
	}
	if ( ifbp->IFB_TickIni == INI_TICK_INI ) rc = HCF_ERR_TIME_OUT;
	ifbp->IFB_TickIni *= 128;						//time out value of 8*128 = 1024 k microseconds
//	}
	x.val[0] = CNV_LITTLE_TO_INT( ONE_SECOND );
	rc = hcf_put_info( ifbp, &x );
	return rc;
} /* calibrate */






/**************************************************************************************************************


.MODULE			cmd_wait
.LIBRARY 		HCF_SUP
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Support for HCFR routines
.DESCRIPTION

.ARGUMENTS

.RETURNS
  hcf_16
	HCF_SUCCESS
	HCF_ERR_TIME_OUT
	HCF_FAILURE
	HCF_ERR_BUSY
	
.NARRATIVE
.DIAGRAM

 1:	the test on rc checks whether a BAP initialization or a call to cmd_wait did ever fail. If so, the Hermes
	is assumed inoperable/defect, and all subsequent bap_ini/cmd_wait calls are nullified till hcf_disable
	clears the IFB_TimStat field.
 	
 2:	Based on the Hermes design, the read of the busy bit is superfluous because we wait for the Cmd bit in
	the Event Status register.

 3:	When the Hermes reports on another command than the Host just issued, the two are apparently out of
 	sync and all bets are off about the consequences. Therefore this situation is treated the same as an
 	Hermes failure as indicated by time-out (blocking all further bap_ini/cmd_wait calls till hcf_disable.
 	
 5:	If HREG_STAT reflects an error it is either an HCF bug or a H/W problem. Since
	no distinction can be made at forehand, the "vague" HCF_FAILURE code is used
	
.NOTICE
	Due to the general HCF strategy to wait for command completion, a 2nd command can never be excuted
	overlapping a previous command. As a consequence the Hermes requirement that no Inquiry command may be
	executed if there is still an unacknowledged Inquiry command outstanding, is automatically met.
	However, there are two pseudo-asynchronous commands (Diagnose and Download) which do not adhere to this
	general HCF strategy. In that case we rely on the MSF to do not overlap these commands, but no protection
	is offered by the HCF
.ENDOC				END DOCUMENTATION
*/
/* -------------------------------------------------------------------------------------------------------------------*/
int cmd_wait( IFBP ifbp, int cmd_code, int par_0 ) {

int		rc = ifbp->IFB_TimStat;
hcf_32	prot_cnt = ifbp->IFB_TickIni;


	if ( rc == HCF_SUCCESS ) {																			/* 1 */
		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_PARAM_0, par_0 );
		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_CMD, cmd_code );
		while (prot_cnt && (IN_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_STAT) & HREG_EV_CMD) == 0 ) prot_cnt--;/*2 */
		if ( prot_cnt == 0 ) {
			rc = ifbp->IFB_TimStat = HCF_ERR_TIME_OUT;
		} else {
			rc = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_STAT );
			OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_CMD );
			if ( (rc ^ cmd_code) & HREG_STAT_CMD_CODE ) {												/* 3 */
				rc = ifbp->IFB_TimStat = HCF_FAILURE;
			} else {
				rc &= HREG_STAT_CMD_RESULT;									//Hermes defined Result Code
			}
			if ( rc ) rc = HCF_FAILURE;																	/* 5 */
		}
	}
	return rc;
}/* cmd_wait */



/***********************************************************************************************************************


 Name:	enable_int

 Summary: Enables a specific Hermes interrupt

 Parameters:
  ifbp	address of the Interface Block
  event	Hermes event to be enabled as interrupt source

 Remarks: To get the contents of the IntEn register changed is a two step process:

 	o change the "shadow" in IFB_IntEnMask

 	o call hcf_action to actually copy the shadow to the IntEn register.

 	To prevent a change in the "Card Interrupt En/Disabled state, a balancing
 	pair of HCF_ACT_INT_OFF and HCF_ACT_INT_ON must be used. To prevent
 	a temporary enabling as undesirable side effect, the first call must be
 	HCF_ACT_INT_OFF.
 	Note that at the very first interrupt, hcf_service_nic causes the removal of
 	the Tick and Cmd bit in the IntEn register.
 	
 	
.DIAGRAM
***********************************************************************************************************************/
//#pragma  Reminder2( "enable_int: shouldn't this be used in more places" )
void	enable_int(IFBP ifbp, int event ) {

	ifbp->IFB_IntEnMask |= event;
	(void)hcf_action( ifbp, HCF_ACT_INT_OFF );
	(void)hcf_action( ifbp, HCF_ACT_INT_ON );
	return;

}/* enable_int */





/****************************************************************************************************************************


.MODULE			ini_hermes
.LIBRARY 		HCF_SUP
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Support for HCF routines
.DESCRIPTION

.ARGUMENTS

.RETURNS
  void
            
            
	As side effect of the Hermes Initialize command, the interrupts are disabled            
.NARRATIVE
 1:	
 2:	
.DIAGRAM

.ENDOC				END DOCUMENTATION
-------------------------------------------------------------------------------------------------------------*/
int ini_hermes( IFBP ifbp ) {

int		rc = HCF_ERR_NO_NIC;
//hcf_32	prot_cnt  = ifbp->IFB_TickIni = INI_TICK_INI;	//initialize at best guess before calibration
hcf_32	prot_cnt;

    if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {//present										/* 7 */
		if ( ifbp->IFB_TickIni == 0)  ifbp->IFB_TickIni = INI_TICK_INI;	//initialize at best guess before calibration
		prot_cnt  = ifbp->IFB_TickIni;
		while (prot_cnt && IN_PORT_WORD(ifbp->IFB_IOBase + HREG_CMD ) & HCMD_BUSY ) prot_cnt--;		/* 16*/
			
		rc = HCF_ERR_TIME_OUT;
		if ( prot_cnt != 0 ) {
			rc = cmd_wait( ifbp, HCMD_INI, 0 );														/* 18*/
			OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, 0xFFFF );
		}

	}
	return rc;
}/* ini_hermes */


/****************************************************************************************************************************


.MODULE			isr_info
.LIBRARY 		HCF_SUP
.TYPE 			function
.SYSTEM			msdos
.SYSTEM			unix
.SYSTEM			NW4
.APPLICATION	Support for HCF routines
.DESCRIPTION

.ARGUMENTS

.RETURNS
  void

.NARRATIVE
 1:	info[0] becomes the length of the T-field + the length of the Value-field in words. Note that it is
	dangerous to determine the length of the Value field by decrementing info[0], because if -e.g. as a
	result of a bug in the Hermes as has happened in real life- info[0] becomes 0, a decrement results in
	a very large number. Therefore all code is crafted around an unchanged info[0], with the intention to
	make the HCF more robust against I/F violations.
 2:	This is an example of the strategy described in #1 above. Info[0] is expected to be HCF_NIC_TAL_CNT + 1.
	By using a pre-decrement, this value results in HCF_NIC_TAL_CNT movements of a single tally value into
	the IFB_NIC_Tallies area of the IFB.
 3:	Although put_info_mb is robust against a len-parameter with value zero, it accepts any bogus value
	for the type-parameter.
.DIAGRAM

.ENDOC				END DOCUMENTATION
-------------------------------------------------------------------------------------------------------------*/
void isr_info( IFBP ifbp ) {

hcf_16	info[2], tmp;
hcf_32	*p;

	tmp = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_INFO_FID );
	(void)hcfio_string(ifbp, BAP_1, tmp, 0, (wci_bufp)info, 2, sizeof(info), IO_IN );						/* 1 */
	
	if ( info[1] == CFG_TALLIES ) {
		if ( info[0] > HCF_NIC_TAL_CNT ) info[0] = HCF_NIC_TAL_CNT + 1;										/* 2 */
		p = (hcf_32*)&ifbp->IFB_NIC_Tallies;//.TxUnicastFrames;
		while ( --info[0] ) *p++ += IN_PORT_WORD( ifbp->IFB_IOBase + BAP_1 );
	}
	return;
}/* isr_info */






#if defined _M_I86TM
#endif //_M_I86TM

/***********************************************************************************************************************


 Name:	put_info

 Summary: stores Hermes configuration information in the ConfigTable of the IFB

 Parameters:
  ifbp	address of the Interface Block
  ltvp	address in NIC RAM where LVT-records are located


.NARRATIVE

**************************************************************************************************************/
int put_info( IFBP ifbp, LTVP ltvp	) {

int					cnt = 3;
//hcf_16				i = ltvp->len - 1;
int					rc = HCF_SUCCESS;

	
	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
	

		do {
			rc = hcfio_string( ifbp, BAP_1,
							   ltvp->typ, 0, (wci_bufp)ltvp, 2, MUL_BY_2(ltvp->len + 1), IO_OUT_CHECK );
		} while ( cnt-- && rc != HCF_SUCCESS );
		if ( rc == HCF_SUCCESS ) rc = cmd_wait( ifbp, HCMD_ACCESS + HCMD_ACCESS_WRITE, ltvp->typ );
	}	
	
	return rc;
}/* put_info */







