diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
commit | e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7 (patch) | |
tree | ea51b391f7d74ca695dcb9f5e46eb02688a92ed9 /drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c | |
parent | 81280572ca6f54009edfa4deee563e8678784218 (diff) | |
parent | a4ac0d847af9dd34d5953a5e264400326144b6b2 (diff) | |
download | op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.zip op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.tar.gz |
Merge 'staging-next' to Linus's tree
This merges the staging-next tree to Linus's tree and resolves
some conflicts that were present due to changes in other trees that were
affected by files here.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c')
-rw-r--r-- | drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c | 940 |
1 files changed, 940 insertions, 0 deletions
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c new file mode 100644 index 0000000..0bf398d --- /dev/null +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c @@ -0,0 +1,940 @@ +/*--------------------------------------------------------------------------- + FT1000 driver for Flarion Flash OFDM NIC Device + + Copyright (C) 2002 Flarion Technologies, All rights reserved. + + This program is 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. + -------------------------------------------------------------------------- + + Description: This module will handshake with the DSP bootloader to + download the DSP runtime image. + +---------------------------------------------------------------------------*/ + +#define __KERNEL_SYSCALLS__ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/unistd.h> +#include <linux/netdevice.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/vmalloc.h> + +#include "ft1000_dev.h" +#include "ft1000.h" +#include "boot.h" + +#ifdef FT_DEBUG +#define DEBUG(n, args...) printk(KERN_DEBUG args); +#else +#define DEBUG(n, args...) +#endif + +#define MAX_DSP_WAIT_LOOPS 100 +#define DSP_WAIT_SLEEP_TIME 1 /* 1 millisecond */ + +#define MAX_LENGTH 0x7f0 + +#define DWNLD_MAG_HANDSHAKE_LOC 0x00 +#define DWNLD_MAG_TYPE_LOC 0x01 +#define DWNLD_MAG_SIZE_LOC 0x02 +#define DWNLD_MAG_PS_HDR_LOC 0x03 + +#define DWNLD_HANDSHAKE_LOC 0x02 +#define DWNLD_TYPE_LOC 0x04 +#define DWNLD_SIZE_MSW_LOC 0x06 +#define DWNLD_SIZE_LSW_LOC 0x08 +#define DWNLD_PS_HDR_LOC 0x0A + +#define HANDSHAKE_TIMEOUT_VALUE 0xF1F1 +#define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */ +#define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */ +#define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */ +#define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */ + +#define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */ +#define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */ + +#define REQUEST_CODE_LENGTH 0x0000 +#define REQUEST_RUN_ADDRESS 0x0001 +#define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */ +#define REQUEST_DONE_BL 0x0003 +#define REQUEST_DONE_CL 0x0004 +#define REQUEST_VERSION_INFO 0x0005 +#define REQUEST_CODE_BY_VERSION 0x0006 +#define REQUEST_MAILBOX_DATA 0x0007 +#define REQUEST_FILE_CHECKSUM 0x0008 + +#define STATE_START_DWNLD 0x01 +#define STATE_BOOT_DWNLD 0x02 +#define STATE_CODE_DWNLD 0x03 +#define STATE_DONE_DWNLD 0x04 +#define STATE_SECTION_PROV 0x05 +#define STATE_DONE_PROV 0x06 +#define STATE_DONE_FILE 0x07 + +USHORT get_handshake(struct net_device *dev, USHORT expected_value); +void put_handshake(struct net_device *dev, USHORT handshake_value); +USHORT get_request_type(struct net_device *dev); +long get_request_value(struct net_device *dev); +void put_request_value(struct net_device *dev, long lvalue); +USHORT hdr_checksum(PPSEUDO_HDR pHdr); + +typedef struct _DSP_FILE_HDR { + long build_date; + long dsp_coff_date; + long loader_code_address; + long loader_code_size; + long loader_code_end; + long dsp_code_address; + long dsp_code_size; + long dsp_code_end; + long reserved[8]; +} __attribute__ ((packed)) DSP_FILE_HDR, *PDSP_FILE_HDR; + +typedef struct _DSP_FILE_HDR_5 { + long version_id; // Version ID of this image format. + long package_id; // Package ID of code release. + long build_date; // Date/time stamp when file was built. + long commands_offset; // Offset to attached commands in Pseudo Hdr format. + long loader_offset; // Offset to bootloader code. + long loader_code_address; // Start address of bootloader. + long loader_code_end; // Where bootloader code ends. + long loader_code_size; + long version_data_offset; // Offset were scrambled version data begins. + long version_data_size; // Size, in words, of scrambled version data. + long nDspImages; // Number of DSP images in file. +} __attribute__ ((packed)) DSP_FILE_HDR_5, *PDSP_FILE_HDR_5; + +typedef struct _DSP_IMAGE_INFO { + long coff_date; // Date/time when DSP Coff image was built. + long begin_offset; // Offset in file where image begins. + long end_offset; // Offset in file where image begins. + long run_address; // On chip Start address of DSP code. + long image_size; // Size of image. + long version; // Embedded version # of DSP code. +} __attribute__ ((packed)) DSP_IMAGE_INFO, *PDSP_IMAGE_INFO; + +typedef struct _DSP_IMAGE_INFO_V6 { + long coff_date; // Date/time when DSP Coff image was built. + long begin_offset; // Offset in file where image begins. + long end_offset; // Offset in file where image begins. + long run_address; // On chip Start address of DSP code. + long image_size; // Size of image. + long version; // Embedded version # of DSP code. + unsigned short checksum; // Dsp File checksum + unsigned short pad1; +} __attribute__ ((packed)) DSP_IMAGE_INFO_V6, *PDSP_IMAGE_INFO_V6; + +void card_bootload(struct net_device *dev) +{ + FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev); + unsigned long flags; + PULONG pdata; + UINT size; + UINT i; + ULONG templong; + + DEBUG(0, "card_bootload is called\n"); + + pdata = (PULONG) bootimage; + size = sizeof(bootimage); + + // check for odd word + if (size & 0x0003) { + size += 4; + } + // Provide mutual exclusive access while reading ASIC registers. + spin_lock_irqsave(&info->dpram_lock, flags); + + // need to set i/o base address initially and hardware will autoincrement + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE); + // write bytes + for (i = 0; i < (size >> 2); i++) { + templong = *pdata++; + outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA); + } + + spin_unlock_irqrestore(&info->dpram_lock, flags); +} + +USHORT get_handshake(struct net_device *dev, USHORT expected_value) +{ + FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev); + USHORT handshake; + ULONG tempx; + int loopcnt; + + loopcnt = 0; + while (loopcnt < MAX_DSP_WAIT_LOOPS) { + if (info->AsicID == ELECTRABUZZ_ID) { + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, + DWNLD_HANDSHAKE_LOC); + + handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA); + } else { + tempx = + ntohl(ft1000_read_dpram_mag_32 + (dev, DWNLD_MAG_HANDSHAKE_LOC)); + handshake = (USHORT) tempx; + } + + if ((handshake == expected_value) + || (handshake == HANDSHAKE_RESET_VALUE)) { + return handshake; + } else { + loopcnt++; + mdelay(DSP_WAIT_SLEEP_TIME); + } + + } + + return HANDSHAKE_TIMEOUT_VALUE; + +} + +void put_handshake(struct net_device *dev, USHORT handshake_value) +{ + FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev); + ULONG tempx; + + if (info->AsicID == ELECTRABUZZ_ID) { + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, + DWNLD_HANDSHAKE_LOC); + ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value); /* Handshake */ + } else { + tempx = (ULONG) handshake_value; + tempx = ntohl(tempx); + ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */ + } +} + +USHORT get_request_type(struct net_device *dev) +{ + FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev); + USHORT request_type; + ULONG tempx; + + if (info->AsicID == ELECTRABUZZ_ID) { + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC); + request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA); + } else { + tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC); + tempx = ntohl(tempx); + request_type = (USHORT) tempx; + } + + return request_type; + +} + +long get_request_value(struct net_device *dev) +{ + FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev); + long value; + USHORT w_val; + + if (info->AsicID == ELECTRABUZZ_ID) { + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, + DWNLD_SIZE_MSW_LOC); + + w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA); + + value = (long)(w_val << 16); + + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, + DWNLD_SIZE_LSW_LOC); + + w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA); + + value = (long)(value | w_val); + } else { + value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC); + value = ntohl(value); + } + + return value; + +} + +void put_request_value(struct net_device *dev, long lvalue) +{ + FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev); + USHORT size; + ULONG tempx; + + if (info->AsicID == ELECTRABUZZ_ID) { + size = (USHORT) (lvalue >> 16); + + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, + DWNLD_SIZE_MSW_LOC); + + ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size); + + size = (USHORT) (lvalue); + + ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, + DWNLD_SIZE_LSW_LOC); + + ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size); + } else { + tempx = ntohl(lvalue); + ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx); /* Handshake */ + } + +} + +USHORT hdr_checksum(PPSEUDO_HDR pHdr) +{ + USHORT *usPtr = (USHORT *) pHdr; + USHORT chksum; + + chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^ + usPtr[4]) ^ usPtr[5]) ^ usPtr[6]); + + return chksum; +} + +int card_download(struct net_device *dev, void *pFileStart, UINT FileLength) +{ + FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev); + int Status = SUCCESS; + USHORT DspWordCnt = 0; + UINT uiState; + USHORT handshake; + PPSEUDO_HDR pHdr; + USHORT usHdrLength; + PDSP_FILE_HDR pFileHdr; + long word_length; + USHORT request; + USHORT temp; + PPROV_RECORD pprov_record; + PUCHAR pbuffer; + PDSP_FILE_HDR_5 pFileHdr5; + PDSP_IMAGE_INFO pDspImageInfo = NULL; + PDSP_IMAGE_INFO_V6 pDspImageInfoV6 = NULL; + long requested_version; + BOOLEAN bGoodVersion = 0; + PDRVMSG pMailBoxData; + USHORT *pUsData = NULL; + USHORT *pUsFile = NULL; + UCHAR *pUcFile = NULL; + UCHAR *pBootEnd = NULL; + UCHAR *pCodeEnd = NULL; + int imageN; + long file_version; + long loader_code_address = 0; + long loader_code_size = 0; + long run_address = 0; + long run_size = 0; + unsigned long flags; + unsigned long templong; + unsigned long image_chksum = 0; + + // + // Get version id of file, at first 4 bytes of file, for newer files. + // + file_version = *(long *)pFileStart; + + uiState = STATE_START_DWNLD; + + pFileHdr = (PDSP_FILE_HDR) pFileStart; + pFileHdr5 = (PDSP_FILE_HDR_5) pFileStart; + + switch (file_version) { + case 5: + case 6: + pUsFile = + (USHORT *) ((long)pFileStart + pFileHdr5->loader_offset); + pUcFile = + (UCHAR *) ((long)pFileStart + pFileHdr5->loader_offset); + + pBootEnd = + (UCHAR *) ((long)pFileStart + pFileHdr5->loader_code_end); + + loader_code_address = pFileHdr5->loader_code_address; + loader_code_size = pFileHdr5->loader_code_size; + bGoodVersion = FALSE; + break; + + default: + Status = FAILURE; + break; + } + + while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) { + + switch (uiState) { + case STATE_START_DWNLD: + + handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY); + + if (handshake == HANDSHAKE_DSP_BL_READY) { + put_handshake(dev, HANDSHAKE_DRIVER_READY); + } else { + Status = FAILURE; + } + + uiState = STATE_BOOT_DWNLD; + + break; + + case STATE_BOOT_DWNLD: + handshake = get_handshake(dev, HANDSHAKE_REQUEST); + if (handshake == HANDSHAKE_REQUEST) { + /* + * Get type associated with the request. + */ + request = get_request_type(dev); + switch (request) { + case REQUEST_RUN_ADDRESS: + put_request_value(dev, + loader_code_address); + break; + case REQUEST_CODE_LENGTH: + put_request_value(dev, + loader_code_size); + break; + case REQUEST_DONE_BL: + /* Reposition ptrs to beginning of code section */ + pUsFile = (USHORT *) ((long)pBootEnd); + pUcFile = (UCHAR *) ((long)pBootEnd); + uiState = STATE_CODE_DWNLD; + break; + case REQUEST_CODE_SEGMENT: + word_length = get_request_value(dev); + if (word_length > MAX_LENGTH) { + Status = FAILURE; + break; + } + if ((word_length * 2 + (long)pUcFile) > + (long)pBootEnd) { + /* + * Error, beyond boot code range. + */ + Status = FAILURE; + break; + } + // Provide mutual exclusive access while reading ASIC registers. + spin_lock_irqsave(&info->dpram_lock, + flags); + if (file_version == 5) { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + ft1000_write_reg(dev, + FT1000_REG_DPRAM_ADDR, + DWNLD_PS_HDR_LOC); + + for (; word_length > 0; word_length--) { /* In words */ + //temp = *pUsFile; + //temp = RtlUshortByteSwap(temp); + ft1000_write_reg(dev, + FT1000_REG_DPRAM_DATA, + *pUsFile); + pUsFile++; + pUcFile += 2; + DspWordCnt++; + } + } else { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + outw(DWNLD_MAG_PS_HDR_LOC, + dev->base_addr + + FT1000_REG_DPRAM_ADDR); + if (word_length & 0x01) { + word_length++; + } + word_length = word_length / 2; + + for (; word_length > 0; word_length--) { /* In words */ + templong = *pUsFile++; + templong |= + (*pUsFile++ << 16); + pUcFile += 4; + outl(templong, + dev->base_addr + + FT1000_REG_MAG_DPDATAL); + } + } + spin_unlock_irqrestore(&info-> + dpram_lock, + flags); + break; + default: + Status = FAILURE; + break; + } + put_handshake(dev, HANDSHAKE_RESPONSE); + } else { + Status = FAILURE; + } + + break; + + case STATE_CODE_DWNLD: + handshake = get_handshake(dev, HANDSHAKE_REQUEST); + if (handshake == HANDSHAKE_REQUEST) { + /* + * Get type associated with the request. + */ + request = get_request_type(dev); + switch (request) { + case REQUEST_FILE_CHECKSUM: + DEBUG(0, + "ft1000_dnld: REQUEST_FOR_CHECKSUM\n"); + put_request_value(dev, image_chksum); + break; + case REQUEST_RUN_ADDRESS: + if (bGoodVersion) { + put_request_value(dev, + run_address); + } else { + Status = FAILURE; + break; + } + break; + case REQUEST_CODE_LENGTH: + if (bGoodVersion) { + put_request_value(dev, + run_size); + } else { + Status = FAILURE; + break; + } + break; + case REQUEST_DONE_CL: + /* Reposition ptrs to beginning of provisioning section */ + switch (file_version) { + case 5: + case 6: + pUsFile = + (USHORT *) ((long)pFileStart + + + pFileHdr5-> + commands_offset); + pUcFile = + (UCHAR *) ((long)pFileStart + + + pFileHdr5-> + commands_offset); + break; + default: + Status = FAILURE; + break; + } + uiState = STATE_DONE_DWNLD; + break; + case REQUEST_CODE_SEGMENT: + if (!bGoodVersion) { + Status = FAILURE; + break; + } + word_length = get_request_value(dev); + if (word_length > MAX_LENGTH) { + Status = FAILURE; + break; + } + if ((word_length * 2 + (long)pUcFile) > + (long)pCodeEnd) { + /* + * Error, beyond boot code range. + */ + Status = FAILURE; + break; + } + if (file_version == 5) { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + ft1000_write_reg(dev, + FT1000_REG_DPRAM_ADDR, + DWNLD_PS_HDR_LOC); + + for (; word_length > 0; word_length--) { /* In words */ + //temp = *pUsFile; + //temp = RtlUshortByteSwap(temp); + ft1000_write_reg(dev, + FT1000_REG_DPRAM_DATA, + *pUsFile); + pUsFile++; + pUcFile += 2; + DspWordCnt++; + } + } else { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + outw(DWNLD_MAG_PS_HDR_LOC, + dev->base_addr + + FT1000_REG_DPRAM_ADDR); + if (word_length & 0x01) { + word_length++; + } + word_length = word_length / 2; + + for (; word_length > 0; word_length--) { /* In words */ + templong = *pUsFile++; + templong |= + (*pUsFile++ << 16); + pUcFile += 4; + outl(templong, + dev->base_addr + + FT1000_REG_MAG_DPDATAL); + } + } + break; + + case REQUEST_MAILBOX_DATA: + // Convert length from byte count to word count. Make sure we round up. + word_length = + (long)(info->DSPInfoBlklen + 1) / 2; + put_request_value(dev, word_length); + pMailBoxData = + (PDRVMSG) & info->DSPInfoBlk[0]; + pUsData = + (USHORT *) & pMailBoxData->data[0]; + // Provide mutual exclusive access while reading ASIC registers. + spin_lock_irqsave(&info->dpram_lock, + flags); + if (file_version == 5) { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + ft1000_write_reg(dev, + FT1000_REG_DPRAM_ADDR, + DWNLD_PS_HDR_LOC); + + for (; word_length > 0; word_length--) { /* In words */ + temp = ntohs(*pUsData); + ft1000_write_reg(dev, + FT1000_REG_DPRAM_DATA, + temp); + pUsData++; + } + } else { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + outw(DWNLD_MAG_PS_HDR_LOC, + dev->base_addr + + FT1000_REG_DPRAM_ADDR); + if (word_length & 0x01) { + word_length++; + } + word_length = word_length / 2; + + for (; word_length > 0; word_length--) { /* In words */ + templong = *pUsData++; + templong |= + (*pUsData++ << 16); + outl(templong, + dev->base_addr + + FT1000_REG_MAG_DPDATAL); + } + } + spin_unlock_irqrestore(&info-> + dpram_lock, + flags); + break; + + case REQUEST_VERSION_INFO: + word_length = + pFileHdr5->version_data_size; + put_request_value(dev, word_length); + pUsFile = + (USHORT *) ((long)pFileStart + + pFileHdr5-> + version_data_offset); + // Provide mutual exclusive access while reading ASIC registers. + spin_lock_irqsave(&info->dpram_lock, + flags); + if (file_version == 5) { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + ft1000_write_reg(dev, + FT1000_REG_DPRAM_ADDR, + DWNLD_PS_HDR_LOC); + + for (; word_length > 0; word_length--) { /* In words */ + ft1000_write_reg(dev, + FT1000_REG_DPRAM_DATA, + *pUsFile + /*temp */ + ); + pUsFile++; + } + } else { + /* + * Position ASIC DPRAM auto-increment pointer. + */ + outw(DWNLD_MAG_PS_HDR_LOC, + dev->base_addr + + FT1000_REG_DPRAM_ADDR); + if (word_length & 0x01) { + word_length++; + } + word_length = word_length / 2; + + for (; word_length > 0; word_length--) { /* In words */ + templong = + ntohs(*pUsFile++); + temp = + ntohs(*pUsFile++); + templong |= + (temp << 16); + outl(templong, + dev->base_addr + + FT1000_REG_MAG_DPDATAL); + } + } + spin_unlock_irqrestore(&info-> + dpram_lock, + flags); + break; + + case REQUEST_CODE_BY_VERSION: + bGoodVersion = FALSE; + requested_version = + get_request_value(dev); + if (file_version == 5) { + pDspImageInfo = + (PDSP_IMAGE_INFO) ((long) + pFileStart + + + sizeof + (DSP_FILE_HDR_5)); + for (imageN = 0; + imageN < + pFileHdr5->nDspImages; + imageN++) { + if (pDspImageInfo-> + version == + requested_version) { + bGoodVersion = + TRUE; + pUsFile = + (USHORT + *) ((long) + pFileStart + + + pDspImageInfo-> + begin_offset); + pUcFile = + (UCHAR + *) ((long) + pFileStart + + + pDspImageInfo-> + begin_offset); + pCodeEnd = + (UCHAR + *) ((long) + pFileStart + + + pDspImageInfo-> + end_offset); + run_address = + pDspImageInfo-> + run_address; + run_size = + pDspImageInfo-> + image_size; + break; + } + pDspImageInfo++; + } + } else { + pDspImageInfoV6 = + (PDSP_IMAGE_INFO_V6) ((long) + pFileStart + + + sizeof + (DSP_FILE_HDR_5)); + for (imageN = 0; + imageN < + pFileHdr5->nDspImages; + imageN++) { + temp = (USHORT) + (pDspImageInfoV6-> + version); + templong = temp; + temp = (USHORT) + (pDspImageInfoV6-> + version >> 16); + templong |= + (temp << 16); + if (templong == + requested_version) { + bGoodVersion = + TRUE; + pUsFile = + (USHORT + *) ((long) + pFileStart + + + pDspImageInfoV6-> + begin_offset); + pUcFile = + (UCHAR + *) ((long) + pFileStart + + + pDspImageInfoV6-> + begin_offset); + pCodeEnd = + (UCHAR + *) ((long) + pFileStart + + + pDspImageInfoV6-> + end_offset); + run_address = + pDspImageInfoV6-> + run_address; + run_size = + pDspImageInfoV6-> + image_size; + image_chksum = + (ULONG) + pDspImageInfoV6-> + checksum; + DEBUG(0, + "ft1000_dnld: image_chksum = 0x%8x\n", + (unsigned + int) + image_chksum); + break; + } + pDspImageInfoV6++; + } + } + if (!bGoodVersion) { + /* + * Error, beyond boot code range. + */ + Status = FAILURE; + break; + } + break; + + default: + Status = FAILURE; + break; + } + put_handshake(dev, HANDSHAKE_RESPONSE); + } else { + Status = FAILURE; + } + + break; + + case STATE_DONE_DWNLD: + if (((UINT) (pUcFile) - (UINT) pFileStart) >= + (UINT) FileLength) { + uiState = STATE_DONE_FILE; + break; + } + + pHdr = (PPSEUDO_HDR) pUsFile; + + if (pHdr->portdest == 0x80 /* DspOAM */ + && (pHdr->portsrc == 0x00 /* Driver */ + || pHdr->portsrc == 0x10 /* FMM */ )) { + uiState = STATE_SECTION_PROV; + } else { + DEBUG(1, + "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n"); + DEBUG(1, "\t Port Source = 0x%2.2x\n", + pHdr->portsrc); + DEBUG(1, "\t Port Destination = 0x%2.2x\n", + pHdr->portdest); + Status = FAILURE; + } + + break; + + case STATE_SECTION_PROV: + + pHdr = (PPSEUDO_HDR) pUcFile; + + if (pHdr->checksum == hdr_checksum(pHdr)) { + if (pHdr->portdest != 0x80 /* Dsp OAM */ ) { + uiState = STATE_DONE_PROV; + break; + } + usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */ + + // Get buffer for provisioning data + pbuffer = + kmalloc((usHdrLength + sizeof(PSEUDO_HDR)), + GFP_ATOMIC); + if (pbuffer) { + memcpy(pbuffer, (void *)pUcFile, + (UINT) (usHdrLength + + sizeof(PSEUDO_HDR))); + // link provisioning data + pprov_record = + kmalloc(sizeof(PROV_RECORD), + GFP_ATOMIC); + if (pprov_record) { + pprov_record->pprov_data = + pbuffer; + list_add_tail(&pprov_record-> + list, + &info->prov_list); + // Move to next entry if available + pUcFile = + (UCHAR *) ((UINT) pUcFile + + (UINT) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(PSEUDO_HDR)); + if ((UINT) (pUcFile) - + (UINT) (pFileStart) >= + (UINT) FileLength) { + uiState = + STATE_DONE_FILE; + } + } else { + kfree(pbuffer); + Status = FAILURE; + } + } else { + Status = FAILURE; + } + } else { + /* Checksum did not compute */ + Status = FAILURE; + } + + break; + + case STATE_DONE_PROV: + uiState = STATE_DONE_FILE; + break; + + default: + Status = FAILURE; + break; + } /* End Switch */ + + } /* End while */ + + return Status; + +} |