staging: ft1000_pcmcia: staticize local functions in ft1000_dnld.c
[linux-2.6/btrfs-unstable.git] / drivers / staging / ft1000 / ft1000-pcmcia / ft1000_dnld.c
blob612ac0bd375698eb487c2eca4545e19a77cd6678
1 /*---------------------------------------------------------------------------
2 FT1000 driver for Flarion Flash OFDM NIC Device
4 Copyright (C) 2002 Flarion Technologies, All rights reserved.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option) any
9 later version. This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details. You should have received a copy of the GNU General Public
13 License along with this program; if not, write to the
14 Free Software Foundation, Inc., 59 Temple Place -
15 Suite 330, Boston, MA 02111-1307, USA.
16 --------------------------------------------------------------------------
18 Description: This module will handshake with the DSP bootloader to
19 download the DSP runtime image.
21 ---------------------------------------------------------------------------*/
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25 #define __KERNEL_SYSCALLS__
27 #include <linux/module.h>
28 #include <linux/fs.h>
29 #include <linux/mm.h>
30 #include <linux/slab.h>
31 #include <linux/unistd.h>
32 #include <linux/netdevice.h>
33 #include <linux/timer.h>
34 #include <linux/delay.h>
35 #include <linux/io.h>
36 #include <linux/uaccess.h>
37 #include <linux/vmalloc.h>
39 #include "ft1000.h"
40 #include "boot.h"
42 #define MAX_DSP_WAIT_LOOPS 100
43 #define DSP_WAIT_SLEEP_TIME 1 /* 1 millisecond */
45 #define MAX_LENGTH 0x7f0
47 #define DWNLD_MAG_HANDSHAKE_LOC 0x00
48 #define DWNLD_MAG_TYPE_LOC 0x01
49 #define DWNLD_MAG_SIZE_LOC 0x02
50 #define DWNLD_MAG_PS_HDR_LOC 0x03
52 #define DWNLD_HANDSHAKE_LOC 0x02
53 #define DWNLD_TYPE_LOC 0x04
54 #define DWNLD_SIZE_MSW_LOC 0x06
55 #define DWNLD_SIZE_LSW_LOC 0x08
56 #define DWNLD_PS_HDR_LOC 0x0A
58 #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
59 #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
60 #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
61 #define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
62 #define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
64 #define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
65 #define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
67 #define REQUEST_CODE_LENGTH 0x0000
68 #define REQUEST_RUN_ADDRESS 0x0001
69 #define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
70 #define REQUEST_DONE_BL 0x0003
71 #define REQUEST_DONE_CL 0x0004
72 #define REQUEST_VERSION_INFO 0x0005
73 #define REQUEST_CODE_BY_VERSION 0x0006
74 #define REQUEST_MAILBOX_DATA 0x0007
75 #define REQUEST_FILE_CHECKSUM 0x0008
77 #define STATE_START_DWNLD 0x01
78 #define STATE_BOOT_DWNLD 0x02
79 #define STATE_CODE_DWNLD 0x03
80 #define STATE_DONE_DWNLD 0x04
81 #define STATE_SECTION_PROV 0x05
82 #define STATE_DONE_PROV 0x06
83 #define STATE_DONE_FILE 0x07
85 struct dsp_file_hdr {
86 u32 version_id; /* Version ID of this image format. */
87 u32 package_id; /* Package ID of code release. */
88 u32 build_date; /* Date/time stamp when file was built. */
89 u32 commands_offset; /* Offset to attached commands in Pseudo Hdr format. */
90 u32 loader_offset; /* Offset to bootloader code. */
91 u32 loader_code_address; /* Start address of bootloader. */
92 u32 loader_code_end; /* Where bootloader code ends. */
93 u32 loader_code_size;
94 u32 version_data_offset; /* Offset were scrambled version data begins. */
95 u32 version_data_size; /* Size, in words, of scrambled version data. */
96 u32 nDspImages; /* Number of DSP images in file. */
97 } __packed;
99 struct dsp_image_info {
100 u32 coff_date; /* Date/time when DSP Coff image was built. */
101 u32 begin_offset; /* Offset in file where image begins. */
102 u32 end_offset; /* Offset in file where image begins. */
103 u32 run_address; /* On chip Start address of DSP code. */
104 u32 image_size; /* Size of image. */
105 u32 version; /* Embedded version # of DSP code. */
106 unsigned short checksum; /* Dsp File checksum */
107 unsigned short pad1;
108 } __packed;
110 void card_bootload(struct net_device *dev)
112 struct ft1000_info *info = netdev_priv(dev);
113 unsigned long flags;
114 u32 *pdata;
115 u32 size;
116 u32 i;
117 u32 templong;
119 netdev_dbg(dev, "card_bootload is called\n");
121 pdata = (u32 *)bootimage;
122 size = sizeof(bootimage);
124 /* check for odd word */
125 if (size & 0x0003)
126 size += 4;
128 /* Provide mutual exclusive access while reading ASIC registers. */
129 spin_lock_irqsave(&info->dpram_lock, flags);
131 /* need to set i/o base address initially and hardware will autoincrement */
132 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
133 /* write bytes */
134 for (i = 0; i < (size >> 2); i++) {
135 templong = *pdata++;
136 outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
139 spin_unlock_irqrestore(&info->dpram_lock, flags);
142 static u16 get_handshake(struct net_device *dev, u16 expected_value)
144 struct ft1000_info *info = netdev_priv(dev);
145 u16 handshake;
146 u32 tempx;
147 int loopcnt;
149 loopcnt = 0;
150 while (loopcnt < MAX_DSP_WAIT_LOOPS) {
151 if (info->AsicID == ELECTRABUZZ_ID) {
152 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
153 DWNLD_HANDSHAKE_LOC);
155 handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
156 } else {
157 tempx =
158 ntohl(ft1000_read_dpram_mag_32
159 (dev, DWNLD_MAG_HANDSHAKE_LOC));
160 handshake = (u16)tempx;
163 if ((handshake == expected_value)
164 || (handshake == HANDSHAKE_RESET_VALUE)) {
165 return handshake;
167 loopcnt++;
168 mdelay(DSP_WAIT_SLEEP_TIME);
172 return HANDSHAKE_TIMEOUT_VALUE;
176 static void put_handshake(struct net_device *dev, u16 handshake_value)
178 struct ft1000_info *info = netdev_priv(dev);
179 u32 tempx;
181 if (info->AsicID == ELECTRABUZZ_ID) {
182 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
183 DWNLD_HANDSHAKE_LOC);
184 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value); /* Handshake */
185 } else {
186 tempx = (u32)handshake_value;
187 tempx = ntohl(tempx);
188 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */
192 static u16 get_request_type(struct net_device *dev)
194 struct ft1000_info *info = netdev_priv(dev);
195 u16 request_type;
196 u32 tempx;
198 if (info->AsicID == ELECTRABUZZ_ID) {
199 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
200 request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
201 } else {
202 tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
203 tempx = ntohl(tempx);
204 request_type = (u16)tempx;
207 return request_type;
211 static long get_request_value(struct net_device *dev)
213 struct ft1000_info *info = netdev_priv(dev);
214 long value;
215 u16 w_val;
217 if (info->AsicID == ELECTRABUZZ_ID) {
218 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
219 DWNLD_SIZE_MSW_LOC);
221 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
223 value = (long)(w_val << 16);
225 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
226 DWNLD_SIZE_LSW_LOC);
228 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
230 value = (long)(value | w_val);
231 } else {
232 value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
233 value = ntohl(value);
236 return value;
240 static void put_request_value(struct net_device *dev, long lvalue)
242 struct ft1000_info *info = netdev_priv(dev);
243 u16 size;
244 u32 tempx;
246 if (info->AsicID == ELECTRABUZZ_ID) {
247 size = (u16) (lvalue >> 16);
249 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
250 DWNLD_SIZE_MSW_LOC);
252 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
254 size = (u16) (lvalue);
256 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
257 DWNLD_SIZE_LSW_LOC);
259 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
260 } else {
261 tempx = ntohl(lvalue);
262 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx); /* Handshake */
267 static u16 hdr_checksum(struct pseudo_hdr *pHdr)
269 u16 *usPtr = (u16 *)pHdr;
270 u16 chksum;
272 chksum = (((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
273 usPtr[4]) ^ usPtr[5]) ^ usPtr[6];
275 return chksum;
278 int card_download(struct net_device *dev, const u8 *pFileStart,
279 size_t FileLength)
281 struct ft1000_info *info = netdev_priv(dev);
282 int Status = SUCCESS;
283 u32 uiState;
284 u16 handshake;
285 struct pseudo_hdr *pHdr;
286 u16 usHdrLength;
287 long word_length;
288 u16 request;
289 u16 temp;
290 struct prov_record *pprov_record;
291 u8 *pbuffer;
292 struct dsp_file_hdr *pFileHdr5;
293 struct dsp_image_info *pDspImageInfoV6 = NULL;
294 long requested_version;
295 bool bGoodVersion = false;
296 struct drv_msg *pMailBoxData;
297 u16 *pUsData = NULL;
298 u16 *pUsFile = NULL;
299 u8 *pUcFile = NULL;
300 u8 *pBootEnd = NULL;
301 u8 *pCodeEnd = NULL;
302 int imageN;
303 long file_version;
304 long loader_code_address = 0;
305 long loader_code_size = 0;
306 long run_address = 0;
307 long run_size = 0;
308 unsigned long flags;
309 unsigned long templong;
310 unsigned long image_chksum = 0;
312 file_version = *(long *)pFileStart;
313 if (file_version != 6) {
314 pr_err("unsupported firmware version %ld\n", file_version);
315 Status = FAILURE;
318 uiState = STATE_START_DWNLD;
320 pFileHdr5 = (struct dsp_file_hdr *)pFileStart;
322 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->loader_offset);
323 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->loader_offset);
324 pBootEnd = (u8 *) ((long)pFileStart + pFileHdr5->loader_code_end);
325 loader_code_address = pFileHdr5->loader_code_address;
326 loader_code_size = pFileHdr5->loader_code_size;
327 bGoodVersion = false;
329 while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
331 switch (uiState) {
332 case STATE_START_DWNLD:
334 handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
336 if (handshake == HANDSHAKE_DSP_BL_READY)
337 put_handshake(dev, HANDSHAKE_DRIVER_READY);
338 else
339 Status = FAILURE;
341 uiState = STATE_BOOT_DWNLD;
343 break;
345 case STATE_BOOT_DWNLD:
346 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
347 if (handshake == HANDSHAKE_REQUEST) {
349 * Get type associated with the request.
351 request = get_request_type(dev);
352 switch (request) {
353 case REQUEST_RUN_ADDRESS:
354 put_request_value(dev,
355 loader_code_address);
356 break;
357 case REQUEST_CODE_LENGTH:
358 put_request_value(dev,
359 loader_code_size);
360 break;
361 case REQUEST_DONE_BL:
362 /* Reposition ptrs to beginning of code section */
363 pUsFile = (u16 *) ((long)pBootEnd);
364 pUcFile = (u8 *) ((long)pBootEnd);
365 uiState = STATE_CODE_DWNLD;
366 break;
367 case REQUEST_CODE_SEGMENT:
368 word_length = get_request_value(dev);
369 if (word_length > MAX_LENGTH) {
370 Status = FAILURE;
371 break;
373 if ((word_length * 2 + (long)pUcFile) >
374 (long)pBootEnd) {
376 * Error, beyond boot code range.
378 Status = FAILURE;
379 break;
381 /* Provide mutual exclusive access while reading ASIC registers. */
382 spin_lock_irqsave(&info->dpram_lock,
383 flags);
385 * Position ASIC DPRAM auto-increment pointer.
387 outw(DWNLD_MAG_PS_HDR_LOC,
388 dev->base_addr +
389 FT1000_REG_DPRAM_ADDR);
390 if (word_length & 0x01)
391 word_length++;
392 word_length = word_length / 2;
394 for (; word_length > 0; word_length--) { /* In words */
395 templong = *pUsFile++;
396 templong |=
397 (*pUsFile++ << 16);
398 pUcFile += 4;
399 outl(templong,
400 dev->base_addr +
401 FT1000_REG_MAG_DPDATAL);
403 spin_unlock_irqrestore(&info->
404 dpram_lock,
405 flags);
406 break;
407 default:
408 Status = FAILURE;
409 break;
411 put_handshake(dev, HANDSHAKE_RESPONSE);
412 } else {
413 Status = FAILURE;
416 break;
418 case STATE_CODE_DWNLD:
419 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
420 if (handshake == HANDSHAKE_REQUEST) {
422 * Get type associated with the request.
424 request = get_request_type(dev);
425 switch (request) {
426 case REQUEST_FILE_CHECKSUM:
427 netdev_dbg(dev,
428 "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
429 put_request_value(dev, image_chksum);
430 break;
431 case REQUEST_RUN_ADDRESS:
432 if (bGoodVersion) {
433 put_request_value(dev,
434 run_address);
435 } else {
436 Status = FAILURE;
437 break;
439 break;
440 case REQUEST_CODE_LENGTH:
441 if (bGoodVersion) {
442 put_request_value(dev,
443 run_size);
444 } else {
445 Status = FAILURE;
446 break;
448 break;
449 case REQUEST_DONE_CL:
450 /* Reposition ptrs to beginning of provisioning section */
451 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->commands_offset);
452 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->commands_offset);
453 uiState = STATE_DONE_DWNLD;
454 break;
455 case REQUEST_CODE_SEGMENT:
456 if (!bGoodVersion) {
457 Status = FAILURE;
458 break;
460 word_length = get_request_value(dev);
461 if (word_length > MAX_LENGTH) {
462 Status = FAILURE;
463 break;
465 if ((word_length * 2 + (long)pUcFile) >
466 (long)pCodeEnd) {
468 * Error, beyond boot code range.
470 Status = FAILURE;
471 break;
474 * Position ASIC DPRAM auto-increment pointer.
476 outw(DWNLD_MAG_PS_HDR_LOC,
477 dev->base_addr +
478 FT1000_REG_DPRAM_ADDR);
479 if (word_length & 0x01)
480 word_length++;
481 word_length = word_length / 2;
483 for (; word_length > 0; word_length--) { /* In words */
484 templong = *pUsFile++;
485 templong |=
486 (*pUsFile++ << 16);
487 pUcFile += 4;
488 outl(templong,
489 dev->base_addr +
490 FT1000_REG_MAG_DPDATAL);
492 break;
494 case REQUEST_MAILBOX_DATA:
495 /* Convert length from byte count to word count. Make sure we round up. */
496 word_length =
497 (long)(info->DSPInfoBlklen + 1) / 2;
498 put_request_value(dev, word_length);
499 pMailBoxData =
500 (struct drv_msg *)&info->DSPInfoBlk[0];
501 pUsData =
502 (u16 *)&pMailBoxData->data[0];
503 /* Provide mutual exclusive access while reading ASIC registers. */
504 spin_lock_irqsave(&info->dpram_lock,
505 flags);
506 if (file_version == 5) {
508 * Position ASIC DPRAM auto-increment pointer.
510 ft1000_write_reg(dev,
511 FT1000_REG_DPRAM_ADDR,
512 DWNLD_PS_HDR_LOC);
514 for (; word_length > 0; word_length--) { /* In words */
515 temp = ntohs(*pUsData);
516 ft1000_write_reg(dev,
517 FT1000_REG_DPRAM_DATA,
518 temp);
519 pUsData++;
521 } else {
523 * Position ASIC DPRAM auto-increment pointer.
525 outw(DWNLD_MAG_PS_HDR_LOC,
526 dev->base_addr +
527 FT1000_REG_DPRAM_ADDR);
528 if (word_length & 0x01)
529 word_length++;
531 word_length = word_length / 2;
533 for (; word_length > 0; word_length--) { /* In words */
534 templong = *pUsData++;
535 templong |=
536 (*pUsData++ << 16);
537 outl(templong,
538 dev->base_addr +
539 FT1000_REG_MAG_DPDATAL);
542 spin_unlock_irqrestore(&info->
543 dpram_lock,
544 flags);
545 break;
547 case REQUEST_VERSION_INFO:
548 word_length =
549 pFileHdr5->version_data_size;
550 put_request_value(dev, word_length);
551 pUsFile =
552 (u16 *) ((long)pFileStart +
553 pFileHdr5->
554 version_data_offset);
555 /* Provide mutual exclusive access while reading ASIC registers. */
556 spin_lock_irqsave(&info->dpram_lock,
557 flags);
559 * Position ASIC DPRAM auto-increment pointer.
561 outw(DWNLD_MAG_PS_HDR_LOC,
562 dev->base_addr +
563 FT1000_REG_DPRAM_ADDR);
564 if (word_length & 0x01)
565 word_length++;
566 word_length = word_length / 2;
568 for (; word_length > 0; word_length--) { /* In words */
569 templong =
570 ntohs(*pUsFile++);
571 temp =
572 ntohs(*pUsFile++);
573 templong |=
574 (temp << 16);
575 outl(templong,
576 dev->base_addr +
577 FT1000_REG_MAG_DPDATAL);
579 spin_unlock_irqrestore(&info->
580 dpram_lock,
581 flags);
582 break;
584 case REQUEST_CODE_BY_VERSION:
585 bGoodVersion = false;
586 requested_version =
587 get_request_value(dev);
588 pDspImageInfoV6 =
589 (struct dsp_image_info *) ((long)
590 pFileStart
592 sizeof
593 (struct dsp_file_hdr));
594 for (imageN = 0;
595 imageN <
596 pFileHdr5->nDspImages;
597 imageN++) {
598 temp = (u16)
599 (pDspImageInfoV6->
600 version);
601 templong = temp;
602 temp = (u16)
603 (pDspImageInfoV6->
604 version >> 16);
605 templong |=
606 (temp << 16);
607 if (templong ==
608 requested_version) {
609 bGoodVersion =
610 true;
611 pUsFile =
612 (u16
613 *) ((long)
614 pFileStart
616 pDspImageInfoV6->
617 begin_offset);
618 pUcFile =
620 *) ((long)
621 pFileStart
623 pDspImageInfoV6->
624 begin_offset);
625 pCodeEnd =
627 *) ((long)
628 pFileStart
630 pDspImageInfoV6->
631 end_offset);
632 run_address =
633 pDspImageInfoV6->
634 run_address;
635 run_size =
636 pDspImageInfoV6->
637 image_size;
638 image_chksum =
639 (u32)
640 pDspImageInfoV6->
641 checksum;
642 netdev_dbg(dev,
643 "ft1000_dnld: image_chksum = 0x%8x\n",
644 (unsigned
645 int)
646 image_chksum);
647 break;
649 pDspImageInfoV6++;
651 if (!bGoodVersion) {
653 * Error, beyond boot code range.
655 Status = FAILURE;
656 break;
658 break;
660 default:
661 Status = FAILURE;
662 break;
664 put_handshake(dev, HANDSHAKE_RESPONSE);
665 } else {
666 Status = FAILURE;
669 break;
671 case STATE_DONE_DWNLD:
672 if (((unsigned long)(pUcFile) - (unsigned long) pFileStart) >=
673 (unsigned long)FileLength) {
674 uiState = STATE_DONE_FILE;
675 break;
678 pHdr = (struct pseudo_hdr *)pUsFile;
680 if (pHdr->portdest == 0x80 /* DspOAM */
681 && (pHdr->portsrc == 0x00 /* Driver */
682 || pHdr->portsrc == 0x10 /* FMM */)) {
683 uiState = STATE_SECTION_PROV;
684 } else {
685 netdev_dbg(dev,
686 "Download error: Bad Port IDs in Pseudo Record\n");
687 netdev_dbg(dev, "\t Port Source = 0x%2.2x\n",
688 pHdr->portsrc);
689 netdev_dbg(dev, "\t Port Destination = 0x%2.2x\n",
690 pHdr->portdest);
691 Status = FAILURE;
694 break;
696 case STATE_SECTION_PROV:
698 pHdr = (struct pseudo_hdr *)pUcFile;
700 if (pHdr->checksum == hdr_checksum(pHdr)) {
701 if (pHdr->portdest != 0x80 /* Dsp OAM */) {
702 uiState = STATE_DONE_PROV;
703 break;
705 usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */
707 /* Get buffer for provisioning data */
708 pbuffer =
709 kmalloc(usHdrLength + sizeof(struct pseudo_hdr),
710 GFP_ATOMIC);
711 if (pbuffer) {
712 memcpy(pbuffer, pUcFile,
713 (u32) (usHdrLength +
714 sizeof(struct pseudo_hdr)));
715 /* link provisioning data */
716 pprov_record =
717 kmalloc(sizeof(struct prov_record),
718 GFP_ATOMIC);
719 if (pprov_record) {
720 pprov_record->pprov_data =
721 pbuffer;
722 list_add_tail(&pprov_record->
723 list,
724 &info->prov_list);
725 /* Move to next entry if available */
726 pUcFile =
727 (u8 *)((unsigned long) pUcFile +
728 (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
729 if ((unsigned long) (pUcFile) -
730 (unsigned long) (pFileStart) >=
731 (unsigned long)FileLength) {
732 uiState =
733 STATE_DONE_FILE;
735 } else {
736 kfree(pbuffer);
737 Status = FAILURE;
739 } else {
740 Status = FAILURE;
742 } else {
743 /* Checksum did not compute */
744 Status = FAILURE;
747 break;
749 case STATE_DONE_PROV:
750 uiState = STATE_DONE_FILE;
751 break;
753 default:
754 Status = FAILURE;
755 break;
756 } /* End Switch */
758 } /* End while */
760 return Status;