1 /*---------------------------------------------------------------------------
2    FT1000 driver for Flarion Flash OFDM NIC Device
3 
4    Copyright (C) 2002 Flarion Technologies, All rights reserved.
5 
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   --------------------------------------------------------------------------
17 
18    Description:  This module will handshake with the DSP bootloader to
19                  download the DSP runtime image.
20 
21 ---------------------------------------------------------------------------*/
22 
23 #define __KERNEL_SYSCALLS__
24 
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>
36 
37 #include "ft1000.h"
38 #include "boot.h"
39 
40 #ifdef FT_DEBUG
41 #define DEBUG(n, args...) printk(KERN_DEBUG args);
42 #else
43 #define DEBUG(n, args...)
44 #endif
45 
46 #define  MAX_DSP_WAIT_LOOPS      100
47 #define  DSP_WAIT_SLEEP_TIME     1	/* 1 millisecond */
48 
49 #define  MAX_LENGTH              0x7f0
50 
51 #define  DWNLD_MAG_HANDSHAKE_LOC 0x00
52 #define  DWNLD_MAG_TYPE_LOC      0x01
53 #define  DWNLD_MAG_SIZE_LOC      0x02
54 #define  DWNLD_MAG_PS_HDR_LOC    0x03
55 
56 #define  DWNLD_HANDSHAKE_LOC     0x02
57 #define  DWNLD_TYPE_LOC          0x04
58 #define  DWNLD_SIZE_MSW_LOC      0x06
59 #define  DWNLD_SIZE_LSW_LOC      0x08
60 #define  DWNLD_PS_HDR_LOC        0x0A
61 
62 #define  HANDSHAKE_TIMEOUT_VALUE 0xF1F1
63 #define  HANDSHAKE_RESET_VALUE   0xFEFE	/* When DSP requests startover */
64 #define  HANDSHAKE_DSP_BL_READY  0xFEFE	/* At start DSP writes this when bootloader ready */
65 #define  HANDSHAKE_DRIVER_READY  0xFFFF	/* Driver writes after receiving 0xFEFE */
66 #define  HANDSHAKE_SEND_DATA     0x0000	/* DSP writes this when ready for more data */
67 
68 #define  HANDSHAKE_REQUEST       0x0001	/* Request from DSP */
69 #define  HANDSHAKE_RESPONSE      0x0000	/* Satisfied DSP request */
70 
71 #define  REQUEST_CODE_LENGTH     0x0000
72 #define  REQUEST_RUN_ADDRESS     0x0001
73 #define  REQUEST_CODE_SEGMENT    0x0002	/* In WORD count */
74 #define  REQUEST_DONE_BL         0x0003
75 #define  REQUEST_DONE_CL         0x0004
76 #define  REQUEST_VERSION_INFO    0x0005
77 #define  REQUEST_CODE_BY_VERSION 0x0006
78 #define  REQUEST_MAILBOX_DATA    0x0007
79 #define  REQUEST_FILE_CHECKSUM   0x0008
80 
81 #define  STATE_START_DWNLD       0x01
82 #define  STATE_BOOT_DWNLD        0x02
83 #define  STATE_CODE_DWNLD        0x03
84 #define  STATE_DONE_DWNLD        0x04
85 #define  STATE_SECTION_PROV      0x05
86 #define  STATE_DONE_PROV         0x06
87 #define  STATE_DONE_FILE         0x07
88 
89 u16 get_handshake(struct net_device *dev, u16 expected_value);
90 void put_handshake(struct net_device *dev, u16 handshake_value);
91 u16 get_request_type(struct net_device *dev);
92 long get_request_value(struct net_device *dev);
93 void put_request_value(struct net_device *dev, long lvalue);
94 u16 hdr_checksum(struct pseudo_hdr *pHdr);
95 
96 struct dsp_file_hdr {
97 	u32  version_id;	// Version ID of this image format.
98 	u32  package_id;	// Package ID of code release.
99 	u32  build_date;	// Date/time stamp when file was built.
100 	u32  commands_offset;	// Offset to attached commands in Pseudo Hdr format.
101 	u32  loader_offset;	// Offset to bootloader code.
102 	u32  loader_code_address;	// Start address of bootloader.
103 	u32  loader_code_end;	// Where bootloader code ends.
104 	u32  loader_code_size;
105 	u32  version_data_offset;	// Offset were scrambled version data begins.
106 	u32  version_data_size;	// Size, in words, of scrambled version data.
107 	u32  nDspImages;	// Number of DSP images in file.
108 } __attribute__ ((packed));
109 
110 struct dsp_image_info {
111 	u32  coff_date;		// Date/time when DSP Coff image was built.
112 	u32  begin_offset;	// Offset in file where image begins.
113 	u32  end_offset;	// Offset in file where image begins.
114 	u32  run_address;	// On chip Start address of DSP code.
115 	u32  image_size;	// Size of image.
116 	u32  version;		// Embedded version # of DSP code.
117 	unsigned short checksum;	// Dsp File checksum
118 	unsigned short pad1;
119 } __attribute__ ((packed));
120 
card_bootload(struct net_device * dev)121 void card_bootload(struct net_device *dev)
122 {
123 	struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
124 	unsigned long flags;
125 	u32 *pdata;
126 	u32 size;
127 	u32 i;
128 	u32 templong;
129 
130 	DEBUG(0, "card_bootload is called\n");
131 
132 	pdata = (u32 *) bootimage;
133 	size = sizeof(bootimage);
134 
135 	// check for odd word
136 	if (size & 0x0003) {
137 		size += 4;
138 	}
139 	// Provide mutual exclusive access while reading ASIC registers.
140 	spin_lock_irqsave(&info->dpram_lock, flags);
141 
142 	// need to set i/o base address initially and hardware will autoincrement
143 	ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
144 	// write bytes
145 	for (i = 0; i < (size >> 2); i++) {
146 		templong = *pdata++;
147 		outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
148 	}
149 
150 	spin_unlock_irqrestore(&info->dpram_lock, flags);
151 }
152 
get_handshake(struct net_device * dev,u16 expected_value)153 u16 get_handshake(struct net_device *dev, u16 expected_value)
154 {
155 	struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
156 	u16 handshake;
157 	u32 tempx;
158 	int loopcnt;
159 
160 	loopcnt = 0;
161 	while (loopcnt < MAX_DSP_WAIT_LOOPS) {
162 		if (info->AsicID == ELECTRABUZZ_ID) {
163 			ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
164 					 DWNLD_HANDSHAKE_LOC);
165 
166 			handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
167 		} else {
168 			tempx =
169 				ntohl(ft1000_read_dpram_mag_32
170 				  (dev, DWNLD_MAG_HANDSHAKE_LOC));
171 			handshake = (u16) tempx;
172 		}
173 
174 		if ((handshake == expected_value)
175 			|| (handshake == HANDSHAKE_RESET_VALUE)) {
176 			return handshake;
177 		} else {
178 			loopcnt++;
179 			mdelay(DSP_WAIT_SLEEP_TIME);
180 		}
181 
182 	}
183 
184 	return HANDSHAKE_TIMEOUT_VALUE;
185 
186 }
187 
put_handshake(struct net_device * dev,u16 handshake_value)188 void put_handshake(struct net_device *dev, u16 handshake_value)
189 {
190 	struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
191 	u32 tempx;
192 
193 	if (info->AsicID == ELECTRABUZZ_ID) {
194 		ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
195 				 DWNLD_HANDSHAKE_LOC);
196 		ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value);	/* Handshake */
197 	} else {
198 		tempx = (u32) handshake_value;
199 		tempx = ntohl(tempx);
200 		ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx);	/* Handshake */
201 	}
202 }
203 
get_request_type(struct net_device * dev)204 u16 get_request_type(struct net_device *dev)
205 {
206 	struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
207 	u16 request_type;
208 	u32 tempx;
209 
210 	if (info->AsicID == ELECTRABUZZ_ID) {
211 		ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
212 		request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
213 	} else {
214 		tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
215 		tempx = ntohl(tempx);
216 		request_type = (u16) tempx;
217 	}
218 
219 	return request_type;
220 
221 }
222 
get_request_value(struct net_device * dev)223 long get_request_value(struct net_device *dev)
224 {
225 	struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
226 	long value;
227 	u16 w_val;
228 
229 	if (info->AsicID == ELECTRABUZZ_ID) {
230 		ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
231 				 DWNLD_SIZE_MSW_LOC);
232 
233 		w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
234 
235 		value = (long)(w_val << 16);
236 
237 		ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
238 				 DWNLD_SIZE_LSW_LOC);
239 
240 		w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
241 
242 		value = (long)(value | w_val);
243 	} else {
244 		value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
245 		value = ntohl(value);
246 	}
247 
248 	return value;
249 
250 }
251 
put_request_value(struct net_device * dev,long lvalue)252 void put_request_value(struct net_device *dev, long lvalue)
253 {
254 	struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
255 	u16 size;
256 	u32 tempx;
257 
258 	if (info->AsicID == ELECTRABUZZ_ID) {
259 		size = (u16) (lvalue >> 16);
260 
261 		ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
262 				 DWNLD_SIZE_MSW_LOC);
263 
264 		ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
265 
266 		size = (u16) (lvalue);
267 
268 		ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
269 				 DWNLD_SIZE_LSW_LOC);
270 
271 		ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
272 	} else {
273 		tempx = ntohl(lvalue);
274 		ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx);	/* Handshake */
275 	}
276 
277 }
278 
hdr_checksum(struct pseudo_hdr * pHdr)279 u16 hdr_checksum(struct pseudo_hdr *pHdr)
280 {
281 	u16 *usPtr = (u16 *) pHdr;
282 	u16 chksum;
283 
284 	chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
285 			usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
286 
287 	return chksum;
288 }
289 
card_download(struct net_device * dev,const u8 * pFileStart,size_t FileLength)290 int card_download(struct net_device *dev, const u8 *pFileStart,
291 		  size_t FileLength)
292 {
293 	struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
294 	int Status = SUCCESS;
295 	u32 uiState;
296 	u16 handshake;
297 	struct pseudo_hdr *pHdr;
298 	u16 usHdrLength;
299 	long word_length;
300 	u16 request;
301 	u16 temp;
302 	struct prov_record *pprov_record;
303 	u8 *pbuffer;
304 	struct dsp_file_hdr *pFileHdr5;
305 	struct dsp_image_info *pDspImageInfoV6 = NULL;
306 	long requested_version;
307 	bool bGoodVersion = 0;
308 	struct drv_msg *pMailBoxData;
309 	u16 *pUsData = NULL;
310 	u16 *pUsFile = NULL;
311 	u8 *pUcFile = NULL;
312 	u8 *pBootEnd = NULL;
313 	u8 *pCodeEnd = NULL;
314 	int imageN;
315 	long file_version;
316 	long loader_code_address = 0;
317 	long loader_code_size = 0;
318 	long run_address = 0;
319 	long run_size = 0;
320 	unsigned long flags;
321 	unsigned long templong;
322 	unsigned long image_chksum = 0;
323 
324 	file_version = *(long *)pFileStart;
325 	if (file_version != 6) {
326 		printk(KERN_ERR "ft1000: unsupported firmware version %ld\n", file_version);
327 		Status = FAILURE;
328 	}
329 
330 	uiState = STATE_START_DWNLD;
331 
332 	pFileHdr5 = (struct dsp_file_hdr *) pFileStart;
333 
334 	pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->loader_offset);
335 	pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->loader_offset);
336 	pBootEnd = (u8 *) ((long)pFileStart + pFileHdr5->loader_code_end);
337 	loader_code_address = pFileHdr5->loader_code_address;
338 	loader_code_size = pFileHdr5->loader_code_size;
339 	bGoodVersion = false;
340 
341 	while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
342 
343 		switch (uiState) {
344 		case STATE_START_DWNLD:
345 
346 			handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
347 
348 			if (handshake == HANDSHAKE_DSP_BL_READY) {
349 				put_handshake(dev, HANDSHAKE_DRIVER_READY);
350 			} else {
351 				Status = FAILURE;
352 			}
353 
354 			uiState = STATE_BOOT_DWNLD;
355 
356 			break;
357 
358 		case STATE_BOOT_DWNLD:
359 			handshake = get_handshake(dev, HANDSHAKE_REQUEST);
360 			if (handshake == HANDSHAKE_REQUEST) {
361 				/*
362 				 * Get type associated with the request.
363 				 */
364 				request = get_request_type(dev);
365 				switch (request) {
366 				case REQUEST_RUN_ADDRESS:
367 					put_request_value(dev,
368 							  loader_code_address);
369 					break;
370 				case REQUEST_CODE_LENGTH:
371 					put_request_value(dev,
372 							  loader_code_size);
373 					break;
374 				case REQUEST_DONE_BL:
375 					/* Reposition ptrs to beginning of code section */
376 					pUsFile = (u16 *) ((long)pBootEnd);
377 					pUcFile = (u8 *) ((long)pBootEnd);
378 					uiState = STATE_CODE_DWNLD;
379 					break;
380 				case REQUEST_CODE_SEGMENT:
381 					word_length = get_request_value(dev);
382 					if (word_length > MAX_LENGTH) {
383 						Status = FAILURE;
384 						break;
385 					}
386 					if ((word_length * 2 + (long)pUcFile) >
387 						(long)pBootEnd) {
388 						/*
389 						 * Error, beyond boot code range.
390 						 */
391 						Status = FAILURE;
392 						break;
393 					}
394 					// Provide mutual exclusive access while reading ASIC registers.
395 					spin_lock_irqsave(&info->dpram_lock,
396 							  flags);
397 					/*
398 					 * Position ASIC DPRAM auto-increment pointer.
399 					 */
400 					outw(DWNLD_MAG_PS_HDR_LOC,
401 						 dev->base_addr +
402 						 FT1000_REG_DPRAM_ADDR);
403 					if (word_length & 0x01)
404 						word_length++;
405 					word_length = word_length / 2;
406 
407 					for (; word_length > 0; word_length--) {	/* In words */
408 						templong = *pUsFile++;
409 						templong |=
410 							(*pUsFile++ << 16);
411 						pUcFile += 4;
412 						outl(templong,
413 							 dev->base_addr +
414 							 FT1000_REG_MAG_DPDATAL);
415 					}
416 					spin_unlock_irqrestore(&info->
417 								   dpram_lock,
418 								   flags);
419 					break;
420 				default:
421 					Status = FAILURE;
422 					break;
423 				}
424 				put_handshake(dev, HANDSHAKE_RESPONSE);
425 			} else {
426 				Status = FAILURE;
427 			}
428 
429 			break;
430 
431 		case STATE_CODE_DWNLD:
432 			handshake = get_handshake(dev, HANDSHAKE_REQUEST);
433 			if (handshake == HANDSHAKE_REQUEST) {
434 				/*
435 				 * Get type associated with the request.
436 				 */
437 				request = get_request_type(dev);
438 				switch (request) {
439 				case REQUEST_FILE_CHECKSUM:
440 					DEBUG(0,
441 						  "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
442 					put_request_value(dev, image_chksum);
443 					break;
444 				case REQUEST_RUN_ADDRESS:
445 					if (bGoodVersion) {
446 						put_request_value(dev,
447 								  run_address);
448 					} else {
449 						Status = FAILURE;
450 						break;
451 					}
452 					break;
453 				case REQUEST_CODE_LENGTH:
454 					if (bGoodVersion) {
455 						put_request_value(dev,
456 								  run_size);
457 					} else {
458 						Status = FAILURE;
459 						break;
460 					}
461 					break;
462 				case REQUEST_DONE_CL:
463 					/* Reposition ptrs to beginning of provisioning section */
464 					pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->commands_offset);
465 					pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->commands_offset);
466 					uiState = STATE_DONE_DWNLD;
467 					break;
468 				case REQUEST_CODE_SEGMENT:
469 					if (!bGoodVersion) {
470 						Status = FAILURE;
471 						break;
472 					}
473 					word_length = get_request_value(dev);
474 					if (word_length > MAX_LENGTH) {
475 						Status = FAILURE;
476 						break;
477 					}
478 					if ((word_length * 2 + (long)pUcFile) >
479 						(long)pCodeEnd) {
480 						/*
481 						 * Error, beyond boot code range.
482 						 */
483 						Status = FAILURE;
484 						break;
485 					}
486 					/*
487 					 * Position ASIC DPRAM auto-increment pointer.
488 					 */
489 					outw(DWNLD_MAG_PS_HDR_LOC,
490 						 dev->base_addr +
491 						 FT1000_REG_DPRAM_ADDR);
492 					if (word_length & 0x01)
493 						word_length++;
494 					word_length = word_length / 2;
495 
496 					for (; word_length > 0; word_length--) {	/* In words */
497 						templong = *pUsFile++;
498 						templong |=
499 							(*pUsFile++ << 16);
500 						pUcFile += 4;
501 						outl(templong,
502 							 dev->base_addr +
503 							 FT1000_REG_MAG_DPDATAL);
504 					}
505 					break;
506 
507 				case REQUEST_MAILBOX_DATA:
508 					// Convert length from byte count to word count. Make sure we round up.
509 					word_length =
510 						(long)(info->DSPInfoBlklen + 1) / 2;
511 					put_request_value(dev, word_length);
512 					pMailBoxData =
513 						(struct drv_msg *) & info->DSPInfoBlk[0];
514 					pUsData =
515 						(u16 *) & pMailBoxData->data[0];
516 					// Provide mutual exclusive access while reading ASIC registers.
517 					spin_lock_irqsave(&info->dpram_lock,
518 							  flags);
519 					if (file_version == 5) {
520 						/*
521 						 * Position ASIC DPRAM auto-increment pointer.
522 						 */
523 						ft1000_write_reg(dev,
524 								 FT1000_REG_DPRAM_ADDR,
525 								 DWNLD_PS_HDR_LOC);
526 
527 						for (; word_length > 0; word_length--) {	/* In words */
528 							temp = ntohs(*pUsData);
529 							ft1000_write_reg(dev,
530 									 FT1000_REG_DPRAM_DATA,
531 									 temp);
532 							pUsData++;
533 						}
534 					} else {
535 						/*
536 						 * Position ASIC DPRAM auto-increment pointer.
537 						 */
538 						outw(DWNLD_MAG_PS_HDR_LOC,
539 							 dev->base_addr +
540 							 FT1000_REG_DPRAM_ADDR);
541 						if (word_length & 0x01) {
542 							word_length++;
543 						}
544 						word_length = word_length / 2;
545 
546 						for (; word_length > 0; word_length--) {	/* In words */
547 							templong = *pUsData++;
548 							templong |=
549 								(*pUsData++ << 16);
550 							outl(templong,
551 								 dev->base_addr +
552 								 FT1000_REG_MAG_DPDATAL);
553 						}
554 					}
555 					spin_unlock_irqrestore(&info->
556 								   dpram_lock,
557 								   flags);
558 					break;
559 
560 				case REQUEST_VERSION_INFO:
561 					word_length =
562 						pFileHdr5->version_data_size;
563 					put_request_value(dev, word_length);
564 					pUsFile =
565 						(u16 *) ((long)pFileStart +
566 							pFileHdr5->
567 							version_data_offset);
568 					// Provide mutual exclusive access while reading ASIC registers.
569 					spin_lock_irqsave(&info->dpram_lock,
570 							  flags);
571 					/*
572 					 * Position ASIC DPRAM auto-increment pointer.
573 					 */
574 					outw(DWNLD_MAG_PS_HDR_LOC,
575 						 dev->base_addr +
576 						 FT1000_REG_DPRAM_ADDR);
577 					if (word_length & 0x01)
578 						word_length++;
579 					word_length = word_length / 2;
580 
581 					for (; word_length > 0; word_length--) {	/* In words */
582 						templong =
583 							ntohs(*pUsFile++);
584 						temp =
585 							ntohs(*pUsFile++);
586 						templong |=
587 							(temp << 16);
588 						outl(templong,
589 							 dev->base_addr +
590 							 FT1000_REG_MAG_DPDATAL);
591 					}
592 					spin_unlock_irqrestore(&info->
593 								   dpram_lock,
594 								   flags);
595 					break;
596 
597 				case REQUEST_CODE_BY_VERSION:
598 					bGoodVersion = false;
599 					requested_version =
600 						get_request_value(dev);
601 					pDspImageInfoV6 =
602 						(struct dsp_image_info *) ((long)
603 								  pFileStart
604 								  +
605 								  sizeof
606 								  (struct dsp_file_hdr));
607 					for (imageN = 0;
608 						 imageN <
609 						 pFileHdr5->nDspImages;
610 						 imageN++) {
611 						temp = (u16)
612 							(pDspImageInfoV6->
613 							 version);
614 						templong = temp;
615 						temp = (u16)
616 							(pDspImageInfoV6->
617 							 version >> 16);
618 						templong |=
619 							(temp << 16);
620 						if (templong ==
621 							requested_version) {
622 							bGoodVersion =
623 								true;
624 							pUsFile =
625 								(u16
626 								 *) ((long)
627 								 pFileStart
628 								 +
629 								 pDspImageInfoV6->
630 								 begin_offset);
631 							pUcFile =
632 								(u8
633 								 *) ((long)
634 								 pFileStart
635 								 +
636 								 pDspImageInfoV6->
637 								 begin_offset);
638 							pCodeEnd =
639 								(u8
640 								 *) ((long)
641 								 pFileStart
642 								 +
643 								 pDspImageInfoV6->
644 								 end_offset);
645 							run_address =
646 								pDspImageInfoV6->
647 								run_address;
648 							run_size =
649 								pDspImageInfoV6->
650 								image_size;
651 							image_chksum =
652 								(u32)
653 								pDspImageInfoV6->
654 								checksum;
655 							DEBUG(0,
656 								  "ft1000_dnld: image_chksum = 0x%8x\n",
657 								  (unsigned
658 								   int)
659 								  image_chksum);
660 							break;
661 						}
662 						pDspImageInfoV6++;
663 					}
664 					if (!bGoodVersion) {
665 						/*
666 						 * Error, beyond boot code range.
667 						 */
668 						Status = FAILURE;
669 						break;
670 					}
671 					break;
672 
673 				default:
674 					Status = FAILURE;
675 					break;
676 				}
677 				put_handshake(dev, HANDSHAKE_RESPONSE);
678 			} else {
679 				Status = FAILURE;
680 			}
681 
682 			break;
683 
684 		case STATE_DONE_DWNLD:
685 			if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >=
686 				(unsigned long) FileLength) {
687 				uiState = STATE_DONE_FILE;
688 				break;
689 			}
690 
691 			pHdr = (struct pseudo_hdr *) pUsFile;
692 
693 			if (pHdr->portdest == 0x80	/* DspOAM */
694 				&& (pHdr->portsrc == 0x00	/* Driver */
695 				|| pHdr->portsrc == 0x10 /* FMM */ )) {
696 				uiState = STATE_SECTION_PROV;
697 			} else {
698 				DEBUG(1,
699 					  "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
700 				DEBUG(1, "\t Port Source = 0x%2.2x\n",
701 					  pHdr->portsrc);
702 				DEBUG(1, "\t Port Destination = 0x%2.2x\n",
703 					  pHdr->portdest);
704 				Status = FAILURE;
705 			}
706 
707 			break;
708 
709 		case STATE_SECTION_PROV:
710 
711 			pHdr = (struct pseudo_hdr *) pUcFile;
712 
713 			if (pHdr->checksum == hdr_checksum(pHdr)) {
714 				if (pHdr->portdest != 0x80 /* Dsp OAM */ ) {
715 					uiState = STATE_DONE_PROV;
716 					break;
717 				}
718 				usHdrLength = ntohs(pHdr->length);	/* Byte length for PROV records */
719 
720 				// Get buffer for provisioning data
721 				pbuffer =
722 					kmalloc((usHdrLength + sizeof(struct pseudo_hdr)),
723 						GFP_ATOMIC);
724 				if (pbuffer) {
725 					memcpy(pbuffer, (void *)pUcFile,
726 						   (u32) (usHdrLength +
727 							   sizeof(struct pseudo_hdr)));
728 					// link provisioning data
729 					pprov_record =
730 						kmalloc(sizeof(struct prov_record),
731 							GFP_ATOMIC);
732 					if (pprov_record) {
733 						pprov_record->pprov_data =
734 							pbuffer;
735 						list_add_tail(&pprov_record->
736 								  list,
737 								  &info->prov_list);
738 						// Move to next entry if available
739 						pUcFile =
740 							(u8 *) ((unsigned long) pUcFile +
741 								   (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
742 						if ((unsigned long) (pUcFile) -
743 							(unsigned long) (pFileStart) >=
744 							(unsigned long) FileLength) {
745 							uiState =
746 								STATE_DONE_FILE;
747 						}
748 					} else {
749 						kfree(pbuffer);
750 						Status = FAILURE;
751 					}
752 				} else {
753 					Status = FAILURE;
754 				}
755 			} else {
756 				/* Checksum did not compute */
757 				Status = FAILURE;
758 			}
759 
760 			break;
761 
762 		case STATE_DONE_PROV:
763 			uiState = STATE_DONE_FILE;
764 			break;
765 
766 		default:
767 			Status = FAILURE;
768 			break;
769 		}		/* End Switch */
770 
771 	}			/* End while */
772 
773 	return Status;
774 
775 }
776