staging: ft1000-pcmcia: Fix ft1000_dnld() to work also on 64bit architectures.
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / ft1000 / ft1000-pcmcia / ft1000_dnld.c
blobfb375ea26dd20e06c27418b28bc4c284e4d5a4b5
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 __KERNEL_SYSCALLS__
25 #include <linux/module.h>
26 #include <linux/fs.h>
27 #include <linux/mm.h>
28 #include <linux/slab.h>
29 #include <linux/unistd.h>
30 #include <linux/netdevice.h>
31 #include <linux/timer.h>
32 #include <linux/delay.h>
33 #include <asm/io.h>
34 #include <asm/uaccess.h>
35 #include <linux/vmalloc.h>
37 #include "ft1000_dev.h"
38 #include "ft1000.h"
39 #include "boot.h"
41 #ifdef FT_DEBUG
42 #define DEBUG(n, args...) printk(KERN_DEBUG args);
43 #else
44 #define DEBUG(n, args...)
45 #endif
47 #define MAX_DSP_WAIT_LOOPS 100
48 #define DSP_WAIT_SLEEP_TIME 1 /* 1 millisecond */
50 #define MAX_LENGTH 0x7f0
52 #define DWNLD_MAG_HANDSHAKE_LOC 0x00
53 #define DWNLD_MAG_TYPE_LOC 0x01
54 #define DWNLD_MAG_SIZE_LOC 0x02
55 #define DWNLD_MAG_PS_HDR_LOC 0x03
57 #define DWNLD_HANDSHAKE_LOC 0x02
58 #define DWNLD_TYPE_LOC 0x04
59 #define DWNLD_SIZE_MSW_LOC 0x06
60 #define DWNLD_SIZE_LSW_LOC 0x08
61 #define DWNLD_PS_HDR_LOC 0x0A
63 #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
64 #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
65 #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
66 #define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
67 #define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
69 #define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
70 #define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
72 #define REQUEST_CODE_LENGTH 0x0000
73 #define REQUEST_RUN_ADDRESS 0x0001
74 #define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
75 #define REQUEST_DONE_BL 0x0003
76 #define REQUEST_DONE_CL 0x0004
77 #define REQUEST_VERSION_INFO 0x0005
78 #define REQUEST_CODE_BY_VERSION 0x0006
79 #define REQUEST_MAILBOX_DATA 0x0007
80 #define REQUEST_FILE_CHECKSUM 0x0008
82 #define STATE_START_DWNLD 0x01
83 #define STATE_BOOT_DWNLD 0x02
84 #define STATE_CODE_DWNLD 0x03
85 #define STATE_DONE_DWNLD 0x04
86 #define STATE_SECTION_PROV 0x05
87 #define STATE_DONE_PROV 0x06
88 #define STATE_DONE_FILE 0x07
90 USHORT get_handshake(struct net_device *dev, USHORT expected_value);
91 void put_handshake(struct net_device *dev, USHORT handshake_value);
92 USHORT get_request_type(struct net_device *dev);
93 long get_request_value(struct net_device *dev);
94 void put_request_value(struct net_device *dev, long lvalue);
95 USHORT hdr_checksum(PPSEUDO_HDR pHdr);
97 typedef struct _DSP_FILE_HDR {
98 u32 build_date;
99 u32 dsp_coff_date;
100 u32 loader_code_address;
101 u32 loader_code_size;
102 u32 loader_code_end;
103 u32 dsp_code_address;
104 u32 dsp_code_size;
105 u32 dsp_code_end;
106 u32 reserved[8];
107 } __attribute__ ((packed)) DSP_FILE_HDR, *PDSP_FILE_HDR;
109 typedef struct _DSP_FILE_HDR_5 {
110 u32 version_id; // Version ID of this image format.
111 u32 package_id; // Package ID of code release.
112 u32 build_date; // Date/time stamp when file was built.
113 u32 commands_offset; // Offset to attached commands in Pseudo Hdr format.
114 u32 loader_offset; // Offset to bootloader code.
115 u32 loader_code_address; // Start address of bootloader.
116 u32 loader_code_end; // Where bootloader code ends.
117 u32 loader_code_size;
118 u32 version_data_offset; // Offset were scrambled version data begins.
119 u32 version_data_size; // Size, in words, of scrambled version data.
120 u32 nDspImages; // Number of DSP images in file.
121 } __attribute__ ((packed)) DSP_FILE_HDR_5, *PDSP_FILE_HDR_5;
123 typedef struct _DSP_IMAGE_INFO {
124 u32 coff_date; // Date/time when DSP Coff image was built.
125 u32 begin_offset; // Offset in file where image begins.
126 u32 end_offset; // Offset in file where image begins.
127 u32 run_address; // On chip Start address of DSP code.
128 u32 image_size; // Size of image.
129 u32 version; // Embedded version # of DSP code.
130 } __attribute__ ((packed)) DSP_IMAGE_INFO, *PDSP_IMAGE_INFO;
132 typedef struct _DSP_IMAGE_INFO_V6 {
133 u32 coff_date; // Date/time when DSP Coff image was built.
134 u32 begin_offset; // Offset in file where image begins.
135 u32 end_offset; // Offset in file where image begins.
136 u32 run_address; // On chip Start address of DSP code.
137 u32 image_size; // Size of image.
138 u32 version; // Embedded version # of DSP code.
139 unsigned short checksum; // Dsp File checksum
140 unsigned short pad1;
141 } __attribute__ ((packed)) DSP_IMAGE_INFO_V6, *PDSP_IMAGE_INFO_V6;
143 void card_bootload(struct net_device *dev)
145 FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
146 unsigned long flags;
147 PULONG pdata;
148 UINT size;
149 UINT i;
150 ULONG templong;
152 DEBUG(0, "card_bootload is called\n");
154 pdata = (PULONG) bootimage;
155 size = sizeof(bootimage);
157 // check for odd word
158 if (size & 0x0003) {
159 size += 4;
161 // Provide mutual exclusive access while reading ASIC registers.
162 spin_lock_irqsave(&info->dpram_lock, flags);
164 // need to set i/o base address initially and hardware will autoincrement
165 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
166 // write bytes
167 for (i = 0; i < (size >> 2); i++) {
168 templong = *pdata++;
169 outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
172 spin_unlock_irqrestore(&info->dpram_lock, flags);
175 USHORT get_handshake(struct net_device *dev, USHORT expected_value)
177 FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
178 USHORT handshake;
179 ULONG tempx;
180 int loopcnt;
182 loopcnt = 0;
183 while (loopcnt < MAX_DSP_WAIT_LOOPS) {
184 if (info->AsicID == ELECTRABUZZ_ID) {
185 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
186 DWNLD_HANDSHAKE_LOC);
188 handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
189 } else {
190 tempx =
191 ntohl(ft1000_read_dpram_mag_32
192 (dev, DWNLD_MAG_HANDSHAKE_LOC));
193 handshake = (USHORT) tempx;
196 if ((handshake == expected_value)
197 || (handshake == HANDSHAKE_RESET_VALUE)) {
198 return handshake;
199 } else {
200 loopcnt++;
201 mdelay(DSP_WAIT_SLEEP_TIME);
206 return HANDSHAKE_TIMEOUT_VALUE;
210 void put_handshake(struct net_device *dev, USHORT handshake_value)
212 FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
213 ULONG tempx;
215 if (info->AsicID == ELECTRABUZZ_ID) {
216 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
217 DWNLD_HANDSHAKE_LOC);
218 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value); /* Handshake */
219 } else {
220 tempx = (ULONG) handshake_value;
221 tempx = ntohl(tempx);
222 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */
226 USHORT get_request_type(struct net_device *dev)
228 FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
229 USHORT request_type;
230 ULONG tempx;
232 if (info->AsicID == ELECTRABUZZ_ID) {
233 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
234 request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
235 } else {
236 tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
237 tempx = ntohl(tempx);
238 request_type = (USHORT) tempx;
241 return request_type;
245 long get_request_value(struct net_device *dev)
247 FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
248 long value;
249 USHORT w_val;
251 if (info->AsicID == ELECTRABUZZ_ID) {
252 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
253 DWNLD_SIZE_MSW_LOC);
255 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
257 value = (long)(w_val << 16);
259 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
260 DWNLD_SIZE_LSW_LOC);
262 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
264 value = (long)(value | w_val);
265 } else {
266 value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
267 value = ntohl(value);
270 return value;
274 void put_request_value(struct net_device *dev, long lvalue)
276 FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
277 USHORT size;
278 ULONG tempx;
280 if (info->AsicID == ELECTRABUZZ_ID) {
281 size = (USHORT) (lvalue >> 16);
283 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
284 DWNLD_SIZE_MSW_LOC);
286 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
288 size = (USHORT) (lvalue);
290 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
291 DWNLD_SIZE_LSW_LOC);
293 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
294 } else {
295 tempx = ntohl(lvalue);
296 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx); /* Handshake */
301 USHORT hdr_checksum(PPSEUDO_HDR pHdr)
303 USHORT *usPtr = (USHORT *) pHdr;
304 USHORT chksum;
306 chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
307 usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
309 return chksum;
312 int card_download(struct net_device *dev, const u8 *pFileStart, UINT FileLength)
314 FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
315 int Status = SUCCESS;
316 USHORT DspWordCnt = 0;
317 UINT uiState;
318 USHORT handshake;
319 PPSEUDO_HDR pHdr;
320 USHORT usHdrLength;
321 PDSP_FILE_HDR pFileHdr;
322 long word_length;
323 USHORT request;
324 USHORT temp;
325 PPROV_RECORD pprov_record;
326 PUCHAR pbuffer;
327 PDSP_FILE_HDR_5 pFileHdr5;
328 PDSP_IMAGE_INFO pDspImageInfo = NULL;
329 PDSP_IMAGE_INFO_V6 pDspImageInfoV6 = NULL;
330 long requested_version;
331 BOOLEAN bGoodVersion = 0;
332 PDRVMSG pMailBoxData;
333 USHORT *pUsData = NULL;
334 USHORT *pUsFile = NULL;
335 UCHAR *pUcFile = NULL;
336 UCHAR *pBootEnd = NULL;
337 UCHAR *pCodeEnd = NULL;
338 int imageN;
339 long file_version;
340 long loader_code_address = 0;
341 long loader_code_size = 0;
342 long run_address = 0;
343 long run_size = 0;
344 unsigned long flags;
345 unsigned long templong;
346 unsigned long image_chksum = 0;
349 // Get version id of file, at first 4 bytes of file, for newer files.
351 file_version = *(long *)pFileStart;
353 uiState = STATE_START_DWNLD;
355 pFileHdr = (PDSP_FILE_HDR) pFileStart;
356 pFileHdr5 = (PDSP_FILE_HDR_5) pFileStart;
358 switch (file_version) {
359 case 5:
360 case 6:
361 pUsFile =
362 (USHORT *) ((long)pFileStart + pFileHdr5->loader_offset);
363 pUcFile =
364 (UCHAR *) ((long)pFileStart + pFileHdr5->loader_offset);
366 pBootEnd =
367 (UCHAR *) ((long)pFileStart + pFileHdr5->loader_code_end);
369 loader_code_address = pFileHdr5->loader_code_address;
370 loader_code_size = pFileHdr5->loader_code_size;
371 bGoodVersion = FALSE;
372 break;
374 default:
375 Status = FAILURE;
376 break;
379 while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
381 switch (uiState) {
382 case STATE_START_DWNLD:
384 handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
386 if (handshake == HANDSHAKE_DSP_BL_READY) {
387 put_handshake(dev, HANDSHAKE_DRIVER_READY);
388 } else {
389 Status = FAILURE;
392 uiState = STATE_BOOT_DWNLD;
394 break;
396 case STATE_BOOT_DWNLD:
397 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
398 if (handshake == HANDSHAKE_REQUEST) {
400 * Get type associated with the request.
402 request = get_request_type(dev);
403 switch (request) {
404 case REQUEST_RUN_ADDRESS:
405 put_request_value(dev,
406 loader_code_address);
407 break;
408 case REQUEST_CODE_LENGTH:
409 put_request_value(dev,
410 loader_code_size);
411 break;
412 case REQUEST_DONE_BL:
413 /* Reposition ptrs to beginning of code section */
414 pUsFile = (USHORT *) ((long)pBootEnd);
415 pUcFile = (UCHAR *) ((long)pBootEnd);
416 uiState = STATE_CODE_DWNLD;
417 break;
418 case REQUEST_CODE_SEGMENT:
419 word_length = get_request_value(dev);
420 if (word_length > MAX_LENGTH) {
421 Status = FAILURE;
422 break;
424 if ((word_length * 2 + (long)pUcFile) >
425 (long)pBootEnd) {
427 * Error, beyond boot code range.
429 Status = FAILURE;
430 break;
432 // Provide mutual exclusive access while reading ASIC registers.
433 spin_lock_irqsave(&info->dpram_lock,
434 flags);
435 if (file_version == 5) {
437 * Position ASIC DPRAM auto-increment pointer.
439 ft1000_write_reg(dev,
440 FT1000_REG_DPRAM_ADDR,
441 DWNLD_PS_HDR_LOC);
443 for (; word_length > 0; word_length--) { /* In words */
444 //temp = *pUsFile;
445 //temp = RtlUshortByteSwap(temp);
446 ft1000_write_reg(dev,
447 FT1000_REG_DPRAM_DATA,
448 *pUsFile);
449 pUsFile++;
450 pUcFile += 2;
451 DspWordCnt++;
453 } else {
455 * Position ASIC DPRAM auto-increment pointer.
457 outw(DWNLD_MAG_PS_HDR_LOC,
458 dev->base_addr +
459 FT1000_REG_DPRAM_ADDR);
460 if (word_length & 0x01) {
461 word_length++;
463 word_length = word_length / 2;
465 for (; word_length > 0; word_length--) { /* In words */
466 templong = *pUsFile++;
467 templong |=
468 (*pUsFile++ << 16);
469 pUcFile += 4;
470 outl(templong,
471 dev->base_addr +
472 FT1000_REG_MAG_DPDATAL);
475 spin_unlock_irqrestore(&info->
476 dpram_lock,
477 flags);
478 break;
479 default:
480 Status = FAILURE;
481 break;
483 put_handshake(dev, HANDSHAKE_RESPONSE);
484 } else {
485 Status = FAILURE;
488 break;
490 case STATE_CODE_DWNLD:
491 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
492 if (handshake == HANDSHAKE_REQUEST) {
494 * Get type associated with the request.
496 request = get_request_type(dev);
497 switch (request) {
498 case REQUEST_FILE_CHECKSUM:
499 DEBUG(0,
500 "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
501 put_request_value(dev, image_chksum);
502 break;
503 case REQUEST_RUN_ADDRESS:
504 if (bGoodVersion) {
505 put_request_value(dev,
506 run_address);
507 } else {
508 Status = FAILURE;
509 break;
511 break;
512 case REQUEST_CODE_LENGTH:
513 if (bGoodVersion) {
514 put_request_value(dev,
515 run_size);
516 } else {
517 Status = FAILURE;
518 break;
520 break;
521 case REQUEST_DONE_CL:
522 /* Reposition ptrs to beginning of provisioning section */
523 switch (file_version) {
524 case 5:
525 case 6:
526 pUsFile =
527 (USHORT *) ((long)pFileStart
529 pFileHdr5->
530 commands_offset);
531 pUcFile =
532 (UCHAR *) ((long)pFileStart
534 pFileHdr5->
535 commands_offset);
536 break;
537 default:
538 Status = FAILURE;
539 break;
541 uiState = STATE_DONE_DWNLD;
542 break;
543 case REQUEST_CODE_SEGMENT:
544 if (!bGoodVersion) {
545 Status = FAILURE;
546 break;
548 word_length = get_request_value(dev);
549 if (word_length > MAX_LENGTH) {
550 Status = FAILURE;
551 break;
553 if ((word_length * 2 + (long)pUcFile) >
554 (long)pCodeEnd) {
556 * Error, beyond boot code range.
558 Status = FAILURE;
559 break;
561 if (file_version == 5) {
563 * Position ASIC DPRAM auto-increment pointer.
565 ft1000_write_reg(dev,
566 FT1000_REG_DPRAM_ADDR,
567 DWNLD_PS_HDR_LOC);
569 for (; word_length > 0; word_length--) { /* In words */
570 //temp = *pUsFile;
571 //temp = RtlUshortByteSwap(temp);
572 ft1000_write_reg(dev,
573 FT1000_REG_DPRAM_DATA,
574 *pUsFile);
575 pUsFile++;
576 pUcFile += 2;
577 DspWordCnt++;
579 } else {
581 * Position ASIC DPRAM auto-increment pointer.
583 outw(DWNLD_MAG_PS_HDR_LOC,
584 dev->base_addr +
585 FT1000_REG_DPRAM_ADDR);
586 if (word_length & 0x01) {
587 word_length++;
589 word_length = word_length / 2;
591 for (; word_length > 0; word_length--) { /* In words */
592 templong = *pUsFile++;
593 templong |=
594 (*pUsFile++ << 16);
595 pUcFile += 4;
596 outl(templong,
597 dev->base_addr +
598 FT1000_REG_MAG_DPDATAL);
601 break;
603 case REQUEST_MAILBOX_DATA:
604 // Convert length from byte count to word count. Make sure we round up.
605 word_length =
606 (long)(info->DSPInfoBlklen + 1) / 2;
607 put_request_value(dev, word_length);
608 pMailBoxData =
609 (PDRVMSG) & info->DSPInfoBlk[0];
610 pUsData =
611 (USHORT *) & pMailBoxData->data[0];
612 // Provide mutual exclusive access while reading ASIC registers.
613 spin_lock_irqsave(&info->dpram_lock,
614 flags);
615 if (file_version == 5) {
617 * Position ASIC DPRAM auto-increment pointer.
619 ft1000_write_reg(dev,
620 FT1000_REG_DPRAM_ADDR,
621 DWNLD_PS_HDR_LOC);
623 for (; word_length > 0; word_length--) { /* In words */
624 temp = ntohs(*pUsData);
625 ft1000_write_reg(dev,
626 FT1000_REG_DPRAM_DATA,
627 temp);
628 pUsData++;
630 } else {
632 * Position ASIC DPRAM auto-increment pointer.
634 outw(DWNLD_MAG_PS_HDR_LOC,
635 dev->base_addr +
636 FT1000_REG_DPRAM_ADDR);
637 if (word_length & 0x01) {
638 word_length++;
640 word_length = word_length / 2;
642 for (; word_length > 0; word_length--) { /* In words */
643 templong = *pUsData++;
644 templong |=
645 (*pUsData++ << 16);
646 outl(templong,
647 dev->base_addr +
648 FT1000_REG_MAG_DPDATAL);
651 spin_unlock_irqrestore(&info->
652 dpram_lock,
653 flags);
654 break;
656 case REQUEST_VERSION_INFO:
657 word_length =
658 pFileHdr5->version_data_size;
659 put_request_value(dev, word_length);
660 pUsFile =
661 (USHORT *) ((long)pFileStart +
662 pFileHdr5->
663 version_data_offset);
664 // Provide mutual exclusive access while reading ASIC registers.
665 spin_lock_irqsave(&info->dpram_lock,
666 flags);
667 if (file_version == 5) {
669 * Position ASIC DPRAM auto-increment pointer.
671 ft1000_write_reg(dev,
672 FT1000_REG_DPRAM_ADDR,
673 DWNLD_PS_HDR_LOC);
675 for (; word_length > 0; word_length--) { /* In words */
676 ft1000_write_reg(dev,
677 FT1000_REG_DPRAM_DATA,
678 *pUsFile
679 /*temp */
681 pUsFile++;
683 } else {
685 * Position ASIC DPRAM auto-increment pointer.
687 outw(DWNLD_MAG_PS_HDR_LOC,
688 dev->base_addr +
689 FT1000_REG_DPRAM_ADDR);
690 if (word_length & 0x01) {
691 word_length++;
693 word_length = word_length / 2;
695 for (; word_length > 0; word_length--) { /* In words */
696 templong =
697 ntohs(*pUsFile++);
698 temp =
699 ntohs(*pUsFile++);
700 templong |=
701 (temp << 16);
702 outl(templong,
703 dev->base_addr +
704 FT1000_REG_MAG_DPDATAL);
707 spin_unlock_irqrestore(&info->
708 dpram_lock,
709 flags);
710 break;
712 case REQUEST_CODE_BY_VERSION:
713 bGoodVersion = FALSE;
714 requested_version =
715 get_request_value(dev);
716 if (file_version == 5) {
717 pDspImageInfo =
718 (PDSP_IMAGE_INFO) ((long)
719 pFileStart
721 sizeof
722 (DSP_FILE_HDR_5));
723 for (imageN = 0;
724 imageN <
725 pFileHdr5->nDspImages;
726 imageN++) {
727 if (pDspImageInfo->
728 version ==
729 requested_version) {
730 bGoodVersion =
731 TRUE;
732 pUsFile =
733 (USHORT
734 *) ((long)
735 pFileStart
737 pDspImageInfo->
738 begin_offset);
739 pUcFile =
740 (UCHAR
741 *) ((long)
742 pFileStart
744 pDspImageInfo->
745 begin_offset);
746 pCodeEnd =
747 (UCHAR
748 *) ((long)
749 pFileStart
751 pDspImageInfo->
752 end_offset);
753 run_address =
754 pDspImageInfo->
755 run_address;
756 run_size =
757 pDspImageInfo->
758 image_size;
759 break;
761 pDspImageInfo++;
763 } else {
764 pDspImageInfoV6 =
765 (PDSP_IMAGE_INFO_V6) ((long)
766 pFileStart
768 sizeof
769 (DSP_FILE_HDR_5));
770 for (imageN = 0;
771 imageN <
772 pFileHdr5->nDspImages;
773 imageN++) {
774 temp = (USHORT)
775 (pDspImageInfoV6->
776 version);
777 templong = temp;
778 temp = (USHORT)
779 (pDspImageInfoV6->
780 version >> 16);
781 templong |=
782 (temp << 16);
783 if (templong ==
784 requested_version) {
785 bGoodVersion =
786 TRUE;
787 pUsFile =
788 (USHORT
789 *) ((long)
790 pFileStart
792 pDspImageInfoV6->
793 begin_offset);
794 pUcFile =
795 (UCHAR
796 *) ((long)
797 pFileStart
799 pDspImageInfoV6->
800 begin_offset);
801 pCodeEnd =
802 (UCHAR
803 *) ((long)
804 pFileStart
806 pDspImageInfoV6->
807 end_offset);
808 run_address =
809 pDspImageInfoV6->
810 run_address;
811 run_size =
812 pDspImageInfoV6->
813 image_size;
814 image_chksum =
815 (ULONG)
816 pDspImageInfoV6->
817 checksum;
818 DEBUG(0,
819 "ft1000_dnld: image_chksum = 0x%8x\n",
820 (unsigned
821 int)
822 image_chksum);
823 break;
825 pDspImageInfoV6++;
828 if (!bGoodVersion) {
830 * Error, beyond boot code range.
832 Status = FAILURE;
833 break;
835 break;
837 default:
838 Status = FAILURE;
839 break;
841 put_handshake(dev, HANDSHAKE_RESPONSE);
842 } else {
843 Status = FAILURE;
846 break;
848 case STATE_DONE_DWNLD:
849 if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >=
850 (unsigned long) FileLength) {
851 uiState = STATE_DONE_FILE;
852 break;
855 pHdr = (PPSEUDO_HDR) pUsFile;
857 if (pHdr->portdest == 0x80 /* DspOAM */
858 && (pHdr->portsrc == 0x00 /* Driver */
859 || pHdr->portsrc == 0x10 /* FMM */ )) {
860 uiState = STATE_SECTION_PROV;
861 } else {
862 DEBUG(1,
863 "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
864 DEBUG(1, "\t Port Source = 0x%2.2x\n",
865 pHdr->portsrc);
866 DEBUG(1, "\t Port Destination = 0x%2.2x\n",
867 pHdr->portdest);
868 Status = FAILURE;
871 break;
873 case STATE_SECTION_PROV:
875 pHdr = (PPSEUDO_HDR) pUcFile;
877 if (pHdr->checksum == hdr_checksum(pHdr)) {
878 if (pHdr->portdest != 0x80 /* Dsp OAM */ ) {
879 uiState = STATE_DONE_PROV;
880 break;
882 usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */
884 // Get buffer for provisioning data
885 pbuffer =
886 kmalloc((usHdrLength + sizeof(PSEUDO_HDR)),
887 GFP_ATOMIC);
888 if (pbuffer) {
889 memcpy(pbuffer, (void *)pUcFile,
890 (UINT) (usHdrLength +
891 sizeof(PSEUDO_HDR)));
892 // link provisioning data
893 pprov_record =
894 kmalloc(sizeof(PROV_RECORD),
895 GFP_ATOMIC);
896 if (pprov_record) {
897 pprov_record->pprov_data =
898 pbuffer;
899 list_add_tail(&pprov_record->
900 list,
901 &info->prov_list);
902 // Move to next entry if available
903 pUcFile =
904 (UCHAR *) ((unsigned long) pUcFile +
905 (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(PSEUDO_HDR));
906 if ((unsigned long) (pUcFile) -
907 (unsigned long) (pFileStart) >=
908 (unsigned long) FileLength) {
909 uiState =
910 STATE_DONE_FILE;
912 } else {
913 kfree(pbuffer);
914 Status = FAILURE;
916 } else {
917 Status = FAILURE;
919 } else {
920 /* Checksum did not compute */
921 Status = FAILURE;
924 break;
926 case STATE_DONE_PROV:
927 uiState = STATE_DONE_FILE;
928 break;
930 default:
931 Status = FAILURE;
932 break;
933 } /* End Switch */
935 } /* End while */
937 return Status;