| //===================================================== |
| // CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. |
| // |
| // |
| // This file is part of Express Card USB Driver |
| // |
| // $Id: |
| //==================================================== |
| // 20090926; aelias; removed compiler warnings; ubuntu 9.04; 2.6.28-15-generic |
| |
| #include <linux/init.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/netdevice.h> |
| #include <linux/etherdevice.h> |
| #include <linux/usb.h> |
| #include <linux/vmalloc.h> |
| #include "ft1000_usb.h" |
| |
| #define FIFO_DNLD 1 |
| |
| #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 MAX_DSP_WAIT_LOOPS 40 |
| #define DSP_WAIT_SLEEP_TIME 1000 /* 1 millisecond */ |
| #define DSP_WAIT_DISPATCH_LVL 50 /* 50 usec */ |
| |
| #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1 |
| #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */ |
| #define HANDSHAKE_RESET_VALUE_USB 0xFE7E /* When DSP requests startover */ |
| #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */ |
| #define HANDSHAKE_DSP_BL_READY_USB 0xFE7E /* 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 |
| |
| #define MAX_LENGTH 0x7f0 |
| |
| // Temporary download mechanism for Magnemite |
| #define DWNLD_MAG_TYPE_LOC 0x00 |
| #define DWNLD_MAG_LEN_LOC 0x01 |
| #define DWNLD_MAG_ADDR_LOC 0x02 |
| #define DWNLD_MAG_CHKSUM_LOC 0x03 |
| #define DWNLD_MAG_VAL_LOC 0x04 |
| |
| #define HANDSHAKE_MAG_DSP_BL_READY 0xFEFE0000 /* At start DSP writes this when bootloader ready */ |
| #define HANDSHAKE_MAG_DSP_ENTRY 0x01000000 /* Dsp writes this to request for entry address */ |
| #define HANDSHAKE_MAG_DSP_DATA 0x02000000 /* Dsp writes this to request for data block */ |
| #define HANDSHAKE_MAG_DSP_DONE 0x03000000 /* Dsp writes this to indicate download done */ |
| |
| #define HANDSHAKE_MAG_DRV_READY 0xFFFF0000 /* Driver writes this to indicate ready to download */ |
| #define HANDSHAKE_MAG_DRV_DATA 0x02FECDAB /* Driver writes this to indicate data available to DSP */ |
| #define HANDSHAKE_MAG_DRV_ENTRY 0x01FECDAB /* Driver writes this to indicate entry point to DSP */ |
| |
| #define HANDSHAKE_MAG_TIMEOUT_VALUE 0xF1F1 |
| |
| |
| // New Magnemite downloader |
| #define DWNLD_MAG1_HANDSHAKE_LOC 0x00 |
| #define DWNLD_MAG1_TYPE_LOC 0x01 |
| #define DWNLD_MAG1_SIZE_LOC 0x02 |
| #define DWNLD_MAG1_PS_HDR_LOC 0x03 |
| |
| #pragma pack (push, pack_save, 1) |
| 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]; |
| } 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. |
| } 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. |
| } 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; |
| } DSP_IMAGE_INFO_V6, *PDSP_IMAGE_INFO_V6; |
| |
| //--------------------------------------------------------------------------- |
| // Function: check_usb_db |
| // |
| // Parameters: struct ft1000_device - device structure |
| // |
| // Returns: 0 - success |
| // |
| // Description: This function checks if the doorbell register is cleared |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static ULONG check_usb_db (struct ft1000_device *ft1000dev) |
| { |
| int loopcnt; |
| USHORT temp; |
| ULONG status; |
| |
| loopcnt = 0; |
| while (loopcnt < 10) |
| { |
| |
| status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_DOORBELL); |
| DEBUG("check_usb_db: read FT1000_REG_DOORBELL value is %x\n", temp); |
| if (temp & 0x0080) |
| { |
| DEBUG("FT1000:Got checkusb doorbell\n"); |
| status = ft1000_write_register (ft1000dev, 0x0080, FT1000_REG_DOORBELL); |
| #if FIFO_DNLD |
| status = ft1000_write_register (ft1000dev, 0x0100, FT1000_REG_DOORBELL); |
| #endif |
| status = ft1000_write_register (ft1000dev, 0x8000, FT1000_REG_DOORBELL); |
| break; |
| } |
| else |
| { |
| loopcnt++; |
| msleep (10); |
| } |
| |
| } //end of while |
| |
| |
| loopcnt = 0; |
| while (loopcnt < 20) |
| { |
| |
| status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_DOORBELL); |
| DEBUG("FT1000:check_usb_db:Doorbell = 0x%x\n", temp); |
| if (temp & 0x8000) |
| { |
| loopcnt++; |
| msleep (10); |
| } |
| else |
| { |
| DEBUG("check_usb_db: door bell is cleared, return 0\n"); |
| return 0; |
| } |
| #if 0 |
| // Check if Card is present |
| status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_SUP_IMASK); |
| if (temp == 0x0000) { |
| break; |
| } |
| |
| status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_ASIC_ID); |
| if (temp == 0xffff) { |
| break; |
| } |
| #endif |
| } |
| |
| return HANDSHAKE_MAG_TIMEOUT_VALUE; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Function: get_handshake |
| // |
| // Parameters: struct ft1000_device - device structure |
| // USHORT expected_value - the handshake value expected |
| // |
| // Returns: handshakevalue - success |
| // HANDSHAKE_TIMEOUT_VALUE - failure |
| // |
| // Description: This function gets the handshake and compare with the expected value |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_value) |
| { |
| USHORT handshake; |
| int loopcnt; |
| ULONG status=0; |
| PFT1000_INFO pft1000info = netdev_priv(ft1000dev->net); |
| |
| loopcnt = 0; |
| while (loopcnt < 100) |
| { |
| |
| #if FIFO_DNLD |
| // Need to clear downloader doorbell if Hartley ASIC |
| status = ft1000_write_register (ft1000dev, FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL); |
| //DEBUG("FT1000:get_handshake:doorbell = 0x%x\n", temp); |
| if (pft1000info->fcodeldr) |
| { |
| DEBUG(" get_handshake: fcodeldr is %d\n", pft1000info->fcodeldr); |
| pft1000info->fcodeldr = 0; |
| status = check_usb_db(ft1000dev); |
| if (status != STATUS_SUCCESS) |
| { |
| DEBUG("get_handshake: check_usb_db failed\n"); |
| status = STATUS_FAILURE; |
| break; |
| } |
| status = ft1000_write_register (ft1000dev, FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL); |
| } |
| |
| status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); |
| //DEBUG("get_handshake: handshake is %x\n", tempx); |
| handshake = ntohs(handshake); |
| //DEBUG("get_handshake: after swap, handshake is %x\n", handshake); |
| #else |
| // Need to clear downloader doorbell if Hartley ASIC |
| status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_DOORBELL); |
| //DEBUG("FT1000:get_handshake:doorbell = 0x%x\n", temp); |
| if (temp) |
| { |
| if (temp & FT1000_DB_DNLD_RX) |
| { |
| //DEBUG("get_handshake: write FT1000_DB_DNLD_RX to doorbell register\n"); |
| status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL); |
| } |
| |
| if (pft1000info->fcodeldr) |
| { |
| DEBUG(" get_handshake: fcodeldr is %d\n", pft1000info->fcodeldr); |
| pft1000info->fcodeldr = 0; |
| status = check_usb_db(ft1000dev); |
| if (status != STATUS_SUCCESS) |
| { |
| DEBUG("get_handshake: check_usb_db failed\n"); |
| status = STATUS_FAILURE; |
| break; |
| } |
| |
| status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_DOORBELL); |
| //DEBUG("FT1000:get_handshake:doorbell = 0x%x\n", temp); |
| if (temp) |
| { |
| if (temp & FT1000_DB_DNLD_RX) |
| status = ft1000_write_register(ft1000dev,FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL); |
| } |
| } |
| |
| status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); |
| //DEBUG("get_handshake: handshake is %x\n", tempx); |
| handshake = ntohs(handshake); |
| //DEBUG("get_handshake: after swap, handshake is %x\n", handshake); |
| |
| } //end of if temp |
| #endif |
| |
| |
| if (status) |
| return HANDSHAKE_TIMEOUT_VALUE; |
| |
| //DEBUG("get_handshake: handshake= %x\n", handshake); |
| if ((handshake == expected_value) || (handshake == HANDSHAKE_RESET_VALUE_USB)) |
| { |
| //DEBUG("get_handshake: return handshake %x\n", handshake); |
| return handshake; |
| } |
| else |
| { |
| loopcnt++; |
| msleep (10); |
| } |
| //DEBUG("HANDSHKE LOOP: %d\n", loopcnt); |
| |
| } |
| |
| //DEBUG("get_handshake: return handshake time out\n"); |
| return HANDSHAKE_TIMEOUT_VALUE; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Function: put_handshake |
| // |
| // Parameters: struct ft1000_device - device structure |
| // USHORT handshake_value - handshake to be written |
| // |
| // Returns: none |
| // |
| // Description: This function write the handshake value to the handshake location |
| // in DPRAM |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static void put_handshake(struct ft1000_device *ft1000dev,USHORT handshake_value) |
| { |
| ULONG tempx; |
| USHORT tempword; |
| int i; |
| ULONG status; |
| |
| |
| |
| tempx = (ULONG)handshake_value; |
| tempx = ntohl(tempx); |
| |
| tempword = (USHORT)(tempx & 0xffff); |
| status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 0); |
| tempword = (USHORT)(tempx >> 16); |
| status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 1); |
| status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL); |
| #if FIFO_DNLD |
| for (i=0; i<1000; i++); |
| #else |
| for (i=0; i<10; i++) |
| { |
| status = ft1000_read_register (ft1000dev, &tempword, FT1000_REG_DOORBELL); |
| if ((tempword & FT1000_DB_DNLD_TX) == 0) |
| break; |
| } |
| if (i==10) |
| { |
| DEBUG("FT1000:put_handshake could not clear Tx doorbell\n"); |
| status = ft1000_read_register (ft1000dev, &tempword, FT1000_REG_DOORBELL); |
| DEBUG("FT1000:put_handshake:doorbell = 0x%x\n",tempword); |
| } |
| #endif |
| |
| } |
| |
| static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected_value) |
| { |
| USHORT handshake; |
| int loopcnt; |
| USHORT temp; |
| ULONG status=0; |
| |
| PFT1000_INFO pft1000info = netdev_priv(ft1000dev->net); |
| loopcnt = 0; |
| handshake = 0; |
| while (loopcnt < 100) |
| { |
| if (pft1000info->usbboot == 2) { |
| status = ft1000_read_dpram32 (ft1000dev, 0, (PUCHAR)&(pft1000info->tempbuf[0]), 64); |
| for (temp=0; temp<16; temp++) |
| DEBUG("tempbuf %d = 0x%x\n", temp, pft1000info->tempbuf[temp]); |
| status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); |
| DEBUG("handshake from read_dpram16 = 0x%x\n", handshake); |
| if (pft1000info->dspalive == pft1000info->tempbuf[6]) |
| handshake = 0; |
| else { |
| handshake = pft1000info->tempbuf[1]; |
| pft1000info->dspalive = pft1000info->tempbuf[6]; |
| } |
| } |
| else { |
| status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); |
| } |
| loopcnt++; |
| msleep(10); |
| handshake = ntohs(handshake); |
| if ((handshake == expected_value) || (handshake == HANDSHAKE_RESET_VALUE_USB)) |
| { |
| return handshake; |
| } |
| } |
| |
| return HANDSHAKE_TIMEOUT_VALUE; |
| } |
| |
| static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_value) |
| { |
| int i; |
| |
| for (i=0; i<1000; i++); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Function: get_request_type |
| // |
| // Parameters: struct ft1000_device - device structure |
| // |
| // Returns: request type - success |
| // |
| // Description: This function returns the request type |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static USHORT get_request_type(struct ft1000_device *ft1000dev) |
| { |
| USHORT request_type; |
| ULONG status; |
| USHORT tempword; |
| ULONG tempx; |
| PFT1000_INFO pft1000info = netdev_priv(ft1000dev->net); |
| |
| if ( pft1000info->bootmode == 1) |
| { |
| status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx); |
| tempx = ntohl(tempx); |
| } |
| else |
| { |
| #if FIFO_DNLD |
| tempx = 0; |
| #else |
| status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 0); |
| tempx = tempword; |
| #endif |
| status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1); |
| tempx |= (tempword << 16); |
| tempx = ntohl(tempx); |
| } |
| request_type = (USHORT)tempx; |
| |
| //DEBUG("get_request_type: request_type is %x\n", request_type); |
| return request_type; |
| |
| } |
| |
| static USHORT get_request_type_usb(struct ft1000_device *ft1000dev) |
| { |
| USHORT request_type; |
| ULONG status; |
| USHORT tempword; |
| ULONG tempx; |
| PFT1000_INFO pft1000info = netdev_priv(ft1000dev->net); |
| if ( pft1000info->bootmode == 1) |
| { |
| status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx); |
| tempx = ntohl(tempx); |
| } |
| else |
| { |
| if (pft1000info->usbboot == 2) { |
| tempx = pft1000info->tempbuf[2]; |
| tempword = pft1000info->tempbuf[3]; |
| } |
| else { |
| tempx = 0; |
| status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1); |
| } |
| tempx |= (tempword << 16); |
| tempx = ntohl(tempx); |
| } |
| request_type = (USHORT)tempx; |
| |
| //DEBUG("get_request_type: request_type is %x\n", request_type); |
| return request_type; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Function: get_request_value |
| // |
| // Parameters: struct ft1000_device - device structure |
| // |
| // Returns: request value - success |
| // |
| // Description: This function returns the request value |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static long get_request_value(struct ft1000_device *ft1000dev) |
| { |
| ULONG value; |
| USHORT tempword; |
| ULONG status; |
| PFT1000_INFO pft1000info = netdev_priv(ft1000dev->net); |
| |
| |
| if ( pft1000info->bootmode == 1) |
| { |
| status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&value); |
| value = ntohl(value); |
| } |
| else |
| { |
| status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 0); |
| value = tempword; |
| status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1); |
| value |= (tempword << 16); |
| value = ntohl(value); |
| } |
| |
| |
| //DEBUG("get_request_value: value is %x\n", value); |
| return value; |
| |
| } |
| |
| #if 0 |
| static long get_request_value_usb(struct ft1000_device *ft1000dev) |
| { |
| ULONG value; |
| USHORT tempword; |
| ULONG status; |
| PFT1000_INFO pft1000info = netdev_priv(ft1000dev->net); |
| |
| if (pft1000info->usbboot == 2) { |
| value = pft1000info->tempbuf[4]; |
| tempword = pft1000info->tempbuf[5]; |
| } |
| else { |
| value = 0; |
| status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1); |
| } |
| |
| value |= (tempword << 16); |
| value = ntohl(value); |
| |
| #if FIFO_DNLD |
| if (pft1000info->usbboot == 1) |
| pft1000info->usbboot = 2; |
| #endif |
| |
| //DEBUG("get_request_value_usb: value is %x\n", value); |
| return value; |
| |
| } |
| #endif |
| |
| //--------------------------------------------------------------------------- |
| // Function: put_request_value |
| // |
| // Parameters: struct ft1000_device - device structure |
| // long lvalue - value to be put into DPRAM location DWNLD_MAG1_SIZE_LOC |
| // |
| // Returns: none |
| // |
| // Description: This function writes a value to DWNLD_MAG1_SIZE_LOC |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static void put_request_value(struct ft1000_device *ft1000dev, long lvalue) |
| { |
| ULONG tempx; |
| ULONG status; |
| |
| tempx = ntohl(lvalue); |
| status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempx); |
| |
| |
| |
| //DEBUG("put_request_value: value is %x\n", lvalue); |
| |
| } |
| |
| |
| |
| //--------------------------------------------------------------------------- |
| // Function: hdr_checksum |
| // |
| // Parameters: PPSEUDO_HDR pHdr - Pseudo header pointer |
| // |
| // Returns: checksum - success |
| // |
| // Description: This function returns the checksum of the pseudo header |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static 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; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // Function: write_blk |
| // |
| // Parameters: struct ft1000_device - device structure |
| // USHORT **pUsFile - DSP image file pointer in USHORT |
| // UCHAR **pUcFile - DSP image file pointer in UCHAR |
| // long word_length - lenght of the buffer to be written |
| // to DPRAM |
| // |
| // Returns: STATUS_SUCCESS - success |
| // STATUS_FAILURE - failure |
| // |
| // Description: This function writes a block of DSP image to DPRAM |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length) |
| { |
| ULONG Status = STATUS_SUCCESS; |
| USHORT dpram; |
| long temp_word_length; |
| int loopcnt, i, j; |
| USHORT *pTempFile; |
| USHORT tempword; |
| USHORT tempbuffer[64]; |
| USHORT resultbuffer[64]; |
| PFT1000_INFO pft1000info = netdev_priv(ft1000dev->net); |
| |
| //DEBUG("FT1000:download:start word_length = %d\n",(int)word_length); |
| dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; |
| tempword = *(*pUsFile); |
| (*pUsFile)++; |
| Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0); |
| tempword = *(*pUsFile); |
| (*pUsFile)++; |
| Status = ft1000_write_dpram16(ft1000dev, dpram++, tempword, 1); |
| |
| *pUcFile = *pUcFile + 4; |
| word_length--; |
| tempword = (USHORT)word_length; |
| word_length = (word_length / 16) + 1; |
| pTempFile = *pUsFile; |
| temp_word_length = word_length; |
| for (; word_length > 0; word_length--) /* In words */ |
| { |
| loopcnt = 0; |
| |
| for (i=0; i<32; i++) |
| { |
| if (tempword != 0) |
| { |
| tempbuffer[i++] = *(*pUsFile); |
| (*pUsFile)++; |
| tempbuffer[i] = *(*pUsFile); |
| (*pUsFile)++; |
| *pUcFile = *pUcFile + 4; |
| loopcnt++; |
| tempword--; |
| } |
| else |
| { |
| tempbuffer[i++] = 0; |
| tempbuffer[i] = 0; |
| } |
| } |
| |
| //DEBUG("write_blk: loopcnt is %d\n", loopcnt); |
| //DEBUG("write_blk: bootmode = %d\n", bootmode); |
| //DEBUG("write_blk: dpram = %x\n", dpram); |
| if (pft1000info->bootmode == 0) |
| { |
| if (dpram >= 0x3F4) |
| Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 8); |
| else |
| Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64); |
| } |
| else |
| { |
| for (j=0; j<10; j++) |
| { |
| Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64); |
| if (Status == STATUS_SUCCESS) |
| { |
| // Work around for ASIC bit stuffing problem. |
| if ( (tempbuffer[31] & 0xfe00) == 0xfe00) |
| { |
| Status = ft1000_write_dpram32(ft1000dev, dpram+12, (PUCHAR)&tempbuffer[24], 64); |
| } |
| // Let's check the data written |
| Status = ft1000_read_dpram32 (ft1000dev, dpram, (PUCHAR)&resultbuffer[0], 64); |
| if ( (tempbuffer[31] & 0xfe00) == 0xfe00) |
| { |
| for (i=0; i<28; i++) |
| { |
| if (resultbuffer[i] != tempbuffer[i]) |
| { |
| //NdisMSleep (100); |
| DEBUG("FT1000:download:DPRAM write failed 1 during bootloading\n"); |
| msleep(10); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| } |
| Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (PUCHAR)&resultbuffer[0], 64); |
| for (i=0; i<16; i++) |
| { |
| if (resultbuffer[i] != tempbuffer[i+24]) |
| { |
| //NdisMSleep (100); |
| DEBUG("FT1000:download:DPRAM write failed 2 during bootloading\n"); |
| msleep(10); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| } |
| } |
| else |
| { |
| for (i=0; i<32; i++) |
| { |
| if (resultbuffer[i] != tempbuffer[i]) |
| { |
| //NdisMSleep (100); |
| DEBUG("FT1000:download:DPRAM write failed 3 during bootloading\n"); |
| msleep(10); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| } |
| } |
| |
| if (Status == STATUS_SUCCESS) |
| break; |
| |
| } |
| } |
| |
| if (Status != STATUS_SUCCESS) |
| { |
| DEBUG("FT1000:download:Write failed tempbuffer[31] = 0x%x\n", tempbuffer[31]); |
| break; |
| } |
| |
| } |
| dpram = dpram + loopcnt; |
| } |
| |
| return Status; |
| } |
| |
| static void usb_dnld_complete (struct urb *urb) |
| { |
| //DEBUG("****** usb_dnld_complete\n"); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Function: write_blk_fifo |
| // |
| // Parameters: struct ft1000_device - device structure |
| // USHORT **pUsFile - DSP image file pointer in USHORT |
| // UCHAR **pUcFile - DSP image file pointer in UCHAR |
| // long word_length - lenght of the buffer to be written |
| // to DPRAM |
| // |
| // Returns: STATUS_SUCCESS - success |
| // STATUS_FAILURE - failure |
| // |
| // Description: This function writes a block of DSP image to DPRAM |
| // |
| // Notes: |
| // |
| //--------------------------------------------------------------------------- |
| static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length) |
| { |
| ULONG Status = STATUS_SUCCESS; |
| int byte_length; |
| long aligncnt; |
| |
| byte_length = word_length * 4; |
| |
| if (byte_length % 4) |
| aligncnt = 4 - (byte_length % 4); |
| else |
| aligncnt = 0; |
| byte_length += aligncnt; |
| |
| if (byte_length && ((byte_length % 64) == 0)) { |
| byte_length += 4; |
| } |
| |
| if (byte_length < 64) |
| byte_length = 68; |
| |
| #if 0 |
| pblk = kzalloc(byte_length, GFP_KERNEL); |
| memcpy (pblk, *pUcFile, byte_length); |
| |
| pipe = usb_sndbulkpipe (ft1000dev->dev, ft1000dev->bulk_out_endpointAddr); |
| |
| Status = usb_bulk_msg (ft1000dev->dev, |
| pipe, |
| pblk, |
| byte_length, |
| &cnt, |
| 10); |
| DEBUG("write_blk_fifo Status = 0x%8x Bytes Transfer = %d Data = 0x%x\n", Status, cnt, *pblk); |
| |
| kfree(pblk); |
| #else |
| usb_init_urb(ft1000dev->tx_urb); |
| memcpy (ft1000dev->tx_buf, *pUcFile, byte_length); |
| usb_fill_bulk_urb(ft1000dev->tx_urb, |
| ft1000dev->dev, |
| usb_sndbulkpipe(ft1000dev->dev, ft1000dev->bulk_out_endpointAddr), |
| ft1000dev->tx_buf, |
| byte_length, |
| usb_dnld_complete, |
| (void*)ft1000dev); |
| |
| usb_submit_urb(ft1000dev->tx_urb, GFP_ATOMIC); |
| #endif |
| |
| *pUsFile = *pUsFile + (word_length << 1); |
| *pUcFile = *pUcFile + (word_length << 2); |
| |
| return Status; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: scram_dnldr |
| // |
| // Synopsis: Scramble downloader for Harley based ASIC via USB interface |
| // |
| // Arguments: pFileStart - pointer to start of file |
| // FileLength - file length |
| // |
| // Returns: status - return code |
| //--------------------------------------------------------------------------- |
| |
| u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLength) |
| { |
| u16 Status = STATUS_SUCCESS; |
| UINT uiState; |
| USHORT handshake; |
| PPSEUDO_HDR pHdr; |
| USHORT usHdrLength; |
| //PPROV_RECORD pProvRecord; |
| PDSP_FILE_HDR pFileHdr; |
| long word_length; |
| USHORT request; |
| USHORT temp; |
| USHORT tempword; |
| |
| PDSP_FILE_HDR_5 pFileHdr5; |
| PDSP_IMAGE_INFO_V6 pDspImageInfoV6 = NULL; |
| long requested_version; |
| BOOLEAN bGoodVersion; |
| PDRVMSG pMailBoxData; |
| USHORT *pUsData = NULL; |
| USHORT *pUsFile = NULL; |
| UCHAR *pUcFile = NULL; |
| UCHAR *pBootEnd = NULL, *pCodeEnd= NULL; |
| int imageN; |
| long loader_code_address, loader_code_size = 0; |
| long run_address = 0, run_size = 0; |
| |
| ULONG templong; |
| ULONG image_chksum = 0; |
| |
| USHORT dpram = 0; |
| PUCHAR pbuffer; |
| PPROV_RECORD pprov_record; |
| FT1000_INFO *pft1000info = netdev_priv(ft1000dev->net); |
| |
| DEBUG("Entered scram_dnldr...\n"); |
| |
| pft1000info->fcodeldr = 0; |
| pft1000info->usbboot = 0; |
| pft1000info->dspalive = 0xffff; |
| |
| |
| // |
| // Get version id of file, at first 4 bytes of file, for newer files. |
| // |
| |
| uiState = STATE_START_DWNLD; |
| |
| pFileHdr = (PDSP_FILE_HDR)pFileStart; |
| pFileHdr5 = (PDSP_FILE_HDR_5)pFileStart; |
| |
| ft1000_write_register (ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); |
| |
| pUsFile = (USHORT *)(pFileStart + pFileHdr5->loader_offset); |
| pUcFile = (UCHAR *)(pFileStart + pFileHdr5->loader_offset); |
| |
| pBootEnd = (UCHAR *)(pFileStart + pFileHdr5->loader_code_end); |
| |
| loader_code_address = pFileHdr5->loader_code_address; |
| loader_code_size = pFileHdr5->loader_code_size; |
| bGoodVersion = FALSE; |
| |
| while ((Status == STATUS_SUCCESS) && (uiState != STATE_DONE_FILE)) |
| { |
| switch (uiState) |
| { |
| case STATE_START_DWNLD: |
| DEBUG("FT1000:STATE_START_DWNLD\n"); |
| if (pft1000info->usbboot) |
| handshake = get_handshake_usb(ft1000dev, HANDSHAKE_DSP_BL_READY); |
| else |
| handshake = get_handshake(ft1000dev, HANDSHAKE_DSP_BL_READY); |
| |
| if (handshake == HANDSHAKE_DSP_BL_READY) |
| { |
| DEBUG("scram_dnldr: handshake is HANDSHAKE_DSP_BL_READY, call put_handshake(HANDSHAKE_DRIVER_READY)\n"); |
| put_handshake(ft1000dev, HANDSHAKE_DRIVER_READY); |
| } |
| else |
| { |
| DEBUG("FT1000:download:Download error: Handshake failed\n"); |
| Status = STATUS_FAILURE; |
| } |
| |
| uiState = STATE_BOOT_DWNLD; |
| |
| break; |
| |
| case STATE_BOOT_DWNLD: |
| DEBUG("FT1000:STATE_BOOT_DWNLD\n"); |
| pft1000info->bootmode = 1; |
| handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST); |
| if (handshake == HANDSHAKE_REQUEST) |
| { |
| /* |
| * Get type associated with the request. |
| */ |
| request = get_request_type(ft1000dev); |
| switch (request) |
| { |
| case REQUEST_RUN_ADDRESS: |
| DEBUG("FT1000:REQUEST_RUN_ADDRESS\n"); |
| put_request_value(ft1000dev, loader_code_address); |
| break; |
| case REQUEST_CODE_LENGTH: |
| DEBUG("FT1000:REQUEST_CODE_LENGTH\n"); |
| put_request_value(ft1000dev, loader_code_size); |
| break; |
| case REQUEST_DONE_BL: |
| DEBUG("FT1000:REQUEST_DONE_BL\n"); |
| /* Reposition ptrs to beginning of code section */ |
| pUsFile = (USHORT *)(pBootEnd); |
| pUcFile = (UCHAR *)(pBootEnd); |
| //DEBUG("FT1000:download:pUsFile = 0x%8x\n", (int)pUsFile); |
| //DEBUG("FT1000:download:pUcFile = 0x%8x\n", (int)pUcFile); |
| uiState = STATE_CODE_DWNLD; |
| pft1000info->fcodeldr = 1; |
| break; |
| case REQUEST_CODE_SEGMENT: |
| //DEBUG("FT1000:REQUEST_CODE_SEGMENT\n"); |
| word_length = get_request_value(ft1000dev); |
| //DEBUG("FT1000:word_length = 0x%x\n", (int)word_length); |
| //NdisMSleep (100); |
| if (word_length > MAX_LENGTH) |
| { |
| DEBUG("FT1000:download:Download error: Max length exceeded\n"); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| if ( (word_length*2 + pUcFile) > pBootEnd) |
| { |
| /* |
| * Error, beyond boot code range. |
| */ |
| DEBUG("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundry.\n", |
| (int)word_length); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| /* |
| * Position ASIC DPRAM auto-increment pointer. |
| */ |
| dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; |
| if (word_length & 0x1) |
| word_length++; |
| word_length = word_length / 2; |
| |
| Status = write_blk(ft1000dev, &pUsFile, &pUcFile, word_length); |
| //DEBUG("write_blk returned %d\n", Status); |
| break; |
| default: |
| DEBUG("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n",request); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| if (pft1000info->usbboot) |
| put_handshake_usb(ft1000dev, HANDSHAKE_RESPONSE); |
| else |
| put_handshake(ft1000dev, HANDSHAKE_RESPONSE); |
| } |
| else |
| { |
| DEBUG("FT1000:download:Download error: Handshake failed\n"); |
| Status = STATUS_FAILURE; |
| } |
| |
| break; |
| |
| case STATE_CODE_DWNLD: |
| //DEBUG("FT1000:STATE_CODE_DWNLD\n"); |
| pft1000info->bootmode = 0; |
| if (pft1000info->usbboot) |
| handshake = get_handshake_usb(ft1000dev, HANDSHAKE_REQUEST); |
| else |
| handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST); |
| if (handshake == HANDSHAKE_REQUEST) |
| { |
| /* |
| * Get type associated with the request. |
| */ |
| if (pft1000info->usbboot) |
| request = get_request_type_usb(ft1000dev); |
| else |
| request = get_request_type(ft1000dev); |
| switch (request) |
| { |
| case REQUEST_FILE_CHECKSUM: |
| DEBUG("FT1000:download:image_chksum = 0x%8x\n", image_chksum); |
| put_request_value(ft1000dev, image_chksum); |
| break; |
| case REQUEST_RUN_ADDRESS: |
| DEBUG("FT1000:download: REQUEST_RUN_ADDRESS\n"); |
| if (bGoodVersion) |
| { |
| DEBUG("FT1000:download:run_address = 0x%8x\n", (int)run_address); |
| put_request_value(ft1000dev, run_address); |
| } |
| else |
| { |
| DEBUG("FT1000:download:Download error: Got Run address request before image offset request.\n"); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| break; |
| case REQUEST_CODE_LENGTH: |
| DEBUG("FT1000:download:REQUEST_CODE_LENGTH\n"); |
| if (bGoodVersion) |
| { |
| DEBUG("FT1000:download:run_size = 0x%8x\n", (int)run_size); |
| put_request_value(ft1000dev, run_size); |
| } |
| else |
| { |
| DEBUG("FT1000:download:Download error: Got Size request before image offset request.\n"); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| break; |
| case REQUEST_DONE_CL: |
| #if FIFO_DNLD |
| pft1000info->usbboot = 3; |
| #endif |
| /* Reposition ptrs to beginning of provisioning section */ |
| pUsFile = (USHORT *)(pFileStart + pFileHdr5->commands_offset); |
| pUcFile = (UCHAR *)(pFileStart + pFileHdr5->commands_offset); |
| uiState = STATE_DONE_DWNLD; |
| break; |
| case REQUEST_CODE_SEGMENT: |
| //DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n"); |
| if (!bGoodVersion) |
| { |
| DEBUG("FT1000:download:Download error: Got Code Segment request before image offset request.\n"); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| #if 0 |
| word_length = get_request_value_usb(ft1000dev); |
| //DEBUG("FT1000:download:word_length = %d\n", (int)word_length); |
| if (word_length > MAX_LENGTH/2) |
| #else |
| word_length = get_request_value(ft1000dev); |
| //DEBUG("FT1000:download:word_length = %d\n", (int)word_length); |
| if (word_length > MAX_LENGTH) |
| #endif |
| { |
| DEBUG("FT1000:download:Download error: Max length exceeded\n"); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| if ( (word_length*2 + pUcFile) > pCodeEnd) |
| { |
| /* |
| * Error, beyond boot code range. |
| */ |
| DEBUG("FT1000:download:Download error: Requested len=%d exceeds DSP code boundry.\n", |
| (int)word_length); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| /* |
| * Position ASIC DPRAM auto-increment pointer. |
| */ |
| dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; |
| if (word_length & 0x1) |
| word_length++; |
| word_length = word_length / 2; |
| |
| #if FIFO_DNLD |
| write_blk_fifo (ft1000dev, &pUsFile, &pUcFile, word_length); |
| if (pft1000info->usbboot == 0) |
| pft1000info->usbboot++; |
| if (pft1000info->usbboot == 1) { |
| tempword = 0; |
| ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_PS_HDR_LOC, tempword, 0); |
| } |
| #else |
| write_blk (ft1000dev, &pUsFile, &pUcFile, word_length); |
| //ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)pUcFile, word_length); |
| #endif |
| break; |
| |
| case REQUEST_MAILBOX_DATA: |
| DEBUG("FT1000:download: REQUEST_MAILBOX_DATA\n"); |
| // Convert length from byte count to word count. Make sure we round up. |
| word_length = (long)(pft1000info->DSPInfoBlklen + 1)/2; |
| put_request_value(ft1000dev, word_length); |
| pMailBoxData = (PDRVMSG)&(pft1000info->DSPInfoBlk[0]); |
| /* |
| * Position ASIC DPRAM auto-increment pointer. |
| */ |
| |
| |
| pUsData = (USHORT *)&pMailBoxData->data[0]; |
| dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; |
| if (word_length & 0x1) |
| word_length++; |
| |
| word_length = (word_length / 2); |
| |
| |
| for (; word_length > 0; word_length--) /* In words */ |
| { |
| |
| templong = *pUsData++; |
| templong |= (*pUsData++ << 16); |
| Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong); |
| |
| } |
| break; |
| |
| case REQUEST_VERSION_INFO: |
| DEBUG("FT1000:download:REQUEST_VERSION_INFO\n"); |
| word_length = pFileHdr5->version_data_size; |
| put_request_value(ft1000dev, word_length); |
| /* |
| * Position ASIC DPRAM auto-increment pointer. |
| */ |
| |
| pUsFile = (USHORT *)(pFileStart + pFileHdr5->version_data_offset); |
| |
| |
| dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; |
| if (word_length & 0x1) |
| word_length++; |
| |
| word_length = (word_length / 2); |
| |
| |
| for (; word_length > 0; word_length--) /* In words */ |
| { |
| |
| templong = ntohs(*pUsFile++); |
| temp = ntohs(*pUsFile++); |
| templong |= (temp << 16); |
| Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong); |
| |
| } |
| break; |
| |
| case REQUEST_CODE_BY_VERSION: |
| DEBUG("FT1000:download:REQUEST_CODE_BY_VERSION\n"); |
| bGoodVersion = FALSE; |
| requested_version = get_request_value(ft1000dev); |
| |
| pDspImageInfoV6 = (PDSP_IMAGE_INFO_V6)(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 == (ULONG)requested_version) |
| { |
| bGoodVersion = TRUE; |
| DEBUG("FT1000:download: bGoodVersion is TRUE\n"); |
| pUsFile = (USHORT *)(pFileStart + pDspImageInfoV6->begin_offset); |
| pUcFile = (UCHAR *)(pFileStart + pDspImageInfoV6->begin_offset); |
| pCodeEnd = (UCHAR *)(pFileStart + pDspImageInfoV6->end_offset); |
| run_address = pDspImageInfoV6->run_address; |
| run_size = pDspImageInfoV6->image_size; |
| image_chksum = (ULONG)pDspImageInfoV6->checksum; |
| break; |
| } |
| pDspImageInfoV6++; |
| |
| |
| } //end of for |
| |
| if (!bGoodVersion) |
| { |
| /* |
| * Error, beyond boot code range. |
| */ |
| DEBUG("FT1000:download:Download error: Bad Version Request = 0x%x.\n",(int)requested_version); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| break; |
| |
| default: |
| DEBUG("FT1000:download:Download error: Bad request type=%d in CODE download state.\n",request); |
| Status = STATUS_FAILURE; |
| break; |
| } |
| if (pft1000info->usbboot) |
| put_handshake_usb(ft1000dev, HANDSHAKE_RESPONSE); |
| else |
| put_handshake(ft1000dev, HANDSHAKE_RESPONSE); |
| } |
| else |
| { |
| DEBUG("FT1000:download:Download error: Handshake failed\n"); |
| Status = STATUS_FAILURE; |
| } |
| |
| break; |
| |
| case STATE_DONE_DWNLD: |
| DEBUG("FT1000:download:Code loader is done...\n"); |
| uiState = STATE_SECTION_PROV; |
| break; |
| |
| case STATE_SECTION_PROV: |
| DEBUG("FT1000:download:STATE_SECTION_PROV\n"); |
| 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, &pft1000info->prov_list); |
| // Move to next entry if available |
| pUcFile = (UCHAR *)((unsigned long)pUcFile + (UINT)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(PSEUDO_HDR)); |
| if ( (unsigned long)(pUcFile) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) { |
| uiState = STATE_DONE_FILE; |
| } |
| } |
| else { |
| kfree(pbuffer); |
| Status = STATUS_FAILURE; |
| } |
| } |
| else { |
| Status = STATUS_FAILURE; |
| } |
| } |
| else |
| { |
| /* Checksum did not compute */ |
| Status = STATUS_FAILURE; |
| } |
| DEBUG("ft1000:download: after STATE_SECTION_PROV, uiState = %d, Status= %d\n", uiState, Status); |
| break; |
| |
| case STATE_DONE_PROV: |
| DEBUG("FT1000:download:STATE_DONE_PROV\n"); |
| uiState = STATE_DONE_FILE; |
| break; |
| |
| |
| default: |
| Status = STATUS_FAILURE; |
| break; |
| } /* End Switch */ |
| |
| if (Status != STATUS_SUCCESS) { |
| break; |
| } |
| |
| /**** |
| // Check if Card is present |
| Status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK); |
| if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) { |
| break; |
| } |
| |
| Status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID); |
| if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) { |
| break; |
| } |
| ****/ |
| |
| } /* End while */ |
| |
| DEBUG("Download exiting with status = 0x%8x\n", Status); |
| ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL); |
| |
| return Status; |
| } |
| |