Пример #1
0
int android_request_firmware(const struct firmware **firmware_p, const char *name,
                     struct device *device)
{
    int ret = 0;
    struct firmware *firmware;
    char filename[256];
    const char *raw_filename = name;
	*firmware_p = firmware = A_MALLOC(sizeof(*firmware));
    if (!firmware) 
		return -ENOMEM;
    A_MEMZERO(firmware, sizeof(*firmware));
	sprintf(filename, "%s/%s", fwpath, raw_filename);
#ifdef TARGET_EUROPA
    if (strcmp(raw_filename, "softmac")==0) {
        sprintf(filename, "/data/.nvmac.info");
    }
#endif /* TARGET_EUROPA */
    do {
        size_t length, bufsize, bmisize;

        if ( (ret=android_readwrite_file(filename, NULL, NULL, 0)) < 0) {
            break;
        } else {
            length = ret;
        }
    
        bufsize = ALIGN(length, PAGE_SIZE);
        bmisize = A_ROUND_UP(length, 4);
        bufsize = max(bmisize, bufsize);
        firmware->data = vmalloc(bufsize);
        firmware->size = length;
        if (!firmware->data) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: Cannot allocate buffer for firmware\n", __FUNCTION__));
            ret = -ENOMEM;
            break;
        }
    
        if ( (ret=android_readwrite_file(filename, (char*)firmware->data, NULL, length)) != length) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: file read error, ret %d request %d\n", __FUNCTION__, ret, length));
            ret = -1;
            break;
        }
    
    } while (0);

    if (ret<0) {
        if (firmware) {
            if (firmware->data)
                vfree(firmware->data);
            A_FREE(firmware);
        }
        *firmware_p = NULL;
    } else {
        ret = 0;
    }
    return ret;    
}
Пример #2
0
int android_request_firmware(const struct firmware **firmware_p, const char *name,
                     struct device *device)
{
    int ret = 0;
    struct firmware *firmware;
    char filename[256];
    const char *raw_filename = name;
	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
    if (!firmware) 
		return -ENOMEM;
	sprintf(filename, "%s/%s", fwpath, raw_filename);
    do {
        size_t length, bufsize, bmisize;

        if ( (ret=android_readwrite_file(filename, NULL, NULL, 0)) < 0) {
            break;
        } else {
            length = ret;
        }
    
        bufsize = ALIGN(length, PAGE_SIZE);
        bmisize = A_ROUND_UP(length, 4);
        bufsize = max(bmisize, bufsize);
        firmware->data = vmalloc(bufsize);
        firmware->size = bmisize;
        if (!firmware->data) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: Cannot allocate buffer for firmware\n", __FUNCTION__));
            ret = -ENOMEM;
            break;
        }
    
        if ( (ret=android_readwrite_file(filename, (char*)firmware->data, NULL, length)) != length) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: file read error, ret %d request %d\n", __FUNCTION__, ret, length));
            ret = -1;
            break;
        }
    
    } while (0);

    if (ret<0) {
        if (firmware) {
            if (firmware->data)
                vfree(firmware->data);
            kfree(firmware);
        }
        *firmware_p = NULL;
    } else {
        ret = 0;
    }
    return ret;    
}
/*
 * Allocate nbytes from the arena.  At this point, which_arena should
 * be set to 0 for the default (and only) arena.  A future allocation
 * module may support multiple separate arenas.
 */
LOCAL void *
cmnos_allocram(void * which_arena, A_UINT32 nbytes)
{
    void *ptr = (void *)allocram_current_addr;
    //nbytes = A_ROUND_UP(nbytes, A_CACHE_LINE_SIZE);
    nbytes = A_ROUND_UP(nbytes, 4);
    if (nbytes <= allocram_remaining_bytes) {
        allocram_remaining_bytes -= nbytes;
        allocram_current_addr += nbytes;
    } else {
        A_PRINTF("RAM allocation (%d bytes) failed!\n", nbytes);
        //A_ASSERT(0);
        adf_os_assert(0);
    }

    return ptr;
}
LOCAL void *
cmnos_allocram_init(void *arena_start, A_UINT32 arena_sz)
{
    A_UINT32 astart = (A_UINT32)arena_start;

#if defined(__XTENSA__)
    /*
     * This hacky line converts from a text or data RAM address
     * into a data RAM address.  (It's all the same on MIPS, but
     * text and data are different address spaces on Xtensa.)
     */
    //astart = TARG_RAM_ADDRS(TARG_RAM_OFFSET(astart));
#endif

#if 0
    if (arena_sz == 0) {
        /* Default arena_sz to most of available RAM */
        arena_sz = TARG_RAM_SZ - (A_UINT32)TARG_RAM_OFFSET(astart);
        arena_sz -= HOST_INTEREST->hi_end_RAM_reserve_sz;
    }
#endif

    /* Clear entire area */
//    A_MEMSET(astart, 0, arena_sz);

    /* Adjust for cache line alignment */
#if 0    
    allocram_current_addr = A_ROUND_UP(astart, A_CACHE_LINE_SIZE);
    arena_sz -= (allocram_current_addr-astart);
#else
    allocram_current_addr = astart;
#endif    
    allocram_remaining_bytes = arena_sz;

    //A_DCACHE_FLUSH();

    //A_PRINTF("cmnos_allocram_init: start=0x%x size=%d\n",
    //    allocram_current_addr, allocram_remaining_bytes);

    return NULL; /* Future implementation may return an arena handle */
}
Пример #5
0
int
main (int argc, char **argv) {
    int c, s, fd;
    unsigned int address, length;
    unsigned int count, param;
    char filename[PATH_MAX], ifname[IFNAMSIZ];
    unsigned int cmd;
    struct ifreq ifr;
    char *buffer;
    struct stat filestat;
    int flag;
    int target_version = -1;
    int target_type = -1;
    unsigned int bitwise_mask;
    
    progname = argv[0];
    if (argc == 1) usage();

    flag = 0;
    memset(filename, '\0', sizeof(filename));
    memset(ifname, '\0', IFNAMSIZ);
    strcpy(ifname, "eth1");
    s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0) err(1, "socket");

    while (1) {
        int option_index = 0;
        static struct option long_options[] = {
            {"get", 0, NULL, 'g'},
            {"set", 0, NULL, 's'},
            {"read", 0, NULL, 'r'},
            {"test", 0, NULL, 't'},
            {"file", 1, NULL, 'f'},
            {"done", 0, NULL, 'd'},
            {"write", 0, NULL, 'w'},
            {"begin", 0, NULL, 'b'},
            {"count", 1, NULL, 'c'},
            {"param", 1, NULL, 'p'},
            {"length", 1, NULL, 'l'},
            {"execute", 0, NULL, 'e'},
            {"address", 1, NULL, 'a'},
            {"interface", 1, NULL, 'i'},
            {"info", 0, NULL, 'I'},
            {"and", 1, NULL, 'n'},
            {"or", 1, NULL, 'o'},
            {"quiet", 0, NULL, 'q'},
            {"uncompress", 0, NULL, 'u'},
            {0, 0, 0, 0}
        };

        c = getopt_long (argc, argv, "rwtebdgsIqf:l:a:p:i:c:n:o:",
                         long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'r':
            cmd = BMI_READ_MEMORY;
            break;

        case 'w':
            cmd = BMI_WRITE_MEMORY;
            break;

        case 'e':
            cmd = BMI_EXECUTE;
            break;

        case 'b':
            cmd = BMI_SET_APP_START;
            break;

        case 'd':
            cmd = BMI_DONE;
            break;

        case 'g':
            cmd = BMI_READ_SOC_REGISTER;
            break;

        case 's':
            cmd = BMI_WRITE_SOC_REGISTER;
            break;

        case 't':
            cmd = BMI_TEST;
            break;

        case 'f':
            memset(filename, '\0', sizeof(filename));
            strncpy(filename, optarg, sizeof(filename));
            flag |= FILE_FLAG;
            break;

        case 'l':
            length = atoi(optarg);
            flag |= LENGTH_FLAG;
            break;

        case 'a':
            address = strtoul(optarg, NULL, 0);
            flag |= ADDRESS_FLAG;
            break;

        case 'p':
            param = strtoul(optarg, NULL, 0);
            flag |= PARAM_FLAG;
            break;

        case 'c':
            count = atoi(optarg);
            flag |= COUNT_FLAG;
            break;

        case 'i':
            memset(ifname, '\0', 8);
            strcpy(ifname, optarg);
            break;

        case 'I':
            cmd = BMI_GET_TARGET_INFO;
            break;
            
        case 'n':
            flag |= PARAM_FLAG | AND_OP_FLAG | BITWISE_OP_FLAG;
            bitwise_mask = strtoul(optarg, NULL, 0);
            break;
            
        case 'o':                
            flag |= PARAM_FLAG | BITWISE_OP_FLAG;
            bitwise_mask = strtoul(optarg, NULL, 0);
            break;

        case 'q':
            flag |= QUIET_FLAG;
            break;
            
        case 'u':
            flag |= UNCOMPRESS_FLAG;
            break;
            
        default:
            usage();
        }
    }

    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    /* Verify that the Target is alive.  If not, wait for it. */
    {
        int rv;
        static int waiting_msg_printed = 0;

        buffer = (char *)MALLOC(sizeof(struct bmi_target_info));
        ((int *)buffer)[0] = AR6000_XIOCTL_TARGET_INFO;
        ifr.ifr_data = buffer;
        while ((rv=ioctl(s, AR6000_IOCTL_EXTENDED, &ifr)) < 0)
        {
            if (errno == ENODEV) {
                /* 
                 * Give the Target device a chance to start.
                 * Then loop back and see if it's alive.
                 */
                if (!waiting_msg_printed) {
                    nqprintf("bmiloader is waiting for Target....\n");
                    waiting_msg_printed = 1;
                }
                usleep(100000); /* Wait for 100ms */
            } else {
                printf("Unexpected error on AR6000_XIOCTL_TARGET_INFO: %d\n", rv);
                exit(1);
            }
        }
        target_version = ((int *)buffer)[0];
        target_type = ((int *)buffer)[1];
        free(buffer);
    }
    switch(cmd)
    {
    case BMI_DONE:
        nqprintf("BMI Done\n");
        buffer = (char *)MALLOC(4);
        ((int *)buffer)[0] = AR6000_XIOCTL_BMI_DONE;
        ifr.ifr_data = buffer;
        if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
        {
            err(1, ifr.ifr_name);
        }
        free(buffer);
        break;

    case BMI_TEST:
        if ((flag & (COUNT_FLAG | LENGTH_FLAG | ADDRESS_FLAG)) == 
            (COUNT_FLAG | LENGTH_FLAG | ADDRESS_FLAG))
        {
            nqprintf("BMI Test (address: 0x%x, length: %d, count: %d)\n", 
                    address, length, count);
            buffer = (char *)MALLOC(16);
            ((int *)buffer)[0] = AR6000_XIOCTL_BMI_TEST;
            ((int *)buffer)[1] = address;
            ((int *)buffer)[2] = length;
            ((int *)buffer)[3] = count;
            ifr.ifr_data = buffer;
            if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
            {
                err(1, ifr.ifr_name);
            }
            free(buffer);
        }
        else usage();
        break;

    case BMI_READ_MEMORY:
        if ((flag & (ADDRESS_FLAG | LENGTH_FLAG | FILE_FLAG)) == 
            (ADDRESS_FLAG | LENGTH_FLAG | FILE_FLAG))
        {
            nqprintf(
                 "BMI Read Memory (address: 0x%x, length: %d, filename: %s)\n",
                  address, length, filename);

            if ((fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC, 00644)) < 0)
            {
                perror("Could not create a file");
                exit(1);
            }
            buffer = (char *)MALLOC(MAX_BUF + 12);

            {
                unsigned int remaining = length;

                while (remaining)
                {
                    length = (remaining > MAX_BUF) ? MAX_BUF : remaining;
                    ((int *)buffer)[0] = AR6000_XIOCTL_BMI_READ_MEMORY;
                    ((int *)buffer)[1] = address;

                    /*
                     * We round up the requested length because some
                     * SDIO Host controllers can't handle other lengths;
                     * but we still only write the requested number of
                     * bytes to the file.
                     */
                    ((int *)buffer)[2] = A_ROUND_UP(length, 4);
                    ifr.ifr_data = buffer;
                    if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
                    {
                        err(1, ifr.ifr_name);
                    }
                    else
                    {
                        write(fd, buffer, length);
                    }

                    remaining -= length;
                    address += length;
                }
            }

            close(fd);
            free(buffer);
        }
        else usage();
        break;

    case BMI_WRITE_MEMORY:
        if (!(flag & ADDRESS_FLAG))
        {
            usage(); /* no address specified */
        }
        if (!(flag & (FILE_FLAG | PARAM_FLAG)))
        {
            usage(); /* no data specified */
        }
        if ((flag & FILE_FLAG) && (flag & PARAM_FLAG))
        {
            usage(); /* too much data specified */
        }
        if ((flag & UNCOMPRESS_FLAG) && !(flag & FILE_FLAG))
        {
            usage(); /* uncompress only works with a file */
        }

        if (flag & FILE_FLAG)
        {
            nqprintf(
                 "BMI Write %sMemory (address: 0x%x, filename: %s)\n",
                  ((flag & UNCOMPRESS_FLAG) ? "compressed " : ""),
                  address, filename);
            if ((fd = open(filename, O_RDONLY)) < 0)
            {
                perror("Could not open file");
                exit(1);
            }
            memset(&filestat, '\0', sizeof(struct stat));
            buffer = (char *)MALLOC(MAX_BUF + 12);
            fstat(fd, &filestat);
            length = filestat.st_size;

            if (flag & UNCOMPRESS_FLAG) {
                /* Initiate compressed stream */
                ((int *)buffer)[0] = AR6000_XIOCTL_BMI_LZ_STREAM_START;
                ((int *)buffer)[1] = address;
                if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
                {
                    err(1, ifr.ifr_name);
                }
            }
        }
        else
        { /* PARAM_FLAG */
            nqprintf(
                 "BMI Write Memory (address: 0x%x, value: 0x%x)\n",
                  address, param);
            length = sizeof(param);
            buffer = (char *)MALLOC(length + 12);
            *(unsigned int *)(&buffer[12]) = param;
            fd = -1;
        }

        /*
         * Write length bytes of data to memory.
         * Data is either present in buffer OR
         * needs to be read from fd in MAX_BUF chunks.
         *
         * Within the kernel, the implementation of
         * AR6000_XIOCTL_BMI_WRITE_MEMORY further
         * limits the size of each transfer over the
         * interconnect according to BMI protocol
         * limitations.
         */ 
        {
            unsigned int remaining = length;
            int *pLength;

            while (remaining)
            {
                length = (remaining > MAX_BUF) ? MAX_BUF : remaining;
                if (flag & UNCOMPRESS_FLAG) {
                    /* 0 pad last word of data to avoid messy uncompression */
                    ((A_UINT32 *)buffer)[2+((length-1)/4)] = 0;

                    if (read(fd, &buffer[8], length) != length)
                    {
                        perror("read from compressed file failed");
                        exit(1);
                    }
                    ((int *)buffer)[0] = AR6000_XIOCTL_BMI_LZ_DATA;
                    pLength = &((int *)buffer)[1];
                } else {
                    if (fd > 0)
                    {
                        if (read(fd, &buffer[12], length) != length)
                        {
                            perror("read from file failed");
                            exit(1);
                        }
                    }

                    ((int *)buffer)[0] = AR6000_XIOCTL_BMI_WRITE_MEMORY;
                    ((int *)buffer)[1] = address;
                    pLength = &((int *)buffer)[2];
                }

                /*
                 * We round up the requested length because some
                 * SDIO Host controllers can't handle other lengths.
                 * This generally isn't a problem for users, but it's
                 * something to be aware of.
                 */
                *pLength = A_ROUND_UP(length, 4);
                ifr.ifr_data = buffer;
                while (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
                {
                    err(1, ifr.ifr_name);
                }

                remaining -= length;
                address += length;
            }
        }

        free(buffer);
        if (fd > 0)
        {
            close(fd);
            if (flag & UNCOMPRESS_FLAG) {
                /*
                 * Close compressed stream and open a new (fake)
                 * one.  This serves mainly to flush Target caches.
                 */
                ((int *)buffer)[0] = AR6000_XIOCTL_BMI_LZ_STREAM_START;
                ((int *)buffer)[1] = 0;
                if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
                {
                    err(1, ifr.ifr_name);
                }
            }
        }

        break;

    case BMI_READ_SOC_REGISTER:
        if ((flag & (ADDRESS_FLAG)) == (ADDRESS_FLAG))
        {
            nqprintf("BMI Read Register (address: 0x%x)\n", address);
            buffer = (char *)MALLOC(8);
            ((int *)buffer)[0] = AR6000_XIOCTL_BMI_READ_SOC_REGISTER;
            ((int *)buffer)[1] = address;
            ifr.ifr_data = buffer;
            if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
            {
                err(1, ifr.ifr_name);
            }
            param = ((int *)buffer)[0];
            if (quiet()) {
                printf("0x%x\n", param);
            } else {
                printf("Return Value from target: 0x%x\n", param);
            }
            free(buffer);
        }
        else usage();
        break;

    case BMI_WRITE_SOC_REGISTER:
        if ((flag & (ADDRESS_FLAG | PARAM_FLAG)) == (ADDRESS_FLAG | PARAM_FLAG))
        {
            int origvalue = 0;
            
            if (flag & BITWISE_OP_FLAG) {
                /* first read */    
                buffer = (char *)MALLOC(8);
                ((int *)buffer)[0] = AR6000_XIOCTL_BMI_READ_SOC_REGISTER;
                ((int *)buffer)[1] = address;
                ifr.ifr_data = buffer;
                if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
                {
                    err(1, ifr.ifr_name);
                }
                param = ((int *)buffer)[0];
                origvalue = param;
                free(buffer);
                
                /* now modify */
                if (flag & AND_OP_FLAG) {
                    param &= bitwise_mask;        
                } else {
                    param |= bitwise_mask;
                }               
            
                /* fall through to write out the parameter */
            }
            
            if (flag & BITWISE_OP_FLAG) {
                if (quiet()) {
                    printf("0x%x\n", origvalue);
                } else {
                    printf("BMI Bit-Wise (%s) modify Register (address: 0x%x, orig:0x%x, new: 0x%x,  mask:0x%X)\n", 
                       (flag & AND_OP_FLAG) ? "AND" : "OR", address, origvalue, param, bitwise_mask );   
                }
            } else{ 
                nqprintf("BMI Write Register (address: 0x%x, param: 0x%x)\n", address, param);
            }
            
            buffer = (char *)MALLOC(12);
            ((int *)buffer)[0] = AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER;
            ((int *)buffer)[1] = address;
            ((int *)buffer)[2] = param;
            ifr.ifr_data = buffer;
            if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
            {
                err(1, ifr.ifr_name);
            }
            free(buffer);
        }
        else usage();
        break;

    case BMI_EXECUTE:
        if ((flag & (ADDRESS_FLAG | PARAM_FLAG)) == (ADDRESS_FLAG | PARAM_FLAG))
        {
            nqprintf("BMI Execute (address: 0x%x, param: 0x%x)\n", address, param);
            buffer = (char *)MALLOC(12);
            ((int *)buffer)[0] = AR6000_XIOCTL_BMI_EXECUTE;
            ((int *)buffer)[1] = address;
            ((int *)buffer)[2] = param;
            ifr.ifr_data = buffer;
            if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
            {
                err(1, ifr.ifr_name);
            }
            param = ((int *)buffer)[0];
            if (quiet()) {
                printf("0x%x\n", param);
            } else {
                printf("Return Value from target: 0x%x\n", param);
            }
            free(buffer);
        }
        else usage();
        break;

    case BMI_SET_APP_START:
        if ((flag & ADDRESS_FLAG) == ADDRESS_FLAG)
        {
            nqprintf("BMI Set App Start (address: 0x%x)\n", address);
            buffer = (char *)MALLOC(8);
            ((int *)buffer)[0] = AR6000_XIOCTL_BMI_SET_APP_START;
            ((int *)buffer)[1] = address;
            ifr.ifr_data = buffer;
            if (ioctl(s, AR6000_IOCTL_EXTENDED, &ifr) < 0)
            {
                err(1, ifr.ifr_name);
            }
            free(buffer);
        }
        else usage();
        break;
    case BMI_GET_TARGET_INFO:
        nqprintf("BMI Target Info:\n");
        printf("TARGET_TYPE=%s\n",
                (target_type == TARGET_TYPE_AR6001) ? "AR6001" :
                ((target_type == TARGET_TYPE_AR6002) ? "AR6002" : 
                (((target_type == TARGET_TYPE_AR6003) ? "AR6003" : "unknown"))));
        printf("TARGET_VERSION=0x%x\n", target_version);
        break;

    default:
        usage();
    }

    exit (0);
}
Пример #6
0
A_STATUS download_binary (HIF_DEVICE *hifDevice,
                          A_UINT32 address,
                          wchar_t *fileName,
                          wchar_t *fileRoot,
                          A_BOOL  bCompressed,
                          AR6K_BIN_CACHE_INFO *pBinCache)
{
    A_STATUS status = A_OK;
    A_UCHAR  *buffer = NULL;
    A_UINT32 length = 0;
    A_UINT32 fileSize = 0;
    A_UINT32 next_address=0;
    A_INT32 file_left = 0;
    size_t nSize;
    wchar_t filePath[128];
    HANDLE fd = NULL;
    BY_HANDLE_FILE_INFORMATION finfo;
    A_BOOL  fillCache = FALSE;

    A_MEMZERO(&finfo, sizeof(finfo));
    if ( wcslen(fileName) + wcslen(fileRoot) > 127 )
    {
         ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Name Very Long :: ====>");
         return A_ERROR;
    }

    wcscpy(filePath,fileRoot);
    wcscat(filePath,fileName);


    ATHR_DISPLAY_MSG (L"file %s \n",filePath);
    do
    {
        if (pBinCache->Valid) {

                /* binary cache is valid */
            if (bCompressed) {
                status = BMILZStreamStart (hifDevice, address);
                if (A_FAILED(status)) {
                    break;
                }
            }

            if (bCompressed) {
                A_UINT32  lastWord = 0;
                A_UINT32  lastWordOffset = pBinCache->ActualLength & ~0x3;
                A_UINT32  unalignedBytes = pBinCache->ActualLength & 0x3;

                if (unalignedBytes) {
                        /* copy the last word into a zero padded buffer */
                    A_MEMCPY(&lastWord,
                             &pBinCache->pData[lastWordOffset],
                             unalignedBytes);
                }

                status = BMILZData(hifDevice,
                                   pBinCache->pData,
                                   lastWordOffset);

                if (A_FAILED(status)) {
                    break;
                }

                if (unalignedBytes) {
                    status = BMILZData(hifDevice,
                                       (A_UINT8 *)&lastWord,
                                       4);
                }

            } else {
                status = BMIWriteMemory(hifDevice,
                                        address,
                                        pBinCache->pData,
                                        A_ROUND_UP(pBinCache->ActualLength,4));
            }

            if (bCompressed && A_SUCCESS(status)) {
                //
                // Close compressed stream and open a new (fake) one.  This serves mainly to flush Target caches.
                //
                status = BMILZStreamStart (hifDevice, 0x00);
                if (A_FAILED(status)) {
                    break;
                }
            }

                /* all done */
            break;
        }

        //Determine the length of the file
        if ( (fd = CreateFile (filePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
        {
            status = A_ERROR;
            ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Not Found :: ====> %s", filePath);
            break;
        }

        if (!GetFileInformationByHandle(fd, &finfo))
        {
            ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Size Error :: ====> %s", filePath);
            status = A_ERROR;
            break;
        }
        fileSize = finfo.nFileSizeLow;
        file_left = fileSize;

        if ((pBinCache->pData != NULL) && (!pBinCache->Static)) {
            /* binary caching is supported */
            A_ASSERT(!pBinCache->Valid);

            if (fileSize <= pBinCache->MaxLength) {
                    /* size if good, flag to cache this binary when read from the filesystem */
                fillCache = TRUE;
                pBinCache->ActualLength = 0; /* reset */
            } else {
                    /* cache is not big enough to hold data */
                A_ASSERT(FALSE);
                ATHR_DISPLAY_MSG (L"AR6K::WARNING!!!! :: File :%s (%d bytes) too big for cache (max=%d)",
                         filePath, fileSize, pBinCache->MaxLength);
            }
        }

        //
        // zero data buffer and init length
        //
        buffer = (A_UCHAR *)A_MALLOC(MAX_BUF);
        if (NULL == buffer)
        {
            status = A_ERROR;
            break;
        }

        if (bCompressed)
        {
            status = BMILZStreamStart (hifDevice, address);
            if (status != A_OK)
            {
                break;
            }
        }


        while (file_left)
        {
            length  = (file_left < (MAX_BUF)) ? file_left : MAX_BUF;
            if (bCompressed)
            {
                //
                // 0 pad last word of data to avoid messy uncompression
                //
                ((A_UINT32 *)buffer)[((length-1)/4)] = 0;
            }

            if (!ReadFile( fd, buffer, length, &nSize, NULL) || nSize != length)
            {
                ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: ReadFile Error :: ====>");
                status = A_ERROR;
                break;
            }
            next_address = address + fileSize - file_left;

            //
            // We round up the requested length because some SDIO Host controllers can't handle other lengths.
            // This generally isn't a problem for users, but it's something to be aware of.
            //
            length = A_ROUND_UP(length, 4);

            if (bCompressed)
            {
                status = BMILZData(hifDevice, buffer, length);
            }
            else
            {
                status = BMIWriteMemory(hifDevice, next_address, buffer, length);
            }

            if (status != A_OK)
            {
               break;
            }

            if (fillCache) {
                CopyChunkToBinCache(pBinCache, buffer, length);
            }

            if (file_left >= MAX_BUF)
            {
                file_left = file_left - MAX_BUF;
            }
            else
            {
                file_left = 0;
            }

        };

        if (status != A_OK)
        {
            break;
        }

        if (fillCache) {
                /* cache was filled, mark it valid */
            pBinCache->Valid = TRUE;
        }

        if (bCompressed)
        {
            //
            // Close compressed stream and open a new (fake) one.  This serves mainly to flush Target caches.
            //
            status = BMILZStreamStart (hifDevice, 0x00);
            if (status != A_OK)
            {
                break;
            }
        }

    } while (FALSE);

    if (buffer)
    {
        free (buffer);
        buffer = NULL;
    }
    if (fd)
    {
        CloseHandle (fd);
    }

    return status;
}