]> Pileus Git - ~andy/linux/blob - drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c
Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[~andy/linux] / drivers / staging / ft1000 / ft1000-pcmcia / ft1000_dnld.c
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
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
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
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
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
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
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
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
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                         uiState = STATE_BOOT_DWNLD;
354
355                         break;
356
357                 case STATE_BOOT_DWNLD:
358                         handshake = get_handshake(dev, HANDSHAKE_REQUEST);
359                         if (handshake == HANDSHAKE_REQUEST) {
360                                 /*
361                                  * Get type associated with the request.
362                                  */
363                                 request = get_request_type(dev);
364                                 switch (request) {
365                                 case REQUEST_RUN_ADDRESS:
366                                         put_request_value(dev,
367                                                           loader_code_address);
368                                         break;
369                                 case REQUEST_CODE_LENGTH:
370                                         put_request_value(dev,
371                                                           loader_code_size);
372                                         break;
373                                 case REQUEST_DONE_BL:
374                                         /* Reposition ptrs to beginning of code section */
375                                         pUsFile = (u16 *) ((long)pBootEnd);
376                                         pUcFile = (u8 *) ((long)pBootEnd);
377                                         uiState = STATE_CODE_DWNLD;
378                                         break;
379                                 case REQUEST_CODE_SEGMENT:
380                                         word_length = get_request_value(dev);
381                                         if (word_length > MAX_LENGTH) {
382                                                 Status = FAILURE;
383                                                 break;
384                                         }
385                                         if ((word_length * 2 + (long)pUcFile) >
386                                                 (long)pBootEnd) {
387                                                 /*
388                                                  * Error, beyond boot code range.
389                                                  */
390                                                 Status = FAILURE;
391                                                 break;
392                                         }
393                                         /* Provide mutual exclusive access while reading ASIC registers. */
394                                         spin_lock_irqsave(&info->dpram_lock,
395                                                           flags);
396                                         /*
397                                          * Position ASIC DPRAM auto-increment pointer.
398                                          */
399                                         outw(DWNLD_MAG_PS_HDR_LOC,
400                                                  dev->base_addr +
401                                                  FT1000_REG_DPRAM_ADDR);
402                                         if (word_length & 0x01)
403                                                 word_length++;
404                                         word_length = word_length / 2;
405
406                                         for (; word_length > 0; word_length--) {        /* In words */
407                                                 templong = *pUsFile++;
408                                                 templong |=
409                                                         (*pUsFile++ << 16);
410                                                 pUcFile += 4;
411                                                 outl(templong,
412                                                          dev->base_addr +
413                                                          FT1000_REG_MAG_DPDATAL);
414                                         }
415                                         spin_unlock_irqrestore(&info->
416                                                                    dpram_lock,
417                                                                    flags);
418                                         break;
419                                 default:
420                                         Status = FAILURE;
421                                         break;
422                                 }
423                                 put_handshake(dev, HANDSHAKE_RESPONSE);
424                         } else {
425                                 Status = FAILURE;
426                         }
427
428                         break;
429
430                 case STATE_CODE_DWNLD:
431                         handshake = get_handshake(dev, HANDSHAKE_REQUEST);
432                         if (handshake == HANDSHAKE_REQUEST) {
433                                 /*
434                                  * Get type associated with the request.
435                                  */
436                                 request = get_request_type(dev);
437                                 switch (request) {
438                                 case REQUEST_FILE_CHECKSUM:
439                                         DEBUG(0,
440                                                   "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
441                                         put_request_value(dev, image_chksum);
442                                         break;
443                                 case REQUEST_RUN_ADDRESS:
444                                         if (bGoodVersion) {
445                                                 put_request_value(dev,
446                                                                   run_address);
447                                         } else {
448                                                 Status = FAILURE;
449                                                 break;
450                                         }
451                                         break;
452                                 case REQUEST_CODE_LENGTH:
453                                         if (bGoodVersion) {
454                                                 put_request_value(dev,
455                                                                   run_size);
456                                         } else {
457                                                 Status = FAILURE;
458                                                 break;
459                                         }
460                                         break;
461                                 case REQUEST_DONE_CL:
462                                         /* Reposition ptrs to beginning of provisioning section */
463                                         pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->commands_offset);
464                                         pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->commands_offset);
465                                         uiState = STATE_DONE_DWNLD;
466                                         break;
467                                 case REQUEST_CODE_SEGMENT:
468                                         if (!bGoodVersion) {
469                                                 Status = FAILURE;
470                                                 break;
471                                         }
472                                         word_length = get_request_value(dev);
473                                         if (word_length > MAX_LENGTH) {
474                                                 Status = FAILURE;
475                                                 break;
476                                         }
477                                         if ((word_length * 2 + (long)pUcFile) >
478                                                 (long)pCodeEnd) {
479                                                 /*
480                                                  * Error, beyond boot code range.
481                                                  */
482                                                 Status = FAILURE;
483                                                 break;
484                                         }
485                                         /*
486                                          * Position ASIC DPRAM auto-increment pointer.
487                                          */
488                                         outw(DWNLD_MAG_PS_HDR_LOC,
489                                                  dev->base_addr +
490                                                  FT1000_REG_DPRAM_ADDR);
491                                         if (word_length & 0x01)
492                                                 word_length++;
493                                         word_length = word_length / 2;
494
495                                         for (; word_length > 0; word_length--) {        /* In words */
496                                                 templong = *pUsFile++;
497                                                 templong |=
498                                                         (*pUsFile++ << 16);
499                                                 pUcFile += 4;
500                                                 outl(templong,
501                                                          dev->base_addr +
502                                                          FT1000_REG_MAG_DPDATAL);
503                                         }
504                                         break;
505
506                                 case REQUEST_MAILBOX_DATA:
507                                         /* Convert length from byte count to word count. Make sure we round up. */
508                                         word_length =
509                                                 (long)(info->DSPInfoBlklen + 1) / 2;
510                                         put_request_value(dev, word_length);
511                                         pMailBoxData =
512                                                 (struct drv_msg *) &info->DSPInfoBlk[0];
513                                         pUsData =
514                                                 (u16 *) &pMailBoxData->data[0];
515                                         /* Provide mutual exclusive access while reading ASIC registers. */
516                                         spin_lock_irqsave(&info->dpram_lock,
517                                                           flags);
518                                         if (file_version == 5) {
519                                                 /*
520                                                  * Position ASIC DPRAM auto-increment pointer.
521                                                  */
522                                                 ft1000_write_reg(dev,
523                                                                  FT1000_REG_DPRAM_ADDR,
524                                                                  DWNLD_PS_HDR_LOC);
525
526                                                 for (; word_length > 0; word_length--) {        /* In words */
527                                                         temp = ntohs(*pUsData);
528                                                         ft1000_write_reg(dev,
529                                                                          FT1000_REG_DPRAM_DATA,
530                                                                          temp);
531                                                         pUsData++;
532                                                 }
533                                         } else {
534                                                 /*
535                                                  * Position ASIC DPRAM auto-increment pointer.
536                                                  */
537                                                 outw(DWNLD_MAG_PS_HDR_LOC,
538                                                          dev->base_addr +
539                                                          FT1000_REG_DPRAM_ADDR);
540                                                 if (word_length & 0x01)
541                                                         word_length++;
542
543                                                 word_length = word_length / 2;
544
545                                                 for (; word_length > 0; word_length--) {        /* In words */
546                                                         templong = *pUsData++;
547                                                         templong |=
548                                                                 (*pUsData++ << 16);
549                                                         outl(templong,
550                                                                  dev->base_addr +
551                                                                  FT1000_REG_MAG_DPDATAL);
552                                                 }
553                                         }
554                                         spin_unlock_irqrestore(&info->
555                                                                    dpram_lock,
556                                                                    flags);
557                                         break;
558
559                                 case REQUEST_VERSION_INFO:
560                                         word_length =
561                                                 pFileHdr5->version_data_size;
562                                         put_request_value(dev, word_length);
563                                         pUsFile =
564                                                 (u16 *) ((long)pFileStart +
565                                                         pFileHdr5->
566                                                         version_data_offset);
567                                         /* Provide mutual exclusive access while reading ASIC registers. */
568                                         spin_lock_irqsave(&info->dpram_lock,
569                                                           flags);
570                                         /*
571                                          * Position ASIC DPRAM auto-increment pointer.
572                                          */
573                                         outw(DWNLD_MAG_PS_HDR_LOC,
574                                                  dev->base_addr +
575                                                  FT1000_REG_DPRAM_ADDR);
576                                         if (word_length & 0x01)
577                                                 word_length++;
578                                         word_length = word_length / 2;
579
580                                         for (; word_length > 0; word_length--) {        /* In words */
581                                                 templong =
582                                                         ntohs(*pUsFile++);
583                                                 temp =
584                                                         ntohs(*pUsFile++);
585                                                 templong |=
586                                                         (temp << 16);
587                                                 outl(templong,
588                                                          dev->base_addr +
589                                                          FT1000_REG_MAG_DPDATAL);
590                                         }
591                                         spin_unlock_irqrestore(&info->
592                                                                    dpram_lock,
593                                                                    flags);
594                                         break;
595
596                                 case REQUEST_CODE_BY_VERSION:
597                                         bGoodVersion = false;
598                                         requested_version =
599                                                 get_request_value(dev);
600                                         pDspImageInfoV6 =
601                                                 (struct dsp_image_info *) ((long)
602                                                                   pFileStart
603                                                                   +
604                                                                   sizeof
605                                                                   (struct dsp_file_hdr));
606                                         for (imageN = 0;
607                                                  imageN <
608                                                  pFileHdr5->nDspImages;
609                                                  imageN++) {
610                                                 temp = (u16)
611                                                         (pDspImageInfoV6->
612                                                          version);
613                                                 templong = temp;
614                                                 temp = (u16)
615                                                         (pDspImageInfoV6->
616                                                          version >> 16);
617                                                 templong |=
618                                                         (temp << 16);
619                                                 if (templong ==
620                                                         requested_version) {
621                                                         bGoodVersion =
622                                                                 true;
623                                                         pUsFile =
624                                                                 (u16
625                                                                  *) ((long)
626                                                                  pFileStart
627                                                                  +
628                                                                  pDspImageInfoV6->
629                                                                  begin_offset);
630                                                         pUcFile =
631                                                                 (u8
632                                                                  *) ((long)
633                                                                  pFileStart
634                                                                  +
635                                                                  pDspImageInfoV6->
636                                                                  begin_offset);
637                                                         pCodeEnd =
638                                                                 (u8
639                                                                  *) ((long)
640                                                                  pFileStart
641                                                                  +
642                                                                  pDspImageInfoV6->
643                                                                  end_offset);
644                                                         run_address =
645                                                                 pDspImageInfoV6->
646                                                                 run_address;
647                                                         run_size =
648                                                                 pDspImageInfoV6->
649                                                                 image_size;
650                                                         image_chksum =
651                                                                 (u32)
652                                                                 pDspImageInfoV6->
653                                                                 checksum;
654                                                         DEBUG(0,
655                                                                   "ft1000_dnld: image_chksum = 0x%8x\n",
656                                                                   (unsigned
657                                                                    int)
658                                                                   image_chksum);
659                                                         break;
660                                                 }
661                                                 pDspImageInfoV6++;
662                                         }
663                                         if (!bGoodVersion) {
664                                                 /*
665                                                  * Error, beyond boot code range.
666                                                  */
667                                                 Status = FAILURE;
668                                                 break;
669                                         }
670                                         break;
671
672                                 default:
673                                         Status = FAILURE;
674                                         break;
675                                 }
676                                 put_handshake(dev, HANDSHAKE_RESPONSE);
677                         } else {
678                                 Status = FAILURE;
679                         }
680
681                         break;
682
683                 case STATE_DONE_DWNLD:
684                         if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >=
685                                 (unsigned long) FileLength) {
686                                 uiState = STATE_DONE_FILE;
687                                 break;
688                         }
689
690                         pHdr = (struct pseudo_hdr *) pUsFile;
691
692                         if (pHdr->portdest == 0x80      /* DspOAM */
693                                 && (pHdr->portsrc == 0x00       /* Driver */
694                                 || pHdr->portsrc == 0x10 /* FMM */)) {
695                                 uiState = STATE_SECTION_PROV;
696                         } else {
697                                 DEBUG(1,
698                                           "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
699                                 DEBUG(1, "\t Port Source = 0x%2.2x\n",
700                                           pHdr->portsrc);
701                                 DEBUG(1, "\t Port Destination = 0x%2.2x\n",
702                                           pHdr->portdest);
703                                 Status = FAILURE;
704                         }
705
706                         break;
707
708                 case STATE_SECTION_PROV:
709
710                         pHdr = (struct pseudo_hdr *) pUcFile;
711
712                         if (pHdr->checksum == hdr_checksum(pHdr)) {
713                                 if (pHdr->portdest != 0x80 /* Dsp OAM */) {
714                                         uiState = STATE_DONE_PROV;
715                                         break;
716                                 }
717                                 usHdrLength = ntohs(pHdr->length);      /* Byte length for PROV records */
718
719                                 /* Get buffer for provisioning data */
720                                 pbuffer =
721                                         kmalloc((usHdrLength + sizeof(struct pseudo_hdr)),
722                                                 GFP_ATOMIC);
723                                 if (pbuffer) {
724                                         memcpy(pbuffer, (void *)pUcFile,
725                                                    (u32) (usHdrLength +
726                                                            sizeof(struct pseudo_hdr)));
727                                         /* link provisioning data */
728                                         pprov_record =
729                                                 kmalloc(sizeof(struct prov_record),
730                                                         GFP_ATOMIC);
731                                         if (pprov_record) {
732                                                 pprov_record->pprov_data =
733                                                         pbuffer;
734                                                 list_add_tail(&pprov_record->
735                                                                   list,
736                                                                   &info->prov_list);
737                                                 /* Move to next entry if available */
738                                                 pUcFile =
739                                                         (u8 *) ((unsigned long) pUcFile +
740                                                                    (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
741                                                 if ((unsigned long) (pUcFile) -
742                                                         (unsigned long) (pFileStart) >=
743                                                         (unsigned long) FileLength) {
744                                                         uiState =
745                                                                 STATE_DONE_FILE;
746                                                 }
747                                         } else {
748                                                 kfree(pbuffer);
749                                                 Status = FAILURE;
750                                         }
751                                 } else {
752                                         Status = FAILURE;
753                                 }
754                         } else {
755                                 /* Checksum did not compute */
756                                 Status = FAILURE;
757                         }
758
759                         break;
760
761                 case STATE_DONE_PROV:
762                         uiState = STATE_DONE_FILE;
763                         break;
764
765                 default:
766                         Status = FAILURE;
767                         break;
768                 }               /* End Switch */
769
770         }                       /* End while */
771
772         return Status;
773
774 }