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