linux/drivers/staging/wlags49_h2/dhf.c
<<
>>
Prefs
   1
   2/**************************************************************************************************************
   3*
   4* FILE   :      DHF.C
   5*
   6* DATE  :       $Date: 2004/07/19 08:16:14 $   $Revision: 1.2 $
   7* Original      :       2004/05/28 14:05:34    Revision: 1.36      Tag: hcf7_t20040602_01
   8* Original      :       2004/05/11 06:22:57    Revision: 1.32      Tag: hcf7_t7_20040513_01
   9* Original      :       2004/04/15 09:24:42    Revision: 1.28      Tag: hcf7_t7_20040415_01
  10* Original      :       2004/04/08 15:18:16    Revision: 1.27      Tag: t7_20040413_01
  11* Original      :       2004/04/01 15:32:55    Revision: 1.25      Tag: t7_20040401_01
  12* Original      :       2004/03/10 15:39:28    Revision: 1.21      Tag: t20040310_01
  13* Original      :       2004/03/04 11:03:37    Revision: 1.19      Tag: t20040304_01
  14* Original      :       2004/03/02 09:27:11    Revision: 1.17      Tag: t20040302_03
  15* Original      :       2004/02/24 13:00:28    Revision: 1.15      Tag: t20040224_01
  16* Original      :       2004/02/19 10:57:28    Revision: 1.14      Tag: t20040219_01
  17* Original      :       2003/11/27 09:00:09    Revision: 1.3      Tag: t20021216_01
  18*
  19* AUTHOR :      John Meertens
  20*                       Nico Valster
  21*
  22* SPECIFICATION: ........
  23*
  24* DESC   :      generic functions to handle the download of NIC firmware
  25*                       Local Support Routines for above procedures
  26*
  27*                       Customizable via HCFCFG.H, which is included by HCF.H
  28*
  29*
  30*       DHF is (intended to be) platform-independent.
  31*       DHF is a module that provides a number of routines to download firmware
  32*       images (the names primary, station, access point, secondary and tertiary
  33*       are used or have been used) to volatile or nonvolatile memory
  34*       in WaveLAN/IEEE NICs. To achieve this DHF makes use of the WaveLAN/IEEE
  35*       WCI as implemented by the HCF-module.
  36*
  37*       Download to non-volatile memory is used to update a WaveLAN/IEEE NIC to new
  38*       firmware. Normally this will be an upgrade to newer firmware, although
  39*       downgrading to older firmware is possible too.
  40*
  41* Note: relative to Asserts, the following can be observed:
  42*       Since the IFB is not known inside the routine, the macro HCFASSERT is replaced with MMDASSERT.
  43*       Also the line number reported in the assert is raised by FILE_NAME_OFFSET (10000) to discriminate the
  44*       DHF Asserts from HCF and MMD asserts.
  45*
  46***************************************************************************************************************
  47*
  48*
  49* SOFTWARE LICENSE
  50*
  51* This software is provided subject to the following terms and conditions,
  52* which you should read carefully before using the software.  Using this
  53* software indicates your acceptance of these terms and conditions.  If you do
  54* not agree with these terms and conditions, do not use the software.
  55*
  56* COPYRIGHT (C) 1999 - 2000 by Lucent Technologies.     All Rights Reserved
  57* COPYRIGHT (C) 2001 - 2004     by Agere Systems Inc.   All Rights Reserved
  58* All rights reserved.
  59*
  60* Redistribution and use in source or binary forms, with or without
  61* modifications, are permitted provided that the following conditions are met:
  62*
  63* . Redistributions of source code must retain the above copyright notice, this
  64*    list of conditions and the following Disclaimer as comments in the code as
  65*    well as in the documentation and/or other materials provided with the
  66*    distribution.
  67*
  68* . Redistributions in binary form must reproduce the above copyright notice,
  69*    this list of conditions and the following Disclaimer in the documentation
  70*    and/or other materials provided with the distribution.
  71*
  72* . Neither the name of Agere Systems Inc. nor the names of the contributors
  73*    may be used to endorse or promote products derived from this software
  74*    without specific prior written permission.
  75*
  76* Disclaimer
  77*
  78* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  79* INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
  80* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  ANY
  81* USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
  82* RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
  83* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  84* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  85* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  86* ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
  87* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  88* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  89* DAMAGE.
  90*
  91*
  92**************************************************************************************************************/
  93
  94#include "hcf.h"
  95#include "hcfdef.h"
  96#include "dhf.h"
  97#include "mmd.h"
  98
  99/* to distinguish MMD from HCF asserts by means of line number */
 100#undef  FILE_NAME_OFFSET
 101#define FILE_NAME_OFFSET MMD_FILE_NAME_OFFSET
 102/*-----------------------------------------------------------------------------
 103 *
 104 * Defines, data structures, and global variables
 105 *
 106 *---------------------------------------------------------------------------*/
 107
 108/*                    12345678901234 */
 109char signature[14] = "FUPU7D37dhfwci";
 110
 111/*-----------------------------------------------------------------------------
 112 *
 113 * LTV-records retrieved from the NIC to:
 114 *      - determine compatibility between NIC and image
 115 *      - ((setup the buffer size dynamically for non-volatile download (see note below) ))
 116 *      - supply plugging information contained in the PDA (H-I only)
 117 *
 118 *---------------------------------------------------------------------------*/
 119
 120/* for USB/H1 we needed a smaller value than the CFG_DL_BUF_STRCT reported 8192
 121        for the time being it seems simpler to always use 2000 for USB/H1 as well as all other cases rather than
 122        using the "fixed anyway" CFG_DL_BUF_STRCT. */
 123#define DL_SIZE 2000
 124
 125/* CFG_IDENTITY_STRCT           pri_identity    = { LOF(CFG_IDENTITY_STRCT), CFG_PRI_IDENTITY }; */
 126CFG_SUP_RANGE_STRCT     mfi_sup         = { LOF(CFG_SUP_RANGE_STRCT), CFG_NIC_MFI_SUP_RANGE };
 127CFG_SUP_RANGE_STRCT     cfi_sup         = { LOF(CFG_SUP_RANGE_STRCT), CFG_NIC_CFI_SUP_RANGE };
 128/* Note: could be used rather than the above explained and defined DL_SIZE if need arises
 129 * CFG_DL_BUF_STRCT     dl_buf          = { LOF(CFG_DL_BUF_STRCT), CFG_DL_BUF };
 130*/
 131
 132/*-----------------------------------------------------------------------------
 133 * Array ltv_info stores NIC information (in the form of LTV-records)
 134 * needed for download. A NULL record indicates the end of the array.
 135 *---------------------------------------------------------------------------*/
 136
 137/* The LTV_INFO_STRUCT is needed to save the sizes of the structs, because after a GET_INFO()
 138 * the len field is changed to the real len of the RID by the called routine.
 139 * This is only relevant if the DHF used without reloading the driver/utility.
 140 */
 141
 142LTV_INFO_STRUCT ltv_info[] = {
 143        { (LTVP)&mfi_sup,                       LOF(CFG_SUP_RANGE_STRCT) } ,
 144        { (LTVP)&cfi_sup,                       LOF(CFG_SUP_RANGE_STRCT) } ,
 145        { (LTVP) NULL,                          0 }
 146};
 147
 148
 149/***********************************************************************************************************/
 150/***************************************  PROTOTYPES  ******************************************************/
 151/***********************************************************************************************************/
 152static int                              check_comp_fw(memimage *fw);
 153
 154
 155/************************************************************************************************************
 156*.SUBMODULE             int check_comp_fw( memimage *fw )
 157*.PURPOSE               Checks compatibility of CFI and MFI, NIC as supplier, station/AP firmware image as supplier.
 158*
 159*.ARGUMENTS
 160*   fw          F/W image to be downloaded
 161*
 162*.RETURNS
 163*   HFC_SUCCESS         - firmware OK
 164*   DHF_ERR_INCOMP_FW
 165*
 166*.DESCRIPTION
 167*   This function uses compatibility and identity information that has been
 168*   retrieved from the card which is currently inserted to check whether the
 169*   station firmware image to be downloaded is compatible.
 170*.ENDDOC                                END DOCUMENTATION
 171*************************************************************************************************************/
 172int
 173check_comp_fw(memimage *fw)
 174{
 175CFG_RANGE20_STRCT               *p;
 176int                                     rc = HCF_SUCCESS;
 177CFG_RANGE_SPEC_STRCT *i;
 178
 179        switch (fw->identity->typ) {
 180        case CFG_FW_IDENTITY:                           /* Station F/W */
 181        case COMP_ID_FW_AP_FAKE:                        /* ;?is this useful (used to be:  CFG_AP_IDENTITY) */
 182                break;
 183        default:
 184                MMDASSERT(DO_ASSERT, fw->identity->typ)         /* unknown/unsupported firmware_type: */
 185                rc = DHF_ERR_INCOMP_FW;
 186                return rc; /* ;? how useful is this anyway,
 187                                        *  till that is sorted out might as well violate my own single exit principle
 188                                        */
 189        }
 190        p = fw->compat;
 191        i = NULL;
 192        while (p->len && i == NULL) {                                   /* check the MFI ranges */
 193                if (p->typ  == CFG_MFI_ACT_RANGES_STA) {
 194                        i = mmd_check_comp((void *)p, &mfi_sup);
 195                }
 196                p++;
 197        }
 198        MMDASSERT(i, 0) /* MFI: NIC Supplier not compatible with F/W image Actor */
 199        if (i) {
 200                p = fw->compat;
 201                i = NULL;
 202                while (p->len && i == NULL) {                   /* check the CFI ranges */
 203                        if (p->typ  == CFG_CFI_ACT_RANGES_STA) {
 204                                 i = mmd_check_comp((void *)p, &cfi_sup);
 205                        }
 206                        p++;
 207                }
 208                MMDASSERT(i, 0) /* CFI: NIC Supplier not compatible with F/W image Actor */
 209        }
 210        if (i == NULL) {
 211                rc = DHF_ERR_INCOMP_FW;
 212        }
 213        return rc;
 214} /* check_comp_fw */
 215
 216
 217
 218
 219
 220/*-----------------------------------------------------------------------------
 221 *
 222 * Exported functions
 223 *
 224 *---------------------------------------------------------------------------*/
 225
 226
 227
 228/*************************************************************************************************************
 229*
 230*.MODULE                int dhf_download_binary( void *ifbp, memimage *fw )
 231*.PURPOSE               Downloads a complete (primary, station, or access point) firmware image to the NIC.
 232*
 233*.ARGUMENTS
 234*       ifbp            address of the Interface Block
 235*   fw          F/W image to be downloaded
 236*
 237*.RETURNS
 238*   HCF_SUCCESS                 - download completed successfully.
 239*   DHF_ERR_INCOMP_FW           - firmware not compatible
 240*
 241*.DESCRIPTION
 242*   Initialize global variables
 243*   Connect to the DHF
 244*   Check the compatibility of the image (For primary firmware images it is checked first
 245*       whether download is necessary).
 246*   If everything's download the firmware.
 247*   Disconnect from the DHF.
 248*
 249*
 250*.DIAGRAM
 251*
 252*.NOTICE:
 253        MMDASSERT is unacceptable because some drivers call dhf_download_binary before hcf_connect
 254
 255* The old comment was:
 256*.ENDDOC                                END DOCUMENTATION
 257*************************************************************************************************************/
 258int
 259dhf_download_binary(memimage *fw)
 260{
 261int                     rc = HCF_SUCCESS;
 262CFG_PROG_STRCT  *p;
 263int                             i;
 264
 265        /* validate the image */
 266        for (i = 0; i < sizeof(signature) && fw->signature[i] == signature[i]; i++)
 267                ; /* NOP */
 268        if (i != sizeof(signature)              ||
 269                 fw->signature[i] != 0x01       ||
 270                 /* test for Little/Big Endian Binary flag */
 271                 fw->signature[i+1] != (/* HCF_BIG_ENDIAN ? 'B' : */ 'L'))
 272                rc = DHF_ERR_INCOMP_FW;
 273        else {                                  /* Little Endian Binary format */
 274                fw->codep    = (CFG_PROG_STRCT FAR*)((char *)fw->codep + (hcf_32)fw);
 275                fw->identity = (CFG_IDENTITY_STRCT FAR*)((char *)fw->identity + (hcf_32)fw);
 276                fw->compat   = (CFG_RANGE20_STRCT FAR*)((char *)fw->compat + (hcf_32)fw);
 277                for (i = 0; fw->p[i]; i++)
 278                        fw->p[i] = ((char *)fw->p[i] + (hcf_32)fw);
 279                p = fw->codep;
 280                while (p->len) {
 281                        p->host_addr = (char *)p->host_addr + (hcf_32)fw;
 282                        p++;
 283                }
 284        }
 285        return rc;
 286}   /* dhf_download_binary */
 287
 288
 289/*************************************************************************************************************
 290*
 291*.MODULE                int dhf_download_fw( void *ifbp, memimage *fw )
 292*.PURPOSE               Downloads a complete (primary or tertiary) firmware image to the NIC.
 293*
 294*.ARGUMENTS
 295*       ifbp            address of the Interface Block
 296*   fw                  F/W image to be downloaded
 297*
 298*.RETURNS
 299*       HCF_SUCCESS             - download completed successfully.
 300*       HCF_ERR_NO_NIC          - no NIC present
 301*       DHF_ERR_INCOMP_FW       - firmware not compatible
 302*
 303*.DESCRIPTION
 304* - check the signature of the image
 305* - get the compatibility information from the components on the NIC
 306*         - Primary Firmware Identity
 307*         -     Modem - Firmware I/F
 308*         -     Controller - Firmware I/F
 309*!! - if necessary ( i.e. H-I) get the PDA contents from the NIC
 310* - check the compatibility of the MFI and CFI of the NIC with the F/W image
 311*       Note: the Primary F/W compatibility is only relevant for the "running" HCF and is already verified in
 312*       hcf_connect
 313*!! -   if necessary ( i.e. H-I)
 314*!!       -     verify the sumcheck of the PDA
 315*!!       -     plug the image (based on the PDA and the default plug records)
 316* - loop over all the download LTVs in the image which consists of a sequence of
 317*         - CFG_PROG_VOLATILE/CFG_PROG_NON_VOLATILE
 318*         - 1 or more sequences of CFG_PROG_ADDR, CFG_PROG_DATA,....,CFG_PROG_DATA
 319*         -     CFG_PROG_STOP
 320*
 321*.DIAGRAM
 322*
 323*.NOTICE
 324* The old comment was:
 325*       // Download primary firmware if necessary and allowed. This is done silently (without telling
 326*       // the user) and only if the firmware in the download image is newer than the firmware in the
 327*       // card.  In Major version 4 of the primary firmware functions of Hermes and Shark were
 328*       // combined. Prior to that two separate versions existed. We only have to download primary
 329*       // firmware if major version of primary firmware in the NIC < 4.
 330*       //              download = pri_identity.version_major < 4;
 331*       //              if ( download ) {
 332*       //                      rc = check_comp_primary( fw );
 333*       //              }
 334* It is my understanding that Pri Variant 1 must be updated by Pri Variant 2. The test on
 335* major version < 4 should amount to the same result but be "principally" less correct
 336* In deliberation with the Architecture team, it was decided that this upgrade for old H-I
 337* NICs, is an aspect which belongs on the WSU level not on the DHF level
 338*
 339*.ENDDOC                                END DOCUMENTATION
 340*************************************************************************************************************/
 341int
 342dhf_download_fw(void *ifbp, memimage *fw)
 343{
 344int                             rc = HCF_SUCCESS;
 345LTV_INFO_STRUCT_PTR pp = ltv_info;
 346CFG_PROG_STRCT          *p = fw->codep;
 347LTVP                            ltvp;
 348int                                     i;
 349
 350        MMDASSERT(fw != NULL, 0)
 351        /* validate the image */
 352        for (i = 0; i < sizeof(signature) && fw->signature[i] == signature[i]; i++)
 353                ; /* NOP */
 354        if (i != sizeof(signature)              ||
 355                 fw->signature[i] != 0x01               ||
 356                 /* check for binary image */
 357                 (fw->signature[i+1] != 'C' && fw->signature[i+1] != (/*HCF_BIG_ENDIAN ? 'B' : */ 'L')))
 358                 rc = DHF_ERR_INCOMP_FW;
 359
 360/*      Retrieve all information needed for download from the NIC */
 361        while ((rc == HCF_SUCCESS) && ((ltvp = pp->ltvp) != NULL)) {
 362                ltvp->len = pp++->len;  /* Set len to original len. This len is changed to real len by GET_INFO() */
 363                rc = GET_INFO(ltvp);
 364                MMDASSERT(rc == HCF_SUCCESS, rc)
 365                MMDASSERT(rc == HCF_SUCCESS, ltvp->typ)
 366                MMDASSERT(rc == HCF_SUCCESS, ltvp->len)
 367        }
 368        if (rc == HCF_SUCCESS)
 369                rc = check_comp_fw(fw);
 370        if (rc == HCF_SUCCESS) {
 371                while (rc == HCF_SUCCESS && p->len) {
 372                        rc = PUT_INFO(p);
 373                        p++;
 374                }
 375        }
 376        MMDASSERT(rc == HCF_SUCCESS, rc)
 377        return rc;
 378}   /* dhf_download_fw */
 379
 380
 381