Logo Search packages:      
Sourcecode: pcmcia-cs version File versions  Download package

wvlan_hcf.c

/* 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 */








Generated by  Doxygen 1.6.0   Back to index